diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Tue Aug 27 12:27:42 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Tue Aug 27 12:27:42 2002
@@ -299,6 +299,8 @@
     EHCI, OHCI, or UHCI.
     </para>
 !Edrivers/usb/core/hcd.c
+!Edrivers/usb/core/hcd-pci.c
+!Edrivers/usb/core/buffer.c
     </sect1>
 
   </chapter>
diff -Nru a/Documentation/filesystems/driverfs.txt b/Documentation/filesystems/driverfs.txt
--- a/Documentation/filesystems/driverfs.txt	Tue Aug 27 12:28:08 2002
+++ b/Documentation/filesystems/driverfs.txt	Tue Aug 27 12:28:08 2002
@@ -165,9 +165,9 @@
 order to relieve pain in declaring attributes, the subsystem should
 also define a macro, like:
 
-#define DEVICE_ATTR(_name,_str,_mode,_show,_store)      \
+#define DEVICE_ATTR(_name,_mode,_show,_store)      \
 struct device_attribute dev_attr_##_name = {            \
-        .attr = {.name  = _str, .mode   = _mode },      \
+        .attr = {.name  = __stringify(_name) , .mode   = _mode },      \
         .show   = _show,                                \
         .store  = _store,                               \
 };
@@ -252,7 +252,7 @@
 
 Declaring:
 
-BUS_ATTR(_name,_str,_mode,_show,_store)
+BUS_ATTR(_name,_mode,_show,_store)
 
 Creation/Removal:
 
@@ -273,7 +273,7 @@
 
 Declaring:
 
-DRIVER_ATTR(_name,_str,_mode,_show,_store)
+DRIVER_ATTR(_name,_mode,_show,_store)
 
 Creation/Removal:
 
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt	Tue Aug 27 12:28:06 2002
+++ b/Documentation/filesystems/ntfs.txt	Tue Aug 27 12:28:06 2002
@@ -247,6 +247,8 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.0.25:
+	- Minor bugfixes in error code paths and small cleanups.
 2.0.24:
 	- Small internal cleanups.
 	- Support for sendfile system call. (Christoph Hellwig)
diff -Nru a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface
--- a/Documentation/i2c/dev-interface	Tue Aug 27 12:27:59 2002
+++ b/Documentation/i2c/dev-interface	Tue Aug 27 12:27:59 2002
@@ -87,7 +87,12 @@
 
 ioctl(file,I2C_TENBIT,long select)
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
-  addresses if select equals 0.
+  addresses if select equals 0. Default 0.
+
+ioctl(file,I2C_PEC,long select)
+  Selects SMBus PEC (packet error checking) generation and verification
+  if select not equals 0, disables if select equals 0. Default 0.
+  Used only for SMBus transactions.
 
 ioctl(file,I2C_FUNCS,unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
diff -Nru a/Documentation/i2c/i2c-old-porting b/Documentation/i2c/i2c-old-porting
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/i2c/i2c-old-porting	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,626 @@
+I2C Conversion Guide for I2C-old to the current I2C API
+July 2002
+For Linux Kernel v2.5.x
+Frank Davis <fdavis@si.rr.com>
+-------------------------------------------------------
+
+There exists several kernel drivers that are using an old version of the I2C
+API. These drivers need to be converted to the current (kernel 2.5.x) version.
+The following document provides a guideline to make the appropriate changes to
+the affected drivers. There maybe slight modifications to this guide that are 
+specific to the driver you are working on. If you see {driver_name}, replace 
+that with the respective name of the driver, such as saa7110.c , {driver_name} 
+= saa7110.
+
+-------------------------------------------------------
+
+Step 1: Include the right header file
+ 
+Perform the following change within the driver
+ 
+#include <linux/i2c-old.h> --> #include <linux/i2c.h>
+
+Step 2: Add and set the i2c modes
+
+Add the following code near the top of the driver
+
+static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END };	
+static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data  = {
+	normal_i2c , normal_i2c_range,
+	probe , probe_range,
+	ignore , ignore_range,
+	force
+};
+
+static struct i2c_client client_template;
+
+Step 3: Modify the driver info struct
+
+Within the struct for the driver , such as struct {driver_name}  ,  make the 
+following change ,
+struct i2c_bus *bus --> struct i2c_client *client
+
+Make changes where this change affects references within the file.
+
+Add a semaphore to the driver struct (as above)
+
+struct semaphore lock 
+
+Step 5: Remove specific read and write functions
+
+Remove the driver specific write and read functions, usually in the form:
+{driver_name}_write , {driver_name}_read , {driver_name}_write_block , etc.
+
+Step 6: Update the write and read functions for the current I2C API
+
+Replace all references of {driver_name}_write with i2c_smbus_write_byte_data
+Replace all references of {driver_name}_read with i2c_smbus_read_byte_data or
+i2c_smbus_read_byte , depending on args passed in.
+
+** Ensure that these functions pass in the i2c_client *client , NOT the
+decoder/encoder that was passed in the driver specific write and read
+functions. 
+ 
+Step 7: Modify the driver's attach function
+
+Change the driver attach function prototype :
+{driver_name}_attach(struct i2c_device *device) --> {driver_name}_attach(struct 
+i2c_adapter *adap, int addr , unsigned short flags, int kind)
+
+Create a i2c_client client...
+Add the following (where "decoder" is a reference to a struct for the driver
+info:
+
+struct i2c_client *client;
+client = kmalloc(sizeof(*client), GFP_KERNEL);
+if(client == NULL)
+	return -ENOMEM;
+client_template.adapter = adap;
+client_template.addr  = addr;
+memcpy(client, &client_template, sizeof(*client));
+strcpy(client->name , "{driver_name}");
+decoder->client = client;
+client->data = decoder;
+decoder->addr = addr;
+
+Towards the end of the function, add:
+
+init_MUTEX(&decoder->lock);
+i2c_attach_client(client);
+
+
+Step 8: Modify the driver's detach function
+
+Change the driver detach function prototype :
+{driver_name}_detach(struct i2c_device *device) --> {driver_name}_detach(struct 
+i2c_client *client)
+
+In the beginning of the detach function, add:
+i2c_detach_client(client);
+
+Towards the end of the detach function, add:
+kfree(client->data);
+kfree(client);
+
+Step 9: Modify the driver's command function
+
+Change the driver command function prototype :
+
+Step 10: Add the probe function after the driver's attach function.
+
+Add the following code:
+
+static int {driver_name}_probe(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, {driver_name}_attach);
+
+}
+
+Step 11: Modify the driver's i2c_driver
+
+Find the i2c_driver , such as
+static struct i2c_driver i2c_driver_saa7110
+It is usually located towards the end of the driver 
+Replace the values from I2C_DRIVERID_{something} to {driver_name}_attach, and 
+add the following
+I2C_DRIVERID_{driver_name} , // verify by looking in include/linux/i2c-id.h 
+I2C_DF_NOTIFY,
+{driver_name}_probe, 
+....
+
+Step 12: Adding the i2c_client 
+
+Add the i2c_client to the driver. Add the following code:
+
+static struct i2c_client client_template = {
+	"{driver_name}_client",
+	-1,
+	0,
+	0,
+	NULL,
+	{i2c_driver reference}
+};
+
+Step 13: Registering and Unregistering
+
+Replace i2c_register_driver with i2c_add_driver
+Replace i2c_unregister_driver with i2c_del_driver
+
+-------------------------------------------------------
+
+Example:
+
+The following patch provides the i2c coversion patch for the saa7110 driver
+based on the above guide (for clarity).
+
+
+--- drivers/media/video/saa7110.c.old	Fri Jun 28 10:22:52 2002
++++ drivers/media/video/saa7110.c	Thu Jul  4 16:51:08 2002
+@@ -26,7 +26,7 @@
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ 
+-#include <linux/i2c-old.h>
++#include <linux/i2c.h>
+ #include <linux/videodev.h>
+ #include "linux/video_decoder.h"
+ 
+@@ -37,13 +37,31 @@
+ 
+ #define	I2C_SAA7110		0x9C	/* or 0x9E */
+ 
++#define IF_NAME	"saa7110"
+ #define	I2C_DELAY		10	/* 10 us or 100khz */
+ 
++static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
++static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
++static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
++
++static struct i2c_client_address_data addr_data = {
++	normal_i2c, normal_i2c_range,
++	probe, probe_range,
++	ignore, ignore_range,
++	force
++};
++
++static struct i2c_client client_template;
++
+ struct saa7110 {
+-	struct	i2c_bus	*bus;
++	struct i2c_client *client;
+ 	int		addr;
+ 	unsigned char	reg[36];
+-
++	struct semaphore lock;
+ 	int		norm;
+ 	int		input;
+ 	int		enable;
+@@ -54,67 +72,10 @@
+ };
+ 
+ /* ----------------------------------------------------------------------- */
+-/* I2C support functions						   */
+-/* ----------------------------------------------------------------------- */
+-static
+-int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data)
+-{
+-	int ack;
+-
+-	LOCK_I2C_BUS(decoder->bus);
+-	i2c_start(decoder->bus);
+-	i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
+-	i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY);
+-	ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY);
+-	i2c_stop(decoder->bus);
+-	decoder->reg[subaddr] = data;
+-	UNLOCK_I2C_BUS(decoder->bus);
+-	return ack;
+-}
+-
+-static
+-int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len)
+-{
+-	unsigned subaddr = *data;
+-
+-	LOCK_I2C_BUS(decoder->bus);
+-        i2c_start(decoder->bus);
+-        i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY);
+-	while (len-- > 0) {
+-                if (i2c_sendbyte(decoder->bus,*data,0)) {
+-                        i2c_stop(decoder->bus);
+-                        UNLOCK_I2C_BUS(decoder->bus);
+-                        return -EAGAIN;
+-                }
+-		decoder->reg[subaddr++] = *data++;
+-        }
+-	i2c_stop(decoder->bus);
+-	UNLOCK_I2C_BUS(decoder->bus);
+-
+-	return 0;
+-}
+-
+-static
+-int saa7110_read(struct saa7110* decoder)
+-{
+-	int data;
+-
+-	LOCK_I2C_BUS(decoder->bus);
+-	i2c_start(decoder->bus);
+-	i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
+-	i2c_start(decoder->bus);
+-	i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY);
+-	data = i2c_readbyte(decoder->bus, 1);
+-	i2c_stop(decoder->bus);
+-	UNLOCK_I2C_BUS(decoder->bus);
+-	return data;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+ /* SAA7110 functions							   */
+ /* ----------------------------------------------------------------------- */
+ static
+-int saa7110_selmux(struct i2c_device *device, int chan)
++int saa7110_selmux(struct i2c_client *client, int chan)
+ {
+ static	const unsigned char modes[9][8] = {
+ /* mode 0 */	{ 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
+@@ -126,61 +87,59 @@
+ /* mode 6 */	{ 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
+ /* mode 7 */	{ 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
+ /* mode 8 */	{ 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
+-	struct saa7110* decoder = device->data;
+ 	const unsigned char* ptr = modes[chan];
+ 
+-	saa7110_write(decoder,0x06,ptr[0]);	/* Luminance control	*/
+-	saa7110_write(decoder,0x20,ptr[1]);	/* Analog Control #1	*/
+-	saa7110_write(decoder,0x21,ptr[2]);	/* Analog Control #2	*/
+-	saa7110_write(decoder,0x22,ptr[3]);	/* Mixer Control #1	*/
+-	saa7110_write(decoder,0x2C,ptr[4]);	/* Mixer Control #2	*/
+-	saa7110_write(decoder,0x30,ptr[5]);	/* ADCs gain control	*/
+-	saa7110_write(decoder,0x31,ptr[6]);	/* Mixer Control #3	*/
+-	saa7110_write(decoder,0x21,ptr[7]);	/* Analog Control #2	*/
++	i2c_smbus_write_byte_data(client,0x06,ptr[0]);	/* Luminance control	*/
++	i2c_smbus_write_byte_data(client,0x20,ptr[1]);	/* Analog Control #1	*/
++	i2c_smbus_write_byte_data(client,0x21,ptr[2]);	/* Analog Control #2	*/
++	i2c_smbus_write_byte_data(client,0x22,ptr[3]);	/* Mixer Control #1	*/
++	i2c_smbus_write_byte_data(client,0x2C,ptr[4]);	/* Mixer Control #2	*/
++	i2c_smbus_write_byte_data(client,0x30,ptr[5]);	/* ADCs gain control	*/
++	i2c_smbus_write_byte_data(client,0x31,ptr[6]);	/* Mixer Control #3	*/
++	i2c_smbus_write_byte_data(client,0x21,ptr[7]);	/* Analog Control #2	*/
+ 
+ 	return 0;
+ }
+ 
+ static
+-int determine_norm(struct i2c_device* dev)
++int determine_norm(struct i2c_client* client)
+ {
+-	struct	saa7110* decoder = dev->data;
+ 	int	status;
+ 
+ 	/* mode changed, start automatic detection */
+-	status = saa7110_read(decoder);
++	status = i2c_smbus_read_byte(client);
+ 	if ((status & 3) == 0) {
+-		saa7110_write(decoder,0x06,0x80);
++		i2c_smbus_write_byte_data(client,0x06,0x80);
+ 		if (status & 0x20) {
+-			DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name));
+-			saa7110_write(decoder,0x2E,0x81);
++			DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name));
++			i2c_smbus_write_byte_data(client,0x2E,0x81);
+ 			return VIDEO_MODE_NTSC;
+ 		}
+-		DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name));
+-		saa7110_write(decoder,0x2E,0x9A);
++		DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name));
++		i2c_smbus_write_byte_data(client,0x2E,0x9A);
+ 		return VIDEO_MODE_PAL;
+ 	}
+ 
+-	saa7110_write(decoder,0x06,0x00);
++	i2c_smbus_write_byte_data(client,0x06,0x00);
+ 	if (status & 0x20) {	/* 60Hz */
+-		DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name));
+-		saa7110_write(decoder,0x0D,0x06);
+-		saa7110_write(decoder,0x11,0x2C);
+-		saa7110_write(decoder,0x2E,0x81);
++		DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name));
++		i2c_smbus_write_byte_data(client,0x0D,0x06);
++		i2c_smbus_write_byte_data(client,0x11,0x2C);
++		i2c_smbus_write_byte_data(client,0x2E,0x81);
+ 		return VIDEO_MODE_NTSC;
+ 	}
+ 
+ 	/* 50Hz -> PAL/SECAM */
+-	saa7110_write(decoder,0x0D,0x06);
+-	saa7110_write(decoder,0x11,0x59);
+-	saa7110_write(decoder,0x2E,0x9A);
++	i2c_smbus_write_byte_data(client,0x0D,0x06);
++	i2c_smbus_write_byte_data(client,0x11,0x59);
++	i2c_smbus_write_byte_data(client,0x2E,0x9A);
+ 
+ 	mdelay(150);	/* pause 150 ms */
+ 
+-	status = saa7110_read(decoder);
++	status = i2c_smbus_read_byte(client);
+ 	if ((status & 0x03) == 0x01) {
+ 		DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
+-		saa7110_write(decoder,0x0D,0x07);
++		i2c_smbus_write_byte_data(client,0x0D,0x07);
+ 		return VIDEO_MODE_SECAM;
+ 	}
+ 	DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
+@@ -188,7 +147,7 @@
+ }
+ 
+ static
+-int saa7110_attach(struct i2c_device *device)
++int saa7110_attach(struct i2c_adapter *adap, int  addr, unsigned short flags, int kind)
+ {
+ static	const unsigned char initseq[] = {
+ 	     0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
+@@ -198,20 +157,28 @@
+ 		0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
+ 		0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
+ 		0x40, 0x75, 0x01, 0x8C, 0x03};
+-	struct	saa7110*	decoder;
++	struct	saa7110	*decoder;
++	struct i2c_client *client;
+ 	int			rv;
+-
+-	device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
+-	if (device->data == 0)
++	client=kmalloc(sizeof(*client), GFP_KERNEL);
++	if(client == NULL) 
+ 		return -ENOMEM;
+-
+-	MOD_INC_USE_COUNT;
++	client_template.adapter = adap;
++	client_template.addr = addr;
++	memcpy(client, &client_template, sizeof(*client));
++
++	decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
++	if (decoder == NULL) {
++		kfree(client);
++		return -ENOMEM;
++		}
+ 
+ 	/* clear our private data */
+-	memset(decoder, 0, sizeof(struct saa7110));
+-	strcpy(device->name, "saa7110");
+-	decoder->bus = device->bus;
+-	decoder->addr = device->addr;
++	memset(decoder, 0, sizeof(*decoder));
++	strcpy(client->name, IF_NAME);
++	decoder->client = client;
++	client->data = decoder;
++	decoder->addr = addr;
+ 	decoder->norm = VIDEO_MODE_PAL;
+ 	decoder->input = 0;
+ 	decoder->enable = 1;
+@@ -220,40 +187,52 @@
+ 	decoder->hue = 32768;
+ 	decoder->sat = 32768;
+ 
+-	rv = saa7110_write_block(decoder, initseq, sizeof(initseq));
++	rv = i2c_master_send(client, initseq, sizeof(initseq));
+ 	if (rv < 0)
+-		printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv);
++		printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv);
+ 	else {
+-		saa7110_write(decoder,0x21,0x16);
+-		saa7110_write(decoder,0x0D,0x04);
+-		DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)));
+-		saa7110_write(decoder,0x0D,0x06);
++		i2c_smbus_write_byte_data(client,0x21,0x16);
++		i2c_smbus_write_byte_data(client,0x0D,0x04);
++		DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client)));
++		i2c_smbus_write_byte_data(client,0x0D,0x06);
+ 	}
+ 
++	init_MUTEX(&decoder->lock);
++	i2c_attach_client(client);
++	MOD_INC_USE_COUNT;
+ 	/* setup and implicit mode 0 select has been performed */
+ 	return 0;
+ }
+ 
++static 
++int saa7110_probe(struct i2c_adapter *adap) 
++{
++	return i2c_probe(adap, &addr_data, saa7110_attach);
++}
++
+ static
+-int saa7110_detach(struct i2c_device *device)
++int saa7110_detach(struct i2c_client *client)
+ {
+-	struct saa7110* decoder = device->data;
++	struct saa7110* decoder = client->data;
+ 
+-	DEBUG(printk(KERN_INFO "%s_detach\n",device->name));
++	i2c_detach_client(client);
++
++	DEBUG(printk(KERN_INFO "%s_detach\n",client->name));
+ 
+ 	/* stop further output */
+-	saa7110_write(decoder,0x0E,0x00);
++	i2c_smbus_write_byte_data(client,0x0E,0x00);
+ 
+-	kfree(device->data);
++	kfree(decoder);
++	kfree(client);
+ 
+ 	MOD_DEC_USE_COUNT;
+ 	return 0;
+ }
+ 
+ static
+-int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg)
++int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ {
+-	struct saa7110* decoder = device->data;
++	struct saa7110* decoder = client->data;
+ 	int	v;
+ 
+ 	switch (cmd) {
+@@ -272,11 +251,11 @@
+ 
+ 	 case DECODER_GET_STATUS:
+ 		{
+-			struct saa7110* decoder = device->data;
++			struct saa7110* decoder = client->data;
+ 			int status;
+ 			int res = 0;
+ 
+-			status = i2c_read(device->bus,device->addr|1);
++			status = i2c_smbus_read_byte(client);
+ 			if (status & 0x40)
+ 				res |= DECODER_STATUS_GOOD;
+ 			if (status & 0x03)
+@@ -301,26 +280,26 @@
+ 		v = *(int*)arg;
+ 		if (decoder->norm != v) {
+ 			decoder->norm = v;
+-			saa7110_write(decoder, 0x06, 0x00);
++			i2c_smbus_write_byte_data(client, 0x06, 0x00);
+ 			switch (v) {
+ 			 case VIDEO_MODE_NTSC:
+-				saa7110_write(decoder, 0x0D, 0x06);
+-				saa7110_write(decoder, 0x11, 0x2C);
+-				saa7110_write(decoder, 0x30, 0x81);
+-				saa7110_write(decoder, 0x2A, 0xDF);
++				i2c_smbus_write_byte_data(client, 0x0D, 0x06);
++				i2c_smbus_write_byte_data(client, 0x11, 0x2C);
++				i2c_smbus_write_byte_data(client, 0x30, 0x81);
++				i2c_smbus_write_byte_data(client, 0x2A, 0xDF);
+ 				break;
+ 			 case VIDEO_MODE_PAL:
+-				saa7110_write(decoder, 0x0D, 0x06);
+-				saa7110_write(decoder, 0x11, 0x59);
+-				saa7110_write(decoder, 0x2E, 0x9A);
++				i2c_smbus_write_byte_data(client, 0x0D, 0x06);
++				i2c_smbus_write_byte_data(client, 0x11, 0x59);
++				i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
+ 				break;
+ 			 case VIDEO_MODE_SECAM:
+-				saa7110_write(decoder, 0x0D, 0x07);
+-				saa7110_write(decoder, 0x11, 0x59);
+-				saa7110_write(decoder, 0x2E, 0x9A);
++				i2c_smbus_write_byte_data(client, 0x0D, 0x07);
++				i2c_smbus_write_byte_data(client, 0x11, 0x59);
++				i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
+ 				break;
+ 			 case VIDEO_MODE_AUTO:
+-				*(int*)arg = determine_norm(device);
++				*(int*)arg = determine_norm(client);
+ 				break;
+ 			 default:
+ 				return -EPERM;
+@@ -334,7 +313,7 @@
+ 			return -EINVAL;
+ 		if (decoder->input != v) {
+ 			decoder->input = v;
+-			saa7110_selmux(device, v);
++			saa7110_selmux(client, v);
+ 		}
+ 		break;
+ 
+@@ -349,7 +328,7 @@
+ 		v = *(int*)arg;
+ 		if (decoder->enable != v) {
+ 			decoder->enable = v;
+-			saa7110_write(decoder,0x0E, v ? 0x18 : 0x00);
++			i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00);
+ 		}
+ 		break;
+ 
+@@ -360,22 +339,22 @@
+ 			if (decoder->bright != pic->brightness) {
+ 				/* We want 0 to 255 we get 0-65535 */
+ 				decoder->bright = pic->brightness;
+-				saa7110_write(decoder, 0x19, decoder->bright >> 8);
++				i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8);
+ 			}
+ 			if (decoder->contrast != pic->contrast) {
+ 				/* We want 0 to 127 we get 0-65535 */
+ 				decoder->contrast = pic->contrast;
+-				saa7110_write(decoder, 0x13, decoder->contrast >> 9);
++				i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9);
+ 			}
+ 			if (decoder->sat != pic->colour) {
+ 				/* We want 0 to 127 we get 0-65535 */
+ 				decoder->sat = pic->colour;
+-				saa7110_write(decoder, 0x12, decoder->sat >> 9);
++				i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9);
+ 			}
+ 			if (decoder->hue != pic->hue) {
+ 				/* We want -128 to 127 we get 0-65535 */
+ 				decoder->hue = pic->hue;
+-				saa7110_write(decoder, 0x07, (decoder->hue>>8)-128);
++				i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128);
+ 			}
+ 		}
+ 		break;
+@@ -383,7 +362,7 @@
+ 	 case DECODER_DUMP:
+ 		for (v=0; v<34; v+=16) {
+ 			int j;
+-			DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v));
++			DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v));
+ 			for (j=0; j<16; j++) {
+ 				DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j]));
+ 			}
+@@ -402,24 +381,30 @@
+ 
+ static struct i2c_driver i2c_driver_saa7110 =
+ {
+-	"saa7110",			/* name */
+-
+-	I2C_DRIVERID_VIDEODECODER,	/* in i2c.h */
+-	I2C_SAA7110, I2C_SAA7110+1,	/* Addr range */
+-
+-	saa7110_attach,
++	IF_NAME,			/* name */
++	I2C_DRIVERID_SAA7110,	/* in i2c.h */
++	I2C_DF_NOTIFY,	/* Addr range */
++	saa7110_probe,
+ 	saa7110_detach,
+ 	saa7110_command
+ };
++static struct i2c_client client_template = {
++	"saa7110_client",
++	-1,
++	0,
++	0,
++	NULL,
++	&i2c_driver_saa7110
++};
+ 
+ static int saa7110_init(void)
+ {
+-	return i2c_register_driver(&i2c_driver_saa7110);
++	return i2c_add_driver(&i2c_driver_saa7110);
+ }
+ 
+ static void saa7110_exit(void)
+ {
+-	i2c_unregister_driver(&i2c_driver_saa7110);
++	i2c_del_driver(&i2c_driver_saa7110);
+ }
+ 
+ 
+ 
+
diff -Nru a/Documentation/i2c/i2c-pport b/Documentation/i2c/i2c-pport
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/i2c/i2c-pport	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,45 @@
+Primitive parallel port is driver for i2c bus, which exploits 
+features of modern bidirectional parallel ports. 
+
+Bidirectional ports have particular bits connected in following way:
+   
+                        |
+            /-----|     R
+         --o|     |-----|
+      read  \-----|     /------- Out pin
+                      |/
+                   - -|\
+                write   V
+                        |
+                       ---  
+
+
+It means when output is set to 1 we can read the port. Therefore 
+we can use 2 pins of parallel port as SDA and SCL for i2c bus. It 
+is not necessary to add any external - additional parts, we can 
+read and write the same port simultaneously.
+	I only use register base+2 so it is possible to use all 
+8 data bits of parallel port for other applications (I have 
+connected EEPROM and LCD display). I do not use bit Enable Bi-directional
+ Port. The only disadvantage is we can only support 5V chips.
+
+Layout:
+
+Cannon 25 pin
+
+SDA - connect to pin 14 (Auto Linefeed)
+SCL - connect to pin 16 (Initialize Printer)
+GND - connect to pin 18-25
++5V - use external supply (I use 5V from 3.5" floppy connector)
+      
+no pullups  requied
+
+Module parameters:
+
+base = 0xXXX
+XXX - 278 or 378
+
+That's all.
+
+Daniel Smolik
+marvin@sitour.cz
diff -Nru a/Documentation/i2c/i2c-velleman b/Documentation/i2c/i2c-velleman
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/i2c/i2c-velleman	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,27 @@
+i2c-velleman driver
+-------------------
+This is a driver for i2c-hw access for Velleman K9000 and other adapters.
+
+Useful links
+------------
+Velleman:
+	http://www.velleman.be/
+
+Velleman K8000 Howto:
+	http://howto.htlw16.ac.at/k8000-howto.html
+
+
+K8000 and K8005 libraries
+-------------------------
+The project has lead to new libs for the Velleman K8000 and K8005..
+LIBK8000 v1.99.1 and LIBK8005 v0.21
+
+With these libs you can control the K8000 and K8005 with the original
+simple commands which are in the original Velleman software.
+Like SetIOchannel, ReadADchannel, SendStepCCWFull and many more.
+Via i2c kernel device /dev/velleman
+
+The libs can be found on http://groups.yahoo.com/group/k8000/files/linux/
+
+The Velleman K8000 interface card on http://www.velleman.be/kits/k8000.htm
+The Velleman K8005 steppermotorcard on http://www.velleman.be/kits/k8005.htm
diff -Nru a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol
--- a/Documentation/i2c/smbus-protocol	Tue Aug 27 12:28:05 2002
+++ b/Documentation/i2c/smbus-protocol	Tue Aug 27 12:28:05 2002
@@ -1,3 +1,10 @@
+SMBus Protocol Summary
+======================
+The following is a summary of the SMBus protocol. It applies to
+all revisions of the protocol (1.0, 1.1, and 2.0).
+Certain protocol features which are not supported by
+this package are briefly described at the end of this document.
+
 Some adapters understand only the SMBus (System Management Bus) protocol,
 which is a subset from the I2C protocol. Fortunately, many devices use
 only the same subset, which makes it possible to put them on an SMBus.
@@ -6,7 +13,7 @@
 I2C protocol). This makes it possible to use the device driver on both
 SMBus adapters and I2C adapters (the SMBus command set is automatically
 translated to I2C on I2C adapters, but plain I2C commands can not be
-handled at all on a pure SMBus adapter).
+handled at all on most pure SMBus adapters).
 
 Below is a list of SMBus commands.
 
@@ -109,7 +116,7 @@
 SMBus Block Read
 ================
 
-This command reads a block of upto 32 bytes from a device, from a 
+This command reads a block of up to 32 bytes from a device, from a 
 designated register that is specified through the Comm byte. The amount
 of data is specified by the device in the Count byte.
 
@@ -120,8 +127,90 @@
 SMBus Block Write
 =================
 
-The opposite of the Block Read command, this writes upto 32 bytes to 
+The opposite of the Block Read command, this writes up to 32 bytes to 
 a device, to a designated register that is specified through the
 Comm byte. The amount of data is specified in the Count byte.
 
 S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P
+
+
+SMBus Block Process Call
+========================
+
+SMBus Block Process Call was introduced in Revision 2.0 of the specification.
+
+This command selects a device register (through the Comm byte), sends
+1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return.
+
+S Addr Wr [A] Comm [A] Count [A] Data [A] ...
+                             S Addr Rd [A] [Count] A [Data] ... A P
+
+
+SMBus Host Notify
+=================
+
+This command is sent from a SMBus device acting as a master to the
+SMBus host acting as a slave.
+It is the same form as Write Word, with the command code replaced by the
+alerting device's address.
+
+[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]
+
+
+Packet Error Checking (PEC)
+===========================
+Packet Error Checking was introduced in Revision 1.1 of the specification.
+
+PEC adds a CRC-8 error-checking byte to all transfers.
+
+
+Address Resolution Protocol (ARP)
+=================================
+The Address Resolution Protocol was introduced in Revision 2.0 of
+the specification. It is a higher-layer protocol which uses the
+messages above.
+
+ARP adds device enumeration and dynamic address assignment to
+the protocol. All ARP communications use slave address 0x61 and
+require PEC checksums.
+
+
+I2C Block Transactions
+======================
+The following I2C block transactions are supported by the
+SMBus layer and are described here for completeness.
+I2C block transactions do not limit the number of bytes transferred
+but the SMBus layer places a limit of 32 bytes.
+
+
+I2C Block Read
+==============
+
+This command reads a block of bytes from a device, from a 
+designated register that is specified through the Comm byte.
+
+S Addr Wr [A] Comm [A] 
+           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+
+
+I2C Block Read (2 Comm bytes)
+=============================
+
+This command reads a block of bytes from a device, from a 
+designated register that is specified through the two Comm bytes.
+
+S Addr Wr [A] Comm1 [A] Comm2 [A] 
+           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+
+
+I2C Block Write
+===============
+
+The opposite of the Block Read command, this writes bytes to 
+a device, to a designated register that is specified through the
+Comm byte. Note that command lengths of 0, 2, or more bytes are
+supported as they are indistinguishable from data.
+
+S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
+
+
diff -Nru a/Documentation/i2c/summary b/Documentation/i2c/summary
--- a/Documentation/i2c/summary	Tue Aug 27 12:27:59 2002
+++ b/Documentation/i2c/summary	Tue Aug 27 12:27:59 2002
@@ -59,16 +59,16 @@
 i2c-algo-8xx:    An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
 i2c-algo-bit:    A bit-banging algorithm
 i2c-algo-pcf:    A PCF 8584 style algorithm
-i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT)
+i2c-algo-ibmocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
 
 Adapter drivers
 ---------------
 
 i2c-elektor:     Elektor ISA card (uses i2c-algo-pcf)
 i2c-elv:         ELV parallel port adapter (uses i2c-algo-bit)
-i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h)
+i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatched)
 i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
-i2c-ppc405:      IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT)
+i2c-adap_ibmocp:      IBM 4xx processor I2C device (uses i2c-algo-ibmocp) (NOT BUILT BY DEFAULT)
 i2c-pport:       Primitive parallel port adapter (uses i2c-algo-bit)
 i2c-rpx:         RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
 i2c-velleman:    Velleman K9000 parallel port adapter (uses i2c-algo-bit)
diff -Nru a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
--- a/Documentation/i2c/writing-clients	Tue Aug 27 12:28:01 2002
+++ b/Documentation/i2c/writing-clients	Tue Aug 27 12:28:01 2002
@@ -365,7 +365,7 @@
 
 The detect client function is called by i2c_probe or i2c_detect.
 The `kind' parameter contains 0 if this call is due to a `force'
-parameter, and 0 otherwise (for i2c_detect, it contains 0 if
+parameter, and -1 otherwise (for i2c_detect, it contains 0 if
 this call is due to the generic `force' parameter, and the chip type
 number if it is due to a specific `force' parameter).
 
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Aug 27 12:28:07 2002
+++ b/MAINTAINERS	Tue Aug 27 12:28:07 2002
@@ -132,6 +132,12 @@
 L:	linux-m68k@lists.linux-m68k.org
 S:	Maintained
 
+AIO
+P:	Benjamin LaHaise
+M:	bcrl@redhat.com
+L:	linux-aio@kvack.org
+S:	Supported
+
 ACENIC DRIVER
 P:	Jes Sorensen
 M:	jes@trained-monkey.org
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Aug 27 12:27:59 2002
+++ b/Makefile	Tue Aug 27 12:27:59 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 31
+SUBLEVEL = 32
 EXTRAVERSION =
 
 # *DOCUMENTATION*
@@ -43,9 +43,6 @@
 	  else echo sh; fi ; fi)
 TOPDIR	:= $(CURDIR)
 
-HPATH   	= $(TOPDIR)/include
-FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
-
 HOSTCC  	= gcc
 HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
 
@@ -151,7 +148,7 @@
 NOSTDINC_FLAGS  = -nostdinc -iwithprefix include
 
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
-	CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
+	CONFIG_SHELL TOPDIR HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
 	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS PERL
 
 export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS OBJCOPYFLAGS
@@ -199,11 +196,17 @@
 
 #	If .config doesn't exist - tough luck
 
-.config:
+.config: arch/$(ARCH)/config.in $(shell find . -name Config.in)
+	@echo '***'
+	@if [ -f $@ ]; then \
+	  echo '*** The tree was updated, so your .config may be'; \
+	  echo '*** out of date!'; \
+	else \
+	  echo '*** You have not yet configured your kernel!'; \
+	fi
 	@echo '***'
-	@echo '*** You have not yet configured your kernel!'
-	@echo '*** Please run some configurator (do "make xconfig" or'
-	@echo '*** "make menuconfig" or "make oldconfig" or "make config").'
+	@echo '*** Please run some configurator (e.g. "make oldconfig" or'
+	@echo '*** "make menuconfig" or "make xconfig").'
 	@echo '***'
 	@exit 1
 
@@ -227,7 +230,7 @@
 # standard CFLAGS
 #
 
-CPPFLAGS := -D__KERNEL__ -I$(HPATH)
+CPPFLAGS := -D__KERNEL__ -I$(objtree)/include
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
 	  -fomit-frame-pointer -fno-strict-aliasing -fno-common
@@ -312,6 +315,12 @@
 prepare: include/linux/version.h include/asm include/config/MARKER
 	@echo '  Starting the build. KBUILD_BUILTIN=$(KBUILD_BUILTIN) KBUILD_MODULES=$(KBUILD_MODULES)'
 
+#	This can be used by arch/$ARCH/Makefile to preprocess
+#	their vmlinux.lds.S file
+
+arch/$ARCH/vmlinux.lds.s: arch/$ARCH/vmlinux.lds.S
+	$(CPP) $(CPPFLAGS) $(CPPFLAGS_$@) -P -C -U$(ARCH) $< -o $@
+
 # Single targets
 # ---------------------------------------------------------------------------
 
@@ -428,7 +437,7 @@
 #	Build modules
 
 ifdef CONFIG_MODVERSIONS
-MODFLAGS += -include $(HPATH)/linux/modversions.h
+MODFLAGS += -include $(objtree)/include/linux/modversions.h
 endif
 
 .PHONY: modules
@@ -565,28 +574,28 @@
 
 menuconfig:
 	@$(MAKE) -C scripts lxdialog
-	$(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Menuconfig arch/$(ARCH)/config.in
 
 config:
-	$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure arch/$(ARCH)/config.in
 
 oldconfig:
-	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure -d arch/$(ARCH)/config.in
 
 randconfig:
-	$(CONFIG_SHELL) scripts/Configure -r arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure -r arch/$(ARCH)/config.in
 
 allyesconfig:
-	$(CONFIG_SHELL) scripts/Configure -y arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure -y arch/$(ARCH)/config.in
 
 allnoconfig:
-	$(CONFIG_SHELL) scripts/Configure -n arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure -n arch/$(ARCH)/config.in
 
 allmodconfig:
-	$(CONFIG_SHELL) scripts/Configure -m arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) $(src)/scripts/Configure -m arch/$(ARCH)/config.in
 
 defconfig:
-	yes '' | $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+	yes '' | $(CONFIG_SHELL) $(src)/scripts/Configure -d arch/$(ARCH)/config.in
 
 # Cleaning up
 # ---------------------------------------------------------------------------
@@ -631,12 +640,9 @@
 	sound/oss/pndspini.c \
 	drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
 	.version .config* config.in config.old \
-	scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
-	scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
 	.menuconfig.log \
 	include/asm \
-	.hdepend scripts/split-include scripts/docproc \
-	scripts/fixdep $(TOPDIR)/include/linux/modversions.h \
+	.hdepend $(TOPDIR)/include/linux/modversions.h \
 	tags TAGS kernel.spec \
 	.tmpversion
 
@@ -666,6 +672,7 @@
 		-type f -print | xargs rm -f
 	@rm -f $(MRPROPER_FILES)
 	@rm -rf $(MRPROPER_DIRS)
+	@$(MAKE) -C scripts mrproper
 	@$(MAKE) -f Documentation/DocBook/Makefile mrproper
 
 distclean: mrproper
diff -Nru a/arch/alpha/Config.help b/arch/alpha/Config.help
--- a/arch/alpha/Config.help	Tue Aug 27 12:27:59 2002
+++ b/arch/alpha/Config.help	Tue Aug 27 12:27:59 2002
@@ -576,13 +576,24 @@
   unless you really know what this hack does.
 
 CONFIG_SRM_ENV
-  If you enable this option, a subdirectory called srm_environment
-  will give you access to the most important SRM environment
-  variables. If you've got an Alpha style system supporting
-  SRC, then it is a good idea to say Yes or Module to this driver.
+  If you enable this option, a subdirectory inside /proc called
+  /proc/srm_environment will give you access to the all important
+  SRM environment variables (those which have a name) and also
+  to all others (by their internal number).
+
+  SRM is something like a BIOS for Alpha machines. There are some
+  other such BIOSes, like AlphaBIOS, which this driver cannot
+  support (hey, that's not SRM!).
+
+  Despite the fact that this driver doesn't work on all Alphas (but
+  only on those which have SRM as their firmware), it's save to
+  build it even if your particular machine doesn't know about SRM
+  (or if you intend to compile a generic kernel). It will simply
+  not create those subdirectory in /proc (and give you some warning,
+  of course).
 
   This driver is also available as a module and will be called
-  srm_env.o if you build it as a module.
+  srm_env.o then.
 
 CONFIG_DEBUG_KERNEL
   Say Y here if you are developing drivers or trying to debug and
diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile
--- a/arch/alpha/Makefile	Tue Aug 27 12:27:59 2002
+++ b/arch/alpha/Makefile	Tue Aug 27 12:27:59 2002
@@ -10,7 +10,7 @@
 
 NM := $(NM) -B
 
-LDFLAGS_vmlinux = -static -T arch/alpha/vmlinux.lds -N #-relax
+LDFLAGS_vmlinux = -static -T arch/alpha/vmlinux.lds.s -N #-relax
 CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
 
 # Determine if we can use the BWX instructions with GAS.
@@ -124,13 +124,9 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
-	rm -f arch/alpha/vmlinux.lds
 	rm -f include/asm-alpha/asm_offsets.h
 
-vmlinux: arch/alpha/vmlinux.lds
-
-arch/alpha/vmlinux.lds: arch/alpha/vmlinux.lds.in
-	$(CPP) $(CPPFLAGS) -xc -P arch/alpha/vmlinux.lds.in -o arch/alpha/vmlinux.lds
+vmlinux: arch/alpha/vmlinux.lds.s
 
 bootpfile:
 	@$(MAKEBOOT) bootpfile
diff -Nru a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
--- a/arch/alpha/boot/Makefile	Tue Aug 27 12:28:01 2002
+++ b/arch/alpha/boot/Makefile	Tue Aug 27 12:28:01 2002
@@ -81,7 +81,7 @@
 	$(OBJSTRIP) -vb bootpheader tools/bootph
 
 $(OBJSTRIP): $(OBJSTRIP).c
-	$(HOSTCC) $(HOSTCFLAGS) -I$(HPATH) $(OBJSTRIP).c -o $(OBJSTRIP)
+	$(HOSTCC) $(HOSTCFLAGS) $< -o $@
 
 tools/mkbb: tools/mkbb.c
 	$(HOSTCC) tools/mkbb.c -o tools/mkbb
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in	Tue Aug 27 12:28:02 2002
+++ b/arch/alpha/config.in	Tue Aug 27 12:28:02 2002
@@ -283,10 +283,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
 
@@ -314,6 +310,8 @@
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+
   mainmenu_option next_comment
   comment 'Network device support'
 
diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c	Tue Aug 27 12:27:59 2002
+++ b/arch/alpha/kernel/alpha_ksyms.c	Tue Aug 27 12:27:59 2002
@@ -40,7 +40,6 @@
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-extern spinlock_t kernel_flag;
 extern spinlock_t rtc_lock;
 
 /* these are C runtime functions with special calling conventions: */
@@ -207,7 +206,6 @@
  */
 
 #ifdef CONFIG_SMP
-EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(flush_tlb_all);
 EXPORT_SYMBOL(flush_tlb_mm);
diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
--- a/arch/alpha/kernel/smp.c	Tue Aug 27 12:28:02 2002
+++ b/arch/alpha/kernel/smp.c	Tue Aug 27 12:28:02 2002
@@ -67,8 +67,6 @@
 	IPI_CPU_STOP,
 };
 
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 /* Set to a secondary's cpuid when it comes online.  */
 static int smp_secondary_alive __initdata = 0;
 
diff -Nru a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c
--- a/arch/alpha/kernel/srm_env.c	Tue Aug 27 12:28:01 2002
+++ b/arch/alpha/kernel/srm_env.c	Tue Aug 27 12:28:01 2002
@@ -33,6 +33,15 @@
  * Changelog
  * ~~~~~~~~~
  *
+ * Thu, 22 Aug 2002 15:10:43 +0200
+ * 	- Update Config.help entry. I got a number of emails asking
+ * 	  me to tell their senders if they could make use of this
+ * 	  piece of code... So: "SRM is something like BIOS for your
+ * 	  Alpha"
+ * 	- Update code formatting a bit to better conform CodingStyle
+ * 	  rules.
+ * 	- So this is v0.0.5, with no changes (except formatting)
+ * 	
  * Wed, 22 May 2002 00:11:21 +0200
  * 	- Fix typo on comment (SRC -> SRM)
  * 	- Call this "Version 0.0.4"
@@ -59,7 +68,7 @@
 #define BASE_DIR	"srm_environment"	/* Subdir in /proc/		*/
 #define NAMED_DIR	"named_variables"	/* Subdir for known variables	*/
 #define NUMBERED_DIR	"numbered_variables"	/* Subdir for all variables	*/
-#define VERSION		"0.0.4"			/* Module version		*/
+#define VERSION		"0.0.5"			/* Module version		*/
 #define NAME		"srm_env"		/* Module name			*/
 
 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
@@ -97,9 +106,12 @@
 };
 static srm_env_t	srm_numbered_entries[256];
 
+
+
 static int
 srm_env_read(char *page, char **start, off_t off, int count, int *eof,
-		void *data) {
+		void *data)
+{
 	int		nbytes;
 	unsigned long	ret;
 	srm_env_t	*entry;
@@ -111,11 +123,11 @@
 		return -EFAULT;
 	}
 
-	entry	= (srm_env_t *)data;
+	entry	= (srm_env_t *) data;
 	ret	= callback_getenv(entry->id, page, count);
 
 	if((ret >> 61) == 0)
-		nbytes = (int)ret;
+		nbytes = (int) ret;
 	else
 		nbytes = -EFAULT;
 
@@ -124,9 +136,11 @@
 	return nbytes;
 }
 
+
 static int
 srm_env_write(struct file *file, const char *buffer, unsigned long count,
-		void *data) {
+		void *data)
+{
 #define BUFLEN	512
 	int		nbytes;
 	srm_env_t	*entry;
@@ -156,7 +170,7 @@
 		do 
 			ret2 = callback_save_env();
 		while((ret2 >> 61) == 1);
-		nbytes = (int)ret1;
+		nbytes = (int) ret1;
 	} else
 		nbytes = -EFAULT;
 
@@ -165,8 +179,10 @@
 	return nbytes;
 }
 
+
 static void
-srm_env_cleanup(void) {
+srm_env_cleanup(void)
+{
 	srm_env_t	*entry;
 	unsigned long	var_num;
 
@@ -210,8 +226,10 @@
 	return;
 }
 
+
 static int __init
-srm_env_init(void) {
+srm_env_init(void)
+{
 	srm_env_t	*entry;
 	unsigned long	var_num;
 
@@ -220,7 +238,9 @@
 	 */
 	if(!alpha_using_srm) {
 		printk(KERN_INFO "%s: This Alpha system doesn't "
-				"know about SRM...\n", __FUNCTION__);
+				"know about SRM (or you've booted "
+				"SRM->MILO->Linux, which gets "
+				"misdetected)...\n", __FUNCTION__);
 		return -ENODEV;
 	}
 
@@ -274,7 +294,7 @@
 		if(entry->proc_entry == NULL)
 			goto cleanup;
 
-		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->data		= (void *) entry;
 		entry->proc_entry->owner	= THIS_MODULE;
 		entry->proc_entry->read_proc	= srm_env_read;
 		entry->proc_entry->write_proc	= srm_env_write;
@@ -295,7 +315,7 @@
 			goto cleanup;
 
 		entry->id			= var_num;
-		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->data		= (void *) entry;
 		entry->proc_entry->owner	= THIS_MODULE;
 		entry->proc_entry->read_proc	= srm_env_read;
 		entry->proc_entry->write_proc	= srm_env_write;
@@ -303,19 +323,25 @@
 
 	printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
 			VERSION);
+
 	return 0;
 
 cleanup:
 	srm_env_cleanup();
+
 	return -ENOMEM;
 }
 
+
 static void __exit
-srm_env_exit(void) {
+srm_env_exit(void)
+{
 	srm_env_cleanup();
 	printk(KERN_INFO "%s: unloaded successfully\n", NAME);
+
 	return;
 }
+
 
 module_init(srm_env_init);
 module_exit(srm_env_exit);
diff -Nru a/arch/alpha/vmlinux.lds.S b/arch/alpha/vmlinux.lds.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/alpha/vmlinux.lds.S	Tue Aug 27 12:28:07 2002
@@ -0,0 +1,123 @@
+#include <linux/config.h>
+
+OUTPUT_FORMAT("elf64-alpha")
+ENTRY(__start)
+PHDRS { kernel PT_LOAD ; }
+jiffies = jiffies_64;
+SECTIONS
+{
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+  . = 0xfffffc0000310000;
+#else
+  . = 0xfffffc0000810000;
+#endif
+
+  .text : {
+	_text = .;
+	*(.text)
+	_etext = .;
+  } :kernel
+
+  /* Exception table */
+  __ex_table ALIGN(16) : {
+	__start___ex_table = .;
+	*(__ex_table)
+	__stop___ex_table = .;
+  }
+
+  /* Kernel symbol table */
+  __ksymtab ALIGN(8) : {
+	__start___ksymtab = .;
+	*(__ksymtab)
+	__stop___ksymtab = .;
+  }
+  .kstrtab : { *(.kstrtab) }
+
+  /* Startup code */
+  .text.init ALIGN(8192) : {
+	__init_begin = .;
+	*(.text.init)
+  }
+  .data.init : { *(.data.init) }
+
+  .setup.init ALIGN(16): {
+	__setup_start = .;
+	*(.setup.init)
+	__setup_end = .;
+  }
+
+  .initcall.init ALIGN(8): {
+	__initcall_start = .;
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+	__initcall_end = .;
+  }
+
+  . = ALIGN(64);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
+
+  /* The initial task and kernel stack */
+  .data.init_thread ALIGN(2*8192) : {
+	__init_end = .;
+	*(.data.init_thread)
+  }
+
+  /* Global data */
+  .data.cacheline_aligned : {
+	_data = .;
+	*(.data.cacheline_aligned)
+  }
+  .rodata : { *(.rodata) *(.rodata.*) }
+  .data : { *(.data) CONSTRUCTORS }
+  .got : { *(.got) }
+  .sdata : {
+	*(.sdata)
+	_edata = .;
+  }
+
+  .sbss : {
+	__bss_start = .;
+	*(.sbss) *(.scommon)
+  }
+  .bss : {
+	*(.bss) *(COMMON)
+	__bss_stop = .;
+	_end = .;
+  }
+
+  .mdebug 0 : { *(.mdebug) }
+  .note 0 : { *(.note) }
+  .comment 0 : { *(.comment) }
+
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+
+  /DISCARD/ : { *(.text.exit) *(.data.exit) *(.exitcall.exit) }
+}
diff -Nru a/arch/alpha/vmlinux.lds.in b/arch/alpha/vmlinux.lds.in
--- a/arch/alpha/vmlinux.lds.in	Tue Aug 27 12:28:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,123 +0,0 @@
-#include <linux/config.h>
-
-OUTPUT_FORMAT("elf64-alpha")
-ENTRY(__start)
-PHDRS { kernel PT_LOAD ; }
-jiffies = jiffies_64;
-SECTIONS
-{
-#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
-  . = 0xfffffc0000310000;
-#else
-  . = 0xfffffc0000810000;
-#endif
-
-  .text : {
-	_text = .;
-	*(.text)
-	_etext = .;
-  } :kernel
-
-  /* Exception table */
-  __ex_table ALIGN(16) : {
-	__start___ex_table = .;
-	*(__ex_table)
-	__stop___ex_table = .;
-  }
-
-  /* Kernel symbol table */
-  __ksymtab ALIGN(8) : {
-	__start___ksymtab = .;
-	*(__ksymtab)
-	__stop___ksymtab = .;
-  }
-  .kstrtab : { *(.kstrtab) }
-
-  /* Startup code */
-  .text.init ALIGN(8192) : {
-	__init_begin = .;
-	*(.text.init)
-  }
-  .data.init : { *(.data.init) }
-
-  .setup.init ALIGN(16): {
-	__setup_start = .;
-	*(.setup.init)
-	__setup_end = .;
-  }
-
-  .initcall.init ALIGN(8): {
-	__initcall_start = .;
-	*(.initcall1.init) 
-	*(.initcall2.init) 
-	*(.initcall3.init) 
-	*(.initcall4.init) 
-	*(.initcall5.init) 
-	*(.initcall6.init) 
-	*(.initcall7.init)
-	__initcall_end = .;
-  }
-
-  . = ALIGN(64);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
-
-  /* The initial task and kernel stack */
-  .data.init_thread ALIGN(2*8192) : {
-	__init_end = .;
-	*(.data.init_thread)
-  }
-
-  /* Global data */
-  .data.cacheline_aligned : {
-	_data = .;
-	*(.data.cacheline_aligned)
-  }
-  .rodata : { *(.rodata) *(.rodata.*) }
-  .data : { *(.data) CONSTRUCTORS }
-  .got : { *(.got) }
-  .sdata : {
-	*(.sdata)
-	_edata = .;
-  }
-
-  .sbss : {
-	__bss_start = .;
-	*(.sbss) *(.scommon)
-  }
-  .bss : {
-	*(.bss) *(COMMON)
-	__bss_stop = .;
-	_end = .;
-  }
-
-  .mdebug 0 : { *(.mdebug) }
-  .note 0 : { *(.note) }
-  .comment 0 : { *(.comment) }
-
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-
-  /DISCARD/ : { *(.text.exit) *(.data.exit) *(.exitcall.exit) }
-}
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c	Tue Aug 27 12:28:02 2002
+++ b/arch/arm/kernel/armksyms.c	Tue Aug 27 12:28:02 2002
@@ -273,7 +273,3 @@
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
 
 EXPORT_SYMBOL(get_wchan);
-
-#ifdef CONFIG_PREEMPT
-EXPORT_SYMBOL(kernel_flag);
-#endif
diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c	Tue Aug 27 12:27:42 2002
+++ b/arch/arm/kernel/setup.c	Tue Aug 27 12:27:42 2002
@@ -36,10 +36,6 @@
 #define MEM_SIZE	(16*1024*1024)
 #endif
 
-#ifdef CONFIG_PREEMPT
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-#endif
-
 #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
 char fpe_type[8];
 
diff -Nru a/arch/cris/config.in b/arch/cris/config.in
--- a/arch/cris/config.in	Tue Aug 27 12:28:07 2002
+++ b/arch/cris/config.in	Tue Aug 27 12:28:07 2002
@@ -135,12 +135,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
 mainmenu_option next_comment
 comment 'ATA/IDE/MFM/RLL support'
 
@@ -168,6 +162,8 @@
 source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+
   mainmenu_option next_comment
   comment 'Network device support'
 
@@ -186,6 +182,8 @@
 source net/irda/Config.in
 
 source drivers/isdn/Config.in
+
+source drivers/telephony/Config.in
 
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S	Tue Aug 27 12:27:51 2002
+++ b/arch/i386/boot/setup.S	Tue Aug 27 12:27:51 2002
@@ -1005,9 +1005,14 @@
 	ret
 
 # Descriptor tables
+#
+# NOTE: if you think the GDT is large, you can make it smaller by just
+# defining the KERNEL_CS and KERNEL_DS entries and shifting the gdt
+# address down by GDT_ENTRY_KERNEL_CS*8. This puts bogus entries into
+# the GDT, but those wont be used so it's not a problem.
+#
 gdt:
-	.word	0, 0, 0, 0			# dummy
-	.word	0, 0, 0, 0			# unused
+	.fill GDT_ENTRY_KERNEL_CS,8,0
 
 	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
 	.word	0				# base address = 0
@@ -1024,8 +1029,7 @@
 	.word	0				# idt limit = 0
 	.word	0, 0				# idt base = 0L
 gdt_48:
-	.word	0x8000				# gdt limit=2048,
-						#  256 GDT entries
+	.word	GDT_ENTRY_KERNEL_CS*8 + 16 - 1	# gdt limit
 
 	.word	0, 0				# gdt base (filled in later)
 
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/config.in	Tue Aug 27 12:28:02 2002
@@ -332,12 +332,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
 source drivers/message/fusion/Config.in
 
 source drivers/ieee1394/Config.in
@@ -345,6 +339,8 @@
 source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -363,6 +359,8 @@
 source net/irda/Config.in
 
 source drivers/isdn/Config.in
+
+source drivers/telephony/Config.in
 
 #
 # input before char - char/joystick depends on it. As does USB.
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/defconfig	Tue Aug 27 12:28:01 2002
@@ -5,11 +5,12 @@
 CONFIG_ISA=y
 # CONFIG_SBUS is not set
 CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
 
 #
 # Code maturity level options
 #
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
 
 #
 # General setup
@@ -57,6 +58,9 @@
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_SMP=y
+# CONFIG_PREEMPT is not set
+# CONFIG_MULTIQUAD is not set
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_NONFATAL=y
 CONFIG_X86_MCE_P4THERMAL=y
@@ -70,19 +74,22 @@
 # CONFIG_HIGHMEM64G is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_MTRR is not set
-CONFIG_SMP=y
-# CONFIG_PREEMPT is not set
-# CONFIG_MULTIQUAD is not set
 CONFIG_HAVE_DEC_LOCK=y
 
 #
-# General options
+# Power management options (ACPI, APM)
 #
 
 #
 # ACPI Support
 #
 # CONFIG_ACPI is not set
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_PCI=y
@@ -112,14 +119,15 @@
 # CONFIG_HOTPLUG_PCI_COMPAQ is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
 # CONFIG_HOTPLUG_PCI_IBM is not set
+
+#
+# Executable file formats
+#
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
-# CONFIG_APM is not set
-# CONFIG_SOFTWARE_SUSPEND is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -133,6 +141,8 @@
 CONFIG_PARPORT_PC=y
 CONFIG_PARPORT_PC_CML1=y
 # CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_PC_PCMCIA is not set
 # CONFIG_PARPORT_AMIGA is not set
 # CONFIG_PARPORT_MFC3 is not set
@@ -147,6 +157,7 @@
 #
 CONFIG_PNP=y
 CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -158,131 +169,97 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-# CONFIG_PHONE_IXJ is not set
-# CONFIG_PHONE_IXJ_PCMCIA is not set
-
-#
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL device support
 #
 CONFIG_IDE=y
 
 #
-# ATA and ATAPI Block devices
+# IDE, ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=y
 
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
-# IDE chipset support
+# IDE chipset support/bugfixes
 #
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 CONFIG_BLK_DEV_RZ1000=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
+CONFIG_PIIX_TUNING=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_ADMA100 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
+CONFIG_BLK_DEV_RZ1000=y
 # CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
 
@@ -293,8 +270,10 @@
 CONFIG_SD_EXTRA_DEVS=40
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -312,7 +291,6 @@
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -346,6 +324,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -361,6 +340,7 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # PCMCIA SCSI adapter support
@@ -368,6 +348,23 @@
 # CONFIG_SCSI_PCMCIA is not set
 
 #
+# Old non-SCSI/ATAPI CD-ROM drives
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
@@ -377,6 +374,11 @@
 # CONFIG_FUSION_LAN is not set
 
 #
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
 # I2O device support
 #
 # CONFIG_I2O is not set
@@ -387,6 +389,47 @@
 # CONFIG_I2O_PROC is not set
 
 #
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -399,6 +442,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
 
 #
@@ -460,6 +504,7 @@
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -474,6 +519,8 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
 
 #
 # Wan interfaces
@@ -481,7 +528,7 @@
 # CONFIG_WAN is not set
 
 #
-# "Tulip" family network device support
+# Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
 
@@ -519,96 +566,98 @@
 # CONFIG_ISDN_BOOL is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_GAMEPORT_NS558 is not set
 # CONFIG_GAMEPORT_L4 is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_GAMEPORT_PCIGAME is not set
+# CONFIG_GAMEPORT_EMU10K1 is not set
+# CONFIG_GAMEPORT_VORTEX is not set
 # CONFIG_GAMEPORT_FM801 is not set
 # CONFIG_GAMEPORT_CS461x is not set
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_I8042_REG_BASE=60
+CONFIG_I8042_KBD_IRQ=1
+CONFIG_I8042_AUX_IRQ=12
 # CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+# CONFIG_INPUT_JOYDUMP is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=y
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-CONFIG_AGP=y
-CONFIG_AGP_INTEL=y
-CONFIG_AGP_I810=y
-CONFIG_AGP_VIA=y
-# CONFIG_AGP_AMD is not set
-CONFIG_AGP_SIS=y
-CONFIG_AGP_ALI=y
-# CONFIG_AGP_SWORKS is not set
-CONFIG_DRM=y
-CONFIG_DRM_TDFX=y
-# CONFIG_DRM_GAMMA is not set
-# CONFIG_DRM_R128 is not set
-CONFIG_DRM_RADEON=y
-# CONFIG_DRM_I810 is not set
-# CONFIG_DRM_MGA is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_PCMCIA_SERIAL_CS is not set
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_MWAVE is not set
 
 #
 # Multimedia devices
@@ -619,6 +668,8 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_REISERFS_FS is not set
@@ -707,6 +758,12 @@
 #
 CONFIG_VGA_CONSOLE=y
 # CONFIG_VIDEO_SELECT is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
 
 #
 # Sound
@@ -731,6 +788,8 @@
 # CONFIG_SND_RTCTIMER is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DEBUG_MEMORY is not set
+# CONFIG_SND_DEBUG_DETECT is not set
 
 #
 # Generic devices
@@ -776,12 +835,14 @@
 #
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
 # CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_YMFPCI is not set
 # CONFIG_SND_ALS4000 is not set
@@ -817,14 +878,14 @@
 #
 # CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_OHCI_HCD is not set
-CONFIG_USB_UHCI_ALT=y
-# CONFIG_USB_OHCI is not set
+# CONFIG_USB_UHCI_HCD_ALT is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 CONFIG_USB_STORAGE=y
@@ -835,21 +896,24 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
 # USB Human Interface Devices (HID)
 #
 # CONFIG_USB_HID is not set
-
-#
-#     Input core support is needed for USB HID input layer or HIDBP support
-#
 # CONFIG_USB_HIDINPUT is not set
+# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
+# CONFIG_LOGITECH_FF is not set
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_KBD is not set
 # CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
 
 #
 # USB Imaging devices
@@ -905,6 +969,7 @@
 # CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
@@ -934,11 +999,24 @@
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_SOFTWARE_SUSPEND is not set
 # CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY_CAPABILITIES=y
 
 #
 # Library routines
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/Makefile	Tue Aug 27 12:28:01 2002
@@ -6,7 +6,7 @@
 
 O_TARGET := kernel.o
 
-export-objs     := mca.o mtrr.o i386_ksyms.o time.o
+export-objs     := mca.o msr.o i386_ksyms.o time.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
@@ -15,7 +15,6 @@
 
 obj-y				+= cpu/
 obj-$(CONFIG_MCA)		+= mca.o
-obj-$(CONFIG_MTRR)		+= mtrr.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
diff -Nru a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
--- a/arch/i386/kernel/acpi.c	Tue Aug 27 12:28:08 2002
+++ b/arch/i386/kernel/acpi.c	Tue Aug 27 12:28:08 2002
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/bootmem.h>
-#include <linux/slab.h>
 #include <linux/irq.h>
 #include <linux/acpi.h>
 #include <asm/mpspec.h>
@@ -53,11 +52,9 @@
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
 
-#ifdef CONFIG_ACPI_BOOT
-
 enum acpi_irq_model_id		acpi_irq_model;
 
-
+#ifdef CONFIG_ACPI_BOOT
 /*
  * Use reserved fixmap pages for physical-to-virtual mappings of ACPI tables.
  * Note that the same range is used for each table, so tables that need to
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Tue Aug 27 12:27:57 2002
+++ b/arch/i386/kernel/apm.c	Tue Aug 27 12:27:57 2002
@@ -214,6 +214,7 @@
 #include <linux/sched.h>
 #include <linux/pm.h>
 #include <linux/kernel.h>
+#include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/system.h>
@@ -419,6 +420,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *	user_list;
 static spinlock_t		user_list_lock = SPIN_LOCK_UNLOCKED;
+static struct desc_struct	bad_bios_desc = { 0, 0x00409200 };
 
 static char			driver_version[] = "1.16";	/* no spaces */
 
@@ -568,7 +570,12 @@
 	u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
 {
 	APM_DECL_SEGS
-	unsigned long	flags;
+	unsigned long		flags;
+	int			cpu = smp_processor_id();
+	struct desc_struct	save_desc_40;
+
+	save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
+	cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
 
 	local_save_flags(flags);
 	APM_DO_CLI;
@@ -591,6 +598,7 @@
 		: "memory", "cc");
 	APM_DO_RESTORE_SEGS;
 	local_irq_restore(flags);
+	cpu_gdt_table[cpu][0x40 / 8] = save_desc_40;
 	return *eax & 0xff;
 }
 
@@ -613,6 +621,11 @@
 	u8		error;
 	APM_DECL_SEGS
 	unsigned long	flags;
+	int			cpu = smp_processor_id();
+	struct desc_struct	save_desc_40;
+
+	save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
+	cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
 
 	local_save_flags(flags);
 	APM_DO_CLI;
@@ -639,6 +652,7 @@
 	}
 	APM_DO_RESTORE_SEGS;
 	local_irq_restore(flags);
+	cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40;
 	return error;
 }
 
@@ -931,9 +945,9 @@
 }
 
 static struct sysrq_key_op	sysrq_poweroff_op = {
-	handler:        handle_poweroff,
-	help_msg:       "Off",
-	action_msg:     "Power Off\n"
+	.handler        = handle_poweroff,
+	.help_msg       = "Off",
+	.action_msg     = "Power Off\n"
 };
 
 
@@ -1826,12 +1840,12 @@
 #endif
 
 static struct file_operations apm_bios_fops = {
-	owner:		THIS_MODULE,
-	read:		do_read,
-	poll:		do_poll,
-	ioctl:		do_ioctl,
-	open:		do_open,
-	release:	do_release,
+	.owner		= THIS_MODULE,
+	.read		= do_read,
+	.poll		= do_poll,
+	.ioctl		= do_ioctl,
+	.open		= do_open,
+	.release	= do_release,
 };
 
 static struct miscdevice apm_device = {
@@ -1927,13 +1941,13 @@
 	 * NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's
 	 * enough to modify CPU#0's GDT.
 	 */
-	for (i = 0; i < NR_CPUS; i++) {
-		set_base(cpu_gdt_table[i][APM_40 >> 3],
-			 __va((unsigned long)0x40 << 4));
-		_set_limit((char *)&cpu_gdt_table[i][APM_40 >> 3], 4095 - (0x40 << 4));
+	set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
+	_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
+
+	apm_bios_entry.offset = apm_info.bios.offset;
+	apm_bios_entry.segment = APM_CS;
 
-		apm_bios_entry.offset = apm_info.bios.offset;
-		apm_bios_entry.segment = APM_CS;
+	for (i = 0; i < NR_CPUS; i++) {
 		set_base(cpu_gdt_table[i][APM_CS >> 3],
 			 __va((unsigned long)apm_info.bios.cseg << 4));
 		set_base(cpu_gdt_table[i][APM_CS_16 >> 3],
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/bluesmoke.c	Tue Aug 27 12:28:02 2002
@@ -307,7 +307,7 @@
 } 
 
 static struct tq_struct mce_task = { 
-	routine: do_mce_timer	
+	.routine = do_mce_timer	
 };
 
 static void mce_timerfunc (unsigned long data)
diff -Nru a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
--- a/arch/i386/kernel/cpu/Makefile	Tue Aug 27 12:28:07 2002
+++ b/arch/i386/kernel/cpu/Makefile	Tue Aug 27 12:28:07 2002
@@ -13,4 +13,6 @@
 obj-y	+=	nexgen.o
 obj-y	+=	umc.o
 
+obj-$(CONFIG_MTRR)	+= mtrr/
+
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
--- a/arch/i386/kernel/cpu/amd.c	Tue Aug 27 12:28:08 2002
+++ b/arch/i386/kernel/cpu/amd.c	Tue Aug 27 12:28:08 2002
@@ -189,8 +189,8 @@
 }
 
 static struct cpu_dev amd_cpu_dev __initdata = {
-	c_vendor:	"AMD",
-	c_ident: 	{ "AuthenticAMD" },
+	.c_vendor	= "AMD",
+	.c_ident 	= { "AuthenticAMD" },
 	c_models: {
 		{ X86_VENDOR_AMD,	4,
 		  {
@@ -203,9 +203,9 @@
 		  }
 		},
 	},
-	c_init:		init_amd,
-	c_identify:	amd_identify,
-	c_size_cache:	amd_size_cache,
+	.c_init		= init_amd,
+	.c_identify	= amd_identify,
+	.c_size_cache	= amd_size_cache,
 };
 
 int __init amd_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
--- a/arch/i386/kernel/cpu/centaur.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/cpu/centaur.c	Tue Aug 27 12:27:59 2002
@@ -411,10 +411,10 @@
 }
 
 static struct cpu_dev centaur_cpu_dev __initdata = {
-	c_vendor:	"Centaur",
-	c_ident:	{ "CentaurHauls" },
-	c_init:		init_centaur,
-	c_size_cache:	centaur_size_cache,
+	.c_vendor	= "Centaur",
+	.c_ident	= { "CentaurHauls" },
+	.c_init		= init_centaur,
+	.c_size_cache	= centaur_size_cache,
 };
 
 int __init centaur_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- a/arch/i386/kernel/cpu/common.c	Tue Aug 27 12:27:57 2002
+++ b/arch/i386/kernel/cpu/common.c	Tue Aug 27 12:27:57 2002
@@ -31,7 +31,7 @@
 }
 
 static struct cpu_dev default_cpu = {
-	c_init:	default_init,
+	.c_init	= default_init,
 };
 static struct cpu_dev * this_cpu = &default_cpu;
 
@@ -423,6 +423,7 @@
 {
 	int cpu = smp_processor_id();
 	struct tss_struct * t = init_tss + cpu;
+	struct thread_struct *thread = &current->thread;
 
 	if (test_and_set_bit(cpu, &cpu_initialized)) {
 		printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
@@ -447,9 +448,13 @@
 	 */
 	if (cpu) {
 		memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE);
-		cpu_gdt_descr[cpu].size = GDT_SIZE;
+		cpu_gdt_descr[cpu].size = GDT_SIZE - 1;
 		cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu];
 	}
+	/*
+	 * Set up the per-thread TLS descriptor cache:
+	 */
+	memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_MAX * 8);
 
 	__asm__ __volatile__("lgdt %0": "=m" (cpu_gdt_descr[cpu]));
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
@@ -468,9 +473,9 @@
 		BUG();
 	enter_lazy_tlb(&init_mm, current, cpu);
 
-	t->esp0 = current->thread.esp0;
+	t->esp0 = thread->esp0;
 	set_tss_desc(cpu,t);
-	cpu_gdt_table[cpu][TSS_ENTRY].b &= 0xfffffdff;
+	cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
 	load_TR_desc();
 	load_LDT(&init_mm.context);
 
diff -Nru a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
--- a/arch/i386/kernel/cpu/cyrix.c	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/cpu/cyrix.c	Tue Aug 27 12:28:01 2002
@@ -322,10 +322,10 @@
 }
 
 static struct cpu_dev cyrix_cpu_dev __initdata = {
-	c_vendor:	"Cyrix",
-	c_ident: 	{ "CyrixInstead" },
-	c_init:		init_cyrix,
-	c_identify:	cyrix_identify,
+	.c_vendor	= "Cyrix",
+	.c_ident 	= { "CyrixInstead" },
+	.c_init		= init_cyrix,
+	.c_identify	= cyrix_identify,
 };
 
 int __init cyrix_init_cpu(void)
@@ -337,10 +337,10 @@
 //early_arch_initcall(cyrix_init_cpu);
 
 static struct cpu_dev nsc_cpu_dev __initdata = {
-	c_vendor:	"NSC",
-	c_ident: 	{ "Geode by NSC" },
-	c_init:		init_cyrix,
-	c_identify:	generic_identify,
+	.c_vendor	= "NSC",
+	.c_ident 	= { "Geode by NSC" },
+	.c_init		= init_cyrix,
+	.c_identify	= generic_identify,
 };
 
 int __init nsc_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/cpu/intel.c	Tue Aug 27 12:28:02 2002
@@ -327,8 +327,8 @@
 }
 
 static struct cpu_dev intel_cpu_dev __initdata = {
-	c_vendor:	"Intel",
-	c_ident: 	{ "GenuineIntel" },
+	.c_vendor	= "Intel",
+	.c_ident 	= { "GenuineIntel" },
 	c_models: {
 		{ X86_VENDOR_INTEL,	4,
 		  { 
@@ -375,9 +375,9 @@
 		  }
 		},
 	},
-	c_init:		init_intel,
-	c_identify:	generic_identify,
-	c_size_cache:	intel_size_cache,
+	.c_init		= init_intel,
+	.c_identify	= generic_identify,
+	.c_size_cache	= intel_size_cache,
 };
 
 __init int intel_cpu_init(void)
diff -Nru a/arch/i386/kernel/cpu/mtrr/Makefile b/arch/i386/kernel/cpu/mtrr/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/Makefile	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,8 @@
+obj-y		:= main.o if.o generic.o state.o
+obj-y		+= amd.o
+obj-y		+= cyrix.o
+obj-y		+= centaur.o
+
+export-objs	:= main.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/mtrr/amd.c b/arch/i386/kernel/cpu/mtrr/amd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/amd.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,121 @@
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+
+#include "mtrr.h"
+
+static void
+amd_get_mtrr(unsigned int reg, unsigned long *base,
+	     unsigned long *size, mtrr_type * type)
+{
+	unsigned long low, high;
+
+	rdmsr(MSR_K6_UWCCR, low, high);
+	/*  Upper dword is region 1, lower is region 0  */
+	if (reg == 1)
+		low = high;
+	/*  The base masks off on the right alignment  */
+	*base = (low & 0xFFFE0000) >> PAGE_SHIFT;
+	*type = 0;
+	if (low & 1)
+		*type = MTRR_TYPE_UNCACHABLE;
+	if (low & 2)
+		*type = MTRR_TYPE_WRCOMB;
+	if (!(low & 3)) {
+		*size = 0;
+		return;
+	}
+	/*
+	 *  This needs a little explaining. The size is stored as an
+	 *  inverted mask of bits of 128K granularity 15 bits long offset
+	 *  2 bits
+	 *
+	 *  So to get a size we do invert the mask and add 1 to the lowest
+	 *  mask bit (4 as its 2 bits in). This gives us a size we then shift
+	 *  to turn into 128K blocks
+	 *
+	 *  eg              111 1111 1111 1100      is 512K
+	 *
+	 *  invert          000 0000 0000 0011
+	 *  +1              000 0000 0000 0100
+	 *  *128K   ...
+	 */
+	low = (~low) & 0x1FFFC;
+	*size = (low + 4) << (15 - PAGE_SHIFT);
+	return;
+}
+
+static void amd_set_mtrr(unsigned int reg, unsigned long base,
+			 unsigned long size, mtrr_type type)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+	u32 regs[2];
+
+	/*
+	 *  Low is MTRR0 , High MTRR 1
+	 */
+	rdmsr(MSR_K6_UWCCR, regs[0], regs[1]);
+	/*
+	 *  Blank to disable
+	 */
+	if (size == 0)
+		regs[reg] = 0;
+	else
+		/* Set the register to the base, the type (off by one) and an
+		   inverted bitmask of the size The size is the only odd
+		   bit. We are fed say 512K We invert this and we get 111 1111
+		   1111 1011 but if you subtract one and invert you get the   
+		   desired 111 1111 1111 1100 mask
+
+		   But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!  */
+		regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC)
+		    | (base << PAGE_SHIFT) | (type + 1);
+
+	/*
+	 *  The writeback rule is quite specific. See the manual. Its
+	 *  disable local interrupts, write back the cache, set the mtrr
+	 */
+	wbinvd();
+	wrmsr(MSR_K6_UWCCR, regs[0], regs[1]);
+}
+
+static int amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
+{
+	/* Apply the K6 block alignment and size rules
+	   In order
+	   o Uncached or gathering only
+	   o 128K or bigger block
+	   o Power of 2 block
+	   o base suitably aligned to the power
+	*/
+	if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT))
+	    || (size & ~(size - 1)) - size || (base & (size - 1)))
+		return -EINVAL;
+	return 0;
+}
+
+static struct mtrr_ops amd_mtrr_ops = {
+	.vendor            = X86_VENDOR_AMD,
+	.set               = amd_set_mtrr,
+	.get               = amd_get_mtrr,
+	.get_free_region   = generic_get_free_region,
+	.validate_add_page = amd_validate_add_page,
+	.have_wrcomb       = positive_have_wrcomb,
+};
+
+int __init amd_init_mtrr(void)
+{
+	set_mtrr_ops(&amd_mtrr_ops);
+	return 0;
+}
+
+//arch_initcall(amd_mtrr_init);
diff -Nru a/arch/i386/kernel/cpu/mtrr/centaur.c b/arch/i386/kernel/cpu/mtrr/centaur.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/centaur.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,219 @@
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+#include "mtrr.h"
+
+static struct {
+	unsigned long high;
+	unsigned long low;
+} centaur_mcr[8];
+
+static u8 centaur_mcr_reserved;
+static u8 centaur_mcr_type;	/* 0 for winchip, 1 for winchip2 */
+
+/*
+ *	Report boot time MCR setups 
+ */
+
+static int
+centaur_get_free_region(unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+	int i, max;
+	mtrr_type ltype;
+	unsigned long lbase, lsize;
+
+	max = num_var_ranges;
+	for (i = 0; i < max; ++i) {
+		if (centaur_mcr_reserved & (1 << i))
+			continue;
+		mtrr_if->get(i, &lbase, &lsize, &ltype);
+		if (lsize == 0)
+			return i;
+	}
+	return -ENOSPC;
+}
+
+void
+mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
+{
+	centaur_mcr[mcr].low = lo;
+	centaur_mcr[mcr].high = hi;
+}
+
+static void
+centaur_get_mcr(unsigned int reg, unsigned long *base,
+		unsigned long *size, mtrr_type * type)
+{
+	*base = centaur_mcr[reg].high >> PAGE_SHIFT;
+	*size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
+	*type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */
+	if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))
+		*type = MTRR_TYPE_UNCACHABLE;
+	if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)
+		*type = MTRR_TYPE_WRBACK;
+	if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)
+		*type = MTRR_TYPE_WRBACK;
+
+}
+
+static void centaur_set_mcr(unsigned int reg, unsigned long base,
+			    unsigned long size, mtrr_type type)
+{
+	unsigned long low, high;
+
+	if (size == 0) {
+		/*  Disable  */
+		high = low = 0;
+	} else {
+		high = base << PAGE_SHIFT;
+		if (centaur_mcr_type == 0)
+			low = -size << PAGE_SHIFT | 0x1f;	/* only support write-combining... */
+		else {
+			if (type == MTRR_TYPE_UNCACHABLE)
+				low = -size << PAGE_SHIFT | 0x02;	/* NC */
+			else
+				low = -size << PAGE_SHIFT | 0x09;	/* WWO,WC */
+		}
+	}
+	centaur_mcr[reg].high = high;
+	centaur_mcr[reg].low = low;
+	wrmsr(MSR_IDT_MCR0 + reg, low, high);
+}
+/*
+ *	Initialise the later (saner) Winchip MCR variant. In this version
+ *	the BIOS can pass us the registers it has used (but not their values)
+ *	and the control register is read/write
+ */
+
+static void __init
+centaur_mcr1_init(void)
+{
+	unsigned i;
+	u32 lo, hi;
+
+	/* Unfortunately, MCR's are read-only, so there is no way to
+	 * find out what the bios might have done.
+	 */
+
+	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+	if (((lo >> 17) & 7) == 1) {	/* Type 1 Winchip2 MCR */
+		lo &= ~0x1C0;	/* clear key */
+		lo |= 0x040;	/* set key to 1 */
+		wrmsr(MSR_IDT_MCR_CTRL, lo, hi);	/* unlock MCR */
+	}
+
+	centaur_mcr_type = 1;
+
+	/*
+	 *  Clear any unconfigured MCR's.
+	 */
+
+	for (i = 0; i < 8; ++i) {
+		if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) {
+			if (!(lo & (1 << (9 + i))))
+				wrmsr(MSR_IDT_MCR0 + i, 0, 0);
+			else
+				/*
+				 *      If the BIOS set up an MCR we cannot see it
+				 *      but we don't wish to obliterate it
+				 */
+				centaur_mcr_reserved |= (1 << i);
+		}
+	}
+	/*  
+	 *  Throw the main write-combining switch... 
+	 *  However if OOSTORE is enabled then people have already done far
+	 *  cleverer things and we should behave. 
+	 */
+
+	lo |= 15;		/* Write combine enables */
+	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+}
+
+/*
+ *	Initialise the original winchip with read only MCR registers
+ *	no used bitmask for the BIOS to pass on and write only control
+ */
+
+static void __init
+centaur_mcr0_init(void)
+{
+	unsigned i;
+
+	/* Unfortunately, MCR's are read-only, so there is no way to
+	 * find out what the bios might have done.
+	 */
+
+	/* Clear any unconfigured MCR's.
+	 * This way we are sure that the centaur_mcr array contains the actual
+	 * values. The disadvantage is that any BIOS tweaks are thus undone.
+	 *
+	 */
+	for (i = 0; i < 8; ++i) {
+		if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0)
+			wrmsr(MSR_IDT_MCR0 + i, 0, 0);
+	}
+
+	wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);	/* Write only */
+}
+
+/*
+ *	Initialise Winchip series MCR registers
+ */
+
+static void __init
+centaur_mcr_init(void)
+{
+	struct set_mtrr_context ctxt;
+
+	set_mtrr_prepare_save(&ctxt);
+	set_mtrr_cache_disable(&ctxt);
+
+	if (boot_cpu_data.x86_model == 4)
+		centaur_mcr0_init();
+	else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9)
+		centaur_mcr1_init();
+
+	set_mtrr_done(&ctxt);
+}
+
+static int centaur_validate_add_page(unsigned long base, 
+				     unsigned long size, unsigned int type)
+{
+	/*
+	 *  FIXME: Winchip2 supports uncached
+	 */
+	if (type != MTRR_TYPE_WRCOMB && 
+	    (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {
+		printk(KERN_WARNING
+		       "mtrr: only write-combining%s supported\n",
+		       centaur_mcr_type ? " and uncacheable are"
+		       : " is");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct mtrr_ops centaur_mtrr_ops = {
+	.vendor            = X86_VENDOR_CENTAUR,
+	.init              = centaur_mcr_init,
+	.set               = centaur_set_mcr,
+	.get               = centaur_get_mcr,
+	.get_free_region   = centaur_get_free_region,
+	.validate_add_page = centaur_validate_add_page,
+	.have_wrcomb       = positive_have_wrcomb,
+};
+
+int __init centaur_init_mtrr(void)
+{
+	set_mtrr_ops(&centaur_mtrr_ops);
+	return 0;
+}
+
+//arch_initcall(centaur_init_mtrr);
diff -Nru a/arch/i386/kernel/cpu/mtrr/changelog b/arch/i386/kernel/cpu/mtrr/changelog
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/changelog	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,229 @@
+    ChangeLog
+
+    Prehistory Martin Tischhäuser <martin@ikcbarka.fzk.de>
+	       Initial register-setting code (from proform-1.0).
+    19971216   Richard Gooch <rgooch@atnf.csiro.au>
+               Original version for /proc/mtrr interface, SMP-safe.
+  v1.0
+    19971217   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix for ioctls()'s.
+	       Added sample code in Documentation/mtrr.txt
+  v1.1
+    19971218   Richard Gooch <rgooch@atnf.csiro.au>
+               Disallow overlapping regions.
+    19971219   Jens Maurer <jmaurer@menuett.rhein-main.de>
+               Register-setting fixups.
+  v1.2
+    19971222   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.75.
+  v1.3
+    19971229   David Wragg <dpw@doc.ic.ac.uk>
+               Register-setting fixups and conformity with Intel conventions.
+    19971229   Richard Gooch <rgooch@atnf.csiro.au>
+               Cosmetic changes and wrote this ChangeLog ;-)
+    19980106   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.78.
+  v1.4
+    19980119   David Wragg <dpw@doc.ic.ac.uk>
+               Included passive-release enable code (elsewhere in PCI setup).
+  v1.5
+    19980131   Richard Gooch <rgooch@atnf.csiro.au>
+               Replaced global kernel lock with private spinlock.
+  v1.6
+    19980201   Richard Gooch <rgooch@atnf.csiro.au>
+               Added wait for other CPUs to complete changes.
+  v1.7
+    19980202   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix in definition of <set_mtrr> for UP.
+  v1.8
+    19980319   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.90.
+    19980323   Richard Gooch <rgooch@atnf.csiro.au>
+               Move SMP BIOS fixup before secondary CPUs call <calibrate_delay>
+  v1.9
+    19980325   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixed test for overlapping regions: confused by adjacent regions
+    19980326   Richard Gooch <rgooch@atnf.csiro.au>
+               Added wbinvd in <set_mtrr_prepare>.
+    19980401   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix for non-SMP compilation.
+    19980418   David Wragg <dpw@doc.ic.ac.uk>
+               Fixed-MTRR synchronisation for SMP and use atomic operations
+	       instead of spinlocks.
+    19980418   Richard Gooch <rgooch@atnf.csiro.au>
+	       Differentiate different MTRR register classes for BIOS fixup.
+  v1.10
+    19980419   David Wragg <dpw@doc.ic.ac.uk>
+	       Bug fix in variable MTRR synchronisation.
+  v1.11
+    19980419   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixups for kernel 2.1.97.
+  v1.12
+    19980421   Richard Gooch <rgooch@atnf.csiro.au>
+	       Safer synchronisation across CPUs when changing MTRRs.
+  v1.13
+    19980423   Richard Gooch <rgooch@atnf.csiro.au>
+	       Bugfix for SMP systems without MTRR support.
+  v1.14
+    19980427   Richard Gooch <rgooch@atnf.csiro.au>
+	       Trap calls to <mtrr_add> and <mtrr_del> on non-MTRR machines.
+  v1.15
+    19980427   Richard Gooch <rgooch@atnf.csiro.au>
+	       Use atomic bitops for setting SMP change mask.
+  v1.16
+    19980428   Richard Gooch <rgooch@atnf.csiro.au>
+	       Removed spurious diagnostic message.
+  v1.17
+    19980429   Richard Gooch <rgooch@atnf.csiro.au>
+	       Moved register-setting macros into this file.
+	       Moved setup code from init/main.c to i386-specific areas.
+  v1.18
+    19980502   Richard Gooch <rgooch@atnf.csiro.au>
+	       Moved MTRR detection outside conditionals in <mtrr_init>.
+  v1.19
+    19980502   Richard Gooch <rgooch@atnf.csiro.au>
+	       Documentation improvement: mention Pentium II and AGP.
+  v1.20
+    19980521   Richard Gooch <rgooch@atnf.csiro.au>
+	       Only manipulate interrupt enable flag on local CPU.
+	       Allow enclosed uncachable regions.
+  v1.21
+    19980611   Richard Gooch <rgooch@atnf.csiro.au>
+	       Always define <main_lock>.
+  v1.22
+    19980901   Richard Gooch <rgooch@atnf.csiro.au>
+	       Removed module support in order to tidy up code.
+	       Added sanity check for <mtrr_add>/<mtrr_del> before <mtrr_init>.
+	       Created addition queue for prior to SMP commence.
+  v1.23
+    19980902   Richard Gooch <rgooch@atnf.csiro.au>
+	       Ported patch to kernel 2.1.120-pre3.
+  v1.24
+    19980910   Richard Gooch <rgooch@atnf.csiro.au>
+	       Removed sanity checks and addition queue: Linus prefers an OOPS.
+  v1.25
+    19981001   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed harmless compiler warning in include/asm-i386/mtrr.h
+	       Fixed version numbering and history for v1.23 -> v1.24.
+  v1.26
+    19990118   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added devfs support.
+  v1.27
+    19990123   Richard Gooch <rgooch@atnf.csiro.au>
+	       Changed locking to spin with reschedule.
+	       Made use of new <smp_call_function>.
+  v1.28
+    19990201   Zoltán Böszörményi <zboszor@mail.externet.hu>
+	       Extended the driver to be able to use Cyrix style ARRs.
+    19990204   Richard Gooch <rgooch@atnf.csiro.au>
+	       Restructured Cyrix support.
+  v1.29
+    19990204   Zoltán Böszörményi <zboszor@mail.externet.hu>
+	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
+	       and disable MAPEN in set_mtrr_done().
+    19990205   Richard Gooch <rgooch@atnf.csiro.au>
+	       Minor cleanups.
+  v1.30
+    19990208   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Protect plain 6x86s (and other processors without the
+               Page Global Enable feature) against accessing CR4 in
+               set_mtrr_prepare() and set_mtrr_done().
+    19990210   Richard Gooch <rgooch@atnf.csiro.au>
+	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
+  v1.31
+    19990212   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Major rewrite of cyrix_arr_init(): do not touch ARRs,
+               leave them as the BIOS have set them up.
+               Enable usage of all 8 ARRs.
+               Avoid multiplications by 3 everywhere and other
+               code clean ups/speed ups.
+    19990213   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Set up other Cyrix processors identical to the boot cpu.
+               Since Cyrix don't support Intel APIC, this is l'art pour l'art.
+               Weigh ARRs by size:
+               If size <= 32M is given, set up ARR# we were given.
+               If size >  32M is given, set up ARR7 only if it is free,
+               fail otherwise.
+    19990214   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Also check for size >= 256K if we are to set up ARR7,
+               mtrr_add() returns the value it gets from set_mtrr()
+    19990218   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Remove Cyrix "coma bug" workaround from here.
+               Moved to linux/arch/i386/kernel/setup.c and
+               linux/include/asm-i386/bugs.h
+    19990228   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added MTRRIOC_KILL_ENTRY ioctl(2)
+	       Trap for counter underflow in <mtrr_file_del>.
+	       Trap for 4 MiB aligned regions for PPro, stepping <= 7.
+    19990301   Richard Gooch <rgooch@atnf.csiro.au>
+	       Created <get_free_region> hook.
+    19990305   Richard Gooch <rgooch@atnf.csiro.au>
+	       Temporarily disable AMD support now MTRR capability flag is set.
+  v1.32
+    19990308   Zoltán Böszörményi <zboszor@mail.externet.hu>
+	       Adjust my changes (19990212-19990218) to Richard Gooch's
+	       latest changes. (19990228-19990305)
+  v1.33
+    19990309   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed typo in <printk> message.
+    19990310   Richard Gooch <rgooch@atnf.csiro.au>
+	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
+  v1.34
+    19990511   Bart Hartgers <bart@etpmod.phys.tue.nl>
+	       Support Centaur C6 MCR's.
+    19990512   Richard Gooch <rgooch@atnf.csiro.au>
+	       Minor cleanups.
+  v1.35
+    19990707   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Check whether ARR3 is protected in cyrix_get_free_region()
+               and mtrr_del(). The code won't attempt to delete or change it
+               from now on if the BIOS protected ARR3. It silently skips ARR3
+               in cyrix_get_free_region() or returns with an error code from
+               mtrr_del().
+    19990711   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Reset some bits in the CCRs in cyrix_arr_init() to disable SMM
+               if ARR3 isn't protected. This is needed because if SMM is active
+               and ARR3 isn't protected then deleting and setting ARR3 again
+               may lock up the processor. With SMM entirely disabled, it does
+               not happen.
+    19990812   Zoltán Böszörményi <zboszor@mail.externet.hu>
+               Rearrange switch() statements so the driver accomodates to
+               the fact that the AMD Athlon handles its MTRRs the same way
+               as Intel does.
+    19990814   Zoltán Böszörményi <zboszor@mail.externet.hu>
+	       Double check for Intel in mtrr_add()'s big switch() because
+	       that revision check is only valid for Intel CPUs.
+    19990819   Alan Cox <alan@redhat.com>
+               Tested Zoltan's changes on a pre production Athlon - 100%
+               success.
+    19991008   Manfred Spraul <manfreds@colorfullife.com>
+    	       replaced spin_lock_reschedule() with a normal semaphore.
+  v1.36
+    20000221   Richard Gooch <rgooch@atnf.csiro.au>
+               Compile fix if procfs and devfs not enabled.
+	       Formatting changes.
+  v1.37
+    20001109   H. Peter Anvin <hpa@zytor.com>
+	       Use the new centralized CPU feature detects.
+
+  v1.38
+    20010309   Dave Jones <davej@suse.de>
+	       Add support for Cyrix III.
+
+  v1.39
+    20010312   Dave Jones <davej@suse.de>
+               Ugh, I broke AMD support.
+	       Reworked fix by Troels Walsted Hansen <troels@thule.no>
+
+  v1.40
+    20010327   Dave Jones <davej@suse.de>
+	       Adapted Cyrix III support to include VIA C3.
+
+  v2.0
+    20020306   Patrick Mochel <mochel@osdl.org>
+               Split mtrr.c -> mtrr/*.c
+               Converted to Linux Kernel Coding Style
+               Fixed several minor nits in form
+               Moved some SMP-only functions out, so they can be used
+                for power management in the future.
+               TODO: Fix user interface cruft.
diff -Nru a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,378 @@
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include "mtrr.h"
+
+int arr3_protected;
+
+static void
+cyrix_get_arr(unsigned int reg, unsigned long *base,
+	      unsigned long *size, mtrr_type * type)
+{
+	unsigned long flags;
+	unsigned char arr, ccr3, rcr, shift;
+
+	arr = CX86_ARR_BASE + (reg << 1) + reg;	/* avoid multiplication by 3 */
+
+	/* Save flags and disable interrupts */
+	local_irq_save(flags);
+
+	ccr3 = getCx86(CX86_CCR3);
+	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);	/* enable MAPEN */
+	((unsigned char *) base)[3] = getCx86(arr);
+	((unsigned char *) base)[2] = getCx86(arr + 1);
+	((unsigned char *) base)[1] = getCx86(arr + 2);
+	rcr = getCx86(CX86_RCR_BASE + reg);
+	setCx86(CX86_CCR3, ccr3);	/* disable MAPEN */
+
+	/* Enable interrupts if it was enabled previously */
+	local_irq_restore(flags);
+	shift = ((unsigned char *) base)[1] & 0x0f;
+	*base >>= PAGE_SHIFT;
+
+	/* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+	 * Note: shift==0xf means 4G, this is unsupported.
+	 */
+	if (shift)
+		*size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
+	else
+		*size = 0;
+
+	/* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+	if (reg < 7) {
+		switch (rcr) {
+		case 1:
+			*type = MTRR_TYPE_UNCACHABLE;
+			break;
+		case 8:
+			*type = MTRR_TYPE_WRBACK;
+			break;
+		case 9:
+			*type = MTRR_TYPE_WRCOMB;
+			break;
+		case 24:
+		default:
+			*type = MTRR_TYPE_WRTHROUGH;
+			break;
+		}
+	} else {
+		switch (rcr) {
+		case 0:
+			*type = MTRR_TYPE_UNCACHABLE;
+			break;
+		case 8:
+			*type = MTRR_TYPE_WRCOMB;
+			break;
+		case 9:
+			*type = MTRR_TYPE_WRBACK;
+			break;
+		case 25:
+		default:
+			*type = MTRR_TYPE_WRTHROUGH;
+			break;
+		}
+	}
+}
+
+static int
+cyrix_get_free_region(unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free ARR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+	int i;
+	mtrr_type ltype;
+	unsigned long lbase, lsize;
+
+	/* If we are to set up a region >32M then look at ARR7 immediately */
+	if (size > 0x2000) {
+		cyrix_get_arr(7, &lbase, &lsize, &ltype);
+		if (lsize == 0)
+			return 7;
+		/*  Else try ARR0-ARR6 first  */
+	} else {
+		for (i = 0; i < 7; i++) {
+			cyrix_get_arr(i, &lbase, &lsize, &ltype);
+			if ((i == 3) && arr3_protected)
+				continue;
+			if (lsize == 0)
+				return i;
+		}
+		/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+		cyrix_get_arr(i, &lbase, &lsize, &ltype);
+		if ((lsize == 0) && (size >= 0x40))
+			return i;
+	}
+	return -ENOSPC;
+}
+
+static void cyrix_set_arr(unsigned int reg, unsigned long base,
+			  unsigned long size, mtrr_type type)
+{
+	unsigned char arr, arr_type, arr_size;
+	u32 cr0, ccr3;
+	u32 cr4 = 0;
+
+	arr = CX86_ARR_BASE + (reg << 1) + reg;	/* avoid multiplication by 3 */
+
+	/* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+	if (reg >= 7)
+		size >>= 6;
+
+	size &= 0x7fff;		/* make sure arr_size <= 14 */
+	for (arr_size = 0; size; arr_size++, size >>= 1) ;
+
+	if (reg < 7) {
+		switch (type) {
+		case MTRR_TYPE_UNCACHABLE:
+			arr_type = 1;
+			break;
+		case MTRR_TYPE_WRCOMB:
+			arr_type = 9;
+			break;
+		case MTRR_TYPE_WRTHROUGH:
+			arr_type = 24;
+			break;
+		default:
+			arr_type = 8;
+			break;
+		}
+	} else {
+		switch (type) {
+		case MTRR_TYPE_UNCACHABLE:
+			arr_type = 0;
+			break;
+		case MTRR_TYPE_WRCOMB:
+			arr_type = 8;
+			break;
+		case MTRR_TYPE_WRTHROUGH:
+			arr_type = 25;
+			break;
+		default:
+			arr_type = 9;
+			break;
+		}
+	}
+
+	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+	if ( cpu_has_pge ) {
+		cr4 = read_cr4();
+		write_cr4(cr4 & (unsigned char) ~(1 << 7));
+	}
+
+	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	    a side-effect  */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	ccr3 = getCx86(CX86_CCR3);
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
+
+	base <<= PAGE_SHIFT;
+	setCx86(arr, ((unsigned char *) &base)[3]);
+	setCx86(arr + 1, ((unsigned char *) &base)[2]);
+	setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size);
+	setCx86(CX86_RCR_BASE + reg, arr_type);
+
+	/*  Flush caches and TLBs  */
+	wbinvd();
+
+	/* Cyrix ARRs - everything else was excluded at the top */
+	setCx86(CX86_CCR3, ccr3);
+		
+	/*  Enable caches  */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/*  Restore value of CR4  */
+	if ( cpu_has_pge )
+		write_cr4(cr4);
+}
+
+typedef struct {
+	unsigned long base;
+	unsigned long size;
+	mtrr_type type;
+} arr_state_t;
+
+arr_state_t arr_state[8] __initdata = {
+	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
+	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
+};
+
+unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+
+static void __init
+cyrix_arr_init_secondary(void)
+{
+	int i;
+	u32 cr0, ccr3, cr4 = 0;
+
+	/* flush cache and enable MAPEN */
+	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+	if ( cpu_has_pge ) {
+		cr4 = read_cr4();
+		write_cr4(cr4 & (unsigned char) ~(1 << 7));
+	}
+
+	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	    a side-effect  */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	ccr3 = getCx86(CX86_CCR3);
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
+
+	/* the CCRs are not contiguous */
+	for (i = 0; i < 4; i++)
+		setCx86(CX86_CCR0 + i, ccr_state[i]);
+	for (; i < 7; i++)
+		setCx86(CX86_CCR4 + i, ccr_state[i]);
+	for (i = 0; i < 8; i++)
+		cyrix_set_arr(i, arr_state[i].base, 
+			      arr_state[i].size, arr_state[i].type);
+
+	/*  Flush caches and TLBs  */
+	wbinvd();
+
+	/* Cyrix ARRs - everything else was excluded at the top */
+	setCx86(CX86_CCR3, ccr3);
+		
+	/*  Enable caches  */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/*  Restore value of CR4  */
+	if ( cpu_has_pge )
+		write_cr4(cr4);
+}
+
+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ *   if it is set, write a warning message: ARR3 cannot be changed!
+ *     (it cannot be changed until the next processor reset)
+ *   if it is reset, then we can change it, set all the needed bits:
+ *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ *   - disable access to SMM memory (CCR1 bit 2 reset)
+ *   - disable SMM mode (CCR1 bit 1 reset)
+ *   - disable write protection of ARR3 (CCR6 bit 1 reset)
+ *   - (maybe) disable ARR3
+ * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+ */
+static void __init
+cyrix_arr_init(void)
+{
+	struct set_mtrr_context ctxt;
+	unsigned char ccr[7];
+	int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+#ifdef CONFIG_SMP
+	int i;
+#endif
+
+	/* flush cache and enable MAPEN */
+	set_mtrr_prepare_save(&ctxt);
+	set_mtrr_cache_disable(&ctxt);
+
+	/* Save all CCRs locally */
+	ccr[0] = getCx86(CX86_CCR0);
+	ccr[1] = getCx86(CX86_CCR1);
+	ccr[2] = getCx86(CX86_CCR2);
+	ccr[3] = ctxt.ccr3;
+	ccr[4] = getCx86(CX86_CCR4);
+	ccr[5] = getCx86(CX86_CCR5);
+	ccr[6] = getCx86(CX86_CCR6);
+
+	if (ccr[3] & 1) {
+		ccrc[3] = 1;
+		arr3_protected = 1;
+	} else {
+		/* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+		 * access to SMM memory through ARR3 (bit 7).
+		 */
+		if (ccr[1] & 0x80) {
+			ccr[1] &= 0x7f;
+			ccrc[1] |= 0x80;
+		}
+		if (ccr[1] & 0x04) {
+			ccr[1] &= 0xfb;
+			ccrc[1] |= 0x04;
+		}
+		if (ccr[1] & 0x02) {
+			ccr[1] &= 0xfd;
+			ccrc[1] |= 0x02;
+		}
+		arr3_protected = 0;
+		if (ccr[6] & 0x02) {
+			ccr[6] &= 0xfd;
+			ccrc[6] = 1;	/* Disable write protection of ARR3 */
+			setCx86(CX86_CCR6, ccr[6]);
+		}
+		/* Disable ARR3. This is safe now that we disabled SMM. */
+		/* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+	}
+	/* If we changed CCR1 in memory, change it in the processor, too. */
+	if (ccrc[1])
+		setCx86(CX86_CCR1, ccr[1]);
+
+	/* Enable ARR usage by the processor */
+	if (!(ccr[5] & 0x20)) {
+		ccr[5] |= 0x20;
+		ccrc[5] = 1;
+		setCx86(CX86_CCR5, ccr[5]);
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < 7; i++)
+		ccr_state[i] = ccr[i];
+	for (i = 0; i < 8; i++)
+		cyrix_get_arr(i,
+			      &arr_state[i].base, &arr_state[i].size,
+			      &arr_state[i].type);
+#endif
+
+	set_mtrr_done(&ctxt);	/* flush cache and disable MAPEN */
+
+	if (ccrc[5])
+		printk("mtrr: ARR usage was not enabled, enabled manually\n");
+	if (ccrc[3])
+		printk("mtrr: ARR3 cannot be changed\n");
+/*
+    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
+    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
+    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
+*/
+	if (ccrc[6])
+		printk("mtrr: ARR3 was write protected, unprotected\n");
+}
+
+static struct mtrr_ops cyrix_mtrr_ops = {
+	.vendor            = X86_VENDOR_CYRIX,
+	.init              = cyrix_arr_init,
+	.init_secondary    = cyrix_arr_init_secondary,
+	.set               = cyrix_set_arr,
+	.get               = cyrix_get_arr,
+	.get_free_region   = cyrix_get_free_region,
+	.validate_add_page = generic_validate_add_page,
+	.have_wrcomb       = positive_have_wrcomb,
+};
+
+int __init cyrix_init_mtrr(void)
+{
+	set_mtrr_ops(&cyrix_mtrr_ops);
+	return 0;
+}
+
+//arch_initcall(cyrix_init_mtrr);
diff -Nru a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/generic.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,187 @@
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+#include <asm/system.h>
+#include <asm/cpufeature.h>
+#include "mtrr.h"
+
+
+int generic_get_free_region(unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+	int i, max;
+	mtrr_type ltype;
+	unsigned long lbase, lsize;
+
+	max = num_var_ranges;
+	for (i = 0; i < max; ++i) {
+		mtrr_if->get(i, &lbase, &lsize, &ltype);
+		if (lsize == 0)
+			return i;
+	}
+	return -ENOSPC;
+}
+
+
+void generic_get_mtrr(unsigned int reg, unsigned long *base,
+		      unsigned long *size, mtrr_type * type)
+{
+	unsigned long mask_lo, mask_hi, base_lo, base_hi;
+
+	rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
+	if ((mask_lo & 0x800) == 0) {
+		/*  Invalid (i.e. free) range  */
+		*base = 0;
+		*size = 0;
+		*type = 0;
+		return;
+	}
+
+	rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
+
+	/* Work out the shifted address mask. */
+	mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
+	    | mask_lo >> PAGE_SHIFT;
+
+	/* This works correctly if size is a power of two, i.e. a
+	   contiguous range. */
+	*size = -mask_lo;
+	*base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+	*type = base_lo & 0xff;
+}
+
+void generic_set_mtrr(unsigned int reg, unsigned long base,
+		      unsigned long size, mtrr_type type)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+	u32 cr0, cr4 = 0;
+	u32 deftype_lo, deftype_hi;
+	static spinlock_t set_atomicity_lock = SPIN_LOCK_UNLOCKED;
+
+	spin_lock(&set_atomicity_lock);
+	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+	if ( cpu_has_pge ) {
+		cr4 = read_cr4();
+		write_cr4(cr4 & (unsigned char) ~(1 << 7));
+	}
+
+	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	    a side-effect  */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/*  Save MTRR state */
+	rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+
+	/*  Disable MTRRs, and set the default type to uncached  */
+	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+
+	if (size == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+	} else {
+		wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
+		      (base & size_and_mask) >> (32 - PAGE_SHIFT));
+		wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
+		      (-size & size_and_mask) >> (32 - PAGE_SHIFT));
+	}
+
+	/*  Flush caches and TLBs  */
+	wbinvd();
+
+	/* Intel (P6) standard MTRRs */
+	wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+		
+	/*  Enable caches  */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/*  Restore value of CR4  */
+	if ( cpu_has_pge )
+		write_cr4(cr4);
+	spin_unlock(&set_atomicity_lock);
+}
+
+int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
+{
+	unsigned long lbase, last;
+
+	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned 
+	    and not touch 0x70000000->0x7003FFFF */
+	if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
+	    boot_cpu_data.x86_model == 1 &&
+	    boot_cpu_data.x86_mask <= 7) {
+		if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
+			printk(KERN_WARNING
+			       "mtrr: base(0x%lx000) is not 4 MiB aligned\n",
+			       base);
+			return -EINVAL;
+		}
+		if (!(base + size < 0x70000000 || base > 0x7003FFFF) &&
+		    (type == MTRR_TYPE_WRCOMB
+		     || type == MTRR_TYPE_WRBACK)) {
+			printk(KERN_WARNING
+			       "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
+			return -EINVAL;
+		}
+	}
+
+	if (base + size < 0x100) {
+		printk(KERN_WARNING
+		       "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
+		       base, size);
+		return -EINVAL;
+	}
+	/*  Check upper bits of base and last are equal and lower bits are 0
+	    for base and 1 for last  */
+	last = base + size - 1;
+	for (lbase = base; !(lbase & 1) && (last & 1);
+	     lbase = lbase >> 1, last = last >> 1) ;
+	if (lbase != last) {
+		printk(KERN_WARNING
+		       "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
+		       base, size);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+int generic_have_wrcomb(void)
+{
+	unsigned long config, dummy;
+	rdmsr(MTRRcap_MSR, config, dummy);
+	return (config & (1 << 10));
+}
+
+int positive_have_wrcomb(void)
+{
+	return 1;
+}
+
+/* generic structure...
+ */
+struct mtrr_ops generic_mtrr_ops = {
+	.use_intel_if      = 1,
+	.init_secondary    = generic_init_secondary,
+	.get               = generic_get_mtrr,
+	.get_free_region   = generic_get_free_region,
+	.set               = generic_set_mtrr,
+	.validate_add_page = generic_validate_add_page,
+	.have_wrcomb       = generic_have_wrcomb,
+};
diff -Nru a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/if.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,396 @@
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+/* What kind of fucking hack is this? */
+#define MTRR_NEED_STRINGS
+
+#include <asm/mtrr.h>
+#include "mtrr.h"
+
+static char *ascii_buffer;
+static unsigned int ascii_buf_bytes;
+
+extern unsigned int *usage_table;
+
+#define LINE_SIZE      80
+
+static int
+mtrr_file_add(unsigned long base, unsigned long size,
+	      unsigned int type, char increment, struct file *file, int page)
+{
+	int reg, max;
+	unsigned int *fcount = file->private_data;
+
+	max = num_var_ranges;
+	if (fcount == NULL) {
+		if ((fcount =
+		     kmalloc(max * sizeof *fcount, GFP_KERNEL)) == NULL) {
+			printk("mtrr: could not allocate\n");
+			return -ENOMEM;
+		}
+		memset(fcount, 0, max * sizeof *fcount);
+		file->private_data = fcount;
+	}
+	if (!page) {
+		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+			printk
+			    ("mtrr: size and base must be multiples of 4 kiB\n");
+			printk("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+			return -EINVAL;
+		}
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+	}
+	reg = mtrr_add_page(base, size, type, 1);
+	if (reg >= 0)
+		++fcount[reg];
+	return reg;
+}
+
+static int
+mtrr_file_del(unsigned long base, unsigned long size,
+	      struct file *file, int page)
+{
+	int reg;
+	unsigned int *fcount = file->private_data;
+
+	if (!page) {
+		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+			printk
+			    ("mtrr: size and base must be multiples of 4 kiB\n");
+			printk("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+			return -EINVAL;
+		}
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+	}
+	reg = mtrr_del_page(-1, base, size);
+	if (reg < 0)
+		return reg;
+	if (fcount == NULL)
+		return reg;
+	if (fcount[reg] < 1)
+		return -EINVAL;
+	--fcount[reg];
+	return reg;
+}
+
+static ssize_t
+mtrr_read(struct file *file, char *buf, size_t len, loff_t * ppos)
+{
+	if (*ppos >= ascii_buf_bytes)
+		return 0;
+	if (*ppos + len > ascii_buf_bytes)
+		len = ascii_buf_bytes - *ppos;
+	if (copy_to_user(buf, ascii_buffer + *ppos, len))
+		return -EFAULT;
+	*ppos += len;
+	return len;
+}
+
+static ssize_t
+mtrr_write(struct file *file, const char *buf, size_t len, loff_t * ppos)
+/*  Format of control line:
+    "base=%Lx size=%Lx type=%s"     OR:
+    "disable=%d"
+*/
+{
+	int i, err;
+	unsigned long reg;
+	unsigned long long base, size;
+	char *ptr;
+	char line[LINE_SIZE];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	memset(line, 0, LINE_SIZE);
+	if (len > LINE_SIZE)
+		len = LINE_SIZE;
+	if (copy_from_user(line, buf, len - 1))
+		return -EFAULT;
+	ptr = line + strlen(line) - 1;
+	if (*ptr == '\n')
+		*ptr = '\0';
+	if (!strncmp(line, "disable=", 8)) {
+		reg = simple_strtoul(line + 8, &ptr, 0);
+		err = mtrr_del_page(reg, 0, 0);
+		if (err < 0)
+			return err;
+		return len;
+	}
+	if (strncmp(line, "base=", 5)) {
+		printk("mtrr: no \"base=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+	base = simple_strtoull(line + 5, &ptr, 0);
+	for (; isspace(*ptr); ++ptr) ;
+	if (strncmp(ptr, "size=", 5)) {
+		printk("mtrr: no \"size=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+	size = simple_strtoull(ptr + 5, &ptr, 0);
+	if ((base & 0xfff) || (size & 0xfff)) {
+		printk("mtrr: size and base must be multiples of 4 kiB\n");
+		printk("mtrr: size: 0x%Lx  base: 0x%Lx\n", size, base);
+		return -EINVAL;
+	}
+	for (; isspace(*ptr); ++ptr) ;
+	if (strncmp(ptr, "type=", 5)) {
+		printk("mtrr: no \"type=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+	ptr += 5;
+	for (; isspace(*ptr); ++ptr) ;
+	for (i = 0; i < MTRR_NUM_TYPES; ++i) {
+//		if (strcmp(ptr, mtrr_strings[i]))
+			continue;
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+		err =
+		    mtrr_add_page((unsigned long) base, (unsigned long) size, i,
+				  1);
+		if (err < 0)
+			return err;
+		return len;
+	}
+	printk("mtrr: illegal type: \"%s\"\n", ptr);
+	return -EINVAL;
+}
+
+static int
+mtrr_ioctl(struct inode *inode, struct file *file,
+	   unsigned int cmd, unsigned long arg)
+{
+	int err;
+	mtrr_type type;
+	struct mtrr_sentry sentry;
+	struct mtrr_gentry gentry;
+
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+	case MTRRIOC_ADD_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err =
+		    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
+				  file, 0);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_SET_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_add(sentry.base, sentry.size, sentry.type, 0);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_DEL_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_del(sentry.base, sentry.size, file, 0);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_KILL_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_del(-1, sentry.base, sentry.size);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_GET_ENTRY:
+		if (copy_from_user(&gentry, (void *) arg, sizeof gentry))
+			return -EFAULT;
+		if (gentry.regnum >= num_var_ranges)
+			return -EINVAL;
+		mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
+
+		/* Hide entries that go above 4GB */
+		if (gentry.base + gentry.size > 0x100000
+		    || gentry.size == 0x100000)
+			gentry.base = gentry.size = gentry.type = 0;
+		else {
+			gentry.base <<= PAGE_SHIFT;
+			gentry.size <<= PAGE_SHIFT;
+			gentry.type = type;
+		}
+
+		if (copy_to_user((void *) arg, &gentry, sizeof gentry))
+			return -EFAULT;
+		break;
+	case MTRRIOC_ADD_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err =
+		    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
+				  file, 1);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_SET_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_DEL_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_del(sentry.base, sentry.size, file, 1);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_KILL_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_del_page(-1, sentry.base, sentry.size);
+		if (err < 0)
+			return err;
+		break;
+	case MTRRIOC_GET_PAGE_ENTRY:
+		if (copy_from_user(&gentry, (void *) arg, sizeof gentry))
+			return -EFAULT;
+		if (gentry.regnum >= num_var_ranges)
+			return -EINVAL;
+		mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
+		gentry.type = type;
+
+		if (copy_to_user((void *) arg, &gentry, sizeof gentry))
+			return -EFAULT;
+		break;
+	}
+	return 0;
+}
+
+static int
+mtrr_close(struct inode *ino, struct file *file)
+{
+	int i, max;
+	unsigned int *fcount = file->private_data;
+
+	if (fcount == NULL)
+		return 0;
+	max = num_var_ranges;
+	for (i = 0; i < max; ++i) {
+		while (fcount[i] > 0) {
+			if (mtrr_del(i, 0, 0) < 0)
+				printk("mtrr: reg %d not used\n", i);
+			--fcount[i];
+		}
+	}
+	kfree(fcount);
+	file->private_data = NULL;
+	return 0;
+}
+
+static struct file_operations mtrr_fops = {
+	.owner   = THIS_MODULE,
+	.read    = mtrr_read,
+	.write   = mtrr_write,
+	.ioctl   = mtrr_ioctl,
+	.release = mtrr_close,
+};
+
+#  ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry *proc_root_mtrr;
+
+#  endif			/*  CONFIG_PROC_FS  */
+
+static devfs_handle_t devfs_handle;
+
+char * attrib_to_str(int x)
+{
+	return (x <= 6) ? mtrr_strings[x] : "?";
+}
+
+void compute_ascii(void)
+{
+	char factor;
+	int i, max;
+	mtrr_type type;
+	unsigned long base, size;
+
+	ascii_buf_bytes = 0;
+	max = num_var_ranges;
+	for (i = 0; i < max; i++) {
+		mtrr_if->get(i, &base, &size, &type);
+		if (size == 0)
+			usage_table[i] = 0;
+		else {
+			if (size < (0x100000 >> PAGE_SHIFT)) {
+				/* less than 1MB */
+				factor = 'K';
+				size <<= PAGE_SHIFT - 10;
+			} else {
+				factor = 'M';
+				size >>= 20 - PAGE_SHIFT;
+			}
+			sprintf
+			    (ascii_buffer + ascii_buf_bytes,
+			     "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
+			     i, base, base >> (20 - PAGE_SHIFT), size, factor,
+			     attrib_to_str(type), usage_table[i]);
+			ascii_buf_bytes +=
+			    strlen(ascii_buffer + ascii_buf_bytes);
+		}
+	}
+	devfs_set_file_size(devfs_handle, ascii_buf_bytes);
+#  ifdef CONFIG_PROC_FS
+	if (proc_root_mtrr)
+		proc_root_mtrr->size = ascii_buf_bytes;
+#  endif			/*  CONFIG_PROC_FS  */
+}
+
+static int __init mtrr_if_init(void)
+{
+	int max = num_var_ranges;
+
+	if ((ascii_buffer = kmalloc(max * LINE_SIZE, GFP_KERNEL)) == NULL) {
+		printk("mtrr: could not allocate\n");
+		return -ENOMEM;
+	}
+	ascii_buf_bytes = 0;
+	compute_ascii();
+#ifdef CONFIG_PROC_FS
+	proc_root_mtrr =
+	    create_proc_entry("mtrr", S_IWUSR | S_IRUGO, &proc_root);
+	if (proc_root_mtrr) {
+		proc_root_mtrr->owner = THIS_MODULE;
+		proc_root_mtrr->proc_fops = &mtrr_fops;
+	}
+#endif
+#ifdef USERSPACE_INTERFACE
+	devfs_handle = devfs_register(NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
+				      S_IFREG | S_IRUGO | S_IWUSR,
+				      &mtrr_fops, NULL);
+#endif
+	return 0;
+}
+
+arch_initcall(mtrr_if_init);
diff -Nru a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/main.c	Tue Aug 27 12:27:57 2002
@@ -0,0 +1,628 @@
+/*  Generic MTRR (Memory Type Range Register) driver.
+
+    Copyright (C) 1997-2000  Richard Gooch
+    Copyright (c) 2002	     Patrick Mochel
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+
+    Source: "Pentium Pro Family Developer's Manual, Volume 3:
+    Operating System Writer's Guide" (Intel document number 242692),
+    section 11.11.7
+
+    This was cleaned and made readable by Patrick Mochel <mochel@osdl.org> 
+    on 6-7 March 2002. 
+    Source: Intel Architecture Software Developers Manual, Volume 3: 
+    System Programming Guide; Section 9.11. (1997 edition - PPro).
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+
+#define MTRR_NEED_STRINGS
+#include <asm/mtrr.h>
+
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include "mtrr.h"
+
+#define MTRR_VERSION            "2.0 (20020519)"
+
+u32 num_var_ranges = 0;
+
+unsigned int *usage_table;
+static DECLARE_MUTEX(main_lock);
+
+u32 size_or_mask, size_and_mask;
+
+static struct mtrr_ops * mtrr_ops[X86_VENDOR_NUM] = {};
+struct mtrr_ops * mtrr_if = NULL;
+
+__initdata char *mtrr_if_name[] = {
+    "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
+};
+
+static void set_mtrr(unsigned int reg, unsigned long base,
+		     unsigned long size, mtrr_type type);
+
+static unsigned int arr3_protected;
+
+void set_mtrr_ops(struct mtrr_ops * ops)
+{
+	if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
+		mtrr_ops[ops->vendor] = ops;
+}
+
+/*  Returns non-zero if we have the write-combining memory type  */
+static int have_wrcomb(void)
+{
+	struct pci_dev *dev = NULL;
+
+	/* WTF is this?
+	 * Someone, please shoot me.
+	 */
+
+	/* ServerWorks LE chipsets have problems with write-combining 
+	   Don't allow it and leave room for other chipsets to be tagged */
+
+	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
+		if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+		    (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) {
+			printk(KERN_INFO
+			       "mtrr: Serverworks LE detected. Write-combining disabled.\n");
+			return 0;
+		}
+	}
+	return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0);
+}
+
+/*  This function returns the number of variable MTRRs  */
+void __init set_num_var_ranges(void)
+{
+	unsigned long config = 0, dummy;
+
+	if (use_intel()) {
+		rdmsr(MTRRcap_MSR, config, dummy);
+	} else if (is_cpu(AMD))
+		config = 2;
+	else if (is_cpu(CYRIX) || is_cpu(CENTAUR))
+		config = 8;
+	num_var_ranges = config & 0xff;
+}
+
+static char * attrib_to_str(int x)
+{
+	return (x <= 6) ? mtrr_strings[x] : "?";
+}
+
+static void init_table(void)
+{
+	int i, max;
+
+	max = num_var_ranges;
+	if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
+	    == NULL) {
+		printk("mtrr: could not allocate\n");
+		return;
+	}
+	for (i = 0; i < max; i++)
+		usage_table[i] = 1;
+#ifdef USERSPACE_INTERFACE
+	if ((ascii_buffer = kmalloc(max * LINE_SIZE, GFP_KERNEL)) == NULL) {
+		printk("mtrr: could not allocate\n");
+		return;
+	}
+	ascii_buf_bytes = 0;
+	compute_ascii();
+#endif
+}
+
+struct set_mtrr_data {
+	atomic_t	count;
+	atomic_t	gate;
+	unsigned long	smp_base;
+	unsigned long	smp_size;
+	unsigned int	smp_reg;
+	mtrr_type	smp_type;
+};
+
+#ifdef CONFIG_SMP
+
+static void ipi_handler(void *info)
+/*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
+    [RETURNS] Nothing.
+*/
+{
+	struct set_mtrr_data *data = info;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	atomic_dec(&data->count);
+	while(!atomic_read(&data->gate)) {
+		cpu_relax();
+		barrier();
+	}
+
+	/*  The master has cleared me to execute  */
+	mtrr_if->set(data->smp_reg, data->smp_base, 
+		     data->smp_size, data->smp_type);
+
+	atomic_dec(&data->count);
+	while(atomic_read(&data->gate)) {
+		cpu_relax();
+		barrier();
+	}
+	local_irq_restore(flags);
+}
+
+#endif
+
+/**
+ * set_mtrr - update mtrrs on all processors
+ * @reg:	mtrr in question
+ * @base:	mtrr base
+ * @size:	mtrr size
+ * @type:	mtrr type
+ *
+ * This is kinda tricky, but fortunately, Intel spelled it out for us cleanly:
+ * 
+ * 1. Send IPI to do the following:
+ * 2. Disable Interrupts
+ * 3. Wait for all procs to do so 
+ * 4. Enter no-fill cache mode
+ * 5. Flush caches
+ * 6. Clear PGE bit
+ * 7. Flush all TLBs
+ * 8. Disable all range registers
+ * 9. Update the MTRRs
+ * 10. Enable all range registers
+ * 11. Flush all TLBs and caches again
+ * 12. Enter normal cache mode and reenable caching
+ * 13. Set PGE 
+ * 14. Wait for buddies to catch up
+ * 15. Enable interrupts.
+ * 
+ * What does that mean for us? Well, first we set data.count to the number
+ * of CPUs. As each CPU disables interrupts, it'll decrement it once. We wait
+ * until it hits 0 and proceed. We set the data.gate flag and reset data.count.
+ * Meanwhile, they are waiting for that flag to be set. Once it's set, each 
+ * CPU goes through the transition of updating MTRRs. The CPU vendors may each do it 
+ * differently, so we call mtrr_if->set() callback and let them take care of it.
+ * When they're done, they again decrement data->count and wait for data.gate to 
+ * be reset. 
+ * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag.
+ * Everyone then enables interrupts and we all continue on.
+ *
+ * Note that the mechanism is the same for UP systems, too; all the SMP stuff
+ * becomes nops.
+ */
+static void set_mtrr(unsigned int reg, unsigned long base,
+		     unsigned long size, mtrr_type type)
+{
+	struct set_mtrr_data data;
+	unsigned long flags;
+
+	data.smp_reg = reg;
+	data.smp_base = base;
+	data.smp_size = size;
+	data.smp_type = type;
+	atomic_set(&data.count, num_booting_cpus() - 1);
+	atomic_set(&data.gate,0);
+
+	/*  Start the ball rolling on other CPUs  */
+	if (smp_call_function(ipi_handler, &data, 1, 0) != 0)
+		panic("mtrr: timed out waiting for other CPUs\n");
+
+	local_irq_save(flags);
+
+	while(atomic_read(&data.count)) {
+		cpu_relax();
+		barrier();
+	}
+	/* ok, reset count and toggle gate */
+	atomic_set(&data.count, num_booting_cpus() - 1);
+	atomic_set(&data.gate,1);
+
+	/* do our MTRR business */
+	mtrr_if->set(reg,base,size,type);
+
+	/* wait for the others */
+	while(atomic_read(&data.count)) {
+		cpu_relax();
+		barrier();
+	}
+	local_irq_restore(flags);
+	atomic_set(&data.gate,0);
+}
+
+/**
+ *	mtrr_add_page - Add a memory type region
+ *	@base: Physical base address of region in pages (4 KB)
+ *	@size: Physical size of region in pages (4 KB)
+ *	@type: Type of MTRR desired
+ *	@increment: If this is true do usage counting on the region
+ *
+ *	Memory type region registers control the caching on newer Intel and
+ *	non Intel processors. This function allows drivers to request an
+ *	MTRR is added. The details and hardware specifics of each processor's
+ *	implementation are hidden from the caller, but nevertheless the 
+ *	caller should expect to need to provide a power of two size on an
+ *	equivalent power of two boundary.
+ *
+ *	If the region cannot be added either because all regions are in use
+ *	or the CPU cannot support it a negative value is returned. On success
+ *	the register number for this entry is returned, but should be treated
+ *	as a cookie only.
+ *
+ *	On a multiprocessor machine the changes are made to all processors.
+ *	This is required on x86 by the Intel processors.
+ *
+ *	The available types are
+ *
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
+ *
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
+ *
+ *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
+ *
+ *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
+ *
+ *	BUGS: Needs a quiet flag for the cases where drivers do not mind
+ *	failures and do not wish system log messages to be sent.
+ */
+
+int mtrr_add_page(unsigned long base, unsigned long size, 
+		  unsigned int type, char increment)
+{
+	int i;
+	mtrr_type ltype;
+	unsigned long lbase, lsize;
+	int error;
+
+	if (!mtrr_if)
+		return -ENXIO;
+		
+	if ((error = mtrr_if->validate_add_page(base,size,type)))
+		return error;
+
+	if (type >= MTRR_NUM_TYPES) {
+		printk("mtrr: type: %u illegal\n", type);
+		return -EINVAL;
+	}
+
+	/*  If the type is WC, check that this processor supports it  */
+	if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {
+		printk(KERN_WARNING
+		       "mtrr: your processor doesn't support write-combining\n");
+		return -ENOSYS;
+	}
+
+	if (base & size_or_mask || size & size_or_mask) {
+		printk("mtrr: base or size exceeds the MTRR width\n");
+		return -EINVAL;
+	}
+
+	error = -EINVAL;
+
+	/*  Search for existing MTRR  */
+	down(&main_lock);
+	for (i = 0; i < num_var_ranges; ++i) {
+		mtrr_if->get(i, &lbase, &lsize, &ltype);
+		if (base >= lbase + lsize)
+			continue;
+		if ((base < lbase) && (base + size <= lbase))
+			continue;
+		/*  At this point we know there is some kind of overlap/enclosure  */
+		if ((base < lbase) || (base + size > lbase + lsize)) {
+			printk(KERN_WARNING
+			       "mtrr: 0x%lx000,0x%lx000 overlaps existing"
+			       " 0x%lx000,0x%lx000\n", base, size, lbase,
+			       lsize);
+			goto out;
+		}
+		/*  New region is enclosed by an existing region  */
+		if (ltype != type) {
+			if (type == MTRR_TYPE_UNCACHABLE)
+				continue;
+			printk ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
+			     base, size, attrib_to_str(ltype),
+			     attrib_to_str(type));
+			goto out;
+		}
+		if (increment)
+			++usage_table[i];
+		compute_ascii();
+		error = i;
+		goto out;
+	}
+	/*  Search for an empty MTRR  */
+	i = mtrr_if->get_free_region(base, size);
+	if (i >= 0) {
+		set_mtrr(i, base, size, type);
+		usage_table[i] = 1;
+		compute_ascii();
+	} else
+		printk("mtrr: no more MTRRs available\n");
+	error = i;
+ out:
+	up(&main_lock);
+	return error;
+}
+
+/**
+ *	mtrr_add - Add a memory type region
+ *	@base: Physical base address of region
+ *	@size: Physical size of region
+ *	@type: Type of MTRR desired
+ *	@increment: If this is true do usage counting on the region
+ *
+ *	Memory type region registers control the caching on newer Intel and
+ *	non Intel processors. This function allows drivers to request an
+ *	MTRR is added. The details and hardware specifics of each processor's
+ *	implementation are hidden from the caller, but nevertheless the 
+ *	caller should expect to need to provide a power of two size on an
+ *	equivalent power of two boundary.
+ *
+ *	If the region cannot be added either because all regions are in use
+ *	or the CPU cannot support it a negative value is returned. On success
+ *	the register number for this entry is returned, but should be treated
+ *	as a cookie only.
+ *
+ *	On a multiprocessor machine the changes are made to all processors.
+ *	This is required on x86 by the Intel processors.
+ *
+ *	The available types are
+ *
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
+ *
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
+ *
+ *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
+ *
+ *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
+ *
+ *	BUGS: Needs a quiet flag for the cases where drivers do not mind
+ *	failures and do not wish system log messages to be sent.
+ */
+
+int
+mtrr_add(unsigned long base, unsigned long size, unsigned int type,
+	 char increment)
+{
+	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+		printk("mtrr: size and base must be multiples of 4 kiB\n");
+		printk("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+		return -EINVAL;
+	}
+	return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
+			     increment);
+}
+
+/**
+ *	mtrr_del_page - delete a memory type region
+ *	@reg: Register returned by mtrr_add
+ *	@base: Physical base address
+ *	@size: Size of region
+ *
+ *	If register is supplied then base and size are ignored. This is
+ *	how drivers should call it.
+ *
+ *	Releases an MTRR region. If the usage count drops to zero the 
+ *	register is freed and the region returns to default state.
+ *	On success the register is returned, on failure a negative error
+ *	code.
+ */
+
+int mtrr_del_page(int reg, unsigned long base, unsigned long size)
+{
+	int i, max;
+	mtrr_type ltype;
+	unsigned long lbase, lsize;
+	int error = -EINVAL;
+
+	if (!mtrr_if)
+		return -ENXIO;
+
+	max = num_var_ranges;
+	down(&main_lock);
+	if (reg < 0) {
+		/*  Search for existing MTRR  */
+		for (i = 0; i < max; ++i) {
+			mtrr_if->get(i, &lbase, &lsize, &ltype);
+			if (lbase == base && lsize == size) {
+				reg = i;
+				break;
+			}
+		}
+		if (reg < 0) {
+			printk("mtrr: no MTRR for %lx000,%lx000 found\n", base,
+			       size);
+			goto out;
+		}
+	}
+	if (reg >= max) {
+		printk("mtrr: register: %d too big\n", reg);
+		goto out;
+	}
+	if (is_cpu(CYRIX) && !use_intel()) {
+		if ((reg == 3) && arr3_protected) {
+			printk("mtrr: ARR3 cannot be changed\n");
+			goto out;
+		}
+	}
+	mtrr_if->get(reg, &lbase, &lsize, &ltype);
+	if (lsize < 1) {
+		printk("mtrr: MTRR %d not used\n", reg);
+		goto out;
+	}
+	if (usage_table[reg] < 1) {
+		printk("mtrr: reg: %d has count=0\n", reg);
+		goto out;
+	}
+	if (--usage_table[reg] < 1)
+		set_mtrr(reg, 0, 0, 0);
+	compute_ascii();
+	error = reg;
+ out:
+	up(&main_lock);
+	return error;
+}
+/**
+ *	mtrr_del - delete a memory type region
+ *	@reg: Register returned by mtrr_add
+ *	@base: Physical base address
+ *	@size: Size of region
+ *
+ *	If register is supplied then base and size are ignored. This is
+ *	how drivers should call it.
+ *
+ *	Releases an MTRR region. If the usage count drops to zero the 
+ *	register is freed and the region returns to default state.
+ *	On success the register is returned, on failure a negative error
+ *	code.
+ */
+
+int
+mtrr_del(int reg, unsigned long base, unsigned long size)
+{
+	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+		printk("mtrr: size and base must be multiples of 4 kiB\n");
+		printk("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+		return -EINVAL;
+	}
+	return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
+
+EXPORT_SYMBOL(mtrr_add);
+EXPORT_SYMBOL(mtrr_del);
+
+/* HACK ALERT!
+ * These should be called implicitly, but we can't yet until all the initcall
+ * stuff is done...
+ */
+extern void amd_init_mtrr(void);
+extern void cyrix_init_mtrr(void);
+extern void centaur_init_mtrr(void);
+
+static void __init init_ifs(void)
+{
+	amd_init_mtrr();
+	cyrix_init_mtrr();
+	centaur_init_mtrr();
+}
+
+/**
+ * mtrr_init - initialie mtrrs on the boot CPU
+ *
+ * This needs to be called early; before any of the other CPUs are 
+ * initialized (i.e. before smp_init()).
+ * 
+ */
+int __init mtrr_init(void)
+{
+	init_ifs();
+
+	if ( cpu_has_mtrr ) {
+		mtrr_if = &generic_mtrr_ops;
+		size_or_mask = 0xff000000;	/* 36 bits */
+		size_and_mask = 0x00f00000;
+			
+		switch (boot_cpu_data.x86_vendor) {
+		case X86_VENDOR_AMD:
+			/* The original Athlon docs said that
+			   total addressable memory is 44 bits wide.
+			   It was not really clear whether its MTRRs
+			   follow this or not. (Read: 44 or 36 bits).
+			   However, "x86-64_overview.pdf" explicitly
+			   states that "previous implementations support
+			   36 bit MTRRs" and also provides a way to
+			   query the width (in bits) of the physical
+			   addressable memory on the Hammer family.
+			 */
+			if (boot_cpu_data.x86 == 7
+			    && (cpuid_eax(0x80000000) >= 0x80000008)) {
+				u32 phys_addr;
+				phys_addr = cpuid_eax(0x80000008) & 0xff;
+				size_or_mask =
+				    ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+				size_and_mask = ~size_or_mask & 0xfff00000;
+			}
+			/* Athlon MTRRs use an Intel-compatible interface for 
+			 * getting and setting */
+			break;
+		case X86_VENDOR_CENTAUR:
+			if (boot_cpu_data.x86 == 6) {
+				/* VIA Cyrix family have Intel style MTRRs, but don't support PAE */
+				size_or_mask = 0xfff00000;	/* 32 bits */
+				size_and_mask = 0;
+			}
+			break;
+		
+		default:
+			break;
+		}
+	} else {
+		switch (boot_cpu_data.x86_vendor) {
+		case X86_VENDOR_AMD:
+			if ( cpu_has_k6_mtrr ) {
+				/* Pre-Athlon (K6) AMD CPU MTRRs */
+				mtrr_if = mtrr_ops[X86_VENDOR_AMD];
+				size_or_mask = 0xfff00000;	/* 32 bits */
+				size_and_mask = 0;
+			}
+			break;
+		case X86_VENDOR_CENTAUR:
+			if ( cpu_has_centaur_mcr ) {
+				mtrr_if = mtrr_ops[X86_VENDOR_CENTAUR];
+				size_or_mask = 0xfff00000;	/* 32 bits */
+				size_and_mask = 0;
+			}
+			break;
+		case X86_VENDOR_CYRIX:
+			if ( cpu_has_cyrix_arr ) {
+				mtrr_if = mtrr_ops[X86_VENDOR_CYRIX];
+				size_or_mask = 0xfff00000;	/* 32 bits */
+				size_and_mask = 0;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	if (mtrr_if) {
+		set_num_var_ranges();
+		if (use_intel()) {
+			/* Only for Intel MTRRs */
+			get_mtrr_state();
+		}
+		init_table();
+	}
+#if 0
+	printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
+	       "mtrr: detected mtrr type: %s\n",
+	       MTRR_VERSION, mtrr_if_name[mtrr_if]);
+#endif
+	return mtrr_if ? -ENXIO : 0;
+}
+
+//subsys_initcall(mtrr_init);
+
diff -Nru a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,98 @@
+/*
+ * local mtrr defines.
+ */
+
+#ifndef TRUE
+#define TRUE  1
+#define FALSE 0
+#endif
+
+#define MTRRcap_MSR     0x0fe
+#define MTRRdefType_MSR 0x2ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define NUM_FIXED_RANGES 88
+#define MTRRfix64K_00000_MSR 0x250
+#define MTRRfix16K_80000_MSR 0x258
+#define MTRRfix16K_A0000_MSR 0x259
+#define MTRRfix4K_C0000_MSR 0x268
+#define MTRRfix4K_C8000_MSR 0x269
+#define MTRRfix4K_D0000_MSR 0x26a
+#define MTRRfix4K_D8000_MSR 0x26b
+#define MTRRfix4K_E0000_MSR 0x26c
+#define MTRRfix4K_E8000_MSR 0x26d
+#define MTRRfix4K_F0000_MSR 0x26e
+#define MTRRfix4K_F8000_MSR 0x26f
+
+#define MTRR_CHANGE_MASK_FIXED     0x01
+#define MTRR_CHANGE_MASK_VARIABLE  0x02
+#define MTRR_CHANGE_MASK_DEFTYPE   0x04
+
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
+   an 8 bit field: */
+typedef u8 mtrr_type;
+
+struct mtrr_ops {
+	u32	vendor;
+	u32	use_intel_if;
+	void	(*init)(void);
+	void	(*init_secondary)(void);
+	void	(*set)(unsigned int reg, unsigned long base,
+		       unsigned long size, mtrr_type type);
+	void	(*get)(unsigned int reg, unsigned long *base,
+		       unsigned long *size, mtrr_type * type);
+	int	(*get_free_region) (unsigned long base, unsigned long size);
+
+	int	(*validate_add_page)(unsigned long base, unsigned long size,
+				     unsigned int type);
+	int	(*have_wrcomb)(void);
+};
+
+extern int generic_get_free_region(unsigned long base, unsigned long size);
+extern void generic_init_secondary(void);
+extern int generic_validate_add_page(unsigned long base, unsigned long size,
+				     unsigned int type);
+
+extern struct mtrr_ops generic_mtrr_ops;
+
+extern int generic_have_wrcomb(void);
+extern int positive_have_wrcomb(void);
+
+/* library functions for processor-specific routines */
+struct set_mtrr_context {
+	unsigned long flags;
+	unsigned long deftype_lo;
+	unsigned long deftype_hi;
+	unsigned long cr4val;
+	unsigned long ccr3;
+};
+
+struct mtrr_var_range {
+	unsigned long base_lo;
+	unsigned long base_hi;
+	unsigned long mask_lo;
+	unsigned long mask_hi;
+};
+
+void set_mtrr_done(struct set_mtrr_context *ctxt);
+void set_mtrr_cache_disable(struct set_mtrr_context *ctxt);
+void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
+
+void get_mtrr_state(void);
+
+extern void set_mtrr_ops(struct mtrr_ops * ops);
+
+/* Don't even ask... */
+extern void compute_ascii(void);
+
+extern u32 size_or_mask, size_and_mask;
+extern struct mtrr_ops * mtrr_if;
+
+#define is_cpu(vnd)	(mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd)
+#define use_intel()	(mtrr_if && mtrr_if->use_intel_if == 1)
+
+extern unsigned int num_var_ranges;
+
+extern char * mtrr_if_name[];
diff -Nru a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mtrr/state.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,338 @@
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+#include "mtrr.h"
+
+struct mtrr_state {
+	struct mtrr_var_range *var_ranges;
+	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
+	unsigned char enabled;
+	mtrr_type def_type;
+};
+
+static unsigned long smp_changes_mask __initdata = 0;
+struct mtrr_state mtrr_state = {};
+
+static int __init set_fixed_ranges(mtrr_type * frs)
+{
+	unsigned long *p = (unsigned long *) frs;
+	int changed = FALSE;
+	int i;
+	unsigned long lo, hi;
+
+	rdmsr(MTRRfix64K_00000_MSR, lo, hi);
+	if (p[0] != lo || p[1] != hi) {
+		wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+		changed = TRUE;
+	}
+
+	for (i = 0; i < 2; i++) {
+		rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
+		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
+			wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
+			      p[3 + i * 2]);
+			changed = TRUE;
+		}
+	}
+
+	for (i = 0; i < 8; i++) {
+		rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
+		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
+			wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
+			      p[7 + i * 2]);
+			changed = TRUE;
+		}
+	}
+	return changed;
+}
+
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
+static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
+{
+	unsigned int lo, hi;
+	int changed = FALSE;
+
+	rdmsr(MTRRphysBase_MSR(index), lo, hi);
+	if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
+	    || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
+		wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+		changed = TRUE;
+	}
+
+	rdmsr(MTRRphysMask_MSR(index), lo, hi);
+
+	if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
+	    || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
+		wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+		changed = TRUE;
+	}
+	return changed;
+}
+
+static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
+/*  [SUMMARY] Set the MTRR state for this CPU.
+    <state> The MTRR state information to read.
+    <ctxt> Some relevant CPU context.
+    [NOTE] The CPU must already be in a safe state for MTRR changes.
+    [RETURNS] 0 if no changes made, else a mask indication what was changed.
+*/
+{
+	unsigned int i;
+	unsigned long change_mask = 0;
+
+	for (i = 0; i < num_var_ranges; i++)
+		if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
+			change_mask |= MTRR_CHANGE_MASK_VARIABLE;
+
+	if (set_fixed_ranges(mtrr_state.fixed_ranges))
+		change_mask |= MTRR_CHANGE_MASK_FIXED;
+
+	/*  Set_mtrr_restore restores the old value of MTRRdefType,
+	   so to set it we fiddle with the saved value  */
+	if ((deftype_lo & 0xff) != mtrr_state.def_type
+	    || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
+		deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10);
+		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
+	}
+
+	return change_mask;
+}
+
+
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
+static void __init mtrr_state_warn(void)
+{
+	unsigned long mask = smp_changes_mask;
+	if (!mask)
+		return;
+	if (mask & MTRR_CHANGE_MASK_FIXED)
+		printk
+		    ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_VARIABLE)
+		printk
+		    ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_DEFTYPE)
+		printk
+		    ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+	printk("mtrr: probably your BIOS does not setup all CPUs\n");
+}
+
+/*  Free resources associated with a struct mtrr_state  */
+static void __init finalize_mtrr_state(void)
+{
+	if (mtrr_state.var_ranges)
+		kfree(mtrr_state.var_ranges);
+	mtrr_state.var_ranges = NULL;
+}
+
+/*  Get the MSR pair relating to a var range  */
+static void __init
+get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
+{
+	rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+	rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+}
+
+static void __init
+get_fixed_ranges(mtrr_type * frs)
+{
+	unsigned long *p = (unsigned long *) frs;
+	int i;
+
+	rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+
+	for (i = 0; i < 2; i++)
+		rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]);
+	for (i = 0; i < 8; i++)
+		rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
+}
+
+/*  Grab all of the MTRR state for this CPU into *state  */
+void get_mtrr_state(void)
+{
+	unsigned int i;
+	struct mtrr_var_range *vrs;
+	unsigned long lo, dummy;
+
+	if (!mtrr_state.var_ranges) {
+		mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), 
+						GFP_KERNEL);
+		if (!mtrr_state.var_ranges)
+			return;
+	} 
+	vrs = mtrr_state.var_ranges;
+
+	for (i = 0; i < num_var_ranges; i++)
+		get_mtrr_var_range(i, &vrs[i]);
+	get_fixed_ranges(mtrr_state.fixed_ranges);
+
+	rdmsr(MTRRdefType_MSR, lo, dummy);
+	mtrr_state.def_type = (lo & 0xff);
+	mtrr_state.enabled = (lo & 0xc00) >> 10;
+}
+
+
+/*  Put the processor into a state where MTRRs can be safely set  */
+void set_mtrr_prepare_save(struct set_mtrr_context *ctxt)
+{
+	unsigned int cr0;
+
+	/*  Disable interrupts locally  */
+	local_irq_save(ctxt->flags);
+
+	if (use_intel() || is_cpu(CYRIX)) {
+
+		/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+		if ( cpu_has_pge ) {
+			ctxt->cr4val = read_cr4();
+			write_cr4(ctxt->cr4val & (unsigned char) ~(1 << 7));
+		}
+
+		/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+		    a side-effect  */
+		cr0 = read_cr0() | 0x40000000;
+		wbinvd();
+		write_cr0(cr0);
+		wbinvd();
+
+		if (use_intel())
+			/*  Save MTRR state */
+			rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+		else
+			/* Cyrix ARRs - everything else were excluded at the top */
+			ctxt->ccr3 = getCx86(CX86_CCR3);
+	}
+}
+
+void set_mtrr_cache_disable(struct set_mtrr_context *ctxt)
+{
+	if (use_intel()) 
+		/*  Disable MTRRs, and set the default type to uncached  */
+		wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
+		      ctxt->deftype_hi);
+	else if (is_cpu(CYRIX))
+		/* Cyrix ARRs - everything else were excluded at the top */
+		setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
+}
+
+/*  Restore the processor after a set_mtrr_prepare  */
+void set_mtrr_done(struct set_mtrr_context *ctxt)
+{
+	if (use_intel() || is_cpu(CYRIX)) {
+
+		/*  Flush caches and TLBs  */
+		wbinvd();
+
+		/*  Restore MTRRdefType  */
+		if (use_intel())
+			/* Intel (P6) standard MTRRs */
+			wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+		else
+			/* Cyrix ARRs - everything else was excluded at the top */
+			setCx86(CX86_CCR3, ctxt->ccr3);
+		
+		/*  Enable caches  */
+		write_cr0(read_cr0() & 0xbfffffff);
+
+		/*  Restore value of CR4  */
+		if ( cpu_has_pge )
+			write_cr4(ctxt->cr4val);
+	}
+	/*  Re-enable interrupts locally (if enabled previously)  */
+	local_irq_restore(ctxt->flags);
+}
+
+void __init generic_init_secondary(void)
+{
+	u32 cr0, cr4 = 0;
+	u32 deftype_lo, deftype_hi;
+	unsigned long mask, count;
+
+	/*  Note that this is not ideal, since the cache is only flushed/disabled
+	   for this CPU while the MTRRs are changed, but changing this requires
+	   more invasive changes to the way the kernel boots  */
+
+	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+	if ( cpu_has_pge ) {
+		cr4 = read_cr4();
+		write_cr4(cr4 & (unsigned char) ~(1 << 7));
+	}
+
+	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	    a side-effect  */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/*  Save MTRR state */
+	rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+
+	/*  Disable MTRRs, and set the default type to uncached  */
+	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+
+	/* Actually set the state */
+	mask = set_mtrr_state(deftype_lo,deftype_hi);
+
+	/*  Flush caches and TLBs  */
+	wbinvd();
+
+	/* Intel (P6) standard MTRRs */
+	wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+		
+	/*  Enable caches  */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/*  Restore value of CR4  */
+	if ( cpu_has_pge )
+		write_cr4(cr4);
+
+	/*  Use the atomic bitops to update the global mask  */
+	for (count = 0; count < sizeof mask * 8; ++count) {
+		if (mask & 0x01)
+			set_bit(count, &smp_changes_mask);
+		mask >>= 1;
+	}
+}
+
+/**
+ * mtrr_init_secondary - setup AP MTRR state
+ * 
+ * Yes, this code is exactly the same as the set_mtrr code, except for the 
+ * piece in the middle - you set all the ranges at once, instead of one
+ * register at a time.
+ * Shoot me.
+ */
+void __init mtrr_init_secondary_cpu(void)
+{
+	unsigned long flags;
+
+	if (!mtrr_if || !mtrr_if->init_secondary) {
+		/* I see no MTRRs I can support in SMP mode... */
+		printk("mtrr: SMP support incomplete for this vendor\n");
+		return;
+	}
+
+	local_irq_save(flags);
+	mtrr_if->init_secondary();
+	local_irq_restore(flags);
+}
+
+/**
+ * mtrr_final_init  - finalize initialization sequence.
+ */
+static int __init mtrr_finalize_state(void)
+{
+	if (use_intel()) {
+		finalize_mtrr_state();
+		mtrr_state_warn();
+	}
+	return 0;
+}
+
+arch_initcall(mtrr_finalize_state);
+
diff -Nru a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
--- a/arch/i386/kernel/cpu/nexgen.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/cpu/nexgen.c	Tue Aug 27 12:27:59 2002
@@ -42,13 +42,13 @@
 }
 
 static struct cpu_dev nexgen_cpu_dev __initdata = {
-	c_vendor:	"Nexgen",
-	c_ident:	{ "NexGenDriven" },
+	.c_vendor	= "Nexgen",
+	.c_ident	= { "NexGenDriven" },
 	c_models: {
 		{ X86_VENDOR_NEXGEN,5, { [1] "Nx586" } },
 	},
-	c_init:		init_nexgen,
-	c_identify:	nexgen_identify,
+	.c_init		= init_nexgen,
+	.c_identify	= nexgen_identify,
 };
 
 int __init nexgen_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
--- a/arch/i386/kernel/cpu/proc.c	Tue Aug 27 12:28:08 2002
+++ b/arch/i386/kernel/cpu/proc.c	Tue Aug 27 12:28:08 2002
@@ -119,8 +119,8 @@
 {
 }
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo,
 };
diff -Nru a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
--- a/arch/i386/kernel/cpu/rise.c	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/cpu/rise.c	Tue Aug 27 12:28:01 2002
@@ -29,8 +29,8 @@
 }
 
 static struct cpu_dev rise_cpu_dev __initdata = {
-	c_vendor:	"Rise",
-	c_ident:	{ "RiseRiseRise" },
+	.c_vendor	= "Rise",
+	.c_ident	= { "RiseRiseRise" },
 	c_models: {
 		{ X86_VENDOR_RISE,	5,
 		  { 
@@ -41,7 +41,7 @@
 		  }
 		},
 	},
-	c_init:		init_rise,
+	.c_init		= init_rise,
 };
 
 int __init rise_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
--- a/arch/i386/kernel/cpu/transmeta.c	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/cpu/transmeta.c	Tue Aug 27 12:28:01 2002
@@ -80,10 +80,10 @@
 }
 
 static struct cpu_dev transmeta_cpu_dev __initdata = {
-	c_vendor:	"Transmeta",
-	c_ident:	{ "GenuineTMx86", "TransmetaCPU" },
-	c_init:		init_transmeta,
-	c_identify:	transmeta_identify,
+	.c_vendor	= "Transmeta",
+	.c_ident	= { "GenuineTMx86", "TransmetaCPU" },
+	.c_init		= init_transmeta,
+	.c_identify	= transmeta_identify,
 };
 
 int __init transmeta_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
--- a/arch/i386/kernel/cpu/umc.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/cpu/umc.c	Tue Aug 27 12:27:59 2002
@@ -11,8 +11,8 @@
 }
 
 static struct cpu_dev umc_cpu_dev __initdata = {
-	c_vendor:	"UMC",
-	c_ident: 	{ "UMC UMC UMC" },
+	.c_vendor	= "UMC",
+	.c_ident 	= { "UMC UMC UMC" },
 	c_models: {
 		{ X86_VENDOR_UMC,	4,
 		  { 
@@ -21,7 +21,7 @@
 		  }
 		},
 	},
-	c_init:		init_umc,
+	.c_init		= init_umc,
 };
 
 int __init umc_init_cpu(void)
diff -Nru a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
--- a/arch/i386/kernel/cpuid.c	Tue Aug 27 12:27:42 2002
+++ b/arch/i386/kernel/cpuid.c	Tue Aug 27 12:27:42 2002
@@ -146,10 +146,10 @@
  * File operations we support
  */
 static struct file_operations cpuid_fops = {
-  owner:	THIS_MODULE,
-  llseek:	cpuid_seek,
-  read:		cpuid_read,
-  open:		cpuid_open,
+  .owner	= THIS_MODULE,
+  .llseek	= cpuid_seek,
+  .read		= cpuid_read,
+  .open		= cpuid_open,
 };
 
 int __init cpuid_init(void)
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/dmi_scan.c	Tue Aug 27 12:28:02 2002
@@ -7,7 +7,6 @@
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <linux/pm.h>
-#include <asm/keyboard.h>
 #include <asm/system.h>
 #include <linux/bootmem.h>
 
@@ -393,21 +392,13 @@
 }
 
 /*
- * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it
- * was disabled before the suspend. Linux gets terribly confused by that.
+ * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it was
+ * disabled before the suspend. Linux used to get terribly confused by that.
  */
 
-typedef void (pm_kbd_func) (void);
-
 static __init int broken_ps2_resume(struct dmi_blacklist *d)
 {
-#ifdef CONFIG_VT
-	if (pm_kbd_request_override == NULL)
-	{
-		pm_kbd_request_override = pckbd_pm_resume;
-		printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident);
-	}
-#endif
+	printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround hopefully not needed.\n", d->ident);
 	return 0;
 }
 
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/entry.S	Tue Aug 27 12:28:02 2002
@@ -753,6 +753,12 @@
 	.long sys_sched_setaffinity
 	.long sys_sched_getaffinity
 	.long sys_set_thread_area
+	.long sys_get_thread_area
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/head.S	Tue Aug 27 12:27:59 2002
@@ -239,12 +239,7 @@
 	movl %eax,%es
 	movl %eax,%fs
 	movl %eax,%gs
-#ifdef CONFIG_SMP
-	movl $(__KERNEL_DS), %eax
-	movl %eax,%ss		# Reload the stack pointer (segment only)
-#else
-	lss stack_start,%esp	# Load processor stack
-#endif
+	movl %eax,%ss
 	xorl %eax,%eax
 	lldt %ax
 	cld			# gcc2 wants the direction flag cleared at all times
@@ -412,34 +407,40 @@
 
 ALIGN
 /*
- * The Global Descriptor Table contains 20 quadwords, per-CPU.
+ * The Global Descriptor Table contains 28 quadwords, per-CPU.
  */
 ENTRY(cpu_gdt_table)
 	.quad 0x0000000000000000	/* NULL descriptor */
-	.quad 0x0000000000000000	/* TLS descriptor */
-	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
-	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
-	.quad 0x00cffa000000ffff	/* 0x23 user   4GB code at 0x00000000 */
-	.quad 0x00cff2000000ffff	/* 0x2b user   4GB data at 0x00000000 */
-	.quad 0x0000000000000000	/* TSS descriptor */
-	.quad 0x0000000000000000	/* LDT descriptor */
+	.quad 0x0000000000000000	/* 0x0b reserved */
+	.quad 0x0000000000000000	/* 0x13 reserved */
+	.quad 0x0000000000000000	/* 0x1b reserved */
+	.quad 0x00cffa000000ffff	/* 0x23 user 4GB code at 0x00000000 */
+	.quad 0x00cff2000000ffff	/* 0x2b user 4GB data at 0x00000000 */
+	.quad 0x0000000000000000	/* 0x33 TLS entry 1 */
+	.quad 0x0000000000000000	/* 0x3b TLS entry 2 */
+	.quad 0x0000000000000000	/* 0x43 TLS entry 3 */
+	.quad 0x0000000000000000	/* 0x4b reserved */
+	.quad 0x0000000000000000	/* 0x53 reserved */
+	.quad 0x0000000000000000	/* 0x5b reserved */
+
+	.quad 0x00cf9a000000ffff	/* 0x60 kernel 4GB code at 0x00000000 */
+	.quad 0x00cf92000000ffff	/* 0x68 kernel 4GB data at 0x00000000 */
+	.quad 0x0000000000000000	/* 0x70 TSS descriptor */
+	.quad 0x0000000000000000	/* 0x78 LDT descriptor */
+
+	/* Segments used for calling PnP BIOS */
+	.quad 0x00c09a0000000000	/* 0x80 32-bit code */
+	.quad 0x00809a0000000000	/* 0x88 16-bit code */
+	.quad 0x0080920000000000	/* 0x90 16-bit data */
+	.quad 0x0080920000000000	/* 0x98 16-bit data */
+	.quad 0x0080920000000000	/* 0xa0 16-bit data */
 	/*
 	 * The APM segments have byte granularity and their bases
 	 * and limits are set at run time.
 	 */
-	.quad 0x0040920000000000	/* 0x40 APM set up for bad BIOS's */
-	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
-	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
-	.quad 0x0040920000000000	/* 0x58 APM DS    data */
-	/* Segments used for calling PnP BIOS */
-	.quad 0x00c09a0000000000	/* 0x60 32-bit code */
-	.quad 0x00809a0000000000	/* 0x68 16-bit code */
-	.quad 0x0080920000000000	/* 0x70 16-bit data */
-	.quad 0x0080920000000000	/* 0x78 16-bit data */
-	.quad 0x0080920000000000	/* 0x80 16-bit data */
-	.quad 0x0000000000000000	/* 0x88 not used */
-	.quad 0x0000000000000000	/* 0x90 not used */
-	.quad 0x0000000000000000	/* 0x98 not used */
+	.quad 0x00409a0000000000	/* 0xa8 APM CS    code */
+	.quad 0x00009a0000000000	/* 0xb0 APM CS 16 code (16 bit) */
+	.quad 0x0040920000000000	/* 0xb8 APM DS    data */
 
 #if CONFIG_SMP
 	.fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Tue Aug 27 12:28:05 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Tue Aug 27 12:28:05 2002
@@ -126,7 +126,6 @@
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL_NOVERS(__write_lock_failed);
 EXPORT_SYMBOL_NOVERS(__read_lock_failed);
diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
--- a/arch/i386/kernel/i8259.c	Tue Aug 27 12:28:08 2002
+++ b/arch/i386/kernel/i8259.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,4 @@
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -247,13 +246,13 @@
 }
 
 static struct device_driver driver_i8259A = {
-	resume:		i8259A_resume,
+	.resume		= i8259A_resume,
 };
 
 static struct device device_i8259A = {
-	name:	       	"i8259A",
-	bus_id:		"0020",
-	driver:		&driver_i8259A,
+	.name	       	= "i8259A",
+	.bus_id		= "0020",
+	.driver		= &driver_i8259A,
 };
 
 static int __init init_8259A_devicefs(void)
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/io_apic.c	Tue Aug 27 12:28:02 2002
@@ -220,6 +220,9 @@
 		((1 << cpu) & (allowed_mask))
 
 #if CONFIG_SMP
+
+#define IRQ_BALANCE_INTERVAL (HZ/50)
+	
 static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction)
 {
 	int search_idle = 1;
@@ -251,8 +254,12 @@
 	irq_balance_t *entry = irq_balance + irq;
 	unsigned long now = jiffies;
 
-	if (entry->timestamp != now) {
+	if (clustered_apic_mode)
+		return;
+
+	if (unlikely(time_after(now, entry->timestamp + IRQ_BALANCE_INTERVAL))) {
 		unsigned long allowed_mask;
+		unsigned int new_cpu;
 		int random_number;
 
 		rdtscl(random_number);
@@ -260,8 +267,11 @@
 
 		allowed_mask = cpu_online_map & irq_affinity[irq];
 		entry->timestamp = now;
-		entry->cpu = move(entry->cpu, allowed_mask, now, random_number);
-		set_ioapic_affinity(irq, 1 << entry->cpu);
+		new_cpu = move(entry->cpu, allowed_mask, now, random_number);
+		if (entry->cpu != new_cpu) {
+			entry->cpu = new_cpu;
+			set_ioapic_affinity(irq, 1 << new_cpu);
+		}
 	}
 }
 #else /* !SMP */
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/irq.c	Tue Aug 27 12:27:59 2002
@@ -18,7 +18,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
--- a/arch/i386/kernel/ldt.c	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/ldt.c	Tue Aug 27 12:28:01 2002
@@ -170,7 +170,7 @@
 	struct mm_struct * mm = current->mm;
 	__u32 entry_1, entry_2, *lp;
 	int error;
-	struct modify_ldt_ldt_s ldt_info;
+	struct user_desc ldt_info;
 
 	error = -EINVAL;
 	if (bytecount != sizeof(ldt_info))
@@ -200,32 +200,17 @@
 
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
-		if (oldmode ||
-		    (ldt_info.contents == 0		&&
-		     ldt_info.read_exec_only == 1	&&
-		     ldt_info.seg_32bit == 0		&&
-		     ldt_info.limit_in_pages == 0	&&
-		     ldt_info.seg_not_present == 1	&&
-		     ldt_info.useable == 0 )) {
+		if (oldmode || LDT_empty(&ldt_info)) {
 			entry_1 = 0;
 			entry_2 = 0;
 			goto install;
 		}
 	}
 
-	entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
-		  (ldt_info.limit & 0x0ffff);
-	entry_2 = (ldt_info.base_addr & 0xff000000) |
-		  ((ldt_info.base_addr & 0x00ff0000) >> 16) |
-		  (ldt_info.limit & 0xf0000) |
-		  ((ldt_info.read_exec_only ^ 1) << 9) |
-		  (ldt_info.contents << 10) |
-		  ((ldt_info.seg_not_present ^ 1) << 15) |
-		  (ldt_info.seg_32bit << 22) |
-		  (ldt_info.limit_in_pages << 23) |
-		  0x7000;
-	if (!oldmode)
-		entry_2 |= (ldt_info.useable << 20);
+	entry_1 = LDT_entry_a(&ldt_info);
+	entry_2 = LDT_entry_b(&ldt_info);
+	if (oldmode)
+		entry_2 &= ~(1 << 20);
 
 	/* Install the new entry ...  */
 install:
diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
--- a/arch/i386/kernel/microcode.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/microcode.c	Tue Aug 27 12:28:02 2002
@@ -109,17 +109,17 @@
 
 /* we share file_operations between misc and devfs mechanisms */
 static struct file_operations microcode_fops = {
-	owner:		THIS_MODULE,
-	read:		microcode_read,
-	write:		microcode_write,
-	ioctl:		microcode_ioctl,
-	open:		microcode_open,
+	.owner		= THIS_MODULE,
+	.read		= microcode_read,
+	.write		= microcode_write,
+	.ioctl		= microcode_ioctl,
+	.open		= microcode_open,
 };
 
 static struct miscdevice microcode_dev = {
-	minor: MICROCODE_MINOR,
-	name:	"microcode",
-	fops:	&microcode_fops,
+	.minor = MICROCODE_MINOR,
+	.name	= "microcode",
+	.fops	= &microcode_fops,
 };
 
 static devfs_handle_t devfs_handle;
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/kernel/mpparse.c	Tue Aug 27 12:28:02 2002
@@ -213,7 +213,6 @@
 		quad = translation_table[mpc_record]->trans_quad;
 		mp_bus_id_to_node[m->mpc_busid] = quad;
 		mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
-		quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
 		printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
 	} else {
 		Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
@@ -224,6 +223,9 @@
 	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
 		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
 	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
+		if (clustered_apic_mode){
+			quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
+		}
 		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
 		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
 		mp_current_pci_id++;
diff -Nru a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c	Tue Aug 27 12:28:05 2002
+++ b/arch/i386/kernel/msr.c	Tue Aug 27 12:28:05 2002
@@ -246,11 +246,11 @@
  * File operations we support
  */
 static struct file_operations msr_fops = {
-  owner:	THIS_MODULE,
-  llseek:	msr_seek,
-  read:		msr_read,
-  write:	msr_write,
-  open:		msr_open,
+  .owner	= THIS_MODULE,
+  .llseek	= msr_seek,
+  .read		= msr_read,
+  .write	= msr_write,
+  .open		= msr_open,
 };
 
 int __init msr_init(void)
diff -Nru a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
--- a/arch/i386/kernel/mtrr.c	Tue Aug 27 12:27:57 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,2303 +0,0 @@
-/*  Generic MTRR (Memory Type Range Register) driver.
-
-    Copyright (C) 1997-2000  Richard Gooch
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-
-    Source: "Pentium Pro Family Developer's Manual, Volume 3:
-    Operating System Writer's Guide" (Intel document number 242692),
-    section 11.11.7
-
-    ChangeLog
-
-    Prehistory Martin Tischhäuser <martin@ikcbarka.fzk.de>
-	       Initial register-setting code (from proform-1.0).
-    19971216   Richard Gooch <rgooch@atnf.csiro.au>
-               Original version for /proc/mtrr interface, SMP-safe.
-  v1.0
-    19971217   Richard Gooch <rgooch@atnf.csiro.au>
-               Bug fix for ioctls()'s.
-	       Added sample code in Documentation/mtrr.txt
-  v1.1
-    19971218   Richard Gooch <rgooch@atnf.csiro.au>
-               Disallow overlapping regions.
-    19971219   Jens Maurer <jmaurer@menuett.rhein-main.de>
-               Register-setting fixups.
-  v1.2
-    19971222   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixups for kernel 2.1.75.
-  v1.3
-    19971229   David Wragg <dpw@doc.ic.ac.uk>
-               Register-setting fixups and conformity with Intel conventions.
-    19971229   Richard Gooch <rgooch@atnf.csiro.au>
-               Cosmetic changes and wrote this ChangeLog ;-)
-    19980106   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixups for kernel 2.1.78.
-  v1.4
-    19980119   David Wragg <dpw@doc.ic.ac.uk>
-               Included passive-release enable code (elsewhere in PCI setup).
-  v1.5
-    19980131   Richard Gooch <rgooch@atnf.csiro.au>
-               Replaced global kernel lock with private spinlock.
-  v1.6
-    19980201   Richard Gooch <rgooch@atnf.csiro.au>
-               Added wait for other CPUs to complete changes.
-  v1.7
-    19980202   Richard Gooch <rgooch@atnf.csiro.au>
-               Bug fix in definition of <set_mtrr> for UP.
-  v1.8
-    19980319   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixups for kernel 2.1.90.
-    19980323   Richard Gooch <rgooch@atnf.csiro.au>
-               Move SMP BIOS fixup before secondary CPUs call <calibrate_delay>
-  v1.9
-    19980325   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed test for overlapping regions: confused by adjacent regions
-    19980326   Richard Gooch <rgooch@atnf.csiro.au>
-               Added wbinvd in <set_mtrr_prepare>.
-    19980401   Richard Gooch <rgooch@atnf.csiro.au>
-               Bug fix for non-SMP compilation.
-    19980418   David Wragg <dpw@doc.ic.ac.uk>
-               Fixed-MTRR synchronisation for SMP and use atomic operations
-	       instead of spinlocks.
-    19980418   Richard Gooch <rgooch@atnf.csiro.au>
-	       Differentiate different MTRR register classes for BIOS fixup.
-  v1.10
-    19980419   David Wragg <dpw@doc.ic.ac.uk>
-	       Bug fix in variable MTRR synchronisation.
-  v1.11
-    19980419   Richard Gooch <rgooch@atnf.csiro.au>
-	       Fixups for kernel 2.1.97.
-  v1.12
-    19980421   Richard Gooch <rgooch@atnf.csiro.au>
-	       Safer synchronisation across CPUs when changing MTRRs.
-  v1.13
-    19980423   Richard Gooch <rgooch@atnf.csiro.au>
-	       Bugfix for SMP systems without MTRR support.
-  v1.14
-    19980427   Richard Gooch <rgooch@atnf.csiro.au>
-	       Trap calls to <mtrr_add> and <mtrr_del> on non-MTRR machines.
-  v1.15
-    19980427   Richard Gooch <rgooch@atnf.csiro.au>
-	       Use atomic bitops for setting SMP change mask.
-  v1.16
-    19980428   Richard Gooch <rgooch@atnf.csiro.au>
-	       Removed spurious diagnostic message.
-  v1.17
-    19980429   Richard Gooch <rgooch@atnf.csiro.au>
-	       Moved register-setting macros into this file.
-	       Moved setup code from init/main.c to i386-specific areas.
-  v1.18
-    19980502   Richard Gooch <rgooch@atnf.csiro.au>
-	       Moved MTRR detection outside conditionals in <mtrr_init>.
-  v1.19
-    19980502   Richard Gooch <rgooch@atnf.csiro.au>
-	       Documentation improvement: mention Pentium II and AGP.
-  v1.20
-    19980521   Richard Gooch <rgooch@atnf.csiro.au>
-	       Only manipulate interrupt enable flag on local CPU.
-	       Allow enclosed uncachable regions.
-  v1.21
-    19980611   Richard Gooch <rgooch@atnf.csiro.au>
-	       Always define <main_lock>.
-  v1.22
-    19980901   Richard Gooch <rgooch@atnf.csiro.au>
-	       Removed module support in order to tidy up code.
-	       Added sanity check for <mtrr_add>/<mtrr_del> before <mtrr_init>.
-	       Created addition queue for prior to SMP commence.
-  v1.23
-    19980902   Richard Gooch <rgooch@atnf.csiro.au>
-	       Ported patch to kernel 2.1.120-pre3.
-  v1.24
-    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-	       Removed sanity checks and addition queue: Linus prefers an OOPS.
-  v1.25
-    19981001   Richard Gooch <rgooch@atnf.csiro.au>
-	       Fixed harmless compiler warning in include/asm-i386/mtrr.h
-	       Fixed version numbering and history for v1.23 -> v1.24.
-  v1.26
-    19990118   Richard Gooch <rgooch@atnf.csiro.au>
-	       Added devfs support.
-  v1.27
-    19990123   Richard Gooch <rgooch@atnf.csiro.au>
-	       Changed locking to spin with reschedule.
-	       Made use of new <smp_call_function>.
-  v1.28
-    19990201   Zoltán Böszörményi <zboszor@mail.externet.hu>
-	       Extended the driver to be able to use Cyrix style ARRs.
-    19990204   Richard Gooch <rgooch@atnf.csiro.au>
-	       Restructured Cyrix support.
-  v1.29
-    19990204   Zoltán Böszörményi <zboszor@mail.externet.hu>
-	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
-	       and disable MAPEN in set_mtrr_done().
-    19990205   Richard Gooch <rgooch@atnf.csiro.au>
-	       Minor cleanups.
-  v1.30
-    19990208   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Protect plain 6x86s (and other processors without the
-               Page Global Enable feature) against accessing CR4 in
-               set_mtrr_prepare() and set_mtrr_done().
-    19990210   Richard Gooch <rgooch@atnf.csiro.au>
-	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
-  v1.31
-    19990212   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Major rewrite of cyrix_arr_init(): do not touch ARRs,
-               leave them as the BIOS have set them up.
-               Enable usage of all 8 ARRs.
-               Avoid multiplications by 3 everywhere and other
-               code clean ups/speed ups.
-    19990213   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Set up other Cyrix processors identical to the boot cpu.
-               Since Cyrix don't support Intel APIC, this is l'art pour l'art.
-               Weigh ARRs by size:
-               If size <= 32M is given, set up ARR# we were given.
-               If size >  32M is given, set up ARR7 only if it is free,
-               fail otherwise.
-    19990214   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Also check for size >= 256K if we are to set up ARR7,
-               mtrr_add() returns the value it gets from set_mtrr()
-    19990218   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Remove Cyrix "coma bug" workaround from here.
-               Moved to linux/arch/i386/kernel/setup.c and
-               linux/include/asm-i386/bugs.h
-    19990228   Richard Gooch <rgooch@atnf.csiro.au>
-	       Added MTRRIOC_KILL_ENTRY ioctl(2)
-	       Trap for counter underflow in <mtrr_file_del>.
-	       Trap for 4 MiB aligned regions for PPro, stepping <= 7.
-    19990301   Richard Gooch <rgooch@atnf.csiro.au>
-	       Created <get_free_region> hook.
-    19990305   Richard Gooch <rgooch@atnf.csiro.au>
-	       Temporarily disable AMD support now MTRR capability flag is set.
-  v1.32
-    19990308   Zoltán Böszörményi <zboszor@mail.externet.hu>
-	       Adjust my changes (19990212-19990218) to Richard Gooch's
-	       latest changes. (19990228-19990305)
-  v1.33
-    19990309   Richard Gooch <rgooch@atnf.csiro.au>
-	       Fixed typo in <printk> message.
-    19990310   Richard Gooch <rgooch@atnf.csiro.au>
-	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
-  v1.34
-    19990511   Bart Hartgers <bart@etpmod.phys.tue.nl>
-	       Support Centaur C6 MCR's.
-    19990512   Richard Gooch <rgooch@atnf.csiro.au>
-	       Minor cleanups.
-  v1.35
-    19990707   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Check whether ARR3 is protected in cyrix_get_free_region()
-               and mtrr_del(). The code won't attempt to delete or change it
-               from now on if the BIOS protected ARR3. It silently skips ARR3
-               in cyrix_get_free_region() or returns with an error code from
-               mtrr_del().
-    19990711   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Reset some bits in the CCRs in cyrix_arr_init() to disable SMM
-               if ARR3 isn't protected. This is needed because if SMM is active
-               and ARR3 isn't protected then deleting and setting ARR3 again
-               may lock up the processor. With SMM entirely disabled, it does
-               not happen.
-    19990812   Zoltán Böszörményi <zboszor@mail.externet.hu>
-               Rearrange switch() statements so the driver accomodates to
-               the fact that the AMD Athlon handles its MTRRs the same way
-               as Intel does.
-    19990814   Zoltán Böszörményi <zboszor@mail.externet.hu>
-	       Double check for Intel in mtrr_add()'s big switch() because
-	       that revision check is only valid for Intel CPUs.
-    19990819   Alan Cox <alan@redhat.com>
-               Tested Zoltan's changes on a pre production Athlon - 100%
-               success.
-    19991008   Manfred Spraul <manfreds@colorfullife.com>
-    	       replaced spin_lock_reschedule() with a normal semaphore.
-  v1.36
-    20000221   Richard Gooch <rgooch@atnf.csiro.au>
-               Compile fix if procfs and devfs not enabled.
-	       Formatting changes.
-  v1.37
-    20001109   H. Peter Anvin <hpa@zytor.com>
-	       Use the new centralized CPU feature detects.
-
-  v1.38
-    20010309   Dave Jones <davej@suse.de>
-	       Add support for Cyrix III.
-
-  v1.39
-    20010312   Dave Jones <davej@suse.de>
-               Ugh, I broke AMD support.
-	       Reworked fix by Troels Walsted Hansen <troels@thule.no>
-
-  v1.40
-    20010327   Dave Jones <davej@suse.de>
-	       Adapted Cyrix III support to include VIA C3.
-
-*/
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/ctype.h>
-#include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#define MTRR_NEED_STRINGS
-#include <asm/mtrr.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/segment.h>
-#include <asm/bitops.h>
-#include <asm/atomic.h>
-#include <asm/msr.h>
-
-#include <asm/hardirq.h>
-#include <linux/irq.h>
-
-#define MTRR_VERSION            "1.40 (20010327)"
-
-#define TRUE  1
-#define FALSE 0
-
-/*
- * The code assumes all processors support the same MTRR
- * interface.  This is generally a good assumption, but could
- * potentially be a problem.
- */
-enum mtrr_if_type {
-    MTRR_IF_NONE,		/* No MTRRs supported */
-    MTRR_IF_INTEL,		/* Intel (P6) standard MTRRs */
-    MTRR_IF_AMD_K6,		/* AMD pre-Athlon MTRRs */
-    MTRR_IF_CYRIX_ARR,		/* Cyrix ARRs */
-    MTRR_IF_CENTAUR_MCR,	/* Centaur MCRs */
-} mtrr_if = MTRR_IF_NONE;
-
-static __initdata char *mtrr_if_name[] = {
-    "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
-};
-
-#define MTRRcap_MSR     0x0fe
-#define MTRRdefType_MSR 0x2ff
-
-#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
-#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
-
-#define NUM_FIXED_RANGES 88
-#define MTRRfix64K_00000_MSR 0x250
-#define MTRRfix16K_80000_MSR 0x258
-#define MTRRfix16K_A0000_MSR 0x259
-#define MTRRfix4K_C0000_MSR 0x268
-#define MTRRfix4K_C8000_MSR 0x269
-#define MTRRfix4K_D0000_MSR 0x26a
-#define MTRRfix4K_D8000_MSR 0x26b
-#define MTRRfix4K_E0000_MSR 0x26c
-#define MTRRfix4K_E8000_MSR 0x26d
-#define MTRRfix4K_F0000_MSR 0x26e
-#define MTRRfix4K_F8000_MSR 0x26f
-
-#ifdef CONFIG_SMP
-#  define MTRR_CHANGE_MASK_FIXED     0x01
-#  define MTRR_CHANGE_MASK_VARIABLE  0x02
-#  define MTRR_CHANGE_MASK_DEFTYPE   0x04
-#endif
-
-/* In the Intel processor's MTRR interface, the MTRR type is always held in
-   an 8 bit field: */
-typedef u8 mtrr_type;
-
-#define LINE_SIZE      80
-#define JIFFIE_TIMEOUT 100
-
-#ifdef CONFIG_SMP
-#  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
-#else
-#  define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
-						       TRUE)
-#endif
-
-#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)
-# define USERSPACE_INTERFACE
-#endif
-
-#ifndef USERSPACE_INTERFACE
-#  define compute_ascii() while (0)
-#endif
-
-#ifdef USERSPACE_INTERFACE
-static char *ascii_buffer;
-static unsigned int ascii_buf_bytes;
-#endif
-static unsigned int *usage_table;
-static DECLARE_MUTEX(main_lock);
-
-/*  Private functions  */
-#ifdef USERSPACE_INTERFACE
-static void compute_ascii (void);
-#endif
-
-
-struct set_mtrr_context
-{
-    unsigned long flags;
-    unsigned long deftype_lo;
-    unsigned long deftype_hi;
-    unsigned long cr4val;
-    unsigned long ccr3;
-};
-
-static int arr3_protected;
-
-/*  Put the processor into a state where MTRRs can be safely set  */
-static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt)
-{
-    /*  Disable interrupts locally  */
-    local_irq_save(ctxt->flags);
-
-    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
-	 return;
-
-    /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-    if ( cpu_has_pge ) {
-	ctxt->cr4val = read_cr4();
-	write_cr4(ctxt->cr4val & (unsigned char) ~(1<<7));
-    }
-
-    /*  Disable and flush caches. Note that wbinvd flushes the TLBs as
-	a side-effect  */
-    {
-	unsigned int cr0 = read_cr0() | 0x40000000;
-	wbinvd();
-	write_cr0( cr0 );
-	wbinvd();
-    }
-
-    if ( mtrr_if == MTRR_IF_INTEL ) {
-	/*  Save MTRR state */
-	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-    } else {
-	/* Cyrix ARRs - everything else were excluded at the top */
-	ctxt->ccr3 = getCx86 (CX86_CCR3);
-    }
-}   /*  End Function set_mtrr_prepare_save  */
-
-static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt)
-{
-    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
-	 return;
-
-    if ( mtrr_if == MTRR_IF_INTEL ) {
-	/*  Disable MTRRs, and set the default type to uncached  */
-	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
-    } else {
-	/* Cyrix ARRs - everything else were excluded at the top */
-	setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
-    }
-}   /*  End Function set_mtrr_cache_disable  */
-
-/*  Restore the processor after a set_mtrr_prepare  */
-static void set_mtrr_done (struct set_mtrr_context *ctxt)
-{
-    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) {
-	 local_irq_restore (ctxt->flags);
-	 return;
-    }
-
-    /*  Flush caches and TLBs  */
-    wbinvd();
-
-    /*  Restore MTRRdefType  */
-    if ( mtrr_if == MTRR_IF_INTEL ) {
-	/* Intel (P6) standard MTRRs */
-	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-    } else {
-	/* Cyrix ARRs - everything else was excluded at the top */
-	setCx86 (CX86_CCR3, ctxt->ccr3);
-    }
-
-    /*  Enable caches  */
-    write_cr0( read_cr0() & 0xbfffffff );
-
-    /*  Restore value of CR4  */
-    if ( cpu_has_pge )
-	write_cr4(ctxt->cr4val);
-
-    /*  Re-enable interrupts locally (if enabled previously)  */
-    local_irq_restore (ctxt->flags);
-}   /*  End Function set_mtrr_done  */
-
-/*  This function returns the number of variable MTRRs  */
-static unsigned int get_num_var_ranges (void)
-{
-    unsigned long config, dummy;
-
-    switch ( mtrr_if )
-    {
-    case MTRR_IF_INTEL:
-	rdmsr (MTRRcap_MSR, config, dummy);
-	return (config & 0xff);
-    case MTRR_IF_AMD_K6:
-	return 2;
-    case MTRR_IF_CYRIX_ARR:
-	return 8;
-    case MTRR_IF_CENTAUR_MCR:
-	return 8;
-    default:
-	return 0;
-    }
-}   /*  End Function get_num_var_ranges  */
-
-/*  Returns non-zero if we have the write-combining memory type  */
-static int have_wrcomb (void)
-{
-    unsigned long config, dummy;
-    struct pci_dev *dev = NULL;
-    
-   /* ServerWorks LE chipsets have problems with write-combining 
-      Don't allow it and leave room for other chipsets to be tagged */
-
-	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
-		if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
-			(dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) {
-		printk (KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n");
-		return 0;
-		}
-	}
-
-    switch ( mtrr_if )
-    {
-    case MTRR_IF_INTEL:
-	rdmsr (MTRRcap_MSR, config, dummy);
-	return (config & (1<<10));
-    case MTRR_IF_AMD_K6:
-    case MTRR_IF_CENTAUR_MCR:
-    case MTRR_IF_CYRIX_ARR:
-	return 1;
-    default:
-	return 0;
-    }
-}   /*  End Function have_wrcomb  */
-
-static u32 size_or_mask, size_and_mask;
-
-static void intel_get_mtrr (unsigned int reg, unsigned long *base,
-			    unsigned long *size, mtrr_type *type)
-{
-    unsigned long mask_lo, mask_hi, base_lo, base_hi;
-
-    rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);
-    if ( (mask_lo & 0x800) == 0 )
-    {
-	/*  Invalid (i.e. free) range  */
-	*base = 0;
-	*size = 0;
-	*type = 0;
-	return;
-    }
-
-    rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
-
-    /* Work out the shifted address mask. */
-    mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
-		| mask_lo >> PAGE_SHIFT;
-
-    /* This works correctly if size is a power of two, i.e. a
-       contiguous range. */
-     *size = -mask_lo;
-     *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
-     *type = base_lo & 0xff;
-}   /*  End Function intel_get_mtrr  */
-
-static void cyrix_get_arr (unsigned int reg, unsigned long *base,
-			   unsigned long *size, mtrr_type *type)
-{
-    unsigned long flags;
-    unsigned char arr, ccr3, rcr, shift;
-
-    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
-
-    /* Save flags and disable interrupts */
-    local_irq_save(flags);
-
-    ccr3 = getCx86 (CX86_CCR3);
-    setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);		/* enable MAPEN */
-    ((unsigned char *) base)[3]  = getCx86 (arr);
-    ((unsigned char *) base)[2]  = getCx86 (arr+1);
-    ((unsigned char *) base)[1]  = getCx86 (arr+2);
-    rcr = getCx86(CX86_RCR_BASE + reg);
-    setCx86 (CX86_CCR3, ccr3);				/* disable MAPEN */
-
-    /* Enable interrupts if it was enabled previously */
-    local_irq_restore (flags);
-    shift = ((unsigned char *) base)[1] & 0x0f;
-    *base >>= PAGE_SHIFT;
-
-    /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
-     * Note: shift==0xf means 4G, this is unsupported.
-     */
-    if (shift)
-      *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
-    else
-      *size = 0;
-
-    /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
-    if (reg < 7)
-    {
-	switch (rcr)
-	{
-	  case  1: *type = MTRR_TYPE_UNCACHABLE; break;
-	  case  8: *type = MTRR_TYPE_WRBACK;     break;
-	  case  9: *type = MTRR_TYPE_WRCOMB;     break;
-	  case 24:
-	  default: *type = MTRR_TYPE_WRTHROUGH;  break;
-	}
-    } else
-    {
-	switch (rcr)
-	{
-	  case  0: *type = MTRR_TYPE_UNCACHABLE; break;
-	  case  8: *type = MTRR_TYPE_WRCOMB;     break;
-	  case  9: *type = MTRR_TYPE_WRBACK;     break;
-	  case 25:
-	  default: *type = MTRR_TYPE_WRTHROUGH;  break;
-	}
-    }
-}   /*  End Function cyrix_get_arr  */
-
-static void amd_get_mtrr (unsigned int reg, unsigned long *base,
-			  unsigned long *size, mtrr_type *type)
-{
-    unsigned long low, high;
-
-    rdmsr (MSR_K6_UWCCR, low, high);
-    /*  Upper dword is region 1, lower is region 0  */
-    if (reg == 1) low = high;
-    /*  The base masks off on the right alignment  */
-    *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
-    *type = 0;
-    if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
-    if (low & 2) *type = MTRR_TYPE_WRCOMB;
-    if ( !(low & 3) )
-    {
-	*size = 0;
-	return;
-    }
-    /*
-     *	This needs a little explaining. The size is stored as an
-     *	inverted mask of bits of 128K granularity 15 bits long offset
-     *	2 bits
-     *
-     *	So to get a size we do invert the mask and add 1 to the lowest
-     *	mask bit (4 as its 2 bits in). This gives us a size we then shift
-     *	to turn into 128K blocks
-     *
-     *	eg		111 1111 1111 1100      is 512K
-     *
-     *	invert		000 0000 0000 0011
-     *	+1		000 0000 0000 0100
-     *	*128K	...
-     */
-    low = (~low) & 0x1FFFC;
-    *size = (low + 4) << (15 - PAGE_SHIFT);
-    return;
-}   /*  End Function amd_get_mtrr  */
-
-static struct
-{
-    unsigned long high;
-    unsigned long low;
-} centaur_mcr[8];
-
-static u8 centaur_mcr_reserved;
-static u8 centaur_mcr_type;		/* 0 for winchip, 1 for winchip2 */
-
-/*
- *	Report boot time MCR setups 
- */
- 
-void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
-{
-	centaur_mcr[mcr].low = lo;
-	centaur_mcr[mcr].high = hi;
-}
-
-static void centaur_get_mcr (unsigned int reg, unsigned long *base,
-			     unsigned long *size, mtrr_type *type)
-{
-    *base = centaur_mcr[reg].high >> PAGE_SHIFT;
-    *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
-    *type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */
-    if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2))
-    	*type = MTRR_TYPE_UNCACHABLE;
-    if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25)
-    	*type = MTRR_TYPE_WRBACK;
-    if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31)
-    	*type = MTRR_TYPE_WRBACK;
-    
-}   /*  End Function centaur_get_mcr  */
-
-static void (*get_mtrr) (unsigned int reg, unsigned long *base,
-			 unsigned long *size, mtrr_type *type);
-
-static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
-			       unsigned long size, mtrr_type type, int do_safe)
-/*  [SUMMARY] Set variable MTRR register on the local CPU.
-    <reg> The register to set.
-    <base> The base address of the region.
-    <size> The size of the region. If this is 0 the region is disabled.
-    <type> The type of the region.
-    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
-    be done externally.
-    [RETURNS] Nothing.
-*/
-{
-    struct set_mtrr_context ctxt;
-
-    if (do_safe) {
-	set_mtrr_prepare_save (&ctxt);
-	set_mtrr_cache_disable (&ctxt);
-	}
-    if (size == 0)
-    {
-	/* The invalid bit is kept in the mask, so we simply clear the
-	   relevant mask register to disable a range. */
-	wrmsr (MTRRphysMask_MSR (reg), 0, 0);
-    }
-    else
-    {
-	wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,
-		(base & size_and_mask) >> (32 - PAGE_SHIFT));
-	wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,
-		(-size & size_and_mask) >> (32 - PAGE_SHIFT));
-    }
-    if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function intel_set_mtrr_up  */
-
-static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
-			      unsigned long size, mtrr_type type, int do_safe)
-{
-    struct set_mtrr_context ctxt;
-    unsigned char arr, arr_type, arr_size;
-
-    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
-
-    /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
-    if (reg >= 7)
-	size >>= 6;
-
-    size &= 0x7fff; /* make sure arr_size <= 14 */
-    for(arr_size = 0; size; arr_size++, size >>= 1);
-
-    if (reg<7)
-    {
-	switch (type) {
-	  case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
-	  case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
-	  case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
-	  default:			arr_type =  8; break;
-	}
-    }
-    else
-    {
-	switch (type)
-	{
-	  case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
-	  case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
-	  case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
-	  default:			arr_type =  9; break;
-	}
-    }
-
-    if (do_safe) {
-	set_mtrr_prepare_save (&ctxt);
-	set_mtrr_cache_disable (&ctxt);
-    }
-    base <<= PAGE_SHIFT;
-    setCx86(arr,    ((unsigned char *) &base)[3]);
-    setCx86(arr+1,  ((unsigned char *) &base)[2]);
-    setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
-    setCx86(CX86_RCR_BASE + reg, arr_type);
-    if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function cyrix_set_arr_up  */
-
-static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
-			     unsigned long size, mtrr_type type, int do_safe)
-/*  [SUMMARY] Set variable MTRR register on the local CPU.
-    <reg> The register to set.
-    <base> The base address of the region.
-    <size> The size of the region. If this is 0 the region is disabled.
-    <type> The type of the region.
-    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
-    be done externally.
-    [RETURNS] Nothing.
-*/
-{
-    u32 regs[2];
-    struct set_mtrr_context ctxt;
-
-    if (do_safe) {
-	set_mtrr_prepare_save (&ctxt);
-	set_mtrr_cache_disable (&ctxt);
-    }
-    /*
-     *	Low is MTRR0 , High MTRR 1
-     */
-    rdmsr (MSR_K6_UWCCR, regs[0], regs[1]);
-    /*
-     *	Blank to disable
-     */
-    if (size == 0)
-	regs[reg] = 0;
-    else
-	/* Set the register to the base, the type (off by one) and an
-	   inverted bitmask of the size The size is the only odd
-	   bit. We are fed say 512K We invert this and we get 111 1111
-	   1111 1011 but if you subtract one and invert you get the   
-	   desired 111 1111 1111 1100 mask
-
-	   But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!  */
-	regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)
-				| (base<<PAGE_SHIFT) | (type+1);
-
-    /*
-     *	The writeback rule is quite specific. See the manual. Its
-     *	disable local interrupts, write back the cache, set the mtrr
-     */
-	wbinvd();
-	wrmsr (MSR_K6_UWCCR, regs[0], regs[1]);
-    if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function amd_set_mtrr_up  */
-
-
-static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
-				unsigned long size, mtrr_type type,
-				int do_safe)
-{
-    struct set_mtrr_context ctxt;
-    unsigned long low, high;
-
-    if (do_safe) {
-	set_mtrr_prepare_save (&ctxt);
-	set_mtrr_cache_disable (&ctxt);
-    }
-    if (size == 0)
-    {
-        /*  Disable  */
-        high = low = 0;
-    }
-    else
-    {
-	high = base << PAGE_SHIFT;
-	if(centaur_mcr_type == 0)
-		low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
-	else
-	{
-		if(type == MTRR_TYPE_UNCACHABLE)
-			low = -size << PAGE_SHIFT | 0x02;	/* NC */
-		else
-			low = -size << PAGE_SHIFT | 0x09;	/* WWO,WC */
-	}
-    }
-    centaur_mcr[reg].high = high;
-    centaur_mcr[reg].low = low;
-    wrmsr (MSR_IDT_MCR0 + reg, low, high);
-    if (do_safe) set_mtrr_done( &ctxt );
-}   /*  End Function centaur_set_mtrr_up  */
-
-static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
-			    unsigned long size, mtrr_type type,
-			    int do_safe);
-
-#ifdef CONFIG_SMP
-
-struct mtrr_var_range
-{
-    unsigned long base_lo;
-    unsigned long base_hi;
-    unsigned long mask_lo;
-    unsigned long mask_hi;
-};
-
-
-/*  Get the MSR pair relating to a var range  */
-static void __init get_mtrr_var_range (unsigned int index,
-					   struct mtrr_var_range *vr)
-{
-    rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi);
-    rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi);
-}   /*  End Function get_mtrr_var_range  */
-
-
-/*  Set the MSR pair relating to a var range. Returns TRUE if
-    changes are made  */
-static int __init set_mtrr_var_range_testing (unsigned int index,
-						  struct mtrr_var_range *vr)
-{
-    unsigned int lo, hi;
-    int changed = FALSE;
-
-    rdmsr(MTRRphysBase_MSR(index), lo, hi);
-    if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
-	 || (vr->base_hi & 0xfUL) != (hi & 0xfUL) )
-    {
-	wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
-	changed = TRUE;
-    }
-
-    rdmsr (MTRRphysMask_MSR(index), lo, hi);
-
-    if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
-	 || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) )
-    {
-	wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
-	changed = TRUE;
-    }
-    return changed;
-}   /*  End Function set_mtrr_var_range_testing  */
-
-static void __init get_fixed_ranges(mtrr_type *frs)
-{
-    unsigned long *p = (unsigned long *)frs;
-    int i;
-
-    rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
-
-    for (i = 0; i < 2; i++)
-	rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
-    for (i = 0; i < 8; i++)
-	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-}   /*  End Function get_fixed_ranges  */
-
-static int __init set_fixed_ranges_testing(mtrr_type *frs)
-{
-    unsigned long *p = (unsigned long *)frs;
-    int changed = FALSE;
-    int i;
-    unsigned long lo, hi;
-
-    rdmsr(MTRRfix64K_00000_MSR, lo, hi);
-    if (p[0] != lo || p[1] != hi)
-    {
-	wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]);
-	changed = TRUE;
-    }
-
-    for (i = 0; i < 2; i++)
-    {
-	rdmsr (MTRRfix16K_80000_MSR + i, lo, hi);
-	if (p[2 + i*2] != lo || p[3 + i*2] != hi)
-	{
-	    wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
-	    changed = TRUE;
-	}
-    }
-
-    for (i = 0; i < 8; i++)
-    {
-	rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi);
-	if (p[6 + i*2] != lo || p[7 + i*2] != hi)
-	{
-	    wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-	    changed = TRUE;
-	}
-    }
-    return changed;
-}   /*  End Function set_fixed_ranges_testing  */
-
-struct mtrr_state
-{
-    unsigned int num_var_ranges;
-    struct mtrr_var_range *var_ranges;
-    mtrr_type fixed_ranges[NUM_FIXED_RANGES];
-    unsigned char enabled;
-    mtrr_type def_type;
-};
-
-
-/*  Grab all of the MTRR state for this CPU into *state  */
-static void __init get_mtrr_state(struct mtrr_state *state)
-{
-    unsigned int nvrs, i;
-    struct mtrr_var_range *vrs;
-    unsigned long lo, dummy;
-
-    nvrs = state->num_var_ranges = get_num_var_ranges();
-    vrs = state->var_ranges
-              = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
-    if (vrs == NULL)
-	nvrs = state->num_var_ranges = 0;
-
-    for (i = 0; i < nvrs; i++)
-	get_mtrr_var_range (i, &vrs[i]);
-    get_fixed_ranges (state->fixed_ranges);
-
-    rdmsr (MTRRdefType_MSR, lo, dummy);
-    state->def_type = (lo & 0xff);
-    state->enabled = (lo & 0xc00) >> 10;
-}   /*  End Function get_mtrr_state  */
-
-
-/*  Free resources associated with a struct mtrr_state  */
-static void __init finalize_mtrr_state(struct mtrr_state *state)
-{
-    if (state->var_ranges) kfree (state->var_ranges);
-}   /*  End Function finalize_mtrr_state  */
-
-
-static unsigned long __init set_mtrr_state (struct mtrr_state *state,
-						struct set_mtrr_context *ctxt)
-/*  [SUMMARY] Set the MTRR state for this CPU.
-    <state> The MTRR state information to read.
-    <ctxt> Some relevant CPU context.
-    [NOTE] The CPU must already be in a safe state for MTRR changes.
-    [RETURNS] 0 if no changes made, else a mask indication what was changed.
-*/
-{
-    unsigned int i;
-    unsigned long change_mask = 0;
-
-    for (i = 0; i < state->num_var_ranges; i++)
-	if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
-	    change_mask |= MTRR_CHANGE_MASK_VARIABLE;
-
-    if ( set_fixed_ranges_testing(state->fixed_ranges) )
-	change_mask |= MTRR_CHANGE_MASK_FIXED;
-    /*  Set_mtrr_restore restores the old value of MTRRdefType,
-	so to set it we fiddle with the saved value  */
-    if ( (ctxt->deftype_lo & 0xff) != state->def_type
-	 || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled)
-    {
-	ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
-	change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
-    }
-
-    return change_mask;
-}   /*  End Function set_mtrr_state  */
-
-
-static atomic_t undone_count;
-static volatile int wait_barrier_cache_disable = FALSE;
-static volatile int wait_barrier_execute = FALSE;
-static volatile int wait_barrier_cache_enable = FALSE;
-
-struct set_mtrr_data
-{
-    unsigned long smp_base;
-    unsigned long smp_size;
-    unsigned int smp_reg;
-    mtrr_type smp_type;
-};
-
-static void ipi_handler (void *info)
-/*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
-    [RETURNS] Nothing.
-*/
-{
-    struct set_mtrr_data *data = info;
-    struct set_mtrr_context ctxt;
-    set_mtrr_prepare_save (&ctxt);
-    /*  Notify master that I've flushed and disabled my cache  */
-    atomic_dec (&undone_count);
-    while (wait_barrier_cache_disable) { rep_nop(); barrier(); }
-    set_mtrr_cache_disable (&ctxt);
-    /*  Notify master that I've flushed and disabled my cache  */
-    atomic_dec (&undone_count);
-    while (wait_barrier_execute) { rep_nop(); barrier(); }
-    /*  The master has cleared me to execute  */
-    (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
-		    data->smp_type, FALSE);
-    /*  Notify master CPU that I've executed the function  */
-    atomic_dec (&undone_count);
-    /*  Wait for master to clear me to enable cache and return  */
-    while (wait_barrier_cache_enable) { rep_nop(); barrier(); }
-    set_mtrr_done (&ctxt);
-}   /*  End Function ipi_handler  */
-
-static void set_mtrr_smp (unsigned int reg, unsigned long base,
-			  unsigned long size, mtrr_type type)
-{
-    struct set_mtrr_data data;
-    struct set_mtrr_context ctxt;
-
-    data.smp_reg = reg;
-    data.smp_base = base;
-    data.smp_size = size;
-    data.smp_type = type;
-    wait_barrier_cache_disable = TRUE;
-    wait_barrier_execute = TRUE;
-    wait_barrier_cache_enable = TRUE;
-    atomic_set (&undone_count, num_booting_cpus() - 1);
-    /*  Start the ball rolling on other CPUs  */
-    if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
-	panic ("mtrr: timed out waiting for other CPUs\n");
-    /* Flush and disable the local CPU's cache */
-    set_mtrr_prepare_save (&ctxt);
-    /*  Wait for all other CPUs to flush and disable their caches  */
-    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
-    /* Set up for completion wait and then release other CPUs to change MTRRs*/
-    atomic_set (&undone_count, num_booting_cpus() - 1);
-    wait_barrier_cache_disable = FALSE;
-    set_mtrr_cache_disable (&ctxt);
-
-    /*  Wait for all other CPUs to flush and disable their caches  */
-    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
-    /* Set up for completion wait and then release other CPUs to change MTRRs*/
-    atomic_set (&undone_count, num_booting_cpus() - 1);
-    wait_barrier_execute = FALSE;
-    (*set_mtrr_up) (reg, base, size, type, FALSE);
-    /*  Now wait for other CPUs to complete the function  */
-    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
-    /*  Now all CPUs should have finished the function. Release the barrier to
-	allow them to re-enable their caches and return from their interrupt,
-	then enable the local cache and return  */
-    wait_barrier_cache_enable = FALSE;
-    set_mtrr_done (&ctxt);
-}   /*  End Function set_mtrr_smp  */
-
-
-/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
-static void __init mtrr_state_warn(unsigned long mask)
-{
-    if (!mask) return;
-    if (mask & MTRR_CHANGE_MASK_FIXED)
-	printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
-    if (mask & MTRR_CHANGE_MASK_VARIABLE)
-	printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
-    if (mask & MTRR_CHANGE_MASK_DEFTYPE)
-	printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
-    printk ("mtrr: probably your BIOS does not setup all CPUs\n");
-}   /*  End Function mtrr_state_warn  */
-
-#endif  /*  CONFIG_SMP  */
-
-static char *attrib_to_str (int x)
-{
-    return (x <= 6) ? mtrr_strings[x] : "?";
-}   /*  End Function attrib_to_str  */
-
-static void init_table (void)
-{
-    int i, max;
-
-    max = get_num_var_ranges ();
-    if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) )
-	 == NULL )
-    {
-	printk ("mtrr: could not allocate\n");
-	return;
-    }
-    for (i = 0; i < max; i++) usage_table[i] = 1;
-#ifdef USERSPACE_INTERFACE
-    if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL )
-    {
-	printk ("mtrr: could not allocate\n");
-	return;
-    }
-    ascii_buf_bytes = 0;
-    compute_ascii ();
-#endif
-}   /*  End Function init_table  */
-
-static int generic_get_free_region (unsigned long base, unsigned long size)
-/*  [SUMMARY] Get a free MTRR.
-    <base> The starting (base) address of the region.
-    <size> The size (in bytes) of the region.
-    [RETURNS] The index of the region on success, else -1 on error.
-*/
-{
-    int i, max;
-    mtrr_type ltype;
-    unsigned long lbase, lsize;
-
-    max = get_num_var_ranges ();
-    for (i = 0; i < max; ++i)
-    {
-	(*get_mtrr) (i, &lbase, &lsize, &ltype);
-	if (lsize == 0) return i;
-    }
-    return -ENOSPC;
-}   /*  End Function generic_get_free_region  */
-
-static int centaur_get_free_region (unsigned long base, unsigned long size)
-/*  [SUMMARY] Get a free MTRR.
-    <base> The starting (base) address of the region.
-    <size> The size (in bytes) of the region.
-    [RETURNS] The index of the region on success, else -1 on error.
-*/
-{
-    int i, max;
-    mtrr_type ltype;
-    unsigned long lbase, lsize;
-
-    max = get_num_var_ranges ();
-    for (i = 0; i < max; ++i)
-    {
-    	if(centaur_mcr_reserved & (1<<i))
-    		continue;
-	(*get_mtrr) (i, &lbase, &lsize, &ltype);
-	if (lsize == 0) return i;
-    }
-    return -ENOSPC;
-}   /*  End Function generic_get_free_region  */
-
-static int cyrix_get_free_region (unsigned long base, unsigned long size)
-/*  [SUMMARY] Get a free ARR.
-    <base> The starting (base) address of the region.
-    <size> The size (in bytes) of the region.
-    [RETURNS] The index of the region on success, else -1 on error.
-*/
-{
-    int i;
-    mtrr_type ltype;
-    unsigned long lbase, lsize;
-
-    /* If we are to set up a region >32M then look at ARR7 immediately */
-    if (size > 0x2000)
-    {
-	cyrix_get_arr (7, &lbase, &lsize, &ltype);
-	if (lsize == 0) return 7;
-	/*  Else try ARR0-ARR6 first  */
-    }
-    else
-    {
-	for (i = 0; i < 7; i++)
-	{
-	    cyrix_get_arr (i, &lbase, &lsize, &ltype);
-	    if ((i == 3) && arr3_protected) continue;
-	    if (lsize == 0) return i;
-	}
-	/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
-	cyrix_get_arr (i, &lbase, &lsize, &ltype);
-	if ((lsize == 0) && (size >= 0x40)) return i;
-    }
-    return -ENOSPC;
-}   /*  End Function cyrix_get_free_region  */
-
-static int (*get_free_region) (unsigned long base,
-			       unsigned long size) = generic_get_free_region;
-
-/**
- *	mtrr_add_page - Add a memory type region
- *	@base: Physical base address of region in pages (4 KB)
- *	@size: Physical size of region in pages (4 KB)
- *	@type: Type of MTRR desired
- *	@increment: If this is true do usage counting on the region
- *
- *	Memory type region registers control the caching on newer Intel and
- *	non Intel processors. This function allows drivers to request an
- *	MTRR is added. The details and hardware specifics of each processor's
- *	implementation are hidden from the caller, but nevertheless the 
- *	caller should expect to need to provide a power of two size on an
- *	equivalent power of two boundary.
- *
- *	If the region cannot be added either because all regions are in use
- *	or the CPU cannot support it a negative value is returned. On success
- *	the register number for this entry is returned, but should be treated
- *	as a cookie only.
- *
- *	On a multiprocessor machine the changes are made to all processors.
- *	This is required on x86 by the Intel processors.
- *
- *	The available types are
- *
- *	%MTRR_TYPE_UNCACHABLE	-	No caching
- *
- *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
- *
- *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
- *
- *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
- *
- *	BUGS: Needs a quiet flag for the cases where drivers do not mind
- *	failures and do not wish system log messages to be sent.
- */
-
-int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment)
-{
-/*  [SUMMARY] Add an MTRR entry.
-    <base> The starting (base, in pages) address of the region.
-    <size> The size of the region. (in pages)
-    <type> The type of the new region.
-    <increment> If true and the region already exists, the usage count will be
-    incremented.
-    [RETURNS] The MTRR register on success, else a negative number indicating
-    the error code.
-    [NOTE] This routine uses a spinlock.
-*/
-    int i, max;
-    mtrr_type ltype;
-    unsigned long lbase, lsize, last;
-
-    switch ( mtrr_if )
-    {
-    case MTRR_IF_NONE:
-	return -ENXIO;		/* No MTRRs whatsoever */
-
-    case MTRR_IF_AMD_K6:
-	/* Apply the K6 block alignment and size rules
-	   In order
-	   o Uncached or gathering only
-	   o 128K or bigger block
-	   o Power of 2 block
-	   o base suitably aligned to the power
-	*/
-	if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) ||
-	     (size & ~(size-1))-size || ( base & (size-1) ) )
-	    return -EINVAL;
-	break;
-
-    case MTRR_IF_INTEL:
-	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned 
-	    and not touch 0x70000000->0x7003FFFF */
-	if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
-	     boot_cpu_data.x86 == 6 &&
-	     boot_cpu_data.x86_model == 1 &&
-	     boot_cpu_data.x86_mask <= 7 )
-	{
-	    if ( base & ((1 << (22-PAGE_SHIFT))-1) )
-	    {
-		printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
-		return -EINVAL;
-	    }
-	    if (!(base + size < 0x70000000 || base > 0x7003FFFF) &&
-		 (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK))
-	    {
-		printk (KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
-	        return -EINVAL;
-	    }
-	}
-	/* Fall through */
-	
-    case MTRR_IF_CYRIX_ARR:
-    case MTRR_IF_CENTAUR_MCR:
-        if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
-	{
-	    /*
-	     *	FIXME: Winchip2 supports uncached
-	     */
-	    if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE))
-	    {
-		printk (KERN_WARNING "mtrr: only write-combining%s supported\n",
-			centaur_mcr_type?" and uncacheable are":" is");
-		return -EINVAL;
-	    }
-	}
-	else if (base + size < 0x100)
-	{
-	    printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
-		    base, size);
-	    return -EINVAL;
-	}
-	/*  Check upper bits of base and last are equal and lower bits are 0
-	    for base and 1 for last  */
-	last = base + size - 1;
-	for (lbase = base; !(lbase & 1) && (last & 1);
-	     lbase = lbase >> 1, last = last >> 1);
-	if (lbase != last)
-	{
-	    printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
-		    base, size);
-	    return -EINVAL;
-	}
-	break;
-
-    default:
-	return -EINVAL;
-    }
-
-    if (type >= MTRR_NUM_TYPES)
-    {
-	printk ("mtrr: type: %u illegal\n", type);
-	return -EINVAL;
-    }
-
-    /*  If the type is WC, check that this processor supports it  */
-    if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
-    {
-        printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n");
-        return -ENOSYS;
-    }
-
-    if ( base & size_or_mask || size  & size_or_mask )
-    {
-	printk ("mtrr: base or size exceeds the MTRR width\n");
-	return -EINVAL;
-    }
-
-    increment = increment ? 1 : 0;
-    max = get_num_var_ranges ();
-    /*  Search for existing MTRR  */
-    down(&main_lock);
-    for (i = 0; i < max; ++i)
-    {
-	(*get_mtrr) (i, &lbase, &lsize, &ltype);
-	if (base >= lbase + lsize) continue;
-	if ( (base < lbase) && (base + size <= lbase) ) continue;
-	/*  At this point we know there is some kind of overlap/enclosure  */
-	if ( (base < lbase) || (base + size > lbase + lsize) )
-	{
-	    up(&main_lock);
-	    printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing"
-		    " 0x%lx000,0x%lx000\n",
-		    base, size, lbase, lsize);
-	    return -EINVAL;
-	}
-	/*  New region is enclosed by an existing region  */
-	if (ltype != type)
-	{
-	    if (type == MTRR_TYPE_UNCACHABLE) continue;
-	    up(&main_lock);
-	    printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
-		     base, size, attrib_to_str (ltype), attrib_to_str (type) );
-	    return -EINVAL;
-	}
-	if (increment) ++usage_table[i];
-	compute_ascii ();
-	up(&main_lock);
-	return i;
-    }
-    /*  Search for an empty MTRR  */
-    i = (*get_free_region) (base, size);
-    if (i < 0)
-    {
-	up(&main_lock);
-	printk ("mtrr: no more MTRRs available\n");
-	return i;
-    }
-    set_mtrr (i, base, size, type);
-    usage_table[i] = 1;
-    compute_ascii ();
-    up(&main_lock);
-    return i;
-}   /*  End Function mtrr_add_page  */
-
-/**
- *	mtrr_add - Add a memory type region
- *	@base: Physical base address of region
- *	@size: Physical size of region
- *	@type: Type of MTRR desired
- *	@increment: If this is true do usage counting on the region
- *
- *	Memory type region registers control the caching on newer Intel and
- *	non Intel processors. This function allows drivers to request an
- *	MTRR is added. The details and hardware specifics of each processor's
- *	implementation are hidden from the caller, but nevertheless the 
- *	caller should expect to need to provide a power of two size on an
- *	equivalent power of two boundary.
- *
- *	If the region cannot be added either because all regions are in use
- *	or the CPU cannot support it a negative value is returned. On success
- *	the register number for this entry is returned, but should be treated
- *	as a cookie only.
- *
- *	On a multiprocessor machine the changes are made to all processors.
- *	This is required on x86 by the Intel processors.
- *
- *	The available types are
- *
- *	%MTRR_TYPE_UNCACHABLE	-	No caching
- *
- *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
- *
- *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
- *
- *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
- *
- *	BUGS: Needs a quiet flag for the cases where drivers do not mind
- *	failures and do not wish system log messages to be sent.
- */
-
-int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment)
-{
-/*  [SUMMARY] Add an MTRR entry.
-    <base> The starting (base) address of the region.
-    <size> The size (in bytes) of the region.
-    <type> The type of the new region.
-    <increment> If true and the region already exists, the usage count will be
-    incremented.
-    [RETURNS] The MTRR register on success, else a negative number indicating
-    the error code.
-*/
-
-    if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
-    {
-	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-	printk ("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
-	return -EINVAL;
-    }
-    return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);
-}   /*  End Function mtrr_add  */
-
-/**
- *	mtrr_del_page - delete a memory type region
- *	@reg: Register returned by mtrr_add
- *	@base: Physical base address
- *	@size: Size of region
- *
- *	If register is supplied then base and size are ignored. This is
- *	how drivers should call it.
- *
- *	Releases an MTRR region. If the usage count drops to zero the 
- *	register is freed and the region returns to default state.
- *	On success the register is returned, on failure a negative error
- *	code.
- */
- 
-int mtrr_del_page (int reg, unsigned long base, unsigned long size)
-/*  [SUMMARY] Delete MTRR/decrement usage count.
-    <reg> The register. If this is less than 0 then <<base>> and <<size>> must
-    be supplied.
-    <base> The base address of the region. This is ignored if <<reg>> is >= 0.
-    <size> The size of the region. This is ignored if <<reg>> is >= 0.
-    [RETURNS] The register on success, else a negative number indicating
-    the error code.
-    [NOTE] This routine uses a spinlock.
-*/
-{
-    int i, max;
-    mtrr_type ltype;
-    unsigned long lbase, lsize;
-
-    if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO;
-
-    max = get_num_var_ranges ();
-    down (&main_lock);
-    if (reg < 0)
-    {
-	/*  Search for existing MTRR  */
-	for (i = 0; i < max; ++i)
-	{
-	    (*get_mtrr) (i, &lbase, &lsize, &ltype);
-	    if (lbase == base && lsize == size)
-	    {
-		reg = i;
-		break;
-	    }
-	}
-	if (reg < 0)
-	{
-	    up(&main_lock);
-	    printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);
-	    return -EINVAL;
-	}
-    }
-    if (reg >= max)
-    {
-	up (&main_lock);
-	printk ("mtrr: register: %d too big\n", reg);
-	return -EINVAL;
-    }
-    if ( mtrr_if == MTRR_IF_CYRIX_ARR )
-    {
-	if ( (reg == 3) && arr3_protected )
-	{
-	    up (&main_lock);
-	    printk ("mtrr: ARR3 cannot be changed\n");
-	    return -EINVAL;
-	}
-    }
-    (*get_mtrr) (reg, &lbase, &lsize, &ltype);
-    if (lsize < 1)
-    {
-	up (&main_lock);
-	printk ("mtrr: MTRR %d not used\n", reg);
-	return -EINVAL;
-    }
-    if (usage_table[reg] < 1)
-    {
-	up (&main_lock);
-	printk ("mtrr: reg: %d has count=0\n", reg);
-	return -EINVAL;
-    }
-    if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
-    compute_ascii ();
-    up (&main_lock);
-    return reg;
-}   /*  End Function mtrr_del_page  */
-
-/**
- *	mtrr_del - delete a memory type region
- *	@reg: Register returned by mtrr_add
- *	@base: Physical base address
- *	@size: Size of region
- *
- *	If register is supplied then base and size are ignored. This is
- *	how drivers should call it.
- *
- *	Releases an MTRR region. If the usage count drops to zero the 
- *	register is freed and the region returns to default state.
- *	On success the register is returned, on failure a negative error
- *	code.
- */
- 
-int mtrr_del (int reg, unsigned long base, unsigned long size)
-/*  [SUMMARY] Delete MTRR/decrement usage count.
-    <reg> The register. If this is less than 0 then <<base>> and <<size>> must
-    be supplied.
-    <base> The base address of the region. This is ignored if <<reg>> is >= 0.
-    <size> The size of the region. This is ignored if <<reg>> is >= 0.
-    [RETURNS] The register on success, else a negative number indicating
-    the error code.
-*/
-{
-    if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
-    {
-	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-	printk ("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
-	return -EINVAL;
-    }
-    return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
-}
-
-#ifdef USERSPACE_INTERFACE
-
-static int mtrr_file_add (unsigned long base, unsigned long size,
-			  unsigned int type, char increment, struct file *file, int page)
-{
-    int reg, max;
-    unsigned int *fcount = file->private_data;
-
-    max = get_num_var_ranges ();
-    if (fcount == NULL)
-    {
-	if ( ( fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL) ) == NULL )
-	{
-	    printk ("mtrr: could not allocate\n");
-	    return -ENOMEM;
-	}
-	memset (fcount, 0, max * sizeof *fcount);
-	file->private_data = fcount;
-    }
-    if (!page) {
-	if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
-	{
-	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
-	    printk ("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
-	    return -EINVAL;
-	}
-	base >>= PAGE_SHIFT;
-	size >>= PAGE_SHIFT;
-    }
-    reg = mtrr_add_page (base, size, type, 1);
-    if (reg >= 0) ++fcount[reg];
-    return reg;
-}   /*  End Function mtrr_file_add  */
-
-static int mtrr_file_del (unsigned long base, unsigned long size,
-			  struct file *file, int page)
-{
-    int reg;
-    unsigned int *fcount = file->private_data;
-
-    if (!page) {
-	if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
-	{
-	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
-	    printk ("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
-	    return -EINVAL;
-	}
-	base >>= PAGE_SHIFT;
-	size >>= PAGE_SHIFT;
-    }
-    reg = mtrr_del_page (-1, base, size);
-    if (reg < 0) return reg;
-    if (fcount == NULL) return reg;
-    if (fcount[reg] < 1) return -EINVAL;
-    --fcount[reg];
-    return reg;
-}   /*  End Function mtrr_file_del  */
-
-static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
-			  loff_t *ppos)
-{
-    if (*ppos >= ascii_buf_bytes) return 0;
-    if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos;
-    if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT;
-    *ppos += len;
-    return len;
-}   /*  End Function mtrr_read  */
-
-static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
-			   loff_t *ppos)
-/*  Format of control line:
-    "base=%Lx size=%Lx type=%s"     OR:
-    "disable=%d"
-*/
-{
-    int i, err;
-    unsigned long reg;
-    unsigned long long base, size;
-    char *ptr;
-    char line[LINE_SIZE];
-
-    if ( !capable(CAP_SYS_ADMIN)) return -EPERM;
-    /*  Can't seek (pwrite) on this device  */
-    if (ppos != &file->f_pos) return -ESPIPE;
-    memset (line, 0, LINE_SIZE);
-    if (len > LINE_SIZE) len = LINE_SIZE;
-    if ( copy_from_user (line, buf, len - 1) ) return -EFAULT;
-    ptr = line + strlen (line) - 1;
-    if (*ptr == '\n') *ptr = '\0';
-    if ( !strncmp (line, "disable=", 8) )
-    {
-	reg = simple_strtoul (line + 8, &ptr, 0);
-	err = mtrr_del_page (reg, 0, 0);
-	if (err < 0) return err;
-	return len;
-    }
-    if ( strncmp (line, "base=", 5) )
-    {
-	printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
-	return -EINVAL;
-    }
-    base = simple_strtoull (line + 5, &ptr, 0);
-    for (; isspace (*ptr); ++ptr);
-    if ( strncmp (ptr, "size=", 5) )
-    {
-	printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);
-	return -EINVAL;
-    }
-    size = simple_strtoull (ptr + 5, &ptr, 0);
-    if ( (base & 0xfff) || (size & 0xfff) )
-    {
-	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-	printk ("mtrr: size: 0x%Lx  base: 0x%Lx\n", size, base);
-	return -EINVAL;
-    }
-    for (; isspace (*ptr); ++ptr);
-    if ( strncmp (ptr, "type=", 5) )
-    {
-	printk ("mtrr: no \"type=\" in line: \"%s\"\n", line);
-	return -EINVAL;
-    }
-    ptr += 5;
-    for (; isspace (*ptr); ++ptr);
-    for (i = 0; i < MTRR_NUM_TYPES; ++i)
-    {
-	if ( strcmp (ptr, mtrr_strings[i]) ) continue;
-	base >>= PAGE_SHIFT;
-	size >>= PAGE_SHIFT;
-	err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1);
-	if (err < 0) return err;
-	return len;
-    }
-    printk ("mtrr: illegal type: \"%s\"\n", ptr);
-    return -EINVAL;
-}   /*  End Function mtrr_write  */
-
-static int mtrr_ioctl (struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-    int err;
-    mtrr_type type;
-    struct mtrr_sentry sentry;
-    struct mtrr_gentry gentry;
-
-    switch (cmd)
-    {
-      default:
-	return -ENOIOCTLCMD;
-      case MTRRIOC_ADD_ENTRY:
-	if ( ! capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_SET_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_DEL_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_file_del (sentry.base, sentry.size, file, 0);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_KILL_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_del (-1, sentry.base, sentry.size);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_GET_ENTRY:
-	if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
-	    return -EFAULT;
-	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
-	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
-
-	/* Hide entries that go above 4GB */
-	if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000)
-	    gentry.base = gentry.size = gentry.type = 0;
-	else {
-	    gentry.base <<= PAGE_SHIFT;
-	    gentry.size <<= PAGE_SHIFT;
-	    gentry.type = type;
-	}
-
-	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
-	     return -EFAULT;
-	break;
-      case MTRRIOC_ADD_PAGE_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_SET_PAGE_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_DEL_PAGE_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_file_del (sentry.base, sentry.size, file, 1);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_KILL_PAGE_ENTRY:
-	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
-	    return -EFAULT;
-	err = mtrr_del_page (-1, sentry.base, sentry.size);
-	if (err < 0) return err;
-	break;
-      case MTRRIOC_GET_PAGE_ENTRY:
-	if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
-	    return -EFAULT;
-	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
-	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
-	gentry.type = type;
-
-	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
-	     return -EFAULT;
-	break;
-    }
-    return 0;
-}   /*  End Function mtrr_ioctl  */
-
-static int mtrr_close (struct inode *ino, struct file *file)
-{
-    int i, max;
-    unsigned int *fcount = file->private_data;
-
-    if (fcount == NULL) return 0;
-    max = get_num_var_ranges ();
-    for (i = 0; i < max; ++i)
-    {
-	while (fcount[i] > 0)
-	{
-	    if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i);
-	    --fcount[i];
-	}
-    }
-    kfree (fcount);
-    file->private_data = NULL;
-    return 0;
-}   /*  End Function mtrr_close  */
-
-static struct file_operations mtrr_fops =
-{
-    owner:	THIS_MODULE,
-    read:	mtrr_read,
-    write:	mtrr_write,
-    ioctl:	mtrr_ioctl,
-    release:	mtrr_close,
-};
-
-#  ifdef CONFIG_PROC_FS
-
-static struct proc_dir_entry *proc_root_mtrr;
-
-#  endif  /*  CONFIG_PROC_FS  */
-
-static devfs_handle_t devfs_handle;
-
-static void compute_ascii (void)
-{
-    char factor;
-    int i, max;
-    mtrr_type type;
-    unsigned long base, size;
-
-    ascii_buf_bytes = 0;
-    max = get_num_var_ranges ();
-    for (i = 0; i < max; i++)
-    {
-	(*get_mtrr) (i, &base, &size, &type);
-	if (size == 0) usage_table[i] = 0;
-	else
-	{
-	    if (size < (0x100000 >> PAGE_SHIFT))
-	    {
-		/* less than 1MB */
-		factor = 'K';
-		size <<= PAGE_SHIFT - 10;
-	    }
-	    else
-	    {
-		factor = 'M';
-		size >>= 20 - PAGE_SHIFT;
-	    }
-	    sprintf
-		(ascii_buffer + ascii_buf_bytes,
-		 "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
-		 i, base, base >> (20 - PAGE_SHIFT), size, factor,
-		 attrib_to_str (type), usage_table[i]);
-	    ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
-	}
-    }
-    devfs_set_file_size (devfs_handle, ascii_buf_bytes);
-#  ifdef CONFIG_PROC_FS
-    if (proc_root_mtrr)
-	proc_root_mtrr->size = ascii_buf_bytes;
-#  endif  /*  CONFIG_PROC_FS  */
-}   /*  End Function compute_ascii  */
-
-#endif  /*  USERSPACE_INTERFACE  */
-
-EXPORT_SYMBOL(mtrr_add);
-EXPORT_SYMBOL(mtrr_del);
-
-#ifdef CONFIG_SMP
-
-typedef struct
-{
-    unsigned long base;
-    unsigned long size;
-    mtrr_type type;
-} arr_state_t;
-
-arr_state_t arr_state[8] __initdata =
-{
-    {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
-    {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
-};
-
-unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
-
-static void __init cyrix_arr_init_secondary(void)
-{
-    struct set_mtrr_context ctxt;
-    int i;
-
-    /* flush cache and enable MAPEN */
-    set_mtrr_prepare_save (&ctxt);
-    set_mtrr_cache_disable (&ctxt);
-
-     /* the CCRs are not contiguous */
-    for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
-    for(   ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
-    for(i=0; i<8; i++)
-      cyrix_set_arr_up(i,
-        arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
-
-    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
-}   /*  End Function cyrix_arr_init_secondary  */
-
-#endif
-
-/*
- * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
- * with the SMM (System Management Mode) mode. So we need the following:
- * Check whether SMI_LOCK (CCR3 bit 0) is set
- *   if it is set, write a warning message: ARR3 cannot be changed!
- *     (it cannot be changed until the next processor reset)
- *   if it is reset, then we can change it, set all the needed bits:
- *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
- *   - disable access to SMM memory (CCR1 bit 2 reset)
- *   - disable SMM mode (CCR1 bit 1 reset)
- *   - disable write protection of ARR3 (CCR6 bit 1 reset)
- *   - (maybe) disable ARR3
- * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
- */
-static void __init cyrix_arr_init(void)
-{
-    struct set_mtrr_context ctxt;
-    unsigned char ccr[7];
-    int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
-#ifdef CONFIG_SMP
-    int i;
-#endif
-
-    /* flush cache and enable MAPEN */
-    set_mtrr_prepare_save (&ctxt);
-    set_mtrr_cache_disable (&ctxt);
-
-    /* Save all CCRs locally */
-    ccr[0] = getCx86 (CX86_CCR0);
-    ccr[1] = getCx86 (CX86_CCR1);
-    ccr[2] = getCx86 (CX86_CCR2);
-    ccr[3] = ctxt.ccr3;
-    ccr[4] = getCx86 (CX86_CCR4);
-    ccr[5] = getCx86 (CX86_CCR5);
-    ccr[6] = getCx86 (CX86_CCR6);
-
-    if (ccr[3] & 1)
-    {
-	ccrc[3] = 1;
-	arr3_protected = 1;
-    }
-    else
-    {
-	/* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
-	 * access to SMM memory through ARR3 (bit 7).
-	 */
-	if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
-	if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
-	if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
-	arr3_protected = 0;
-	if (ccr[6] & 0x02) {
-	    ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */
-	    setCx86 (CX86_CCR6, ccr[6]);
-	}
-	/* Disable ARR3. This is safe now that we disabled SMM. */
-	/* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
-    }
-    /* If we changed CCR1 in memory, change it in the processor, too. */
-    if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
-
-    /* Enable ARR usage by the processor */
-    if (!(ccr[5] & 0x20))
-    {
-	ccr[5] |= 0x20; ccrc[5] = 1;
-	setCx86 (CX86_CCR5, ccr[5]);
-    }
-
-#ifdef CONFIG_SMP
-    for(i=0; i<7; i++) ccr_state[i] = ccr[i];
-    for(i=0; i<8; i++)
-      cyrix_get_arr(i,
-        &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
-#endif
-
-    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
-
-    if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
-    if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
-/*
-    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
-    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
-    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
-*/
-    if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
-}   /*  End Function cyrix_arr_init  */
-
-/*
- *	Initialise the later (saner) Winchip MCR variant. In this version
- *	the BIOS can pass us the registers it has used (but not their values)
- *	and the control register is read/write
- */
- 
-static void __init centaur_mcr1_init(void)
-{
-    unsigned i;
-    u32 lo, hi;
-
-    /* Unfortunately, MCR's are read-only, so there is no way to
-     * find out what the bios might have done.
-     */
-     
-    rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-    if(((lo>>17)&7)==1)		/* Type 1 Winchip2 MCR */
-    {
-    	lo&= ~0x1C0;		/* clear key */
-    	lo|= 0x040;		/* set key to 1 */
-	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);	/* unlock MCR */
-    }    
-    
-    centaur_mcr_type = 1;
-    
-    /*
-     *	Clear any unconfigured MCR's.
-     */
-
-    for (i = 0; i < 8; ++i)
-    {
-    	if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0)
-    	{
-    		if(!(lo & (1<<(9+i))))
-			wrmsr (MSR_IDT_MCR0 + i , 0, 0);
-		else
-			/*
-			 *	If the BIOS set up an MCR we cannot see it
-			 *	but we don't wish to obliterate it
-			 */
-			centaur_mcr_reserved |= (1<<i);
-	}
-    }
-    /*  
-     *	Throw the main write-combining switch... 
-     *	However if OOSTORE is enabled then people have already done far
-     *  cleverer things and we should behave. 
-     */
-
-    lo |= 15;			/* Write combine enables */
-    wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}   /*  End Function centaur_mcr1_init  */
-
-/*
- *	Initialise the original winchip with read only MCR registers
- *	no used bitmask for the BIOS to pass on and write only control
- */
- 
-static void __init centaur_mcr0_init(void)
-{
-    unsigned i;
-
-    /* Unfortunately, MCR's are read-only, so there is no way to
-     * find out what the bios might have done.
-     */
-     
-    /* Clear any unconfigured MCR's.
-     * This way we are sure that the centaur_mcr array contains the actual
-     * values. The disadvantage is that any BIOS tweaks are thus undone.
-     *
-     */
-    for (i = 0; i < 8; ++i)
-    {
-    	if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0)
-		wrmsr (MSR_IDT_MCR0 + i , 0, 0);
-    }
-
-    wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);	/* Write only */
-}   /*  End Function centaur_mcr0_init  */
-
-/*
- *	Initialise Winchip series MCR registers
- */
- 
-static void __init centaur_mcr_init(void)
-{
-    struct set_mtrr_context ctxt;
-
-    set_mtrr_prepare_save (&ctxt);
-    set_mtrr_cache_disable (&ctxt);
-
-    if(boot_cpu_data.x86_model==4)
-    	centaur_mcr0_init();
-    else if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9)
-    	centaur_mcr1_init();
-
-    set_mtrr_done (&ctxt);
-}   /*  End Function centaur_mcr_init  */
-
-static int __init mtrr_setup(void)
-{
-    if ( cpu_has_mtrr ) {
-	/* Intel (P6) standard MTRRs */
-	mtrr_if = MTRR_IF_INTEL;
-	get_mtrr = intel_get_mtrr;
-	set_mtrr_up = intel_set_mtrr_up;
-	switch (boot_cpu_data.x86_vendor) {
-
-	case X86_VENDOR_AMD:
-		/* The original Athlon docs said that
-		   total addressable memory is 44 bits wide.
-		   It was not really clear whether its MTRRs
-		   follow this or not. (Read: 44 or 36 bits).
-		   However, "x86-64_overview.pdf" explicitly
-		   states that "previous implementations support
-		   36 bit MTRRs" and also provides a way to
-		   query the width (in bits) of the physical
-		   addressable memory on the Hammer family.
-		 */
-		if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
-			u32	phys_addr;
-			phys_addr = cpuid_eax(0x80000008) & 0xff ;
-			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
-			size_and_mask = ~size_or_mask & 0xfff00000;
-			break;
-		}
-		size_or_mask  = 0xff000000; /* 36 bits */
-		size_and_mask = 0x00f00000;
-		break;
-
-	case X86_VENDOR_CENTAUR:
-		/* VIA Cyrix family have Intel style MTRRs, but don't support PAE */
-		if (boot_cpu_data.x86 == 6) {
-			size_or_mask  = 0xfff00000; /* 32 bits */
-			size_and_mask = 0;
-		}
-		break;
-
-	default:
-		/* Intel, etc. */
-		size_or_mask  = 0xff000000; /* 36 bits */
-		size_and_mask = 0x00f00000;
-		break;
-	}
-
-    } else if ( cpu_has_k6_mtrr ) {
-	/* Pre-Athlon (K6) AMD CPU MTRRs */
-	mtrr_if = MTRR_IF_AMD_K6;
-	get_mtrr = amd_get_mtrr;
-	set_mtrr_up = amd_set_mtrr_up;
-	size_or_mask  = 0xfff00000; /* 32 bits */
-	size_and_mask = 0;
-    } else if ( cpu_has_cyrix_arr ) {
-	/* Cyrix ARRs */
-	mtrr_if = MTRR_IF_CYRIX_ARR;
-	get_mtrr = cyrix_get_arr;
-	set_mtrr_up = cyrix_set_arr_up;
-	get_free_region = cyrix_get_free_region;
-	cyrix_arr_init();
-	size_or_mask  = 0xfff00000; /* 32 bits */
-	size_and_mask = 0;
-    } else if ( cpu_has_centaur_mcr ) {
-	/* Centaur MCRs */
-	mtrr_if = MTRR_IF_CENTAUR_MCR;
-	get_mtrr = centaur_get_mcr;
-	set_mtrr_up = centaur_set_mcr_up;
-	get_free_region = centaur_get_free_region;
-	centaur_mcr_init();
-	size_or_mask  = 0xfff00000; /* 32 bits */
-	size_and_mask = 0;
-    } else {
-	/* No supported MTRR interface */
-	mtrr_if = MTRR_IF_NONE;
-    }
-
-    printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
-	    "mtrr: detected mtrr type: %s\n",
-	    MTRR_VERSION, mtrr_if_name[mtrr_if]);
-
-    return (mtrr_if != MTRR_IF_NONE);
-}   /*  End Function mtrr_setup  */
-
-#ifdef CONFIG_SMP
-
-static volatile unsigned long smp_changes_mask __initdata = 0;
-static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
-
-void __init mtrr_init_boot_cpu(void)
-{
-    if ( !mtrr_setup () )
-	return;
-
-    if ( mtrr_if == MTRR_IF_INTEL ) {
-	/* Only for Intel MTRRs */
-	get_mtrr_state (&smp_mtrr_state);
-    }
-}   /*  End Function mtrr_init_boot_cpu  */
-
-static void __init intel_mtrr_init_secondary_cpu(void)
-{
-    unsigned long mask, count;
-    struct set_mtrr_context ctxt;
-
-    /*  Note that this is not ideal, since the cache is only flushed/disabled
-	for this CPU while the MTRRs are changed, but changing this requires
-	more invasive changes to the way the kernel boots  */
-    set_mtrr_prepare_save (&ctxt);
-    set_mtrr_cache_disable (&ctxt);
-    mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
-    set_mtrr_done (&ctxt);
-    /*  Use the atomic bitops to update the global mask  */
-    for (count = 0; count < sizeof mask * 8; ++count)
-    {
-	if (mask & 0x01) set_bit (count, &smp_changes_mask);
-	mask >>= 1;
-    }
-}   /*  End Function intel_mtrr_init_secondary_cpu  */
-
-void __init mtrr_init_secondary_cpu(void)
-{
-    switch ( mtrr_if ) {
-    case MTRR_IF_INTEL:
-	/* Intel (P6) standard MTRRs */
-	intel_mtrr_init_secondary_cpu();
-	break;
-    case MTRR_IF_CYRIX_ARR:
-	/* This is _completely theoretical_!
-	 * I assume here that one day Cyrix will support Intel APIC.
-	 * In reality on non-Intel CPUs we won't even get to this routine.
-	 * Hopefully no one will plug two Cyrix processors in a dual P5 board.
-	 *  :-)
-	 */
-	cyrix_arr_init_secondary ();
-	break;
-    case MTRR_IF_NONE:
-	break;
-    default:
-	/* I see no MTRRs I can support in SMP mode... */
-	printk ("mtrr: SMP support incomplete for this vendor\n");
-    }
-}   /*  End Function mtrr_init_secondary_cpu  */
-#endif  /*  CONFIG_SMP  */
-
-int __init mtrr_init(void)
-{
-#ifdef CONFIG_SMP
-    /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */
-
-    if ( mtrr_if == MTRR_IF_INTEL ) {
-	finalize_mtrr_state (&smp_mtrr_state);
-	mtrr_state_warn (smp_changes_mask);
-    }
-#else
-    if ( !mtrr_setup() )
-	return 0;		/* MTRRs not supported? */
-#endif
-
-#ifdef CONFIG_PROC_FS
-    proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
-    if (proc_root_mtrr) {
-	proc_root_mtrr->owner = THIS_MODULE;
-	proc_root_mtrr->proc_fops = &mtrr_fops;
-    }
-#endif
-#ifdef USERSPACE_INTERFACE
-    devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
-				   S_IFREG | S_IRUGO | S_IWUSR,
-				   &mtrr_fops, NULL);
-#endif
-    init_table ();
-    return 0;
-}   /*  End Function mtrr_init  */
-
-/*
- * Local Variables:
- * mode:c
- * c-file-style:"k&r"
- * c-basic-offset:4
- * End:
- */
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Tue Aug 27 12:27:37 2002
+++ b/arch/i386/kernel/process.c	Tue Aug 27 12:27:39 2002
@@ -23,7 +23,6 @@
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/user.h>
@@ -566,6 +565,7 @@
 	struct_cpy(childregs, regs);
 	childregs->eax = 0;
 	childregs->esp = esp;
+	p->user_tid = NULL;
 
 	p->thread.esp = (unsigned long) childregs;
 	p->thread.esp0 = (unsigned long) (childregs+1);
@@ -587,6 +587,45 @@
 			IO_BITMAP_BYTES);
 	}
 
+	/*
+	 * The common fastpath:
+	 */
+	if (!(clone_flags & (CLONE_SETTLS | CLONE_SETTID | CLONE_CLEARTID)))
+		return 0;
+	/*
+	 * Set a new TLS for the child thread?
+	 */
+	if (clone_flags & CLONE_SETTLS) {
+		struct desc_struct *desc;
+		struct user_desc info;
+		int idx;
+
+		if (copy_from_user(&info, (void *)childregs->esi, sizeof(info)))
+			return -EFAULT;
+		if (LDT_empty(&info))
+			return -EINVAL;
+
+		idx = info.entry_number;
+		if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+			return -EINVAL;
+
+		desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+
+	/*
+	 * Notify the child of the TID?
+	 */
+	if (clone_flags & CLONE_SETTID)
+		if (put_user(p->pid, (pid_t *)childregs->edx))
+			return -EFAULT;
+
+	/*
+	 * Does the userspace VM want the TID cleared on mm_release()?
+	 */
+	if (clone_flags & CLONE_CLEARTID)
+		p->user_tid = (int *) childregs->edx;
 	return 0;
 }
 
@@ -681,11 +720,8 @@
 
 	/*
 	 * Load the per-thread Thread-Local Storage descriptor.
-	 *
-	 * NOTE: it's faster to do the two stores unconditionally
-	 * than to branch away.
 	 */
-	load_TLS_desc(next, cpu);
+	load_TLS(next, cpu);
 
 	/*
 	 * Save away %fs and %gs. No need to save %es and %ds, as
@@ -834,35 +870,114 @@
 #undef first_sched
 
 /*
- * Set the Thread-Local Storage area:
+ * sys_alloc_thread_area: get a yet unused TLS descriptor index.
+ */
+static int get_free_idx(void)
+{
+	struct thread_struct *t = &current->thread;
+	int idx;
+
+	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
+		if (desc_empty(t->tls_array + idx))
+			return idx + GDT_ENTRY_TLS_MIN;
+	return -ESRCH;
+}
+
+/*
+ * Set a given TLS descriptor:
  */
-asmlinkage int sys_set_thread_area(unsigned long base, unsigned long flags)
+asmlinkage int sys_set_thread_area(struct user_desc *u_info)
 {
 	struct thread_struct *t = &current->thread;
-	int writable = 0;
-	int cpu;
+	struct user_desc info;
+	struct desc_struct *desc;
+	int cpu, idx;
+
+	if (copy_from_user(&info, u_info, sizeof(info)))
+		return -EFAULT;
+	idx = info.entry_number;
 
-	/* do not allow unused flags */
-	if (flags & ~TLS_FLAGS_MASK)
+	/*
+	 * index -1 means the kernel should try to find and
+	 * allocate an empty descriptor:
+	 */
+	if (idx == -1) {
+		idx = get_free_idx();
+		if (idx < 0)
+			return idx;
+		if (put_user(idx, &u_info->entry_number))
+			return -EFAULT;
+	}
+
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
 		return -EINVAL;
 
-	if (flags & TLS_FLAG_WRITABLE)
-		writable = 1;
+	desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
 
 	/*
 	 * We must not get preempted while modifying the TLS.
 	 */
 	cpu = get_cpu();
 
-        t->tls_desc.a = ((base & 0x0000ffff) << 16) | 0xffff;
-
-        t->tls_desc.b = (base & 0xff000000) | ((base & 0x00ff0000) >> 16) |
-				0xf0000 | (writable << 9) | (1 << 15) |
-					(1 << 22) | (1 << 23) | 0x7000;
+	if (LDT_empty(&info)) {
+		desc->a = 0;
+		desc->b = 0;
+	} else {
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+	load_TLS(t, cpu);
 
-	load_TLS_desc(t, cpu);
 	put_cpu();
 
-	return TLS_ENTRY*8 + 3;
+	return 0;
+}
+
+/*
+ * Get the current Thread-Local Storage area:
+ */
+
+#define GET_BASE(desc) ( \
+	(((desc)->a >> 16) & 0x0000ffff) | \
+	(((desc)->b << 16) & 0x00ff0000) | \
+	( (desc)->b        & 0xff000000)   )
+
+#define GET_LIMIT(desc) ( \
+	((desc)->a & 0x0ffff) | \
+	 ((desc)->b & 0xf0000) )
+	
+#define GET_32BIT(desc)		(((desc)->b >> 23) & 1)
+#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)
+#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)
+#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)
+#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)
+#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)
+
+asmlinkage int sys_get_thread_area(struct user_desc *u_info)
+{
+	struct user_desc info;
+	struct desc_struct *desc;
+	int idx;
+
+	if (get_user(idx, &u_info->entry_number))
+		return -EFAULT;
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
+
+	info.entry_number = idx;
+	info.base_addr = GET_BASE(desc);
+	info.limit = GET_LIMIT(desc);
+	info.seg_32bit = GET_32BIT(desc);
+	info.contents = GET_CONTENTS(desc);
+	info.read_exec_only = !GET_WRITABLE(desc);
+	info.limit_in_pages = GET_LIMIT_PAGES(desc);
+	info.seg_not_present = !GET_PRESENT(desc);
+	info.useable = GET_USEABLE(desc);
+
+	if (copy_to_user(u_info, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
 }
 
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Tue Aug 27 12:28:05 2002
+++ b/arch/i386/kernel/setup.c	Tue Aug 27 12:28:05 2002
@@ -275,16 +275,17 @@
  * replaces the original e820 map with a new one, removing overlaps.
  *
  */
+struct change_member {
+	struct e820entry *pbios; /* pointer to original bios entry */
+	unsigned long long addr; /* address for this change point */
+};
+struct change_member change_point_list[2*E820MAX] __initdata;
+struct change_member *change_point[2*E820MAX] __initdata;
+struct e820entry *overlap_list[E820MAX] __initdata;
+struct e820entry new_bios[E820MAX] __initdata;
+
 static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
 {
-	struct change_member {
-		struct e820entry *pbios; /* pointer to original bios entry */
-		unsigned long long addr; /* address for this change point */
-	};
-	struct change_member change_point_list[2*E820MAX];
-	struct change_member *change_point[2*E820MAX];
-	struct e820entry *overlap_list[E820MAX];
-	struct e820entry new_bios[E820MAX];
 	struct change_member *change_tmp;
 	unsigned long current_type, last_type;
 	unsigned long long last_addr;
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Tue Aug 27 12:28:05 2002
+++ b/arch/i386/kernel/signal.c	Tue Aug 27 12:28:05 2002
@@ -15,7 +15,6 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
--- a/arch/i386/kernel/smp.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/smp.c	Tue Aug 27 12:27:59 2002
@@ -18,6 +18,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
+#include <linux/interrupt.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
@@ -102,9 +103,6 @@
  *	or are signal timing bugs worked around in hardware and there's
  *	about nothing of note with C stepping upwards.
  */
-
-/* The 'big kernel lock' */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }};
 
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Tue Aug 27 12:28:05 2002
+++ b/arch/i386/kernel/smpboot.c	Tue Aug 27 12:28:05 2002
@@ -968,20 +968,6 @@
 {
 	int apicid, cpu, bit;
 
-        if (clustered_apic_mode && (numnodes > 1)) {
-                printk("Remapping cross-quad port I/O for %d quads\n",
-			numnodes);
-                printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
-                        (u_long) xquad_portio, 
-			(u_long) numnodes * XQUAD_PORTIO_LEN);
-                xquad_portio = ioremap (XQUAD_PORTIO_BASE, 
-			numnodes * XQUAD_PORTIO_LEN);
-        }
-
-#ifdef CONFIG_MTRR
-	/*  Must be done before other processors booted  */
-	mtrr_init_boot_cpu ();
-#endif
 	/*
 	 * Initialize the logical to physical CPU number mapping
 	 * and the per-CPU profiling counter/multiplier
@@ -1075,6 +1061,16 @@
 
 	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid)
 		BUG();
+
+        if (clustered_apic_mode && (numnodes > 1)) {
+                printk("Remapping cross-quad port I/O for %d quads\n",
+			numnodes);
+                printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
+                        (u_long) xquad_portio, 
+			(u_long) numnodes * XQUAD_PORTIO_LEN);
+                xquad_portio = ioremap (XQUAD_PORTIO_BASE, 
+			numnodes * XQUAD_PORTIO_LEN);
+        }
 
 	/*
 	 * Scan the CPU present map and fire up the other CPUs via do_boot_cpu
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c	Tue Aug 27 12:28:08 2002
+++ b/arch/i386/kernel/suspend.c	Tue Aug 27 12:28:08 2002
@@ -207,7 +207,7 @@
 	struct tss_struct * t = init_tss + cpu;
 
 	set_tss_desc(cpu,t);	/* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */
-        cpu_gdt_table[cpu][TSS_ENTRY].b &= 0xfffffdff;
+        cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
 
 	load_TR_desc();				/* This does ltr */
 	load_LDT(&current->mm->context);	/* This does lldt */
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Tue Aug 27 12:28:06 2002
+++ b/arch/i386/kernel/time.c	Tue Aug 27 12:28:06 2002
@@ -639,8 +639,8 @@
 }
 
 static struct device device_i8253 = {
-	name:	       	"i8253",
-	bus_id:		"0040",
+	.name	       	= "i8253",
+	.bus_id		= "0040",
 };
 
 static int time_init_driverfs(void)
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Tue Aug 27 12:28:01 2002
+++ b/arch/i386/kernel/traps.c	Tue Aug 27 12:28:01 2002
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/init.h>
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c	Tue Aug 27 12:27:59 2002
+++ b/arch/i386/kernel/vm86.c	Tue Aug 27 12:27:59 2002
@@ -8,7 +8,6 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
diff -Nru a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
--- a/arch/i386/lib/checksum.S	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/lib/checksum.S	Tue Aug 27 12:28:02 2002
@@ -149,6 +149,8 @@
 30:	subl $2, %ecx          
 	ja 20b                 
 	je 32f
+	addl $2, %ecx
+	jz 80f
 	movzbl (%esi),%ebx	# csumming 1 byte, 2-aligned
 	addl %ebx, %eax
 	adcl $0, %eax
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Tue Aug 27 12:27:42 2002
+++ b/arch/i386/mm/fault.c	Tue Aug 27 12:27:42 2002
@@ -184,7 +184,7 @@
 	 * If we're in an interrupt, have no user context or are running in an
 	 * atomic region then we must not take the fault..
 	 */
-	if (preempt_count() || !mm)
+	if (in_atomic() || !mm)
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c	Tue Aug 27 12:28:02 2002
+++ b/arch/i386/mm/ioremap.c	Tue Aug 27 12:28:02 2002
@@ -159,7 +159,7 @@
 	area->phys_addr = phys_addr;
 	addr = area->addr;
 	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
-		vfree(addr);
+		vunmap(addr);
 		return NULL;
 	}
 	return (void *) (offset + (char *)addr);
@@ -215,13 +215,13 @@
 	struct vm_struct *p;
 	if (addr <= high_memory) 
 		return; 
-	p = remove_kernel_area((void *) (PAGE_MASK & (unsigned long) addr));
+	p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
 	if (!p) { 
 		printk("__iounmap: bad address %p\n", addr);
 		return;
 	} 
 
-	vmfree_area_pages(VMALLOC_VMADDR(p->addr), p->size);	
+	unmap_vm_area(p);
 	if (p->flags && p->phys_addr < virt_to_phys(high_memory)) { 
 		change_page_attr(virt_to_page(__va(p->phys_addr)),
 				 p->size >> PAGE_SHIFT,
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Tue Aug 27 12:27:57 2002
+++ b/arch/ia64/Makefile	Tue Aug 27 12:27:57 2002
@@ -13,8 +13,8 @@
 
 export AWK
 
-OBJCOPYFLAGS := --strip-all 
-LDFLAGS_vmlinux := -static -T arch/$(ARCH)/vmlinux.lds
+OBJCOPYFLAGS := --strip-all
+LDFLAGS_vmlinux := -static -T arch/$(ARCH)/vmlinux.lds.s
 AFLAGS_KERNEL := -mconstant-gp
 EXTRA	=
 
@@ -26,7 +26,7 @@
 GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
 
 ifneq ($(GCC_VERSION),2)
-	CFLAGS += -frename-registers --param max-inline-insns=2000
+	CFLAGS += -frename-registers --param max-inline-insns=5000
 endif
 
 ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y)
@@ -94,11 +94,9 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-vmlinux: arch/$(ARCH)/vmlinux.lds
+vmlinux: arch/$(ARCH)/vmlinux.lds.s
 
-arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE
-	$(CPP) -D__ASSEMBLY__ -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \
-		-traditional arch/$(ARCH)/vmlinux.lds.S > $@
+CPPFLAGS_arch/ia64/vmlinux.lds.s := -traditional
 
 compressed: vmlinux
 	$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux-tmp
@@ -125,7 +123,6 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
-	rm -f arch/$(ARCH)/vmlinux.lds
 	@$(MAKE) -C arch/$(ARCH)/tools mrproper
 
 bootpfile:
diff -Nru a/arch/ia64/boot/Makefile b/arch/ia64/boot/Makefile
--- a/arch/ia64/boot/Makefile	Tue Aug 27 12:28:07 2002
+++ b/arch/ia64/boot/Makefile	Tue Aug 27 12:28:07 2002
@@ -12,8 +12,10 @@
 
 OBJECTS	= bootloader.o
 
-targets-$(CONFIG_IA64_HP_SIM) += bootloader
-targets-$(CONFIG_IA64_GENERIC) += bootloader
+targets-$(CONFIG_IA64_HP_SIM)	+= bootloader
+targets-$(CONFIG_IA64_GENERIC)	+= bootloader
+
+CFLAGS	:= $(CFLAGS) $(CFLAGS_KERNEL)
 
 all:	$(targets-y)
 
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/config.in	Tue Aug 27 12:28:08 2002
@@ -64,12 +64,13 @@
 	fi
 fi
 
-if [ "$CONFIG_IA64_GENERIC" = "y" -o  "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
+if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ];
+then
 	bool '  Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
 	define_bool CONFIG_PM y
 fi
 
-if [ "$CONFIG_IA64_SGI_SN1" = "y" -o  "$CONFIG_IA64_SGI_SN2" = "y" ]; then
+if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then
 	define_bool CONFIG_IA64_SGI_SN y
 	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG
 	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM
@@ -99,63 +100,45 @@
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  source drivers/acpi/Config.in
 
-source drivers/acpi/Config.in
+  bool 'PCI support' CONFIG_PCI
+  source drivers/pci/Config.in
 
-bool 'PCI support' CONFIG_PCI
-source drivers/pci/Config.in
-
-bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
-if [ "$CONFIG_HOTPLUG" = "y" ]; then
-   source drivers/pcmcia/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-fi
-
-source drivers/parport/Config.in
+  bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+  if [ "$CONFIG_HOTPLUG" = "y" ]; then
+     source drivers/hotplug/Config.in
+     source drivers/pcmcia/Config.in
+  else
+     define_bool CONFIG_PCMCIA n
+  fi
 
+  source drivers/parport/Config.in
 fi # !HP_SIM
 
 endmenu
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
-
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  source drivers/mtd/Config.in
+  source drivers/pnp/Config.in
+  source drivers/block/Config.in
+  source drivers/ieee1394/Config.in
+  source drivers/message/i2o/Config.in
+  source drivers/md/Config.in
+  source drivers/message/fusion/Config.in
 
-source drivers/mtd/Config.in
-source drivers/pnp/Config.in
-source drivers/block/Config.in
-source drivers/ieee1394/Config.in
-source drivers/message/i2o/Config.in
-source drivers/md/Config.in
-source drivers/message/fusion/Config.in
-
-mainmenu_option next_comment
-comment 'ATA/ATAPI/MFM/RLL support'
-
-tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE
+  mainmenu_option next_comment
+  comment 'ATA/ATAPI/MFM/RLL support'
 
-if [ "$CONFIG_IDE" != "n" ]; then
-  source drivers/ide/Config.in
-else
-  define_bool CONFIG_BLK_DEV_HD n
-fi
-endmenu
+  tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE
 
-else # ! HP_SIM
-mainmenu_option next_comment
-comment 'Block devices'
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
-
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
-   int '  Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+  if [ "$CONFIG_IDE" != "n" ]; then
+    source drivers/ide/Config.in
+  else
+    define_bool CONFIG_BLK_DEV_HD n
+  fi
+  endmenu
 fi
-endmenu
-fi # !HP_SIM
 
 mainmenu_option next_comment
 comment 'SCSI support'
@@ -167,81 +150,88 @@
 fi
 endmenu
 
+if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+fi
+
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  if [ "$CONFIG_NET" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'Network device support'
+
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+    fi
+    endmenu
+  fi
+  source net/ax25/Config.in
+  source drivers/isdn/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
-  comment 'Network device support'
+  comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
-  bool 'Network device support' CONFIG_NETDEVICES
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source drivers/net/Config.in
+  bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+  if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+    source drivers/cdrom/Config.in
   fi
   endmenu
-fi
 
-source net/ax25/Config.in
+  #
+  # input before char - char/joystick depends on it. As does USB.
+  #
+  source drivers/input/Config.in
+  source drivers/char/Config.in
 
-source drivers/isdn/Config.in
+  #source drivers/misc/Config.in
 
-mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
-bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-  source drivers/cdrom/Config.in
-fi
-endmenu
-
-fi # !HP_SIM
-
-#
-# input before char - char/joystick depends on it. As does USB.
-#
-source drivers/input/Config.in
-source drivers/char/Config.in
+  source drivers/media/Config.in
+else # HP_SIM
 
-#source drivers/misc/Config.in
-
-source drivers/media/Config.in
-
-source fs/Config.in
-
-if [ "$CONFIG_VT" = "y" ]; then
   mainmenu_option next_comment
-  comment 'Console drivers'
-  bool 'VGA text console' CONFIG_VGA_CONSOLE
-  source drivers/video/Config.in
-  if [ "$CONFIG_FB" = "y" ]; then
-    define_bool CONFIG_PCI_CONSOLE y
+  comment 'Block devices'
+  tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+  dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+
+  tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+  if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+    int '  Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
   fi
   endmenu
-fi
+fi # HP_SIM
 
-if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
-
-mainmenu_option next_comment
-comment 'Sound'
-
-tristate 'Sound card support' CONFIG_SOUND
-if [ "$CONFIG_SOUND" != "n" ]; then
-  source sound/Config.in
-fi
-endmenu
+source fs/Config.in
 
-source drivers/usb/Config.in
+if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  if [ "$CONFIG_VT" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'Console drivers'
+    bool 'VGA text console' CONFIG_VGA_CONSOLE
+    source drivers/video/Config.in
+    if [ "$CONFIG_FB" = "y" ]; then
+      define_bool CONFIG_PCI_CONSOLE y
+    fi
+    endmenu
+  fi
 
-source lib/Config.in
+  mainmenu_option next_comment
+  comment 'Sound'
 
-source net/bluetooth/Config.in
+  tristate 'Sound card support' CONFIG_SOUND
+  if [ "$CONFIG_SOUND" != "n" ]; then
+    source sound/Config.in
+  fi
+  endmenu
 
+  source drivers/usb/Config.in
+  source lib/Config.in
+  source net/bluetooth/Config.in
 fi # !HP_SIM
 
 if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then
-  source arch/ia64/hp/Config.in
+  source arch/ia64/hp/sim/Config.in
 fi
 
-
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
@@ -255,7 +245,14 @@
    bool '  Disable VHPT' CONFIG_DISABLE_VHPT
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
 
-   bool '  Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
+   bool '  Early printk support' CONFIG_IA64_EARLY_PRINTK
+   if [ "$CONFIG_IA64_EARLY_PRINTK" != "n" ]; then
+      bool '    Early printk on MMIO serial port' CONFIG_IA64_EARLY_PRINTK_UART
+      if [ "$CONFIG_IA64_EARLY_PRINTK_UART" != "n" ]; then
+         hex '      UART MMIO base address' CONFIG_IA64_EARLY_PRINTK_UART_BASE ff5e0000
+      fi
+      bool '    Early printk on VGA' CONFIG_IA64_EARLY_PRINTK_VGA
+   fi
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
diff -Nru a/arch/ia64/hp/Config.in b/arch/ia64/hp/Config.in
--- a/arch/ia64/hp/Config.in	Tue Aug 27 12:27:57 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-mainmenu_option next_comment
-comment 'HP Simulator drivers'
-
-bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
-bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
-if [ "$CONFIG_SCSI" != "n" ]; then
-  bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
-fi
-endmenu
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c	Tue Aug 27 12:28:01 2002
+++ b/arch/ia64/hp/common/sba_iommu.c	Tue Aug 27 12:28:01 2002
@@ -2,6 +2,7 @@
 **  IA64 System Bus Adapter (SBA) I/O MMU manager
 **
 **	(c) Copyright 2002 Alex Williamson
+**	(c) Copyright 2002 Grant Grundler
 **	(c) Copyright 2002 Hewlett-Packard Company
 **
 **	Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)
@@ -110,7 +111,7 @@
 */
 #define DELAYED_RESOURCE_CNT	16
 
-#define DEFAULT_DMA_HINT_REG	0
+#define DEFAULT_DMA_HINT_REG(d)	0
 
 #define ZX1_FUNC_ID_VALUE    ((PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP)
 #define ZX1_MC_ID    ((PCI_DEVICE_ID_HP_ZX1_MC << 16) | PCI_VENDOR_ID_HP)
@@ -216,9 +217,10 @@
 static int reserve_sba_gart = 1;
 static struct pci_dev sac_only_dev;
 
-#define sba_sg_iova(sg) (sg->address)
+#define sba_sg_address(sg) (page_address((sg)->page) + (sg)->offset)
 #define sba_sg_len(sg) (sg->length)
-#define sba_sg_buffer(sg) (sg->orig_address)
+#define sba_sg_iova(sg) (sg->dma_address)
+#define sba_sg_iova_len(sg) (sg->dma_length)
 
 /* REVISIT - fix me for multiple SBAs/IOCs */
 #define GET_IOC(dev) (sba_list->ioc)
@@ -232,7 +234,7 @@
 ** rather than the HW. I/O MMU allocation alogorithms can be
 ** faster with smaller size is (to some degree).
 */
-#define DMA_CHUNK_SIZE  (BITS_PER_LONG*PAGE_SIZE)
+#define DMA_CHUNK_SIZE  (BITS_PER_LONG*IOVP_SIZE)
 
 /* Looks nice and keeps the compiler happy */
 #define SBA_DEV(d) ((struct sba_device *) (d))
@@ -255,7 +257,7 @@
  * sba_dump_tlb - debugging only - print IOMMU operating parameters
  * @hpa: base address of the IOMMU
  *
- * Print the size/location of the IO MMU PDIR.
+ * Print the size/location of the IO MMU Pdir.
  */
 static void
 sba_dump_tlb(char *hpa)
@@ -273,12 +275,12 @@
 #ifdef ASSERT_PDIR_SANITY
 
 /**
- * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * sba_dump_pdir_entry - debugging only - print one IOMMU Pdir entry
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @msg: text to print ont the output line.
  * @pide: pdir index.
  *
- * Print one entry of the IO MMU PDIR in human readable form.
+ * Print one entry of the IO MMU Pdir in human readable form.
  */
 static void
 sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
@@ -360,25 +362,25 @@
  * print the SG list so we can verify it's correct by hand.
  */
 static void
-sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+sba_dump_sg(struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	while (nents-- > 0) {
-		printk(" %d : %08lx/%05x %p\n",
+		printk(" %d : DMA %08lx/%05x CPU %p\n",
 				nents,
 				(unsigned long) sba_sg_iova(startsg),
-				sba_sg_len(startsg),
-				sba_sg_buffer(startsg));
+				sba_sg_iova_len(startsg),
+				sba_sg_address(startsg));
 		startsg++;
 	}
 }
 static void
-sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+sba_check_sg(struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	struct scatterlist *the_sg = startsg;
 	int the_nents = nents;
 
 	while (the_nents-- > 0) {
-		if (sba_sg_buffer(the_sg) == 0x0UL)
+		if (sba_sg_address(the_sg) == 0x0UL)
 			sba_dump_sg(NULL, startsg, nents);
 		the_sg++;
 	}
@@ -404,7 +406,6 @@
 #define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
 #define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase))
 
-/* FIXME : review these macros to verify correctness and usage */
 #define PDIR_INDEX(iovp)   ((iovp)>>IOVP_SHIFT)
 
 #define RESMAP_MASK(n)    ~(~0UL << (n))
@@ -412,7 +413,7 @@
 
 
 /**
- * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * sba_search_bitmap - find free space in IO Pdir resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @bits_wanted: number of entries we need.
  *
@@ -449,7 +450,7 @@
 		** We need the alignment to invalidate I/O TLB using
 		** SBA HW features in the unmap path.
 		*/
-		unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
+		unsigned long o = 1UL << get_order(bits_wanted << IOVP_SHIFT);
 		uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
 		unsigned long mask;
 
@@ -495,7 +496,7 @@
 
 
 /**
- * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * sba_alloc_range - find free bits and mark them in IO Pdir resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @size: number of bytes to create a mapping for
  *
@@ -557,7 +558,7 @@
 
 
 /**
- * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * sba_free_range - unmark bits in IO Pdir resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @iova: IO virtual address which was previously allocated.
  * @size: number of bytes to create a mapping for
@@ -604,14 +605,14 @@
 
 
 /**
- * sba_io_pdir_entry - fill in one IO PDIR entry
- * @pdir_ptr:  pointer to IO PDIR entry
- * @vba: Virtual CPU address of buffer to map
+ * sba_io_pdir_entry - fill in one IO Pdir entry
+ * @pdir_ptr:  pointer to IO Pdir entry
+ * @phys_page: phys CPU address of page to map
  *
  * SBA Mapping Routine
  *
- * Given a virtual address (vba, arg1) sba_io_pdir_entry()
- * loads the I/O PDIR entry pointed to by pdir_ptr (arg0).
+ * Given a physical address (phys_page, arg1) sba_io_pdir_entry()
+ * loads the I/O Pdir entry pointed to by pdir_ptr (arg0).
  * Each IO Pdir entry consists of 8 bytes as shown below
  * (LSB == bit 0):
  *
@@ -623,20 +624,12 @@
  *  V  == Valid Bit
  *  U  == Unused
  * PPN == Physical Page Number
- *
- * The physical address fields are filled with the results of virt_to_phys()
- * on the vba.
  */
 
-#if 1
-#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL)
-#else
-void SBA_INLINE
-sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
-{
-	*pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL);
-}
-#endif
+#define SBA_VALID_MASK	0x80000000000000FFULL
+#define sba_io_pdir_entry(pdir_ptr, phys_page) *pdir_ptr = (phys_page | SBA_VALID_MASK)
+#define sba_io_page(pdir_ptr) (*pdir_ptr & ~SBA_VALID_MASK)
+
 
 #ifdef ENABLE_MARK_CLEAN
 /**
@@ -660,12 +653,12 @@
 #endif
 
 /**
- * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * sba_mark_invalid - invalidate one or more IO Pdir entries
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @iova:  IO Virtual Address mapped earlier
  * @byte_cnt:  number of bytes this mapping covers.
  *
- * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * Marking the IO Pdir entry(ies) as Invalid and invalidate
  * corresponding IO TLB entry. The PCOM (Purge Command Register)
  * is to purge stale entries in the IO TLB when unmapping entries.
  *
@@ -700,14 +693,14 @@
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
 		/*
-		** clear I/O PDIR entry "valid" bit
+		** clear I/O Pdir entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
 		** We should only clear bits that have previously
 		** been enabled.
 		*/
-		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+		ioc->pdir_base[off] &= ~SBA_VALID_MASK;
 	} else {
-		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+		u32 t = get_order(byte_cnt) + IOVP_SHIFT;
 
 		iovp |= t;
 		ASSERT(t <= 31);   /* 2GB! Max value of "size" field */
@@ -716,7 +709,7 @@
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
 			/* clear I/O Pdir entry "valid" bit first */
-			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+			ioc->pdir_base[off] &= ~SBA_VALID_MASK;
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
@@ -744,7 +737,7 @@
 	u64 *pdir_start;
 	int pide;
 #ifdef ALLOW_IOV_BYPASS
-	unsigned long pci_addr = virt_to_phys(addr);
+	unsigned long phys_addr = virt_to_phys(addr);
 #endif
 
 	ioc = GET_IOC(dev);
@@ -754,7 +747,7 @@
 	/*
  	** Check if the PCI device can DMA to ptr... if so, just return ptr
  	*/
-	if ((pci_addr & ~dev->dma_mask) == 0) {
+	if ((phys_addr & ~dev->dma_mask) == 0) {
 		/*
  		** Device is bit capable of DMA'ing to the buffer...
 		** just return the PCI address of ptr
@@ -765,8 +758,8 @@
 		spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 		DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
-		           dev->dma_mask, pci_addr);
-		return pci_addr;
+		           dev->dma_mask, phys_addr);
+		return phys_addr;
 	}
 #endif
 
@@ -799,7 +792,8 @@
 
 	while (size > 0) {
 		ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
-		sba_io_pdir_entry(pdir_start, (unsigned long) addr);
+
+		sba_io_pdir_entry(pdir_start, virt_to_phys(addr));
 
 		DBG_RUN("     pdir 0x%p %lx\n", pdir_start, *pdir_start);
 
@@ -812,7 +806,7 @@
 	sba_check_pdir(ioc,"Check after sba_map_single()");
 #endif
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
-	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG(direction));
 }
 
 /**
@@ -866,6 +860,29 @@
 	size += offset;
 	size = ROUNDUP(size, IOVP_SIZE);
 
+#ifdef ENABLE_MARK_CLEAN
+	/*
+	** Don't need to hold the spinlock while telling VM pages are "clean".
+	** The pages are "busy" in the resource map until we mark them free.
+	** But tell VM pages are clean *before* releasing the resource
+	** in order to avoid race conditions.
+	*/
+	if (direction == PCI_DMA_FROMDEVICE) {
+		u32 iovp = (u32) SBA_IOVP(ioc,iova);
+		unsigned int pide = PDIR_INDEX(iovp);
+		u64 *pdirp = &(ioc->pdir_base[pide]);
+		size_t byte_cnt = size;
+		void *addr;
+
+		do {
+			addr = phys_to_virt(sba_io_page(pdirp));
+			mark_clean(addr, min(byte_cnt, IOVP_SIZE));
+			pdirp++;
+			byte_cnt -= IOVP_SIZE;
+		} while (byte_cnt > 0);
+	}
+#endif
+
 	spin_lock_irqsave(&ioc->res_lock, flags);
 #ifdef CONFIG_PROC_FS
 	ioc->usingle_calls++;
@@ -891,40 +908,7 @@
 	sba_free_range(ioc, iova, size);
 	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
 #endif /* DELAYED_RESOURCE_CNT == 0 */
-#ifdef ENABLE_MARK_CLEAN
-	if (direction == PCI_DMA_FROMDEVICE) {
-		u32 iovp = (u32) SBA_IOVP(ioc,iova);
-		int off = PDIR_INDEX(iovp);
-		void *addr;
-
-		if (size <= IOVP_SIZE) {
-			addr = phys_to_virt(ioc->pdir_base[off] &
-					    ~0xE000000000000FFFULL);
-			mark_clean(addr, size);
-		} else {
-			size_t byte_cnt = size;
-
-			do {
-				addr = phys_to_virt(ioc->pdir_base[off] &
-				                    ~0xE000000000000FFFULL);
-				mark_clean(addr, min(byte_cnt, IOVP_SIZE));
-				off++;
-				byte_cnt -= IOVP_SIZE;
-
-			   } while (byte_cnt > 0);
-		}
-	}
-#endif
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
-
-	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
-	** For Astro based systems this isn't a big deal WRT performance.
-	** As long as 2.4 kernels copyin/copyout data from/to userspace,
-	** we don't need the syncdma. The issue here is I/O MMU cachelines
-	** are *not* coherent in all cases.  May be hwrev dependent.
-	** Need to investigate more.
-	asm volatile("syncdma");	
-	*/
 }
 
 
@@ -980,242 +964,109 @@
 }
 
 
-/*
-** Since 0 is a valid pdir_base index value, can't use that
-** to determine if a value is valid or not. Use a flag to indicate
-** the SG list entry contains a valid pdir index.
-*/
-#define PIDE_FLAG 0x1UL
-
 #ifdef DEBUG_LARGE_SG_ENTRIES
 int dump_run_sg = 0;
 #endif
 
-
-/**
- * sba_fill_pdir - write allocated SG entries into IO PDIR
- * @ioc: IO MMU structure which owns the pdir we are interested in.
- * @startsg:  list of IOVA/size pairs
- * @nents: number of entries in startsg list
- *
- * Take preprocessed SG list and write corresponding entries
- * in the IO PDIR.
- */
-
-static SBA_INLINE int
-sba_fill_pdir(
-	struct ioc *ioc,
-	struct scatterlist *startsg,
-	int nents)
-{
-	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
-	int n_mappings = 0;
-	u64 *pdirp = 0;
-	unsigned long dma_offset = 0;
-
-	dma_sg--;
-	while (nents-- > 0) {
-		int     cnt = sba_sg_len(startsg);
-		sba_sg_len(startsg) = 0;
-
-#ifdef DEBUG_LARGE_SG_ENTRIES
-		if (dump_run_sg)
-			printk(" %2d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
-#else
-		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
-#endif
-		/*
-		** Look for the start of a new DMA stream
-		*/
-		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
-			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
-			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sba_sg_iova(startsg) = 0;
-			dma_sg++;
-			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
-			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
-			n_mappings++;
-		}
-
-		/*
-		** Look for a VCONTIG chunk
-		*/
-		if (cnt) {
-			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
-			ASSERT(pdirp);
-
-			/* Since multiple Vcontig blocks could make up
-			** one DMA stream, *add* cnt to dma_len.
-			*/
-			sba_sg_len(dma_sg) += cnt;
-			cnt += dma_offset;
-			dma_offset=0;	/* only want offset on first chunk */
-			cnt = ROUNDUP(cnt, IOVP_SIZE);
-#ifdef CONFIG_PROC_FS
-			ioc->msg_pages += cnt >> IOVP_SHIFT;
-#endif
-			do {
-				sba_io_pdir_entry(pdirp, vaddr);
-				vaddr += IOVP_SIZE;
-				cnt -= IOVP_SIZE;
-				pdirp++;
-			} while (cnt > 0);
-		}
-		startsg++;
-	}
-#ifdef DEBUG_LARGE_SG_ENTRIES
-	dump_run_sg = 0;
-#endif
-	return(n_mappings);
-}
-
-
-/*
-** Two address ranges are DMA contiguous *iff* "end of prev" and
-** "start of next" are both on a page boundry.
-**
-** (shift left is a quick trick to mask off upper bits)
-*/
-#define DMA_CONTIG(__X, __Y) \
-	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+#define SG_ENT_VIRT_PAGE(sg) page_address((sg)->page)
+#define SG_ENT_PHYS_PAGE(SG) virt_to_phys(SG_ENT_VIRT_PAGE(SG))
 
 
 /**
  * sba_coalesce_chunks - preprocess the SG list
  * @ioc: IO MMU structure which owns the pdir we are interested in.
- * @startsg:  list of IOVA/size pairs
+ * @startsg:  input=SG list	output=DMA addr/len pairs filled in
  * @nents: number of entries in startsg list
+ * @direction: R/W or both.
+ *
+ * Walk the SG list and determine where the breaks are in the DMA stream.
+ * Allocate IO Pdir resources and fill them in separate loop.
+ * Returns the number of DMA streams used for output IOVA list.
+ * Note each DMA stream can consume multiple IO Pdir entries.
  *
- * First pass is to walk the SG list and determine where the breaks are
- * in the DMA stream. Allocates PDIR entries but does not fill them.
- * Returns the number of DMA chunks.
- *
- * Doing the fill seperate from the coalescing/allocation keeps the
- * code simpler. Future enhancement could make one pass through
- * the sglist do both.
+ * Code is written assuming some coalescing is possible.
  */
 static SBA_INLINE int
-sba_coalesce_chunks( struct ioc *ioc,
-	struct scatterlist *startsg,
-	int nents)
-{
-	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
-	unsigned long vcontig_len;         /* len of VCONTIG chunk */
-	unsigned long vcontig_end;
-	struct scatterlist *dma_sg;        /* next DMA stream head */
-	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+sba_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg,
+	int nents, int direction)
+{
+	struct scatterlist *dma_sg = startsg;	/* return array */
 	int n_mappings = 0;
 
-	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) (startsg->address); 
+	ASSERT(nents > 1);
+
+	do {
+		unsigned int dma_cnt = 1; /* number of pages in DMA stream */
+		unsigned int pide;	/* index into IO Pdir array */
+		u64 *pdirp;		/* pointer into IO Pdir array */
+		unsigned long dma_offset, dma_len; /* cumulative DMA stream */
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
-		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
-		vcontig_end +=  vaddr;
-		dma_offset = vaddr & ~IOVP_MASK;
-
-		/* PARANOID: clear entries */
-		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
-		sba_sg_iova(startsg) = 0;
-		sba_sg_len(startsg) = 0;
+		dma_len = sba_sg_len(startsg);
+		dma_offset = (unsigned long) sba_sg_address(startsg);
+		startsg++;
+		nents--;
 
 		/*
-		** This loop terminates one iteration "early" since
-		** it's always looking one "ahead".
+		** We want to know how many entries can be coalesced
+		** before trying to allocate IO Pdir space.
+		** IOVAs can then be allocated "naturally" aligned
+		** to take advantage of the block IO TLB flush.
 		*/
-		while (--nents > 0) {
-			unsigned long vaddr;	/* tmp */
+		while (nents) {
+			unsigned long end_offset = dma_offset + dma_len;
 
-			startsg++;
-
-			/* catch brokenness in SCSI layer */
-			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
+			/* prev entry must end on a page boundary */
+			if (end_offset & IOVP_MASK)
+				break;
 
-			/*
-			** First make sure current dma stream won't
-			** exceed DMA_CHUNK_SIZE if we coalesce the
-			** next entry.
-			*/
-			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+			/* next entry start on a page boundary? */
+			if (startsg->offset)
 				break;
 
 			/*
-			** Then look for virtually contiguous blocks.
-			**
-			** append the next transaction?
+			** make sure current dma stream won't exceed
+			** DMA_CHUNK_SIZE if coalescing entries.
 			*/
-			vaddr = (unsigned long) sba_sg_iova(startsg);
-			if  (vcontig_end == vaddr)
-			{
-				vcontig_len += sba_sg_len(startsg);
-				vcontig_end += sba_sg_len(startsg);
-				dma_len     += sba_sg_len(startsg);
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				sba_sg_len(startsg) = 0;
-				continue;
-			}
+			if (((end_offset + startsg->length + ~IOVP_MASK)
+								& IOVP_MASK)
+					> DMA_CHUNK_SIZE)
+				break;
 
-#ifdef DEBUG_LARGE_SG_ENTRIES
-			dump_run_sg = (vcontig_len > IOVP_SIZE);
-#endif
+			dma_len += sba_sg_len(startsg);
+			startsg++;
+			nents--;
+			dma_cnt++;
+		}
 
-			/*
-			** Not virtually contigous.
-			** Terminate prev chunk.
-			** Start a new chunk.
-			**
-			** Once we start a new VCONTIG chunk, dma_offset
-			** can't change. And we need the offset from the first
-			** chunk - not the last one. Ergo Successive chunks
-			** must start on page boundaries and dove tail
-			** with it's predecessor.
-			*/
-			sba_sg_len(vcontig_sg) = vcontig_len;
+		ASSERT(dma_len <= DMA_CHUNK_SIZE);
 
-			vcontig_sg = startsg;
-			vcontig_len = sba_sg_len(startsg);
+		/* allocate IO Pdir resource.
+		** returns index into (u64) IO Pdir array.
+		** IOVA is formed from this.
+		*/
+		pide = sba_alloc_range(ioc, dma_cnt << IOVP_SHIFT);
+		pdirp = &(ioc->pdir_base[pide]);
 
-			/*
-			** 3) do the entries end/start on page boundaries?
-			**    Don't update vcontig_end until we've checked.
-			*/
-			if (DMA_CONTIG(vcontig_end, vaddr))
-			{
-				vcontig_end = vcontig_len + vaddr;
-				dma_len += vcontig_len;
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				continue;
-			} else {
-				break;
-			}
+		/* fill_pdir: write stream into IO Pdir */
+		while (dma_cnt--) {
+			sba_io_pdir_entry(pdirp, SG_ENT_PHYS_PAGE(startsg));
+			startsg++;
+			pdirp++;
 		}
 
-		/*
-		** End of DMA Stream
-		** Terminate last VCONTIG block.
-		** Allocate space for DMA stream.
-		*/
-		sba_sg_len(vcontig_sg) = vcontig_len;
-		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
-		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
-			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
-			| dma_offset);
+		/* "output" IOVA */
+		sba_sg_iova(dma_sg) = SBA_IOVA(ioc,
+					((dma_addr_t) pide << IOVP_SHIFT),
+					dma_offset,
+					DEFAULT_DMA_HINT_REG(direction));
+		sba_sg_iova_len(dma_sg) = dma_len;
+
+		dma_sg++;
 		n_mappings++;
-	}
+	} while (nents);
 
 	return n_mappings;
 }
@@ -1223,7 +1074,7 @@
 
 /**
  * sba_map_sg - map Scatter/Gather list
- * @dev: instance of PCI owned by the driver that's asking.
+ * @dev: instance of PCI device owned by the driver that's asking.
  * @sglist:  array of buffer/length pairs
  * @nents:  number of entries in list
  * @direction:  R/W or both.
@@ -1234,42 +1085,46 @@
 		int direction)
 {
 	struct ioc *ioc;
-	int coalesced, filled = 0;
+	int filled = 0;
 	unsigned long flags;
 #ifdef ALLOW_IOV_BYPASS
 	struct scatterlist *sg;
 #endif
 
-	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+	DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n", __FUNCTION__, nents,
+		sba_sg_address(sglist), sba_sg_len(sglist));
+
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
 #ifdef ALLOW_IOV_BYPASS
 	if (dev->dma_mask >= ioc->dma_mask) {
-		for (sg = sglist ; filled < nents ; filled++, sg++){
-			sba_sg_buffer(sg) = sba_sg_iova(sg);
-			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+		for (sg = sglist ; filled < nents ; filled++, sg++) {
+			sba_sg_iova(sg) = virt_to_phys(sba_sg_address(sg));
+			sba_sg_iova_len(sg) = sba_sg_len(sg);
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
 		ioc->msg_bypass++;
 		spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
+		DBG_RUN_SG("%s() DONE %d mappings bypassed\n", __FUNCTION__, filled);
 		return filled;
 	}
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
-		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
-						sba_sg_buffer(sglist),
-						sba_sg_len(sglist), direction);
+		sba_sg_iova(sglist) = sba_map_single(dev,
+						     (void *) sba_sg_iova(sglist),
+						     sba_sg_len(sglist), direction);
+		sba_sg_iova_len(sglist) = sba_sg_len(sglist);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
 		** be precise quickly starts wasting CPU time.
 		*/
 #endif
+		DBG_RUN_SG("%s() DONE 1 mapping\n", __FUNCTION__);
 		return 1;
 	}
 
@@ -1286,26 +1141,11 @@
 #ifdef CONFIG_PROC_FS
 	ioc->msg_calls++;
 #endif
-
-	/*
-	** First coalesce the chunks and allocate I/O pdir space
-	**
-	** If this is one DMA stream, we can properly map using the
-	** correct virtual address associated with each DMA page.
-	** w/o this association, we wouldn't have coherent DMA!
-	** Access to the virtual address is what forces a two pass algorithm.
-	*/
-	coalesced = sba_coalesce_chunks(ioc, sglist, nents);
  
 	/*
-	** Program the I/O Pdir
-	**
-	** map the virtual addresses to the I/O Pdir
-	** o dma_address will contain the pdir index
-	** o dma_len will contain the number of bytes to map 
-	** o address contains the virtual address.
+	** coalesce and program the I/O Pdir
 	*/
-	filled = sba_fill_pdir(ioc, sglist, nents);
+	filled = sba_coalesce_chunks(ioc, sglist, nents, direction);
 
 #ifdef ASSERT_PDIR_SANITY
 	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
@@ -1317,7 +1157,6 @@
 
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
-	ASSERT(coalesced == filled);
 	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
 
 	return filled;
@@ -1341,8 +1180,8 @@
 	unsigned long flags;
 #endif
 
-	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+	DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n",
+		__FUNCTION__, nents, sba_sg_address(sglist), sba_sg_len(sglist));
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1360,7 +1199,7 @@
 	while (sba_sg_len(sglist) && nents--) {
 
 		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_len(sglist), direction);
+		                 sba_sg_iova_len(sglist), direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1368,7 +1207,7 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> IOVP_SHIFT;
 #endif
 		++sglist;
 	}
@@ -1429,12 +1268,12 @@
 		__FUNCTION__, ioc->ioc_hpa, iova_space_size>>20,
 		iov_order + PAGE_SHIFT, ioc->pdir_size);
 
-	/* FIXME : DMA HINTs not used */
+	/* XXX DMA HINTs not used */
 	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
 	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
 
-	ioc->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
+	ioc->pdir_base = pdir_base =
+		(void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
 	if (NULL == pdir_base)
 	{
 		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
@@ -1452,20 +1291,8 @@
 
 	/* build IMASK for IOC and Elroy */
 	iova_space_mask =  0xffffffff;
-	iova_space_mask <<= (iov_order + PAGE_SHIFT);
+	iova_space_mask <<= (iov_order + IOVP_SHIFT);
 
-#ifdef CONFIG_IA64_HP_PROTO
-	/*
-	** REVISIT - this is a kludge, but we won't be supporting anything but
-	** zx1 2.0 or greater for real.  When fw is in shape, ibase will
-	** be preprogrammed w/ the IOVA hole base and imask will give us
-	** the size.
-	*/
-	if ((sba_dev->hw_rev & 0xFF) < 0x20) {
-		DBG_INIT("%s() Found SBA rev < 2.0, setting IOVA base to 0.  This device will not be supported in the future.\n", __FUNCTION__);
-		ioc->ibase = 0x0;
-	} else
-#endif
 	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL;
 
 	ioc->imask = iova_space_mask;	/* save it */
@@ -1474,7 +1301,7 @@
 		__FUNCTION__, ioc->ibase, ioc->imask);
 
 	/*
-	** FIXME: Hint registers are programmed with default hint
+	** XXX DMA HINT registers are programmed with default hint
 	** values during boot, so hints should be sane even if we
 	** can't reprogram them the way drivers want.
 	*/
@@ -1487,8 +1314,8 @@
 	*/
 	ioc->imask |= 0xFFFFFFFF00000000UL;
 
-	/* Set I/O PDIR Page size to system page size */
-	switch (PAGE_SHIFT) {
+	/* Set I/O Pdir page size to system page size */
+	switch (IOVP_SHIFT) {
 		case 12: /* 4K */
 			tcnfg = 0;
 			break;
@@ -1628,7 +1455,7 @@
 			sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
 
 			for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) {
-				u64 *res_ptr = sba_dev->ioc[i].res_map;
+				u64 *res_ptr = (u64 *) sba_dev->ioc[i].res_map;
 				int index = PDIR_INDEX(reserved_iov);
 				int res_word;
 				u64 mask;
@@ -1636,7 +1463,7 @@
 				res_word = (int)(index / BITS_PER_LONG);
 				mask =  0x1UL << (index - (res_word * BITS_PER_LONG));
 				res_ptr[res_word] |= mask;
-				sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (0x80000000000000FFULL | reserved_iov);
+				sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (SBA_VALID_MASK | reserved_iov);
 
 			}
 		}
@@ -1759,8 +1586,8 @@
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		if (pci_resource_flags(device, i) == IORESOURCE_MEM) {
-			hpa = ioremap(pci_resource_start(device, i),
-				pci_resource_len(device, i));
+			hpa = (u64) ioremap(pci_resource_start(device, i),
+					    pci_resource_len(device, i));
 			break;
 		}
 	}
@@ -1768,7 +1595,7 @@
 	func_id = READ_REG(hpa + SBA_FUNC_ID);
 
 	if (func_id == ZX1_FUNC_ID_VALUE) {
-		(void)strcpy(sba_rev, "zx1");
+		strcpy(sba_rev, "zx1");
 		func_offset = zx1_func_offsets;
 	} else {
 		return;
diff -Nru a/arch/ia64/hp/sim/Config.in b/arch/ia64/hp/sim/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/Config.in	Tue Aug 27 12:27:59 2002
@@ -0,0 +1,9 @@
+mainmenu_option next_comment
+comment 'HP Simulator drivers'
+
+bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
+if [ "$CONFIG_SCSI" != "n" ]; then
+  bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
+fi
+endmenu
diff -Nru a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c
--- a/arch/ia64/hp/sim/hpsim_console.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/hp/sim/hpsim_console.c	Tue Aug 27 12:28:02 2002
@@ -30,12 +30,12 @@
 static kdev_t simcons_console_device (struct console *);
 
 struct console hpsim_cons = {
-	name:		"simcons",
-	write:		simcons_write,
-	device:		simcons_console_device,
-	setup:		simcons_init,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name =		"simcons",
+	.write =	simcons_write,
+	.device =	simcons_console_device,
+	.setup =	simcons_init,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
 };
 
 static int
diff -Nru a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c
--- a/arch/ia64/hp/sim/hpsim_irq.c	Tue Aug 27 12:28:06 2002
+++ b/arch/ia64/hp/sim/hpsim_irq.c	Tue Aug 27 12:28:06 2002
@@ -22,14 +22,14 @@
 }
 
 static struct hw_interrupt_type irq_type_hp_sim = {
-	typename:	"hpsim",
-	startup:	hpsim_irq_startup,
-	shutdown:	hpsim_irq_noop,
-	enable:		hpsim_irq_noop,
-	disable:	hpsim_irq_noop,
-	ack:		hpsim_irq_noop,
-	end:		hpsim_irq_noop,
-	set_affinity:	(void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
+	.typename =	"hpsim",
+	.startup =	hpsim_irq_startup,
+	.shutdown =	hpsim_irq_noop,
+	.enable =	hpsim_irq_noop,
+	.disable =	hpsim_irq_noop,
+	.ack =		hpsim_irq_noop,
+	.end =		hpsim_irq_noop,
+	.set_affinity =	(void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
 };
 
 void __init
diff -Nru a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c
--- a/arch/ia64/hp/sim/hpsim_setup.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ia64/hp/sim/hpsim_setup.c	Tue Aug 27 12:28:07 2002
@@ -1,18 +1,19 @@
 /*
  * Platform dependent support for HP simulator.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
  */
+#include <linux/console.h>
 #include <linux/init.h>
+#include <linux/kdev_t.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 #include <linux/param.h>
+#include <linux/root_dev.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/console.h>
-#include <linux/root_dev.h>
 
 #include <asm/delay.h>
 #include <asm/irq.h>
@@ -55,5 +56,5 @@
 {
 	ROOT_DEV = Root_SDA1;		/* default to first SCSI drive */
 
-	register_console (&hpsim_cons);
+	register_console(&hpsim_cons);
 }
diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
--- a/arch/ia64/hp/sim/simscsi.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/hp/sim/simscsi.c	Tue Aug 27 12:28:05 2002
@@ -62,7 +62,9 @@
 
 extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
 
-static int desc[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+static int desc[16] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
 
 static struct queue_entry {
 	Scsi_Cmnd *sc;
@@ -148,9 +150,9 @@
 {
 	int size = disk->capacity;
 
-	ip[0] = 64;
-	ip[1] = 32;
-	ip[2] = size >> 11;
+	ip[0] = 64;		/* heads */
+	ip[1] = 32;		/* sectors */
+	ip[2] = size >> 11;	/* cylinders */
 	return 0;
 }
 
@@ -229,6 +231,29 @@
 		simscsi_readwrite(sc, mode, offset, sc->cmnd[4]*512);
 }
 
+static size_t
+simscsi_get_disk_size (int fd)
+{
+	struct disk_stat stat;
+	size_t bit, sectors = 0;
+	struct disk_req req;
+	char buf[512];
+
+	/*
+	 * This is a bit kludgey: the simulator doesn't provide a direct way of determining
+	 * the disk size, so we do a binary search, assuming a maximum disk size of 4GB.
+	 */
+	for (bit = (4UL << 30)/512; bit != 0; bit >>= 1) {
+		req.addr = __pa(&buf);
+		req.len = sizeof(buf);
+		ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ);
+		stat.fd = fd;
+		ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION);
+		if (stat.count == sizeof(buf))
+			sectors |= bit;
+	}
+	return sectors - 1;	/* return last valid sector number */
+}
 
 static void
 simscsi_readwrite10 (Scsi_Cmnd *sc, int mode)
@@ -247,6 +272,7 @@
 simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
 {
 	char fname[MAX_ROOT_LEN+16];
+	size_t disk_size;
 	char *buf;
 #if DEBUG_SIMSCSI
 	register long sp asm ("sp");
@@ -258,15 +284,15 @@
 
 	sc->result = DID_BAD_TARGET << 16;
 	sc->scsi_done = done;
-	if (sc->target <= 7 && sc->lun == 0) {
+	if (sc->target <= 15 && sc->lun == 0) {
 		switch (sc->cmnd[0]) {
 		      case INQUIRY:
 			if (sc->request_bufflen < 35) {
 				break;
 			}
 			sprintf (fname, "%s%c", simscsi_root, 'a' + sc->target);
-			desc[sc->target] = ia64_ssc (__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
-						     0, 0, SSC_OPEN);
+			desc[sc->target] = ia64_ssc(__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
+						    0, 0, SSC_OPEN);
 			if (desc[sc->target] < 0) {
 				/* disk doesn't exist... */
 				break;
@@ -319,11 +345,13 @@
 			}
 			buf = sc->request_buffer;
 
+			disk_size = simscsi_get_disk_size(desc[sc->target]);
+
 			/* pretend to be a 1GB disk (partition table contains real stuff): */
-			buf[0] = 0x00;
-			buf[1] = 0x1f;
-			buf[2] = 0xff;
-			buf[3] = 0xff;
+			buf[0] = (disk_size >> 24) & 0xff;
+			buf[1] = (disk_size >> 16) & 0xff;
+			buf[2] = (disk_size >>  8) & 0xff;
+			buf[3] = (disk_size >>  0) & 0xff;
 			/* set block size of 512 bytes: */
 			buf[4] = 0;
 			buf[5] = 0;
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/hp/sim/simserial.c	Tue Aug 27 12:28:05 2002
@@ -13,6 +13,7 @@
  *
  * 02/04/00 D. Mosberger	Merged in serial.c bug fixes in rs_close().
  * 02/25/00 D. Mosberger	Synced up with 2.3.99pre-5 version of serial.c.
+ * 07/30/02 D. Mosberger	Replace sti()/cli() with explicit spinlocks & local irq masking
  */
 
 #include <linux/config.h>
@@ -31,6 +32,7 @@
 #include <linux/serialP.h>
 
 #include <asm/irq.h>
+#include <asm/hw_irq.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_KDB
@@ -61,6 +63,7 @@
 
 static char *serial_name = "SimSerial driver";
 static char *serial_version = "0.6";
+static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * This has been extracted from asm/serial.h. We need one eventually but
@@ -232,14 +235,14 @@
 
 	if (!tty || !info->xmit.buf) return;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&serial_lock, flags);
 	if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&serial_lock, flags);
 		return;
 	}
 	info->xmit.buf[info->xmit.head] = ch;
 	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 }
 
 static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -247,7 +250,7 @@
 	int count;
 	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&serial_lock, flags);
 
 	if (info->x_char) {
 		char c = info->x_char;
@@ -290,7 +293,7 @@
 		info->xmit.tail += count;
 	}
 out:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 }
 
 static void rs_flush_chars(struct tty_struct *tty)
@@ -314,7 +317,6 @@
 
 	if (!tty || !info->xmit.buf || !tmp_buf) return 0;
 
-	save_flags(flags);
 	if (from_user) {
 		down(&tmp_buf_sem);
 		while (1) {
@@ -331,21 +333,26 @@
 					ret = -EFAULT;
 				break;
 			}
-			cli();
-			c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-			if (c1 < c)
-				c = c1;
-			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
-			info->xmit.head = ((info->xmit.head + c) &
-					   (SERIAL_XMIT_SIZE-1));
-			restore_flags(flags);
+
+			spin_lock_irqsave(&serial_lock, flags);
+			{
+				c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail,
+						       SERIAL_XMIT_SIZE);
+				if (c1 < c)
+					c = c1;
+				memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+				info->xmit.head = ((info->xmit.head + c) &
+						   (SERIAL_XMIT_SIZE-1));
+			}
+			spin_unlock_irqrestore(&serial_lock, flags);
+
 			buf += c;
 			count -= c;
 			ret += c;
 		}
 		up(&tmp_buf_sem);
 	} else {
-		cli();
+		spin_lock_irqsave(&serial_lock, flags);
 		while (1) {
 			c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 			if (count < c)
@@ -360,7 +367,7 @@
 			count -= c;
 			ret += c;
 		}
-		restore_flags(flags);
+		spin_unlock_irqrestore(&serial_lock, flags);
 	}
 	/*
 	 * Hey, we transmit directly from here in our case
@@ -391,9 +398,9 @@
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&serial_lock, flags);
 	info->xmit.head = info->xmit.tail = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 
 	wake_up_interruptible(&tty->write_wait);
 
@@ -566,44 +573,45 @@
 	       state->irq);
 #endif
 
-	save_flags(flags); cli(); /* Disable interrupts */
-
-	/*
-	 * First unlink the serial port from the IRQ chain...
-	 */
-	if (info->next_port)
-		info->next_port->prev_port = info->prev_port;
-	if (info->prev_port)
-		info->prev_port->next_port = info->next_port;
-	else
-		IRQ_ports[state->irq] = info->next_port;
+	spin_lock_irqsave(&serial_lock, flags);
+	{
+		/*
+		 * First unlink the serial port from the IRQ chain...
+		 */
+		if (info->next_port)
+			info->next_port->prev_port = info->prev_port;
+		if (info->prev_port)
+			info->prev_port->next_port = info->next_port;
+		else
+			IRQ_ports[state->irq] = info->next_port;
 
-	/*
-	 * Free the IRQ, if necessary
-	 */
-	if (state->irq && (!IRQ_ports[state->irq] ||
-			  !IRQ_ports[state->irq]->next_port)) {
-		if (IRQ_ports[state->irq]) {
-			free_irq(state->irq, NULL);
-			retval = request_irq(state->irq, rs_interrupt_single,
-					     IRQ_T(info), "serial", NULL);
-
-			if (retval)
-				printk("serial shutdown: request_irq: error %d"
-				       "  Couldn't reacquire IRQ.\n", retval);
-		} else
-			free_irq(state->irq, NULL);
-	}
+		/*
+		 * Free the IRQ, if necessary
+		 */
+		if (state->irq && (!IRQ_ports[state->irq] ||
+				   !IRQ_ports[state->irq]->next_port)) {
+			if (IRQ_ports[state->irq]) {
+				free_irq(state->irq, NULL);
+				retval = request_irq(state->irq, rs_interrupt_single,
+						     IRQ_T(info), "serial", NULL);
+
+				if (retval)
+					printk("serial shutdown: request_irq: error %d"
+					       "  Couldn't reacquire IRQ.\n", retval);
+			} else
+				free_irq(state->irq, NULL);
+		}
 
-	if (info->xmit.buf) {
-		free_page((unsigned long) info->xmit.buf);
-		info->xmit.buf = 0;
-	}
+		if (info->xmit.buf) {
+			free_page((unsigned long) info->xmit.buf);
+			info->xmit.buf = 0;
+		}
 
-	if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
+		info->flags &= ~ASYNC_INITIALIZED;
+	}
+	spin_unlock_irqrestore(&serial_lock, flags);
 }
 
 /*
@@ -626,14 +634,13 @@
 
 	state = info->state;
 
-	save_flags(flags); cli();
-
+	spin_lock_irqsave(&serial_lock, flags);
 	if (tty_hung_up_p(filp)) {
 #ifdef SIMSERIAL_DEBUG
 		printk("rs_close: hung_up\n");
 #endif
 		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&serial_lock, flags);
 		return;
 	}
 #ifdef SIMSERIAL_DEBUG
@@ -658,11 +665,11 @@
 	}
 	if (state->count) {
 		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&serial_lock, flags);
 		return;
 	}
 	info->flags |= ASYNC_CLOSING;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
@@ -770,7 +777,7 @@
 	if (!page)
 		return -ENOMEM;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&serial_lock, flags);
 
 	if (info->flags & ASYNC_INITIALIZED) {
 		free_page(page);
@@ -851,11 +858,11 @@
 	}
 
 	info->flags |= ASYNC_INITIALIZED;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 	return 0;
 
 errout:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&serial_lock, flags);
 	return retval;
 }
 
diff -Nru a/arch/ia64/hp/zx1/hpzx1_machvec.c b/arch/ia64/hp/zx1/hpzx1_machvec.c
--- a/arch/ia64/hp/zx1/hpzx1_machvec.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/hp/zx1/hpzx1_machvec.c	Tue Aug 27 12:28:02 2002
@@ -1,4 +1,2 @@
 #define MACHVEC_PLATFORM_NAME	hpzx1
 #include <asm/machvec_init.h>
-#define MACHVEC_PLATFORM_NAME	hpzx1
-#include <asm/machvec_init.h>
diff -Nru a/arch/ia64/hp/zx1/hpzx1_misc.c b/arch/ia64/hp/zx1/hpzx1_misc.c
--- a/arch/ia64/hp/zx1/hpzx1_misc.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/hp/zx1/hpzx1_misc.c	Tue Aug 27 12:28:05 2002
@@ -12,111 +12,65 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#include <asm/iosapic.h>
+
+#include <asm/dma.h>
 #include <asm/efi.h>
+#include <asm/iosapic.h>
 
-#include "../drivers/acpi/include/platform/acgcc.h"
-#include "../drivers/acpi/include/actypes.h"
-#include "../drivers/acpi/include/acexcep.h"
-#include "../drivers/acpi/include/acpixf.h"
-#include "../drivers/acpi/include/actbl.h"
-#include "../drivers/acpi/include/acconfig.h"
-#include "../drivers/acpi/include/acmacros.h"
-#include "../drivers/acpi/include/aclocal.h"
-#include "../drivers/acpi/include/acobject.h"
-#include "../drivers/acpi/include/acstruct.h"
-#include "../drivers/acpi/include/acnamesp.h"
-#include "../drivers/acpi/include/acutils.h"
+extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *,
+					  unsigned long *);
 
 #define PFX "hpzx1: "
 
+static int hpzx1_devices;
+
 struct fake_pci_dev {
-	struct fake_pci_dev *next;
-	unsigned char bus;
-	unsigned int devfn;
-	int sizing;		// in middle of BAR sizing operation?
 	unsigned long csr_base;
-	unsigned int csr_size;
+	unsigned long csr_size;
 	unsigned long mapped_csrs;	// ioremapped
+	int sizing;			// in middle of BAR sizing operation?
 };
 
-static struct fake_pci_dev *fake_pci_head, **fake_pci_tail = &fake_pci_head;
-
 static struct pci_ops *orig_pci_ops;
 
-static inline struct fake_pci_dev *
-fake_pci_find_slot(unsigned char bus, unsigned int devfn)
-{
-	struct fake_pci_dev *dev;
-
-	for (dev = fake_pci_head; dev; dev = dev->next)
-		if (dev->bus == bus && dev->devfn == devfn)
-			return dev;
-	return NULL;
+#define HP_CFG_RD(sz, bits, name)						\
+static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value)	\
+{										\
+	struct fake_pci_dev *fake_dev;						\
+	if (!(fake_dev = (struct fake_pci_dev *) dev->sysdata))			\
+		return orig_pci_ops->name(dev, where, value);			\
+										\
+	if (where == PCI_BASE_ADDRESS_0) {					\
+		if (fake_dev->sizing)						\
+			*value = ~(fake_dev->csr_size - 1);			\
+		else								\
+			*value = (fake_dev->csr_base &				\
+				    PCI_BASE_ADDRESS_MEM_MASK) |		\
+				PCI_BASE_ADDRESS_SPACE_MEMORY;			\
+		fake_dev->sizing = 0;						\
+		return PCIBIOS_SUCCESSFUL;					\
+	}									\
+	*value = read##sz(fake_dev->mapped_csrs + where);			\
+	if (where == PCI_COMMAND)						\
+		*value |= PCI_COMMAND_MEMORY; /* SBA omits this */		\
+	return PCIBIOS_SUCCESSFUL;						\
 }
 
-static struct fake_pci_dev *
-alloc_fake_pci_dev(void)
-{
-        struct fake_pci_dev *dev;
-
-        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return NULL;
-
-	memset(dev, 0, sizeof(*dev));
-
-        *fake_pci_tail = dev;
-        fake_pci_tail = &dev->next;
-
-        return dev;
-}
-
-#define HP_CFG_RD(sz, bits, name) \
-static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value) \
-{ \
-	struct fake_pci_dev *fake_dev; \
-	if (!(fake_dev = fake_pci_find_slot(dev->bus->number, dev->devfn))) \
-		return orig_pci_ops->name(dev, where, value); \
-	\
-	switch (where) { \
-	case PCI_COMMAND: \
-		*value = read##sz(fake_dev->mapped_csrs + where); \
-		*value |= PCI_COMMAND_MEMORY; /* SBA omits this */ \
-		break; \
-	case PCI_BASE_ADDRESS_0: \
-		if (fake_dev->sizing) \
-			*value = ~(fake_dev->csr_size - 1); \
-		else \
-			*value = (fake_dev->csr_base & \
-				    PCI_BASE_ADDRESS_MEM_MASK) | \
-				PCI_BASE_ADDRESS_SPACE_MEMORY; \
-		fake_dev->sizing = 0; \
-		break; \
-	default: \
-		*value = read##sz(fake_dev->mapped_csrs + where); \
-		break; \
-	} \
-	return PCIBIOS_SUCCESSFUL; \
-}
-
-#define HP_CFG_WR(sz, bits, name) \
-static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value) \
-{ \
-	struct fake_pci_dev *fake_dev; \
-	if (!(fake_dev = fake_pci_find_slot(dev->bus->number, dev->devfn))) \
-		return orig_pci_ops->name(dev, where, value); \
-	\
-	switch (where) { \
-	case PCI_BASE_ADDRESS_0: \
-		if (value == ~0) \
-			fake_dev->sizing = 1; \
-		break; \
-	default: \
-		write##sz(value, fake_dev->mapped_csrs + where); \
-		break; \
-	} \
-	return PCIBIOS_SUCCESSFUL; \
+#define HP_CFG_WR(sz, bits, name)						\
+static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value)	\
+{										\
+	struct fake_pci_dev *fake_dev;						\
+										\
+	if (!(fake_dev = (struct fake_pci_dev *) dev->sysdata))			\
+		return orig_pci_ops->name(dev, where, value);			\
+										\
+	if (where == PCI_BASE_ADDRESS_0) {					\
+		if (value == (u##bits) ~0)					\
+			fake_dev->sizing = 1;					\
+		return PCIBIOS_SUCCESSFUL;					\
+	} else									\
+		write##sz(value, fake_dev->mapped_csrs + where);		\
+	return PCIBIOS_SUCCESSFUL;						\
 }
 
 HP_CFG_RD(b,  8, read_byte)
@@ -135,51 +89,86 @@
 	hp_cfg_writel,
 };
 
-/*
- * Assume we'll never have a physical slot higher than 0x10, so we can
- * use slots above that for "fake" PCI devices to represent things
- * that only show up in the ACPI namespace.
- */
-#define HP_MAX_SLOT	0x10
-
-static struct fake_pci_dev *
-hpzx1_fake_pci_dev(unsigned long addr, unsigned int bus, unsigned int size)
+static void
+hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size)
 {
-	struct fake_pci_dev *dev;
-	int slot;
+	struct fake_pci_dev *fake;
+	int slot, ret;
+	struct pci_dev *dev;
+	struct pci_bus *b, *bus = NULL;
+	u8 hdr;
+
+        fake = kmalloc(sizeof(*fake), GFP_KERNEL);
+	if (!fake) {
+		printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name, (void *) addr);
+		return;
+	}
 
-	// Note: lspci thinks 0x1f is invalid
-	for (slot = 0x1e; slot > HP_MAX_SLOT; slot--) {
-		if (!fake_pci_find_slot(bus, PCI_DEVFN(slot, 0)))
+	memset(fake, 0, sizeof(*fake));
+	fake->csr_base = addr;
+	fake->csr_size = size;
+	fake->mapped_csrs = (unsigned long) ioremap(addr, size);
+	fake->sizing = 0;
+
+	pci_for_each_bus(b)
+		if (busnum == b->number) {
+			bus = b;
 			break;
+		}
+
+	if (!bus) {
+		printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)\n",
+		       busnum, name, (void *) addr);
+		kfree(fake);
+		return;
 	}
-	if (slot == HP_MAX_SLOT) {
-		printk(KERN_ERR PFX
-			"no slot space for device (0x%p) on bus 0x%02x\n",
-			(void *) addr, bus);
-		return NULL;
+
+	for (slot = 0x1e; slot; slot--)
+		if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0)))
+			break;
+
+	if (slot < 0) {
+		printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02x\n",
+		       name, (void *) addr, busnum);
+		kfree(fake);
+		return;
 	}
 
-	dev = alloc_fake_pci_dev();
+        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
-		printk(KERN_ERR PFX
-			"no memory for device (0x%p) on bus 0x%02x\n",
-			(void *) addr, bus);
-		return NULL;
+		printk(KERN_ERR PFX "No memory for %s (0x%p)\n", name, (void *) addr);
+		kfree(fake);
+		return;
 	}
 
+	bus->ops = &hp_pci_conf;	// replace pci ops for this bus
+
+	memset(dev, 0, sizeof(*dev));
 	dev->bus = bus;
+	dev->sysdata = fake;
+	dev->dev.parent = bus->dev;
+	dev->dev.bus = &pci_bus_type;
 	dev->devfn = PCI_DEVFN(slot, 0);
-	dev->csr_base = addr;
-	dev->csr_size = size;
+	pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
+	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr);
+	dev->hdr_type = hdr & 0x7f;
+
+	pci_setup_device(dev);
+
+	// pci_insert_device() without running /sbin/hotplug
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+
+	strcpy(dev->dev.name, dev->name);
+	strcpy(dev->dev.bus_id, dev->slot_name);
+	ret = device_register(&dev->dev);
+	if (ret < 0)
+		printk(KERN_INFO PFX "fake device registration failed (%d)\n", ret);
 
-	/*
-	 * Drivers should ioremap what they need, but we have to do
-	 * it here, too, so PCI config accesses work.
-	 */
-	dev->mapped_csrs = ioremap(dev->csr_base, dev->csr_size);
+	printk(KERN_INFO PFX "%s at 0x%lx; pci dev %s\n", name, addr, dev->slot_name);
 
-	return dev;
+	hpzx1_devices++;
 }
 
 typedef struct {
@@ -189,10 +178,10 @@
 	u8	csr_length[8];
 } acpi_hp_vendor_long;
 
-#define HP_CCSR_LENGTH 0x21
-#define HP_CCSR_TYPE 0x2
-#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f,			\
-			      0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
+#define HP_CCSR_LENGTH	0x21
+#define HP_CCSR_TYPE	0x2
+#define HP_CCSR_GUID	EFI_GUID(0x69e9adf9, 0x924f, 0xab5f,				\
+				 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
 
 extern acpi_status acpi_get_crs(acpi_handle, acpi_buffer *);
 extern acpi_resource *acpi_get_crs_next(acpi_buffer *, int *);
@@ -213,7 +202,7 @@
 	*csr_length = 0;
 
 	status = acpi_get_crs(obj, &buf);
-	if (status != AE_OK) {
+	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PFX "Unable to get _CRS data on object\n");
 		return status;
 	}
@@ -254,13 +243,12 @@
 hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
 {
 	u64 csr_base = 0, csr_length = 0;
-	char *name = context;
-	struct fake_pci_dev *dev;
 	acpi_status status;
+	char *name = context;
+	char fullname[16];
 
 	status = hp_csr_space(obj, &csr_base, &csr_length);
-
-	if (status != AE_OK)
+	if (ACPI_FAILURE(status))
 		return status;
 
 	/*
@@ -268,14 +256,10 @@
 	 * includes both SBA and IOC.  Make SBA and IOC show up
 	 * separately in PCI space.
 	 */
-	if ((dev = hpzx1_fake_pci_dev(csr_base, 0, 0x1000)))
-		printk(KERN_INFO PFX "%s SBA at 0x%lx; pci dev %02x:%02x.%d\n",
-			name, csr_base, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	if ((dev = hpzx1_fake_pci_dev(csr_base + 0x1000, 0, 0x1000)))
-		printk(KERN_INFO PFX "%s IOC at 0x%lx; pci dev %02x:%02x.%d\n",
-			name, csr_base + 0x1000, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	sprintf(fullname, "%s SBA", name);
+	hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000);
+	sprintf(fullname, "%s IOC", name);
+	hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000);
 
 	return AE_OK;
 }
@@ -283,28 +267,24 @@
 static acpi_status
 hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
 {
-	acpi_status status;
 	u64 csr_base = 0, csr_length = 0;
+	acpi_status status;
+	NATIVE_UINT busnum;
 	char *name = context;
-	NATIVE_UINT busnum = 0;
-	struct fake_pci_dev *dev;
+	char fullname[32];
 
 	status = hp_csr_space(obj, &csr_base, &csr_length);
-
-	if (status != AE_OK)
+	if (ACPI_FAILURE(status))
 		return status;
 
 	status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PFX "evaluate _BBN fail=0x%x\n", status);
+		printk(KERN_WARNING PFX "evaluate _BBN fail=0x%x\n", status);
 		busnum = 0;	// no _BBN; stick it on bus 0
 	}
 
-	if ((dev = hpzx1_fake_pci_dev(csr_base, busnum, csr_length)))
-		printk(KERN_INFO PFX "%s LBA at 0x%lx, _BBN 0x%02x; "
-			"pci dev %02x:%02x.%d\n",
-			name, csr_base, busnum, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum);
+	hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length);
 
 	return AE_OK;
 }
@@ -314,6 +294,8 @@
 {
 	extern struct pci_ops *pci_root_ops;
 
+	orig_pci_ops = pci_root_ops;
+
 	/*
 	 * Make fake PCI devices for the following hardware in the
 	 * ACPI namespace.  This makes it more convenient for drivers
@@ -328,10 +310,10 @@
 	 */
 	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
 #ifdef CONFIG_IA64_HP_PROTO
-	if (fake_pci_tail != &fake_pci_head) {
+	if (hpzx1_devices) {
 #endif
-	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002", NULL);
-	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003", NULL);
+	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
+	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
 
 #ifdef CONFIG_IA64_HP_PROTO
 	}
@@ -342,48 +324,25 @@
 	 * if we didn't find anything, add the things we know are
 	 * there.
 	 */
-	if (fake_pci_tail == &fake_pci_head) {
+	if (hpzx1_devices == 0) {
 		u64 hpa, csr_base;
-		struct fake_pci_dev *dev;
 
 		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x1000);
+		hpa = (u64) ioremap(csr_base, 0x2000);
 		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			if ((dev = hpzx1_fake_pci_dev(csr_base, 0, 0x1000)))
-				printk(KERN_INFO PFX "HWP0001 SBA at 0x%lx; "
-					"pci dev %02x:%02x.%d\n", csr_base,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
-			if ((dev = hpzx1_fake_pci_dev(csr_base + 0x1000, 0,
-					0x1000)))
-				printk(KERN_INFO PFX "HWP0001 IOC at 0x%lx; "
-					"pci dev %02x:%02x.%d\n",
-					csr_base + 0x1000,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
+			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
+			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
+					    0x1000);
 
 			csr_base = 0xfed24000UL;
 			iounmap(hpa);
 			hpa = (u64) ioremap(csr_base, 0x1000);
-			if ((dev = hpzx1_fake_pci_dev(csr_base, 0x40, 0x1000)))
-				printk(KERN_INFO PFX "HWP0003 AGP LBA at "
-					"0x%lx; pci dev %02x:%02x.%d\n",
-					csr_base,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
+			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
+					    0x1000);
 		}
 		iounmap(hpa);
 	}
 #endif
-
-	if (fake_pci_tail == &fake_pci_head)
-		return;
-
-	/*
-	 * Replace PCI ops, but only if we made fake devices.
-	 */
-	orig_pci_ops = pci_root_ops;
-	pci_root_ops = &hp_pci_conf;
 }
 
 extern void sba_init(void);
@@ -391,9 +350,16 @@
 void
 hpzx1_pci_fixup (int phase)
 {
-	if (phase == 0)
-		hpzx1_acpi_dev_init();
 	iosapic_pci_fixup(phase);
-        if (phase == 1)
+	switch (phase) {
+	      case 0:
+		/* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
+		MAX_DMA_ADDRESS = ~0UL;
+		break;
+
+	      case 1:
+		hpzx1_acpi_dev_init();
 		sba_init();
+		break;
+	}
 }
diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
--- a/arch/ia64/ia32/binfmt_elf32.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/ia32/binfmt_elf32.c	Tue Aug 27 12:28:08 2002
@@ -67,7 +67,7 @@
 }
 
 static struct vm_operations_struct ia32_shared_page_vm_ops = {
-	nopage:	ia32_install_shared_page
+	.nopage =ia32_install_shared_page
 };
 
 void
diff -Nru a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c
--- a/arch/ia64/ia32/ia32_ioctl.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/ia32/ia32_ioctl.c	Tue Aug 27 12:28:08 2002
@@ -30,6 +30,8 @@
 #include <asm/ia32.h>
 
 #include <../drivers/char/drm/drm.h>
+#include <../drivers/char/drm/mga_drm.h>
+#include <../drivers/char/drm/i810_drm.h>
 
 
 #define IOCTL_NR(a)	((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/acpi.c	Tue Aug 27 12:28:05 2002
@@ -56,16 +56,19 @@
 void (*pm_idle) (void);
 void (*pm_power_off) (void);
 
+unsigned char acpi_kbd_controller_present = 1;
+
 const char *
 acpi_get_sysname (void)
 {
 #ifdef CONFIG_IA64_GENERIC
-	unsigned long rsdp_phys = 0;
+	unsigned long rsdp_phys;
 	struct acpi20_table_rsdp *rsdp;
 	struct acpi_table_xsdt *xsdt;
 	struct acpi_table_header *hdr;
 
-	if ((0 != acpi_find_rsdp(&rsdp_phys)) || !rsdp_phys) {
+	rsdp_phys = acpi_find_rsdp();
+	if (!rsdp_phys) {
 		printk("ACPI 2.0 RSDP not found, default to \"dig\"\n");
 		return "dig";
 	}
@@ -99,6 +102,8 @@
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
+# elif defined (CONFIG_IA64_HP_ZX1)
+	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
@@ -130,9 +135,7 @@
 	if (!buf->pointer)
 		return -ENOMEM;
 
-	result = acpi_get_current_resources(obj, buf);
-
-	return result;
+	return acpi_get_current_resources(obj, buf);
 }
 
 acpi_resource *
@@ -175,6 +178,8 @@
 /* Array to record platform interrupt vectors for generic interrupt routing. */
 int platform_irq_list[ACPI_MAX_PLATFORM_IRQS] = { [0 ... ACPI_MAX_PLATFORM_IRQS - 1] = -1 };
 
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC;
+
 /*
  * Interrupt routing API for device drivers.  Provides interrupt vector for
  * a generic platform event.  Currently only CPEI is implemented.
@@ -189,10 +194,14 @@
 		vector = platform_irq_list[int_type];
 	} else
 		printk("acpi_request_vector(): invalid interrupt type\n");
-
 	return vector;
 }
 
+char *
+__acpi_map_table (unsigned long phys_addr, unsigned long size)
+{
+	return __va(phys_addr);
+}
 
 /* --------------------------------------------------------------------------
                             Boot-time Table Parsing
@@ -206,7 +215,7 @@
 static int __init
 acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header)
 {
-	struct acpi_table_lapic_addr_ovr *lapic = NULL;
+	struct acpi_table_lapic_addr_ovr *lapic;
 
 	lapic = (struct acpi_table_lapic_addr_ovr *) header;
 	if (!lapic)
@@ -218,7 +227,6 @@
 		iounmap((void *) ipi_base_addr);
 		ipi_base_addr = (unsigned long) ioremap(lapic->address, 0);
 	}
-
 	return 0;
 }
 
@@ -226,7 +234,7 @@
 static int __init
 acpi_parse_lsapic (acpi_table_entry_header *header)
 {
-	struct acpi_table_lsapic *lsapic = NULL;
+	struct acpi_table_lsapic *lsapic;
 
 	lsapic = (struct acpi_table_lsapic *) header;
 	if (!lsapic)
@@ -262,7 +270,7 @@
 static int __init
 acpi_parse_lapic_nmi (acpi_table_entry_header *header)
 {
-	struct acpi_table_lapic_nmi *lacpi_nmi = NULL;
+	struct acpi_table_lapic_nmi *lacpi_nmi;
 
 	lacpi_nmi = (struct acpi_table_lapic_nmi*) header;
 	if (!lacpi_nmi)
@@ -271,7 +279,6 @@
 	acpi_table_print_madt_entry(header);
 
 	/* TBD: Support lapic_nmi entries */
-
 	return 0;
 }
 
@@ -279,11 +286,11 @@
 static int __init
 acpi_find_iosapic (int global_vector, u32 *irq_base, char **iosapic_address)
 {
-	struct acpi_table_iosapic *iosapic = NULL;
-	int ver = 0;
-	int max_pin = 0;
-	char *p = 0;
-	char *end = 0;
+	struct acpi_table_iosapic *iosapic;
+	int ver;
+	int max_pin;
+	char *p;
+	char *end;
 
 	if (!irq_base || !iosapic_address)
 		return -ENODEV;
@@ -338,10 +345,10 @@
 static int __init
 acpi_parse_plat_int_src (acpi_table_entry_header *header)
 {
-	struct acpi_table_plat_int_src *plintsrc = NULL;
-	int vector = 0;
-	u32 irq_base = 0;
-	char *iosapic_address = NULL;
+	struct acpi_table_plat_int_src *plintsrc;
+	int vector;
+	u32 irq_base;
+	char *iosapic_address;
 
 	plintsrc = (struct acpi_table_plat_int_src *) header;
 	if (!plintsrc)
@@ -354,7 +361,7 @@
 		return -ENODEV;
 	}
 
-	if (0 != acpi_find_iosapic(plintsrc->global_irq, &irq_base, &iosapic_address)) {
+	if (acpi_find_iosapic(plintsrc->global_irq, &irq_base, &iosapic_address)) {
 		printk(KERN_WARNING PREFIX "IOSAPIC not found\n");
 		return -ENODEV;
 	}
@@ -363,15 +370,15 @@
 	 * Get vector assignment for this IRQ, set attributes, and program the
 	 * IOSAPIC routing table.
 	 */
-	vector = iosapic_register_platform_irq (plintsrc->type,
-						plintsrc->global_irq,
-						plintsrc->iosapic_vector,
-						plintsrc->eid,
-						plintsrc->id,
-						(plintsrc->flags.polarity == 1) ? 1 : 0,
-						(plintsrc->flags.trigger == 1) ? 1 : 0,
-						irq_base,
-						iosapic_address);
+	vector = iosapic_register_platform_irq(plintsrc->type,
+					       plintsrc->global_irq,
+					       plintsrc->iosapic_vector,
+					       plintsrc->eid,
+					       plintsrc->id,
+					       (plintsrc->flags.polarity == 1) ? 1 : 0,
+					       (plintsrc->flags.trigger == 1) ? 1 : 0,
+					       irq_base,
+					       iosapic_address);
 
 	platform_irq_list[plintsrc->type] = vector;
 	return 0;
@@ -381,7 +388,7 @@
 static int __init
 acpi_parse_int_src_ovr (acpi_table_entry_header *header)
 {
-	struct acpi_table_int_src_ovr *p = NULL;
+	struct acpi_table_int_src_ovr *p;
 
 	p = (struct acpi_table_int_src_ovr *) header;
 	if (!p)
@@ -394,9 +401,8 @@
 		return 0;
 
 	iosapic_register_legacy_irq(p->bus_irq, p->global_irq,
-		(p->flags.polarity == 1) ? 1 : 0,
-		(p->flags.trigger == 1) ? 1 : 0);
-
+				    (p->flags.polarity == 1) ? 1 : 0,
+				    (p->flags.trigger == 1) ? 1 : 0);
 	return 0;
 }
 
@@ -404,7 +410,7 @@
 static int __init
 acpi_parse_nmi_src (acpi_table_entry_header *header)
 {
-	struct acpi_table_nmi_src *nmi_src = NULL;
+	struct acpi_table_nmi_src *nmi_src;
 
 	nmi_src = (struct acpi_table_nmi_src*) header;
 	if (!nmi_src)
@@ -413,7 +419,6 @@
 	acpi_table_print_madt_entry(header);
 
 	/* TBD: Support nimsrc entries */
-
 	return 0;
 }
 
@@ -425,50 +430,59 @@
 		return -EINVAL;
 
 	acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
-	if (!acpi_madt) {
-		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
-		return -ENODEV;
-	}
 
 	/* Get base address of IPI Message Block */
 
 	if (acpi_madt->lapic_address)
-		ipi_base_addr = (unsigned long)
-			ioremap(acpi_madt->lapic_address, 0);
+		ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0);
 
 	printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr);
-
 	return 0;
 }
 
-
-int __init
-acpi_find_rsdp (unsigned long *rsdp_phys)
+static int __init
+acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
 {
-	if (!rsdp_phys)
+	struct acpi_table_header *fadt_header;
+	fadt_descriptor_rev2 *fadt;
+
+	if (!phys_addr || !size)
 		return -EINVAL;
 
-	if (efi.acpi20) {
-		(*rsdp_phys) = __pa(efi.acpi20);
-		return 0;
-	}
-	else if (efi.acpi) {
-		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
-	}
+	fadt_header = (struct acpi_table_header *) __va(phys_addr);
+	if (fadt_header->revision != 3)
+		return -ENODEV;		/* Only deal with ACPI 2.0 FADT */
 
-	return -ENODEV;
+	fadt = (fadt_descriptor_rev2 *) fadt_header;
+
+	if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
+		acpi_kbd_controller_present = 0;
+
+	return 0;
+}
+
+unsigned long __init
+acpi_find_rsdp (void)
+{
+	unsigned long rsdp_phys = 0;
+
+	if (efi.acpi20)
+		rsdp_phys = __pa(efi.acpi20);
+	else if (efi.acpi)
+		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
+	return rsdp_phys;
 }
 
 
-#ifdef CONFIG_SERIAL_ACPI
+#ifdef CONFIG_SERIAL_8250_ACPI
 
 #include <linux/acpi_serial.h>
 
 static int __init
 acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
 {
-	acpi_ser_t *spcr = NULL;
-	unsigned long global_int = 0;
+	acpi_ser_t *spcr;
+	unsigned long global_int;
 
 	if (!phys_addr || !size)
 		return -EINVAL;
@@ -486,11 +500,6 @@
 	 */
 
 	spcr = (acpi_ser_t *) __va(phys_addr);
-	if (!spcr) {
-		printk(KERN_WARNING PREFIX "Unable to map SPCR\n");
-		return -ENODEV;
-	}
-
 	setup_serial_acpi(spcr);
 
 	if (spcr->length < sizeof(acpi_ser_t))
@@ -500,38 +509,37 @@
 	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
 	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC))
 	{
-		u32 irq_base = 0;
-		char *iosapic_address = NULL;
-		int vector = 0;
+		u32 irq_base;
+		char *iosapic_address;
+		int vector;
 
 		/* We have a UART in memory space with an SAPIC interrupt */
 
-		global_int = (  (spcr->global_int[3] << 24) |
-				(spcr->global_int[2] << 16) |
-				(spcr->global_int[1] << 8)  |
-				(spcr->global_int[0])  );
+		global_int = ((spcr->global_int[3] << 24) |
+			      (spcr->global_int[2] << 16) |
+			      (spcr->global_int[1] << 8)  |
+			      (spcr->global_int[0])  );
 
 		/* Which iosapic does this IRQ belong to? */
 
-		if (0 == acpi_find_iosapic(global_int, &irq_base, &iosapic_address)) {
-			vector = iosapic_register_irq (global_int, 1, 1,
-						       irq_base, iosapic_address);
-		}
+		if (!acpi_find_iosapic(global_int, &irq_base, &iosapic_address))
+			vector = iosapic_register_irq(global_int, 1, 1,
+						      irq_base, iosapic_address);
 	}
 	return 0;
 }
 
-#endif /*CONFIG_SERIAL_ACPI*/
+#endif /* CONFIG_SERIAL_8250_ACPI */
 
 
 int __init
 acpi_boot_init (char *cmdline)
 {
-	int result = 0;
+	int result;
 
 	/* Initialize the ACPI boot-time table parser */
 	result = acpi_table_init(cmdline);
-	if (0 != result)
+	if (result)
 		return result;
 
 	/*
@@ -542,59 +550,44 @@
 	 * information -- the successor to MPS tables.
 	 */
 
-	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
-	if (1 > result)
-		return result;
+	if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
+		printk(KERN_ERR PREFIX "Can't find MADT\n");
+		goto skip_madt;
+	}
 
 	/* Local APIC */
 
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);
-	if (0 > result) {
+	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr) < 0)
 		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
-		return result;
-	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic);
-	if (1 > result) {
-		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries!\n");
-		return -ENODEV;
-	}
+	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic) < 1)
+		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n");
 
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
-	if (0 > result) {
+	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi) < 0)
 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
-		return result;
-	}
 
 	/* I/O APIC */
 
-	result = acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic);
-	if (1 > result) {
-		printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries!\n");
-		return ((result == 0) ? -ENODEV : result);
-	}
+	if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic) < 1)
+		printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n");
 
 	/* System-Level Interrupt Routing */
 
-	result = acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src);
-	if (0 > result) {
+	if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src) < 0)
 		printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n");
-		return result;
-	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);
-	if (0 > result) {
+	if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr) < 0)
 		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
-		return result;
-	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
-	if (0 > result) {
+	if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src) < 0)
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
-		return result;
-	}
+  skip_madt:
 
-#ifdef CONFIG_SERIAL_ACPI
+	/* FADT says whether a legacy keyboard controller is present. */
+	if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1)
+		printk(KERN_ERR PREFIX "Can't find FADT\n");
+
+#ifdef CONFIG_SERIAL_8250_ACPI
 	/*
 	 * TBD: Need phased approach to table parsing (only do those absolutely
 	 *      required during boot-up).  Recommend expanding concept of fix-
@@ -602,7 +595,7 @@
 	 *      serial ports, EC, SMBus, etc.
 	 */
 	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
-#endif /*CONFIG_SERIAL_ACPI*/
+#endif
 
 #ifdef CONFIG_SMP
 	if (available_cpus == 0) {
@@ -610,10 +603,11 @@
 		available_cpus = 1; /* We've got at least one of these, no? */
 	}
 	smp_boot_data.cpu_count = total_cpus;
+
+	smp_build_cpu_map();
 #endif
 	/* Make boot-up look pretty */
 	printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
-
 	return 0;
 }
 
@@ -625,9 +619,9 @@
 int __init
 acpi_get_prt (struct pci_vector_struct **vectors, int *count)
 {
-	struct pci_vector_struct *vector = NULL;
-	struct list_head *node = NULL;
-	struct acpi_prt_entry *entry = NULL;
+	struct pci_vector_struct *vector;
+	struct list_head *node;
+	struct acpi_prt_entry *entry;
 	int i = 0;
 
 	if (!vectors || !count)
@@ -636,14 +630,14 @@
 	*vectors = NULL;
 	*count = 0;
 
-	if (acpi_prts.count <= 0) {
+	if (acpi_prt.count < 0) {
 		printk(KERN_ERR PREFIX "No PCI IRQ routing entries\n");
 		return -ENODEV;
 	}
 
 	/* Allocate vectors */
 
-	*vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prts.count, GFP_KERNEL);
+	*vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prt.count, GFP_KERNEL);
 	if (!(*vectors))
 		return -ENOMEM;
 
@@ -651,15 +645,15 @@
 
 	vector = *vectors;
 
-	list_for_each(node, &acpi_prts.entries) {
+	list_for_each(node, &acpi_prt.entries) {
 		entry = (struct acpi_prt_entry *)node;
 		vector[i].bus    = entry->id.bus;
-		vector[i].pci_id = ((u32) entry->id.dev << 16) | 0xffff;
-		vector[i].pin    = entry->id.pin;
-		vector[i].irq    = entry->source.index;
+		vector[i].pci_id = ((u32) entry->id.device << 16) | 0xffff;
+		vector[i].pin    = entry->pin;
+		vector[i].irq    = entry->link.index;
 		i++;
 	}
-	*count = acpi_prts.count;
+	*count = acpi_prt.count;
 	return 0;
 }
 
@@ -671,8 +665,7 @@
         if (!type)
                 return -EINVAL;
 
-	*type = ACPI_INT_MODEL_IOSAPIC;
-
+	*type = ACPI_IRQ_MODEL_IOSAPIC;
         return 0;
 }
 
diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
--- a/arch/ia64/kernel/efi.c	Tue Aug 27 12:27:57 2002
+++ b/arch/ia64/kernel/efi.c	Tue Aug 27 12:27:57 2002
@@ -125,9 +125,79 @@
 	tv->tv_usec = tm.nanosecond / 1000;
 }
 
+static int
+is_available_memory (efi_memory_desc_t *md)
+{
+	if (!(md->attribute & EFI_MEMORY_WB))
+		return 0;
+
+	switch (md->type) {
+	      case EFI_LOADER_CODE:
+	      case EFI_LOADER_DATA:
+	      case EFI_BOOT_SERVICES_CODE:
+	      case EFI_BOOT_SERVICES_DATA:
+	      case EFI_CONVENTIONAL_MEMORY:
+		return 1;
+	}
+	return 0;
+}
+
 /*
- * Walks the EFI memory map and calls CALLBACK once for each EFI
- * memory descriptor that has memory that is available for OS use.
+ * Trim descriptor MD so its starts at address START_ADDR.  If the descriptor covers
+ * memory that is normally available to the kernel, issue a warning that some memory
+ * is being ignored.
+ */
+static void
+trim_bottom (efi_memory_desc_t *md, u64 start_addr)
+{
+	u64 num_skipped_pages;
+
+	if (md->phys_addr >= start_addr || !md->num_pages)
+		return;
+
+	num_skipped_pages = (start_addr - md->phys_addr) >> EFI_PAGE_SHIFT;
+	if (num_skipped_pages > md->num_pages)
+		num_skipped_pages = md->num_pages;
+
+	if (is_available_memory(md))
+		printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole "
+		       "at 0x%lx\n", __FUNCTION__,
+		       (num_skipped_pages << EFI_PAGE_SHIFT) >> 10,
+		       md->phys_addr, start_addr - IA64_GRANULE_SIZE);
+	/*
+	 * NOTE: Don't set md->phys_addr to START_ADDR because that could cause the memory
+	 * descriptor list to become unsorted.  In such a case, md->num_pages will be
+	 * zero, so the Right Thing will happen.
+	 */
+	md->phys_addr += num_skipped_pages << EFI_PAGE_SHIFT;
+	md->num_pages -= num_skipped_pages;
+}
+
+static void
+trim_top (efi_memory_desc_t *md, u64 end_addr)
+{
+	u64 num_dropped_pages, md_end_addr;
+
+	md_end_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+	if (md_end_addr <= end_addr || !md->num_pages)
+		return;
+
+	num_dropped_pages = (md_end_addr - end_addr) >> EFI_PAGE_SHIFT;
+	if (num_dropped_pages > md->num_pages)
+		num_dropped_pages = md->num_pages;
+
+	if (is_available_memory(md))
+		printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole "
+		       "at 0x%lx\n", __FUNCTION__,
+		       (num_dropped_pages << EFI_PAGE_SHIFT) >> 10,
+		       md->phys_addr, end_addr);
+	md->num_pages -= num_dropped_pages;
+}
+
+/*
+ * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
+ * has memory that is available for OS use.
  */
 void
 efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
@@ -137,9 +207,9 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p;
-	efi_memory_desc_t *md;
-	u64 efi_desc_size, start, end;
+	void *efi_map_start, *efi_map_end, *p, *q;
+	efi_memory_desc_t *md, *check_md;
+	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
 	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
@@ -147,24 +217,56 @@
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
-		switch (md->type) {
-		      case EFI_LOADER_CODE:
-		      case EFI_LOADER_DATA:
-		      case EFI_BOOT_SERVICES_CODE:
-		      case EFI_BOOT_SERVICES_DATA:
-		      case EFI_CONVENTIONAL_MEMORY:
-			if (!(md->attribute & EFI_MEMORY_WB))
-				continue;
+
+		/* skip over non-WB memory descriptors; that's all we're interested in... */
+		if (!(md->attribute & EFI_MEMORY_WB))
+			continue;
+
+		if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > first_non_wb_addr) {
+			/*
+			 * Search for the next run of contiguous WB memory.  Start search
+			 * at first granule boundary covered by md.
+			 */
+			granule_addr = ((md->phys_addr + IA64_GRANULE_SIZE - 1)
+					& -IA64_GRANULE_SIZE);
+			first_non_wb_addr = granule_addr;
+			for (q = p; q < efi_map_end; q += efi_desc_size) {
+				check_md = q;
+
+				if (check_md->attribute & EFI_MEMORY_WB)
+					trim_bottom(md, granule_addr);
+
+				if (check_md->phys_addr < granule_addr)
+					continue;
+
+				if (!(check_md->attribute & EFI_MEMORY_WB))
+					break;	/* hit a non-WB region; stop search */
+
+				if (check_md->phys_addr != first_non_wb_addr)
+					break;	/* hit a memory hole; stop search */
+
+				first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT;
+			}
+			/* round it down to the previous granule-boundary: */
+			first_non_wb_addr &= -IA64_GRANULE_SIZE;
+
+			if (!(first_non_wb_addr > granule_addr))
+				continue;	/* couldn't find enough contiguous memory */
+		}
+
+		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
+
+		trim_top(md, first_non_wb_addr);
+
+		if (is_available_memory(md)) {
 			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
 				if (md->phys_addr > mem_limit)
 					continue;
 				md->num_pages = (mem_limit - md->phys_addr) >> EFI_PAGE_SHIFT;
 			}
-			if (md->num_pages == 0) {
-				printk("efi_memmap_walk: ignoring empty region at 0x%lx",
-				       md->phys_addr);
+
+			if (md->num_pages == 0)
 				continue;
-			}
 
 			curr.start = PAGE_OFFSET + md->phys_addr;
 			curr.end   = curr.start + (md->num_pages << EFI_PAGE_SHIFT);
@@ -187,10 +289,6 @@
 					prev = curr;
 				}
 			}
-			break;
-
-		      default:
-			continue;
 		}
 	}
 	if (prev_valid) {
@@ -268,8 +366,9 @@
 		 */
 		psr = ia64_clear_ic();
 		ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask,
-			 pte_val(pfn_pte(md->phys_addr >> PAGE_SHIFT, PAGE_KERNEL)), IA64_GRANULE_SHIFT);
-		ia64_set_psr(psr);
+			 pte_val(pfn_pte(md->phys_addr >> PAGE_SHIFT, PAGE_KERNEL)),
+			 IA64_GRANULE_SHIFT);
+		ia64_set_psr(psr);		/* restore psr */
 		ia64_srlz_i();
 	}
 }
@@ -347,6 +446,9 @@
 		} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
 			efi.sal_systab = __va(config_tables[i].table);
 			printk(" SALsystab=0x%lx", config_tables[i].table);
+		} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
+			efi.hcdp = __va(config_tables[i].table);
+			printk(" HCDP=0x%lx", config_tables[i].table);
 		}
 	}
 	printk("\n");
@@ -376,7 +478,7 @@
 			md = p;
 			printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
 			       i, md->type, md->attribute, md->phys_addr,
-			       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1,
+			       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
 			       md->num_pages >> (20 - EFI_PAGE_SHIFT));
 		}
 	}
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/entry.S	Tue Aug 27 12:28:02 2002
@@ -175,6 +175,7 @@
 (p6)	srlz.d
 	ld8 sp=[r21]			// load kernel stack pointer of new task
 	mov IA64_KR(CURRENT)=r20	// update "current" application register
+	mov r8=r13			// return pointer to previously running task
 	mov r13=in0			// set "current" pointer
 	;;
 	DO_LOAD_SWITCH_STACK
diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
--- a/arch/ia64/kernel/ia64_ksyms.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/ia64_ksyms.c	Tue Aug 27 12:28:05 2002
@@ -84,16 +84,6 @@
 EXPORT_SYMBOL(smp_call_function_single);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(ia64_cpu_to_sapicid);
-
-#include <asm/smplock.h>
-EXPORT_SYMBOL(kernel_flag);
-
-/* #include <asm/system.h> */
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
-
 #else /* !CONFIG_SMP */
 
 EXPORT_SYMBOL(__flush_tlb_all);
diff -Nru a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c
--- a/arch/ia64/kernel/init_task.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/kernel/init_task.c	Tue Aug 27 12:28:08 2002
@@ -34,8 +34,8 @@
 	} s;
 	unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)];
 } init_thread_union __attribute__((section(".data.init_task"))) = {{
-	task: INIT_TASK(init_thread_union.s.task),
-	thread_info: INIT_THREAD_INFO(init_thread_union.s.thread_info)
+	.task =		INIT_TASK(init_thread_union.s.task),
+	.thread_info =	INIT_THREAD_INFO(init_thread_union.s.thread_info)
 }};
 
 asm (".global init_task; init_task = init_thread_union");
diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/iosapic.c	Tue Aug 27 12:28:05 2002
@@ -88,7 +88,7 @@
 
 static struct iosapic_irq {
 	char *addr;			/* base address of IOSAPIC */
-	unsigned char base_irq;		/* first irq assigned to this IOSAPIC */
+	unsigned int base_irq;		/* first irq assigned to this IOSAPIC */
 	char pin;			/* IOSAPIC pin (-1 => not an IOSAPIC irq) */
 	unsigned char dmode	: 3;	/* delivery mode (see iosapic.h) */
 	unsigned char polarity	: 1;	/* interrupt polarity (see iosapic.h) */
@@ -97,9 +97,9 @@
 
 static struct iosapic {
 	char *addr;			/* base address of IOSAPIC */
-	unsigned char	pcat_compat;	/* 8259 compatibility flag */
-	unsigned char 	base_irq;	/* first irq assigned to this IOSAPIC */
+	unsigned int 	base_irq;	/* first irq assigned to this IOSAPIC */
 	unsigned short 	max_pin;	/* max input pin supported in this IOSAPIC */
+	unsigned char	pcat_compat;	/* 8259 compatibility flag */
 } iosapic_lists[256] __initdata;
 
 static int num_iosapic = 0;
@@ -160,6 +160,10 @@
 	int pin;
 	char redir;
 
+#ifdef DEBUG_IRQ_ROUTING
+	printk(KERN_DEBUG "set_rte: routing vector 0x%02x to 0x%lx\n", vector, dest);
+#endif
+
 	pin = iosapic_irq[vector].pin;
 	if (pin < 0)
 		return;		/* not an IOSAPIC interrupt */
@@ -322,14 +326,14 @@
 #define iosapic_ack_level_irq		nop
 
 struct hw_interrupt_type irq_type_iosapic_level = {
-	typename:	"IO-SAPIC-level",
-	startup:	iosapic_startup_level_irq,
-	shutdown:	iosapic_shutdown_level_irq,
-	enable:		iosapic_enable_level_irq,
-	disable:	iosapic_disable_level_irq,
-	ack:		iosapic_ack_level_irq,
-	end:		iosapic_end_level_irq,
-	set_affinity:	iosapic_set_affinity
+	.typename =	"IO-SAPIC-level",
+	.startup =	iosapic_startup_level_irq,
+	.shutdown =	iosapic_shutdown_level_irq,
+	.enable =	iosapic_enable_level_irq,
+	.disable =	iosapic_disable_level_irq,
+	.ack =		iosapic_ack_level_irq,
+	.end =		iosapic_end_level_irq,
+	.set_affinity =	iosapic_set_affinity
 };
 
 /*
@@ -366,14 +370,14 @@
 #define iosapic_end_edge_irq		nop
 
 struct hw_interrupt_type irq_type_iosapic_edge = {
-	typename:	"IO-SAPIC-edge",
-	startup:	iosapic_startup_edge_irq,
-	shutdown:	iosapic_disable_edge_irq,
-	enable:		iosapic_enable_edge_irq,
-	disable:	iosapic_disable_edge_irq,
-	ack:		iosapic_ack_edge_irq,
-	end:		iosapic_end_edge_irq,
-	set_affinity:	iosapic_set_affinity
+	.typename =	"IO-SAPIC-edge",
+	.startup =	iosapic_startup_edge_irq,
+	.shutdown =	iosapic_disable_edge_irq,
+	.enable =	iosapic_enable_edge_irq,
+	.disable =	iosapic_disable_edge_irq,
+	.ack =		iosapic_ack_edge_irq,
+	.end =		iosapic_end_edge_irq,
+	.set_affinity =	iosapic_set_affinity
 };
 
 unsigned int
@@ -406,7 +410,7 @@
 	    || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger)
 	{
 		new_vector = ia64_alloc_irq();
-		printk("Reassigning Vector 0x%x to 0x%x\n", vector, new_vector);
+		printk("Reassigning vector 0x%x to 0x%x\n", vector, new_vector);
 		memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector],
 			sizeof(struct iosapic_irq));
 		memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq));
@@ -422,6 +426,7 @@
 	irq_desc_t *idesc;
 	struct hw_interrupt_type *irq_type;
 
+	gsi_to_vector(global_vector) = vector;
 	iosapic_irq[vector].pin	= pin;
 	iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
 	iosapic_irq[vector].dmode    = delivery;
@@ -640,7 +645,7 @@
 	unsigned int irq;
 	char *addr;
 
-	if (0 != acpi_get_prt(&pci_irq.route, &pci_irq.num_routes))
+	if (acpi_get_prt(&pci_irq.route, &pci_irq.num_routes))
 		return;
 
 	for (i = 0; i < pci_irq.num_routes; i++) {
@@ -679,11 +684,10 @@
 		       pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin,
 		       iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector);
 #endif
-
 		/*
-		 * Forget not to program the IOSAPIC RTE per ACPI _PRT
+		 * NOTE: The IOSAPIC RTE will be programmed in iosapic_pci_fixup().  It
+		 * needs to be done there to ensure PCI hotplug works right.
 		 */
-		set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
 	}
 }
 
@@ -757,10 +761,11 @@
 				if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
 					static int cpu_index = 0;
 
-					set_rte(vector, cpu_physical_id(cpu_index) & 0xffff);
+					while (!cpu_online(cpu_index))
+						if (++cpu_index >= NR_CPUS)
+							cpu_index = 0;
 
-					for (cpu_index++; !cpu_online(cpu_index % NR_CPUS); cpu_index++);
-                                        cpu_index %= NR_CPUS;
+					set_rte(vector, cpu_physical_id(cpu_index) & 0xffff);
 				} else {
 					/*
 					 * Direct the interrupt vector to the current cpu,
diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
--- a/arch/ia64/kernel/irq.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/irq.c	Tue Aug 27 12:28:02 2002
@@ -200,277 +200,12 @@
 	return 0;
 }
 
-
-/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
- */
-
-#ifdef CONFIG_SMP
-unsigned int global_irq_holder = NO_PROC_ID;
-unsigned volatile long global_irq_lock; /* pedantic: long for set_bit --RR */
-
-extern void show_stack(unsigned long* esp);
-
-static void show(char * str)
+#if CONFIG_SMP
+inline void synchronize_irq(unsigned int irq)
 {
-	int i;
-	int cpu = smp_processor_id();
-
-	printk("\n%s, CPU %d:\n", str, cpu);
-	printk("irq:  %d [",irqs_running());
-	for(i=0;i < NR_CPUS;i++)
-		printk(" %d",irq_count(i));
-	printk(" ]\nbh:   %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
-	for(i=0;i < NR_CPUS;i++)
-		printk(" %d",bh_count(i));
-
-	printk(" ]\nStack dumps:");
-#if defined(CONFIG_IA64)
-	/*
-	 * We can't unwind the stack of another CPU without access to
-	 * the registers of that CPU.  And sending an IPI when we're
-	 * in a potentially wedged state doesn't sound like a smart
-	 * idea.
-	 */
-#elif defined(CONFIG_X86)
-	for(i=0;i< NR_CPUS;i++) {
-		unsigned long esp;
-		if(i==cpu)
-			continue;
-		printk("\nCPU %d:",i);
-		esp = init_tss[i].esp0;
-		if(esp==NULL) {
-			/* tss->esp0 is set to NULL in cpu_init(),
-			 * it's initialized when the cpu returns to user
-			 * space. -- manfreds
-			 */
-			printk(" <unknown> ");
-			continue;
-		}
-		esp &= ~(THREAD_SIZE-1);
-		esp += sizeof(struct task_struct);
-		show_stack((void*)esp);
-	}
-#else
-	You lose...
-#endif
-	printk("\nCPU %d:",cpu);
-	show_stack(NULL);
-	printk("\n");
+	while (irq_desc(irq)->status & IRQ_INPROGRESS)
+		cpu_relax();
 }
-
-#define MAXCOUNT 100000000
-
-/*
- * I had a lockup scenario where a tight loop doing
- * spin_unlock()/spin_lock() on CPU#1 was racing with
- * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
- * apparently the spin_unlock() information did not make it
- * through to CPU#0 ... nasty, is this by design, do we have to limit
- * 'memory update oscillation frequency' artificially like here?
- *
- * Such 'high frequency update' races can be avoided by careful design, but
- * some of our major constructs like spinlocks use similar techniques,
- * it would be nice to clarify this issue. Set this define to 0 if you
- * want to check whether your system freezes.  I suspect the delay done
- * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
- * i thought that such things are guaranteed by design, since we use
- * the 'LOCK' prefix.
- */
-#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
-
-#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
-# define SYNC_OTHER_CORES(x) udelay(x+1)
-#else
-/*
- * We have to allow irqs to arrive between local_irq_enable and local_irq_disable
- */
-# ifdef CONFIG_IA64
-#  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0")
-# else
-#  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
-# endif
-#endif
-
-static inline void wait_on_irq(void)
-{
-	int count = MAXCOUNT;
-
-	for (;;) {
-
-		/*
-		 * Wait until all interrupts are gone. Wait
-		 * for bottom half handlers unless we're
-		 * already executing in one..
-		 */
-		if (!irqs_running())
-			if (really_local_bh_count() || !spin_is_locked(&global_bh_lock))
-				break;
-
-		/* Duh, we have to loop. Release the lock to avoid deadlocks */
-		smp_mb__before_clear_bit();	/* need barrier before releasing lock... */
-		clear_bit(0,&global_irq_lock);
-
-		for (;;) {
-			if (!--count) {
-				show("wait_on_irq");
-				count = ~0;
-			}
-			local_irq_enable();
-			SYNC_OTHER_CORES(smp_processor_id());
-			local_irq_disable();
-			if (irqs_running())
-				continue;
-			if (global_irq_lock)
-				continue;
-			if (!really_local_bh_count() && spin_is_locked(&global_bh_lock))
-				continue;
-			if (!test_and_set_bit(0,&global_irq_lock))
-				break;
-		}
-	}
-}
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-void synchronize_irq(void)
-{
-	if (irqs_running()) {
-		/* Stupid approach */
-		cli();
-		sti();
-	}
-}
-
-static inline void get_irqlock(void)
-{
-	if (test_and_set_bit(0,&global_irq_lock)) {
-		/* do we already hold the lock? */
-		if (smp_processor_id() == global_irq_holder)
-			return;
-		/* Uhhuh.. Somebody else got it. Wait.. */
-		do {
-			do {
-#ifdef CONFIG_X86
-				rep_nop();
-#endif
-			} while (test_bit(0,&global_irq_lock));
-		} while (test_and_set_bit(0,&global_irq_lock));
-	}
-	/*
-	 * We also to make sure that nobody else is running
-	 * in an interrupt context.
-	 */
-	wait_on_irq();
-
-	/*
-	 * Ok, finally..
-	 */
-	global_irq_holder = smp_processor_id();
-}
-
-#define EFLAGS_IF_SHIFT 9
-
-/*
- * A global "cli()" while in an interrupt context
- * turns into just a local cli(). Interrupts
- * should use spinlocks for the (very unlikely)
- * case that they ever want to protect against
- * each other.
- *
- * If we already have local interrupts disabled,
- * this will not turn a local disable into a
- * global one (problems with spinlocks: this makes
- * save_flags+cli+sti usable inside a spinlock).
- */
-void __global_cli(void)
-{
-	unsigned int flags;
-
-#ifdef CONFIG_IA64
-	local_save_flags(flags);
-	if (flags & IA64_PSR_I) {
-		local_irq_disable();
-		if (!really_local_irq_count())
-			get_irqlock();
-	}
-#else
-	local_save_flags(flags);
-	if (flags & (1 << EFLAGS_IF_SHIFT)) {
-		local_irq_disable();
-		if (!really_local_irq_count())
-			get_irqlock();
-	}
-#endif
-}
-
-void __global_sti(void)
-{
-	if (!really_local_irq_count())
-		release_irqlock(smp_processor_id());
-	local_irq_enable();
-}
-
-/*
- * SMP flags value to restore to:
- * 0 - global cli
- * 1 - global sti
- * 2 - local cli
- * 3 - local sti
- */
-unsigned long __global_save_flags(void)
-{
-	int retval;
-	int local_enabled;
-	unsigned long flags;
-	int cpu = smp_processor_id();
-
-	local_save_flags(flags);
-#ifdef CONFIG_IA64
-	local_enabled = (flags & IA64_PSR_I) != 0;
-#else
-	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
-#endif
-	/* default to local */
-	retval = 2 + local_enabled;
-
-	/* check for global flags if we're not in an interrupt */
-	if (!really_local_irq_count()) {
-		if (local_enabled)
-			retval = 1;
-		if (global_irq_holder == cpu)
-			retval = 0;
-	}
-	return retval;
-}
-
-void __global_restore_flags(unsigned long flags)
-{
-	switch (flags) {
-	case 0:
-		__global_cli();
-		break;
-	case 1:
-		__global_sti();
-		break;
-	case 2:
-		local_irq_disable();
-		break;
-	case 3:
-		local_irq_enable();
-		break;
-	default:
-		printk("global_restore_flags: %08lx (%08lx)\n",
-			flags, (&flags)[-1]);
-	}
-}
-
 #endif
 
 /*
@@ -482,11 +217,7 @@
  */
 int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
 {
-	int status;
-
-	local_irq_enter(irq);
-
-	status = 1;	/* Force the "do bottom halves" bit */
+	int status = 1;	/* Force the "do bottom halves" bit */
 
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
@@ -500,11 +231,16 @@
 		add_interrupt_randomness(irq);
 	local_irq_disable();
 
-	local_irq_exit(irq);
-
 	return status;
 }
 
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
 /**
  *	disable_irq_nosync - disable an irq without waiting
  *	@irq: Interrupt to disable
@@ -546,14 +282,7 @@
 void disable_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
-
-#ifdef CONFIG_SMP
-	if (!really_local_irq_count()) {
-		do {
-			barrier();
-		} while (irq_desc(irq)->status & IRQ_INPROGRESS);
-	}
-#endif
+	synchronize_irq(irq);
 }
 
 /**
@@ -616,6 +345,7 @@
 	struct irqaction * action;
 	unsigned int status;
 
+	irq_enter();
 	kstat.irqs[cpu][irq]++;
 
 	if (desc->status & IRQ_PER_CPU) {
@@ -638,7 +368,7 @@
 		 * use the action we have.
 		 */
 		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
 			action = desc->action;
 			status &= ~IRQ_PENDING; /* we commit to handling */
 			status |= IRQ_INPROGRESS; /* we are handling it */
@@ -651,7 +381,7 @@
 		 * a different instance of this same irq, the other processor
 		 * will take care of it.
 		 */
-		if (!action)
+		if (unlikely(!action))
 			goto out;
 
 		/*
@@ -673,8 +403,8 @@
 				break;
 			desc->status &= ~IRQ_PENDING;
 		}
-		desc->status &= ~IRQ_INPROGRESS;
 	  out:
+		desc->status &= ~IRQ_INPROGRESS;
 		/*
 		 * The ->end() handler has to deal with interrupts which got
 		 * disabled while the handler was running.
@@ -682,6 +412,7 @@
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
+	irq_exit();
 	return 1;
 }
 
@@ -811,7 +542,7 @@
 #ifdef CONFIG_SMP
 			/* Wait to make sure it's not being used on another CPU */
 			while (desc->status & IRQ_INPROGRESS)
-				barrier();
+				synchronize_irq(irq);
 #endif
 			kfree(action);
 			return;
@@ -864,7 +595,7 @@
 
 	/* Wait for longstanding interrupts to trigger. */
 	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
-		/* about 20ms delay */ synchronize_irq();
+		/* about 20ms delay */ barrier();
 
 	/*
 	 * enable any unassigned irqs
@@ -887,7 +618,7 @@
 	 * Wait for spurious interrupts to trigger
 	 */
 	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
-		/* about 100ms delay */ synchronize_irq();
+		/* about 100ms delay */ barrier();
 
 	/*
 	 * Now filter out any obviously spurious interrupts
diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
--- a/arch/ia64/kernel/irq_ia64.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/irq_ia64.c	Tue Aug 27 12:28:02 2002
@@ -36,6 +36,10 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_PERFMON
+# include <asm/perfmon.h>
+#endif
+
 #define IRQ_DEBUG	0
 
 /* default base addr of IPI table */
@@ -50,6 +54,11 @@
 	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21
 };
 
+/*
+ * GSI to IA-64 vector translation table.
+ */
+__u8 gsi_to_vector_map[255];
+
 int
 ia64_alloc_irq (void)
 {
@@ -144,9 +153,9 @@
 extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
 
 static struct irqaction ipi_irqaction = {
-	handler:	handle_IPI,
-	flags:		SA_INTERRUPT,
-	name:		"IPI"
+	.handler =	handle_IPI,
+	.flags =	SA_INTERRUPT,
+	.name =		"IPI"
 };
 #endif
 
@@ -172,6 +181,9 @@
 	register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
 #ifdef CONFIG_SMP
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
+#endif
+#ifdef CONFIG_PERFMON
+	perfmon_init_percpu();
 #endif
 	platform_irq_init();
 }
diff -Nru a/arch/ia64/kernel/irq_lsapic.c b/arch/ia64/kernel/irq_lsapic.c
--- a/arch/ia64/kernel/irq_lsapic.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/irq_lsapic.c	Tue Aug 27 12:28:02 2002
@@ -27,12 +27,12 @@
 }
 
 struct hw_interrupt_type irq_type_ia64_lsapic = {
-	typename:	"LSAPIC",
-	startup:	lsapic_noop_startup,
-	shutdown:	lsapic_noop,
-	enable:		lsapic_noop,
-	disable:	lsapic_noop,
-	ack:		lsapic_noop,
-	end:		lsapic_noop,
-	set_affinity:	(void (*)(unsigned int, unsigned long)) lsapic_noop
+	.typename =	"LSAPIC",
+	.startup =	lsapic_noop_startup,
+	.shutdown =	lsapic_noop,
+	.enable =	lsapic_noop,
+	.disable =	lsapic_noop,
+	.ack =		lsapic_noop,
+	.end =		lsapic_noop,
+	.set_affinity =	(void (*)(unsigned int, unsigned long)) lsapic_noop
 };
diff -Nru a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
--- a/arch/ia64/kernel/machvec.c	Tue Aug 27 12:28:06 2002
+++ b/arch/ia64/kernel/machvec.c	Tue Aug 27 12:28:06 2002
@@ -11,13 +11,16 @@
 struct ia64_machine_vector ia64_mv;
 
 /*
- * Most platforms use this routine for mapping page frame addresses
- * into a memory map index.
+ * Most platforms use this routine for mapping page frame addresses into a memory map
+ * index.
+ *
+ * Note: we can't use __pa() because map_nr_dense(X) MUST map to something >= max_mapnr if
+ * X is outside the identity mapped kernel space.
  */
 unsigned long
 map_nr_dense (unsigned long addr)
 {
-	return MAP_NR_DENSE(addr);
+	return (addr - PAGE_OFFSET) >> PAGE_SHIFT;
 }
 
 static struct ia64_machine_vector *
diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/mca.c	Tue Aug 27 12:28:05 2002
@@ -82,27 +82,27 @@
 extern struct hw_interrupt_type	irq_type_iosapic_level;
 
 static struct irqaction cmci_irqaction = {
-	handler:    ia64_mca_cmc_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "cmc_hndlr"
+	.handler =	ia64_mca_cmc_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"cmc_hndlr"
 };
 
 static struct irqaction mca_rdzv_irqaction = {
-	handler:    ia64_mca_rendez_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "mca_rdzv"
+	.handler =	ia64_mca_rendez_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"mca_rdzv"
 };
 
 static struct irqaction mca_wkup_irqaction = {
-	handler:    ia64_mca_wakeup_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "mca_wkup"
+	.handler =	ia64_mca_wakeup_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"mca_wkup"
 };
 
 static struct irqaction mca_cpe_irqaction = {
-	handler:    ia64_mca_cpe_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "cpe_hndlr"
+	.handler =	ia64_mca_cpe_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"cpe_hndlr"
 };
 
 /*
@@ -626,9 +626,12 @@
 void
 ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
 {
-	int flags, cpu = 0;
+	unsigned long flags;
+	int cpu = 0;
+
 	/* Mask all interrupts */
-	save_and_cli(flags);
+#warning XXX fix me: this used to be: save_and_cli(flags);
+	local_irq_save(flags);
 
 #ifdef CONFIG_SMP
 	cpu = cpu_logical_id(hard_smp_processor_id());
@@ -646,7 +649,7 @@
 	ia64_mca_wakeup_ipi_wait();
 
 	/* Enable all interrupts */
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 
diff -Nru a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
--- a/arch/ia64/kernel/mca_asm.S	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/mca_asm.S	Tue Aug 27 12:28:02 2002
@@ -684,9 +684,9 @@
 	movl	r3=SAL_GET_STATE_INFO;;
 	DATA_VA_TO_PA(r7);;		// convert to physical address
 	ld8	r8=[r7],8;;		// get pdesc function pointer
-	DATA_VA_TO_PA(r8)		// convert to physical address
+	dep	r8=0,r8,61,3;;		// convert SAL VA to PA
 	ld8	r1=[r7];;		// set new (ia64_sal) gp
-	DATA_VA_TO_PA(r1)		// convert to physical address
+	dep	r1=0,r1,61,3;;		// convert SAL VA to PA
 	mov	b6=r8
 
 	alloc	r5=ar.pfs,8,0,8,0;;	// allocate stack frame for SAL call
diff -Nru a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c
--- a/arch/ia64/kernel/pci.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/pci.c	Tue Aug 27 12:28:05 2002
@@ -165,7 +165,7 @@
  */
 
 struct pci_bus *
-pcibios_scan_root(int seg, int bus)
+pcibios_scan_root(int bus)
 {
 	struct list_head *list = NULL;
 	struct pci_bus *pci_bus = NULL;
@@ -174,12 +174,12 @@
 		pci_bus = pci_bus_b(list);
 		if (pci_bus->number == bus) {
 			/* Already scanned */
-			printk("PCI: Bus (%02x:%02x) already probed\n", seg, bus);
+			printk("PCI: Bus (%02x) already probed\n", bus);
 			return pci_bus;
 		}
 	}
 
-	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+	printk("PCI: Probing PCI hardware on bus (%02x)\n", bus);
 
 	return pci_scan_bus(bus, pci_root_ops, NULL);
 }
@@ -265,12 +265,37 @@
 int
 pcibios_enable_device (struct pci_dev *dev)
 {
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
 	if (!dev)
 		return -EINVAL;
 
-	/* Not needed, since we enable all devices at startup.  */
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because of resource collisions\n",
+			       dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
 
 	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
+
 	return 0;
 }
 
diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
--- a/arch/ia64/kernel/perfmon.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/kernel/perfmon.c	Tue Aug 27 12:28:08 2002
@@ -106,6 +106,12 @@
 
 #define PFM_REG_RETFLAG_SET(flags, val)	do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)
 
+#ifdef CONFIG_SMP
+#define cpu_is_online(i) (cpu_online_map & (1UL << i))
+#else
+#define cpu_is_online(i)        (i==0)
+#endif
+
 /*
  * debugging
  */
@@ -277,8 +283,8 @@
 typedef struct {
 	pfm_pmu_reg_type_t	type;
 	int			pm_pos;
-	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val);
-	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val);
+	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	unsigned long		dep_pmd[4];
 	unsigned long		dep_pmc[4];
 } pfm_reg_desc_t;
@@ -369,8 +375,8 @@
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
 static pfm_stats_t	pfm_stats;
-int __per_cpu_data pfm_syst_wide;
-static int __per_cpu_data pfm_dcr_pp;
+DEFINE_PER_CPU(int, pfm_syst_wide);
+static DEFINE_PER_CPU(int, pfm_dcr_pp);
 
 /* sysctl() controls */
 static pfm_sysctl_t pfm_sysctl;
@@ -396,7 +402,7 @@
 static void pfm_vm_close(struct vm_area_struct * area);
 
 static struct vm_operations_struct pfm_vm_ops={
-	close: pfm_vm_close
+	.close = pfm_vm_close
 };
 
 /*
@@ -902,8 +908,8 @@
 		/*
 		 * and it must be a valid CPU
 		 */
-		cpu = ffs(pfx->ctx_cpu_mask);
-		if (!cpu_online(cpu)) {
+		cpu = ffz(~pfx->ctx_cpu_mask);
+		if (cpu_is_online(cpu) == 0) {
 			DBprintk(("CPU%d is not online\n", cpu));
 			return -EINVAL;
 		}
@@ -925,11 +931,12 @@
 			DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid));
 			return -EINVAL;
 		}
-
+#if 0
 		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) {
 			DBprintk(("cannot notify self when blocking for [%d]\n", task->pid));
 			return -EINVAL;
 		}
+#endif
 	}
 	/* probably more to add here */
 
@@ -968,7 +975,7 @@
 	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
 
 		/* at this point, we know there is at least one bit set */
-		cpu = ffs(tmp.ctx_cpu_mask) - 1;
+		cpu = ffz(~tmp.ctx_cpu_mask);
 
 		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
 
@@ -1280,7 +1287,7 @@
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value);
+		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1371,7 +1378,7 @@
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value);
+		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1394,6 +1401,8 @@
 
 		/* keep track of what we use */
 		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+		/* mark this register as used as well */
+		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
 		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
@@ -1438,7 +1447,7 @@
 	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long reg_val = ~0UL, ctx_val = ~0UL;
+		unsigned long ctx_val = ~0UL;
 
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
@@ -1462,7 +1471,7 @@
 		 */
 		if (atomic_read(&ctx->ctx_last_cpu) == smp_processor_id()){
 			ia64_srlz_d();
-			val = reg_val = ia64_get_pmd(cnum);
+			val = ia64_get_pmd(cnum);
 			DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val));
 		} else {
 #ifdef CONFIG_SMP
@@ -1484,7 +1493,7 @@
 			}
 #endif
 			/* context has been saved */
-			val = reg_val = th->pmd[cnum];
+			val = th->pmd[cnum];
 		}
 		if (PMD_IS_COUNTING(cnum)) {
 			/*
@@ -1493,9 +1502,7 @@
 
 			val &= pmu_conf.perf_ovfl_val;
 			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
-		} else {
-			val = reg_val = ia64_get_pmd(cnum);
-		}
+		} 
 
 		tmp.reg_value = val;
 
@@ -1503,14 +1510,13 @@
 		 * execute read checker, if any
 		 */
 		if (PMD_RD_FUNC(cnum)) {
-			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value);
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
 		}
 
 		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
 
-		DBprintk(("read pmd[%u] ret=%d soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", 
-					cnum, ret, ctx_val, reg_val, 
-					ia64_get_pmc(cnum)));
+		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
+					cnum, ret, val, ia64_get_pmc(cnum)));
 
 		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
@@ -1553,15 +1559,11 @@
 	 */
 	if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1;
 
-	/*
-	 * XXX: not pretty
-	 */
 	LOCK_PFS();
 
 	/*
-	 * We only allow the use of debug registers when there is no system
-	 * wide monitoring 
-	 * XXX: we could relax this by 
+	 * We cannot allow setting breakpoints when system wide monitoring
+	 * sessions are using the debug registers.
 	 */
 	if (pfm_sessions.pfs_sys_use_dbregs> 0)
 		ret = -1;
@@ -1762,7 +1764,7 @@
 		ia64_srlz_i();
 
 #ifdef CONFIG_SMP
-		this_cpu(pfm_dcr_pp)  = 0;
+		__get_cpu_var(pfm_dcr_pp)  = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
@@ -1921,7 +1923,6 @@
 	dbr_mask_reg_t dbr;
 } dbreg_t;
 
-
 static int
 pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs)
 {
@@ -1963,8 +1964,8 @@
 	if (ctx->ctx_fl_system) {
 		/* we mark ourselves as owner  of the debug registers */
 		ctx->ctx_fl_using_dbreg = 1;
-	} else {
-       		if (ctx->ctx_fl_using_dbreg == 0) {
+		DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid));
+	} else if (first_time) {
 			ret= -EBUSY;
 			if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) {
 				DBprintk(("debug registers already in use for [%d]\n", task->pid));
@@ -1973,6 +1974,7 @@
 			/* we mark ourselves as owner  of the debug registers */
 			ctx->ctx_fl_using_dbreg = 1;
 
+			DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid));
 			/* 
 			 * Given debug registers cannot be used for both debugging 
 			 * and performance monitoring at the same time, we reuse
@@ -1980,20 +1982,27 @@
 			 */
 			memset(task->thread.dbr, 0, sizeof(task->thread.dbr));
 			memset(task->thread.ibr, 0, sizeof(task->thread.ibr));
+	}
 
-			/*
-			 * clear hardware registers to make sure we don't
-			 * pick up stale state
-			 */
-			for (i=0; i < pmu_conf.num_ibrs; i++) {
-				ia64_set_ibr(i, 0UL);
-			}
-			ia64_srlz_i();
-			for (i=0; i < pmu_conf.num_dbrs; i++) {
-				ia64_set_dbr(i, 0UL);
-			}
-			ia64_srlz_d();
+	if (first_time) {
+		DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid));
+		/*
+	 	 * clear hardware registers to make sure we don't
+	 	 * pick up stale state. 
+		 *
+		 * for a system wide session, we do not use
+		 * thread.dbr, thread.ibr because this process
+		 * never leaves the current CPU and the state
+		 * is shared by all processes running on it
+	 	 */
+		for (i=0; i < pmu_conf.num_ibrs; i++) {
+			ia64_set_ibr(i, 0UL);
 		}
+		ia64_srlz_i();
+		for (i=0; i < pmu_conf.num_dbrs; i++) {
+			ia64_set_dbr(i, 0UL);
+		}
+		ia64_srlz_d();
 	}
 
 	ret = -EFAULT;
@@ -2163,7 +2172,7 @@
 	if (ctx->ctx_fl_system) {
 		
 #ifdef CONFIG_SMP
-		this_cpu(pfm_dcr_pp)  = 1;
+		__get_cpu_var(pfm_dcr_pp)  = 1;
 #else
 		pfm_tasklist_toggle_pp(1);
 #endif
@@ -2218,8 +2227,8 @@
 		ia64_srlz_i();
 
 #ifdef CONFIG_SMP
-		this_cpu(pfm_syst_wide) = 1;
-		this_cpu(pfm_dcr_pp)    = 0;
+		__get_cpu_var(pfm_syst_wide) = 1;
+		__get_cpu_var(pfm_dcr_pp)    = 0;
 #endif
 	} else {
 		/*
@@ -2361,9 +2370,9 @@
 {
 	struct pt_regs *regs = (struct pt_regs *)&stack;
 	struct task_struct *task = current;
-	pfm_context_t *ctx = task->thread.pfm_context;
+	pfm_context_t *ctx;
 	size_t sz;
-	int ret = -ESRCH, narg;
+	int ret, narg;
 
 	/* 
 	 * reject any call if perfmon was disabled at initialization time
@@ -2393,6 +2402,8 @@
 
 		if (pid != current->pid) {
 
+			ret = -ESRCH;
+
 			read_lock(&tasklist_lock);
 
 			task = find_task_by_pid(pid);
@@ -2407,10 +2418,11 @@
 				ret = check_task_state(task);
 				if (ret != 0) goto abort_call;
 			}
-			ctx = task->thread.pfm_context;
 		}
 	} 
 
+	ctx = task->thread.pfm_context;
+
 	if (PFM_CMD_USE_CTX(cmd)) {
 		ret = -EINVAL;
 	       if (ctx == NULL) {
@@ -2953,11 +2965,6 @@
 static int
 perfmon_proc_info(char *page)
 {
-#ifdef CONFIG_SMP
-#define cpu_is_online(i) (cpu_online_map & (1UL << i))
-#else
-#define cpu_is_online(i)        1
-#endif
 	char *p = page;
 	int i;
 
@@ -2973,9 +2980,9 @@
 	p += sprintf(p, "CPU%d syst_wide   : %d\n"
 			"CPU%d dcr_pp      : %d\n", 
 			smp_processor_id(), 
-			this_cpu(pfm_syst_wide), 
+			__get_cpu_var(pfm_syst_wide), 
 			smp_processor_id(), 
-			this_cpu(pfm_dcr_pp));
+			__get_cpu_var(pfm_dcr_pp));
 #endif
 
 	LOCK_PFS();
@@ -3045,7 +3052,7 @@
 	/*
 	 * propagate the value of the dcr_pp bit to the psr
 	 */
-	ia64_psr(regs)->pp = mode ? this_cpu(pfm_dcr_pp) : 0;
+	ia64_psr(regs)->pp = mode ? __get_cpu_var(pfm_dcr_pp) : 0;
 }
 #endif
 
@@ -3539,8 +3546,8 @@
 		ia64_srlz_i();
 
 #ifdef CONFIG_SMP
-		this_cpu(pfm_syst_wide) = 0;
-		this_cpu(pfm_dcr_pp)    = 0;
+		__get_cpu_var(pfm_syst_wide) = 0;
+		__get_cpu_var(pfm_dcr_pp)    = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
@@ -4118,9 +4125,9 @@
 }
 
 static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"perfmon"
+	.handler =	perfmon_interrupt,
+	.flags =	SA_INTERRUPT,
+	.name =		"perfmon"
 };
 
 
@@ -4150,11 +4157,6 @@
 	pal_perf_mon_info_u_t pm_info;
 	s64 status;
 
-	register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
-
-	ia64_set_pmv(IA64_PERFMON_VECTOR);
-	ia64_srlz_d();
-
 	pmu_conf.pfm_is_disabled = 1;
 
 	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
@@ -4232,6 +4234,9 @@
 void
 perfmon_init_percpu (void)
 {
+	if (smp_processor_id() == 0)
+		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
+
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
 }
diff -Nru a/arch/ia64/kernel/perfmon_itanium.h b/arch/ia64/kernel/perfmon_itanium.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/kernel/perfmon_itanium.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,99 @@
+/*
+ * This file contains the Itanium PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
+
+#define RDEP(x)	(1UL<<(x))
+
+#ifndef CONFIG_ITANIUM
+#error "This file is only valid when CONFIG_ITANIUM is defined"
+#endif
+
+static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
+
+static pfm_reg_desc_t pmc_desc[256]={
+/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static pfm_reg_desc_t pmd_desc[256]={
+/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static int
+pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	pfm_context_t *ctx = task->thread.pfm_context;
+	int ret;
+
+	/*
+	 * we must clear the (instruction) debug registers if pmc13.ta bit is cleared
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+
+	/*
+	 * we must clear the (data) debug registers if pmc11.pt bit is cleared
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+	return 0;
+}
+
diff -Nru a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/kernel/perfmon_mckinley.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,134 @@
+/*
+ * This file contains the McKinley PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
+
+#define RDEP(x)	(1UL<<(x))
+
+#ifndef CONFIG_MCKINLEY
+#error "This file is only valid when CONFIG_MCKINLEY is defined"
+#endif
+
+static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
+
+static pfm_reg_desc_t pmc_desc[256]={
+/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static pfm_reg_desc_t pmd_desc[256]={
+/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static int
+pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	struct thread_struct *th = &task->thread;
+	pfm_context_t *ctx = task->thread.pfm_context;
+	int ret = 0, check_case1 = 0;
+	unsigned long val8 = 0, val14 = 0, val13 = 0;
+
+	/*
+	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+	/* 
+	 * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled 
+	 * before they are (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs);
+		if (ret) return ret;
+
+	}
+
+	switch(cnum) {
+		case  4: *val |= 1UL << 23; /* force power enable bit */
+			 break;
+		case  8: val8 = *val;
+			 val13 = th->pmc[13];
+			 val14 = th->pmc[14];
+			 check_case1 = 1;
+			 break;
+		case 13: val8  = th->pmc[8];
+			 val13 = *val;
+			 val14 = th->pmc[14];
+			 check_case1 = 1;
+			 break;
+		case 14: val8  = th->pmc[13];
+			 val13 = th->pmc[13];
+			 val14 = *val;
+			 check_case1 = 1;
+			 break;
+	}
+	/* check illegal configuration which can produce inconsistencies in tagging
+	 * i-side events in L1D and L2 caches
+	 */
+	if (check_case1) {
+		ret =   ((val13 >> 45) & 0xf) == 0 
+		   && ((val8 & 0x1) == 0)
+		   && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
+		       ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
+
+		if (ret) printk("perfmon: failure check_case1\n");
+	}
+
+	return ret ? -EINVAL : 0;
+}
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/kernel/process.c	Tue Aug 27 12:28:05 2002
@@ -194,7 +194,7 @@
 		pfm_save_regs(task);
 
 # ifdef CONFIG_SMP
-	if (this_cpu(pfm_syst_wide))
+	if (__get_cpu_var(pfm_syst_wide))
 		pfm_syst_wide_update_task(task, 0);
 # endif
 #endif
@@ -216,7 +216,7 @@
 		pfm_load_regs(task);
 
 # ifdef CONFIG_SMP
-	if (this_cpu(pfm_syst_wide)) pfm_syst_wide_update_task(task, 1);
+	if (__get_cpu_var(pfm_syst_wide)) pfm_syst_wide_update_task(task, 1);
 # endif
 #endif
 
@@ -325,6 +325,11 @@
 
 	/* copy parts of thread_struct: */
 	p->thread.ksp = (unsigned long) child_stack - 16;
+
+	/* stop some PSR bits from being inherited: */
+	child_ptregs->cr_ipsr =  ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+				  & ~IA64_PSR_BITS_TO_CLEAR);
+
 	/*
 	 * NOTE: The calling convention considers all floating point
 	 * registers in the high partition (fph) to be scratch.  Since
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Tue Aug 27 12:28:01 2002
+++ b/arch/ia64/kernel/setup.c	Tue Aug 27 12:28:01 2002
@@ -58,7 +58,7 @@
 unsigned long __per_cpu_offset[NR_CPUS];
 #endif
 
-struct cpuinfo_ia64 cpu_info __per_cpu_data;
+DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info);
 
 unsigned long ia64_phys_stacked_size_p8;
 unsigned long ia64_cycles_per_usec;
@@ -347,6 +347,14 @@
 #ifdef CONFIG_ACPI_BOOT
 	acpi_boot_init(*cmdline_p);
 #endif
+#ifdef CONFIG_SERIAL_HCDP
+	if (efi.hcdp) {
+		void setup_serial_hcdp(void *);
+
+		/* Setup the serial ports described by HCDP */
+		setup_serial_hcdp(efi.hcdp);
+	}
+#endif
 #ifdef CONFIG_VT
 # if defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
@@ -436,7 +444,7 @@
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-	while (*pos < NR_CPUS && !(cpu_online_map & (1 << *pos)))
+	while (*pos < NR_CPUS && !(cpu_online_map & (1UL << *pos)))
 		++*pos;
 #endif
 	return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
@@ -455,10 +463,10 @@
 }
 
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo
+	.start =	c_start,
+	.next =		c_next,
+	.stop =		c_stop,
+	.show =		show_cpuinfo
 };
 
 void
@@ -542,7 +550,18 @@
 	extern char __per_cpu_end[];
 	int cpu = smp_processor_id();
 
-	my_cpu_data = alloc_bootmem_pages(__per_cpu_end - __per_cpu_start);
+	if (__per_cpu_end - __per_cpu_start > PAGE_SIZE)
+		panic("Per-cpu data area too big! (%Zu > %Zu)",
+		      __per_cpu_end - __per_cpu_start, PAGE_SIZE);
+
+	/*
+	 * On the BSP, the page allocator isn't initialized by the time we get here.  On
+	 * the APs, the bootmem allocator is no longer available...
+	 */
+	if (cpu == 0)
+		my_cpu_data = alloc_bootmem_pages(__per_cpu_end - __per_cpu_start);
+	else
+		my_cpu_data = (void *) get_free_page(GFP_KERNEL);
 	memcpy(my_cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
 	__per_cpu_offset[cpu] = (char *) my_cpu_data - __per_cpu_start;
 	my_cpu_info = my_cpu_data + ((char *) &cpu_info - __per_cpu_start);
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c	Tue Aug 27 12:27:56 2002
+++ b/arch/ia64/kernel/signal.c	Tue Aug 27 12:27:56 2002
@@ -146,6 +146,7 @@
 	if (from->si_code < 0) {
 		if (__copy_to_user(to, from, sizeof(siginfo_t)))
 			return -EFAULT;
+		return 0;
 	} else {
 		int err;
 
diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
--- a/arch/ia64/kernel/smp.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/kernel/smp.c	Tue Aug 27 12:28:08 2002
@@ -53,14 +53,6 @@
 #include <asm/mca.h>
 
 /*
- * The Big Kernel Lock.  It's not supposed to be used for performance critical stuff
- * anymore.  But we still need to align it because certain workloads are still affected by
- * it.  For example, llseek() and various other filesystem related routines still use the
- * BKL.
- */
-spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
-
-/*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
  * requirements. It also looks cleaner.
  */
@@ -80,7 +72,7 @@
 #define IPI_CPU_STOP		1
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
-static __u64 ipi_operation __per_cpu_data ____cacheline_aligned;
+static DECLARE_PER_CPU(__u64, ipi_operation) ____cacheline_aligned;
 
 static void
 stop_this_cpu (void)
@@ -99,7 +91,7 @@
 handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
 {
 	int this_cpu = smp_processor_id();
-	unsigned long *pending_ipis = &this_cpu(ipi_operation);
+	unsigned long *pending_ipis = &__get_cpu_var(ipi_operation);
 	unsigned long ops;
 
 	/* Count this now; we may make a call that never returns. */
diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/kernel/smpboot.c	Tue Aug 27 12:28:02 2002
@@ -1,10 +1,14 @@
 /*
  * SMP boot-related support
  *
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 01/05/16 Rohit Seth <rohit.seth@intel.com>	Moved SMP booting functions from smp.c to here.
  * 01/04/27 David Mosberger <davidm@hpl.hp.com>	Added ITC synching code.
+ * 02/07/31 David Mosberger <davidm@hpl.hp.com>	Switch over to hotplug-CPU boot-sequence.
+ *						smp_boot_cpus()/smp_commence() is replaced by
+ *						smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
  */
 
 
@@ -66,18 +70,16 @@
 
 #define DEBUG_ITC_SYNC	0
 
-extern void __init calibrate_delay(void);
-extern void start_ap(void);
+extern void __init calibrate_delay (void);
+extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
 int cpucount;
 task_t *task_for_booting_cpu;
 
-/* Setup configured maximum number of CPUs to activate */
-static int max_cpus = -1;
-
 /* Bitmask of currently online CPUs */
 volatile unsigned long cpu_online_map;
+unsigned long phys_cpu_present_map;
 
 /* which logical CPU number maps to which CPU (physical APIC ID) */
 volatile int ia64_cpu_to_sapicid[NR_CPUS];
@@ -86,44 +88,12 @@
 
 struct smp_boot_data smp_boot_data __initdata;
 
-/* Set when the idlers are all forked */
-volatile int smp_threads_ready;
-
 unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */
 
 char __initdata no_int_routing;
 
 unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */
 
-/*
- * Setup routine for controlling SMP activation
- *
- * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
- * activation entirely (the MPS table probe still happens, though).
- *
- * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
- * greater than 0, limits the maximum number of CPUs activated in
- * SMP mode to <NUM>.
- */
-
-static int __init
-nosmp (char *str)
-{
-	max_cpus = 0;
-	return 1;
-}
-
-__setup("nosmp", nosmp);
-
-static int __init
-maxcpus (char *str)
-{
-	get_option(&str, &max_cpus);
-	return 1;
-}
-
-__setup("maxcpus=", maxcpus);
-
 static int __init
 nointroute (char *str)
 {
@@ -299,7 +269,7 @@
 
 static volatile atomic_t smp_commenced = ATOMIC_INIT(0);
 
-void __init
+static void __init
 smp_commence (void)
 {
 	/*
@@ -308,7 +278,7 @@
 	Dprintk("Setting commenced=1, go go go\n");
 
 	wmb();
-	atomic_set(&smp_commenced,1);
+	atomic_set(&smp_commenced, 1);
 }
 
 
@@ -380,11 +350,7 @@
 	efi_map_pal_code();
 	cpu_init();
 	smp_callin();
-	Dprintk("CPU %d is set to go.\n", smp_processor_id());
-	while (!atomic_read(&smp_commenced))
-		cpu_relax();
 
-	Dprintk("CPU %d is starting idle.\n", smp_processor_id());
 	return cpu_idle();
 }
 
@@ -392,22 +358,20 @@
 fork_by_hand (void)
 {
 	/*
-	 * don't care about the eip and regs settings since
-	 * we'll never reschedule the forked task.
+	 * don't care about the eip and regs settings since we'll never reschedule the
+	 * forked task.
 	 */
 	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, 0, 0);
 }
 
-static void __init
-do_boot_cpu (int sapicid)
+static int __init
+do_boot_cpu (int sapicid, int cpu)
 {
 	struct task_struct *idle;
-	int timeout, cpu;
+	int timeout;
 
-	cpu = ++cpucount;
 	/*
-	 * We can't use kernel_thread since we must avoid to
-	 * reschedule the child.
+	 * We can't use kernel_thread since we must avoid to reschedule the child.
 	 */
 	idle = fork_by_hand();
 	if (IS_ERR(idle))
@@ -419,13 +383,11 @@
 	 */
 	init_idle(idle, cpu);
 
-	ia64_cpu_to_sapicid[cpu] = sapicid;
-
 	unhash_process(idle);
 
 	task_for_booting_cpu = idle;
 
-	Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
+	Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
 
 	platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
 
@@ -448,8 +410,10 @@
 	} else {
 		printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
 		ia64_cpu_to_sapicid[cpu] = -1;
-		cpucount--;
+		clear_bit(cpu, &cpu_online_map);  /* was set in smp_callin() */
+		return -EINVAL;
 	}
+	return 0;
 }
 
 unsigned long cache_decay_ticks;	/* # of ticks an idle task is considered cache-hot */
@@ -464,21 +428,42 @@
 }
 
 /*
+ * Initialize the logical CPU number to SAPICID mapping
+ */
+void __init
+smp_build_cpu_map (void)
+{
+	int sapicid, cpu, i;
+	int boot_cpu_id = hard_smp_processor_id();
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		ia64_cpu_to_sapicid[cpu] = -1;
+
+	ia64_cpu_to_sapicid[0] = boot_cpu_id;
+	phys_cpu_present_map = 1;
+
+	for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
+		sapicid = smp_boot_data.cpu_phys_id[i];
+		if (sapicid == -1 || sapicid == boot_cpu_id)
+			continue;
+		phys_cpu_present_map |= (1 << cpu);
+		ia64_cpu_to_sapicid[cpu] = sapicid;
+		cpu++;
+	}
+}
+
+/*
  * Cycle through the APs sending Wakeup IPIs to boot each.
  */
 void __init
-smp_boot_cpus (void)
+smp_prepare_cpus (unsigned int max_cpus)
 {
-	int sapicid, cpu;
 	int boot_cpu_id = hard_smp_processor_id();
 
 	/*
-	 * Initialize the logical to physical CPU number mapping
-	 * and the per-CPU profiling counter/multiplier
+	 * Initialize the per-CPU profiling counter/multiplier
 	 */
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
-		ia64_cpu_to_sapicid[cpu] = -1;
 	smp_setup_percpu_timer();
 
 	/*
@@ -492,7 +477,6 @@
 
 	printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id);
 
-	global_irq_holder = NO_PROC_ID;
 	current_thread_info()->cpu = 0;
 	smp_tune_scheduling();
 
@@ -501,55 +485,48 @@
 	 */
 	if (!max_cpus || (max_cpus < -1)) {
 		printk(KERN_INFO "SMP mode deactivated.\n");
-		cpu_online_map =  1;
-		goto smp_done;
+		cpu_online_map = phys_cpu_present_map = 1;
+		return;
 	}
-	if (max_cpus != -1)
-		printk (KERN_INFO "Limiting CPUs to %d\n", max_cpus);
+}
+
+void
+smp_cpus_done (unsigned int dummy)
+{
+	int cpu;
+	unsigned long bogosum = 0;
 
-	if (smp_boot_data.cpu_count > 1) {
+	/*
+	 * Allow the user to impress friends.
+	 */
 
-		printk(KERN_INFO "SMP: starting up secondaries.\n");
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		if (cpu_online(cpu))
+			bogosum += cpu_data(cpu)->loops_per_jiffy;
 
-		for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++) {
-			/*
-			 * Don't even attempt to start the boot CPU!
-			 */
-			sapicid = smp_boot_data.cpu_phys_id[cpu];
-			if ((sapicid == -1) || (sapicid == hard_smp_processor_id()))
-				continue;
-
-			if ((max_cpus > 0) && (cpucount + 1 >= max_cpus))
-				break;
-
-			do_boot_cpu(sapicid);
-
-			/*
-			 * Make sure we unmap all failed CPUs
-			 */
-			if (ia64_cpu_to_sapicid[cpu] == -1)
-				printk("phys CPU#%d not responding - cannot use it.\n", cpu);
-		}
+	printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+	       num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
+}
 
-		/*
-		 * Allow the user to impress friends.
-		 */
-
-		printk("Before bogomips.\n");
-		if (!cpucount) {
-			printk(KERN_ERR "Error: only one processor found.\n");
-		} else {
-			unsigned long bogosum = 0;
-  			for (cpu = 0; cpu < NR_CPUS; cpu++)
-				if (cpu_online_map & (1<<cpu))
-					bogosum += cpu_data(cpu)->loops_per_jiffy;
+int __devinit
+__cpu_up (unsigned int cpu)
+{
+	int ret;
+	int sapicid;
 
-			printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
-			       cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
-		}
-	}
-  smp_done:
-	;
+	sapicid = ia64_cpu_to_sapicid[cpu];
+	if (sapicid == -1)
+		return -EINVAL;
+
+	printk(KERN_INFO "Processor %d/%d is spinning up...\n", sapicid, cpu);
+
+	/* Processor goes to start_secondary(), sets online flag */
+	ret = do_boot_cpu(sapicid, cpu);
+	if (ret < 0)
+		return ret;
+
+	printk(KERN_INFO "Processor %d has spun up...\n", cpu);
+	return 0;
 }
 
 /*
@@ -571,9 +548,6 @@
 	ap_startup = (struct fptr *) start_ap;
 	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
 				       __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0);
-	if (sal_ret < 0) {
-		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n     Forcing UP mode\n",
-		       ia64_sal_strerror(sal_ret));
-		max_cpus = 0;
-	}
+	if (sal_ret < 0)
+		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret));
 }
diff -Nru a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
--- a/arch/ia64/kernel/sys_ia64.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ia64/kernel/sys_ia64.c	Tue Aug 27 12:28:07 2002
@@ -82,7 +82,6 @@
 ia64_shmat (int shmid, void *shmaddr, int shmflg, long arg3, long arg4, long arg5, long arg6,
 	    long arg7, long stack)
 {
-	extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 	unsigned long raddr;
 	int retval;
@@ -136,10 +135,6 @@
 
 	/* Check against existing mmap mappings. */
 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
-		goto out;
-
-	/* Check if we have enough memory.. */
-	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
 		goto out;
 
 	/* Ok, looks good - let it rip. */
diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
--- a/arch/ia64/kernel/time.c	Tue Aug 27 12:28:01 2002
+++ b/arch/ia64/kernel/time.c	Tue Aug 27 12:28:01 2002
@@ -41,21 +41,22 @@
 	extern unsigned long prof_cpu_mask;
 	extern char _stext;
 
+	if (!prof_buffer)
+		return;
+
 	if (!((1UL << smp_processor_id()) & prof_cpu_mask))
 		return;
 
-	if (prof_buffer && current->pid) {
-		ip -= (unsigned long) &_stext;
-		ip >>= prof_shift;
-		/*
-		 * Don't ignore out-of-bounds IP values silently, put them into the last
-		 * histogram slot, so if present, they will show up as a sharp peak.
-		 */
-		if (ip > prof_len - 1)
-			ip = prof_len - 1;
+	ip -= (unsigned long) &_stext;
+	ip >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds IP values silently, put them into the last
+	 * histogram slot, so if present, they will show up as a sharp peak.
+	 */
+	if (ip > prof_len - 1)
+		ip = prof_len - 1;
 
-		atomic_inc((atomic_t *) &prof_buffer[ip]);
-	}
+	atomic_inc((atomic_t *) &prof_buffer[ip]);
 }
 
 /*
@@ -285,9 +286,9 @@
 }
 
 static struct irqaction timer_irqaction = {
-	handler:	timer_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"timer"
+	.handler =	timer_interrupt,
+	.flags =	SA_INTERRUPT,
+	.name =		"timer"
 };
 
 void __init
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/kernel/traps.c	Tue Aug 27 12:28:08 2002
@@ -49,10 +49,15 @@
 void __init
 trap_init (void)
 {
-	printk("fpswa interface at %lx\n", ia64_boot_param->fpswa);
-	if (ia64_boot_param->fpswa)
+	int major = 0, minor = 0;
+
+	if (ia64_boot_param->fpswa) {
 		/* FPSWA fixup: make the interface pointer a kernel virtual address: */
 		fpswa_interface = __va(ia64_boot_param->fpswa);
+		major = fpswa_interface->revision & 0xffff;
+		minor = fpswa_interface->revision >> 16;
+	}
+	printk("fpswa interface at %lx (rev %d.%d)\n", ia64_boot_param->fpswa, major, minor);
 }
 
 /*
@@ -62,27 +67,26 @@
 void
 bust_spinlocks (int yes)
 {
+	int loglevel_save = console_loglevel;
+
 	spin_lock_init(&timerlist_lock);
 	if (yes) {
 		oops_in_progress = 1;
-#ifdef CONFIG_SMP
-		global_irq_lock = 0;	/* Many serial drivers do __global_cli() */
-#endif
-	} else {
-		int loglevel_save = console_loglevel;
+		return;
+	}
+
 #ifdef CONFIG_VT
-		unblank_screen();
+	unblank_screen();
 #endif
-		oops_in_progress = 0;
-		/*
-		 * OK, the message is on the console.  Now we call printk() without
-		 * oops_in_progress set so that printk will give klogd a poke.  Hold onto
-		 * your hats...
-		 */
-		console_loglevel = 15;		/* NMI oopser may have shut the console up */
-		printk(" ");
-		console_loglevel = loglevel_save;
-	}
+	oops_in_progress = 0;
+	/*
+	 * OK, the message is on the console.  Now we call printk() without
+	 * oops_in_progress set so that printk will give klogd a poke.  Hold onto
+	 * your hats...
+	 */
+	console_loglevel = 15;		/* NMI oopser may have shut the console up */
+	printk(" ");
+	console_loglevel = loglevel_save;
 }
 
 void
@@ -93,9 +97,9 @@
 		int lock_owner;
 		int lock_owner_depth;
 	} die = {
-		lock:			SPIN_LOCK_UNLOCKED,
-		lock_owner:		-1,
-		lock_owner_depth:	0
+		.lock =			SPIN_LOCK_UNLOCKED,
+		.lock_owner =		-1,
+		.lock_owner_depth =	0
 	};
 
 	if (die.lock_owner != smp_processor_id()) {
@@ -131,6 +135,8 @@
 	siginfo_t siginfo;
 	int sig, code;
 
+	die_if_kernel("bad break", regs, break_num);
+
 	/* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
 	siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 	siginfo.si_imm = break_num;
@@ -247,10 +253,9 @@
 
 		if (fpu_owner)
 			ia64_flush_fph(fpu_owner);
-
-		ia64_set_fpu_owner(current);
 	}
 #endif /* !CONFIG_SMP */
+	ia64_set_fpu_owner(current);
 	if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
 		__ia64_load_fpu(current->thread.fph);
 		psr->mfh = 0;
@@ -435,7 +440,7 @@
 	unsigned long code, error = isr;
 	struct siginfo siginfo;
 	char buf[128];
-	int result;
+	int result, sig;
 	static const char *reason[] = {
 		"IA-64 Illegal Operation fault",
 		"IA-64 Privileged Operation fault",
@@ -479,6 +484,30 @@
 		break;
 
 	      case 26: /* NaT Consumption */
+		if (user_mode(regs)) {
+			if (((isr >> 4) & 0xf) == 2) {
+				/* NaT page consumption */
+				sig = SIGSEGV;
+				code = SEGV_ACCERR;
+			} else {
+				/* register NaT consumption */
+				sig = SIGILL;
+				code = ILL_ILLOPN;
+			}
+			siginfo.si_signo = sig;
+			siginfo.si_code = code;
+			siginfo.si_errno = 0;
+			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+			siginfo.si_imm = vector;
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_isr = isr;
+			force_sig_info(sig, &siginfo, current);
+			return;
+		} else if (done_with_exception(regs))
+			return;
+		sprintf(buf, "NaT consumption");
+		break;
+
 	      case 31: /* Unsupported Data Reference */
 		if (user_mode(regs)) {
 			siginfo.si_signo = SIGILL;
@@ -491,7 +520,7 @@
 			force_sig_info(SIGILL, &siginfo, current);
 			return;
 		}
-		sprintf(buf, (vector == 26) ? "NaT consumption" : "Unsupported data reference");
+		sprintf(buf, "Unsupported data reference");
 		break;
 
 	      case 29: /* Debug */
@@ -508,16 +537,15 @@
 			if (ia64_psr(regs)->is == 0)
 			  ifa = regs->cr_iip;
 #endif
-			siginfo.si_addr = (void *) ifa;
 			break;
-		      case 35: siginfo.si_code = TRAP_BRANCH; break;
-		      case 36: siginfo.si_code = TRAP_TRACE; break;
+		      case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
+		      case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
 		}
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_flags = 0;
 		siginfo.si_isr = 0;
-		siginfo.si_addr = 0;
+		siginfo.si_addr = (void *) ifa;
 		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 		return;
diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/kernel/unwind.c	Tue Aug 27 12:28:08 2002
@@ -140,13 +140,13 @@
 	} stat;
 # endif
 } unw = {
-	tables: &unw.kernel_table,
-	lock: SPIN_LOCK_UNLOCKED,
-	save_order: {
+	.tables = &unw.kernel_table,
+	.lock = SPIN_LOCK_UNLOCKED,
+	.save_order = {
 		UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
 		UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
 	},
-	preg_index: {
+	.preg_index = {
 		struct_offset(struct unw_frame_info, pri_unat_loc)/8,	/* PRI_UNAT_GR */
 		struct_offset(struct unw_frame_info, pri_unat_loc)/8,	/* PRI_UNAT_MEM */
 		struct_offset(struct unw_frame_info, bsp_loc)/8,
@@ -189,9 +189,9 @@
 		struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8,
 		struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8,
 	},
-	hash : { [0 ... UNW_HASH_SIZE - 1] = -1 },
+	.hash = { [0 ... UNW_HASH_SIZE - 1] = -1 },
 #if UNW_DEBUG
-	preg_name: {
+	.preg_name = {
 		"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",
 		"r4", "r5", "r6", "r7",
 		"ar.unat", "pr", "ar.lc", "ar.fpsr",
@@ -634,8 +634,8 @@
 	for (reg = hi; reg >= lo; --reg) {
 		if (reg->where == UNW_WHERE_SPILL_HOME) {
 			reg->where = UNW_WHERE_PSPREL;
-			reg->val = 0x10 - *offp;
-			*offp += regsize;
+			*offp -= regsize;
+			reg->val = *offp;
 		}
 	}
 }
@@ -814,7 +814,8 @@
 	}
 	for (i = 0; i < 20; ++i) {
 		if ((frmask & 1) != 0) {
-			set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME,
+			int base = (i < 4) ? UNW_REG_F2 : UNW_REG_F16 - 4;
+			set_reg(sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME,
 				sr->region_start + sr->region_len - 1, 0);
 			sr->any_spills = 1;
 		}
diff -Nru a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
--- a/arch/ia64/lib/Makefile	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/lib/Makefile	Tue Aug 27 12:28:08 2002
@@ -6,43 +6,51 @@
 
 export-objs := swiotlb.o
 
-obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
-	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o copy_page.o				\
-	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
-	flush.o io.o ip_fast_csum.o do_csum.o						\
-	memcpy.o memset.o strlen.o swiotlb.o
+obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o			\
+	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o			\
+	checksum.o clear_page.o csum_partial_copy.o copy_page.o		\
+	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
+	flush.o io.o ip_fast_csum.o do_csum.o				\
+	memset.o strlen.o swiotlb.o
 
-obj-$(CONFIG_ITANIUM) += copy_page.o
-obj-$(CONFIG_MCKINLEY) += copy_page_mck.o
+obj-$(CONFIG_ITANIUM)	+= copy_page.o copy_user.o memcpy.o
+obj-$(CONFIG_MCKINLEY)	+= copy_page_mck.o memcpy_mck.o
 
 IGNORE_FLAGS_OBJS =	__divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
 			__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o
 
-$(L_TARGET): $(obj-y) $(export-objs)
+include $(TOPDIR)/Rules.make
+
+AFLAGS___divdi3.o	=
+AFLAGS___udivdi3.o	= -DUNSIGNED
+AFLAGS___moddi3.o	= 	     -DMODULO
+AFLAGS___umoddi3.o	= -DUNSIGNED -DMODULO
+
+AFLAGS___divsi3.o	=
+AFLAGS___udivsi3.o	= -DUNSIGNED
+AFLAGS___modsi3.o	=	     -DMODULO
+AFLAGS___umodsi3.o	= -DUNSIGNED -DMODULO
 
 __divdi3.o: idiv64.S
-	$(CC) $(AFLAGS) -c -o $@ $<
+	$(cmd_as_o_S)
 
 __udivdi3.o: idiv64.S
-	$(CC) $(AFLAGS) -c -DUNSIGNED -c -o $@ $<
+	$(cmd_as_o_S)
 
 __moddi3.o: idiv64.S
-	$(CC) $(AFLAGS) -c -DMODULO -c -o $@ $<
+	$(cmd_as_o_S)
 
 __umoddi3.o: idiv64.S
-	$(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -c -o $@ $<
+	$(cmd_as_o_S)
 
 __divsi3.o: idiv32.S
-	$(CC) $(AFLAGS) -c -o $@ $<
+	$(cmd_as_o_S)
 
 __udivsi3.o: idiv32.S
-	$(CC) $(AFLAGS) -c -DUNSIGNED -c -o $@ $<
+	$(cmd_as_o_S)
 
 __modsi3.o: idiv32.S
-	$(CC) $(AFLAGS) -c -DMODULO -c -o $@ $<
+	$(cmd_as_o_S)
 
 __umodsi3.o: idiv32.S
-	$(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -c -o $@ $<
-
-include $(TOPDIR)/Rules.make
+	$(cmd_as_o_S)
diff -Nru a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S
--- a/arch/ia64/lib/copy_user.S	Tue Aug 27 12:28:01 2002
+++ b/arch/ia64/lib/copy_user.S	Tue Aug 27 12:28:01 2002
@@ -237,15 +237,17 @@
 .copy_user_bit##rshift:						\
 1:								\
 	EX(.failure_out,(EPI) st8 [dst1]=tmp,8);		\
-(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
-	EX(3f,(p16) ld8 val1[0]=[src1],8);			\
+(EPI_1) shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift;	\
+	EX(3f,(p16) ld8 val1[1]=[src1],8);			\
+(p16)	mov val1[0]=r0;						\
 	br.ctop.dptk 1b;					\
 	;;							\
 	br.cond.sptk.many .diff_align_do_tail;			\
 2:								\
 (EPI)	st8 [dst1]=tmp,8;					\
-(EPI_1)	shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
+(EPI_1)	shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift;	\
 3:								\
+(p16)	mov val1[1]=r0;						\
 (p16)	mov val1[0]=r0;						\
 	br.ctop.dptk 2b;					\
 	;;							\
diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c
--- a/arch/ia64/lib/io.c	Tue Aug 27 12:27:42 2002
+++ b/arch/ia64/lib/io.c	Tue Aug 27 12:27:42 2002
@@ -87,6 +87,12 @@
 	__ia64_outl(val, port);
 }
 
+void
+ia64_mmiob (void)
+{
+	__ia64_mmiob();
+}
+
 /* define aliases: */
 
 asm (".global __ia64_inb, __ia64_inw, __ia64_inl");
@@ -98,5 +104,8 @@
 asm ("__ia64_outb = ia64_outb");
 asm ("__ia64_outw = ia64_outw");
 asm ("__ia64_outl = ia64_outl");
+
+asm (".global __ia64_mmiob");
+asm ("__ia64_mmiob = ia64_mmiob");
 
 #endif /* CONFIG_IA64_GENERIC */
diff -Nru a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/lib/memcpy_mck.S	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,674 @@
+/*
+ * Itanium 2-optimized version of memcpy and copy_user function
+ *
+ * Inputs:
+ * 	in0:	destination address
+ *	in1:	source address
+ *	in2:	number of bytes to copy
+ * Output:
+ * 	0 if success, or number of byte NOT copied if error occurred.
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
+ */
+#include <linux/config.h>
+#include <asm/asmmacro.h>
+#include <asm/page.h>
+
+#if __GNUC__ >= 3
+# define EK(y...) EX(y)
+#else
+# define EK(y,x...)  x
+#endif
+
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)
+
+/* McKinley specific optimization */
+
+#define retval		r8
+#define saved_pfs	r31
+#define saved_lc	r10
+#define saved_pr	r11
+#define saved_in0	r14
+#define saved_in1	r15
+#define saved_in2	r16
+
+#define src0		r2
+#define src1		r3
+#define dst0		r17
+#define dst1		r18
+#define cnt		r9
+
+/* r19-r30 are temp for each code section */
+#define PREFETCH_DIST	8
+#define src_pre_mem	r19
+#define dst_pre_mem	r20
+#define src_pre_l2	r21
+#define dst_pre_l2	r22
+#define t1		r23
+#define t2		r24
+#define t3		r25
+#define t4		r26
+#define t5		t1	// alias!
+#define t6		t2	// alias!
+#define t7		t3	// alias!
+#define n8		r27
+#define t9		t5	// alias!
+#define t10		t4	// alias!
+#define t11		t7	// alias!
+#define t12		t6	// alias!
+#define t14		t10	// alias!
+#define t13		r28
+#define t15		r29
+#define tmp		r30
+
+/* defines for long_copy block */
+#define	A	0
+#define B	(PREFETCH_DIST)
+#define C	(B + PREFETCH_DIST)
+#define D	(C + 1)
+#define N	(D + 1)
+#define Nrot	((N + 7) & ~7)
+
+/* alias */
+#define in0		r32
+#define in1		r33
+#define in2		r34
+
+GLOBAL_ENTRY(memcpy)
+	and	r28=0x7,in0
+	and	r29=0x7,in1
+	mov	f6=f0
+	br.cond.sptk .common_code
+	;;
+GLOBAL_ENTRY(__copy_user)
+	.prologue
+// check dest alignment
+	and	r28=0x7,in0
+	and	r29=0x7,in1
+	mov	f6=f1
+	mov	saved_in0=in0	// save dest pointer
+	mov	saved_in1=in1	// save src pointer
+	mov	saved_in2=in2	// save len
+	;;
+.common_code:
+	cmp.gt	p15,p0=8,in2	// check for small size
+	cmp.ne	p13,p0=0,r28	// check dest alignment
+	cmp.ne	p14,p0=0,r29	// check src alignment
+	add	src0=0,in1
+	sub	r30=8,r28	// for .align_dest
+	mov	retval=r0	// initialize return value
+	;;
+	add	dst0=0,in0
+	add	dst1=1,in0	// dest odd index
+	cmp.le	p6,p0 = 1,r30	// for .align_dest
+(p15)	br.cond.dpnt .memcpy_short
+(p13)	br.cond.dpnt .align_dest
+(p14)	br.cond.dpnt .unaligned_src
+	;;
+
+// both dest and src are aligned on 8-byte boundary
+.aligned_src:
+	.save ar.pfs, saved_pfs
+	alloc	saved_pfs=ar.pfs,3,Nrot-3,0,Nrot
+	.save pr, saved_pr
+	mov	saved_pr=pr
+
+	shr.u	cnt=in2,7	// this much cache line
+	;;
+	cmp.lt	p6,p0=2*PREFETCH_DIST,cnt
+	cmp.lt	p7,p8=1,cnt
+	.save ar.lc, saved_lc
+	mov	saved_lc=ar.lc
+	.body
+	add	cnt=-1,cnt
+	add	src_pre_mem=0,in1	// prefetch src pointer
+	add	dst_pre_mem=0,in0	// prefetch dest pointer
+	;;
+(p7)	mov	ar.lc=cnt	// prefetch count
+(p8)	mov	ar.lc=r0
+(p6)	br.cond.dpnt .long_copy
+	;;
+
+.prefetch:
+	lfetch.fault	  [src_pre_mem], 128
+	lfetch.fault.excl [dst_pre_mem], 128
+	br.cloop.dptk.few .prefetch
+	;;
+
+.medium_copy:
+	and	tmp=31,in2	// copy length after iteration
+	shr.u	r29=in2,5	// number of 32-byte iteration
+	add	dst1=8,dst0	// 2nd dest pointer
+	;;
+	add	cnt=-1,r29	// ctop iteration adjustment
+	cmp.eq	p10,p0=r29,r0	// do we really need to loop?
+	add	src1=8,src0	// 2nd src pointer
+	cmp.le	p6,p0=8,tmp
+	;;
+	cmp.le	p7,p0=16,tmp
+	mov	ar.lc=cnt	// loop setup
+	cmp.eq	p16,p17 = r0,r0
+	mov	ar.ec=2
+(p10)	br.dpnt.few .aligned_src_tail
+	;;
+	.align 32
+1:
+EX(.ex_handler, (p16)	ld8	r34=[src0],16)
+EK(.ex_handler, (p16)	ld8	r38=[src1],16)
+EX(.ex_handler, (p17)	st8	[dst0]=r33,16)
+EK(.ex_handler, (p17)	st8	[dst1]=r37,16)
+	;;
+EX(.ex_handler, (p16)	ld8	r32=[src0],16)
+EK(.ex_handler, (p16)	ld8	r36=[src1],16)
+EX(.ex_handler, (p16)	st8	[dst0]=r34,16)
+EK(.ex_handler, (p16)	st8	[dst1]=r38,16)
+	br.ctop.dptk.few 1b
+	;;
+
+.aligned_src_tail:
+EX(.ex_handler, (p6)	ld8	t1=[src0])
+	mov	ar.lc=saved_lc
+	mov	ar.pfs=saved_pfs
+EX(.ex_hndlr_s, (p7)	ld8	t2=[src1],8)
+	cmp.le	p8,p0=24,tmp
+	and	r21=-8,tmp
+	;;
+EX(.ex_hndlr_s, (p8)	ld8	t3=[src1])
+EX(.ex_handler, (p6)	st8	[dst0]=t1)	// store byte 1
+	and	in2=7,tmp	// remaining length
+EX(.ex_hndlr_d, (p7)	st8	[dst1]=t2,8)	// store byte 2
+	add	src0=src0,r21	// setting up src pointer
+	add	dst0=dst0,r21	// setting up dest pointer
+	;;
+EX(.ex_handler, (p8)	st8	[dst1]=t3)	// store byte 3
+	mov	pr=saved_pr,-1
+	br.dptk.many .memcpy_short
+	;;
+
+/* code taken from copy_page_mck */
+.long_copy:
+	.rotr v[2*PREFETCH_DIST]
+	.rotp p[N]
+
+	mov src_pre_mem = src0
+	mov pr.rot = 0x10000
+	mov ar.ec = 1				// special unrolled loop
+
+	mov dst_pre_mem = dst0
+
+	add src_pre_l2 = 8*8, src0
+	add dst_pre_l2 = 8*8, dst0
+	;;
+	add src0 = 8, src_pre_mem		// first t1 src
+	mov ar.lc = 2*PREFETCH_DIST - 1
+	shr.u cnt=in2,7				// number of lines
+	add src1 = 3*8, src_pre_mem		// first t3 src
+	add dst0 = 8, dst_pre_mem		// first t1 dst
+	add dst1 = 3*8, dst_pre_mem		// first t3 dst
+	;;
+	and tmp=127,in2				// remaining bytes after this block
+	add cnt = -(2*PREFETCH_DIST) - 1, cnt
+	// same as .line_copy loop, but with all predicated-off instructions removed:
+.prefetch_loop:
+EX(.ex_hndlr_lcpy_1, (p[A])	ld8 v[A] = [src_pre_mem], 128)		// M0
+EK(.ex_hndlr_lcpy_1, (p[B])	st8 [dst_pre_mem] = v[B], 128)		// M2
+	br.ctop.sptk .prefetch_loop
+	;;
+	cmp.eq p16, p0 = r0, r0			// reset p16 to 1
+	mov ar.lc = cnt
+	mov ar.ec = N				// # of stages in pipeline
+	;;
+.line_copy:
+EX(.ex_handler,	(p[D])	ld8 t2 = [src0], 3*8)			// M0
+EK(.ex_handler,	(p[D])	ld8 t4 = [src1], 3*8)			// M1
+EX(.ex_handler_lcpy,	(p[B])	st8 [dst_pre_mem] = v[B], 128)		// M2 prefetch dst from memory
+EK(.ex_handler_lcpy,	(p[D])	st8 [dst_pre_l2] = n8, 128)		// M3 prefetch dst from L2
+	;;
+EX(.ex_handler_lcpy,	(p[A])	ld8 v[A] = [src_pre_mem], 128)		// M0 prefetch src from memory
+EK(.ex_handler_lcpy,	(p[C])	ld8 n8 = [src_pre_l2], 128)		// M1 prefetch src from L2
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t1, 8)			// M2
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t3, 8)			// M3
+	;;
+EX(.ex_handler,	(p[D])	ld8  t5 = [src0], 8)
+EK(.ex_handler,	(p[D])	ld8  t7 = [src1], 3*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t2, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t4, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8  t6 = [src0], 3*8)
+EK(.ex_handler,	(p[D])	ld8 t10 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t5, 8)
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t7, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8  t9 = [src0], 3*8)
+EK(.ex_handler,	(p[D])	ld8 t11 = [src1], 3*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t6, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t10, 8)
+	;;
+EX(.ex_handler,	(p[D])	ld8 t12 = [src0], 8)
+EK(.ex_handler,	(p[D])	ld8 t14 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t9, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t11, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8 t13 = [src0], 4*8)
+EK(.ex_handler,	(p[D])	ld8 t15 = [src1], 4*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] = t12, 8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t14, 8)
+	;;
+EX(.ex_handler,	(p[C])	ld8  t1 = [src0], 8)
+EK(.ex_handler,	(p[C])	ld8  t3 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] = t13, 4*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t15, 4*8)
+	br.ctop.sptk .line_copy
+	;;
+
+	add dst0=-8,dst0
+	add src0=-8,src0
+	mov in2=tmp
+	.restore sp
+	br.sptk.many .medium_copy
+	;;
+
+#define BLOCK_SIZE	128*32
+#define blocksize	r23
+#define curlen		r24
+
+// dest is on 8-byte boundary, src is not. We need to do
+// ld8-ld8, shrp, then st8.  Max 8 byte copy per cycle.
+.unaligned_src:
+	.prologue
+	.save ar.pfs, saved_pfs
+	alloc	saved_pfs=ar.pfs,3,5,0,8
+	.save ar.lc, saved_lc
+	mov	saved_lc=ar.lc
+	.save pr, saved_pr
+	mov	saved_pr=pr
+	.body
+.4k_block:
+	mov	saved_in0=dst0	// need to save all input arguments
+	mov	saved_in2=in2
+	mov	blocksize=BLOCK_SIZE
+	;;
+	cmp.lt	p6,p7=blocksize,in2
+	mov	saved_in1=src0
+	;;
+(p6)	mov	in2=blocksize
+	;;
+	shr.u	r21=in2,7	// this much cache line
+	shr.u	r22=in2,4	// number of 16-byte iteration
+	and	curlen=15,in2	// copy length after iteration
+	and	r30=7,src0	// source alignment
+	;;
+	cmp.lt	p7,p8=1,r21
+	add	cnt=-1,r21
+	;;
+
+	add	src_pre_mem=0,src0	// prefetch src pointer
+	add	dst_pre_mem=0,dst0	// prefetch dest pointer
+	and	src0=-8,src0		// 1st src pointer
+(p7)	mov	ar.lc = r21
+(p8)	mov	ar.lc = r0
+	;;
+	.align 32
+1:	lfetch.fault	  [src_pre_mem], 128
+	lfetch.fault.excl [dst_pre_mem], 128
+	br.cloop.dptk.few 1b
+	;;
+
+	shladd	dst1=r22,3,dst0	// 2nd dest pointer
+	shladd	src1=r22,3,src0	// 2nd src pointer
+	cmp.eq	p8,p9=r22,r0	// do we really need to loop?
+	cmp.le	p6,p7=8,curlen;	// have at least 8 byte remaining?
+	add	cnt=-1,r22	// ctop iteration adjustment
+	;;
+EX(.ex_handler, (p9)	ld8	r33=[src0],8)	// loop primer
+EK(.ex_handler, (p9)	ld8	r37=[src1],8)
+(p8)	br.dpnt.few .noloop
+	;;
+
+// The jump address is calculated based on src alignment. The COPYU
+// macro below need to confine its size to power of two, so an entry
+// can be caulated using shl instead of an expensive multiply. The
+// size is then hard coded by the following #define to match the
+// actual size.  This make it somewhat tedious when COPYU macro gets
+// changed and this need to be adjusted to match.
+#define LOOP_SIZE 6
+1:
+	mov	r29=ip		// jmp_table thread
+	mov	ar.lc=cnt
+	;;
+	add	r29=.jump_table - 1b - (.jmp1-.jump_table), r29
+	shl	r28=r30, LOOP_SIZE	// jmp_table thread
+	mov	ar.ec=2		// loop setup
+	;;
+	add	r29=r29,r28		// jmp_table thread
+	cmp.eq	p16,p17=r0,r0
+	;;
+	mov	b6=r29			// jmp_table thread
+	;;
+	br.cond.sptk.few b6
+
+// for 8-15 byte case
+// We will skip the loop, but need to replicate the side effect
+// that the loop produces.
+.noloop:
+EX(.ex_handler, (p6)	ld8	r37=[src1],8)
+	add	src0=8,src0
+(p6)	shl	r25=r30,3
+	;;
+EX(.ex_handler, (p6)	ld8	r27=[src1])
+(p6)	shr.u	r28=r37,r25
+(p6)	sub	r26=64,r25
+	;;
+(p6)	shl	r27=r27,r26
+	;;
+(p6)	or	r21=r28,r27
+
+.unaligned_src_tail:
+/* check if we have more than blocksize to copy, if so go back */
+	cmp.gt	p8,p0=saved_in2,blocksize
+	;;
+(p8)	add	dst0=saved_in0,blocksize
+(p8)	add	src0=saved_in1,blocksize
+(p8)	sub	in2=saved_in2,blocksize
+(p8)	br.dpnt	.4k_block
+	;;
+
+/* we have up to 15 byte to copy in the tail.
+ * part of work is already done in the jump table code
+ * we are at the following state.
+ * src side:
+ * 
+ *   xxxxxx xx                   <----- r21 has xxxxxxxx already
+ * -------- -------- --------
+ * 0        8        16
+ *          ^
+ *          |
+ *          src1
+ * 
+ * dst
+ * -------- -------- --------
+ * ^
+ * |
+ * dst1
+ */
+EX(.ex_handler, (p6)	st8	[dst1]=r21,8)	// more than 8 byte to copy
+(p6)	add	curlen=-8,curlen	// update length
+	mov	ar.pfs=saved_pfs
+	;;
+	mov	ar.lc=saved_lc
+	mov	pr=saved_pr,-1
+	mov	in2=curlen	// remaining length
+	mov	dst0=dst1	// dest pointer
+	add	src0=src1,r30	// forward by src alignment
+	;;
+
+// 7 byte or smaller.
+.memcpy_short:
+	cmp.le	p8,p9   = 1,in2
+	cmp.le	p10,p11 = 2,in2
+	cmp.le	p12,p13 = 3,in2
+	cmp.le	p14,p15 = 4,in2
+	add	src1=1,src0	// second src pointer
+	add	dst1=1,dst0	// second dest pointer
+	;;
+
+EX(.ex_handler_short, (p8)	ld1	t1=[src0],2)
+EK(.ex_handler_short, (p10)	ld1	t2=[src1],2)
+(p9)	br.ret.dpnt rp		// 0 byte copy
+	;;
+
+EX(.ex_handler_short, (p8)	st1	[dst0]=t1,2)
+EK(.ex_handler_short, (p10)	st1	[dst1]=t2,2)
+(p11)	br.ret.dpnt rp		// 1 byte copy
+
+EX(.ex_handler_short, (p12)	ld1	t3=[src0],2)
+EK(.ex_handler_short, (p14)	ld1	t4=[src1],2)
+(p13)	br.ret.dpnt rp		// 2 byte copy
+	;;
+
+	cmp.le	p6,p7   = 5,in2
+	cmp.le	p8,p9   = 6,in2
+	cmp.le	p10,p11 = 7,in2
+
+EX(.ex_handler_short, (p12)	st1	[dst0]=t3,2)
+EK(.ex_handler_short, (p14)	st1	[dst1]=t4,2)
+(p15)	br.ret.dpnt rp		// 3 byte copy
+	;;
+
+EX(.ex_handler_short, (p6)	ld1	t5=[src0],2)
+EK(.ex_handler_short, (p8)	ld1	t6=[src1],2)
+(p7)	br.ret.dpnt rp		// 4 byte copy
+	;;
+
+EX(.ex_handler_short, (p6)	st1	[dst0]=t5,2)
+EK(.ex_handler_short, (p8)	st1	[dst1]=t6,2)
+(p9)	br.ret.dptk rp		// 5 byte copy
+
+EX(.ex_handler_short, (p10)	ld1	t7=[src0],2)
+(p11)	br.ret.dptk rp		// 6 byte copy
+	;;
+
+EX(.ex_handler_short, (p10)	st1	[dst0]=t7,2)
+	br.ret.dptk rp		// done all cases
+
+
+/* Align dest to nearest 8-byte boundary. We know we have at
+ * least 7 bytes to copy, enough to crawl to 8-byte boundary.
+ * Actual number of byte to crawl depend on the dest alignment.
+ * 7 byte or less is taken care at .memcpy_short
+
+ * src0 - source even index
+ * src1 - source  odd index
+ * dst0 - dest even index
+ * dst1 - dest  odd index
+ * r30  - distance to 8-byte boundary
+ */
+
+.align_dest:
+	add	src1=1,in1	// source odd index
+	cmp.le	p7,p0 = 2,r30	// for .align_dest
+	cmp.le	p8,p0 = 3,r30	// for .align_dest
+EX(.ex_handler_short, (p6)	ld1	t1=[src0],2)
+	cmp.le	p9,p0 = 4,r30	// for .align_dest
+	cmp.le	p10,p0 = 5,r30
+	;;
+EX(.ex_handler_short, (p7)	ld1	t2=[src1],2)
+EK(.ex_handler_short, (p8)	ld1	t3=[src0],2)
+	cmp.le	p11,p0 = 6,r30
+EX(.ex_handler_short, (p6)	st1	[dst0] = t1,2)
+	cmp.le	p12,p0 = 7,r30
+	;;
+EX(.ex_handler_short, (p9)	ld1	t4=[src1],2)
+EK(.ex_handler_short, (p10)	ld1	t5=[src0],2)
+EX(.ex_handler_short, (p7)	st1	[dst1] = t2,2)
+EK(.ex_handler_short, (p8)	st1	[dst0] = t3,2)
+	;;
+EX(.ex_handler_short, (p11)	ld1	t6=[src1],2)
+EK(.ex_handler_short, (p12)	ld1	t7=[src0],2)
+	cmp.eq	p6,p7=r28,r29
+EX(.ex_handler_short, (p9)	st1	[dst1] = t4,2)
+EK(.ex_handler_short, (p10)	st1	[dst0] = t5,2)
+	sub	in2=in2,r30
+	;;
+EX(.ex_handler_short, (p11)	st1	[dst1] = t6,2)
+EK(.ex_handler_short, (p12)	st1	[dst0] = t7)
+	add	dst0=in0,r30	// setup arguments
+	add	src0=in1,r30
+(p6)	br.cond.dptk .aligned_src
+(p7)	br.cond.dpnt .unaligned_src
+	;;
+
+/* main loop body in jump table format */
+#define COPYU(shift)									\
+1:											\
+EX(.ex_handler,  (p16)	ld8	r32=[src0],8);		/* 1 */				\
+EK(.ex_handler,  (p16)	ld8	r36=[src1],8);						\
+		 (p17)	shrp	r35=r33,r34,shift;;	/* 1 */				\
+EX(.ex_handler,  (p6)	ld8	r22=[src1]);	/* common, prime for tail section */	\
+		 nop.m	0;								\
+		 (p16)	shrp	r38=r36,r37,shift;					\
+EX(.ex_handler,  (p17)	st8	[dst0]=r35,8);		/* 1 */				\
+EK(.ex_handler,  (p17)	st8	[dst1]=r39,8);						\
+		 br.ctop.dptk.few 1b;;							\
+		 (p7)	add	src1=-8,src1;	/* back out for <8 byte case */		\
+		 shrp	r21=r22,r38,shift;	/* speculative work */			\
+		 br.sptk.few .unaligned_src_tail /* branch out of jump table */		\
+		 ;;
+	.align 32
+.jump_table:
+	COPYU(8)	// unaligned cases
+.jmp1:
+	COPYU(16)
+	COPYU(24)
+	COPYU(32)
+	COPYU(40)
+	COPYU(48)
+	COPYU(56)
+
+#undef A
+#undef B
+#undef C
+#undef D
+END(memcpy)
+
+/*
+ * Due to lack of local tag support in gcc 2.x assembler, it is not clear which
+ * instruction failed in the bundle.  The exception algorithm is that we
+ * first figure out the faulting address, then detect if there is any
+ * progress made on the copy, if so, redo the copy from last known copied
+ * location up to the faulting address (exclusive). In the copy_from_user
+ * case, remaining byte in kernel buffer will be zeroed.
+ *
+ * Take copy_from_user as an example, in the code there are multiple loads
+ * in a bundle and those multiple loads could span over two pages, the
+ * faulting address is calculated as page_round_down(max(src0, src1)).
+ * This is based on knowledge that if we can access one byte in a page, we
+ * can access any byte in that page.
+ *
+ * predicate used in the exception handler:
+ * p6-p7: direction
+ * p10-p11: src faulting addr calculation
+ * p12-p13: dst faulting addr calculation
+ */
+
+#define A	r19
+#define B	r20
+#define C	r21
+#define D	r22
+#define F	r28
+
+#define memset_arg0	r32
+#define memset_arg2	r33
+
+#define saved_retval	loc0
+#define saved_rtlink	loc1
+#define saved_pfs_stack	loc2
+
+.ex_hndlr_s:
+	add	src0=8,src0
+	br.sptk .ex_handler
+	;;
+.ex_hndlr_d:
+	add	dst0=8,dst0
+	br.sptk .ex_handler
+	;;
+.ex_hndlr_lcpy_1:
+	mov	src1=src_pre_mem
+	mov	dst1=dst_pre_mem
+	cmp.gtu	p10,p11=src_pre_mem,saved_in1
+	cmp.gtu	p12,p13=dst_pre_mem,saved_in0
+	;;
+(p10)	add	src0=8,saved_in1
+(p11)	mov	src0=saved_in1
+(p12)	add	dst0=8,saved_in0
+(p13)	mov	dst0=saved_in0
+	br.sptk	.ex_handler
+.ex_handler_lcpy:
+	// in line_copy block, the preload addresses should always ahead
+	// of the other two src/dst pointers.  Furthermore, src1/dst1 should
+	// always ahead of src0/dst0.
+	mov	src1=src_pre_mem
+	mov	dst1=dst_pre_mem
+.ex_handler:
+	mov	pr=saved_pr,-1		// first restore pr, lc, and pfs
+	mov	ar.lc=saved_lc
+	mov	ar.pfs=saved_pfs
+	;;
+.ex_handler_short: // fault occurred in these sections didn't change pr, lc, pfs
+	cmp.ltu	p6,p7=saved_in0, saved_in1	// get the copy direction
+	cmp.ltu	p10,p11=src0,src1
+	cmp.ltu	p12,p13=dst0,dst1
+	fcmp.eq	p8,p0=f6,f0		// is it memcpy?
+	mov	tmp = dst0
+	;;
+(p11)	mov	src1 = src0		// pick the larger of the two
+(p13)	mov	dst0 = dst1		// make dst0 the smaller one
+(p13)	mov	dst1 = tmp		// and dst1 the larger one
+	;;
+(p6)	dep	F = r0,dst1,0,PAGE_SHIFT // usr dst round down to page boundary
+(p7)	dep	F = r0,src1,0,PAGE_SHIFT // usr src round down to page boundary
+	;;
+(p6)	cmp.le	p14,p0=dst0,saved_in0	// no progress has been made on store
+(p7)	cmp.le	p14,p0=src0,saved_in1	// no progress has been made on load
+	mov	retval=saved_in2
+(p8)	ld1	tmp=[src1]		// force an oops for memcpy call
+(p8)	st1	[dst1]=r0		// force an oops for memcpy call
+(p14)	br.ret.sptk.many rp
+
+/*
+ * The remaining byte to copy is calculated as:
+ *
+ * A =	(faulting_addr - orig_src)	-> len to faulting ld address
+ *	or 
+ * 	(faulting_addr - orig_dst)	-> len to faulting st address
+ * B =	(cur_dst - orig_dst)		-> len copied so far
+ * C =	A - B				-> len need to be copied
+ * D =	orig_len - A			-> len need to be zeroed
+ */
+(p6)	sub	A = F, saved_in0
+(p7)	sub	A = F, saved_in1
+	clrrrb
+	;;
+	alloc	saved_pfs_stack=ar.pfs,3,3,3,0
+	sub	B = dst0, saved_in0	// how many byte copied so far
+	;;
+	sub	C = A, B
+	sub	D = saved_in2, A
+	;;
+	cmp.gt	p8,p0=C,r0		// more than 1 byte?
+	add	memset_arg0=saved_in0, A
+(p6)	mov	memset_arg2=0		// copy_to_user should not call memset
+(p7)	mov	memset_arg2=D		// copy_from_user need to have kbuf zeroed
+	mov	r8=0
+	mov	saved_retval = D
+	mov	saved_rtlink = b0
+
+	add	out0=saved_in0, B
+	add	out1=saved_in1, B
+	mov	out2=C
+(p8)	br.call.sptk.few b0=__copy_user	// recursive call
+	;;
+
+	add	saved_retval=saved_retval,r8	// above might return non-zero value
+	cmp.gt	p8,p0=memset_arg2,r0	// more than 1 byte?
+	mov	out0=memset_arg0	// *s
+	mov	out1=r0			// c
+	mov	out2=memset_arg2	// n
+(p8)	br.call.sptk.few b0=memset
+	;;
+
+	mov	retval=saved_retval
+	mov	ar.pfs=saved_pfs_stack
+	mov	b0=saved_rtlink
+	br.ret.sptk.many rp
+
+/* end of McKinley specific optimization */
+END(__copy_user)
diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/lib/swiotlb.c	Tue Aug 27 12:28:08 2002
@@ -415,18 +415,21 @@
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
 	void *addr;
+	unsigned long pci_addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
-		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
-			sg->page = virt_to_page(addr);
-			sg->offset = (u64) addr & ~PAGE_MASK;
-		}
+		addr = SG_ENT_VIRT_ADDRESS(sg);
+		pci_addr = virt_to_phys(addr);
+		if ((pci_addr & ~hwdev->dma_mask) != 0)
+			sg->dma_address = (dma_addr_t)
+				map_single(hwdev, addr, sg->length, direction);
+		else
+			sg->dma_address = pci_addr;
+		sg->dma_length = sg->length;
 	}
 	return nelems;
 }
@@ -444,12 +447,10 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
-			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-			sg->page = virt_to_page(sg->orig_address);
-			sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
-		} else if (direction == PCI_DMA_FROMDEVICE)
-			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
+		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
+			unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction);
+		else if (direction == PCI_DMA_FROMDEVICE)
+			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
 /*
@@ -468,14 +469,14 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
-			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
+		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
+			sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction);
 }
 
 unsigned long
 swiotlb_dma_address (struct scatterlist *sg)
 {
-	return SG_ENT_PHYS_ADDRESS(sg);
+	return sg->dma_address;
 }
 
 /*
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ia64/mm/init.c	Tue Aug 27 12:28:05 2002
@@ -10,6 +10,7 @@
 
 #include <linux/bootmem.h>
 #include <linux/mm.h>
+#include <linux/personality.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -68,10 +69,9 @@
 	struct vm_area_struct *vma;
 
 	/*
-	 * If we're out of memory and kmem_cache_alloc() returns NULL,
-	 * we simply ignore the problem.  When the process attempts to
-	 * write to the register backing store for the first time, it
-	 * will get a SEGFAULT in this case.
+	 * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore
+	 * the problem.  When the process attempts to write to the register backing store
+	 * for the first time, it will get a SEGFAULT in this case.
 	 */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (vma) {
@@ -86,6 +86,19 @@
 		vma->vm_private_data = NULL;
 		insert_vm_struct(current->mm, vma);
 	}
+
+	/* map NaT-page at address zero to speed up speculative dereferencing of NULL: */
+	if (!(current->personality & MMAP_PAGE_ZERO)) {
+		vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+		if (vma) {
+			memset(vma, 0, sizeof(*vma));
+			vma->vm_mm = current->mm;
+			vma->vm_end = PAGE_SIZE;
+			vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT);
+			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED;
+			insert_vm_struct(current->mm, vma);
+		}
+	}
 }
 
 void
@@ -95,7 +108,7 @@
 
 	addr = (unsigned long) &__init_begin;
 	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
-		clear_bit(PG_reserved, &virt_to_page(addr)->flags);
+		ClearPageReserved(virt_to_page(addr));
 		set_page_count(virt_to_page(addr), 1);
 		free_page(addr);
 		++totalram_pages;
@@ -149,9 +162,9 @@
 		if (!virt_addr_valid(start))
 			continue;
 		page = virt_to_page(start);
-		clear_bit(PG_reserved, &page->flags);
+		ClearPageReserved(page);
 		set_page_count(page, 1);
-		__free_page(page);
+		free_page(start);
 		++totalram_pages;
 	}
 }
diff -Nru a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
--- a/arch/ia64/mm/tlb.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/mm/tlb.c	Tue Aug 27 12:28:08 2002
@@ -35,12 +35,14 @@
 		1 << _PAGE_SIZE_4K )
 
 struct ia64_ctx ia64_ctx = {
-	lock:	SPIN_LOCK_UNLOCKED,
-	next:	1,
-	limit:	(1 << 15) - 1,		/* start out with the safe (architected) limit */
-	max_ctx: ~0U
+	.lock =		SPIN_LOCK_UNLOCKED,
+	.next =		1,
+	.limit =	(1 << 15) - 1,		/* start out with the safe (architected) limit */
+	.max_ctx =	~0U
 };
 
+u8 ia64_need_tlb_flush __per_cpu_data;
+
 /*
  * Acquire the ia64_ctx.lock before calling this function!
  */
@@ -49,6 +51,7 @@
 {
 	unsigned long tsk_context, max_ctx = ia64_ctx.max_ctx;
 	struct task_struct *tsk;
+	int i;
 
 	if (ia64_ctx.next > max_ctx)
 		ia64_ctx.next = 300;	/* skip daemons */
@@ -77,7 +80,11 @@
 			ia64_ctx.limit = tsk_context;
 	}
 	read_unlock(&tasklist_lock);
-	flush_tlb_all();
+	/* can't call flush_tlb_all() here because of race condition with O(1) scheduler [EF] */
+	for (i = 0; i < NR_CPUS; ++i)
+		if (i != smp_processor_id())
+			per_cpu(ia64_need_tlb_flush, i) = 1;
+	__flush_tlb_all();
 }
 
 void
diff -Nru a/arch/ia64/sn/fakeprom/Makefile b/arch/ia64/sn/fakeprom/Makefile
--- a/arch/ia64/sn/fakeprom/Makefile	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/sn/fakeprom/Makefile	Tue Aug 27 12:28:08 2002
@@ -7,7 +7,6 @@
 #
 
 TOPDIR=../../../..
-HPATH           = $(TOPDIR)/include
 
 LIB     = ../../lib/lib.a
 
diff -Nru a/arch/ia64/sn/io/ifconfig_net.c b/arch/ia64/sn/io/ifconfig_net.c
--- a/arch/ia64/sn/io/ifconfig_net.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/sn/io/ifconfig_net.c	Tue Aug 27 12:28:02 2002
@@ -279,9 +279,9 @@
 }
 
 struct file_operations ifconfig_net_fops = {
-	ioctl:ifconfig_net_ioctl,	/* ioctl */
-	open:ifconfig_net_open,		/* open */
-	release:ifconfig_net_close	/* release */
+	.ioctl =ifconfig_net_ioctl,	/* ioctl */
+	.open =ifconfig_net_open,		/* open */
+	.release =ifconfig_net_close	/* release */
 };
 
 
diff -Nru a/arch/ia64/sn/io/pciba.c b/arch/ia64/sn/io/pciba.c
--- a/arch/ia64/sn/io/pciba.c	Tue Aug 27 12:27:57 2002
+++ b/arch/ia64/sn/io/pciba.c	Tue Aug 27 12:27:57 2002
@@ -210,31 +210,31 @@
 
 /* file operations for each type of node */
 static struct file_operations rom_fops = {
-	owner:		THIS_MODULE,
-	mmap:		rom_mmap,
-	open:		generic_open,
-	release:	rom_release
+	.owner =	THIS_MODULE,
+	.mmap =		rom_mmap,
+	.open =		generic_open,
+	.release =	rom_release
 };
  
 
 static struct file_operations base_fops = {
-	owner:		THIS_MODULE,
-	mmap:		base_mmap,
-	open:		generic_open
+	.owner =	THIS_MODULE,
+	.mmap =		base_mmap,
+	.open =		generic_open
 };
 
 
 static struct file_operations config_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		config_ioctl,
-	open:		generic_open
+	.owner =	THIS_MODULE,
+	.ioctl =	config_ioctl,
+	.open =		generic_open
 };	
 
 static struct file_operations dma_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		dma_ioctl,
-	mmap:		dma_mmap,
-	open:		generic_open
+	.owner =	THIS_MODULE,
+	.ioctl =	dma_ioctl,
+	.mmap =		dma_mmap,
+	.open =		generic_open
 };	
 
 
diff -Nru a/arch/ia64/sn/io/sn1/hubcounters.c b/arch/ia64/sn/io/sn1/hubcounters.c
--- a/arch/ia64/sn/io/sn1/hubcounters.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/sn/io/sn1/hubcounters.c	Tue Aug 27 12:28:02 2002
@@ -24,7 +24,7 @@
 
 static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 struct file_operations hub_mon_fops = {
-        ioctl:          hubstats_ioctl,
+        .ioctl =        hubstats_ioctl,
 };
 
 #define HUB_CAPTURE_TICKS	(2 * HZ)
diff -Nru a/arch/ia64/sn/io/sn1/pcibr.c b/arch/ia64/sn/io/sn1/pcibr.c
--- a/arch/ia64/sn/io/sn1/pcibr.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ia64/sn/io/sn1/pcibr.c	Tue Aug 27 12:28:08 2002
@@ -307,22 +307,22 @@
  * appropriate function name below.
  */
 struct file_operations pcibr_fops = {
-        owner:  THIS_MODULE,
-        llseek: NULL,
-        read: NULL,
-        write: NULL,
-        readdir: NULL,
-        poll: NULL,
-        ioctl: NULL,
-        mmap: NULL,
-        open: NULL,
-        flush: NULL,
-        release: NULL,
-        fsync: NULL,
-        fasync: NULL,
-        lock: NULL,
-        readv: NULL,
-        writev: NULL
+        .owner = THIS_MODULE,
+        .llseek = NULL,
+        .read = NULL,
+        .write = NULL,
+        .readdir = NULL,
+        .poll = NULL,
+        .ioctl = NULL,
+        .mmap = NULL,
+        .open = NULL,
+        .flush = NULL,
+        .release = NULL,
+        .fsync = NULL,
+        .fasync = NULL,
+        .lock = NULL,
+        .readv = NULL,
+        .writev = NULL
 };
 
 extern devfs_handle_t hwgraph_root;
diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c
--- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	Tue Aug 27 12:28:06 2002
+++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	Tue Aug 27 12:28:06 2002
@@ -64,22 +64,22 @@
  * appropriate function name below.
  */
 struct file_operations pcibr_fops = {
-	owner:  THIS_MODULE,
-	llseek: NULL,
-	read: NULL,
-	write: NULL,
-	readdir: NULL,
-	poll: NULL,
-	ioctl: NULL,
-	mmap: NULL,
-	open: NULL,
-	flush: NULL,
-	release: NULL,
-	fsync: NULL,
-	fasync: NULL,
-	lock: NULL,
-	readv: NULL,
-	writev: NULL
+	.owner =THIS_MODULE,
+	.llseek = NULL,
+	.read = NULL,
+	.write = NULL,
+	.readdir = NULL,
+	.poll = NULL,
+	.ioctl = NULL,
+	.mmap = NULL,
+	.open = NULL,
+	.flush = NULL,
+	.release = NULL,
+	.fsync = NULL,
+	.fasync = NULL,
+	.lock = NULL,
+	.readv = NULL,
+	.writev = NULL
 };
 
 #ifdef LATER
diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
--- a/arch/ia64/sn/kernel/setup.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/sn/kernel/setup.c	Tue Aug 27 12:28:02 2002
@@ -109,14 +109,14 @@
  * VGA color display.
  */
 struct screen_info sn1_screen_info = {
-	orig_x:			 0,
-	orig_y:			 0,
-	orig_video_mode:	 3,
-	orig_video_cols:	80,
-	orig_video_ega_bx:	 3,
-	orig_video_lines:	25,
-	orig_video_isVGA:	 1,
-	orig_video_points:	16
+	.orig_x =		 0,
+	.orig_y =		 0,
+	.orig_video_mode =	 3,
+	.orig_video_cols =	80,
+	.orig_video_ega_bx =	 3,
+	.orig_video_lines =	25,
+	.orig_video_isVGA =	 1,
+	.orig_video_points =	16
 };
 
 /*
@@ -170,9 +170,9 @@
 #ifdef NOT_YET_CONFIG_IA64_MCA
 extern void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs);
 static struct irqaction mca_cpe_irqaction = { 
-	handler:    ia64_mca_cpe_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "cpe_hndlr"
+	.handler =  ia64_mca_cpe_int_handler,
+	.flags =    SA_INTERRUPT,
+	.name =     "cpe_hndlr"
 };
 #endif
 #ifdef CONFIG_IA64_MCA
diff -Nru a/arch/ia64/tools/Makefile b/arch/ia64/tools/Makefile
--- a/arch/ia64/tools/Makefile	Tue Aug 27 12:27:40 2002
+++ b/arch/ia64/tools/Makefile	Tue Aug 27 12:27:40 2002
@@ -4,7 +4,9 @@
 
 all:
 
-mrproper:
+fastdep:
+
+mrproper: clean
 
 clean:
 	rm -f print_offsets.s print_offsets offsets.h
diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S
--- a/arch/ia64/vmlinux.lds.S	Tue Aug 27 12:28:02 2002
+++ b/arch/ia64/vmlinux.lds.S	Tue Aug 27 12:28:02 2002
@@ -41,9 +41,6 @@
 
   /* Read-only data */
 
-  . = ALIGN(16);
-  __gp = . + 0x200000;	/* gp must be 16-byte aligned for exc. table */
-
   /* Global data */
   _data = .;
 
@@ -145,6 +142,9 @@
 
   .data : AT(ADDR(.data) - PAGE_OFFSET)
 	{ *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
+
+  . = ALIGN(16);
+  __gp = . + 0x200000;	/* gp must be 16-byte aligned for exc. table */
 
   .got : AT(ADDR(.got) - PAGE_OFFSET)
 	{ *(.got.plt) *(.got) }
diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in
--- a/arch/m68k/config.in	Tue Aug 27 12:28:08 2002
+++ b/arch/m68k/config.in	Tue Aug 27 12:28:08 2002
@@ -152,10 +152,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 if [ "$CONFIG_MAC" = "y" ]; then
    source drivers/input/Config.in
 fi
@@ -271,6 +267,7 @@
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
 
    mainmenu_option next_comment
    comment 'Network device support'
diff -Nru a/arch/mips/config.in b/arch/mips/config.in
--- a/arch/mips/config.in	Tue Aug 27 12:28:07 2002
+++ b/arch/mips/config.in	Tue Aug 27 12:28:07 2002
@@ -218,15 +218,6 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'CPU selection'
 
 choice 'CPU type' \
@@ -334,12 +325,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
 if [ "$CONFIG_SGI_IP22" != "y" -a \
      "$CONFIG_DECSTATION" != "y" ]; then
 
@@ -372,6 +357,8 @@
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -390,6 +377,8 @@
 source net/irda/Config.in
 
 source drivers/isdn/Config.in
+
+source drivers/telephony/Config.in
 
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
--- a/arch/mips/kernel/smp.c	Tue Aug 27 12:28:01 2002
+++ b/arch/mips/kernel/smp.c	Tue Aug 27 12:28:01 2002
@@ -53,7 +53,6 @@
 
 
 /* Ze Big Kernel Lock! */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;  /* Not used */
 int smp_num_cpus;    
 int global_irq_holder = NO_PROC_ID;
diff -Nru a/arch/mips64/Makefile b/arch/mips64/Makefile
--- a/arch/mips64/Makefile	Tue Aug 27 12:28:02 2002
+++ b/arch/mips64/Makefile	Tue Aug 27 12:28:02 2002
@@ -12,7 +12,6 @@
 #
 # Select the object file format to substitute into the linker script.
 #
-CPP=$(CC) -E
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 tool-prefix	= mips64el-linux-
 else
@@ -118,7 +117,7 @@
 #
 ifdef CONFIG_BOOT_ELF32
 CFLAGS += -Wa,-32
-LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/vmlinux.lds.s
 endif
 #
 # The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
@@ -126,7 +125,7 @@
 #
 ifdef CONFIG_BOOT_ELF64
 CFLAGS += -Wa,-32
-LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/vmlinux.lds.s
 #AS += -64
 #LDFLAGS += -m elf64bmip
 #LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf64
@@ -148,9 +147,9 @@
 64bit-bfd = elf64-bigmips
 endif
 
-vmlinux: arch/mips64/ld.script.elf32
-arch/mips64/ld.script.elf32: arch/mips64/ld.script.elf32.S
-	$(CPP) -C -P -I$(HPATH) -imacros $(HPATH)/asm-mips64/sn/mapped_kernel.h -Umips arch/mips64/ld.script.elf32.S > arch/mips64/ld.script.elf32
+vmlinux: arch/mips64/vmlinux.lds.s
+
+CPPFLAGS_arch/mips64/vmlinux.lds.s := -imacros $(srctree)/include/asm-mips64/sn/mapped_kernel.h
 
 ifdef CONFIG_MAPPED_KERNEL
 vmlinux.64: vmlinux
@@ -171,7 +170,6 @@
 archclean:
 	@$(MAKEBOOT) clean
 	$(MAKE) -C arch/$(ARCH)/tools clean
-	rm -f vmlinux.64 arch/$(ARCH)/ld.script.elf32
 
 archmrproper:
 	@$(MAKEBOOT) mrproper
diff -Nru a/arch/mips64/config.in b/arch/mips64/config.in
--- a/arch/mips64/config.in	Tue Aug 27 12:28:01 2002
+++ b/arch/mips64/config.in	Tue Aug 27 12:28:01 2002
@@ -132,12 +132,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
 
@@ -163,6 +157,8 @@
 #source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -181,6 +177,8 @@
 source net/irda/Config.in
 
 source drivers/isdn/Config.in
+
+source drivers/telephony/Config.in
 
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/mips64/kernel/smp.c b/arch/mips64/kernel/smp.c
--- a/arch/mips64/kernel/smp.c	Tue Aug 27 12:28:01 2002
+++ b/arch/mips64/kernel/smp.c	Tue Aug 27 12:28:01 2002
@@ -53,7 +53,6 @@
 #endif /* CONFIG_SGI_IP27 */
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;	/* Not used */
 atomic_t smp_commenced = ATOMIC_INIT(0);
 struct cpuinfo_mips cpu_data[NR_CPUS];
diff -Nru a/arch/mips64/ld.script.elf32.S b/arch/mips64/ld.script.elf32.S
--- a/arch/mips64/ld.script.elf32.S	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,132 +0,0 @@
-OUTPUT_ARCH(mips)
-ENTRY(kernel_entry)
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  .init          : { *(.init)		} =0
-  .text      :
-  {
-    *(.text)
-    *(.rodata)
-    *(.rodata.*)
-    *(.rodata1)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  } =0
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___dbe_table = .;	/* Exception table for data bus errors */
-  __dbe_table : { *(__dbe_table) }
-  __stop___dbe_table = .;
-
-  _etext = .;
-
-  . = ALIGN(16384);
-  . = . + MAPPED_OFFSET; 	/* for CONFIG_MAPPED_KERNEL */
-  .data.init_task : { *(.data.init_task) }
-
-  /* Startup code */
-  . = ALIGN(4096);
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-	*(.initcall1.init) 
-	*(.initcall2.init) 
-	*(.initcall3.init) 
-	*(.initcall4.init) 
-	*(.initcall5.init) 
-	*(.initcall6.init) 
-	*(.initcall7.init)
-  }
-  __initcall_end = .;
-  . = ALIGN(4096);	/* Align double page for init_task_union */
-  __init_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  .fini      : { *(.fini)    } =0
-  .reginfo : { *(.reginfo) }
-  /* Adjust the address for the data segment.  We want to adjust up to
-     the same address within the page on the next page up.  It would
-     be more correct to do this:
-       . = .;
-     The current expression does not correctly handle the case of a
-     text segment ending precisely at the end of a page; it causes the
-     data segment to skip a page.  The above expression does not have
-     this problem, but it will currently (2/95) cause BFD to allocate
-     a single segment, combining both text and data, for this case.
-     This will prevent the text segment from being shared among
-     multiple executions of the program; I think that is more
-     important than losing a page of the virtual address space (note
-     that no actual memory is lost; the page which is skipped can not
-     be referenced).  */
-  . = .;
-  .data    :
-  {
-    _fdata = . ;
-    *(.data)
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  .lit8 : { *(.lit8) }
-  .lit4 : { *(.lit4) }
-  .ctors         : { *(.ctors)   }
-  .dtors         : { *(.dtors)   }
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  _end = . ;
-  }
-
-  /* Sections to be discarded */
-  /DISCARD/ : 
-  {
-        *(.text.exit)
-        *(.data.exit)
-        *(.exitcall.exit)
-  }
-
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* DWARF debug sections.
-     Symbols in the .debug DWARF section are relative to the beginning of the
-     section so we begin .debug at 0.  It's not clear yet what needs to happen
-     for the others.   */
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
-  /* These must appear regardless of  .  */
-  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
-  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-}
diff -Nru a/arch/mips64/vmlinux.lds.S b/arch/mips64/vmlinux.lds.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/mips64/vmlinux.lds.S	Tue Aug 27 12:28:05 2002
@@ -0,0 +1,132 @@
+OUTPUT_ARCH(mips)
+ENTRY(kernel_entry)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .init          : { *(.init)		} =0
+  .text      :
+  {
+    *(.text)
+    *(.rodata)
+    *(.rodata.*)
+    *(.rodata1)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___dbe_table = .;	/* Exception table for data bus errors */
+  __dbe_table : { *(__dbe_table) }
+  __stop___dbe_table = .;
+
+  _etext = .;
+
+  . = ALIGN(16384);
+  . = . + MAPPED_OFFSET; 	/* for CONFIG_MAPPED_KERNEL */
+  .data.init_task : { *(.data.init_task) }
+
+  /* Startup code */
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
+  __initcall_end = .;
+  . = ALIGN(4096);	/* Align double page for init_task_union */
+  __init_end = .;
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  .fini      : { *(.fini)    } =0
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  It would
+     be more correct to do this:
+       . = .;
+     The current expression does not correctly handle the case of a
+     text segment ending precisely at the end of a page; it causes the
+     data segment to skip a page.  The above expression does not have
+     this problem, but it will currently (2/95) cause BFD to allocate
+     a single segment, combining both text and data, for this case.
+     This will prevent the text segment from being shared among
+     multiple executions of the program; I think that is more
+     important than losing a page of the virtual address space (note
+     that no actual memory is lost; the page which is skipped can not
+     be referenced).  */
+  . = .;
+  .data    :
+  {
+    _fdata = . ;
+    *(.data)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .lit8 : { *(.lit8) }
+  .lit4 : { *(.lit4) }
+  .ctors         : { *(.ctors)   }
+  .dtors         : { *(.dtors)   }
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  _end = . ;
+  }
+
+  /* Sections to be discarded */
+  /DISCARD/ : 
+  {
+        *(.text.exit)
+        *(.data.exit)
+        *(.exitcall.exit)
+  }
+
+  /* These are needed for ELF backends which have not yet been
+     converted to the new style linker.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  /* DWARF debug sections.
+     Symbols in the .debug DWARF section are relative to the beginning of the
+     section so we begin .debug at 0.  It's not clear yet what needs to happen
+     for the others.   */
+  .debug          0 : { *(.debug) }
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  .line           0 : { *(.line) }
+  /* These must appear regardless of  .  */
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+}
diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile
--- a/arch/parisc/Makefile	Tue Aug 27 12:28:02 2002
+++ b/arch/parisc/Makefile	Tue Aug 27 12:28:02 2002
@@ -19,7 +19,6 @@
 
 FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
 
-CPP=$(CC) -E
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
 LDFLAGS_vmlinux =-T arch/parisc/vmlinux.lds
 
diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in
--- a/arch/parisc/config.in	Tue Aug 27 12:28:08 2002
+++ b/arch/parisc/config.in	Tue Aug 27 12:28:08 2002
@@ -47,15 +47,6 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all module symbols' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'General setup'
 
 tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
@@ -99,10 +90,6 @@
 
 source drivers/block/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'SCSI support'
 
@@ -149,6 +136,8 @@
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+
   mainmenu_option next_comment
   comment 'Network device support'
 
diff -Nru a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
--- a/arch/parisc/kernel/parisc_ksyms.c	Tue Aug 27 12:28:08 2002
+++ b/arch/parisc/kernel/parisc_ksyms.c	Tue Aug 27 12:28:08 2002
@@ -35,9 +35,6 @@
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
 
-#include <asm/smplock.h>
-EXPORT_SYMBOL(kernel_flag);
-
 #include <asm/system.h>
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
diff -Nru a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c
--- a/arch/ppc/amiga/config.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc/amiga/config.c	Tue Aug 27 12:28:02 2002
@@ -93,7 +93,6 @@
 static void a2000_gettod (int *, int *, int *, int *, int *, int *);
 static int amiga_hwclk (int, struct hwclk_time *);
 static int amiga_set_clock_mmss (unsigned long);
-extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
 #endif
@@ -115,8 +114,6 @@
 	index:		-1,
 };
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
-
 
     /*
      *  Motherboard Resources present in all Amiga models
@@ -432,7 +429,6 @@
 #ifdef CONFIG_DUMMY_CONSOLE
   conswitchp           = &dummy_con;
 #endif
-  kd_mksound           = amiga_mksound;
 #ifdef CONFIG_HEARTBEAT
   mach_heartbeat = amiga_heartbeat;
 #endif
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Tue Aug 27 12:27:42 2002
+++ b/arch/ppc/config.in	Tue Aug 27 12:27:42 2002
@@ -419,10 +419,6 @@
 source drivers/block/Config.in
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'ATA/IDE/MFM/RLL support'
 
@@ -449,6 +445,8 @@
 source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -541,11 +539,6 @@
       if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
          bool '     Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
       fi
-   fi
-   # This is for drivers/macintosh/mac_hid.o, which is needed if the input
-   # layer is used.
-   if [ "$CONFIG_INPUT" != "n" ]; then
-      define_bool CONFIG_MAC_HID y
    fi
    if [ "$CONFIG_ADB_CUDA" != "n" ]; then
       bool 'Support for ANS LCD display' CONFIG_ANSLCD
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc/kernel/misc.S	Tue Aug 27 12:28:02 2002
@@ -1298,6 +1298,12 @@
 	.long sys_sched_getaffinity
 	.long sys_security
 	.long sys_ni_syscall	/* 225 - reserved for Tux */
+	.long sys_sendfile64
+	.long sys_io_setup
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit	/* 230 */
+	.long sys_io_cancel
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Tue Aug 27 12:28:08 2002
@@ -5,8 +5,8 @@
 #include <linux/module.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/elfcore.h>
 #include <linux/sched.h>
+#include <linux/elfcore.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -93,9 +93,6 @@
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(probe_irq_mask);
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(kernel_flag);
-#endif /* CONFIG_SMP */
 
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL_NOVERS(DMA_MODE_READ);
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc/kernel/setup.c	Tue Aug 27 12:28:08 2002
@@ -659,3 +659,100 @@
 	/* this is for modules since _machine can be a define -- Cort */
 	ppc_md.ppc_machine = _machine;
 }
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+ * chars are endian independant, of course, but strings need to be flipped.
+ * (Despite what it says in drivers/block/ide.h, they come up as little
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void ide_fix_driveid(struct hd_driveid *id)
+{
+        int i;
+	unsigned short *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (unsigned short *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (unsigned short *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (unsigned short *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; i++)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+        for (i = 0; i < 4; i++)
+                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; i++)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+}
+#endif
diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
--- a/arch/ppc/kernel/smp.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc/kernel/smp.c	Tue Aug 27 12:28:08 2002
@@ -47,7 +47,6 @@
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 };
 unsigned int prof_counter[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 };
 unsigned long cache_decay_ticks = HZ/100;
diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc/platforms/chrp_setup.c	Tue Aug 27 12:28:02 2002
@@ -68,7 +68,6 @@
 void btext_progress(char *, unsigned short);
 
 extern unsigned long pmac_find_end_of_memory(void);
-extern void select_adb_keyboard(void);
 extern int of_show_percpuinfo(struct seq_file *, int);
 
 extern kdev_t boot_dev;
@@ -437,22 +436,6 @@
 
 	if (ppc_md.progress)
 		ppc_md.progress("  Have fun!    ", 0x7777);
-
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT)
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	{
-		struct device_node *kbd;
-
-		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
-			if (kbd->parent && kbd->parent->type
-			    && strcmp(kbd->parent->type, "adb") == 0) {
-				select_adb_keyboard();
-				break;
-			}
-		}
-	}
-#endif /* CONFIG_VT && CONFIG_INPUT */
 }
 
 void __init
diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc/platforms/pmac_setup.c	Tue Aug 27 12:28:07 2002
@@ -66,7 +66,6 @@
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
 #include <asm/machdep.h>
-#include <asm/keyboard.h>
 #include <asm/dma.h>
 #include <asm/bootx.h>
 #include <asm/cputable.h>
@@ -230,17 +229,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_VT
-/*
- * Dummy mksound function that does nothing.
- * The real one is in the dmasound driver.
- */
-static void __pmac
-pmac_mksound(unsigned int hz, unsigned int ticks)
-{
-}
-#endif /* CONFIG_VT */
-
 static volatile u32 *sysctrl_regs;
 
 void __init
@@ -324,9 +312,6 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
-#ifdef CONFIG_VT
-	kd_mksound = pmac_mksound;
-#endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start)
 		ROOT_DEV = Root_RAM0;
@@ -618,15 +603,6 @@
 }
 
 void __init
-select_adb_keyboard(void)
-{
-#ifdef CONFIG_VT
-	ppc_md.kbd_translate     = mac_hid_kbd_translate;
-	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
-#endif /* CONFIG_VT */
-}
-
-void __init
 pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7)
 {
@@ -665,8 +641,6 @@
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
 
 	ppc_md.feature_call   = pmac_do_feature_call;
-
-	select_adb_keyboard();
 
 #ifdef CONFIG_BOOTX_TEXT
 	ppc_md.progress = pmac_progress;
diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile	Tue Aug 27 12:28:01 2002
+++ b/arch/ppc64/Makefile	Tue Aug 27 12:28:01 2002
@@ -18,9 +18,9 @@
 LDFLAGS		:= -m elf64ppc
 LDFLAGS_vmlinux	= -T arch/ppc64/vmlinux.lds -Bstatic \
 		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
-CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
+CFLAGS		:= $(CFLAGS) -msoft-float -pipe \
 		-Wno-uninitialized -mminimal-toc -mtraceback=full \
-		-Wa,-mpower4 -finline-limit-2000 -mcpu=630
+		-finline-limit-2000 -mcpu=power4
 CPP		= $(CC) -E $(CFLAGS)
 
 
diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
--- a/arch/ppc64/boot/Makefile	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/boot/Makefile	Tue Aug 27 12:28:08 2002
@@ -24,7 +24,7 @@
 #CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux-
 
 BOOTCC = $(CROSS32_COMPILE)gcc
-BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH)
+BOOTCFLAGS = $(HOSTCFLAGS) -I$(objtree)/include
 BOOTLD = $(CROSS32_COMPILE)ld
 BOOTAS = $(CROSS32_COMPILE)as
 BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS)
diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in
--- a/arch/ppc64/config.in	Tue Aug 27 12:28:01 2002
+++ b/arch/ppc64/config.in	Tue Aug 27 12:28:01 2002
@@ -87,10 +87,6 @@
 source drivers/block/Config.in
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
 
@@ -118,6 +114,8 @@
 source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc64/defconfig	Tue Aug 27 12:28:02 2002
@@ -125,7 +125,6 @@
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 CONFIG_IPV6=m
-# CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
 
@@ -156,7 +155,7 @@
 # CONFIG_NET_SCHED is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -434,6 +433,7 @@
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_ACCEL=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
 CONFIG_FBCON_FONTS=y
 CONFIG_FONT_8x8=y
@@ -474,7 +474,6 @@
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_Q40KBD is not set
 # CONFIG_SERIO_PARKBD is not set
 
 #
@@ -487,10 +486,26 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_HVC_CONSOLE=y
@@ -523,6 +538,7 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
+CONFIG_RAW_DRIVER=y
 
 #
 # Multimedia devices
@@ -686,6 +702,11 @@
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
 # CONFIG_PPCDBG is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY_CAPABILITIES=y
 
 #
 # Library routines
diff -Nru a/arch/ppc64/kernel/bitops.c b/arch/ppc64/kernel/bitops.c
--- a/arch/ppc64/kernel/bitops.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/kernel/bitops.c	Tue Aug 27 12:28:07 2002
@@ -45,17 +45,6 @@
 	return result + ffz(tmp);
 }
 
-static __inline__ unsigned long ___ffs(unsigned long word)
-{
-        unsigned long result = 0;
-
-        while (!(word & 1UL)) {
-                result++;
-                word >>= 1;
-        }
-        return result;
-}
-
 unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
 {
 	unsigned long *p = addr + (offset >> 6);
@@ -91,7 +80,7 @@
 	if (tmp == 0UL)        /* Are any bits set? */
 		return result + size; /* Nope. */
 found_middle:
-	return result + ___ffs(tmp);
+	return result + __ffs(tmp);
 }
 
 static __inline__ unsigned int ext2_ilog2(unsigned int x) 
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Tue Aug 27 12:28:06 2002
+++ b/arch/ppc64/kernel/head.S	Tue Aug 27 12:28:06 2002
@@ -1421,7 +1421,7 @@
 	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r4)
+	stfd	fr0,THREAD_FPSCR(r4)
 	ld	r5,PT_REGS(r4)
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
@@ -1430,10 +1430,12 @@
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
-	ld	r4, PACACURRENT(r13)
+	ld	r4,PACACURRENT(r13)
 	addi	r5,r4,THREAD		/* Get THREAD */
-	lfd	fr0,THREAD_FPSCR-4(r5)
+	lwz	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP
+	or	r23,r23,r4
+	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
@@ -1476,7 +1478,7 @@
 	cmpi	0,r5,0
 	SAVE_32FPRS(0, r3)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r3)
+	stfd	fr0,THREAD_FPSCR(r3)
 	beq	1f
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r3,MSR_FP|MSR_FE0|MSR_FE1
diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c
--- a/arch/ppc64/kernel/htab.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/kernel/htab.c	Tue Aug 27 12:28:07 2002
@@ -38,7 +38,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
-#include <asm/system.h>
 #include <asm/pmc.h>
 #include <asm/machdep.h>
 #include <asm/lmb.h>
diff -Nru a/arch/ppc64/kernel/i8259.c b/arch/ppc64/kernel/i8259.c
--- a/arch/ppc64/kernel/i8259.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/i8259.c	Tue Aug 27 12:28:08 2002
@@ -123,7 +123,8 @@
 
 static void i8259_end_irq(unsigned int irq)
 {
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+	    irq_desc[irq].action)
 		i8259_unmask_irq(irq);
 }
 
diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/idle.c	Tue Aug 27 12:28:08 2002
@@ -18,6 +18,7 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
+#include <linux/interrupt.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Tue Aug 27 12:28:05 2002
+++ b/arch/ppc64/kernel/irq.c	Tue Aug 27 12:28:05 2002
@@ -169,10 +169,8 @@
 
 inline void synchronize_irq(unsigned int irq)
 {
-	while (irq_desc[irq].status & IRQ_INPROGRESS) {
-		barrier();
+	while (irq_desc[irq].status & IRQ_INPROGRESS)
 		cpu_relax();
-	}
 }
 
 #endif /* CONFIG_SMP */
@@ -500,7 +498,7 @@
 	 * use the action we have.
 	 */
 	action = NULL;
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
 		action = desc->action;
 		if (!action || !action->handler) {
 			ppc_spurious_interrupts++;
@@ -527,10 +525,9 @@
 	   a different instance of this same irq, the other processor
 	   will take care of it.
 	 */
-	if (!action)
+	if (unlikely(!action))
 		goto out;
 
-
 	/*
 	 * Edge triggered interrupts need to remember
 	 * pending events.
@@ -546,12 +543,12 @@
 		handle_irq_event(irq, regs, action);
 		spin_lock(&desc->lock);
 		
-		if (!(desc->status & IRQ_PENDING))
+		if (likely(!(desc->status & IRQ_PENDING)))
 			break;
 		desc->status &= ~IRQ_PENDING;
 	}
-	desc->status &= ~IRQ_INPROGRESS;
 out:
+	desc->status &= ~IRQ_INPROGRESS;
 	/*
 	 * The ->end() handler has to deal with interrupts which got
 	 * disabled while the handler was running.
@@ -567,7 +564,6 @@
 
 int do_IRQ(struct pt_regs *regs)
 {
-	int cpu = smp_processor_id();
 	int irq, first = 1;
 #ifdef CONFIG_PPC_ISERIES
 	struct paca_struct *lpaca;
@@ -605,7 +601,7 @@
 		ppc_spurious_interrupts++;
 #endif
 
-        irq_exit();
+	irq_exit();
 
 #ifdef CONFIG_PPC_ISERIES
 	if (lpaca->xLpPaca.xIntDword.xFields.xDecrInt) {
@@ -614,9 +610,6 @@
 		timer_interrupt(regs);
 	}
 #endif
-
-	if (softirq_pending(cpu))
-		do_softirq();
 
 	return 1; /* lets ret_from_int know we can do checks */
 }
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc64/kernel/misc.S	Tue Aug 27 12:28:02 2002
@@ -460,21 +460,21 @@
 	blr
 
 _GLOBAL(cvt_fd)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfs	0,0(r3)
 	stfd	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 _GLOBAL(cvt_df)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfd	0,0(r3)
 	stfs	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 /*
@@ -518,8 +518,8 @@
 	.llong .sys32_execve
 	.llong .sys_chdir
 	.llong .sys32_time
-	.llong .sys32_mknod
-	.llong .sys32_chmod		/* 15 */
+	.llong .sys_mknod
+	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
 	.llong .sys_ni_syscall			/* old break syscall holder */
 	.llong .sys32_stat
@@ -605,7 +605,7 @@
 	.llong .sys_ni_syscall			/* old profil syscall holder */
 	.llong .sys32_statfs
 	.llong .sys32_fstatfs	/* 100 */
-	.llong .sys32_ioperm
+	.llong .sys_ni_syscall		/* old ioperm syscall holder */
 	.llong .sys32_socketcall
 	.llong .sys32_syslog
 	.llong .sys32_setitimer
@@ -614,10 +614,10 @@
 	.llong .sys32_newlstat
 	.llong .sys32_newfstat
 	.llong .sys_uname
-	.llong .sys32_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall holder */
 	.llong .sys_vhangup
-	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys32_vm86
+	.llong .sys_ni_syscall		/* old 'idle' syscall */
+	.llong .sys_ni_syscall		/* old vm86 syscall holder */
 	.llong .sys32_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys32_sysinfo
@@ -627,7 +627,7 @@
 	.llong .sys32_clone		/* 120 */
 	.llong .sys32_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys32_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall holder */
 	.llong .sys32_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys32_sigprocmask
@@ -683,8 +683,8 @@
 	.llong .sys32_rt_sigtimedwait
 	.llong .sys32_rt_sigqueueinfo
 	.llong .sys32_rt_sigsuspend
-	.llong .sys32_pread
-	.llong .sys32_pwrite	        /* 180 */
+	.llong .sys32_pread64
+	.llong .sys32_pwrite64	        /* 180 */
 	.llong .sys_chown
 	.llong .sys_getcwd
 	.llong .sys_capget
@@ -695,7 +695,7 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys32_vfork
 	.llong .sys32_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys32_readahead
 	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
 	.llong .sys32_truncate64	/* 193 - truncate64 */
 	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
@@ -726,11 +726,12 @@
 	.llong .sys_lremovexattr
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
-	.llong .sys_ni_syscall		/* reserved for tux */
 	.llong .sys32_sched_setaffinity
 	.llong .sys32_sched_getaffinity
+	.llong .sys_ni_syscall		/* reserved for security */
+	.llong .sys_ni_syscall		/* 225 - reserved for tux */
 
-	.rept NR_syscalls-224
+	.rept NR_syscalls-225
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -838,7 +839,7 @@
 	.llong .sys_ni_syscall			/* old profil syscall holder */
 	.llong .sys_statfs
 	.llong .sys_fstatfs	/* 100 */
-	.llong .sys_ioperm
+	.llong .sys_ni_syscall		/* old ioperm syscall holder */
 	.llong .sys_socketcall
 	.llong .sys_syslog
 	.llong .sys_setitimer
@@ -847,10 +848,10 @@
 	.llong .sys_newlstat
 	.llong .sys_newfstat
 	.llong .sys_uname
-	.llong .sys_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall holder */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall holder */
 	.llong .sys_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys_sysinfo
@@ -860,7 +861,7 @@
 	.llong .sys_clone		/* 120 */
 	.llong .sys_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys_sigprocmask
@@ -928,7 +929,7 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys_vfork
 	.llong .sys_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_readahead
 	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
 	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
 	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
@@ -959,10 +960,11 @@
 	.llong .sys_lremovexattr
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
-	.llong .sys_ni_syscall		/* reserved for tux */
 	.llong .sys_sched_setaffinity
 	.llong .sys_sched_getaffinity
+	.llong .sys_ni_syscall		/* reserved for security */
+	.llong .sys_ni_syscall		/* reserved for tux */
 
-	.rept NR_syscalls-224
+	.rept NR_syscalls-225
 	.llong .sys_ni_syscall
 	.endr
diff -Nru a/arch/ppc64/kernel/mk_defs.c b/arch/ppc64/kernel/mk_defs.c
--- a/arch/ppc64/kernel/mk_defs.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/kernel/mk_defs.c	Tue Aug 27 12:28:07 2002
@@ -51,6 +51,7 @@
 	/* task_struct->thread */
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
 	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c
--- a/arch/ppc64/kernel/open_pic.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/kernel/open_pic.c	Tue Aug 27 12:28:07 2002
@@ -576,7 +576,7 @@
  */
 static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED;
 
-void __init do_openpic_setup_cpu(void)
+void __devinit do_openpic_setup_cpu(void)
 {
 #ifdef CONFIG_IRQ_ALL_CPUS
  	int i;
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Tue Aug 27 12:28:08 2002
@@ -155,7 +155,7 @@
 		       unsigned long ptex,
 		       unsigned long avpn)
 {
-	return plpar_hcall_norets(H_PROTECT, flags, ptex);
+	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
 }
 
 long plpar_tce_get(unsigned long liobn,
@@ -552,6 +552,7 @@
 				     int secondary, unsigned long hpteflags,
 				     int bolted, int large)
 {
+	/* XXX fix for large page */
 	unsigned long avpn = vpn >> 11;
 	unsigned long arpn = physRpn_to_absRpn(prpn);
 	unsigned long lpar_rc;
@@ -651,11 +652,10 @@
 				       unsigned long va, int large)
 {
 	unsigned long lpar_rc;
-	unsigned long flags;
-	flags = (newpp & 7) | H_AVPN;
-	unsigned long vpn = va >> PAGE_SHIFT;
+	unsigned long flags = (newpp & 7) | H_AVPN;
+	unsigned long avpn = va >> 23;
 
-	lpar_rc = plpar_pte_protect(flags, slot, (vpn >> 4) & ~0x7fUL);
+	lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7));
 
 	if (lpar_rc == H_Not_Found) {
 		udbg_printf("updatepp missed\n");
@@ -748,18 +748,11 @@
 static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
 					 int large, int local)
 {
-	unsigned long vpn, avpn;
+	unsigned long avpn = va >> 23;
 	unsigned long lpar_rc;
 	unsigned long dummy1, dummy2;
 
-	if (large)
-		vpn = va >> LARGE_PAGE_SHIFT;
-	else
-		vpn = va >> PAGE_SHIFT;
-
-	avpn = vpn >> 11;
-
-	lpar_rc = plpar_pte_remove(H_AVPN, slot, (vpn >> 4) & ~0x7fUL, &dummy1,
+	lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1,
 				   &dummy2);
 
 	if (lpar_rc == H_Not_Found) {
diff -Nru a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
--- a/arch/ppc64/kernel/ppc_ksyms.c	Tue Aug 27 12:28:01 2002
+++ b/arch/ppc64/kernel/ppc_ksyms.c	Tue Aug 27 12:28:01 2002
@@ -54,12 +54,6 @@
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
-extern void do_IRQ(struct pt_regs *regs, int isfake);
-extern void SystemResetException(struct pt_regs *regs);
-extern void MachineCheckException(struct pt_regs *regs);
-extern void AlignmentException(struct pt_regs *regs);
-extern void ProgramCheckException(struct pt_regs *regs);
-extern void SingleStepException(struct pt_regs *regs);
 extern int sys_sigreturn(struct pt_regs *regs);
 extern int do_signal(sigset_t *, struct pt_regs *);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
@@ -74,18 +68,12 @@
 extern struct pci_dev * iSeries_vio_dev;
 
 EXPORT_SYMBOL(do_signal);
-EXPORT_SYMBOL(do_IRQ);
-EXPORT_SYMBOL(SystemResetException);
-EXPORT_SYMBOL(MachineCheckException);
-EXPORT_SYMBOL(AlignmentException);
-EXPORT_SYMBOL(ProgramCheckException);
-EXPORT_SYMBOL(SingleStepException);
 EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
 #ifdef CONFIG_SMP
-EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(synchronize_irq);
 #endif /* CONFIG_SMP */
 
 EXPORT_SYMBOL(register_ioctl32_conversion);
@@ -126,15 +114,6 @@
 EXPORT_SYMBOL(__strncpy_from_user);
 EXPORT_SYMBOL(__strnlen_user);
 
-/*
-EXPORT_SYMBOL(inb);
-EXPORT_SYMBOL(inw);
-EXPORT_SYMBOL(inl);
-EXPORT_SYMBOL(outb);
-EXPORT_SYMBOL(outw);
-EXPORT_SYMBOL(outl);
-EXPORT_SYMBOL(outsl);*/
-
 #ifdef CONFIG_MSCHUNKS
 EXPORT_SYMBOL(msChunks);
 #endif
@@ -243,8 +222,6 @@
 
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(irq_desc);
-void ppc_irq_dispatch_handler(struct pt_regs *, int);
-EXPORT_SYMBOL(ppc_irq_dispatch_handler);
 EXPORT_SYMBOL(get_wchan);
 EXPORT_SYMBOL(console_drivers);
 #ifdef CONFIG_XMON
@@ -265,10 +242,6 @@
 EXPORT_SYMBOL(debugger_iabr_match);
 EXPORT_SYMBOL(debugger_dabr_match);
 EXPORT_SYMBOL(debugger_fault_handler);
-#endif
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(atomic_dec_and_lock);
 #endif
 
 EXPORT_SYMBOL(tb_ticks_per_usec);
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/kernel/process.c	Tue Aug 27 12:28:07 2002
@@ -163,8 +163,7 @@
  */
 int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
-	    unsigned long unused,
-	    struct task_struct *p, struct pt_regs *regs)
+	    unsigned long unused, struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs, *kregs;
 	extern void ret_from_fork(void);
@@ -208,17 +207,6 @@
  	 */
 	kregs->nip = *((unsigned long *)ret_from_fork);
 
-	/*
-	 * copy fpu info - assume lazy fpu switch now always
-	 *  -- Cort
-	 */
-	if (regs->msr & MSR_FP) {
-		giveup_fpu(current);
-		childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
-	}
-	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
-	p->thread.fpscr = current->thread.fpscr;
-
 	return 0;
 }
 
@@ -247,10 +235,38 @@
 	current->thread.fpscr = 0;
 }
 
+/* XXX temporary */
+#define PR_FP_EXC_PRECISE	3	/* precise exception mode */
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
 	struct task_struct *p;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
 	p = do_fork(p1 & ~CLONE_IDLETASK, regs->gpr[1], regs, 0);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
@@ -259,6 +275,10 @@
 	     struct pt_regs *regs)
 {
 	struct task_struct *p;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
 	p = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
@@ -267,6 +287,10 @@
 			 struct pt_regs *regs)
 {
 	struct task_struct *p;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
 	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/prom.c	Tue Aug 27 12:28:08 2002
@@ -144,6 +144,7 @@
 #define FB_MAX	8
 #endif
 
+static int ppc64_is_smp;
 
 struct prom_t prom = {
 	0,			/* entry */
diff -Nru a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c
--- a/arch/ppc64/kernel/ptrace32.c	Tue Aug 27 12:27:54 2002
+++ b/arch/ppc64/kernel/ptrace32.c	Tue Aug 27 12:27:54 2002
@@ -177,10 +177,7 @@
 		if (numReg >= PT_FPR0) {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
-		        if (numReg == PT_FPSCR) 
-			        tmp = ((unsigned int *)child->thread.fpscr);
-		        else 
-			        tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
+			tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
 		} else { /* register within PT_REGS struct */
 			tmp = get_reg(child, numReg);
 		} 
diff -Nru a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
--- a/arch/ppc64/kernel/rtasd.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc64/kernel/rtasd.c	Tue Aug 27 12:28:02 2002
@@ -17,7 +17,6 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
-#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Tue Aug 27 12:27:42 2002
+++ b/arch/ppc64/kernel/signal.c	Tue Aug 27 12:27:42 2002
@@ -55,7 +55,19 @@
  * able to continue 'til the next breakpoint from within the signal
  * handler, even if the handler returns.
  */
+#if 0
 #define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+#else
+/*
+ * glibc tries to set FE0/FE1 via a signal handler. Since it only ever
+ * sets both bits and this is the default setting we now disable this
+ * behaviour. This is done to insure the new prctl which alters FE0/FE1 does
+ * not get overriden by glibc. Setting and clearing FE0/FE1 via signal
+ * handler has always been bogus since load_up_fpu used to set FE0/FE1
+ * unconditionally.
+ */
+#define MSR_USERCHANGE	0
+#endif
 
 /*
  * When we have signals to deliver, we set up on the
diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/signal32.c	Tue Aug 27 12:28:08 2002
@@ -39,7 +39,19 @@
  * able to continue 'til the next breakpoint from within the signal
  * handler, even if the handler returns.
  */
+#if 0
 #define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+#else
+/*
+ * glibc tries to set FE0/FE1 via a signal handler. Since it only ever
+ * sets both bits and this is the default setting we now disable this
+ * behaviour. This is done to insure the new prctl which alters FE0/FE1 does
+ * not get overriden by glibc. Setting and clearing FE0/FE1 via signal
+ * handler has always been bogus since load_up_fpu used to set FE0/FE1
+ * unconditionally.
+ */
+#define MSR_USERCHANGE	0
+#endif
 
 struct timespec32 {
 	s32    tv_sec;
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/smp.c	Tue Aug 27 12:28:08 2002
@@ -25,8 +25,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/cache.h>
@@ -53,22 +51,18 @@
 #include <asm/machdep.h>
 
 int smp_threads_ready = 0;
-volatile int smp_commenced = 0;
-int smp_tb_synchronized = 0;
-spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 unsigned long cache_decay_ticks;
-static int max_cpus __initdata = NR_CPUS;
 
 /* initialised so it doesnt end up in bss */
 unsigned long cpu_online_map = 0;
 int boot_cpuid = 0;
-int ppc64_is_smp = 0;
 
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+static struct smp_ops_t *smp_ops;
+
+volatile unsigned long cpu_callin_map[NR_CPUS];
 
 extern unsigned char stab_array[];
 
-int start_secondary(void *);
 extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
 void smp_message_pass(int target, int msg, unsigned long data, int wait);
@@ -86,13 +80,13 @@
 
 struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
-#define smp_message_pass(t,m,d,w) ppc_md.smp_message_pass((t),(m),(d),(w))
+#define smp_message_pass(t,m,d,w) smp_ops->message_pass((t),(m),(d),(w))
 
 static inline void set_tb(unsigned int upper, unsigned int lower)
 {
-	mtspr(SPRN_TBWL, 0);
-	mtspr(SPRN_TBWU, upper);
-	mtspr(SPRN_TBWL, lower);
+	mttbl(0);
+	mttbu(upper);
+	mttbl(lower);
 }
 
 void iSeries_smp_message_recv( struct pt_regs * regs )
@@ -106,7 +100,6 @@
 	for ( msg = 0; msg < 4; ++msg )
 		if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) )
 			smp_message_recv( msg, regs );
-
 }
 
 static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait)
@@ -127,6 +120,7 @@
 	}
 }
 
+#ifdef CONFIG_PPC_ISERIES
 static int smp_iSeries_numProcs(void)
 {
 	unsigned np, i;
@@ -141,24 +135,23 @@
         }
 	return np;
 }
+#endif
 
-static void smp_iSeries_probe(void)
+static int smp_iSeries_probe(void)
 {
 	unsigned i;
-	unsigned np;
-	struct ItLpPaca * lpPaca;
+	unsigned np = 0;
+	struct ItLpPaca *lpPaca;
 
-	np = 0;
 	for (i=0; i < MAX_PACAS; ++i) {
 		lpPaca = paca[i].xLpPacaPtr;
-		if ( lpPaca->xDynProcStatus < 2 ) {
+		if (lpPaca->xDynProcStatus < 2) {
 			paca[i].active = 1;
 			++np;
-			paca[i].next_jiffy_update_tb = paca[0].next_jiffy_update_tb;
 		}
 	}
 
-	smp_tb_synchronized = 1;
+	return np;
 }
 
 static void smp_iSeries_kick_cpu(int nr)
@@ -187,17 +180,18 @@
 	paca[nr].xProcStart = 1;
 }
 
-static void smp_iSeries_setup_cpu(int nr)
+static void __devinit smp_iSeries_setup_cpu(int nr)
 {
 }
 
 /* This is called very early. */
-void smp_init_iSeries(void)
+void __init smp_init_iSeries(void)
 {
-	ppc_md.smp_message_pass = smp_iSeries_message_pass;
-	ppc_md.smp_probe        = smp_iSeries_probe;
-	ppc_md.smp_kick_cpu     = smp_iSeries_kick_cpu;
-	ppc_md.smp_setup_cpu    = smp_iSeries_setup_cpu;
+	smp_ops = &ppc_md.smp_ops;
+	smp_ops->message_pass = smp_iSeries_message_pass;
+	smp_ops->probe        = smp_iSeries_probe;
+	smp_ops->kick_cpu     = smp_iSeries_kick_cpu;
+	smp_ops->setup_cpu    = smp_iSeries_setup_cpu;
 #ifdef CONFIG_PPC_ISERIES
 #warning fix for iseries
 	naca->processorCount	= smp_iSeries_numProcs();
@@ -229,10 +223,20 @@
 	}
 }
 
-static void smp_chrp_probe(void)
+static int __init smp_chrp_probe(void)
 {
-	if (ppc64_is_smp)
+	int i;
+	int nr_cpus = 0;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_possible(i))
+			nr_cpus++;
+	}
+
+	if (nr_cpus > 1)
 		openpic_request_IPIs();
+
+	return nr_cpus;
 }
 
 static void
@@ -252,78 +256,32 @@
 	/* The processor is currently spinning, waiting
 	 * for the xProcStart field to become non-zero
 	 * After we set xProcStart, the processor will
-	 * continue on to secondary_start in iSeries_head.S
+	 * continue on to secondary_start
 	 */
 	paca[nr].xProcStart = 1;
 }
 
-extern struct gettimeofday_struct do_gtod;
-
-static void smp_space_timers()
+static void __init smp_space_timers(unsigned int max_cpus)
 {
 	int i;
-	unsigned long offset = tb_ticks_per_jiffy / NR_CPUS;
+	unsigned long offset = tb_ticks_per_jiffy / max_cpus;
+	unsigned long previous_tb = paca[boot_cpuid].next_jiffy_update_tb;
 
-	for (i = 1; i < NR_CPUS; ++i)
-		paca[i].next_jiffy_update_tb =
-			paca[i-1].next_jiffy_update_tb + offset;
-}
-
-static void
-smp_chrp_setup_cpu(int cpu_nr)
-{
-	static atomic_t ready = ATOMIC_INIT(1);
-	static volatile int frozen = 0;
-
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
-		/* timebases already synced under the hypervisor. */
-		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
-		if (cpu_nr == boot_cpuid) {
-			do_gtod.tb_orig_stamp = tb_last_stamp;
-			/* Should update do_gtod.stamp_xsec.
-			 * For now we leave it which means the time can be some
-			 * number of msecs off until someone does a settimeofday()
-			 */
-		}
-		smp_tb_synchronized = 1;
-	} else {
-		if (cpu_nr == boot_cpuid) {
-			/* wait for all the others */
-			while (atomic_read(&ready) < num_online_cpus())
-				barrier();
-			atomic_set(&ready, 1);
-			/* freeze the timebase */
-			rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-			mb();
-			frozen = 1;
-			set_tb(0, 0);
-			paca[boot_cpuid].next_jiffy_update_tb = 0;
-			smp_space_timers();
-			while (atomic_read(&ready) < num_online_cpus())
-				barrier();
-			/* thaw the timebase again */
-			rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-			mb();
-			frozen = 0;
-			tb_last_stamp = get_tb();
-			do_gtod.tb_orig_stamp = tb_last_stamp;
-			smp_tb_synchronized = 1;
-		} else {
-			atomic_inc(&ready);
-			while (!frozen)
-				barrier();
-			set_tb(0, 0);
-			mb();
-			atomic_inc(&ready);
-			while (frozen)
-				barrier();
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_possible(i) && i != boot_cpuid) {
+			paca[i].next_jiffy_update_tb =
+				previous_tb + offset;
+			previous_tb = paca[i].next_jiffy_update_tb;
 		}
 	}
+}
 
+static void __devinit pSeries_setup_cpu(int cpu)
+{
 	if (OpenPIC_Addr) {
 		do_openpic_setup_cpu();
 	} else {
-		if (cpu_nr != boot_cpuid)
+		if (cpu != boot_cpuid)
 			xics_setup_cpu();
 	}
 }
@@ -347,26 +305,65 @@
 	}
 }
 
-static void smp_xics_probe(void)
+static int __init smp_xics_probe(void)
+{
+	int i;
+	int nr_cpus = 0;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_possible(i))
+			nr_cpus++;
+	}
+
+	return nr_cpus;
+}
+
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long timebase = 0;
+
+static void __devinit pSeries_give_timebase(void)
+{
+	spin_lock(&timebase_lock);
+	rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
+	timebase = get_tb();
+	spin_unlock(&timebase_lock);
+
+	while (timebase)
+		barrier();
+	rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
+}
+
+static void __devinit pSeries_take_timebase(void)
 {
+	while (!timebase)
+		barrier();
+	spin_lock(&timebase_lock);
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	timebase = 0;
+	spin_unlock(&timebase_lock);
 }
 
 /* This is called very early */
-void smp_init_pSeries(void)
+void __init smp_init_pSeries(void)
 {
-	if(naca->interrupt_controller == IC_OPEN_PIC) {
-		ppc_md.smp_message_pass = smp_openpic_message_pass;
-		ppc_md.smp_probe        = smp_chrp_probe;
-		ppc_md.smp_kick_cpu     = smp_kick_cpu;
-		ppc_md.smp_setup_cpu    = smp_chrp_setup_cpu;
+	smp_ops = &ppc_md.smp_ops;
+
+	if (naca->interrupt_controller == IC_OPEN_PIC) {
+		smp_ops->message_pass	= smp_openpic_message_pass;
+		smp_ops->probe		= smp_chrp_probe;
 	} else {
-		ppc_md.smp_message_pass = smp_xics_message_pass;
-		ppc_md.smp_probe        = smp_xics_probe;
-		ppc_md.smp_kick_cpu     = smp_kick_cpu;
-		ppc_md.smp_setup_cpu    = smp_chrp_setup_cpu;
+		smp_ops->message_pass	= smp_xics_message_pass;
+		smp_ops->probe		= smp_xics_probe;
+	}
+
+	if (naca->platform == PLATFORM_PSERIES) {
+		smp_ops->give_timebase = pSeries_give_timebase;
+		smp_ops->take_timebase = pSeries_take_timebase;
 	}
-}
 
+	smp_ops->kick_cpu = smp_kick_cpu;
+	smp_ops->setup_cpu = pSeries_setup_cpu;
+}
 
 void smp_local_timer_interrupt(struct pt_regs * regs)
 {
@@ -469,8 +466,7 @@
  * hardware interrupt handler or from a bottom half handler.
  */
 int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
-			int wait)
-
+		       int wait)
 { 
 	struct call_data_struct data;
 	int ret = -1, cpus = num_online_cpus()-1;
@@ -553,38 +549,41 @@
 		atomic_inc(&call_data->finished);
 }
 
-
 extern unsigned long decr_overclock;
+extern struct gettimeofday_struct do_gtod;
 
-struct thread_struct *current_set[NR_CPUS] = {&init_thread_union, 0};
+struct thread_info *current_set[NR_CPUS];
 
-void __init smp_boot_cpus(void)
+static void __devinit smp_store_cpu_info(int id)
 {
-	int i, cpu_nr = 0;
-	struct task_struct *p;
-
-	printk("Entering SMP Mode...\n");
+	paca[id].pvr = _get_PVR();
+}
 
-        smp_store_cpu_info(boot_cpuid);
-	cpu_callin_map[boot_cpuid] = 1;
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i;
 
-	/* XXX buggy - Anton */
-	current_thread_info()->cpu = 0;
+	/* Fixup boot cpu */
+	smp_store_cpu_info(smp_processor_id());
+	cpu_callin_map[smp_processor_id()] = 1;
 
 	for (i = 0; i < NR_CPUS; i++) {
 		paca[i].prof_counter = 1;
 		paca[i].prof_multiplier = 1;
 		if (i != boot_cpuid) {
+			void *tmp;
 		        /*
 			 * the boot cpu segment table is statically 
 			 * initialized to real address 0x5000.  The
 			 * Other processor's tables are created and
 			 * initialized here.
 			 */
-			paca[i].xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)];
-			memset((void *)paca[i].xStab_data.virt, 0, PAGE_SIZE); 
-			paca[i].xStab_data.real = __v2a(paca[i].xStab_data.virt);
-			paca[i].default_decr = tb_ticks_per_jiffy / decr_overclock;
+			tmp = &stab_array[PAGE_SIZE * (i-1)];
+			memset(tmp, 0, PAGE_SIZE); 
+			paca[i].xStab_data.virt = (unsigned long)tmp;
+			paca[i].xStab_data.real = (unsigned long)__v2a(tmp);
+			paca[i].default_decr = tb_ticks_per_jiffy /
+				decr_overclock;
 		}
 	}
 
@@ -593,135 +592,83 @@
 	 */
 	cache_decay_ticks = HZ/100;
 
-	ppc_md.smp_probe();
+#ifndef CONFIG_PPC_ISERIES
+	paca[boot_cpuid].next_jiffy_update_tb = tb_last_stamp = get_tb();
 
-	for (i = 0; i < NR_CPUS; i++) {
-		if (paca[i].active)
-			cpu_nr++;
-	}
-	printk("Probe found %d CPUs\n", cpu_nr);
-
-#ifdef CONFIG_ISERIES
-	smp_space_timers();
+	/*
+	 * Should update do_gtod.stamp_xsec.
+	 * For now we leave it which means the time can be some
+	 * number of msecs off until someone does a settimeofday()
+	 */
+	do_gtod.tb_orig_stamp = tb_last_stamp;
 #endif
 
-	printk("Waiting for %d CPUs\n", cpu_nr-1);
-
-	for (i = 1 ; i < NR_CPUS; i++) {
-		int c;
-		struct pt_regs regs;
-
-		if (!paca[i].active)
-			continue;
+	max_cpus = smp_ops->probe();
+	smp_space_timers(max_cpus);
+}
 
-		if (i == boot_cpuid)
-			continue;
+int __devinit __cpu_up(unsigned int cpu)
+{
+	struct pt_regs regs;
+	struct task_struct *p;
+	int c;
 
-		if (num_online_cpus() >= max_cpus)
-			break;
+	/* create a process for the processor */
+	/* only regs.msr is actually used, and 0 is OK for it */
+	memset(&regs, 0, sizeof(struct pt_regs));
+	p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
+	if (IS_ERR(p))
+		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
 
-		/* create a process for the processor */
-		/* we don't care about the values in regs since we'll
-		   never reschedule the forked task. */
-		/* We DO care about one bit in the pt_regs we
-		   pass to do_fork.  That is the MSR_FP bit in
-		   regs.msr.  If that bit is on, then do_fork
-		   (via copy_thread) will call giveup_fpu.
-		   giveup_fpu will get a pointer to our (current's)
-		   last register savearea via current->thread.regs
-		   and using that pointer will turn off the MSR_FP,
-		   MSR_FE0 and MSR_FE1 bits.  At this point, this
-		   pointer is pointing to some arbitrary point within
-		   our stack */
-
-		memset(&regs, 0, sizeof(struct pt_regs));
-
-		p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
-		if (IS_ERR(p))
-			panic("failed fork for CPU %d", i);
-
-		init_idle(p, i);
-
-		unhash_process(p);
-
-		paca[i].xCurrent = (u64)p;
-		current_set[i] = p->thread_info;
-
-		/* wake up cpus */
-		ppc_md.smp_kick_cpu(i);
-
-		/*
-		 * wait to see if the cpu made a callin (is actually up).
-		 * use this value that I found through experimentation.
-		 * -- Cort
-		 */
-		for ( c = 5000; c && !cpu_callin_map[i] ; c-- ) {
-			udelay(100);
-		}
-		
-		if ( cpu_callin_map[i] )
-		{
-			printk("Processor %d found.\n", i);
-			/* this sync's the decr's -- Cort */
-		} else {
-			printk("Processor %d is stuck.\n", i);
-		}
-	}
+	init_idle(p, cpu);
+	unhash_process(p);
 
-	/* Setup boot cpu last (important) */
-	ppc_md.smp_setup_cpu(boot_cpuid);
+	paca[cpu].xCurrent = (u64)p;
+	current_set[cpu] = p->thread_info;
 
-	if (num_online_cpus() < 2) {
-	        tb_last_stamp = get_tb();
-		smp_tb_synchronized = 1;
-	}
-}
+	/* wake up cpus */
+	smp_ops->kick_cpu(cpu);
 
-void __init smp_commence(void)
-{
 	/*
-	 *	Lets the callin's below out of their loop.
+	 * wait to see if the cpu made a callin (is actually up).
+	 * use this value that I found through experimentation.
+	 * -- Cort
 	 */
-	PPCDBG(PPCDBG_SMP, "smp_commence: start\n"); 
-	wmb();
-	smp_commenced = 1;
-}
+	for (c = 5000; c && !cpu_callin_map[cpu]; c--)
+		udelay(100);
 
-void __init smp_callin(void)
-{
-	int cpu = smp_processor_id();
-
-        smp_store_cpu_info(cpu);
-	set_dec(paca[cpu].default_decr);
-	set_bit(smp_processor_id(), &cpu_online_map);
-	smp_mb();
-	cpu_callin_map[cpu] = 1;
-
-	ppc_md.smp_setup_cpu(cpu);
-	
-	while(!smp_commenced) {
-		barrier();
+	if (!cpu_callin_map[cpu]) {
+		printk("Processor %u is stuck.\n", cpu);
+		return -ENOENT;
 	}
-	local_irq_enable();
-}
 
-/* intel needs this */
-void __init initialize_secondary(void)
-{
+	printk("Processor %u found.\n", cpu);
+
+	if (smp_ops->give_timebase)
+		smp_ops->give_timebase();
+	set_bit(cpu, &cpu_online_map);
+	return 0;
 }
 
 /* Activate a secondary processor. */
-int start_secondary(void *unused)
+int __devinit start_secondary(void *unused)
 {
+	unsigned int cpu = smp_processor_id();
+
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
-	smp_callin();
 
-	return cpu_idle(NULL);
-}
+	smp_store_cpu_info(cpu);
+	set_dec(paca[cpu].default_decr);
+	cpu_callin_map[cpu] = 1;
 
-void __init smp_setup(char *str, int *ints)
-{
+	smp_ops->setup_cpu(cpu);
+	if (smp_ops->take_timebase)
+		smp_ops->take_timebase();
+
+	local_irq_enable();
+
+	return cpu_idle(NULL);
 }
 
 int setup_profiling_timer(unsigned int multiplier)
@@ -729,17 +676,10 @@
 	return 0;
 }
 
-/* this function is called for each processor
- */
-void __init smp_store_cpu_info(int id)
+void __init smp_cpus_done(unsigned int max_cpus)
 {
-        paca[id].pvr = _get_PVR();
-}
+	smp_ops->setup_cpu(boot_cpuid);
 
-static int __init maxcpus(char *str)
-{
-	get_option(&str, &max_cpus);
-	return 1;
+	/* XXX fix this, xics currently relies on it - Anton */
+	smp_threads_ready = 1;
 }
-
-__setup("maxcpus=", maxcpus);
diff -Nru a/arch/ppc64/kernel/sys32.S b/arch/ppc64/kernel/sys32.S
--- a/arch/ppc64/kernel/sys32.S	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/sys32.S	Tue Aug 27 12:28:08 2002
@@ -19,8 +19,6 @@
 #include <asm/errno.h>
 #include <asm/processor.h>
 
-/* NOTE: call as jump breaks return stack, we have to avoid that */
-
 	.text
 
 _GLOBAL(sys32_mmap)
@@ -31,14 +29,6 @@
 _GLOBAL(sys32_lseek)
 	extsw		r4,r4		/* sign extend off_t offset parm */
 	b		.sys_lseek
-
-_GLOBAL(sys32_chmod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_chmod
-
-_GLOBAL(sys32_mknod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_mknod
 
 _GLOBAL(sys32_sendto)
 	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/sys_ppc32.c	Tue Aug 27 12:28:08 2002
@@ -95,8 +95,6 @@
 	int ret;
 	char *filenam;
 	
-	PPCDBG(PPCDBG_SYS32NI, "sys32_utime - running - filename=%s, times=%p - pid=%ld, comm=%s \n", filename, times, current->pid, current->comm);
-
 	if (!times)
 		return sys_utime(filename, NULL);
 	if (get_user(t.actime, &times->actime) || __get_user(t.modtime, &times->modtime))
@@ -225,8 +223,6 @@
 	struct file *file;
 	long ret = -EBADF;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_readv - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	file = fget(fd);
 	if(!file)
 		goto bad_file;
@@ -237,7 +233,6 @@
 	fput(file);
 
 bad_file:
-	PPCDBG(PPCDBG_SYS32, "sys32_readv - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return ret;
 }
 
@@ -246,8 +241,6 @@
 	struct file *file;
 	int ret = -EBADF;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_writev - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	file = fget(fd);
 	if(!file)
 		goto bad_file;
@@ -257,7 +250,6 @@
 	fput(file);
 
 bad_file:
-	PPCDBG(PPCDBG_SYS32, "sys32_writev - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return ret;
 }
 
@@ -404,8 +396,6 @@
 	unsigned long dir_page = 0;
 	int err, is_smb, is_ncp;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_mount - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	is_smb = is_ncp = 0;
 
 	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
@@ -460,23 +450,9 @@
 	free_page(type_page);
 
 out:
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_mount - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return err;
 }
 
-struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
-};
-                                
 /* readdir & getdents */
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
@@ -594,8 +570,6 @@
 	struct getdents_callback32 buf;
 	int error = -EBADF;
 
-	PPCDBG(PPCDBG_SYS32NI, "sys32_getdents - running - fd=%x, pid=%ld, comm=%s \n", fd, current->pid, current->comm);
-
 	file = fget(fd);
 	if (!file)
 		goto out;
@@ -711,8 +685,6 @@
 	long timeout;
 	int ret, size;
 	
-  PPCDBG(PPCDBG_SYS32X, "sys32_select - entered - n=%x, inp=%p, outp=%p - pid=%ld comm=%s \n", n, inp, outp, current->pid, current->comm);
-
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
@@ -776,7 +748,7 @@
 		put_user(usec, &tvp->tv_usec);
 	}
 
-  if (ret < 0)
+	if (ret < 0)
 		goto out;
 	if (!ret) {
 		ret = -ERESTARTNOHAND;
@@ -793,7 +765,6 @@
 	kfree(bits);
 
 out_nofds:
-	PPCDBG(PPCDBG_SYS32X, "sys32_select - exited - pid=%ld, comm=%s \n", current->pid, current->comm);
 	return ret;
 }
 
@@ -894,8 +865,6 @@
 	mm_segment_t old_fs = get_fs();
 	char *pth;
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-	
 	pth = getname (path);
 	ret = PTR_ERR(pth);
 	if (!IS_ERR(pth)) {
@@ -907,8 +876,6 @@
 			return -EFAULT;
 	}
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -920,16 +887,12 @@
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-	
 	set_fs (KERNEL_DS);
 	ret = sys_fstatfs(fd, &s);
 	set_fs (old_fs);
 	if (put_statfs(buf, &s))
 		return -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -944,7 +907,6 @@
  */
 asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_sysfs - running - pid=%ld, comm=%s\n", current->pid, current->comm);
 	return sys_sysfs((int)option, arg1, arg2);
 }
 
@@ -961,10 +923,6 @@
 	unsigned long ret = -EINVAL;
 	unsigned long new_addr = AA(__new_addr);
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_mremap - entered - pid=%ld current=%lx comm=%s\n",
-		    current->pid, current, current->comm);
-
-
 	if (old_len > 0xf0000000UL || new_len > 0xf0000000UL)
 		goto out;
 	if (addr > 0xf0000000UL - old_len)
@@ -986,10 +944,6 @@
 out_sem:
 	up_write(&current->mm->mmap_sem);
 out:
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_mremap - exited - pid=%ld current=%lx comm=%s\n",
-		    current->pid, current, current->comm);
-
 	return ret;       
 }
 
@@ -1017,8 +971,6 @@
 	struct timex txc;
 	int ret;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_adjtimex - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	memset(&txc, 0, sizeof(struct timex));
 
 	if(get_user(txc.modes, &utp->modes) ||
@@ -1081,9 +1033,6 @@
 
 asmlinkage unsigned long sys32_create_module(const char *name_user, __kernel_size_t32 size)
 {
-	
-	PPCDBG(PPCDBG_SYS32M, "sys32_create_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return sys_create_module(name_user, (size_t)size);
 }
 
@@ -1093,9 +1042,6 @@
 
 asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return sys_init_module(name_user, mod_user);
 }
 
@@ -1105,9 +1051,6 @@
 
 asmlinkage long sys32_delete_module(const char *name_user)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return sys_delete_module(name_user);
 }
 
@@ -1384,9 +1327,6 @@
 	struct module *mod;
 	int err;
 	
-	PPCDBG(PPCDBG_SYS32M, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n",
-		    current->pid, current, current->comm);
-
 	lock_kernel();
 	if (name_user == 0) {
 		/* This finds "kernel_module" which is not exported. */
@@ -1439,8 +1379,6 @@
 out:
 	unlock_kernel();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return err;
 }
 
@@ -1459,9 +1397,6 @@
 	struct kernel_sym *tbl;
 	mm_segment_t old_fs;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	
 	len = sys_get_kernel_syms(NULL);
 	if (!table) return len;
 	tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
@@ -1477,8 +1412,6 @@
 	}
 	kfree (tbl);
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return i;
 }
 
@@ -1486,23 +1419,16 @@
 
 asmlinkage unsigned long sys32_create_module(const char *name_user, size_t size)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_create_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	return -ENOSYS;
 }
 
 asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	return -ENOSYS;
 }
 
 asmlinkage long sys32_delete_module(const char *name_user)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	return -ENOSYS;
 }
 
@@ -1513,20 +1439,15 @@
  */
 asmlinkage long sys32_query_module(const char *name_user, u32 which, char *buf, size_t bufsize, size_t *ret)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	/* Let the program know about the new interface.  Not that it'll do them much good. */
 	if ((int)which == 0)
 		return 0;
 
-	PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	return -ENOSYS;
 }
 
 asmlinkage long sys32_get_kernel_syms(struct kernel_sym *table)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	return -ENOSYS;
 }
 
@@ -1893,8 +1814,6 @@
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 	
-	PPCDBG(PPCDBG_SYS32NI, "sys32_nanosleep - running - pid=%ld, comm=%s \n", current->pid, current->comm);
-	
 	if (get_user (t.tv_sec, &rqtp->tv_sec) ||
 	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
@@ -1916,9 +1835,6 @@
 /* These are here just in case some old sparc32 binary calls it. */
 asmlinkage long sys32_pause(void)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_pause - running - pid=%ld, comm=%s \n", current->pid, current->comm);
-
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
 	
@@ -1974,14 +1890,10 @@
 	struct itimerval kit;
 	int error;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_getitimer - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	error = do_getitimer((int)which, &kit);
 	if (!error && put_it32(it, &kit))
 		error = -EFAULT;
 
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_getitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	return error;
 }
 
@@ -1999,8 +1911,6 @@
 	struct itimerval kin, kout;
 	int error;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_setitimer - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	if (in) {
 		if (get_it32(&kin, in))
 			return -EFAULT;
@@ -2013,8 +1923,6 @@
 	if (put_it32(out, &kout))
 		return -EFAULT;
 
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_setitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	return 0;
 }
 
@@ -2049,32 +1957,23 @@
 {
 	struct rlimit   x;    // 64-bit version of the resource limits.
 	struct rlimit32 x32;  // 32-bit version of the resource limits.
-	long rc = 0;
-	
-	if (resource >= RLIM_NLIMITS) {
-		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - specified resource is too large (%x) - pid=%ld, comm=%s\n", resource, current->pid, current->comm);
+
+	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
-	}
 
 	memcpy(&x, current->rlim+resource, sizeof(struct rlimit));
 
-	if(x.rlim_cur > RLIM_INFINITY32)
+	if (x.rlim_cur > RLIM_INFINITY32)
 		x32.rlim_cur = RLIM_INFINITY32;
 	else
 		x32.rlim_cur = x.rlim_cur;
 
-	if(x.rlim_max > RLIM_INFINITY32)
+	if (x.rlim_max > RLIM_INFINITY32)
 		x32.rlim_max = RLIM_INFINITY32;
 	else
 		x32.rlim_max = x.rlim_max;
 
-	rc = (copy_to_user(rlim, &x32, sizeof(x32))) ? (-EFAULT) : 0;
-	if (rc == 0) {
-		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - current=%x, maximum=%x - pid=%ld, comm=%s\n", x32.rlim_cur, x32.rlim_max, current->pid, current->comm);
-	} else {
-		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - unable to copy into user's storage - pid=%ld, comm=%s\n", current->pid, current->comm);
-	}
-	return rc;
+	return (copy_to_user(rlim, &x32, sizeof(x32))) ? (-EFAULT) : 0;
 }
 
 extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
@@ -2084,8 +1983,6 @@
 	long ret;
 	mm_segment_t old_fs = get_fs ();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - entered - resource=%x, rlim=%p - pid=%ld, comm=%s\n", resource, rlim, current->pid, current->comm);
-
 	if (resource >= RLIM_NLIMITS) return -EINVAL;	
 	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
 	    __get_user (r.rlim_max, &rlim->rlim_max))
@@ -2098,7 +1995,6 @@
 	ret = sys_setrlimit(resource, &r);
 	set_fs (old_fs);
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - exited w/ ret=%x - pid=%ld, comm=%s\n", ret, current->pid, current->comm);
 	return ret;
 }
 
@@ -2161,8 +2057,6 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_getrusage - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-		
 	set_fs (KERNEL_DS);
 	ret = sys_getrusage((int)who, &r);
 	set_fs (old_fs);
@@ -2196,8 +2090,6 @@
 	int ret, err;
 	mm_segment_t old_fs = get_fs ();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	
 	set_fs (KERNEL_DS);
 	ret = sys_sysinfo(&s);
 	set_fs (old_fs);
@@ -2215,8 +2107,6 @@
 	if (err)
 		return -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -2230,9 +2120,6 @@
 
 asmlinkage long sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
 {
-	
-	PPCDBG(PPCDBG_SYS32X, "sys32_gettimeofday - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	if (tv) {
 		struct timeval ktv;
 		do_gettimeofday(&ktv);
@@ -2254,8 +2141,6 @@
 	struct timeval ktv;
 	struct timezone ktz;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_settimeofday - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
  	if (tv) {
 		if (get_tv32(&ktv, tv))
 			return -EFAULT;
@@ -2269,8 +2154,6 @@
 }
 
 
-
-
 struct tms32 {
 	__kernel_clock_t32 tms_utime;
 	__kernel_clock_t32 tms_stime;
@@ -2287,8 +2170,6 @@
 	mm_segment_t old_fs = get_fs ();
 	int err;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_times - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	
 	set_fs (KERNEL_DS);
 	ret = sys_times(tbuf ? &t : NULL);
 	set_fs (old_fs);
@@ -2301,8 +2182,6 @@
 			ret = -EFAULT;
 	}
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_times - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -2847,9 +2726,6 @@
 	int third  = (int)third_parm;
 	int version, err;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_ipc - entered - call=%x, parm1=%x, parm2=%x, parm3=%x, parm4=%x, parm5=%x \n", 
-         call, first_parm, second_parm, third_parm, ptr, fifth);
-
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
@@ -2900,9 +2776,6 @@
 		err = -EINVAL;
 		break;
 	}
-
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_ipc - exited w/ %d/0x%x \n", err, err);
 	return err;
 }
 
@@ -2999,9 +2872,6 @@
 
 asmlinkage long sys32_setsockopt(int fd, int level, int optname, char* optval, int optlen)
 {
-	
-	PPCDBG(PPCDBG_SYS32,"sys32_setsockopt - running - pid=%ld, comm=%s\n", current->pid, current->comm);
-
 	if (optname == SO_ATTACH_FILTER) {
 		struct sock_fprog32 {
 			__u16 len;
@@ -3272,8 +3142,6 @@
 	struct msghdr kern_msg;
 	int err, total_len;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags);
-
 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
 		return -EFAULT;
 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
@@ -3306,8 +3174,6 @@
 	if(kern_msg.msg_iov != iov)
 		kfree(kern_msg.msg_iov);
 out:
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - exited w/ %lx \n", err);
 	return err;
 }
 
@@ -3510,8 +3376,6 @@
 	unsigned long cmsg_ptr;
 	int err, total_len, len = 0;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags);
-
 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
 		return -EFAULT;
 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
@@ -3579,7 +3443,6 @@
 	if(err < 0)
 		return err;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - exited w/ %lx \n", len);
 	return len;
 }
 
@@ -3804,8 +3667,6 @@
  */
 asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
 {
-	PPCDBG(PPCDBG_SYS32, "sys32_prctl - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return sys_prctl((int)option,
 			 (unsigned long) arg2,
 			 (unsigned long) arg3,
@@ -3826,8 +3687,6 @@
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	
 	set_fs (KERNEL_DS);
 	ret = sys_sched_rr_get_interval((int)pid, &t);
 	set_fs (old_fs);
@@ -3835,7 +3694,6 @@
 	    __put_user (t.tv_nsec, &interval->tv_nsec))
 		return -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return ret;
 }
 
@@ -3844,9 +3702,6 @@
 
 asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_read - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return sys_pciconfig_read((unsigned long) bus,
 				  (unsigned long) dfn,
 				  (unsigned long) off,
@@ -3862,9 +3717,6 @@
 
 asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_write - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return sys_pciconfig_write((unsigned long) bus,
 				   (unsigned long) dfn,
 				   (unsigned long) off,
@@ -3962,8 +3814,6 @@
  */
 asmlinkage long sys32_wait4(u32 pid, unsigned int * stat_addr, u32 options, struct rusage * ru)
 {
-        PPCDBG(PPCDBG_SYS32, "sys32_wait4 - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	if (!ru)
 		return sys_wait4((int)pid, stat_addr, options, NULL);
 	else {
@@ -4062,30 +3912,6 @@
 }
 
 
-extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
-
-/* Note: it is necessary to treat on as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on)
-{
-	return sys_ioperm(from, num, (int)on);
-}
-
-
-extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4);
-}
 
 
 extern asmlinkage long sys_kill(int pid, int sig);
@@ -4127,19 +3953,6 @@
 }
 
 
-extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
 
 /* Note: it is necessary to treat flags as an unsigned int,
@@ -4426,42 +4239,32 @@
 }
 
 
-extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
-
-
-
-extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
-				    size_t count, loff_t pos);
+extern ssize_t sys_pread64(unsigned int fd, char *buf, size_t count,
+			   loff_t pos);
 
-extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
-				     size_t count, loff_t pos);
+extern ssize_t sys_pwrite64(unsigned int fd, const char *buf, size_t count,
+			    loff_t pos);
 
 typedef __kernel_ssize_t32 ssize_t32;
 
-asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
-				 __kernel_size_t32 count, u32 reg6, u32 poshi, u32 poslo)
+ssize_t32 sys32_pread64(unsigned int fd, char *ubuf, __kernel_size_t32 count,
+			u32 reg6, u32 poshi, u32 poslo)
 {
-	return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+	return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
-				  __kernel_size_t32 count, u32 reg6 ,u32 poshi, u32 poslo)
+ssize_t32 sys32_pwrite64(unsigned int fd, char *ubuf, __kernel_size_t32 count,
+			 u32 reg6 ,u32 poshi, u32 poslo)
 {
-	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+	return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+ssize_t32 sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+{
+        return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+}
 
 extern asmlinkage long sys_truncate(const char * path, unsigned long length);
 extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c	Tue Aug 27 12:28:01 2002
+++ b/arch/ppc64/kernel/syscalls.c	Tue Aug 27 12:28:01 2002
@@ -52,30 +52,11 @@
 {
 }
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	printk(KERN_ERR "sys_ioperm()\n");
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -86,8 +67,6 @@
 {
 	int version, ret;
 
-	PPCDBG(PPCDBG_SYS64X, "sys_ipc - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
@@ -174,7 +153,6 @@
 		break;
 	}
 
-	PPCDBG(PPCDBG_SYS64X, "sys_ipc - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return ret;
 }
 
@@ -187,32 +165,27 @@
 	int fd[2];
 	int error;
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_pipe - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	error = do_pipe(fd);
 	if (!error) {
 		if (copy_to_user(fildes, fd, 2*sizeof(int)))
 			error = -EFAULT;
 	}
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_pipe - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return error;
 }
 
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
-				  unsigned long prot, unsigned long flags,
-				  unsigned long fd, off_t offset)
+unsigned long sys_mmap(unsigned long addr, size_t len,
+		       unsigned long prot, unsigned long flags,
+		       unsigned long fd, off_t offset)
 {
 	struct file * file = NULL;
 	unsigned long ret = -EBADF;
 
-	PPCDBG(PPCDBG_SYS64X, "sys_mmap - entered - addr=%lx, len=%lx - pid=%ld, comm=%s \n", addr, len, current->pid, current->comm);
-	
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (!(file = fget(fd)))
 			goto out;
 	}
-	
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	down_write(&current->mm->mmap_sem);
 	ret = do_mmap(file, addr, len, prot, flags, offset);
@@ -221,9 +194,6 @@
 		fput(file);
 
 out:
-	
-	PPCDBG(PPCDBG_SYS64X, "sys_mmap - exited - ret=%x \n", ret);
-	
 	return ret;
 }
 
@@ -240,14 +210,11 @@
 {
 	int err = -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_uname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	down_read(&uts_sem);
 	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
 		err = 0;
 	up_read(&uts_sem);
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_uname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return err;
 }
 
@@ -255,8 +222,6 @@
 {
 	int error;
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_olduname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	if (!name)
 		return -EFAULT;
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
@@ -277,7 +242,6 @@
 
 	error = error ? -EFAULT : 0;
 	
-	PPCDBG(PPCDBG_SYS64X, "sys_olduname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 	return error;
 }
 
diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
--- a/arch/ppc64/kernel/time.c	Tue Aug 27 12:28:08 2002
+++ b/arch/ppc64/kernel/time.c	Tue Aug 27 12:28:08 2002
@@ -60,6 +60,7 @@
 
 #include <asm/time.h>
 #include <asm/ppcdebug.h>
+#include <asm/prom.h>
 
 void smp_local_timer_interrupt(struct pt_regs *);
 
@@ -293,9 +294,6 @@
 
 	irq_exit();
 
-	if (softirq_pending(cpu))
-		do_softirq();
-	
 	return 1;
 }
 
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Tue Aug 27 12:28:06 2002
+++ b/arch/ppc64/kernel/traps.c	Tue Aug 27 12:28:06 2002
@@ -128,13 +128,12 @@
 SystemResetException(struct pt_regs *regs)
 {
 	if (fwnmi_active) {
-		char *msg;
 		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
 		struct rtas_error_log *errlog;
 
-		msg = "FWNMI is active with save area at %016lx\n";
-		udbg_printf(msg, r3); printk(msg, r3);
+		udbg_printf("FWNMI is active with save area at %016lx\n", r3);
 		errlog = FWNMI_get_errinfo(regs);
+		FWNMI_release_errinfo();
 	}
 
 	if (debugger)
@@ -241,14 +240,12 @@
 static void parse_fpe(struct pt_regs *regs)
 {
 	siginfo_t info;
-	unsigned int *tmp;
-	unsigned int fpscr;
+	unsigned long fpscr;
 
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	tmp = &current->thread.fpscr;
-	fpscr = *tmp;
+	fpscr = current->thread.fpscr;
 
 	/* Invalid operation */
 	if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c	Tue Aug 27 12:27:45 2002
+++ b/arch/ppc64/kernel/xics.c	Tue Aug 27 12:27:45 2002
@@ -373,7 +373,7 @@
 	if (naca->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
 		for (i = 0; i < NR_CPUS; ++i) {
-			if (!paca[i].active)
+			if (!cpu_possible(i))
 				continue;
 			xics_info.per_cpu[i] =
 			  __ioremap((ulong)inodes[i].addr, 
diff -Nru a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile
--- a/arch/ppc64/lib/Makefile	Tue Aug 27 12:27:42 2002
+++ b/arch/ppc64/lib/Makefile	Tue Aug 27 12:27:42 2002
@@ -4,6 +4,8 @@
 
 O_TARGET = lib.o
 
+export-objs     := dec_and_lock.o
+
 obj-y           := checksum.o dec_and_lock.o string.o strcase.o copypage.o \
 		   memcpy.o copyuser.o
 
diff -Nru a/arch/ppc64/lib/dec_and_lock.c b/arch/ppc64/lib/dec_and_lock.c
--- a/arch/ppc64/lib/dec_and_lock.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc64/lib/dec_and_lock.c	Tue Aug 27 12:28:02 2002
@@ -7,32 +7,49 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/system.h>
 
+/*
+ * This is an implementation of the notion of "decrement a
+ * reference count, and return locked if it decremented to zero".
+ *
+ * This implementation can be used on any architecture that
+ * has a cmpxchg, and where atomic->value is an int holding
+ * the value of the atomic (i.e. the high bits aren't used
+ * for a lock or anything like that).
+ *
+ * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h
+ * if spinlocks are empty and thus atomic_dec_and_lock is defined
+ * to be atomic_dec_and_test - in that case we don't need it
+ * defined here as well.
+ */
+
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
 	int newcount;
 
-repeat:
-	counter = atomic_read(atomic);
-	newcount = counter-1;
-
-	if (!newcount)
-		goto slow_path;
+	for (;;) {
+		counter = atomic_read(atomic);
+		newcount = counter - 1;
+		if (!newcount)
+			break;		/* do it the slow way */
+
+		newcount = cmpxchg(&atomic->counter, counter, newcount);
+		if (newcount == counter)
+			return 0;
+	}
 
-	newcount = cmpxchg(&atomic->counter, counter, newcount);
-
-	if (newcount != counter)
-		goto repeat;
-	return 0;
-
-slow_path:
 	spin_lock(lock);
 	if (atomic_dec_and_test(atomic))
 		return 1;
 	spin_unlock(lock);
 	return 0;
 }
+
+EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif /* ATOMIC_DEC_AND_LOCK */
diff -Nru a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c
--- a/arch/ppc64/mm/imalloc.c	Tue Aug 27 12:28:02 2002
+++ b/arch/ppc64/mm/imalloc.c	Tue Aug 27 12:28:02 2002
@@ -13,6 +13,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 
 rwlock_t imlist_lock = RW_LOCK_UNLOCKED;
 struct vm_struct * imlist = NULL;
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Tue Aug 27 12:28:07 2002
+++ b/arch/ppc64/mm/init.c	Tue Aug 27 12:28:07 2002
@@ -566,7 +566,8 @@
  */
 void flush_dcache_page(struct page *page)
 {
-	clear_bit(PG_arch_1, &page->flags);
+	if (test_bit(PG_arch_1, &page->flags))
+		clear_bit(PG_arch_1, &page->flags);
 }
 
 void flush_icache_page(struct vm_area_struct *vma, struct page *page)
@@ -589,10 +590,12 @@
 	clear_page(page);
 
 	/* XXX we shouldnt have to do this, but glibc requires it */
-	if (cpu_has_noexecute())
-		clear_bit(PG_arch_1, &pg->flags);
-	else
+	if (cpu_has_noexecute()) {
+		if (test_bit(PG_arch_1, &pg->flags))
+			clear_bit(PG_arch_1, &pg->flags);
+	} else {
 		__flush_dcache_icache(page);
+	}
 }
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
@@ -609,10 +612,12 @@
 		return;
 #endif
 
-	if (cpu_has_noexecute())
-		clear_bit(PG_arch_1, &pg->flags);
-	else
+	if (cpu_has_noexecute()) {
+		if (test_bit(PG_arch_1, &pg->flags))
+			clear_bit(PG_arch_1, &pg->flags);
+	} else {
 		__flush_dcache_icache(vto);
+	}
 }
 
 void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
diff -Nru a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
--- a/arch/s390/kernel/smp.c	Tue Aug 27 12:27:45 2002
+++ b/arch/s390/kernel/smp.c	Tue Aug 27 12:27:45 2002
@@ -54,8 +54,6 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 volatile unsigned long phys_cpu_present_map;
 volatile unsigned long cpu_online_map;
 unsigned long    cache_decay_ticks = 0;
@@ -634,7 +632,6 @@
 }
 
 EXPORT_SYMBOL(lowcore_ptr);
-EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
diff -Nru a/arch/s390x/Makefile b/arch/s390x/Makefile
--- a/arch/s390x/Makefile	Tue Aug 27 12:28:06 2002
+++ b/arch/s390x/Makefile	Tue Aug 27 12:28:06 2002
@@ -14,7 +14,6 @@
 #
 
 LDFLAGS		:= -m elf64_s390
-CPP=$(CC) -E
 OBJCOPYFLAGS	:= -O binary
 ifeq ($(CONFIG_SHARED_KERNEL),y)
   LINKSCRIPT := arch/s390x/vmlinux-shared.lds
diff -Nru a/arch/s390x/kernel/smp.c b/arch/s390x/kernel/smp.c
--- a/arch/s390x/kernel/smp.c	Tue Aug 27 12:28:07 2002
+++ b/arch/s390x/kernel/smp.c	Tue Aug 27 12:28:07 2002
@@ -53,8 +53,6 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 volatile unsigned long phys_cpu_present_map;
 volatile unsigned long cpu_online_map;
 unsigned long    cache_decay_ticks = 0;
@@ -613,7 +611,6 @@
 }
 
 EXPORT_SYMBOL(lowcore_ptr);
-EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile
--- a/arch/sh/Makefile	Tue Aug 27 12:28:07 2002
+++ b/arch/sh/Makefile	Tue Aug 27 12:28:07 2002
@@ -45,7 +45,7 @@
 # error messages during linking.  Select a default linkscript if
 # none has been choosen above.
 #
-LINKSCRIPT    = arch/sh/vmlinux.lds
+LINKSCRIPT    = arch/sh/vmlinux.lds.s
 LDFLAGS_vmlinux     += -T $(word 1,$(LINKSCRIPT)) -e _stext
 
 ifdef LOADADDR
@@ -70,10 +70,9 @@
 CORE_FILES += arch/sh/stboards/stboards.o
 endif
 
-vmlinux: arch/sh/vmlinux.lds
+vmlinux: arch/sh/vmlinux.lds.s
 
-arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE
-	$(CPP) -traditional -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
+CPPFLAGS_arch/sh/vmlinux.lds.s := -traditional
 
 FORCE: ;
 
@@ -92,4 +91,4 @@
 #	$(MAKE) -C arch/$(ARCH)/tools clean
 
 archmrproper:
-	rm -f arch/sh/vmlinux.lds
+
diff -Nru a/arch/sh/config.in b/arch/sh/config.in
--- a/arch/sh/config.in	Tue Aug 27 12:28:06 2002
+++ b/arch/sh/config.in	Tue Aug 27 12:28:06 2002
@@ -207,10 +207,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
 
@@ -236,6 +232,8 @@
 source drivers/ieee1394/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -324,7 +322,7 @@
 bool 'Watchdog Timer Support' CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
    bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
-   dep_tristate '  SH 3/4 Watchdog' CONFIG_SH_WDT $CONFIG_SUPERH
+   tristate '  SH 3/4 Watchdog' CONFIG_SH_WDT
 fi
 endmenu
 
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Tue Aug 27 12:27:59 2002
+++ b/arch/sparc/config.in	Tue Aug 27 12:27:59 2002
@@ -87,10 +87,6 @@
 
 endmenu
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 # Don't frighten a common SBus user
 if [ "$CONFIG_PCI" = "y" ]; then
 
@@ -158,6 +154,8 @@
 source drivers/fc4/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc/kernel/Makefile	Tue Aug 27 12:28:02 2002
@@ -30,6 +30,8 @@
 
 include $(TOPDIR)/Rules.make
 
+HPATH := $(objtree)/include
+
 check_asm: FORCE
 	@if [ ! -r $(HPATH)/asm/asm_offsets.h ] ; then \
 	  touch $(HPATH)/asm/asm_offsets.h ; \
diff -Nru a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
--- a/arch/sparc/kernel/ebus.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc/kernel/ebus.c	Tue Aug 27 12:28:08 2002
@@ -24,9 +24,6 @@
 
 struct linux_ebus *ebus_chain = 0;
 
-#ifdef CONFIG_SUN_AUXIO
-extern void auxio_probe(void);
-#endif
 extern void rs_init(void);
 
 /* We are together with pcic.c under CONFIG_PCI. */
@@ -366,7 +363,4 @@
 	}
 
 	rs_init();
-#ifdef CONFIG_SUN_AUXIO
-	auxio_probe();
-#endif
 }
diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
--- a/arch/sparc/kernel/irq.c	Tue Aug 27 12:27:57 2002
+++ b/arch/sparc/kernel/irq.c	Tue Aug 27 12:27:57 2002
@@ -12,6 +12,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -415,7 +416,7 @@
 	extern void smp4m_irq_rotate(int cpu);
 #endif
 
-	irq_enter(cpu, irq);
+	irq_enter();
 	disable_pil_irq(irq);
 #ifdef CONFIG_SMP
 	/* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
@@ -431,9 +432,7 @@
 		action = action->next;
 	} while (action);
 	enable_pil_irq(irq);
-	irq_exit(cpu, irq);
-	if (softirq_pending(cpu))
-		do_softirq();
+	irq_exit();
 }
 
 #ifdef CONFIG_BLK_DEV_FD
@@ -444,13 +443,14 @@
 	int cpu = smp_processor_id();
 
 	disable_pil_irq(irq);
-	irq_enter(cpu, irq);
+	irq_enter();
 	kstat.irqs[cpu][irq]++;
 	floppy_interrupt(irq, dev_id, regs);
-	irq_exit(cpu, irq);
+	irq_exit();
 	enable_pil_irq(irq);
-	if (softirq_pending(cpu))
-		do_softirq();
+	// XXX Eek, it's totally changed with preempt_count() and such
+	// if (softirq_pending(cpu))
+	//	do_softirq();
 }
 #endif
 
@@ -644,7 +644,7 @@
 	extern void sun4c_init_IRQ( void );
 	extern void sun4m_init_IRQ( void );
 	extern void sun4d_init_IRQ( void );
-    
+
 	switch(sparc_cpu_model) {
 	case sun4c:
 	case sun4:
diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
--- a/arch/sparc/kernel/pcic.c	Tue Aug 27 12:27:42 2002
+++ b/arch/sparc/kernel/pcic.c	Tue Aug 27 12:27:42 2002
@@ -55,10 +55,6 @@
 
 #else
 
-#ifdef CONFIG_SUN_JSFLASH
-extern int jsflash_init(void);
-#endif
-
 struct pci_fixup pcibios_fixups[] = {
 	{ 0 }
 };
@@ -435,7 +431,7 @@
 /*
  * Main entry point from the PCI subsystem.
  */
-void __init pcibios_init(void)
+static int __init pcibios_init(void)
 {
 	struct linux_pcic *pcic;
 
@@ -444,7 +440,7 @@
 	 * So, here we report the presence of PCIC and do some magic passes.
 	 */
 	if(!pcic0_up)
-		return;
+		return 0;
 	pcic = &pcic0;
 
 	/*
@@ -465,9 +461,7 @@
 	pcic_pbm_scan_bus(pcic);
 
 	ebus_init();
-#ifdef CONFIG_SUN_JSFLASH
-	jsflash_init();
-#endif
+	return 0;
 }
 
 int pcic_present(void)
@@ -1037,3 +1031,5 @@
 }
 
 #endif
+
+subsys_initcall(pcibios_init);
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Tue Aug 27 12:28:01 2002
+++ b/arch/sparc/kernel/process.c	Tue Aug 27 12:28:01 2002
@@ -508,6 +508,8 @@
 #endif
 	}
 
+	p->user_tid = NULL;
+
 	/* Calculate offset to stack_frame & pt_regs */
 	stack_offset = THREAD_SIZE - TRACEREG_SZ;
 
@@ -581,6 +583,16 @@
 	/* Set the return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
 
+	if (!(clone_flags & (CLONE_SETTID | CLONE_CLEARTID)))
+		return 0;
+
+	if (clone_flags & CLONE_SETTID)
+		if (put_user(p->pid, (int *)childregs->u_regs[UREG_G2]))
+			return -EFAULT;
+
+	if (clone_flags & CLONE_CLEARTID)
+		p->user_tid = (int *) childregs->u_regs[UREG_G2];
+
 	return 0;
 }
 
@@ -681,6 +693,8 @@
 	error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
 			  (char **) regs->u_regs[base + UREG_I2], regs);
 	putname(filename);
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
 out:
 	return error;
 }
diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
--- a/arch/sparc/kernel/ptrace.c	Tue Aug 27 12:28:05 2002
+++ b/arch/sparc/kernel/ptrace.c	Tue Aug 27 12:28:05 2002
@@ -17,6 +17,7 @@
 #include <linux/user.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/security.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -283,11 +284,19 @@
 	}
 #endif
 	if(request == PTRACE_TRACEME) {
+		int ret;
+
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED) {
 			pt_error_return(regs, EPERM);
 			goto out;
 		}
+		ret = security_ops->ptrace(current->parent, current);
+		if (ret) {
+			pt_error_return(regs, -ret);
+			goto out;
+		}
+
 		/* set the ptrace bit in the process flags. */
 		current->ptrace |= PT_PTRACED;
 		pt_succ_return(regs, 0);
diff -Nru a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
--- a/arch/sparc/kernel/rtrap.S	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc/kernel/rtrap.S	Tue Aug 27 12:28:02 2002
@@ -86,7 +86,8 @@
 	wr	%t_psr, 0x0, %psr
 	WRITE_PAUSE
 
-	ld	[%curptr + AOFF_task_thread + AOFF_thread_w_saved], %twin_tmp1
+	ld	[%curptr + TI_TASK], %o5
+	ld	[%o5 + AOFF_task_thread + AOFF_thread_w_saved], %twin_tmp1
 	orcc	%g0, %twin_tmp1, %g0
 	be	ret_trap_nobufwins
 	 nop
diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c	Tue Aug 27 12:27:51 2002
+++ b/arch/sparc/kernel/setup.c	Tue Aug 27 12:27:51 2002
@@ -130,7 +130,7 @@
 static void
 prom_console_write(struct console *con, const char *s, unsigned n)
 {
-	prom_printf("%s", s);
+	prom_write(s, n);
 }
 
 static struct console prom_debug_console = {
diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
--- a/arch/sparc/kernel/smp.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc/kernel/smp.c	Tue Aug 27 12:28:02 2002
@@ -66,9 +66,6 @@
  * instruction which is much better...
  */
 
-/* Kernel spinlock */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 /* Used to make bitops atomic */
 unsigned char bitops_spinlock = 0;
 
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Tue Aug 27 12:27:59 2002
+++ b/arch/sparc/kernel/sparc_ksyms.c	Tue Aug 27 12:27:59 2002
@@ -77,10 +77,6 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
-#ifdef CONFIG_SMP
-extern spinlock_t kernel_flag;
-#endif
-
 /* One thing to note is that the way the symbols of the mul/div
  * support routines are named is a mess, they all start with
  * a '.' which makes it a bitch to export, here is the trick:
@@ -130,9 +126,6 @@
 EXPORT_SYMBOL_PRIVATE(_change_bit);
 
 #ifdef CONFIG_SMP
-/* Kernel wide locking */
-EXPORT_SYMBOL(kernel_flag);
-
 /* IRQ implementation. */
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(synchronize_irq);
diff -Nru a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
--- a/arch/sparc/kernel/sun4c_irq.c	Tue Aug 27 12:27:59 2002
+++ b/arch/sparc/kernel/sun4c_irq.c	Tue Aug 27 12:27:59 2002
@@ -10,12 +10,12 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff -Nru a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
--- a/arch/sparc/kernel/sun4d_irq.c	Tue Aug 27 12:27:40 2002
+++ b/arch/sparc/kernel/sun4d_irq.c	Tue Aug 27 12:27:40 2002
@@ -7,12 +7,12 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/random.h>
@@ -198,7 +198,7 @@
 	
 	cc_set_iclr(1 << irq);
 	
-	irq_enter(cpu, irq);
+	irq_enter();
 	kstat.irqs[cpu][irq]++;
 	if (!sbusl) {
 		action = *(irq + irq_action);
@@ -239,9 +239,7 @@
 					}
 			}
 	}
-	irq_exit(cpu, irq);
-	if (softirq_pending(cpu))
-		do_softirq();
+	irq_exit();
 }
 
 unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
--- a/arch/sparc/kernel/sun4d_smp.c	Tue Aug 27 12:27:59 2002
+++ b/arch/sparc/kernel/sun4d_smp.c	Tue Aug 27 12:27:59 2002
@@ -458,9 +458,9 @@
 	if(!--prof_counter[cpu]) {
 		int user = user_mode(regs);
 
-		irq_enter(cpu, 0);
+		irq_enter();
 		update_process_times(user);
-		irq_exit(cpu, 0);
+		irq_exit();
 
 		prof_counter[cpu] = prof_multiplier[cpu];
 	}
diff -Nru a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
--- a/arch/sparc/kernel/sun4m_irq.c	Tue Aug 27 12:28:07 2002
+++ b/arch/sparc/kernel/sun4m_irq.c	Tue Aug 27 12:28:07 2002
@@ -10,12 +10,12 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
--- a/arch/sparc/kernel/sun4m_smp.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc/kernel/sun4m_smp.c	Tue Aug 27 12:28:08 2002
@@ -445,9 +445,9 @@
 	if(!--prof_counter[cpu]) {
 		int user = user_mode(regs);
 
-		irq_enter(cpu, 0);
+		irq_enter();
 		update_process_times(user);
-		irq_exit(cpu, 0);
+		irq_exit();
 
 		prof_counter[cpu] = prof_multiplier[cpu];
 	}
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Tue Aug 27 12:28:06 2002
+++ b/arch/sparc/kernel/systbls.S	Tue Aug 27 12:28:06 2002
@@ -49,7 +49,7 @@
 /*140*/	.long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
 /*145*/	.long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
-/*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
+/*155*/	.long sys_fcntl64, sys_security, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 /*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
 /*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
diff -Nru a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
--- a/arch/sparc/mm/fault.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc/mm/fault.c	Tue Aug 27 12:28:02 2002
@@ -10,6 +10,7 @@
 
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/threads.h>
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Tue Aug 27 12:27:54 2002
+++ b/arch/sparc/mm/srmmu.c	Tue Aug 27 12:27:54 2002
@@ -49,6 +49,26 @@
 
 #include <asm/btfixup.h>
 
+/*
+ * To support pagetables in highmem, Linux introduces APIs which
+ * return struct page* and generally manipulate page tables when
+ * they are not mapped into kernel space. Our hardware page tables
+ * are smaller than pages. We lump hardware tabes into big, page sized
+ * software tables.
+ *
+ * PMD_SHIFT determines the size of the area a second-level page table entry
+ * can map, and our pmd_t is 16 times larger than normal.
+ */
+#define SRMMU_PTRS_PER_PMD_SOFT    0x4	/* Each pmd_t contains 16 hard PTPs */
+#define SRMMU_PTRS_PER_PTE_SOFT  0x400	/* 16 hard tables per 4K page */
+#define SRMMU_PTE_SZ_SOFT       0x1000	/* same as above, in bytes */
+
+#define SRMMU_PMD_SHIFT_SOFT	22
+#define SRMMU_PMD_SIZE_SOFT	(1UL << SRMMU_PMD_SHIFT_SOFT)
+#define SRMMU_PMD_MASK_SOFT	(~(SRMMU_PMD_SIZE_SOFT-1))
+// #define SRMMU_PMD_ALIGN(addr)  (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+
+
 enum mbus_module srmmu_modtype;
 unsigned int hwbug_bitmask;
 int vac_cache_size;
@@ -129,36 +149,30 @@
 #define __nocache_va(PADDR) (__va((unsigned long)PADDR) - (unsigned long)srmmu_nocache_pool + SRMMU_NOCACHE_VADDR)
 #define __nocache_fix(VADDR) __va(__nocache_pa(VADDR))
 
-static inline unsigned long srmmu_pgd_page(pgd_t pgd)
-{ return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__nocache_va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
-
-static inline unsigned long srmmu_pmd_page_kernel(pmd_t pmd)
-{
-	return (unsigned long)
-	    __nocache_va((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4);
-}
-
-static struct page *srmmu_pmd_page(pmd_t pmd)	/* XXX inline later */
+static inline unsigned long srmmu_pte_pfn(pte_t pte)
 {
-
-	if (srmmu_device_memory(pmd_val(pmd))) {
+	if (srmmu_device_memory(pte_val(pte))) {
 		/* XXX Anton obviously had something in mind when he did this.
 		 * But what?
 		 */
 		/* return (struct page *)~0; */
-		BUG();	/* NO WAY */
+		BUG();
 	}
-	return virt_to_page(srmmu_pmd_page_kernel(pmd));
+	return (pte_val(pte) & SRMMU_PTE_PMASK) >> (PAGE_SHIFT-4);
 }
 
-static inline unsigned long srmmu_pte_pfn(pte_t pte)
+static struct page *srmmu_pmd_page(pmd_t pmd)
 {
-	if (srmmu_device_memory(pte_val(pte)))
+
+	if (srmmu_device_memory(pmd_val(pmd)))
 		BUG();
-	return (unsigned long)
-	    (((pte_val(pte) & SRMMU_PTE_PMASK) << 4) >> PAGE_SHIFT);
+	return pfn_to_page((pmd_val(pmd) & SRMMU_PTD_PMASK) >> (PAGE_SHIFT-4));
 }
 
+static inline unsigned long srmmu_pgd_page(pgd_t pgd)
+{ return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__nocache_va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
+
+
 static inline int srmmu_pte_none(pte_t pte)
 { return !(pte_val(pte) & 0xFFFFFFF); }
 
@@ -177,8 +191,11 @@
 static inline int srmmu_pmd_present(pmd_t pmd)
 { return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
 
-static inline void srmmu_pmd_clear(pmd_t *pmdp)
-{ srmmu_set_pte((pte_t *)pmdp, __pte(0)); }
+static inline void srmmu_pmd_clear(pmd_t *pmdp) {
+	int i;
+	for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++)
+		srmmu_set_pte((pte_t *)&pmdp->pmdv[i], __pte(0));
+}
 
 static inline int srmmu_pgd_none(pgd_t pgd)          
 { return !(pgd_val(pgd) & 0xFFFFFFF); }
@@ -224,7 +241,7 @@
  * and a page entry and page directory to the page they refer to.
  */
 static pte_t srmmu_mk_pte(struct page *page, pgprot_t pgprot)
-{ return __pte((((page - mem_map) << PAGE_SHIFT) >> 4) | pgprot_val(pgprot)); }
+{ return __pte(((page - mem_map) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); }
 
 static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
 { return __pte(((page) >> 4) | pgprot_val(pgprot)); }
@@ -239,16 +256,28 @@
 static inline void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
 { srmmu_set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pmdp) >> 4))); }
 
-static inline void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+static void srmmu_pmd_set(pmd_t *pmdp, pte_t *ptep)
 {
-	srmmu_set_pte((pte_t *)pmdp,
-	    (SRMMU_ET_PTD | (__nocache_pa((unsigned long) ptep) >> 4)));
+	unsigned long ptp;	/* Physical address, shifted right by 4 */
+	int i;
+
+	ptp = __nocache_pa((unsigned long) ptep) >> 4;
+	for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) {
+		srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
+		ptp += (SRMMU_PTRS_PER_PTE*sizeof(pte_t) >> 4);
+	}
 }
 
-static inline void srmmu_pmd_populate(pmd_t * pmdp, struct page * ptep)
+static void srmmu_pmd_populate(pmd_t *pmdp, struct page *ptep)
 {
-	srmmu_set_pte((pte_t *)pmdp,
-	    (SRMMU_ET_PTD | (((ptep - mem_map) << PAGE_SHIFT) >> 4)));
+	unsigned long ptp;	/* Physical address, shifted right by 4 */
+	int i;
+
+	ptp = (ptep - mem_map) << (PAGE_SHIFT-4);	/* watch for overflow */
+	for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) {
+		srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
+		ptp += (SRMMU_PTRS_PER_PTE*sizeof(pte_t) >> 4);
+	}
 }
 
 static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
@@ -260,19 +289,27 @@
 
 /* Find an entry in the second-level page table.. */
 static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
-{ return (pmd_t *) srmmu_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); }
+{
+	return (pmd_t *) srmmu_pgd_page(*dir) +
+	    ((address >> SRMMU_PMD_SHIFT_SOFT) & (SRMMU_PTRS_PER_PMD_SOFT - 1));
+}
 
 /* Find an entry in the third-level page table.. */ 
 static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
 {
-	unsigned long pte;
+	void *pte;
 
-	pte = srmmu_pmd_page_kernel(*dir);
+	pte = __nocache_va((dir->pmdv[0] & SRMMU_PTD_PMASK) << 4);
 	return (pte_t *) pte +
-			((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+	    ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE_SOFT - 1));
 }
 
-unsigned long __srmmu_get_nocache(int size, int align)
+/*
+ * size: bytes to allocate in the nocache area.
+ * align: bytes, number to align at.
+ * Returns the virtual address of the allocated area.
+ */
+static unsigned long __srmmu_get_nocache(int size, int align)
 {
 	int offset = srmmu_nocache_low;
 	int i;
@@ -423,36 +460,55 @@
 	srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE);
 }
 
-static pte_t *srmmu_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+static pmd_t *srmmu_pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	return (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE);
+	return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
 }
 
-static struct page *srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address)
+static void srmmu_pmd_free(pmd_t * pmd)
 {
-	return virt_to_page(srmmu_pte_alloc_one_kernel(mm, address));
+	srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE);
 }
 
-static void srmmu_free_pte_fast(pte_t *pte)
+/*
+ * Hardware needs alignment to 256 only, but we align to whole page size
+ * to reduce fragmentation problems due to the buddy principle.
+ * XXX Provide actual fragmentation statistics in /proc.
+ *
+ * Alignments up to the page size are the same for physical and virtual
+ * addresses of the nocache area.
+ */
+static pte_t *
+srmmu_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-	srmmu_free_nocache((unsigned long)pte, SRMMU_PTE_TABLE_SIZE);
+	return (pte_t *)srmmu_get_nocache(SRMMU_PTE_SZ_SOFT, SRMMU_PTE_SZ_SOFT);
 }
 
-static void srmmu_pte_free(struct page *pte)
+static struct page *
+srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	srmmu_free_nocache((unsigned long)page_address(pte), SRMMU_PTE_TABLE_SIZE);
+	unsigned long pte;
+
+	if ((pte = (unsigned long)srmmu_pte_alloc_one_kernel(mm, address)) == 0)
+		return NULL;
+	return mem_map + (__nocache_pa(pte) >> PAGE_SHIFT);
 }
 
-static pmd_t *srmmu_pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static void srmmu_free_pte_fast(pte_t *pte)
 {
-	return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
+	srmmu_free_nocache((unsigned long)pte, SRMMU_PTE_SZ_SOFT);
 }
 
-static void srmmu_free_pmd_fast(pmd_t * pmd)
+static void srmmu_pte_free(struct page *pte)
 {
-	srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE);
+	unsigned long p = (unsigned long)page_address(pte);
+	if (p == 0)
+		BUG();
+	srmmu_free_nocache(p, SRMMU_PTE_SZ_SOFT);
 }
 
+/*
+ */
 static inline void alloc_context(struct mm_struct *old_mm, struct mm_struct *mm)
 {
 	struct ctx_list *ctxp;
@@ -966,7 +1022,8 @@
 	while(start < end) {
 		pgdp = pgd_offset_k(start);
 		if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
-			pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
+			pmdp = (pmd_t *) __srmmu_get_nocache(
+			    SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
 			if (pmdp == NULL)
 				early_pgtable_allocfail("pmd");
 			memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
@@ -974,10 +1031,11 @@
 		}
 		pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start);
 		if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
-			ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE);
+			ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_SZ_SOFT,
+			    SRMMU_PTE_SZ_SOFT);
 			if (ptep == NULL)
 				early_pgtable_allocfail("pte");
-			memset(__nocache_fix(ptep), 0, SRMMU_PTE_TABLE_SIZE);
+			memset(__nocache_fix(ptep), 0, SRMMU_PTE_SZ_SOFT);
 			srmmu_pmd_set(__nocache_fix(pmdp), ptep);
 		}
 		start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK;
@@ -1001,10 +1059,11 @@
 		}
 		pmdp = srmmu_pmd_offset(pgdp, start);
 		if(srmmu_pmd_none(*pmdp)) {
-			ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE);
+			ptep = (pte_t *) __srmmu_get_nocache(SRMMU_PTE_SZ_SOFT,
+			    SRMMU_PTE_SZ_SOFT);
 			if (ptep == NULL)
 				early_pgtable_allocfail("pte");
-			memset(ptep, 0, SRMMU_PTE_TABLE_SIZE);
+			memset(ptep, 0, SRMMU_PTE_SZ_SOFT);
 			srmmu_pmd_set(pmdp, ptep);
 		}
 		start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK;
@@ -1062,18 +1121,26 @@
 			srmmu_pgd_set(__nocache_fix(pgdp), pmdp);
 		}
 		pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start);
-		if(what == 1) {
-			*(pmd_t *)__nocache_fix(pmdp) = __pmd(prompte);
-			start += SRMMU_PMD_SIZE;
-			continue;
-		}
 		if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
-			ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE);
+			ptep = (pte_t *) __srmmu_get_nocache(SRMMU_PTE_SZ_SOFT,
+			    SRMMU_PTE_SZ_SOFT);
 			if (ptep == NULL)
 				early_pgtable_allocfail("pte");
-			memset(__nocache_fix(ptep), 0, SRMMU_PTE_TABLE_SIZE);
+			memset(__nocache_fix(ptep), 0, SRMMU_PTE_SZ_SOFT);
 			srmmu_pmd_set(__nocache_fix(pmdp), ptep);
 		}
+		if(what == 1) {
+			/*
+			 * We bend the rule where all 16 PTPs in a pmd_t point
+			 * inside the same PTE page, and we leak a perfectly
+			 * good hardware PTE piece. Alternatives seem worse.
+			 */
+			unsigned int x;	/* Index of HW PMD in soft cluster */
+			x = (start >> SRMMU_PMD_SHIFT) & 15;
+			*(ulong *)__nocache_fix(&pmdp->pmdv[x]) = prompte;
+			start += SRMMU_PMD_SIZE;
+			continue;
+		}
 		ptep = srmmu_pte_offset(__nocache_fix(pmdp), start);
 		*(pte_t *)__nocache_fix(ptep) = __pte(prompte);
 		start += PAGE_SIZE;
@@ -2032,17 +2099,17 @@
 	extern void ld_mmu_iommu(void);
 	extern void ld_mmu_iounit(void);
 	extern void ___xchg32_sun4md(void);
-	
-	/* First the constants */
-	BTFIXUPSET_SIMM13(pmd_shift, SRMMU_PMD_SHIFT);
-	BTFIXUPSET_SETHI(pmd_size, SRMMU_PMD_SIZE);
-	BTFIXUPSET_SETHI(pmd_mask, SRMMU_PMD_MASK);
+
+	BTFIXUPSET_SIMM13(pmd_shift, SRMMU_PMD_SHIFT_SOFT);
+	BTFIXUPSET_SETHI(pmd_size, SRMMU_PMD_SIZE_SOFT);
+	BTFIXUPSET_SETHI(pmd_mask, SRMMU_PMD_MASK_SOFT);
+
 	BTFIXUPSET_SIMM13(pgdir_shift, SRMMU_PGDIR_SHIFT);
 	BTFIXUPSET_SETHI(pgdir_size, SRMMU_PGDIR_SIZE);
 	BTFIXUPSET_SETHI(pgdir_mask, SRMMU_PGDIR_MASK);
 
-	BTFIXUPSET_SIMM13(ptrs_per_pte, SRMMU_PTRS_PER_PTE);
-	BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD);
+	BTFIXUPSET_SIMM13(ptrs_per_pte, SRMMU_PTRS_PER_PTE_SOFT);
+	BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD_SOFT);
 	BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
 
 	BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
@@ -2090,12 +2157,13 @@
 	BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK);
 	BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_offset_kernel, srmmu_pte_offset, BTFIXUPCALL_NORM);
+
 	BTFIXUPSET_CALL(free_pte_fast, srmmu_free_pte_fast, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_free, srmmu_pte_free, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_alloc_one_kernel, srmmu_pte_alloc_one_kernel, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_alloc_one, srmmu_pte_alloc_one, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(free_pmd_fast, srmmu_free_pmd_fast, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_alloc_one_fast, srmmu_pmd_alloc_one_fast, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(free_pmd_fast, srmmu_pmd_free, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(pmd_alloc_one, srmmu_pmd_alloc_one, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(free_pgd_fast, srmmu_free_pgd_fast, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_NORM);
 
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Tue Aug 27 12:28:01 2002
+++ b/arch/sparc/mm/sun4c.c	Tue Aug 27 12:28:01 2002
@@ -1710,13 +1710,13 @@
 
 static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
 {
-	*pmdp = __pmd(PGD_TABLE | (unsigned long) ptep);
+	pmdp->pmdv[0] = PGD_TABLE | (unsigned long) ptep;
 }
 
 static void sun4c_pmd_populate(pmd_t * pmdp, struct page * ptep)
 {
 	if (page_address(ptep) == NULL) BUG();	/* No highmem on sun4c */
-	*pmdp = __pmd(PGD_TABLE | (unsigned long) page_address(ptep));
+	pmdp->pmdv[0] = PGD_TABLE | (unsigned long) page_address(ptep);
 }
 
 static int sun4c_pte_present(pte_t pte)
@@ -1735,7 +1735,14 @@
 {
 	return ((pmd_val(pmd) & PGD_PRESENT) != 0);
 }
+
+#if 0 /* if PMD takes one word */
 static void sun4c_pmd_clear(pmd_t *pmdp)	{ *pmdp = __pmd(0); }
+#else /* if pmd_t is a longish aggregate */
+static void sun4c_pmd_clear(pmd_t *pmdp) {
+	memset((void *)pmdp, 0, sizeof(pmd_t));
+}
+#endif
 
 static int sun4c_pgd_none(pgd_t pgd)		{ return 0; }
 static int sun4c_pgd_bad(pgd_t pgd)		{ return 0; }
@@ -1913,7 +1920,7 @@
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-static pmd_t *sun4c_pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static pmd_t *sun4c_pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
 	BUG();
 	return NULL;
@@ -2176,7 +2183,7 @@
 	BTFIXUPSET_CALL(pte_alloc_one_kernel, sun4c_pte_alloc_one_kernel, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_alloc_one, sun4c_pte_alloc_one, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(free_pmd_fast, sun4c_free_pmd_fast, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(pmd_alloc_one_fast, sun4c_pmd_alloc_one_fast, BTFIXUPCALL_RETO0);
+	BTFIXUPSET_CALL(pmd_alloc_one, sun4c_pmd_alloc_one, BTFIXUPCALL_RETO0);
 	BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM);
 
diff -Nru a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c
--- a/arch/sparc/prom/printf.c	Tue Aug 27 12:27:59 2002
+++ b/arch/sparc/prom/printf.c	Tue Aug 27 12:27:59 2002
@@ -1,11 +1,15 @@
-/* $Id: printf.c,v 1.7 2000/02/08 20:24:23 davem Exp $
+/*
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* This routine is internal to the prom library, no one else should know
- * about or use it!  It's simple and smelly anyway....
+ * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * We used to warn all over the code: DO NOT USE prom_printf(),
+ * and yet people do. Anton's banking code was outputing banks
+ * with prom_printf for most of the 2.4 lifetime. Since an effective
+ * stick is not available, we deployed a carrot: an early printk
+ * through PROM by means of -p boot option. This ought to fix it.
+ * USE printk; if you need, deploy -p.
  */
 
 #include <linux/kernel.h>
@@ -16,23 +20,27 @@
 static char ppbuf[1024];
 
 void
+prom_write(const char *buf, unsigned int n)
+{
+	char ch;
+
+	while (n != 0) {
+		--n;
+		if ((ch = *buf++) == '\n')
+			prom_putchar('\r');
+		prom_putchar(ch);
+	}
+}
+
+void
 prom_printf(char *fmt, ...)
 {
 	va_list args;
-	char ch, *bptr;
 	int i;
 
 	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
+	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
-	return;
+
+	prom_write(ppbuf, i);
 }
diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in
--- a/arch/sparc64/config.in	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/config.in	Tue Aug 27 12:28:02 2002
@@ -95,10 +95,6 @@
 
 endmenu
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL device support'
 
@@ -207,6 +203,8 @@
 source drivers/ieee1394/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/defconfig	Tue Aug 27 12:28:02 2002
@@ -35,6 +35,7 @@
 CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
 # CONFIG_ISA is not set
 # CONFIG_ISAPNP is not set
 # CONFIG_EISA is not set
@@ -94,7 +95,9 @@
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_ATY_CT=y
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
@@ -110,9 +113,12 @@
 # CONFIG_FB_CGTHREE is not set
 # CONFIG_FB_LEO is not set
 CONFIG_FB_PCI=y
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_ACCEL=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
 CONFIG_FONT_SUN8x16=y
 # CONFIG_FBCON_FONTS is not set
@@ -185,78 +191,6 @@
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK_DEV=y
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-CONFIG_ARPD=y
-CONFIG_INET_ECN=y
-# CONFIG_SYN_COOKIES is not set
-CONFIG_IPV6=m
-# CONFIG_ATM is not set
-CONFIG_VLAN_8021Q=m
-
-#
-#  
-#
-CONFIG_IPX=m
-# CONFIG_IPX_INTERN is not set
-CONFIG_ATALK=m
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-CONFIG_DECNET=m
-CONFIG_DECNET_SIOCGIFCONF=y
-# CONFIG_DECNET_ROUTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-CONFIG_LLC=m
-CONFIG_LLC_UI=y
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_QOS=y
-CONFIG_NET_ESTIMATOR=y
-CONFIG_NET_CLS=y
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_ROUTE=y
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_NET_CLS_POLICE=y
-
-#
 # ATA/ATAPI/MFM/RLL device support
 #
 CONFIG_IDE=y
@@ -420,6 +354,71 @@
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
 #
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_ARPD=y
+CONFIG_INET_ECN=y
+# CONFIG_SYN_COOKIES is not set
+CONFIG_IPV6=m
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_LLC=m
+CONFIG_LLC_UI=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK is not set
+CONFIG_DECNET=m
+CONFIG_DECNET_SIOCGIFCONF=y
+# CONFIG_DECNET_ROUTER is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -942,6 +941,7 @@
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
 # CONFIG_BLUEZ_HCIBLUECARD is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
diff -Nru a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
--- a/arch/sparc64/kernel/chmc.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/chmc.c	Tue Aug 27 12:28:02 2002
@@ -424,7 +424,7 @@
 	int index;
 
 	/* This driver is only for cheetah platforms. */
-	if (tlb_type != cheetah)
+	if (tlb_type != cheetah && tlb_type != cheetah_plus)
 		return -ENODEV;
 
 	index = probe_for_string("memory-controller", 0);
diff -Nru a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
--- a/arch/sparc64/kernel/cpu.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc64/kernel/cpu.c	Tue Aug 27 12:28:08 2002
@@ -33,6 +33,7 @@
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
   { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
+  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -44,6 +45,7 @@
   { 0x17, 0x12, "TI UltraSparc IIi"},
   { 0x17, 0x13, "TI UltraSparc IIe"},
   { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
+  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff -Nru a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
--- a/arch/sparc64/kernel/devices.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/devices.c	Tue Aug 27 12:28:02 2002
@@ -63,7 +63,8 @@
 				if (tlb_type == spitfire) {
 					prom_getproperty(scan, "upa-portid",
 							 (char *) &thismid, sizeof(thismid));
-				} else if (tlb_type == cheetah) {
+				} else if (tlb_type == cheetah ||
+					   tlb_type == cheetah_plus) {
 					prom_getproperty(scan, "portid",
 							 (char *) &thismid, sizeof(thismid));
 				}
diff -Nru a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
--- a/arch/sparc64/kernel/dtlb_base.S	Tue Aug 27 12:28:06 2002
+++ b/arch/sparc64/kernel/dtlb_base.S	Tue Aug 27 12:28:06 2002
@@ -73,7 +73,7 @@
 	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
-	cmp		%g5, 3				! Last trap level?
+	cmp		%g5, 4				! Last trap level?
 	be,pn		%xcc, longpath			! Yep, cannot risk VPTE miss
 	 nop						! delay slot
 
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Tue Aug 27 12:27:39 2002
+++ b/arch/sparc64/kernel/entry.S	Tue Aug 27 12:27:39 2002
@@ -774,7 +774,14 @@
 	membar		#Sync
 	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etraptl1
-	 or		%g7, %lo(109f), %g7	! Merge in below
+109:	 or		%g7, %lo(109b), %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		instruction_access_exception_tl1
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
 __do_instruction_access_exception:
 	rdpr		%pstate, %g4
 	wrpr		%g4, PSTATE_MG|PSTATE_AG, %pstate
@@ -1074,6 +1081,181 @@
 	jmpl		%g2 + %lo(cheetah_deferred_trap), %g0
 	 mov		1, %g1
 
+	/* Cheetah+ specific traps. These are for the new I/D cache parity
+	 * error traps.  The first argument to cheetah_plus_parity_handler
+	 * is encoded as follows:
+	 *
+	 * Bit0:	0=dcache,1=icache
+	 * Bit1:	0=recoverable,1=unrecoverable
+	 */
+	.globl		cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1
+cheetah_plus_dcpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_data_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_data_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_data_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x0, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_dcpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_dcpe_tl1), %g3
+	jmpl		%g3 + %lo(do_dcpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	.globl		cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1
+cheetah_plus_icpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_insn_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_insn_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_insn_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x1, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_icpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_icpe_tl1), %g3
+	jmpl		%g3 + %lo(do_icpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	/* If we take one of these traps when tl >= 1, then we
+	 * jump to interrupt globals.  If some trap level above us
+	 * was also using interrupt globals, we cannot recover.
+	 * We may use all interrupt global registers except %g6.
+	 */
+	.globl		do_dcpe_tl1, do_icpe_tl1
+do_dcpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_dcpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_dcpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Reset D-cache parity */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1		! Move down 1 cacheline
+1:	srl		%g1, 14, %g3		! Compute UTAG
+	membar		#Sync
+	stxa		%g3, [%g1] ASI_DCACHE_UTAG
+	membar		#Sync
+	sub		%g2, 8, %g3		! 64-bit data word within line
+2:	membar		#Sync
+	stxa		%g0, [%g1 + %g3] ASI_DCACHE_DATA
+	membar		#Sync
+	subcc		%g3, 8, %g3		! Next 64-bit data word
+	bge,pt		%icc, 2b
+	 nop
+	subcc		%g1, %g2, %g1		! Next cacheline
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_dcpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x2, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+do_icpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_icpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_icpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Flush I-cache */
+	sethi		%hi(1 << 15), %g1	! I-cache size
+	mov		(1 << 5), %g2		! I-cache line size
+	sub		%g1, %g2, %g1
+1:	or		%g1, (2 << 3), %g3
+	stxa		%g0, [%g3] ASI_IC_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_icpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x3, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+	
+dcpe_icpe_tl1_common:
+	/* Flush D-cache, re-enable D/I caches in DCU and finally
+	 * retry the trapping instruction.
+	 */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1
+1:	stxa		%g0, [%g1] ASI_DCACHE_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	or		%g1, (DCU_DC | DCU_IC), %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	retry
+
 	/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
 	 * in the trap table.  That code has done a memory barrier
 	 * and has disabled both the I-cache and D-cache in the DCU
@@ -1639,11 +1821,16 @@
 	or	%g2, %lo(xtime), %g2
 	or	%g1, %lo(timer_tick_compare), %g1
 1:	rdpr	%ver, %o2
-	sethi	%hi(0x003e0014), %o1
+	sethi	%hi(CHEETAH_ID), %o1
 	srlx	%o2, 32, %o2
-	or	%o1, %lo(0x003e0014), %o1
+	or	%o1, %lo(CHEETAH_ID), %o1
 	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
+	cmp	%o2, %o1
+	be,a,pn	%xcc, 3f
+	 rd	%asr24, %o1
+	sethi	%hi(CHEETAH_PLUS_ID), %o1
+	or	%o1, %lo(CHEETAH_PLUS_ID), %o1
 	cmp	%o2, %o1
 	bne,pt	%xcc, 2f
 	 nop
diff -Nru a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
--- a/arch/sparc64/kernel/etrap.S	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/etrap.S	Tue Aug 27 12:28:02 2002
@@ -109,8 +109,56 @@
 		 stb	%g0, [%l4 + %l3]					! Store		Group
 		nop
 
-etraptl1:	rdpr	%tstate, %g1						! Single	Group+4bubbles
-		sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+etraptl1:	/* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
+		 * We place this right after pt_regs on the trap stack.  The layout
+		 * is:
+		 *	0x00	TL1's TSTATE
+		 *	0x08	TL1's TPC
+		 *	0x10	TL1's TNPC
+		 *	 ...
+		 *	0x58	TL4's TNPC
+		 *	0x60	TL
+		 */
+		sub	%sp, (24 * 8) + 8, %g2
+		rdpr	%tl, %g1
+
+		wrpr	%g0, 1, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x00]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x08]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x10]
+
+		wrpr	%g0, 2, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x18]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x20]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x28]
+
+		wrpr	%g0, 3, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x30]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x38]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x40]
+
+		wrpr	%g0, 4, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x48]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x50]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x58]
+
+		wrpr	%g1, %tl
+		stx	%g1, [%g2 + STACK_BIAS + 0x60]
+
+		rdpr	%tstate, %g1						! Single	Group+4bubbles
+		sub	%g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
 		ba,pt	%xcc, 1b						! CTI		Group
 		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
 
diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
--- a/arch/sparc64/kernel/head.S	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/head.S	Tue Aug 27 12:28:02 2002
@@ -79,24 +79,34 @@
 	 */
 sparc64_boot:
 	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
+	sethi	%hi(CHEETAH_ID), %g5
 	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
+	or	%g5, %lo(CHEETAH_ID), %g5
+	cmp	%g1, %g5
+	be,pn	%icc, cheetah_boot
+	 sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp	%g1, %g5
 	bne,pt	%icc, spitfire_boot
 	 nop
 
+cheetah_plus_boot:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_boot
+	 nop
+
 cheetah_boot:
 	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr	%g1, %asr18
 
-	sethi	%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or	%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sethi	%uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
 	sllx	%g5, 32, %g5
 	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
 	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar	#Sync
 
+cheetah_generic_boot:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -149,6 +159,7 @@
 	 add	%l0, (1 << 3), %l0
 
 cheetah_got_tlbentry:
+	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
 	membar	#Sync
 	and	%g1, %g3, %g1
@@ -200,6 +211,36 @@
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
 
+	/* On Cheetah+, have to check second DTLB.  */
+	rdpr	%ver, %g1
+	srlx	%g1, 32, %g1
+	sethi	%hi(CHEETAH_PLUS_ID), %l0
+	or	%l0, %lo(CHEETAH_PLUS_ID), %l0
+	cmp	%g1, %l0
+	bne,pt	%icc, 9f
+	 nop
+
+	set	3 << 16, %l0
+1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	
+2:	and	%l0, (511 << 3), %g1
+	cmp	%g1, (511 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+9:
+
 	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
 	 * entry 15 (and maybe 14 too).
 	 */
@@ -429,20 +470,26 @@
 	membar	#Sync
 
 	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
+	sethi	%hi(CHEETAH_ID), %g5
 	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
+	or	%g5, %lo(CHEETAH_ID), %g5
+	cmp	%g1, %g5
+	be,pn	%icc, cheetah_tlb_fixup
+	 sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp	%g1, %g5
 	bne,pt	%icc, spitfire_tlb_fixup
 	 nop
 
 cheetah_tlb_fixup:
 	set	(0 << 16) | (15 << 3), %g7
+	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
 	membar	#Sync
 
+	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
@@ -452,9 +499,17 @@
 	flush	%g3
 	membar	#Sync
 
-	/* Set TLB type to cheetah. */
-	mov	1, %g2
-	sethi	%hi(tlb_type), %g5
+	sethi	%hi(CHEETAH_PLUS_ID), %g5
+	or	%g5, %lo(CHEETAH_PLUS_ID), %g5
+	rdpr	%ver, %g2
+	srlx	%g2, 32, %g2
+	cmp	%g2, %g5
+	bne,a,pt %icc, 1f
+	 mov	1, %g2		/* Set TLB type to cheetah. */
+
+	mov	2, %g2		/* Set TLB type to cheetah+. */
+
+1:	sethi	%hi(tlb_type), %g5
 	stw	%g2, [%g5 + %lo(tlb_type)]
 
 	/* Patch copy/page operations to cheetah optimized versions. */
@@ -462,6 +517,8 @@
 	 nop
 	call	cheetah_patch_pgcopyops
 	 nop
+	call	cheetah_patch_cachetlbops
+	 nop
 
 	ba,pt	%xcc, tlb_fixup_done
 	 nop
@@ -575,18 +632,23 @@
 	or	%g2, KERN_LOWBITS, %g2
 
 	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
+	sethi		%hi(CHEETAH_ID), %g7
 	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
+	or		%g7, %lo(CHEETAH_ID), %g7
+	cmp		%g3, %g7
+	be,pn		%icc, cheetah_vpte_base
+	sethi		%hi(CHEETAH_PLUS_ID), %g7
+	or		%g7, %lo(CHEETAH_PLUS_ID), %g7
 	cmp		%g3, %g7
-	bne,pt		%icc, 1f
+	bne,pt		%icc, spitfire_vpte_base
 	 nop
 
+cheetah_vpte_base:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
 	 sllx		%g3, 32, %g3
-1:
+spitfire_vpte_base:
 	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
 	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
 	sllx		%g3, 32, %g3
@@ -614,13 +676,18 @@
 
 not_starfire:
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,pn		%icc, is_cheetah
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,pt		%icc, not_cheetah
 	 nop
 
+is_cheetah:
 	ldxa		[%g0] ASI_SAFARI_CONFIG, %g1
 	srlx		%g1, 17, %g1
 	ba,pt		%xcc, set_worklist
@@ -644,14 +711,19 @@
 	wr	%g0, 0, %tick_cmpr
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
 	cmp		%g1, %g5
-	bne,pt		%icc, 1f
+	be,pn		%icc, 1f
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
+	cmp		%g1, %g5
+	bne,pt		%icc, 2f
 	 nop
 
 	/* Disable STICK_INT interrupts. */
+1:
 	sethi		%hi(0x80000000), %g1
 	sllx		%g1, 32, %g1
 	wr		%g1, %asr25
@@ -659,7 +731,7 @@
 	/* Ok, we're done setting up all the state our trap mechanims needs,
 	 * now get back into normal globals and let the PROM know what is up.
 	 */
-1:
+2:
 	wrpr	%g0, %g0, %wstate
 	wrpr	%o1, PSTATE_IE, %pstate
 
diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
--- a/arch/sparc64/kernel/irq.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/irq.c	Tue Aug 27 12:28:02 2002
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -162,7 +163,7 @@
 	if (imap == 0UL)
 		return;
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* We set it to our Safari AID. */
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (tid)
@@ -1068,7 +1069,7 @@
 			goal_cpu = 0;
 	}
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		tid = goal_cpu << 26;
 		tid &= IMAP_AID_SAFARI;
 	} else if (this_is_starfire == 0) {
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Tue Aug 27 12:27:40 2002
+++ b/arch/sparc64/kernel/pci.c	Tue Aug 27 12:27:40 2002
@@ -114,6 +114,53 @@
 	printk("PCI: Ignoring controller...\n");
 }
 
+static int pci_is_controller(char *model_name, int namelen, int node)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
+		if (!strncmp(model_name,
+			     pci_controller_table[i].model_name,
+			     namelen)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* Is there some PCI controller in the system?  */
+int pcic_present(void)
+{
+	char namebuf[16];
+	int node;
+
+	node = prom_getchild(prom_root_node);
+	while ((node = prom_searchsiblings(node, "pci")) != 0) {
+		int len, ret;
+
+		len = prom_getproperty(node, "model",
+				       namebuf, sizeof(namebuf));
+
+		ret = 0;
+		if (len > 0) {
+			ret = pci_is_controller(namebuf, len, node);
+		} else {
+			len = prom_getproperty(node, "compatible",
+					       namebuf, sizeof(namebuf));
+			if (len > 0)
+				ret = pci_is_controller(namebuf, len, node);
+		}
+		if (ret)
+			return ret;
+
+		node = prom_getsibling(node);
+		if (!node)
+			break;
+	}
+
+	return 0;
+}
+
 /* Find each controller in the system, attach and initialize
  * software state structure for each and link into the
  * pci_controller_root.  Setup the controller enough such
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Tue Aug 27 12:28:05 2002
+++ b/arch/sparc64/kernel/process.c	Tue Aug 27 12:28:05 2002
@@ -591,6 +591,8 @@
 	p->thread.smp_lock_pc = 0;
 #endif
 
+	p->user_tid = NULL;
+
 	/* Calculate offset to stack_frame & pt_regs */
 	child_trap_frame = ((char *)t) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
 	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
@@ -647,6 +649,19 @@
 	/* Set the second return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
 
+	if (!(clone_flags & (CLONE_SETTID | CLONE_CLEARTID)))
+		return 0;
+
+	if (t->flags & _TIF_32BIT)
+		t->kregs->u_regs[UREG_G2] &= 0xffffffff;
+
+	if (clone_flags & CLONE_SETTID)
+		if (put_user(p->pid, (int *)t->kregs->u_regs[UREG_G2]))
+			return -EFAULT;
+
+	if (clone_flags & CLONE_CLEARTID)
+		p->user_tid = (int *) t->kregs->u_regs[UREG_G2];
+
 	return 0;
 }
 
@@ -791,6 +806,7 @@
 		current_thread_info()->xfsr[0] = 0;
 		current_thread_info()->fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
+		current->ptrace &= ~PT_DTRACE;
 	}
 out:
 	return error;
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc64/kernel/ptrace.c	Tue Aug 27 12:28:08 2002
@@ -18,6 +18,7 @@
 #include <linux/user.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/security.h>
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
@@ -132,11 +133,19 @@
 	}
 #endif
 	if (request == PTRACE_TRACEME) {
+		int ret;
+
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED) {
 			pt_error_return(regs, EPERM);
 			goto out;
 		}
+		ret = security_ops->ptrace(current->parent, current);
+		if (ret) {
+			pt_error_return(regs, -ret);
+			goto out;
+		}
+
 		/* set the ptrace bit in the process flags. */
 		current->ptrace |= PT_PTRACED;
 		pt_succ_return(regs, 0);
@@ -570,7 +579,7 @@
 	{
 		unsigned long va;
 
-		if (tlb_type == cheetah) {
+		if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 			for (va = 0; va < (1 << 16); va += (1 << 5))
 				spitfire_put_dcache_tag(va, 0x0);
 			/* No need to mess with I-cache on Cheetah. */
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/setup.c	Tue Aug 27 12:28:02 2002
@@ -73,7 +73,7 @@
 static void
 prom_console_write(struct console *con, const char *s, unsigned n)
 {
-	prom_printf("%s", s);
+	prom_write(s, n);
 }
 
 static struct console prom_console = {
@@ -193,7 +193,7 @@
 
 			if (tlb_type == spitfire)
 				tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
 
 			res = PROM_TRUE;
@@ -506,7 +506,7 @@
 		extern unsigned int irqsz_patchme[1];
 		irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
 							SMP_CACHE_BYTES_SHIFT + 1);
-		flushi((long)&irqsz_patchme[1]);
+		flushi((long)&irqsz_patchme[0]);
 	} else {
 		prom_printf("Unexpected size of irq_stat[] elements\n");
 		prom_halt();
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Tue Aug 27 12:27:42 2002
+++ b/arch/sparc64/kernel/smp.c	Tue Aug 27 12:27:42 2002
@@ -46,9 +46,6 @@
 /* Please don't make this stuff initdata!!!  --DaveM */
 static unsigned char boot_cpu_id;
 
-/* Kernel spinlock */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 atomic_t sparc64_num_cpus_online = ATOMIC_INIT(0);
 unsigned long cpu_online_map = 0;
 atomic_t sparc64_num_cpus_possible = ATOMIC_INIT(0);
@@ -558,9 +555,9 @@
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
 extern unsigned long xcall_flush_tlb_kernel_range;
-extern unsigned long xcall_flush_tlb_all;
-extern unsigned long xcall_tlbcachesync;
-extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_flush_tlb_all_spitfire;
+extern unsigned long xcall_flush_tlb_all_cheetah;
+extern unsigned long xcall_flush_cache_all_spitfire;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_flush_dcache_page_cheetah;
@@ -676,13 +673,19 @@
 
 void smp_flush_cache_all(void)
 {
-	smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
-	__flush_cache_all();
+	/* Cheetah need do nothing. */
+	if (tlb_type == spitfire) {
+		smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
+		__flush_cache_all();
+	}
 }
 
 void smp_flush_tlb_all(void)
 {
-	smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+	if (tlb_type == spitfire)
+		smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0);
+	else
+		smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0);
 	__flush_tlb_all();
 }
 
@@ -1115,7 +1118,7 @@
 	 * of moving a process from one cpu to another).
 	 */
 	printk("SMP: Calibrating ecache flush... ");
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		cacheflush_time = cheetah_tune_scheduling();
 		goto report;
 	}
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Tue Aug 27 12:28:02 2002
@@ -101,9 +101,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs);
 
-#ifdef CONFIG_SMP
-extern spinlock_t kernel_flag;
-#ifdef CONFIG_DEBUG_SPINLOCK
+#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
 extern void _do_spin_lock (spinlock_t *lock, char *str);
 extern void _do_spin_unlock (spinlock_t *lock);
 extern int _spin_trylock (spinlock_t *lock);
@@ -112,7 +110,6 @@
 extern void _do_write_lock(rwlock_t *rw, char *str);
 extern void _do_write_unlock(rwlock_t *rw);
 #endif
-#endif
 
 extern unsigned long phys_base;
 extern unsigned long pfn_base;
@@ -126,9 +123,6 @@
 EXPORT_SYMBOL(__write_lock);
 EXPORT_SYMBOL(__write_unlock);
 #endif
-
-/* Kernel wide locking */
-EXPORT_SYMBOL(kernel_flag);
 
 /* Hard IRQ locking */
 #ifdef CONFIG_SMP
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Tue Aug 27 12:28:07 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Tue Aug 27 12:28:07 2002
@@ -57,6 +57,7 @@
 #include <asm/uaccess.h>
 #include <asm/fpumacro.h>
 #include <asm/semaphore.h>
+#include <asm/mmu_context.h>
 
 #include <net/scm.h>
 
@@ -2873,26 +2874,30 @@
 	int retval;
 	int i;
 
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
 	file = open_exec(filename);
 
 	retval = PTR_ERR(file);
 	if (IS_ERR(file))
 		return retval;
 
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
+
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-
+	bprm.security = NULL;
 	bprm.mm = mm_alloc();
 	retval = -ENOMEM;
 	if (!bprm.mm) 
 		goto out_file;
 
+	retval = init_new_context(current, bprm.mm);
+	if (retval < 0)
+		goto out_mm;
+
 	bprm.argc = count32(argv, bprm.p / sizeof(u32));
 	if ((retval = bprm.argc) < 0)
 		goto out_mm;
@@ -2901,6 +2906,10 @@
 	if ((retval = bprm.envc) < 0)
 		goto out_mm;
 
+	retval = security_ops->bprm_alloc_security(&bprm);
+	if (retval) 
+		goto out;
+
 	retval = prepare_binprm(&bprm);
 	if (retval < 0)
 		goto out;
@@ -2919,9 +2928,11 @@
 		goto out;
 
 	retval = search_binary_handler(&bprm, regs);
-	if (retval >= 0)
+	if (retval >= 0) {
 		/* execve success */
+		security_ops->bprm_free_security(&bprm);
 		return retval;
+	}
 
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
@@ -2931,6 +2942,9 @@
 			__free_page(page);
 	}
 
+	if (bprm.security)
+		security_ops->bprm_free_security(&bprm);
+
 out_mm:
 	mmdrop(bprm.mm);
 
@@ -2971,6 +2985,7 @@
 		current_thread_info()->xfsr[0] = 0;
 		current_thread_info()->fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
+		current->ptrace &= ~PT_DTRACE;
 	}
 out:
         return error;
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Tue Aug 27 12:28:05 2002
+++ b/arch/sparc64/kernel/systbls.S	Tue Aug 27 12:28:05 2002
@@ -50,7 +50,7 @@
 /*140*/	.word sys32_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys32_getrlimit
 	.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
-	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
+	.word sys32_fcntl64, sys_security, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys32_sched_setaffinity, sys32_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 	.word sys_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
@@ -109,7 +109,7 @@
 /*140*/	.word sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
 	.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
-	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
+	.word sys_nis_syscall, sys_security, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.word sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_utrap_install
 	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
diff -Nru a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
--- a/arch/sparc64/kernel/trampoline.S	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/kernel/trampoline.S	Tue Aug 27 12:28:02 2002
@@ -34,13 +34,22 @@
 	flushw
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,pn		%icc, cheetah_startup
+	 sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,pt		%icc, spitfire_startup
 	 nop
 
+cheetah_plus_startup:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_startup
+	 nop
+
 cheetah_startup:
 	mov		DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr		%g1, %asr18
@@ -52,6 +61,7 @@
 	stxa		%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar		#Sync
 
+cheetah_generic_startup:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -118,9 +128,14 @@
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,a,pn		%icc, 1f
+	 mov		15, %g2
+	sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,a,pt	%icc, 1f
 	 mov		63, %g2
@@ -153,9 +168,14 @@
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
 	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
+	sethi		%hi(CHEETAH_ID), %g5
 	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
+	or		%g5, %lo(CHEETAH_ID), %g5
+	cmp		%g1, %g5
+	be,a,pn		%icc, 1f
+	 mov		15, %g2
+	sethi		%hi(CHEETAH_PLUS_ID), %g5
+	or		%g5, %lo(CHEETAH_PLUS_ID), %g5
 	cmp		%g1, %g5
 	bne,a,pt	%icc, 1f
 	 mov		63, %g2
@@ -225,13 +245,18 @@
 	or		%g2, KERN_LOWBITS, %g2
 
 	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
+	sethi		%hi(CHEETAH_ID), %g7
 	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
+	or		%g7, %lo(CHEETAH_ID), %g7
+	cmp		%g3, %g7
+	be,pn		%icc, 9f
+	 sethi		%hi(CHEETAH_PLUS_ID), %g7
+	or		%g7, %lo(CHEETAH_PLUS_ID), %g7
 	cmp		%g3, %g7
 	bne,pt		%icc, 1f
 	 nop
 
+9:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc64/kernel/traps.c	Tue Aug 27 12:28:08 2002
@@ -37,6 +37,33 @@
 #include <linux/kmod.h>
 #endif
 
+/* When an irrecoverable trap occurs at tl > 0, the trap entry
+ * code logs the trap state registers at every level in the trap
+ * stack.  It is found at (pt_regs + sizeof(pt_regs)) and the layout
+ * is as follows:
+ */
+struct tl1_traplog {
+	struct {
+		unsigned long tstate;
+		unsigned long tpc;
+		unsigned long tnpc;
+	} trapstack[4];
+	unsigned long tl;
+};
+
+static void dump_tl1_traplog(struct tl1_traplog *p)
+{
+	int i;
+
+	printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n",
+	       p->tl);
+	for (i = 0; i < 4; i++) {
+		printk("TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] TNPC[%016lx]\n",
+		       i + 1,
+		       p->trapstack[i].tstate, p->trapstack[i].tpc, p->trapstack[i].tnpc);
+	}
+}
+
 void bad_trap (struct pt_regs *regs, long lvl)
 {
 	char buffer[32];
@@ -66,8 +93,10 @@
 
 void bad_trap_tl1 (struct pt_regs *regs, long lvl)
 {
-	char buffer[24];
+	char buffer[32];
 	
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+
 	sprintf (buffer, "Bad trap %lx at tl>0", lvl);
 	die_if_kernel (buffer, regs);
 }
@@ -80,8 +109,8 @@
 }
 #endif
 
-void instruction_access_exception (struct pt_regs *regs,
-				   unsigned long sfsr, unsigned long sfar)
+void instruction_access_exception(struct pt_regs *regs,
+				  unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
 
@@ -102,6 +131,13 @@
 	force_sig_info(SIGSEGV, &info, current);
 }
 
+void instruction_access_exception_tl1(struct pt_regs *regs,
+				      unsigned long sfsr, unsigned long sfar)
+{
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+	instruction_access_exception(regs, sfsr, sfar);
+}
+
 void data_access_exception (struct pt_regs *regs,
 			    unsigned long sfsr, unsigned long sfar)
 {
@@ -167,7 +203,7 @@
 					    LSU_CONTROL_IM | LSU_CONTROL_DM),
 				     "i" (ASI_LSU_CONTROL)
 				     : "memory");
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* Flush D-cache */
 		for (va = 0; va < (1 << 16); va += (1 << 5)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
@@ -201,7 +237,7 @@
 		pci_poke_faulted = 1;
 
 		/* Why the fuck did they have to change this? */
-		if (tlb_type == cheetah)
+		if (tlb_type == cheetah || tlb_type == cheetah_plus)
 			regs->tpc += 4;
 
 		regs->tnpc = regs->tpc + 4;
@@ -390,10 +426,14 @@
 	return p;
 }
 
+extern unsigned int tl0_icpe[], tl1_icpe[];
+extern unsigned int tl0_dcpe[], tl1_dcpe[];
 extern unsigned int tl0_fecc[], tl1_fecc[];
 extern unsigned int tl0_cee[], tl1_cee[];
 extern unsigned int tl0_iae[], tl1_iae[];
 extern unsigned int tl0_dae[], tl1_dae[];
+extern unsigned int cheetah_plus_icpe_trap_vector[], cheetah_plus_icpe_trap_vector_tl1[];
+extern unsigned int cheetah_plus_dcpe_trap_vector[], cheetah_plus_dcpe_trap_vector_tl1[];
 extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
 extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
 extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
@@ -487,6 +527,12 @@
 	memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
 	memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
 	memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
+	if (tlb_type == cheetah_plus) {
+		memcpy(tl0_dcpe, cheetah_plus_dcpe_trap_vector, (8 * 4));
+		memcpy(tl1_dcpe, cheetah_plus_dcpe_trap_vector_tl1, (8 * 4));
+		memcpy(tl0_icpe, cheetah_plus_icpe_trap_vector, (8 * 4));
+		memcpy(tl1_icpe, cheetah_plus_icpe_trap_vector_tl1, (8 * 4));
+	}
 	flushi(PAGE_OFFSET);
 }
 
@@ -567,9 +613,22 @@
  *
  * So we must only flush the I-cache when it is disabled.
  */
+static void __cheetah_flush_icache(void)
+{
+	unsigned long i;
+
+	/* Clear the valid bits in all the tags. */
+	for (i = 0; i < (1 << 15); i += (1 << 5)) {
+		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
+	}
+}
+
 static void cheetah_flush_icache(void)
 {
-	unsigned long dcu_save, i;
+	unsigned long dcu_save;
 
 	/* Save current DCU, disable I-cache. */
 	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
@@ -580,13 +639,7 @@
 			     : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
 			     : "g1");
 
-	/* Clear the valid bits in all the tags. */
-	for (i = 0; i < (1 << 16); i += (1 << 5)) {
-		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
-	}
+	__cheetah_flush_icache();
 
 	/* Restore DCU register */
 	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
@@ -607,6 +660,34 @@
 	}
 }
 
+/* In order to make the even parity correct we must do two things.
+ * First, we clear DC_data_parity and set DC_utag to an appropriate value.
+ * Next, we clear out all 32-bytes of data for that line.  Data of
+ * all-zero + tag parity value of zero == correct parity.
+ */
+static void cheetah_plus_zap_dcache_parity(void)
+{
+	unsigned long i;
+
+	for (i = 0; i < (1 << 16); i += (1 << 5)) {
+		unsigned long tag = (i >> 14);
+		unsigned long j;
+
+		__asm__ __volatile__("membar	#Sync\n\t"
+				     "stxa	%0, [%1] %2\n\t"
+				     "membar	#Sync"
+				     : /* no outputs */
+				     : "r" (tag), "r" (i),
+				       "i" (ASI_DCACHE_UTAG));
+		for (j = i; j < i + (1 << 5); j += (1 << 3))
+			__asm__ __volatile__("membar	#Sync\n\t"
+					     "stxa	%%g0, [%0] %1\n\t"
+					     "membar	#Sync"
+					     : /* no outputs */
+					     : "r" (j), "i" (ASI_DCACHE_DATA));
+	}
+}
+
 /* Conversion tables used to frob Cheetah AFSR syndrome values into
  * something palatable to the memory controller driver get_unumber
  * routine.
@@ -1327,6 +1408,46 @@
 		panic("Irrecoverable deferred error trap.\n");
 }
 
+/* Handle a D/I cache parity error trap.  TYPE is encoded as:
+ *
+ * Bit0:	0=dcache,1=icache
+ * Bit1:	0=recoverable,1=unrecoverable
+ *
+ * The hardware has disabled both the I-cache and D-cache in
+ * the %dcr register.  
+ */
+void cheetah_plus_parity_error(int type, struct pt_regs *regs)
+{
+	if (type & 0x1)
+		__cheetah_flush_icache();
+	else
+		cheetah_plus_zap_dcache_parity();
+	cheetah_flush_dcache();
+
+	/* Re-enable I-cache/D-cache */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_DCU_CONTROL_REG),
+			       "i" (DCU_DC | DCU_IC)
+			     : "g1");
+
+	if (type & 0x2) {
+		printk(KERN_EMERG "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+		       smp_processor_id(),
+		       (type & 0x1) ? 'I' : 'D',
+		       regs->tpc);
+		panic("Irrecoverable Cheetah+ parity error.");
+	}
+
+	printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+	       smp_processor_id(),
+	       (type & 0x1) ? 'I' : 'D',
+	       regs->tpc);
+}
+
 void do_fpe_common(struct pt_regs *regs)
 {
 	if (regs->tstate & TSTATE_PRIV) {
@@ -1604,56 +1725,67 @@
 
 void do_cee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Cache Error Exception", regs);
 }
 
 void do_dae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Data Access Exception", regs);
 }
 
 void do_iae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Instruction Access Exception", regs);
 }
 
 void do_div0_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
 void do_fpdis_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Disabled", regs);
 }
 
 void do_fpieee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU IEEE Exception", regs);
 }
 
 void do_fpother_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Other Exception", regs);
 }
 
 void do_ill_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Illegal Instruction Exception", regs);
 }
 
 void do_irq_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: IRQ Exception", regs);
 }
 
 void do_lddfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: LDDF Exception", regs);
 }
 
 void do_stdfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: STDF Exception", regs);
 }
 
@@ -1664,6 +1796,7 @@
 
 void do_paw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Phys Watchpoint Exception", regs);
 }
 
@@ -1674,11 +1807,13 @@
 
 void do_vaw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Virt Watchpoint Exception", regs);
 }
 
 void do_tof_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Tag Overflow Exception", regs);
 }
 
diff -Nru a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
--- a/arch/sparc64/kernel/ttable.S	Tue Aug 27 12:27:56 2002
+++ b/arch/sparc64/kernel/ttable.S	Tue Aug 27 12:27:56 2002
@@ -7,6 +7,8 @@
 #include <linux/config.h>
 
 	.globl	sparc64_ttable_tl0, sparc64_ttable_tl1
+	.globl	tl0_icpe, tl1_icpe
+	.globl	tl0_dcpe, tl1_dcpe
 	.globl	tl0_fecc, tl1_fecc
 	.globl	tl0_cee, tl1_cee
 	.globl	tl0_iae, tl1_iae
@@ -79,7 +81,9 @@
 tl0_daprot:
 #include	"dtlb_prot.S"
 tl0_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl0_resv071:	BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
+tl0_dcpe:	BTRAP(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl0_icpe:	BTRAP(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl0_resv073:	BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
 tl0_resv076:	BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
 tl0_resv07c:	BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
 tl0_s0n:	SPILL_0_NORMAL
@@ -235,8 +239,10 @@
 #include	"dtlb_backend.S"
 tl1_daprot:
 #include	"dtlb_prot.S"
-tl1_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl1_resc071:	BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
+tl1_fecc:	BTRAPTL1(0x70)	/* Fast-ECC on Cheetah */
+tl1_dcpe:	BTRAPTL1(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl1_icpe:	BTRAPTL1(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl1_resv073:	BTRAPTL1(0x73)
 tl1_resv074:	BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
 tl1_resv078:	BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
 tl1_resv07c:	BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
diff -Nru a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
--- a/arch/sparc64/lib/blockops.S	Tue Aug 27 12:27:45 2002
+++ b/arch/sparc64/lib/blockops.S	Tue Aug 27 12:27:45 2002
@@ -66,14 +66,14 @@
 	ldx		[%g6 + TI_FLAGS], %g3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o4
+	mov		PRIMARY_CONTEXT, %o4
 	stxa		%g0, [%o4] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o5
+	mov		PRIMARY_CONTEXT, %o5
 	stxa		%g0, [%o5] ASI_DMMU
 	membar		#Sync
 
@@ -85,14 +85,14 @@
 	add		%o3, (TLBTEMP_ENTSZ), %o3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -109,7 +109,9 @@
 	rdpr		%ver, %g3
 	sllx		%g3, 16, %g3
 	srlx		%g3, 32 + 16, %g3
-	cmp		%g3, 0x14
+	cmp		%g3, 0x14			! CHEETAH_ID
+	be,pn		%icc, cheetah_copy_user_page
+	 cmp		%g3, 0x15			! CHEETAH_PLUS_ID
 	bne,pt		%icc, spitfire_copy_user_page
 	 nop
 
@@ -357,14 +359,14 @@
 	wrpr		%g3, PSTATE_IE, %pstate
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -409,7 +411,8 @@
 	retl
 	 nop
 
-1:	stxa		%g5, [%o2] ASI_DMMU
+1:
+	stxa		%g5, [%o2] ASI_DMMU
 	stxa		%g7, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 	jmpl		%o7 + 0x8, %g0
diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
--- a/arch/sparc64/mm/fault.c	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc64/mm/fault.c	Tue Aug 27 12:28:08 2002
@@ -9,6 +9,7 @@
 
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/signal.h>
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/mm/init.c	Tue Aug 27 12:28:02 2002
@@ -345,6 +345,8 @@
 {
 	if (tlb_type == cheetah)
 		seq_printf(m, "MMU Type\t: Cheetah\n");
+	else if (tlb_type == cheetah_plus)
+		seq_printf(m, "MMU Type\t: Cheetah+\n");
 	else if (tlb_type == spitfire)
 		seq_printf(m, "MMU Type\t: Spitfire\n");
 	else
@@ -514,6 +516,7 @@
 		break;
 
 	case cheetah:
+	case cheetah_plus:
 		phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
 		break;
 	};
@@ -539,7 +542,7 @@
 			"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
 			"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
 			: "memory");
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* Lock this into i/d tlb-0 entry 11 */
 		__asm__ __volatile__(
 			"stxa	%%g0, [%2] %3\n\t"
@@ -684,9 +687,9 @@
 				spitfire_put_dtlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		for (i = 0; i < 512; i++) {
-			unsigned long tag = cheetah_get_dtlb_tag(i);
+			unsigned long tag = cheetah_get_dtlb_tag(i, 2);
 
 			if ((tag & ~PAGE_MASK) == 0 &&
 			    (tag & PAGE_MASK) >= prom_reserved_base) {
@@ -694,7 +697,21 @@
 						     "membar #Sync"
 						     : /* no outputs */
 						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_dtlb_data(i, 0x0UL);
+				cheetah_put_dtlb_data(i, 0x0UL, 2);
+			}
+
+			if (tlb_type != cheetah_plus)
+				continue;
+
+			tag = cheetah_get_dtlb_tag(i, 3);
+
+			if ((tag & ~PAGE_MASK) == 0 &&
+			    (tag & PAGE_MASK) >= prom_reserved_base) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+						     "membar #Sync"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				cheetah_put_dtlb_data(i, 0x0UL, 3);
 			}
 		}
 	} else {
@@ -743,7 +760,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
 			}
@@ -756,7 +773,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
 			}
@@ -891,7 +908,7 @@
 					break;
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
 
 		for (i = 0; i < high; i++) {
@@ -963,7 +980,7 @@
 			if (tlb_type == spitfire)
 				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 						       prom_dtlb[i].tlb_data);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 						      prom_dtlb[i].tlb_data);
 		}
@@ -1064,7 +1081,7 @@
 				spitfire_put_itlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		cheetah_flush_dtlb_all();
 		cheetah_flush_itlb_all();
 	}
@@ -1208,7 +1225,7 @@
 				slot+2,
 				spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of itlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1246,7 +1263,7 @@
 				slot+2,
 				spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of dtlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1259,9 +1276,19 @@
 		for (slot = 0; slot < 512; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
 				slot,
-				cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot),
+				cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
 				slot+1,
-				cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1));
+				cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
+		}
+		if (tlb_type == cheetah_plus) {
+			printk ("Contents of dtlb3:\n");
+			for (slot = 0; slot < 512; slot+=2) {
+				printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+					slot,
+					cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
+					slot+1,
+					cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
+			}
 		}
 	}
 }
@@ -1439,7 +1466,7 @@
 			  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
 			: "memory");
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		__asm__ __volatile__(
 	"	stxa	%1, [%0] %3\n"
 	"	stxa	%2, [%5] %4\n"
@@ -1745,7 +1772,7 @@
 	       initpages << (PAGE_SHIFT-10), 
 	       PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
 
-	if (tlb_type == cheetah)
+	if (tlb_type == cheetah || tlb_type == cheetah_plus)
 		cheetah_ecache_flush_init();
 }
 
diff -Nru a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c
--- a/arch/sparc64/mm/modutil.c	Tue Aug 27 12:28:02 2002
+++ b/arch/sparc64/mm/modutil.c	Tue Aug 27 12:28:02 2002
@@ -4,9 +4,10 @@
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *  Based upon code written by Linus Torvalds and others.
  */
- 
+
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -16,6 +17,7 @@
 void module_unmap (void * addr)
 {
 	struct vm_struct **p, *tmp;
+	int i;
 
 	if (!addr)
 		return;
@@ -23,24 +25,40 @@
 		printk("Trying to unmap module with bad address (%p)\n", addr);
 		return;
 	}
+
 	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
-			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
-			kfree(tmp);
-			return;
+			goto found;
 		}
 	}
 	printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
+	return;
+
+found:
+	unmap_vm_area(tmp);
+	
+	for (i = 0; i < tmp->nr_pages; i++) {
+		if (unlikely(!tmp->pages[i]))
+			BUG();
+		__free_page(tmp->pages[i]);
+	}
+
+	kfree(tmp->pages);
+	kfree(tmp);
 }
 
+
 void * module_map (unsigned long size)
 {
-	void * addr;
 	struct vm_struct **p, *tmp, *area;
+	struct page **pages;
+	void * addr;
+	unsigned int nr_pages, array_size, i;
 
 	size = PAGE_ALIGN(size);
-	if (!size || size > MODULES_LEN) return NULL;
+	if (!size || size > MODULES_LEN)
+		return NULL;
 		
 	addr = (void *) MODULES_VADDR;
 	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
@@ -48,18 +66,52 @@
 			break;
 		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
 	}
-	if ((unsigned long) addr + size >= MODULES_END) return NULL;
+	if ((unsigned long) addr + size >= MODULES_END)
+		return NULL;
 	
 	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area) return NULL;
+	if (!area)
+		return NULL;
 	area->size = size + PAGE_SIZE;
 	area->addr = addr;
 	area->next = *p;
+	area->pages = NULL;
+	area->nr_pages = 0;
+	area->phys_addr = 0;
 	*p = area;
 
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
-		module_unmap(addr);
-		return NULL;
+	nr_pages = size >> PAGE_SHIFT;
+	array_size = (nr_pages * sizeof(struct page *));
+
+	area->nr_pages = nr_pages;
+	area->pages = pages = kmalloc(array_size, GFP_KERNEL);
+	if (!area->pages)
+		goto fail;
+
+	memset(area->pages, 0, array_size);
+
+	for (i = 0; i < area->nr_pages; i++) {
+		area->pages[i] = alloc_page(GFP_KERNEL);
+		if (unlikely(!area->pages[i]))
+			goto fail;
+	}
+	
+	if (map_vm_area(area, PAGE_KERNEL, &pages)) {
+		unmap_vm_area(area);
+		goto fail;
 	}
-	return addr;
+
+	return area->addr;
+
+fail:
+	if (area->pages) {
+		for (i = 0; i < area->nr_pages; i++) {
+			if (area->pages[i])
+				__free_page(area->pages[i]);
+		}
+		kfree(area->pages);
+	}
+	kfree(area);
+
+	return NULL;
 }
diff -Nru a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
--- a/arch/sparc64/mm/ultra.S	Tue Aug 27 12:28:08 2002
+++ b/arch/sparc64/mm/ultra.S	Tue Aug 27 12:28:08 2002
@@ -14,21 +14,12 @@
 #include <asm/head.h>
 #include <asm/thread_info.h>
 
-	/* Basically, all this madness has to do with the
-	 * fact that Cheetah does not support IMMU flushes
-	 * out of the secondary context.  Someone needs to
-	 * throw a south lake birthday party for the folks
+	/* Basically, most of the Spitfire vs. Cheetah madness
+	 * has to do with the fact that Cheetah does not support
+	 * IMMU flushes out of the secondary context.  Someone needs
+	 * to throw a south lake birthday party for the folks
 	 * in Microelectronics who refused to fix this shit.
 	 */
-#define BRANCH_IF_CHEETAH(tmp1, tmp2, label)		\
-	rdpr	%ver, %tmp1;				\
-	sethi	%hi(0x003e0014), %tmp2;			\
-	srlx	%tmp1, 32, %tmp1;			\
-	or	%tmp2, %lo(0x003e0014), %tmp2;		\
-	cmp	%tmp1, %tmp2;				\
-	be,pn	%icc, label;				\
-	 nop;						\
-	nop;
 
 	/* This file is meant to be read efficiently by the CPU, not humans.
 	 * Staraj sie tego nikomu nie pierdolnac...
@@ -37,9 +28,7 @@
 	.align		32
 	.globl		__flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
 __flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
-/*IC1*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page)
-__spitfire_flush_tlb_page:
-/*IC2*/	ldxa		[%o2] ASI_DMMU, %g2
+	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_page_slow
 	 or		%o1, 0x10, %g3
@@ -47,27 +36,17 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_page:
-/*IC3*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-	stxa		%g0, [%o1] ASI_DMMU_DEMAP
-/*IC4*/	stxa		%g0, [%o1] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
-/*IC5*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm)
-__spitfire_flush_tlb_mm:
-/*IC6*/	ldxa		[%o1] ASI_DMMU, %g2
+	ldxa		[%o1] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_mm_slow
 	 mov		0x50, %g3
@@ -75,30 +54,20 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_mm:
-/*IC7*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	mov		0x40, %g3
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-/*IC8*/	stxa		%g0, [%g3] ASI_DMMU_DEMAP
-	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
 		    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
 		    */
-/*IC9*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range)
-__spitfire_flush_tlb_range:
 #define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
-/*IC10*/cmp		%o5, %o4
+	cmp		%o5, %o4
 	bleu,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, PAGE_SHIFT, %g5
 	cmp		%g5, TLB_MAGIC
@@ -107,7 +76,7 @@
 	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 __spitfire_flush_tlb_range_page_by_page:
-/*IC11*/bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
+	bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
 	 sub		%o5, %o4, %o5
 1:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
@@ -116,10 +85,9 @@
 	retl
 	 flush		%g6
 __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
-/*IC12*/rdpr		%pstate, %g1
+	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
-	/* XXX Spitfire dependency... */
 	mov		((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
@@ -131,7 +99,7 @@
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
 	bne,pt		%icc, 2f
-/*IC13*/ andn		%o4, TAG_CONTEXT_BITS, %o4
+	 andn		%o4, TAG_CONTEXT_BITS, %o4
 	cmp		%o4, %o1
 	blu,pt		%xcc, 2f
 	 cmp		%o4, %o3
@@ -139,7 +107,7 @@
 2:	 ldxa		[%g2] ASI_DTLB_TAG_READ, %o4
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
-/*IC14*/andn		%o4, TAG_CONTEXT_BITS, %o4
+	andn		%o4, TAG_CONTEXT_BITS, %o4
 	bne,pt		%icc, 3f
 	 cmp		%o4, %o1
 	blu,pt		%xcc, 3f
@@ -147,7 +115,7 @@
 	blu,pn		%xcc, 5f
 	 nop
 3:	brnz,pt		%g2, 1b
-/*IC15*/ sub		%g2, (1 << 3), %g2
+	 sub		%g2, (1 << 3), %g2
 	retl
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
@@ -163,7 +131,7 @@
 	 nop
 
 5:	stxa		%g0, [%g3] ASI_DMMU
-/*IC16*/stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
 	flush		%g6
 
 	/* Spitfire Errata #32 workaround. */
@@ -175,33 +143,6 @@
 	 nop
 
 	.align		32
-__cheetah_flush_tlb_range:
-	cmp		%o5, %o4
-	bleu,pt		%xcc, __cheetah_flush_tlb_page
-	 nop
-/*IC17*/rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	sub		%o5, %o4, %o5
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-
-/*IC18*/
-1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
-	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
-	membar		#Sync
-	brnz,pt		%o5, 1b
-	 sub		%o5, %o4, %o5
-
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-/*IC19*/ wrpr		%g5, 0x0, %pstate
-
-	.align		32
 	.globl		__flush_tlb_kernel_range
 __flush_tlb_kernel_range:	/* %o0=start, %o1=end */
 	cmp		%o0, %o1
@@ -226,7 +167,7 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	flush		%g6
 	stxa		%g2, [%o1] ASI_DMMU
-/*IC18*/flush		%g6
+	flush		%g6
 	retl
 	 wrpr		%g1, 0, %pstate
 
@@ -236,7 +177,7 @@
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-/*IC20*/flush		%g6
+	flush		%g6
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
@@ -246,7 +187,7 @@
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o2] ASI_DMMU
-/*IC21*/
+
 2:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
 	brnz,pt		%o5, 2b
@@ -255,7 +196,7 @@
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
-/*IC22*/ wrpr		%g1, 0x0, %pstate
+	 wrpr		%g1, 0x0, %pstate
 
 /*
  * The following code flushes one page_size worth.
@@ -318,32 +259,6 @@
 	flush		%g6
 	ba,a,pt		%xcc, 3b
 
-	.align		64
-	.globl		__flush_dcache_page
-__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
-	sethi		%uhi(PAGE_OFFSET), %g1
-	sllx		%g1, 32, %g1
-	sub		%o0, %g1, %o0
-	
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g2
-	srlx		%g1, 32, %g1
-	or		%g2, %lo(0x003e0014), %g2
-	cmp		%g1, %g2
-	bne,pt		%icc, flush_dcpage_spitfire
-	 nop
-
-flush_dcpage_cheetah:
-	sethi		%hi(PAGE_SIZE), %o4
-1:	subcc		%o4, (1 << 5), %o4
-	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
-	bne,pt		%icc, 1b
-	 nop
-	membar		#Sync
-	/* I-cache flush never needed on Cheetah, see callers. */
-	retl
-	 nop
-
 #if (PAGE_SHIFT == 13)
 #define DTAG_MASK 0x3
 #elif (PAGE_SHIFT == 16)
@@ -354,7 +269,12 @@
 #define DTAG_MASK 0x3ff
 #endif
 
-flush_dcpage_spitfire:
+	.align		64
+	.globl		__flush_dcache_page
+__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
+	sethi		%uhi(PAGE_OFFSET), %g1
+	sllx		%g1, 32, %g1
+	sub		%o0, %g1, %o0
 	clr		%o4
 	srlx		%o0, 11, %o0
 	sethi		%hi(1 << 14), %o2
@@ -435,6 +355,121 @@
 	 or		%o5, %o0, %o5
 	ba,a,pt		%xcc, __prefill_itlb
 
+	/* Cheetah specific versions, patched at boot time.  */
+__cheetah_flush_tlb_page: /* 14 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%o1] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_mm: /* 15 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	mov		0x40, %g3
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_range: /* 20 insns */
+	cmp		%o5, %o4
+	blu,pt		%xcc, 9f
+	 rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	sub		%o5, %o4, %o5
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%o5, 1b
+	 sub		%o5, %o4, %o5
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+9:	retl
+	 wrpr		%g5, 0x0, %pstate
+
+flush_dcpage_cheetah: /* 11 insns */
+	sethi		%uhi(PAGE_OFFSET), %g1
+	sllx		%g1, 32, %g1
+	sub		%o0, %g1, %o0
+	sethi		%hi(PAGE_SIZE), %o4
+1:	subcc		%o4, (1 << 5), %o4
+	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
+	membar		#Sync
+	bne,pt		%icc, 1b
+	 nop
+	retl		/* I-cache flush never needed on Cheetah, see callers. */
+	 nop
+
+cheetah_patch_one:
+1:	lduw		[%o1], %g1
+	stw		%g1, [%o0]
+	flush		%o0
+	subcc		%o2, 1, %o2
+	add		%o1, 4, %o1
+	bne,pt		%icc, 1b
+	 add		%o0, 4, %o0
+	retl
+	 nop
+
+	.globl		cheetah_patch_cachetlbops
+cheetah_patch_cachetlbops:
+	save		%sp, -128, %sp
+
+	sethi		%hi(__flush_tlb_page), %o0
+	or		%o0, %lo(__flush_tlb_page), %o0
+	sethi		%hi(__cheetah_flush_tlb_page), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_page), %o1
+	call		cheetah_patch_one
+	 mov		14, %o2
+
+	sethi		%hi(__flush_tlb_mm), %o0
+	or		%o0, %lo(__flush_tlb_mm), %o0
+	sethi		%hi(__cheetah_flush_tlb_mm), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
+	call		cheetah_patch_one
+	 mov		15, %o2
+
+	sethi		%hi(__flush_tlb_range), %o0
+	or		%o0, %lo(__flush_tlb_range), %o0
+	sethi		%hi(__cheetah_flush_tlb_range), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_range), %o1
+	call		cheetah_patch_one
+	 mov		20, %o2
+
+	sethi		%hi(__flush_dcache_page), %o0
+	or		%o0, %lo(__flush_dcache_page), %o0
+	sethi		%hi(flush_dcpage_cheetah), %o1
+	or		%o1, %lo(flush_dcpage_cheetah), %o1
+	call		cheetah_patch_one
+	 mov		11, %o2
+
+	ret
+	 restore
+
 #ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
@@ -538,7 +573,7 @@
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
-	b,pt		%xcc, etrap
+	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		__show_regs
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
@@ -553,9 +588,9 @@
 	sethi		%hi(PAGE_SIZE), %g3
 1:	subcc		%g3, (1 << 5), %g3
 	stxa		%g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
+	membar		#Sync
 	bne,pt		%icc, 1b
 	 nop
-	membar		#Sync
 	retry
 	nop
 
@@ -601,7 +636,7 @@
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
-	b,pt		%xcc, etrap
+	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	flushw
 	call		prom_stopself
@@ -618,10 +653,8 @@
 	.text
 
 	/* These two are not performance critical... */
-	.globl		xcall_flush_tlb_all
-xcall_flush_tlb_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all)
-__spitfire_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_spitfire
+xcall_flush_tlb_all_spitfire:
 	/* Spitfire Errata #32 workaround. */
 	sethi		%hi(errata32_hwbug), %g4
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
@@ -663,16 +696,15 @@
 	flush		%g6
 	retry
 
-__cheetah_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_cheetah
+xcall_flush_tlb_all_cheetah:
 	mov		0x80, %g2
 	stxa		%g0, [%g2] ASI_DMMU_DEMAP
 	stxa		%g0, [%g2] ASI_IMMU_DEMAP
 	retry
 
-	.globl		xcall_flush_cache_all
-xcall_flush_cache_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all)
-__spitfire_xcall_flush_cache_all:
+	.globl		xcall_flush_cache_all_spitfire
+xcall_flush_cache_all_spitfire:
 	sethi		%hi(16383), %g2
 	or		%g2, %lo(16383), %g2
 	clr		%g3
@@ -683,13 +715,6 @@
 	bleu,pt		%xcc, 1b
 	 nop
 	flush		%g6
-	retry
-
-	/* Cheetah's caches are fully coherent in the sense that
-	 * caches are flushed here.  We need to verify this and
-	 * really just not even send out the xcall at the top level.
-	 */
-__cheetah_xcall_flush_cache_all:
 	retry
 
 	/* These just get rescheduled to PIL vectors. */
diff -Nru a/arch/sparc64/prom/printf.c b/arch/sparc64/prom/printf.c
--- a/arch/sparc64/prom/printf.c	Tue Aug 27 12:28:07 2002
+++ b/arch/sparc64/prom/printf.c	Tue Aug 27 12:28:07 2002
@@ -1,12 +1,16 @@
-/* $Id: printf.c,v 1.3 1997/03/18 18:00:00 jj Exp $
+/*
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-/* This routine is internal to the prom library, no one else should know
- * about or use it!  It's simple and smelly anyway....
+ * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * We used to warn all over the code: DO NOT USE prom_printf(),
+ * and yet people do. Anton's banking code was outputing banks
+ * with prom_printf for most of the 2.4 lifetime. Since an effective
+ * stick is not available, we deployed a carrot: an early printk
+ * through PROM by means of -p boot option. This ought to fix it.
+ * USE printk; if you need, deploy -p.
  */
 
 #include <linux/kernel.h>
@@ -16,31 +20,28 @@
 
 static char ppbuf[1024];
 
-extern void prom_puts (char *, int);
+void
+prom_write(const char *buf, unsigned int n)
+{
+	char ch;
+
+	while (n != 0) {
+		--n;
+		if ((ch = *buf++) == '\n')
+			prom_putchar('\r');
+		prom_putchar(ch);
+	}
+}
 
 void
 prom_printf(char *fmt, ...)
 {
 	va_list args;
-	char ch, *bptr, *last;
 	int i;
 
 	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-	last = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n') {
-			if (last < bptr - 1)
-				prom_puts (last, bptr - 1 - last);
-			prom_putchar('\r');
-			last = bptr - 1;
-		}
-	}
-	if (last < bptr - 1)
-		prom_puts (last, bptr - 1 - last);
+	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
-	return;
+
+	prom_write(ppbuf, i);
 }
diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile
--- a/arch/x86_64/Makefile	Tue Aug 27 12:28:02 2002
+++ b/arch/x86_64/Makefile	Tue Aug 27 12:28:02 2002
@@ -25,9 +25,9 @@
 # early bootup linking needs 32bit. You can either use real 32bit tools
 # here or 64bit tools in 32bit mode.
 #
-IA32_CC := $(CROSS_COMPILE)gcc -m32 -O2 -fomit-frame-pointer -nostdinc -I $(HPATH)
-IA32_LD := $(CROSS_COMPILE)ld -m elf_i386
-IA32_AS := $(CROSS_COMPILE)gcc -m32 -Wa,--32 -D__ASSEMBLY__ -traditional -c -nostdinc -I $(HPATH) 
+IA32_CC := $(CC) $(CPPFLAGS) -m32 -O2 -fomit-frame-pointer
+IA32_LD := $(LD) -m elf_i386
+IA32_AS := $(CC) $(AFLAGS) -m32 -Wa,--32 -traditional -c
 IA32_OBJCOPY := $(CROSS_COMPILE)objcopy
 IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E
 export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in
--- a/arch/x86_64/config.in	Tue Aug 27 12:28:02 2002
+++ b/arch/x86_64/config.in	Tue Aug 27 12:28:02 2002
@@ -119,12 +119,6 @@
 
 source drivers/md/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
 
@@ -155,6 +149,8 @@
 #source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+
    mainmenu_option next_comment
    comment 'Network device support'
 
@@ -175,6 +171,8 @@
 
 source drivers/isdn/Config.in
 
+source drivers/telephony/Config.in
+
 # no support for non IDE/SCSI cdroms as they were all ISA only
 
 #
@@ -225,7 +223,6 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Additional run-time checks' CONFIG_CHECKING
    bool '  Debug __init statements' CONFIG_INIT_DEBUG
-   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
 fi
 endmenu
 
diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
--- a/arch/x86_64/kernel/smp.c	Tue Aug 27 12:28:02 2002
+++ b/arch/x86_64/kernel/smp.c	Tue Aug 27 12:28:02 2002
@@ -22,9 +22,6 @@
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
-/* The 'big kernel lock' */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 /*
  * the following functions deal with sending IPIs between CPUs.
  *
diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
--- a/arch/x86_64/kernel/x8664_ksyms.c	Tue Aug 27 12:28:01 2002
+++ b/arch/x86_64/kernel/x8664_ksyms.c	Tue Aug 27 12:28:01 2002
@@ -109,7 +109,6 @@
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL_NOVERS(__write_lock_failed);
diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/Makefile	Tue Aug 27 12:28:08 2002
@@ -7,7 +7,7 @@
 ACPI_CFLAGS	:= -D_LINUX -I$(CURDIR)/include
 
 ifdef CONFIG_ACPI_DEBUG
-  ACPI_CFLAGS	+= -DACPI_DEBUG
+  ACPI_CFLAGS	+= -DACPI_DEBUG_OUTPUT
 endif
 
 EXTRA_CFLAGS	+= $(ACPI_CFLAGS)
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/acpi_ksyms.c	Tue Aug 27 12:28:02 2002
@@ -62,6 +62,7 @@
 EXPORT_SYMBOL(acpi_get_next_object);
 EXPORT_SYMBOL(acpi_evaluate_object);
 EXPORT_SYMBOL(acpi_get_table);
+EXPORT_SYMBOL(acpi_get_firmware_table);
 EXPORT_SYMBOL(acpi_install_notify_handler);
 EXPORT_SYMBOL(acpi_remove_notify_handler);
 EXPORT_SYMBOL(acpi_install_gpe_handler);
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/bus.c	Tue Aug 27 12:28:07 2002
@@ -2052,7 +2052,7 @@
 
 	/* Mimic structured exception handling */
 error4:
-	remove_proc_entry("ACPI", NULL);
+	remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL);
 error3:
 	acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
 error2:
diff -Nru a/drivers/acpi/debugger/dbcmds.c b/drivers/acpi/debugger/dbcmds.c
--- a/drivers/acpi/debugger/dbcmds.c	Tue Aug 27 12:27:51 2002
+++ b/drivers/acpi/debugger/dbcmds.c	Tue Aug 27 12:27:51 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbcmds - debug commands and output routines
- *              $Revision: 85 $
+ *              $Revision: 87 $
  *
  ******************************************************************************/
 
@@ -33,9 +33,9 @@
 #include "acresrc.h"
 #include "acdisasm.h"
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbcmds")
 
 
@@ -1111,4 +1111,4 @@
 
 }
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
diff -Nru a/drivers/acpi/debugger/dbdisply.c b/drivers/acpi/debugger/dbdisply.c
--- a/drivers/acpi/debugger/dbdisply.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/debugger/dbdisply.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbdisply - debug display commands
- *              $Revision: 76 $
+ *              $Revision: 78 $
  *
  ******************************************************************************/
 
@@ -33,10 +33,10 @@
 #include "acdebug.h"
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbdisply")
 
 
@@ -855,5 +855,5 @@
 	acpi_db_display_internal_object (obj_desc, walk_state);
 }
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
 
diff -Nru a/drivers/acpi/debugger/dbexec.c b/drivers/acpi/debugger/dbexec.c
--- a/drivers/acpi/debugger/dbexec.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/debugger/dbexec.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbexec - debugger control method execution
- *              $Revision: 42 $
+ *              $Revision: 44 $
  *
  ******************************************************************************/
 
@@ -27,9 +27,9 @@
 #include "acpi.h"
 #include "acdebug.h"
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbexec")
 
 
@@ -209,7 +209,7 @@
 	acpi_buffer             return_obj;
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 	u32                     previous_allocations;
 	u32                     allocations;
 
@@ -236,7 +236,7 @@
 	acpi_os_sleep (0, 10);
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 
 	/* Memory allocation tracking */
 
@@ -400,6 +400,6 @@
 }
 
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
 
 
diff -Nru a/drivers/acpi/debugger/dbfileio.c b/drivers/acpi/debugger/dbfileio.c
--- a/drivers/acpi/debugger/dbfileio.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/debugger/dbfileio.c	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dbfileio - Debugger file I/O commands.  These can't usually
  *              be used when running the debugger in Ring 0 (Kernel mode)
- *              $Revision: 67 $
+ *              $Revision: 68 $
  *
  ******************************************************************************/
 
@@ -30,9 +30,9 @@
 #include "acnamesp.h"
 #include "actables.h"
 
-#if (defined ENABLE_DEBUGGER || defined ACPI_DISASSEMBLER)
+#if (defined ACPI_DEBUGGER || defined ACPI_DISASSEMBLER)
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbfileio")
 
 
@@ -86,7 +86,7 @@
 }
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 /*******************************************************************************
  *
  * FUNCTION:    Acpi_db_close_debug_file
@@ -395,5 +395,5 @@
 }
 
 
-#endif  /* ENABLE_DEBUGGER */
+#endif  /* ACPI_DEBUGGER */
 
diff -Nru a/drivers/acpi/debugger/dbhistry.c b/drivers/acpi/debugger/dbhistry.c
--- a/drivers/acpi/debugger/dbhistry.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/debugger/dbhistry.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dbhistry - debugger HISTORY command
- *              $Revision: 24 $
+ *              $Revision: 25 $
  *
  *****************************************************************************/
 
@@ -27,9 +27,9 @@
 #include "acpi.h"
 #include "acdebug.h"
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbhistry")
 
 
@@ -185,5 +185,5 @@
 }
 
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
 
diff -Nru a/drivers/acpi/debugger/dbinput.c b/drivers/acpi/debugger/dbinput.c
--- a/drivers/acpi/debugger/dbinput.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/debugger/dbinput.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbinput - user front-end to the AML debugger
- *              $Revision: 86 $
+ *              $Revision: 87 $
  *
  ******************************************************************************/
 
@@ -28,9 +28,9 @@
 #include "acdebug.h"
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbinput")
 
 
@@ -888,5 +888,5 @@
 }
 
 
-#endif  /* ENABLE_DEBUGGER */
+#endif  /* ACPI_DEBUGGER */
 
diff -Nru a/drivers/acpi/debugger/dbstats.c b/drivers/acpi/debugger/dbstats.c
--- a/drivers/acpi/debugger/dbstats.c	Tue Aug 27 12:27:47 2002
+++ b/drivers/acpi/debugger/dbstats.c	Tue Aug 27 12:27:47 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbstats - Generation and display of ACPI table statistics
- *              $Revision: 60 $
+ *              $Revision: 61 $
  *
  ******************************************************************************/
 
@@ -28,9 +28,9 @@
 #include <acdebug.h>
 #include <acnamesp.h>
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbstats")
 
 /*
@@ -148,8 +148,6 @@
 }
 
 
-#ifndef PARSER_ONLY
-
 /*******************************************************************************
  *
  * FUNCTION:    Acpi_db_classify_one_object
@@ -254,8 +252,6 @@
 			   FALSE, acpi_db_classify_one_object, NULL, NULL);
 }
 
-#endif
-
 
 /*******************************************************************************
  *
@@ -303,13 +299,11 @@
 
 	switch (type)
 	{
-#ifndef PARSER_ONLY
 	case CMD_STAT_ALLOCATIONS:
 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
 		acpi_ut_dump_allocation_info ();
 #endif
 		break;
-#endif
 
 	case CMD_STAT_TABLES:
 
@@ -322,8 +316,6 @@
 
 	case CMD_STAT_OBJECTS:
 
-#ifndef PARSER_ONLY
-
 		acpi_db_count_namespace_objects ();
 
 		acpi_os_printf ("\nObjects defined in the current namespace:\n\n");
@@ -340,8 +332,6 @@
 
 		acpi_os_printf ("%16.16s % 10ld% 10ld\n", "TOTALS:",
 			acpi_gbl_num_nodes, acpi_gbl_num_objects);
-
-#endif
 		break;
 
 	case CMD_STAT_MEMORY:
@@ -445,7 +435,7 @@
 
 
 	case CMD_STAT_STACK:
-#if defined(ACPI_DEBUG)
+#if defined(ACPI_DEBUG_OUTPUT)
 
 		size = (u32) (acpi_gbl_entry_stack_pointer - acpi_gbl_lowest_stack_pointer);
 
@@ -466,4 +456,4 @@
 }
 
 
-#endif /* ENABLE_DEBUGGER  */
+#endif /* ACPI_DEBUGGER  */
diff -Nru a/drivers/acpi/debugger/dbutils.c b/drivers/acpi/debugger/dbutils.c
--- a/drivers/acpi/debugger/dbutils.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/debugger/dbutils.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbutils - AML debugger utilities
- *              $Revision: 55 $
+ *              $Revision: 56 $
  *
  ******************************************************************************/
 
@@ -32,9 +32,9 @@
 #include "acdispat.h"
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbutils")
 
 
@@ -375,6 +375,6 @@
 }
 
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
 
 
diff -Nru a/drivers/acpi/debugger/dbxface.c b/drivers/acpi/debugger/dbxface.c
--- a/drivers/acpi/debugger/dbxface.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/debugger/dbxface.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbxface - AML Debugger external interfaces
- *              $Revision: 61 $
+ *              $Revision: 64 $
  *
  ******************************************************************************/
 
@@ -30,9 +30,9 @@
 #include "acdisasm.h"
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
-#define _COMPONENT          ACPI_DEBUGGER
+#define _COMPONENT          ACPI_CA_DEBUGGER
 	 ACPI_MODULE_NAME    ("dbxface")
 
 
@@ -184,7 +184,7 @@
 		/* Restore everything */
 
 		op->common.next = next;
-		acpi_os_printf ("\n");
+		acpi_os_printf ("\n\n");
 		acpi_dbg_level = original_debug_level;
 	}
 
@@ -385,4 +385,4 @@
 }
 
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
diff -Nru a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
--- a/drivers/acpi/dispatcher/dsfield.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/dispatcher/dsfield.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsfield - Dispatcher field routines
- *              $Revision: 65 $
+ *              $Revision: 66 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
--- a/drivers/acpi/dispatcher/dsmethod.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/acpi/dispatcher/dsmethod.c	Tue Aug 27 12:28:05 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
- *              $Revision: 87 $
+ *              $Revision: 88 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
--- a/drivers/acpi/dispatcher/dsmthdat.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/dispatcher/dsmthdat.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dsmthdat - control method arguments and local variables
- *              $Revision: 62 $
+ *              $Revision: 63 $
  *
  ******************************************************************************/
 
@@ -587,23 +587,40 @@
 		 *
 		 * Weird, but true.
 		 */
-		if ((opcode == AML_ARG_OP) &&
-			(ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) == ACPI_DESC_TYPE_NAMED)) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-				"Arg (%p) is an Obj_ref(Node), storing in node %p\n",
-				obj_desc, current_obj_desc));
-
-			/* Detach an existing object from the Node */
-
-			acpi_ns_detach_object ((acpi_namespace_node *) current_obj_desc);
+		if (opcode == AML_ARG_OP) {
+			/*
+			 * Make sure that the object is the correct type.  This may be overkill, but
+			 * it is here because references were NS nodes in the past.  Now they are
+			 * operand objects of type Reference.
+			 */
+			if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+				ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: %X\n",
+					current_obj_desc->common.type));
+				return_ACPI_STATUS (AE_AML_INTERNAL);
+			}
 
 			/*
-			 * Store this object into the Node
-			 * (perform the indirect store)
+			 * If we have a valid reference object that came from Ref_of(), do the
+			 * indirect store
 			 */
-			status = acpi_ns_attach_object ((acpi_namespace_node *) current_obj_desc,
-					  obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc));
-			return_ACPI_STATUS (status);
+			if ((current_obj_desc->common.type == INTERNAL_TYPE_REFERENCE) &&
+				(current_obj_desc->reference.opcode == AML_REF_OF_OP)) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+					"Arg (%p) is an Obj_ref(Node), storing in node %p\n",
+					obj_desc, current_obj_desc));
+
+				/* Detach an existing object from the referenced Node */
+
+				acpi_ns_detach_object (current_obj_desc->reference.object);
+
+				/*
+				 * Store this object into the Node
+				 * (perform the indirect store)
+				 */
+				status = acpi_ns_attach_object (current_obj_desc->reference.object,
+						  obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc));
+				return_ACPI_STATUS (status);
+			}
 		}
 
 		/*
diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
--- a/drivers/acpi/dispatcher/dsobject.c	Tue Aug 27 12:27:51 2002
+++ b/drivers/acpi/dispatcher/dsobject.c	Tue Aug 27 12:27:51 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsobject - Dispatcher object management routines
- *              $Revision: 105 $
+ *              $Revision: 106 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
--- a/drivers/acpi/dispatcher/dsopcode.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/dispatcher/dsopcode.c	Tue Aug 27 12:28:02 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dsopcode - Dispatcher Op Region support and handling of
  *                         "control" opcodes
- *              $Revision: 80 $
+ *              $Revision: 81 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
--- a/drivers/acpi/dispatcher/dswexec.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/dispatcher/dswexec.c	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dswexec - Dispatcher method execution callbacks;
  *                        dispatch to interpreter.
- *              $Revision: 94 $
+ *              $Revision: 95 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
--- a/drivers/acpi/dispatcher/dswload.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/dispatcher/dswload.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswload - Dispatcher namespace load callbacks
- *              $Revision: 69 $
+ *              $Revision: 70 $
  *
  *****************************************************************************/
 
@@ -296,7 +296,7 @@
 	NATIVE_CHAR             *buffer_ptr;
 
 
-	ACPI_FUNCTION_NAME ("Ds_load2_begin_op");
+	ACPI_FUNCTION_TRACE ("Ds_load2_begin_op");
 
 
 	op = walk_state->op;
@@ -307,7 +307,7 @@
 
 		if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
 			(!(walk_state->op_info->flags & AML_NAMED))) {
-			return (AE_OK);
+			return_ACPI_STATUS (AE_OK);
 		}
 
 		/*
@@ -320,7 +320,7 @@
 			if (!buffer_ptr) {
 				/* No name, just exit */
 
-				return (AE_OK);
+				return_ACPI_STATUS (AE_OK);
 			}
 		}
 		else {
@@ -368,11 +368,11 @@
 			if (acpi_ns_opens_scope (object_type)) {
 				status = acpi_ds_scope_stack_push (node, object_type, walk_state);
 				if (ACPI_FAILURE (status)) {
-					return (status);
+					return_ACPI_STATUS (status);
 				}
 
 			}
-			return (AE_OK);
+			return_ACPI_STATUS (AE_OK);
 		}
 
 		/*
@@ -390,7 +390,7 @@
 
 			op = acpi_ps_alloc_op (walk_state->opcode);
 			if (!op) {
-				return (AE_NO_MEMORY);
+				return_ACPI_STATUS (AE_NO_MEMORY);
 			}
 
 			/* Initialize the new op */
@@ -410,7 +410,7 @@
 		op->common.node = node;
 	}
 
-	return (status);
+	return_ACPI_STATUS (status);
 }
 
 
@@ -444,7 +444,7 @@
 #endif
 
 
-	ACPI_FUNCTION_NAME ("Ds_load2_end_op");
+	ACPI_FUNCTION_TRACE ("Ds_load2_end_op");
 
 	op = walk_state->op;
 	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
@@ -453,7 +453,7 @@
 	/* Only interested in opcodes that have namespace objects */
 
 	if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
-		return (AE_OK);
+		return_ACPI_STATUS (AE_OK);
 	}
 
 	if (op->common.aml_opcode == AML_SCOPE_OP) {
@@ -479,13 +479,13 @@
 
 	/* Pop the scope stack */
 
-	if (acpi_ns_opens_scope (object_type)) {
+	if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
 			acpi_ut_get_type_name (object_type), op));
 
 		status = acpi_ds_scope_stack_pop (walk_state);
 		if (ACPI_FAILURE (status)) {
-			return (status);
+			return_ACPI_STATUS (status);
 		}
 	}
 
@@ -730,7 +730,7 @@
 
 	walk_state->operands[0] = NULL;
 	walk_state->num_operands = 0;
-	return (status);
+	return_ACPI_STATUS (status);
 }
 
 
diff -Nru a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
--- a/drivers/acpi/dispatcher/dswstate.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/dispatcher/dswstate.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswstate - Dispatcher parse tree walk management routines
- *              $Revision: 67 $
+ *              $Revision: 68 $
  *
  *****************************************************************************/
 
@@ -835,6 +835,8 @@
 	walk_state->method_desc     = mth_desc;
 	walk_state->thread          = thread;
 
+	walk_state->parser_state.start_op = origin;
+
 	/* Init the method args/local */
 
 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
@@ -883,6 +885,7 @@
 {
 	acpi_status             status;
 	acpi_parse_state        *parser_state = &walk_state->parser_state;
+	acpi_parse_object       *extra_op;
 
 
 	ACPI_FUNCTION_TRACE ("Ds_init_aml_walk");
@@ -925,9 +928,23 @@
 		}
 	}
 	else {
-		/* Setup the current scope */
+		/*
+		 * Setup the current scope.
+		 * Find a Named Op that has a namespace node associated with it.
+		 * search upwards from this Op.  Current scope is the first
+		 * Op with a namespace node.
+		 */
+		extra_op = parser_state->start_op;
+		while (extra_op && !extra_op->common.node) {
+			extra_op = extra_op->common.parent;
+		}
+		if (!extra_op) {
+			parser_state->start_node = NULL;
+		}
+		else {
+			parser_state->start_node = extra_op->common.node;
+		}
 
-		parser_state->start_node = parser_state->start_op->common.node;
 		if (parser_state->start_node) {
 			/* Push start scope on scope stack and make it current  */
 
diff -Nru a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
--- a/drivers/acpi/events/evevent.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/events/evevent.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evevent - Fixed and General Purpose Even handling and dispatch
- *              $Revision: 88 $
+ *              $Revision: 90 $
  *
  *****************************************************************************/
 
@@ -104,7 +104,7 @@
 	acpi_status             status;
 
 
-	ACPI_FUNCTION_TRACE ("Ev_initialize");
+	ACPI_FUNCTION_TRACE ("Ev_handler_initialize");
 
 
 	/* Install the SCI handler */
diff -Nru a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
--- a/drivers/acpi/events/evmisc.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/events/evmisc.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evmisc - Miscellaneous event manager support functions
- *              $Revision: 53 $
+ *              $Revision: 56 $
  *
  *****************************************************************************/
 
@@ -442,11 +442,13 @@
 	ACPI_FUNCTION_TRACE ("Ev_acquire_global_lock");
 
 
+#ifndef ACPI_APPLICATION
 	/* Make sure that we actually have a global lock */
 
 	if (!acpi_gbl_global_lock_present) {
 		return_ACPI_STATUS (AE_NO_GLOBAL_LOCK);
 	}
+#endif
 
 	/* One more thread wants the global lock */
 
@@ -552,9 +554,56 @@
 void
 acpi_ev_terminate (void)
 {
+	NATIVE_UINT_MAX32       i;
+	acpi_status             status;
+
 
 	ACPI_FUNCTION_TRACE ("Ev_terminate");
 
+	/*
+	 * Disable all event-related functionality.
+	 * In all cases, on error, print a message but obviously we don't abort.
+	 */
+
+	/*
+	 * Disable all fixed events
+	 */
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+		status = acpi_disable_event(i, ACPI_EVENT_FIXED, 0);
+		if (ACPI_FAILURE (status)) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to disable fixed event %d.\n", i));
+		}
+	}
+
+	/*
+	 * Disable all GPEs
+	 */
+	for (i = 0; i < acpi_gbl_gpe_number_max; i++) {
+		if (acpi_ev_get_gpe_number_index(i) != ACPI_GPE_INVALID) {
+			status = acpi_hw_disable_gpe(i);
+			if (ACPI_FAILURE (status)) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to disable GPE %d.\n", i));
+			}
+		}
+	}
+
+	/*
+	 * Remove SCI handler
+	 */
+	status = acpi_ev_remove_sci_handler();
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to remove SCI handler.\n"));
+	}
+
+	/*
+	 * Return to original mode if necessary
+	 */
+	if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
+		status = acpi_disable ();
+		if (ACPI_FAILURE (status)) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Acpi_disable failed.\n"));
+		}
+	}
 
 	/*
 	 * Free global tables, etc.
diff -Nru a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
--- a/drivers/acpi/events/evregion.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/events/evregion.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch
- *              $Revision: 134 $
+ *              $Revision: 135 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
--- a/drivers/acpi/events/evrgnini.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/events/evrgnini.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evrgnini- ACPI Address_space (Op_region) init
- *              $Revision: 62 $
+ *              $Revision: 63 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
--- a/drivers/acpi/events/evxface.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/events/evxface.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evxface - External interfaces for ACPI events
- *              $Revision: 129 $
+ *              $Revision: 130 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
--- a/drivers/acpi/events/evxfevnt.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/events/evxfevnt.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
- *              $Revision: 55 $
+ *              $Revision: 57 $
  *
  *****************************************************************************/
 
@@ -52,16 +52,14 @@
 	ACPI_FUNCTION_TRACE ("Acpi_enable");
 
 
-	/* Make sure we have ACPI tables */
+	/* Make sure we have the FADT*/
 
-	if (!acpi_gbl_DSDT) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No ACPI tables present!\n"));
+	if (!acpi_gbl_FADT) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
 		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
 	}
 
-	acpi_gbl_original_mode = acpi_hw_get_mode ();
-
-	if (acpi_gbl_original_mode == ACPI_SYS_MODE_ACPI) {
+	if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Already in ACPI mode.\n"));
 	}
 	else {
@@ -88,8 +86,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Returns the system to original ACPI/legacy mode, and
- *              uninstalls the SCI interrupt handler.
+ * DESCRIPTION: Transfers the system into LEGACY mode.
  *
  ******************************************************************************/
 
@@ -101,20 +98,26 @@
 
 	ACPI_FUNCTION_TRACE ("Acpi_disable");
 
+	if (!acpi_gbl_FADT) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
+		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+	}
 
-	if (acpi_hw_get_mode () != acpi_gbl_original_mode) {
-		/* Restore original mode  */
+	if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Already in LEGACY mode.\n"));
+	}
+	else {
+		/* Transition to LEGACY mode */
+		status = acpi_hw_set_mode (ACPI_SYS_MODE_LEGACY);
 
-		status = acpi_hw_set_mode (acpi_gbl_original_mode);
 		if (ACPI_FAILURE (status)) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to transition to original mode"));
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not transition to LEGACY mode."));
 			return_ACPI_STATUS (status);
 		}
-	}
 
-	/* Unload the SCI interrupt handler  */
+		ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Transition to LEGACY mode successful\n"));
+	}
 
-	status = acpi_ev_remove_sci_handler ();
 	return_ACPI_STATUS (status);
 }
 
diff -Nru a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
--- a/drivers/acpi/executer/exdump.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/executer/exdump.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exdump - Interpreter debug output routines
- *              $Revision: 157 $
+ *              $Revision: 159 $
  *
  *****************************************************************************/
 
@@ -38,7 +38,7 @@
  * The following routines are used for debug output only
  */
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*****************************************************************************
  *
diff -Nru a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
--- a/drivers/acpi/executer/exfldio.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/executer/exfldio.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exfldio - Aml Field I/O
- *              $Revision: 87 $
+ *              $Revision: 88 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
--- a/drivers/acpi/executer/exmisc.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/executer/exmisc.c	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
- *              $Revision: 107 $
+ *              $Revision: 108 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
--- a/drivers/acpi/executer/exoparg1.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/executer/exoparg1.c	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg1 - AML execution - opcodes with 1 argument
- *              $Revision: 141 $
+ *              $Revision: 142 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
--- a/drivers/acpi/executer/exoparg2.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/acpi/executer/exoparg2.c	Tue Aug 27 12:28:06 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
- *              $Revision: 109 $
+ *              $Revision: 110 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
--- a/drivers/acpi/executer/exprep.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/executer/exprep.c	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
- *              $Revision: 118 $
+ *              $Revision: 119 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
--- a/drivers/acpi/executer/exregion.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/executer/exregion.c	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exregion - ACPI default Op_region (address space) handlers
- *              $Revision: 79 $
+ *              $Revision: 80 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
--- a/drivers/acpi/executer/exresop.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/executer/exresop.c	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresop - AML Interpreter operand/object resolution
- *              $Revision: 54 $
+ *              $Revision: 55 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
--- a/drivers/acpi/executer/exstore.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/acpi/executer/exstore.c	Tue Aug 27 12:28:05 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstore - AML Interpreter object store support
- *              $Revision: 168 $
+ *              $Revision: 169 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
--- a/drivers/acpi/executer/exutils.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/executer/exutils.c	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exutils - interpreter/scanner utilities
- *              $Revision: 102 $
+ *              $Revision: 103 $
  *
  *****************************************************************************/
 
@@ -261,7 +261,8 @@
 		if (ACPI_FAILURE (status)) {
 			/* Report the error, but there isn't much else we can do */
 
-			ACPI_REPORT_ERROR (("Could not release ACPI Global Lock\n"));
+			ACPI_REPORT_ERROR (("Could not release ACPI Global Lock, %s\n",
+				acpi_format_exception (status)));
 		}
 	}
 
diff -Nru a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
--- a/drivers/acpi/hardware/hwacpi.c	Tue Aug 27 12:27:47 2002
+++ b/drivers/acpi/hardware/hwacpi.c	Tue Aug 27 12:27:47 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
- *              $Revision: 58 $
+ *              $Revision: 60 $
  *
  *****************************************************************************/
 
@@ -95,6 +95,27 @@
 
 
 	ACPI_FUNCTION_TRACE ("Hw_set_mode");
+
+	/*
+	 * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
+	 * system does not support mode transition.
+	 */
+	if (!acpi_gbl_FADT->smi_cmd) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No SMI_CMD in FADT, mode transition failed.\n"));
+		return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
+	}
+
+	/*
+	 * ACPI 2.0 clarified the meaning of ACPI_ENABLE and ACPI_DISABLE
+	 * in FADT: If it is zero, enabling or disabling is not supported.
+	 * As old systems may have used zero for mode transition,
+	 * we make sure both the numbers are zero to determine these
+	 * transitions are not supported.
+	 */
+	if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No mode transition supported in this system.\n"));
+		return_ACPI_STATUS (AE_OK);
+	}
 
 	switch (mode) {
 	case ACPI_SYS_MODE_ACPI:
diff -Nru a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
--- a/drivers/acpi/hardware/hwgpe.c	Tue Aug 27 12:27:54 2002
+++ b/drivers/acpi/hardware/hwgpe.c	Tue Aug 27 12:27:54 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
- *              $Revision: 41 $
+ *              $Revision: 42 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
--- a/drivers/acpi/hardware/hwregs.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/hardware/hwregs.c	Tue Aug 27 12:28:08 2002
@@ -3,7 +3,7 @@
  *
  * Module Name: hwregs - Read/write access functions for the various ACPI
  *                       control and status registers.
- *              $Revision: 133 $
+ *              $Revision: 134 $
  *
  ******************************************************************************/
 
diff -Nru a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
--- a/drivers/acpi/hardware/hwsleep.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/hardware/hwsleep.c	Tue Aug 27 12:27:59 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
- *              $Revision: 45 $
+ *              $Revision: 46 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h
--- a/drivers/acpi/include/acconfig.h	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/include/acconfig.h	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acconfig.h - Global configuration constants
- *       $Revision: 107 $
+ *       $Revision: 109 $
  *
  *****************************************************************************/
 
@@ -34,7 +34,7 @@
  *****************************************************************************/
 
 /*
- * ACPI_DEBUG           - This switch enables all the debug facilities of the
+ * ACPI_DEBUG_OUTPUT    - This switch enables all the debug facilities of the
  *                        ACPI subsystem.  This includes the DEBUG_PRINT output
  *                        statements.  When disabled, all DEBUG_PRINT
  *                        statements are compiled out.
@@ -54,7 +54,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20020725
+#define ACPI_CA_VERSION                 0x20020815
 
 /* Version of ACPI supported */
 
diff -Nru a/drivers/acpi/include/acdisasm.h b/drivers/acpi/include/acdisasm.h
--- a/drivers/acpi/include/acdisasm.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/include/acdisasm.h	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acdisasm.h - AML disassembler
- *       $Revision: 2 $
+ *       $Revision: 3 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/acglobal.h b/drivers/acpi/include/acglobal.h
--- a/drivers/acpi/include/acglobal.h	Tue Aug 27 12:27:39 2002
+++ b/drivers/acpi/include/acglobal.h	Tue Aug 27 12:27:39 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acglobal.h - Declarations for global variables
- *       $Revision: 128 $
+ *       $Revision: 130 $
  *
  *****************************************************************************/
 
@@ -152,8 +152,12 @@
  ****************************************************************************/
 
 #define NUM_NS_TYPES                    INTERNAL_TYPE_INVALID+1
-#define NUM_PREDEFINED_NAMES            9
 
+#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+#define NUM_PREDEFINED_NAMES            10
+#else
+#define NUM_PREDEFINED_NAMES            9
+#endif
 
 ACPI_EXTERN acpi_namespace_node         acpi_gbl_root_node_struct;
 ACPI_EXTERN acpi_namespace_node        *acpi_gbl_root_node;
@@ -161,7 +165,7 @@
 extern const u8                         acpi_gbl_ns_properties[NUM_NS_TYPES];
 extern const acpi_predefined_names      acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES];
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 ACPI_EXTERN u32                         acpi_gbl_current_node_count;
 ACPI_EXTERN u32                         acpi_gbl_current_node_size;
 ACPI_EXTERN u32                         acpi_gbl_max_concurrent_node_count;
@@ -245,7 +249,7 @@
 #endif
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
 extern      u8                          acpi_gbl_method_executing;
 extern      u8                          acpi_gbl_db_terminate_threads;
@@ -287,7 +291,7 @@
 ACPI_EXTERN u32                         acpi_gbl_size_of_node_entries;
 ACPI_EXTERN u32                         acpi_gbl_size_of_acpi_objects;
 
-#endif /* ENABLE_DEBUGGER */
+#endif /* ACPI_DEBUGGER */
 
 
 #endif /* __ACGLOBAL_H__ */
diff -Nru a/drivers/acpi/include/aclocal.h b/drivers/acpi/include/aclocal.h
--- a/drivers/acpi/include/aclocal.h	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/include/aclocal.h	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: aclocal.h - Internal data types used across the ACPI subsystem
- *       $Revision: 173 $
+ *       $Revision: 175 $
  *
  *****************************************************************************/
 
@@ -73,7 +73,7 @@
 #define NUM_MTX                         MAX_MTX+1
 
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 #ifdef DEFINE_ACPI_GLOBALS
 
 /* Names for the mutexes used in the subsystem */
@@ -567,7 +567,7 @@
  */
 typedef struct acpi_opcode_info
 {
-#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG)
+#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT)
 	NATIVE_CHAR             *name;          /* Opcode name (disassembler/debug only) */
 #endif
 	u32                     parse_args;     /* Grammar/Parse time arguments */
diff -Nru a/drivers/acpi/include/acmacros.h b/drivers/acpi/include/acmacros.h
--- a/drivers/acpi/include/acmacros.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/include/acmacros.h	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acmacros.h - C macros for the entire subsystem.
- *       $Revision: 126 $
+ *       $Revision: 128 $
  *
  *****************************************************************************/
 
@@ -287,7 +287,7 @@
 /*
  * Macros for the master AML opcode table
  */
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG)
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
 #define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags)    {name,Pargs,Iargs,flags,obj_type,class,type}
 #else
 #define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags)    {Pargs,Iargs,flags,obj_type,class,type}
@@ -353,11 +353,11 @@
 
 /*
  * Error reporting.  These versions add callers module and line#.  Since
- * _THIS_MODULE gets compiled out when ACPI_DEBUG isn't defined, only
+ * _THIS_MODULE gets compiled out when ACPI_DEBUG_OUTPUT isn't defined, only
  * use it in debug mode.
  */
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 
 #define ACPI_REPORT_INFO(fp)                {acpi_ut_report_info(_THIS_MODULE,__LINE__,_COMPONENT); \
 												acpi_os_printf ACPI_PARAM_LIST(fp);}
@@ -390,7 +390,7 @@
  * Debug macros that are conditionally compiled
  */
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 
 #define ACPI_MODULE_NAME(name)               static char *_THIS_MODULE = name;
 
@@ -525,9 +525,9 @@
 /*
  * Some code only gets executed when the debugger is built in.
  * Note that this is entirely independent of whether the
- * DEBUG_PRINT stuff (set by ACPI_DEBUG) is on, or not.
+ * DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not.
  */
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 #define ACPI_DEBUGGER_EXEC(a)           a
 #else
 #define ACPI_DEBUGGER_EXEC(a)
@@ -536,7 +536,7 @@
 
 /*
  * For 16-bit code, we want to shrink some things even though
- * we are using ACPI_DEBUG to get the debug output
+ * we are using ACPI_DEBUG_OUTPUT to get the debug output
  */
 #if ACPI_MACHINE_WIDTH == 16
 #undef ACPI_DEBUG_ONLY_MEMBERS
@@ -545,7 +545,7 @@
 #endif
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 /*
  * 1) Set name to blanks
  * 2) Copy the object name
diff -Nru a/drivers/acpi/include/acobject.h b/drivers/acpi/include/acobject.h
--- a/drivers/acpi/include/acobject.h	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/include/acobject.h	Tue Aug 27 12:27:59 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Name: acobject.h - Definition of acpi_operand_object  (Internal object only)
- *       $Revision: 112 $
+ *       $Revision: 113 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/acoutput.h b/drivers/acpi/include/acoutput.h
--- a/drivers/acpi/include/acoutput.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/include/acoutput.h	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acoutput.h -- debug output
- *       $Revision: 87 $
+ *       $Revision: 90 $
  *
  *****************************************************************************/
 
@@ -43,18 +43,20 @@
 #define ACPI_DISPATCHER             0x00000040
 #define ACPI_EXECUTER               0x00000080
 #define ACPI_RESOURCES              0x00000100
-#define ACPI_DEBUGGER               0x00000200
+#define ACPI_CA_DEBUGGER            0x00000200
 #define ACPI_OS_SERVICES            0x00000400
-
-#define ACPI_ALL_COMPONENTS         0x00000FFF
-
-#define ACPI_COMPONENT_DEFAULT      (ACPI_ALL_COMPONENTS)
+#define ACPI_CA_DISASSEMBLER        0x00000800
 
 /* Component IDs for ACPI tools and utilities */
 
 #define ACPI_COMPILER               0x00001000
 #define ACPI_TOOLS                  0x00002000
 
+#define ACPI_ALL_COMPONENTS         0x00003FFF
+
+#define ACPI_COMPONENT_DEFAULT      (ACPI_ALL_COMPONENTS)
+
+
 /* Component IDs reserved for ACPI drivers */
 
 #define ACPI_ALL_DRIVERS            0xFFFF0000
@@ -94,7 +96,8 @@
 
 #define ACPI_LV_ALLOCATIONS         0x00100000
 #define ACPI_LV_FUNCTIONS           0x00200000
-#define ACPI_LV_VERBOSITY2          0x00300000 | ACPI_LV_VERBOSITY1
+#define ACPI_LV_OPTIMIZATIONS       0x00400000
+#define ACPI_LV_VERBOSITY2          0x00700000 | ACPI_LV_VERBOSITY1
 #define ACPI_LV_ALL                 ACPI_LV_VERBOSITY2
 
 /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */
@@ -144,6 +147,7 @@
 #define ACPI_DB_BFIELD              ACPI_DEBUG_LEVEL (ACPI_LV_BFIELD)
 #define ACPI_DB_TABLES              ACPI_DEBUG_LEVEL (ACPI_LV_TABLES)
 #define ACPI_DB_FUNCTIONS           ACPI_DEBUG_LEVEL (ACPI_LV_FUNCTIONS)
+#define ACPI_DB_OPTIMIZATIONS       ACPI_DEBUG_LEVEL (ACPI_LV_OPTIMIZATIONS)
 #define ACPI_DB_VALUES              ACPI_DEBUG_LEVEL (ACPI_LV_VALUES)
 #define ACPI_DB_OBJECTS             ACPI_DEBUG_LEVEL (ACPI_LV_OBJECTS)
 #define ACPI_DB_ALLOCATIONS         ACPI_DEBUG_LEVEL (ACPI_LV_ALLOCATIONS)
diff -Nru a/drivers/acpi/include/acparser.h b/drivers/acpi/include/acparser.h
--- a/drivers/acpi/include/acparser.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/include/acparser.h	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: acparser.h - AML Parser subcomponent prototypes and defines
- *       $Revision: 60 $
+ *       $Revision: 61 $
  *
  *****************************************************************************/
 
@@ -86,7 +86,7 @@
 	u32                     arg_type,
 	acpi_parse_object       *arg);
 
-void
+acpi_status
 acpi_ps_get_next_namepath (
 	acpi_parse_state        *parser_state,
 	acpi_parse_object       *arg,
@@ -97,11 +97,12 @@
 acpi_ps_get_next_field (
 	acpi_parse_state        *parser_state);
 
-acpi_parse_object *
+acpi_status
 acpi_ps_get_next_arg (
 	acpi_parse_state        *parser_state,
 	u32                     arg_type,
-	u32                     *arg_count);
+	u32                     *arg_count,
+	acpi_parse_object       **return_arg);
 
 
 /* psfind */
diff -Nru a/drivers/acpi/include/acresrc.h b/drivers/acpi/include/acresrc.h
--- a/drivers/acpi/include/acresrc.h	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/include/acresrc.h	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acresrc.h - Resource Manager function prototypes
- *       $Revision: 33 $
+ *       $Revision: 34 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/actbl2.h b/drivers/acpi/include/actbl2.h
--- a/drivers/acpi/include/actbl2.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/include/actbl2.h	Tue Aug 27 12:28:07 2002
@@ -139,8 +139,8 @@
 	u16                     plvl3_lat;          /* Worst case HW latency to enter/exit C3 state */
 	u16                     flush_size;         /* Number of flush strides that need to be read */
 	u16                     flush_stride;       /* Processor's memory cache line width, in bytes */
-	u8                      duty_offset;        /* Processor_’s duty cycle index in processor's P_CNT reg*/
-	u8                      duty_width;         /* Processor_’s duty cycle value bit width in P_CNT register.*/
+	u8                      duty_offset;        /* Processor’s duty cycle index in processor's P_CNT reg*/
+	u8                      duty_width;         /* Processor’s duty cycle value bit width in P_CNT register.*/
 	u8                      day_alrm;           /* Index to day-of-month alarm in RTC CMOS RAM */
 	u8                      mon_alrm;           /* Index to month-of-year alarm in RTC CMOS RAM */
 	u8                      century;            /* Index to century in RTC CMOS RAM */
diff -Nru a/drivers/acpi/include/acutils.h b/drivers/acpi/include/acutils.h
--- a/drivers/acpi/include/acutils.h	Tue Aug 27 12:27:47 2002
+++ b/drivers/acpi/include/acutils.h	Tue Aug 27 12:27:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures
- *       $Revision: 142 $
+ *       $Revision: 143 $
  *
  *****************************************************************************/
 
@@ -94,7 +94,7 @@
  * Ut_global - Global data structures and procedures
  */
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 NATIVE_CHAR *
 acpi_ut_get_mutex_name (
@@ -686,7 +686,7 @@
 acpi_ut_set_integer_width (
 	u8                      revision);
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 void
 acpi_ut_display_init_pathname (
 	acpi_handle             obj_handle,
diff -Nru a/drivers/acpi/include/amlcode.h b/drivers/acpi/include/amlcode.h
--- a/drivers/acpi/include/amlcode.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/include/amlcode.h	Tue Aug 27 12:28:07 2002
@@ -3,7 +3,7 @@
  * Name: amlcode.h - Definitions for AML, as included in "definition blocks"
  *                   Declarations and definitions contained herein are derived
  *                   directly from the ACPI specification.
- *       $Revision: 69 $
+ *       $Revision: 70 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/amlresrc.h b/drivers/acpi/include/amlresrc.h
--- a/drivers/acpi/include/amlresrc.h	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/include/amlresrc.h	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: amlresrc.h - AML resource descriptors
- *              $Revision: 20 $
+ *              $Revision: 22 $
  *
  *****************************************************************************/
 
@@ -326,173 +326,6 @@
 	u8                          U8item;
 
 } ASL_RESOURCE_DESC;
-
-
-#define NEXT_RESOURCE_DESC(a,b)     (ASL_RESOURCE_DESC *) (((char *) (a)) + sizeof(b))
-
-#define DEFAULT_RESOURCE_DESC_SIZE  (sizeof (ASL_RESOURCE_DESC) + sizeof (ASL_END_TAG_DESC))
-
-
-/*
- * Resource utilities
- */
-
-ASL_RESOURCE_NODE *
-rs_allocate_resource_node (
-	u32                     size);
-
-	void
-rs_create_bit_field (
-	acpi_parse_object       *op,
-	char                    *name,
-	u32                     byte_offset,
-	u32                     bit_offset);
-
-void
-rs_create_byte_field (
-	acpi_parse_object       *op,
-	char                    *name,
-	u32                     byte_offset);
-
-void
-rs_set_flag_bits (
-	u8                      *flags,
-	acpi_parse_object       *op,
-	u8                      position,
-	u8                      default);
-
-acpi_parse_object *
-rs_complete_node_and_get_next (
-	acpi_parse_object       *op);
-
-ASL_RESOURCE_NODE *
-rs_do_one_resource_descriptor (
-	acpi_parse_object       *descriptor_type_op,
-	u32                     current_byte_offset);
-
-u32
-rs_link_descriptor_chain (
-	ASL_RESOURCE_NODE       **previous_rnode,
-	ASL_RESOURCE_NODE       *rnode);
-
-
-/*
- * Small descriptors
- */
-
-ASL_RESOURCE_NODE *
-rs_do_dma_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_end_dependent_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_fixed_io_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_interrupt_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_io_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_irq_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_irq_no_flags_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_memory24_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_memory32_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_memory32_fixed_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_start_dependent_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_start_dependent_no_pri_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_vendor_small_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-
-/*
- * Large descriptors
- */
-
-u32
-rs_get_string_data_length (
-	acpi_parse_object       *initializer_op);
-
-ASL_RESOURCE_NODE *
-rs_do_dword_io_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_dword_memory_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_qword_io_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_qword_memory_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_word_io_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_word_bus_number_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_vendor_large_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
-
-ASL_RESOURCE_NODE *
-rs_do_general_register_descriptor (
-	acpi_parse_object       *op,
-	u32                     current_byte_offset);
 
 
 #endif
diff -Nru a/drivers/acpi/include/platform/acenv.h b/drivers/acpi/include/platform/acenv.h
--- a/drivers/acpi/include/platform/acenv.h	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/include/platform/acenv.h	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acenv.h - Generation environment specific items
- *       $Revision: 99 $
+ *       $Revision: 101 $
  *
  *****************************************************************************/
 
@@ -33,7 +33,7 @@
 
 #ifdef _ACPI_DUMP_APP
 #ifndef MSDOS
-#define ACPI_DEBUG
+#define ACPI_DEBUG_OUTPUT
 #endif
 #define ACPI_APPLICATION
 #define ACPI_DISASSEMBLER
@@ -44,15 +44,15 @@
 #ifdef _ACPI_EXEC_APP
 #undef DEBUGGER_THREADING
 #define DEBUGGER_THREADING      DEBUGGER_SINGLE_THREADED
-#define ACPI_DEBUG
+#define ACPI_DEBUG_OUTPUT
 #define ACPI_APPLICATION
-#define ENABLE_DEBUGGER
+#define ACPI_DEBUGGER
 #define ACPI_DISASSEMBLER
 #define ACPI_USE_SYSTEM_CLIBRARY
 #endif
 
 #ifdef _ACPI_ASL_COMPILER
-#define ACPI_DEBUG
+#define ACPI_DEBUG_OUTPUT
 #define ACPI_APPLICATION
 #define ACPI_DISASSEMBLER
 #define ACPI_CONSTANT_EVAL_ONLY
@@ -149,7 +149,7 @@
  * 1) This is the debug version
  * 2) This is NOT a 16-bit version of the code (not enough real-mode memory)
  */
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 #if ACPI_MACHINE_WIDTH != 16
 #define ACPI_DBG_TRACK_ALLOCATIONS
 #endif
diff -Nru a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
--- a/drivers/acpi/namespace/nsaccess.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nsaccess.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nsaccess - Top-level functions for accessing ACPI namespace
- *              $Revision: 156 $
+ *              $Revision: 161 $
  *
  ******************************************************************************/
 
@@ -117,6 +117,19 @@
 			 * used for initial values are implemented here.
 			 */
 			switch (init_val->type) {
+			case ACPI_TYPE_METHOD:
+				obj_desc->method.param_count =
+						(u8) ACPI_STRTOUL (init_val->val, NULL, 10);
+				obj_desc->common.flags |= AOPOBJ_DATA_VALID;
+
+#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+
+				/* Compiler cheats by putting parameter count in the Owner_iD */
+
+				new_node->owner_id = obj_desc->method.param_count;
+#endif
+				break;
+
 			case ACPI_TYPE_INTEGER:
 
 				obj_desc->integer.value =
@@ -228,6 +241,7 @@
 	acpi_namespace_node     **return_node)
 {
 	acpi_status             status;
+	NATIVE_CHAR             *path = pathname;
 	acpi_namespace_node     *prefix_node;
 	acpi_namespace_node     *current_node = NULL;
 	acpi_namespace_node     *this_node = NULL;
@@ -235,7 +249,9 @@
 	acpi_name               simple_name;
 	acpi_object_type        type_to_check_for;
 	acpi_object_type        this_search_type;
-	u32                     local_flags = flags & ~ACPI_NS_ERROR_IF_FOUND;
+	u32                     search_parent_flag = ACPI_NS_SEARCH_PARENT;
+	u32                     local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND |
+			   ACPI_NS_SEARCH_PARENT);
 
 
 	ACPI_FUNCTION_TRACE ("Ns_lookup");
@@ -266,6 +282,21 @@
 	}
 	else {
 		prefix_node = scope_info->scope.node;
+		if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "[%p] Not a namespace node\n",
+				prefix_node));
+			return_ACPI_STATUS (AE_AML_INTERNAL);
+		}
+
+		/*
+		 * This node might not be a actual "scope" node (such as a
+		 * Device/Method, etc.)  It could be a Package or other object node.
+		 * Backup up the tree to find the containing scope node.
+		 */
+		while (!acpi_ns_opens_scope (prefix_node->type) &&
+				prefix_node->type != ACPI_TYPE_ANY) {
+			prefix_node = acpi_ns_get_parent_node (prefix_node);
+		}
 	}
 
 	/*
@@ -297,7 +328,7 @@
 
 		num_segments = 0;
 		this_node    = acpi_gbl_root_node;
-		pathname     = "";
+		path     = "";
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
 			"Null Pathname (Zero segments), Flags=%X\n", flags));
@@ -316,23 +347,24 @@
 		 * Parent Prefixes (in which case the name's scope is relative
 		 * to the current scope).
 		 */
-		if (*pathname == (u8) AML_ROOT_PREFIX) {
+		if (*path == (u8) AML_ROOT_PREFIX) {
 			/* Pathname is fully qualified, start from the root */
 
 			this_node = acpi_gbl_root_node;
+			search_parent_flag = ACPI_NS_NO_UPSEARCH;
 
 			/* Point to name segment part */
 
-			pathname++;
+			path++;
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching from root [%p]\n",
-				this_node));
+			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+				"Path is absolute from root [%p]\n", this_node));
 		}
 		else {
 			/* Pathname is relative to current scope, start there */
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
-				"Searching relative to pfx scope [%p]\n",
+				"Searching relative to prefix scope [%p]\n",
 				prefix_node));
 
 			/*
@@ -340,12 +372,15 @@
 			 * the parent node for each prefix instance.
 			 */
 			this_node = prefix_node;
-			while (*pathname == (u8) AML_PARENT_PREFIX) {
+			while (*path == (u8) AML_PARENT_PREFIX) {
+				/* Name is fully qualified, no search rules apply */
+
+				search_parent_flag = ACPI_NS_NO_UPSEARCH;
 				/*
 				 * Point past this prefix to the name segment
 				 * part or the next Parent Prefix
 				 */
-				pathname++;
+				path++;
 
 				/* Backup to the parent node */
 
@@ -358,6 +393,11 @@
 					return_ACPI_STATUS (AE_NOT_FOUND);
 				}
 			}
+
+			if (search_parent_flag == ACPI_NS_NO_UPSEARCH) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+					"Path is absolute with one or more carats\n"));
+			}
 		}
 
 		/*
@@ -373,7 +413,7 @@
 		 * Examine the name prefix opcode, if any, to determine the number of
 		 * segments.
 		 */
-		switch (*pathname) {
+		switch (*path) {
 		case 0:
 			/*
 			 * Null name after a root or parent prefixes. We already
@@ -387,10 +427,14 @@
 
 		case AML_DUAL_NAME_PREFIX:
 
+			/* More than one Name_seg, search rules do not apply */
+
+			search_parent_flag = ACPI_NS_NO_UPSEARCH;
+
 			/* Two segments, point to first name segment */
 
 			num_segments = 2;
-			pathname++;
+			path++;
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
 				"Dual Pathname (2 segments, Flags=%X)\n", flags));
@@ -398,11 +442,15 @@
 
 		case AML_MULTI_NAME_PREFIX_OP:
 
+			/* More than one Name_seg, search rules do not apply */
+
+			search_parent_flag = ACPI_NS_NO_UPSEARCH;
+
 			/* Extract segment count, point to first name segment */
 
-			pathname++;
-			num_segments = (u32) (u8) *pathname;
-			pathname++;
+			path++;
+			num_segments = (u32) (u8) *path;
+			path++;
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
 				"Multi Pathname (%d Segments, Flags=%X) \n",
@@ -421,33 +469,49 @@
 			break;
 		}
 
-		ACPI_DEBUG_EXEC (acpi_ns_print_pathname (num_segments, pathname));
+		ACPI_DEBUG_EXEC (acpi_ns_print_pathname (num_segments, path));
 	}
 
+
 	/*
 	 * Search namespace for each segment of the name.  Loop through and
-	 * verify/add each name segment.
+	 * verify (or add to the namespace) each name segment.
+	 *
+	 * The object type is significant only at the last name
+	 * segment.  (We don't care about the types along the path, only
+	 * the type of the final target object.)
 	 */
+	this_search_type = ACPI_TYPE_ANY;
 	current_node = this_node;
 	while (num_segments && current_node) {
-		/*
-		 * Search for the current name segment under the current
-		 * named object.  The Type is significant only at the last name
-		 * segment.  (We don't care about the types along the path, only
-		 * the type of the final target object.)
-		 */
-		this_search_type = ACPI_TYPE_ANY;
 		num_segments--;
 		if (!num_segments) {
+			/*
+			 * This is the last segment, enable typechecking
+			 */
 			this_search_type = type;
-			local_flags = flags;
+
+			/*
+			 * Only allow automatic parent search (search rules) if the caller
+			 * requested it AND we have a single, non-fully-qualified Name_seg
+			 */
+			if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) &&
+				(flags & ACPI_NS_SEARCH_PARENT)) {
+				local_flags |= ACPI_NS_SEARCH_PARENT;
+			}
+
+			/* Set error flag according to caller */
+
+			if (flags & ACPI_NS_ERROR_IF_FOUND) {
+				local_flags |= ACPI_NS_ERROR_IF_FOUND;
+			}
 		}
 
 		/* Extract one ACPI name from the front of the pathname */
 
-		ACPI_MOVE_UNALIGNED32_TO_32 (&simple_name, pathname);
+		ACPI_MOVE_UNALIGNED32_TO_32 (&simple_name, path);
 
-		/* Try to find the ACPI name */
+		/* Try to find the single (4 character) ACPI name */
 
 		status = acpi_ns_search_and_enter (simple_name, walk_state, current_node,
 				  interpreter_mode, this_search_type, local_flags, &this_node);
@@ -457,7 +521,8 @@
 
 				ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
 					"Name [%4.4s] not found in scope [%4.4s] %p\n",
-					(char *) &simple_name, (char *) &current_node->name, current_node));
+					(char *) &simple_name, (char *) &current_node->name,
+					current_node));
 			}
 
 			return_ACPI_STATUS (status);
@@ -504,7 +569,7 @@
 
 		/* Point to next name segment and make this node current */
 
-		pathname += ACPI_NAME_SIZE;
+		path += ACPI_NAME_SIZE;
 		current_node = this_node;
 	}
 
diff -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
--- a/drivers/acpi/namespace/nsdump.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nsdump.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 137 $
+ *              $Revision: 139 $
  *
  *****************************************************************************/
 
@@ -32,7 +32,7 @@
 #define _COMPONENT          ACPI_NAMESPACE
 	 ACPI_MODULE_NAME    ("nsdump")
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 
 /*******************************************************************************
diff -Nru a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
--- a/drivers/acpi/namespace/nsdumpdv.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/acpi/namespace/nsdumpdv.c	Tue Aug 27 12:27:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 1 $
+ *              $Revision: 3 $
  *
  *****************************************************************************/
 
@@ -33,7 +33,7 @@
 	 ACPI_MODULE_NAME    ("nsdumpdv")
 
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*******************************************************************************
  *
diff -Nru a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
--- a/drivers/acpi/namespace/nseval.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/namespace/nseval.c	Tue Aug 27 12:28:02 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nseval - Object evaluation interfaces -- includes control
  *                       method lookup and execution.
- *              $Revision: 117 $
+ *              $Revision: 118 $
  *
  ******************************************************************************/
 
diff -Nru a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
--- a/drivers/acpi/namespace/nsinit.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/namespace/nsinit.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsinit - namespace initialization
- *              $Revision: 47 $
+ *              $Revision: 49 $
  *
  *****************************************************************************/
 
@@ -369,7 +369,7 @@
 		if (status != AE_NOT_FOUND) {
 			/* Ignore error and move on to next device */
 
-	#ifdef ACPI_DEBUG
+	#ifdef ACPI_DEBUG_OUTPUT
 			NATIVE_CHAR *scope_name = acpi_ns_get_external_pathname (obj_handle);
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n",
diff -Nru a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
--- a/drivers/acpi/namespace/nsload.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nsload.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsload - namespace loading/expanding/contracting procedures
- *              $Revision: 57 $
+ *              $Revision: 58 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
--- a/drivers/acpi/namespace/nsnames.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nsnames.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nsnames - Name manipulation and search
- *              $Revision: 78 $
+ *              $Revision: 79 $
  *
  ******************************************************************************/
 
@@ -103,7 +103,7 @@
 }
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 /*******************************************************************************
  *
  * FUNCTION:    Acpi_ns_get_external_pathname
diff -Nru a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
--- a/drivers/acpi/namespace/nssearch.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nssearch.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nssearch - Namespace search
- *              $Revision: 86 $
+ *              $Revision: 89 $
  *
  ******************************************************************************/
 
@@ -71,7 +71,7 @@
 	ACPI_FUNCTION_TRACE ("Ns_search_node");
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 	if (ACPI_LV_NAMES & acpi_dbg_level) {
 		NATIVE_CHAR         *scope_name;
 
@@ -290,10 +290,10 @@
 	/* Parameter validation */
 
 	if (!node || !target_name || !return_node) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null param-  Table %p Name %X Return %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null param: Node %p Name %X Return_node %p\n",
 			node, target_name, return_node));
 
-		ACPI_REPORT_ERROR (("Ns_search_and_enter: bad (null) parameter\n"));
+		ACPI_REPORT_ERROR (("Ns_search_and_enter: Null parameter\n"));
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
diff -Nru a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
--- a/drivers/acpi/namespace/nsutils.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/acpi/namespace/nsutils.c	Tue Aug 27 12:28:06 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
  *                        parents and siblings and Scope manipulation
- *              $Revision: 110 $
+ *              $Revision: 112 $
  *
  *****************************************************************************/
 
@@ -434,9 +434,12 @@
 
 	case '^':
 		for (i = 0; i < internal_name_length; i++) {
-			if (internal_name[i] != '^') {
+			if (internal_name[i] == '^') {
 				prefix_length = i + 1;
 			}
+			else {
+				break;
+			}
 		}
 
 		if (i == internal_name_length) {
@@ -834,7 +837,7 @@
 }
 
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*******************************************************************************
  *
@@ -868,7 +871,7 @@
 	return (FALSE);
 }
 
-#endif /* ACPI_DEBUG */
+#endif /* ACPI_DEBUG_OUTPUT */
 
 
 /*******************************************************************************
diff -Nru a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
--- a/drivers/acpi/namespace/nsxfeval.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/acpi/namespace/nsxfeval.c	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsxfeval - Public interfaces to the ACPI subsystem
  *                         ACPI Object evaluation interfaces
- *              $Revision: 1 $
+ *              $Revision: 2 $
  *
  ******************************************************************************/
 
diff -Nru a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
--- a/drivers/acpi/parser/psargs.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/parser/psargs.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psargs - Parse AML opcode arguments
- *              $Revision: 62 $
+ *              $Revision: 64 $
  *
  *****************************************************************************/
 
@@ -162,7 +162,7 @@
 	/* Handle multiple prefix characters */
 
 	while (acpi_ps_is_prefix_char (ACPI_GET8 (end))) {
-		/* include prefix '\\' or '^' */
+		/* Include prefix '\\' or '^' */
 
 		end++;
 	}
@@ -218,20 +218,17 @@
  *              Method_call         - Whether the namepath can be the start
  *                                    of a method call
  *
- * RETURN:      None
+ * RETURN:      Status
  *
- * DESCRIPTION: Get next name (if method call, push appropriate # args).  Names
- *              are looked up in either the parsed or internal namespace to
- *              determine if the name represents a control method.  If a method
+ * DESCRIPTION: Get next name (if method call, return # of required args).
+ *              Names are looked up in the internal namespace to determine
+ *              if the name represents a control method.  If a method
  *              is found, the number of arguments to the method is returned.
  *              This information is critical for parsing to continue correctly.
  *
  ******************************************************************************/
 
-
-#ifdef PARSER_ONLY
-
-void
+acpi_status
 acpi_ps_get_next_namepath (
 	acpi_parse_state        *parser_state,
 	acpi_parse_object       *arg,
@@ -240,188 +237,91 @@
 {
 	NATIVE_CHAR             *path;
 	acpi_parse_object       *name_op;
-	acpi_parse_object       *op;
-	acpi_parse_object       *count;
+	acpi_status             status = AE_OK;
+	acpi_operand_object     *method_desc;
+	acpi_namespace_node     *node;
+	acpi_generic_state      scope_info;
 
 
 	ACPI_FUNCTION_TRACE ("Ps_get_next_namepath");
 
 
 	path = acpi_ps_get_next_namestring (parser_state);
-	if (!path || !method_call) {
-		/* Null name case, create a null namepath object */
 
-		acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
-		arg->common.value.name = path;
-		return_VOID;
-	}
+	/* Null path case is allowed */
 
-
-	if (acpi_gbl_parsed_namespace_root) {
+	if (path) {
 		/*
-		 * Lookup the name in the parsed namespace
+		 * Lookup the name in the internal namespace
 		 */
-		op = NULL;
-		if (method_call) {
-			op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
-					   path, AML_METHOD_OP, 0);
+		scope_info.scope.node = NULL;
+		node = parser_state->start_node;
+		if (node) {
+			scope_info.scope.node = node;
 		}
 
-		if (op) {
-			if (op->common.aml_opcode == AML_METHOD_OP) {
-				/*
-				 * The name refers to a control method, so this namepath is a
-				 * method invocation.  We need to 1) Get the number of arguments
-				 * associated with this method, and 2) Change the NAMEPATH
-				 * object into a METHODCALL object.
-				 */
-				count = acpi_ps_get_arg (op, 0);
-				if (count && count->common.aml_opcode == AML_BYTE_OP) {
-					name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
-					if (name_op) {
-						/* Change arg into a METHOD CALL and attach the name */
-
-						acpi_ps_init_op (arg, AML_INT_METHODCALL_OP);
-
-						name_op->common.value.name = path;
-
-						/* Point METHODCALL/NAME to the METHOD Node */
-
-						name_op->common.node = (acpi_namespace_node *) op;
-						acpi_ps_append_arg (arg, name_op);
-
-						*arg_count = (u32) count->common.value.integer &
-								 METHOD_FLAGS_ARG_COUNT;
-					}
+		/*
+		 * Lookup object.  We don't want to add anything new to the namespace
+		 * here, however.  So we use MODE_EXECUTE.  Allow searching of the
+		 * parent tree, but don't open a new scope -- we just want to lookup the
+		 * object  (MUST BE mode EXECUTE to perform upsearch)
+		 */
+		status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+				 ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL,
+				 &node);
+		if (ACPI_SUCCESS (status) && method_call) {
+			if (node->type == ACPI_TYPE_METHOD) {
+				method_desc = acpi_ns_get_attached_object (node);
+				ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n",
+					node, method_desc, path));
+
+				name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
+				if (!name_op) {
+					return_ACPI_STATUS (AE_NO_MEMORY);
 				}
 
-				return_VOID;
-			}
-
-			/*
-			 * Else this is normal named object reference.
-			 * Just init the NAMEPATH object with the pathname.
-			 * (See code below)
-			 */
-		}
-	}
-
-	/*
-	 * Either we didn't find the object in the namespace, or the object is
-	 * something other than a control method.  Just initialize the Op with the
-	 * pathname
-	 */
-	acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
-	arg->common.value.name = path;
-
-
-	return_VOID;
-}
-
-
-#else
-
-
-void
-acpi_ps_get_next_namepath (
-	acpi_parse_state        *parser_state,
-	acpi_parse_object       *arg,
-	u32                     *arg_count,
-	u8                      method_call)
-{
-	NATIVE_CHAR             *path;
-	acpi_parse_object       *name_op;
-	acpi_status             status;
-	acpi_operand_object     *method_desc;
-	acpi_namespace_node     *node;
-	acpi_generic_state      scope_info;
-
-
-	ACPI_FUNCTION_TRACE ("Ps_get_next_namepath");
-
-
-	path = acpi_ps_get_next_namestring (parser_state);
-	if (!path || !method_call) {
-		/* Null name case, create a null namepath object */
-
-		acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
-		arg->common.value.name = path;
-		return_VOID;
-	}
-
-	/*
-	 * Lookup the name in the internal namespace
-	 */
-	scope_info.scope.node = NULL;
-	node = parser_state->start_node;
-	if (node) {
-		scope_info.scope.node = node;
-	}
+				/* Change arg into a METHOD CALL and attach name to it */
 
-	/*
-	 * Lookup object.  We don't want to add anything new to the namespace
-	 * here, however.  So we use MODE_EXECUTE.  Allow searching of the
-	 * parent tree, but don't open a new scope -- we just want to lookup the
-	 * object  (MUST BE mode EXECUTE to perform upsearch)
-	 */
-	status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
-			 ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL,
-			 &node);
-	if (ACPI_SUCCESS (status)) {
-		if (node->type == ACPI_TYPE_METHOD) {
-			method_desc = acpi_ns_get_attached_object (node);
-			ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n",
-				node, method_desc, path));
-
-			name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
-			if (!name_op) {
-				return_VOID;
-			}
+				acpi_ps_init_op (arg, AML_INT_METHODCALL_OP);
 
-			/* Change arg into a METHOD CALL and attach name to it */
+				name_op->common.value.name = path;
 
-			acpi_ps_init_op (arg, AML_INT_METHODCALL_OP);
+				/* Point METHODCALL/NAME to the METHOD Node */
 
-			name_op->common.value.name = path;
+				name_op->common.node = node;
+				acpi_ps_append_arg (arg, name_op);
 
-			/* Point METHODCALL/NAME to the METHOD Node */
+				if (!method_desc) {
+					ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p has no attached object\n",
+						node));
+					return_ACPI_STATUS (AE_AML_INTERNAL);
+				}
 
-			name_op->common.node = node;
-			acpi_ps_append_arg (arg, name_op);
+				ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Args %X\n",
+					node, method_desc->method.param_count));
 
-			if (!method_desc) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p has no attached object\n",
-					node));
-				return_VOID;
+				*arg_count = method_desc->method.param_count;
+				return_ACPI_STATUS (AE_OK);
 			}
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Args %X\n",
-				node, method_desc->method.param_count));
-
-			*arg_count = method_desc->method.param_count;
-			return_VOID;
+			/*
+			 * Else this is normal named object reference.
+			 * Just init the NAMEPATH object with the pathname.
+			 * (See code below)
+			 */
 		}
-
-		/*
-		 * Else this is normal named object reference.
-		 * Just init the NAMEPATH object with the pathname.
-		 * (See code below)
-		 */
 	}
 
 	/*
-	 * Either we didn't find the object in the namespace, or the object is
-	 * something other than a control method.  Just initialize the Op with the
-	 * pathname.
+	 * Regardless of success/failure above,
+	 * Just initialize the Op with the pathname.
 	 */
 	acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
 	arg->common.value.name = path;
 
-
-	return_VOID;
+	return_ACPI_STATUS (status);
 }
 
-#endif
 
 /*******************************************************************************
  *
@@ -630,23 +530,25 @@
  *              Arg_count           - If the argument points to a control method
  *                                    the method's argument is returned here.
  *
- * RETURN:      An op object containing the next argument.
+ * RETURN:      Status, and an op object containing the next argument.
  *
  * DESCRIPTION: Get next argument (including complex list arguments that require
  *              pushing the parser stack)
  *
  ******************************************************************************/
 
-acpi_parse_object *
+acpi_status
 acpi_ps_get_next_arg (
 	acpi_parse_state        *parser_state,
 	u32                     arg_type,
-	u32                     *arg_count)
+	u32                     *arg_count,
+	acpi_parse_object       **return_arg)
 {
 	acpi_parse_object       *arg = NULL;
 	acpi_parse_object       *prev = NULL;
 	acpi_parse_object       *field;
 	u32                     subop;
+	acpi_status             status = AE_OK;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("Ps_get_next_arg", parser_state);
@@ -663,15 +565,16 @@
 		/* constants, strings, and namestrings are all the same size */
 
 		arg = acpi_ps_alloc_op (AML_BYTE_OP);
-		if (arg) {
-			acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
+		if (!arg) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
 		}
+		acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
 		break;
 
 
 	case ARGP_PKGLENGTH:
 
-		/* package length, nothing returned */
+		/* Package length, nothing returned */
 
 		parser_state->pkg_end = acpi_ps_get_next_package_end (parser_state);
 		break;
@@ -680,18 +583,17 @@
 	case ARGP_FIELDLIST:
 
 		if (parser_state->aml < parser_state->pkg_end) {
-			/* non-empty list */
+			/* Non-empty list */
 
 			while (parser_state->aml < parser_state->pkg_end) {
 				field = acpi_ps_get_next_field (parser_state);
 				if (!field) {
-					break;
+					return_ACPI_STATUS (AE_NO_MEMORY);
 				}
 
 				if (prev) {
 					prev->common.next = field;
 				}
-
 				else {
 					arg = field;
 				}
@@ -699,7 +601,7 @@
 				prev = field;
 			}
 
-			/* skip to End of byte data */
+			/* Skip to End of byte data */
 
 			parser_state->aml = parser_state->pkg_end;
 		}
@@ -709,17 +611,19 @@
 	case ARGP_BYTELIST:
 
 		if (parser_state->aml < parser_state->pkg_end) {
-			/* non-empty list */
+			/* Non-empty list */
 
 			arg = acpi_ps_alloc_op (AML_INT_BYTELIST_OP);
-			if (arg) {
-				/* fill in bytelist data */
-
-				arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml);
-				arg->named.data = parser_state->aml;
+			if (!arg) {
+				return_ACPI_STATUS (AE_NO_MEMORY);
 			}
 
-			/* skip to End of byte data */
+			/* Fill in bytelist data */
+
+			arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml);
+			arg->named.data = parser_state->aml;
+
+			/* Skip to End of byte data */
 
 			parser_state->aml = parser_state->pkg_end;
 		}
@@ -728,24 +632,25 @@
 
 	case ARGP_TARGET:
 	case ARGP_SUPERNAME:
-	case ARGP_SIMPLENAME: {
-			subop = acpi_ps_peek_opcode (parser_state);
-			if (subop == 0              ||
-				acpi_ps_is_leading_char (subop) ||
-				acpi_ps_is_prefix_char (subop)) {
-				/* Null_name or Name_string */
-
-				arg = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
-				if (arg) {
-					acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0);
-				}
+	case ARGP_SIMPLENAME:
+
+		subop = acpi_ps_peek_opcode (parser_state);
+		if (subop == 0                  ||
+			acpi_ps_is_leading_char (subop) ||
+			acpi_ps_is_prefix_char (subop)) {
+			/* Null_name or Name_string */
+
+			arg = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
+			if (!arg) {
+				return_ACPI_STATUS (AE_NO_MEMORY);
 			}
 
-			else {
-				/* single complex argument, nothing returned */
+			status = acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0);
+		}
+		else {
+			/* single complex argument, nothing returned */
 
-				*arg_count = 1;
-			}
+			*arg_count = 1;
 		}
 		break;
 
@@ -770,10 +675,14 @@
 		}
 		break;
 
+
 	default:
+
 		ACPI_REPORT_ERROR (("Invalid Arg_type: %X\n", arg_type));
+		status = AE_AML_OPERAND_TYPE;
 		break;
 	}
 
-	return_PTR (arg);
+	*return_arg = arg;
+	return_ACPI_STATUS (status);
 }
diff -Nru a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
--- a/drivers/acpi/parser/psopcode.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/parser/psopcode.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psopcode - Parser/Interpreter opcode information table
- *              $Revision: 71 $
+ *              $Revision: 72 $
  *
  *****************************************************************************/
 
@@ -558,17 +558,17 @@
 /* 60 */ ACPI_OP ("LNotEqual",          ARGP_LNOTEQUAL_OP,         ARGI_LNOTEQUAL_OP,          ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           AML_HAS_ARGS | AML_CONSTANT),
 /* 61 */ ACPI_OP ("LLessEqual",         ARGP_LLESSEQUAL_OP,        ARGI_LLESSEQUAL_OP,         ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           AML_HAS_ARGS | AML_CONSTANT),
 /* 62 */ ACPI_OP ("LGreaterEqual",      ARGP_LGREATEREQUAL_OP,     ARGI_LGREATEREQUAL_OP,      ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           AML_HAS_ARGS | AML_CONSTANT),
-/* 63 */ ACPI_OP ("[NamePath]",         ARGP_NAMEPATH_OP,          ARGI_NAMEPATH_OP,           INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         AML_NSOBJECT | AML_NSNODE ),
-/* 64 */ ACPI_OP ("[MethodCall]",       ARGP_METHODCALL_OP,        ARGI_METHODCALL_OP,         ACPI_TYPE_METHOD,        AML_CLASS_METHOD_CALL,     AML_TYPE_METHOD_CALL,     AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
-/* 65 */ ACPI_OP ("[ByteList]",         ARGP_BYTELIST_OP,          ARGI_BYTELIST_OP,           ACPI_TYPE_ANY,           AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         0),
-/* 66 */ ACPI_OP ("[ReservedField]",    ARGP_RESERVEDFIELD_OP,     ARGI_RESERVEDFIELD_OP,      ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
-/* 67 */ ACPI_OP ("[NamedField]",       ARGP_NAMEDFIELD_OP,        ARGI_NAMEDFIELD_OP,         ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ),
-/* 68 */ ACPI_OP ("[AccessField]",      ARGP_ACCESSFIELD_OP,       ARGI_ACCESSFIELD_OP,        ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
-/* 69 */ ACPI_OP ("[StaticString",      ARGP_STATICSTRING_OP,      ARGI_STATICSTRING_OP,       ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
-/* 6A */ ACPI_OP ("[Return Value]",     ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_RETURN_VALUE,    AML_TYPE_RETURN,          AML_HAS_ARGS | AML_HAS_RETVAL),
-/* 6B */ ACPI_OP ("UNKNOWN_OP!",        ARG_NONE,                  ARG_NONE,                   INTERNAL_TYPE_INVALID,   AML_CLASS_UNKNOWN,         AML_TYPE_BOGUS,           AML_HAS_ARGS),
-/* 6C */ ACPI_OP ("ASCII_ONLY!",        ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_ASCII,           AML_TYPE_BOGUS,           AML_HAS_ARGS),
-/* 6D */ ACPI_OP ("PREFIX_ONLY!",       ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_PREFIX,          AML_TYPE_BOGUS,           AML_HAS_ARGS),
+/* 63 */ ACPI_OP ("-NamePath-",         ARGP_NAMEPATH_OP,          ARGI_NAMEPATH_OP,           INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         AML_NSOBJECT | AML_NSNODE ),
+/* 64 */ ACPI_OP ("-MethodCall-",       ARGP_METHODCALL_OP,        ARGI_METHODCALL_OP,         ACPI_TYPE_METHOD,        AML_CLASS_METHOD_CALL,     AML_TYPE_METHOD_CALL,     AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
+/* 65 */ ACPI_OP ("-ByteList-",         ARGP_BYTELIST_OP,          ARGI_BYTELIST_OP,           ACPI_TYPE_ANY,           AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         0),
+/* 66 */ ACPI_OP ("-ReservedField-",    ARGP_RESERVEDFIELD_OP,     ARGI_RESERVEDFIELD_OP,      ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
+/* 67 */ ACPI_OP ("-NamedField-",       ARGP_NAMEDFIELD_OP,        ARGI_NAMEDFIELD_OP,         ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ),
+/* 68 */ ACPI_OP ("-AccessField-",      ARGP_ACCESSFIELD_OP,       ARGI_ACCESSFIELD_OP,        ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
+/* 69 */ ACPI_OP ("-StaticString",      ARGP_STATICSTRING_OP,      ARGI_STATICSTRING_OP,       ACPI_TYPE_ANY,           AML_CLASS_INTERNAL,        AML_TYPE_BOGUS,           0),
+/* 6A */ ACPI_OP ("-Return Value-",     ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_RETURN_VALUE,    AML_TYPE_RETURN,          AML_HAS_ARGS | AML_HAS_RETVAL),
+/* 6B */ ACPI_OP ("-UNKNOWN_OP-",       ARG_NONE,                  ARG_NONE,                   INTERNAL_TYPE_INVALID,   AML_CLASS_UNKNOWN,         AML_TYPE_BOGUS,           AML_HAS_ARGS),
+/* 6C */ ACPI_OP ("-ASCII_ONLY-",       ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_ASCII,           AML_TYPE_BOGUS,           AML_HAS_ARGS),
+/* 6D */ ACPI_OP ("-PREFIX_ONLY-",      ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,           AML_CLASS_PREFIX,          AML_TYPE_BOGUS,           AML_HAS_ARGS),
 
 
 /* ACPI 2.0 opcodes */
diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
--- a/drivers/acpi/parser/psparse.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/parser/psparse.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psparse - Parser top level AML parse routines
- *              $Revision: 129 $
+ *              $Revision: 133 $
  *
  *****************************************************************************/
 
@@ -113,58 +113,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_ps_find_object
- *
- * PARAMETERS:  Opcode          - Current opcode
- *              Parser_state    - Current state
- *              Walk_state      - Current state
- *              *Op             - Where found/new op is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Find a named object.  Two versions - one to search the parse
- *              tree (for parser-only applications such as acpidump), another
- *              to search the ACPI internal namespace (the parse tree may no
- *              longer exist)
- *
- ******************************************************************************/
-
-#ifdef PARSER_ONLY
-
-acpi_status
-acpi_ps_find_object (
-	acpi_walk_state         *walk_state,
-	acpi_parse_object       **out_op)
-{
-	NATIVE_CHAR             *path;
-
-
-	/* We are only interested in opcodes that have an associated name */
-
-	if (!(walk_state->op_info->flags & AML_NAMED)) {
-		*out_op = walk_state->op;
-		return (AE_OK);
-	}
-
-	/* Find the name in the parse tree */
-
-	path = acpi_ps_get_next_namestring (&walk_state->parser_state);
-
-	*out_op = acpi_ps_find (acpi_ps_get_parent_scope (&walk_state->parser_state),
-			  path, walk_state->opcode, 1);
-
-	if (!(*out_op)) {
-		return (AE_NOT_FOUND);
-	}
-
-	return (AE_OK);
-}
-
-#endif
-
-
-/*******************************************************************************
- *
  * FUNCTION:    Acpi_ps_complete_this_op
  *
  * PARAMETERS:  Walk_state      - Current State
@@ -181,7 +129,6 @@
 	acpi_walk_state         *walk_state,
 	acpi_parse_object       *op)
 {
-#ifndef PARSER_ONLY
 	acpi_parse_object       *prev;
 	acpi_parse_object       *next;
 	const acpi_opcode_info  *parent_info;
@@ -317,10 +264,6 @@
 	}
 
 	return_VOID;
-
-#else
-	return;
-#endif
 }
 
 
@@ -381,6 +324,13 @@
 		parser_state->aml = walk_state->aml_last_while;
 		break;
 
+#if 0
+	case AE_CTRL_SKIP:
+
+		parser_state->aml = parser_state->scope->parse_scope.pkg_end;
+		status = AE_OK;
+		break;
+#endif
 
 	case AE_CTRL_TRUE:
 
@@ -585,14 +535,25 @@
 				 * Get and append arguments until we find the node that contains
 				 * the name (the type ARGP_NAME).
 				 */
-				while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME) {
-					arg = acpi_ps_get_next_arg (parser_state,
+				while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) &&
+					  (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME)) {
+					status = acpi_ps_get_next_arg (parser_state,
 							 GET_CURRENT_ARG_TYPE (walk_state->arg_types),
-							 &walk_state->arg_count);
+							 &walk_state->arg_count, &arg);
+					if (ACPI_FAILURE (status)) {
+						goto close_this_op;
+					}
+
 					acpi_ps_append_arg (&pre_op, arg);
 					INCREMENT_ARG_LIST (walk_state->arg_types);
 				}
 
+				/* Make sure that we found a NAME and didn't run out of arguments */
+
+				if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) {
+					return_ACPI_STATUS (AE_AML_NO_OPERAND);
+				}
+
 				/* We know that this arg is a name, move to next arg */
 
 				INCREMENT_ARG_LIST (walk_state->arg_types);
@@ -688,8 +649,8 @@
 
 			if (walk_state->op_info) {
 				ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
-					"Opcode %4.4hX [%s] Op %p Aml %p Aml_offset %5.5X\n",
-					 op->common.aml_opcode, walk_state->op_info->name,
+					"Opcode %4.4X [%s] Op %p Aml %p Aml_offset %5.5X\n",
+					 (u32) op->common.aml_opcode, walk_state->op_info->name,
 					 op, parser_state->aml, op->common.aml_offset));
 			}
 		}
@@ -717,7 +678,17 @@
 
 			case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */
 
-				acpi_ps_get_next_namepath (parser_state, op, &walk_state->arg_count, 1);
+				status = acpi_ps_get_next_namepath (parser_state, op, &walk_state->arg_count, 1);
+				if (ACPI_FAILURE (status)) {
+					/* NOT_FOUND is an error only if we are actually executing a method */
+
+					if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) &&
+							(status == AE_NOT_FOUND)) ||
+						(status != AE_NOT_FOUND)) {
+						goto close_this_op;
+					}
+				}
+
 				walk_state->arg_types = 0;
 				break;
 
@@ -729,14 +700,24 @@
 				while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) {
 					walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml,
 							   parser_state->aml_start);
-					arg = acpi_ps_get_next_arg (parser_state,
+					status = acpi_ps_get_next_arg (parser_state,
 							 GET_CURRENT_ARG_TYPE (walk_state->arg_types),
-							 &walk_state->arg_count);
+							 &walk_state->arg_count, &arg);
+					if (ACPI_FAILURE (status)) {
+						/* NOT_FOUND is an error only if we are actually executing a method */
+
+						if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) &&
+								(status == AE_NOT_FOUND)                                            &&
+								(op->common.aml_opcode != AML_COND_REF_OF_OP)) ||
+							(status != AE_NOT_FOUND)) {
+							goto close_this_op;
+						}
+					}
+
 					if (arg) {
 						arg->common.aml_offset = walk_state->aml_offset;
 						acpi_ps_append_arg (op, arg);
 					}
-
 					INCREMENT_ARG_LIST (walk_state->arg_types);
 				}
 
@@ -887,15 +868,17 @@
 
 			acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count);
 
-			walk_state->op    = op;
-			walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
-			walk_state->opcode = op->common.aml_opcode;
+			if (op) {
+				walk_state->op    = op;
+				walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+				walk_state->opcode = op->common.aml_opcode;
 
-			status = walk_state->ascending_callback (walk_state);
-			status = acpi_ps_next_parse_state (walk_state, op, status);
+				status = walk_state->ascending_callback (walk_state);
+				status = acpi_ps_next_parse_state (walk_state, op, status);
 
-			acpi_ps_complete_this_op (walk_state, op);
-			op = NULL;
+				acpi_ps_complete_this_op (walk_state, op);
+				op = NULL;
+			}
 			status = AE_OK;
 			break;
 
@@ -1053,6 +1036,7 @@
 	acpi_walk_state         *walk_state)
 {
 	acpi_status             status;
+	acpi_status             terminate_status;
 	ACPI_THREAD_STATE       *thread;
 	ACPI_THREAD_STATE       *prev_walk_list = acpi_gbl_current_walk_list;
 	acpi_walk_state         *previous_walk_state;
@@ -1131,10 +1115,9 @@
 		 * there's lots of cleanup to do
 		 */
 		if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) {
-			status = acpi_ds_terminate_control_method (walk_state);
-			if (ACPI_FAILURE (status)) {
+			terminate_status = acpi_ds_terminate_control_method (walk_state);
+			if (ACPI_FAILURE (terminate_status)) {
 				ACPI_REPORT_ERROR (("Could not terminate control method properly\n"));
-				status = AE_OK;
 
 				/* Ignore error and continue */
 			}
diff -Nru a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
--- a/drivers/acpi/parser/pstree.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/parser/pstree.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: pstree - Parser op tree manipulation/traversal/search
- *              $Revision: 39 $
+ *              $Revision: 40 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
--- a/drivers/acpi/resources/rsdump.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/resources/rsdump.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rsdump - Functions to display the resource structures.
- *              $Revision: 32 $
+ *              $Revision: 33 $
  *
  ******************************************************************************/
 
@@ -31,7 +31,7 @@
 	 ACPI_MODULE_NAME    ("rsdump")
 
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*******************************************************************************
  *
diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c
--- a/drivers/acpi/system.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/system.c	Tue Aug 27 12:28:07 2002
@@ -256,7 +256,8 @@
 	acpi_status		status = AE_ERROR;
 	unsigned long		flags = 0;
 
-	save_flags(flags);
+	local_irq_save(flags);
+	local_irq_disable();
 	
 	switch (state)
 	{
@@ -270,7 +271,7 @@
 		do_suspend_lowlevel(0);
 		break;
 	}
-	restore_flags(flags);
+	local_irq_restore(flags);
 
 	return status;
 }
diff -Nru a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
--- a/drivers/acpi/tables/tbconvrt.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/tables/tbconvrt.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbconvrt - ACPI Table conversion utilities
- *              $Revision: 42 $
+ *              $Revision: 43 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
--- a/drivers/acpi/tables/tbget.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/tables/tbget.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbget - ACPI Table get* routines
- *              $Revision: 78 $
+ *              $Revision: 79 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
--- a/drivers/acpi/tables/tbgetall.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/tables/tbgetall.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbgetall - Get all required ACPI tables
- *              $Revision: 1 $
+ *              $Revision: 2 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
--- a/drivers/acpi/tables/tbinstal.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/tables/tbinstal.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbinstal - ACPI table installation and removal
- *              $Revision: 62 $
+ *              $Revision: 63 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
--- a/drivers/acpi/tables/tbrsdt.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/tables/tbrsdt.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbrsdt - ACPI RSDT table utilities
- *              $Revision: 2 $
+ *              $Revision: 3 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
--- a/drivers/acpi/tables/tbutils.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/tables/tbutils.c	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbutils - Table manipulation utilities
- *              $Revision: 55 $
+ *              $Revision: 56 $
  *
  *****************************************************************************/
 
@@ -135,7 +135,7 @@
 			table_header, (char *) &signature));
 
 		ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n",
-			table_header->length));
+			(u32) table_header->length));
 		ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header));
 		return (AE_BAD_HEADER);
 	}
@@ -176,7 +176,7 @@
 
 	if (checksum) {
 		ACPI_REPORT_WARNING (("Invalid checksum (%X) in table %4.4s\n",
-			checksum, table_header->signature));
+			(u32) checksum, table_header->signature));
 
 		status = AE_BAD_CHECKSUM;
 	}
diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c
--- a/drivers/acpi/tables.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/tables.c	Tue Aug 27 12:28:02 2002
@@ -36,7 +36,7 @@
 
 #define PREFIX			"ACPI: "
 
-#define ACPI_MAX_TABLES		ACPI_TABLE_COUNT
+#define ACPI_MAX_TABLES		256
 
 static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
 	[ACPI_TABLE_UNKNOWN]	= "????",
@@ -338,7 +338,7 @@
 		sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3;
 		if (sdt.count > ACPI_MAX_TABLES) {
 			printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n",
-				(ACPI_MAX_TABLES - sdt.count));
+				(sdt.count - ACPI_MAX_TABLES));
 			sdt.count = ACPI_MAX_TABLES;
 		}
 
@@ -383,7 +383,7 @@
 		sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 2;
 		if (sdt.count > ACPI_MAX_TABLES) {
 			printk(KERN_WARNING PREFIX "Truncated %lu RSDT entries\n",
-				(ACPI_TABLE_COUNT - sdt.count));
+				(sdt.count - ACPI_TABLE_COUNT));
 			sdt.count = ACPI_MAX_TABLES;
 		}
 
diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
--- a/drivers/acpi/thermal.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/acpi/thermal.c	Tue Aug 27 12:28:02 2002
@@ -473,6 +473,7 @@
 			trend, passive->tc1, tz->temperature, 
 			tz->last_temperature, passive->tc2, 
 			tz->temperature, passive->temperature));
+		tz->trips.passive.flags.enabled = 1;
 		/* Heating up? */
 		if (trend > 0)
 			for (i=0; i<passive->devices.count; i++)
@@ -518,6 +519,7 @@
 	struct acpi_thermal_active *active = NULL;
 	int                     i = 0;
 	int			j = 0;
+	unsigned long		maxtemp = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_thermal_active");
 
@@ -537,7 +539,8 @@
 		 * associated with this active threshold.
 		 */
 		if (tz->temperature >= active->temperature) {
-			tz->state.active_index = i;
+			if (active->temperature > maxtemp)
+				tz->state.active_index = i, maxtemp = active->temperature;
 			if (!active->flags.enabled) {
 				for (j = 0; j < active->devices.count; j++) {
 					result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0);
@@ -591,6 +594,7 @@
 	struct acpi_thermal	*tz = (struct acpi_thermal *) data;
 	unsigned long		sleep_time = 0;
 	int			i = 0;
+	struct acpi_thermal_state state = tz->state;
 
 	ACPI_FUNCTION_TRACE("acpi_thermal_check");
 
@@ -613,15 +617,15 @@
 	 * this function determines when a state is entered, but the 
 	 * individual policy decides when it is exited (e.g. hysteresis).
 	 */
-	if ((tz->trips.critical.flags.valid) && (tz->temperature >= tz->trips.critical.temperature))
-		tz->trips.critical.flags.enabled = 1;
-	if ((tz->trips.hot.flags.valid) && (tz->temperature >= tz->trips.hot.temperature))
-		tz->trips.hot.flags.enabled = 1;
-	if ((tz->trips.passive.flags.valid) && (tz->temperature >= tz->trips.passive.temperature))
-		tz->trips.passive.flags.enabled = 1;
+	if (tz->trips.critical.flags.valid)
+		state.critical |= (tz->temperature >= tz->trips.critical.temperature);
+	if (tz->trips.hot.flags.valid)
+		state.hot |= (tz->temperature >= tz->trips.hot.temperature);
+	if (tz->trips.passive.flags.valid)
+		state.passive |= (tz->temperature >= tz->trips.passive.temperature);
 	for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++)
-		if ((tz->trips.active[i].flags.valid) && (tz->temperature >= tz->trips.active[i].temperature))
-			tz->trips.active[i].flags.enabled = 1;
+		if (tz->trips.active[i].flags.valid)
+			state.active |= (tz->temperature >= tz->trips.active[i].temperature);
 
 	/*
 	 * Invoke Policy
@@ -629,13 +633,13 @@
 	 * Separated from the above check to allow individual policy to 
 	 * determine when to exit a given state.
 	 */
-	if (tz->trips.critical.flags.enabled)
+	if (state.critical)
 		acpi_thermal_critical(tz);
-	if (tz->trips.hot.flags.enabled)
+	if (state.hot)
 		acpi_thermal_hot(tz);
-	if (tz->trips.passive.flags.enabled)
+	if (state.passive)
 		acpi_thermal_passive(tz);
-	if (tz->trips.active[0].flags.enabled)
+	if (state.active)
 		acpi_thermal_active(tz);
 
 	/*
diff -Nru a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
--- a/drivers/acpi/utilities/utdebug.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/utilities/utdebug.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utdebug - Debug print routines
- *              $Revision: 103 $
+ *              $Revision: 104 $
  *
  *****************************************************************************/
 
@@ -30,7 +30,7 @@
 	 ACPI_MODULE_NAME    ("utdebug")
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 
 static u32   acpi_gbl_prev_thread_id = 0xFFFFFFFF;
 static char     *acpi_gbl_fn_entry_str = "----Entry";
diff -Nru a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
--- a/drivers/acpi/utilities/uteval.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/utilities/uteval.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: uteval - Object evaluation
- *              $Revision: 40 $
+ *              $Revision: 41 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/utilities/utglobal.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utglobal - Global variables for the ACPI subsystem
- *              $Revision: 165 $
+ *              $Revision: 168 $
  *
  *****************************************************************************/
 
@@ -126,7 +126,7 @@
 
 /* Debug switch - level and trace mask */
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 u32                         acpi_dbg_level = DEBUG_DEFAULT;
 #else
 u32                         acpi_dbg_level = NORMAL_DEFAULT;
@@ -185,6 +185,10 @@
 	{"_REV",    ACPI_TYPE_INTEGER,          "2"},
 	{"_OS_",    ACPI_TYPE_STRING,           ACPI_OS_NAME},
 	{"_GL_",    ACPI_TYPE_MUTEX,            "0"},
+
+#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+	{"_OSI",    ACPI_TYPE_METHOD,           "1"},
+#endif
 	{NULL,      ACPI_TYPE_ANY,              NULL}              /* Table terminator */
 };
 
@@ -522,7 +526,7 @@
 }
 
 
-#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*
  * Strings and procedures used for debug only
@@ -773,7 +777,7 @@
 	acpi_gbl_root_node_struct.flags     = ANOBJ_END_OF_PEER_LIST;
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 	acpi_gbl_lowest_stack_pointer       = ACPI_SIZE_MAX;
 #endif
 
diff -Nru a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
--- a/drivers/acpi/utilities/utinit.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/acpi/utilities/utinit.c	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utinit - Common ACPI subsystem initialization
- *              $Revision: 112 $
+ *              $Revision: 113 $
  *
  *****************************************************************************/
 
@@ -198,13 +198,13 @@
 	acpi_gbl_shutdown = TRUE;
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n"));
 
-	/* Close the Namespace */
-
-	acpi_ns_terminate ();
-
 	/* Close the Acpi_event Handling */
 
 	acpi_ev_terminate ();
+
+	/* Close the Namespace */
+
+	acpi_ns_terminate ();
 
 	/* Close the globals */
 
diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
--- a/drivers/acpi/utilities/utmisc.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/acpi/utilities/utmisc.c	Tue Aug 27 12:27:59 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: utmisc - common utility procedures
- *              $Revision: 78 $
+ *              $Revision: 80 $
  *
  ******************************************************************************/
 
@@ -104,7 +104,7 @@
 }
 
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 /*******************************************************************************
  *
  * FUNCTION:    Acpi_ut_display_init_pathname
diff -Nru a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
--- a/drivers/acpi/utilities/utxface.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/acpi/utilities/utxface.c	Tue Aug 27 12:28:01 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utxface - External interfaces for "global" ACPI functions
- *              $Revision: 97 $
+ *              $Revision: 100 $
  *
  *****************************************************************************/
 
@@ -159,6 +159,8 @@
 	if (!(flags & ACPI_NO_ACPI_ENABLE)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n"));
 
+		acpi_gbl_original_mode = acpi_hw_get_mode();
+
 		status = acpi_enable ();
 		if (ACPI_FAILURE (status)) {
 			ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Acpi_enable failed.\n"));
@@ -291,7 +293,7 @@
 	acpi_ut_mutex_terminate ();
 
 
-#ifdef ENABLE_DEBUGGER
+#ifdef ACPI_DEBUGGER
 
 	/* Shut down the debugger */
 
diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Tue Aug 27 12:28:02 2002
+++ b/drivers/base/Makefile	Tue Aug 27 12:28:02 2002
@@ -1,10 +1,11 @@
 # Makefile for the Linux device tree
 
 obj-y		:= core.o sys.o interface.o power.o bus.o \
-			driver.o 
+			driver.o class.o intf.o
 
 obj-y		+= fs/
 
-export-objs	:= core.o power.o sys.o bus.o driver.o
+export-objs	:= core.o power.o sys.o bus.o driver.o \
+			class.o intf.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/base/base.h	Tue Aug 27 12:28:02 2002
@@ -6,9 +6,11 @@
 # define DBG(x...)
 #endif
 
-extern struct device device_root;
+extern struct list_head global_device_list;
 extern spinlock_t device_lock;
 
+extern struct device * get_device_locked(struct device *);
+
 extern int bus_add_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
 
@@ -23,6 +25,28 @@
 
 extern int device_bus_link(struct device * dev);
 extern void device_remove_symlink(struct driver_dir_entry * dir, const char * name);
+
+extern int devclass_make_dir(struct device_class *);
+extern void devclass_remove_dir(struct device_class *);
+
+extern int devclass_drv_link(struct device_driver *);
+extern void devclass_drv_unlink(struct device_driver *);
+
+extern int devclass_dev_link(struct device_class *, struct device *);
+extern void devclass_dev_unlink(struct device_class *, struct device *);
+
+extern int devclass_add_device(struct device *);
+extern void devclass_remove_device(struct device *);
+
+extern int intf_make_dir(struct device_interface *);
+extern void intf_remove_dir(struct device_interface *);
+
+extern int intf_dev_link(struct intf_data *);
+extern void intf_dev_unlink(struct intf_data *);
+
+extern int interface_add(struct device_class *, struct device *);
+extern void interface_remove(struct device_class *, struct device *);
+
 
 extern int driver_attach(struct device_driver * drv);
 extern void driver_detach(struct device_driver * drv);
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/base/bus.c	Tue Aug 27 12:28:02 2002
@@ -16,6 +16,9 @@
 
 static LIST_HEAD(bus_driver_list);
 
+#define to_dev(node) container_of(node,struct device,bus_list)
+#define to_drv(node) container_of(node,struct device_driver,bus_list)
+
 /**
  * bus_for_each_dev - walk list of devices and do something to each
  * @bus:	bus in question
@@ -26,42 +29,41 @@
  * counting on devices as we touch each one.
  *
  * Algorithm:
- * Take the bus lock and get the first node in the list. We increment
- * the reference count and unlock the bus. If we have a device from a 
- * previous iteration, we decrement the reference count. 
- * After we call the callback, we get the next node in the list and loop.
- * At the end, if @dev is not null, we still have it pinned, so we need
- * to let it go.
+ * Take device_lock and get the first node in the list. 
+ * Try and increment the reference count on it. If we can't, it's in the
+ * process of being removed, but that process hasn't acquired device_lock.
+ * It's still in the list, so we grab the next node and try that one. 
+ * We drop the lock to call the callback.
+ * We can't decrement the reference count yet, because we need the next
+ * node in the list. So, we set @prev to point to the current device.
+ * On the next go-round, we decrement the reference count on @prev, so if 
+ * it's being removed, it won't affect us.
  */
 int bus_for_each_dev(struct bus_type * bus, void * data, 
 		     int (*callback)(struct device * dev, void * data))
 {
-	struct device * next;
-	struct device * dev = NULL;
 	struct list_head * node;
+	struct device * prev = NULL;
 	int error = 0;
 
 	get_bus(bus);
-	read_lock(&bus->lock);
-	node = bus->devices.next;
-	while (node != &bus->devices) {
-		next = list_entry(node,struct device,bus_list);
-		get_device(next);
-		read_unlock(&bus->lock);
-
-		if (dev)
-			put_device(dev);
-		dev = next;
-		if ((error = callback(dev,data))) {
-			put_device(dev);
-			break;
+	spin_lock(&device_lock);
+	list_for_each(node,&bus->devices) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			spin_unlock(&device_lock);
+			error = callback(dev,data);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
+			if (error)
+				break;
 		}
-		read_lock(&bus->lock);
-		node = dev->bus_list.next;
 	}
-	read_unlock(&bus->lock);
-	if (dev)
-		put_device(dev);
+	spin_unlock(&device_lock);
+	if (prev)
+		put_device(prev);
 	put_bus(bus);
 	return error;
 }
@@ -69,34 +71,30 @@
 int bus_for_each_drv(struct bus_type * bus, void * data,
 		     int (*callback)(struct device_driver * drv, void * data))
 {
-	struct device_driver * next;
-	struct device_driver * drv = NULL;
 	struct list_head * node;
+	struct device_driver * prev = NULL;
 	int error = 0;
 
 	/* pin bus in memory */
 	get_bus(bus);
 
-	read_lock(&bus->lock);
-	node = bus->drivers.next;
-	while (node != &bus->drivers) {
-		next = list_entry(node,struct device_driver,bus_list);
-		get_driver(next);
-		read_unlock(&bus->lock);
-
-		if (drv)
-			put_driver(drv);
-		drv = next;
-		if ((error = callback(drv,data))) {
-			put_driver(drv);
-			break;
+	spin_lock(&device_lock);
+	list_for_each(node,&bus->drivers) {
+		struct device_driver * drv = get_driver(to_drv(node));
+		if (drv) {
+			spin_unlock(&device_lock);
+			error = callback(drv,data);
+			if (prev)
+				put_driver(prev);
+			prev = drv;
+			spin_lock(&device_lock);
+			if (error)
+				break;
 		}
-		read_lock(&bus->lock);
-		node = drv->bus_list.next;
 	}
-	read_unlock(&bus->lock);
-	if (drv)
-		put_driver(drv);
+	spin_unlock(&device_lock);
+	if (prev)
+		put_driver(prev);
 	put_bus(bus);
 	return error;
 }
@@ -115,9 +113,9 @@
 	if (dev->bus) {
 		pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
 		get_bus(dev->bus);
-		write_lock(&dev->bus->lock);
+		spin_lock(&device_lock);
 		list_add_tail(&dev->bus_list,&dev->bus->devices);
-		write_unlock(&dev->bus->lock);
+		spin_unlock(&device_lock);
 		device_bus_link(dev);
 	}
 	return 0;
@@ -134,9 +132,6 @@
 {
 	if (dev->bus) {
 		device_remove_symlink(&dev->bus->device_dir,dev->bus_id);
-		write_lock(&dev->bus->lock);
-		list_del_init(&dev->bus_list);
-		write_unlock(&dev->bus->lock);
 		put_bus(dev->bus);
 	}
 }
diff -Nru a/drivers/base/class.c b/drivers/base/class.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/class.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,109 @@
+/*
+ * class.c - basic device class management
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include "base.h"
+
+static LIST_HEAD(class_list);
+
+int devclass_add_driver(struct device_driver * drv)
+{
+	if (drv->devclass) {
+		pr_debug("Registering driver %s:%s with class %s\n",
+			 drv->bus->name,drv->name,drv->devclass->name);
+
+		spin_lock(&device_lock);
+		list_add_tail(&drv->class_list,&drv->devclass->drivers);
+		spin_unlock(&device_lock);
+		devclass_drv_link(drv);
+	}
+	return 0;
+}
+
+void devclass_remove_driver(struct device_driver * drv)
+{
+	if (drv->devclass) {
+		pr_debug("Removing driver %s:%s:%s\n",
+			 drv->devclass->name,drv->bus->name,drv->name);
+		spin_lock(&device_lock);
+		list_del_init(&drv->class_list);
+		spin_unlock(&device_lock);
+		devclass_drv_unlink(drv);
+	}
+}
+
+
+static void enum_device(struct device_class * cls, struct device * dev)
+{
+	u32 val;
+	spin_lock(&device_lock);
+	val = cls->devnum++;
+	spin_unlock(&device_lock);
+	dev->class_num = val;
+	devclass_dev_link(cls,dev);
+}
+
+static void unenum_device(struct device_class * cls, struct device * dev)
+{
+	devclass_dev_unlink(cls,dev);
+	dev->class_num = 0;
+}
+
+int devclass_add_device(struct device * dev)
+{
+	struct device_class * cls = dev->driver->devclass;
+	int error = 0;
+	if (cls) {
+		pr_debug("adding device '%s' to class '%s'\n",
+			 dev->name,cls->name);
+		if (cls->add_device) 
+			error = cls->add_device(dev);
+		if (!error) {
+			enum_device(cls,dev);
+			interface_add(cls,dev);
+		}
+	}
+	return error;
+}
+
+void devclass_remove_device(struct device * dev)
+{
+	struct device_class * cls = dev->driver->devclass;
+	if (cls) {
+		pr_debug("removing device '%s' from class '%s'\n",
+			 dev->name,cls->name);
+		interface_remove(cls,dev);
+		unenum_device(cls,dev);
+		if (cls->remove_device)
+			cls->remove_device(dev);
+	}
+}
+
+int devclass_register(struct device_class * cls)
+{
+	INIT_LIST_HEAD(&cls->drivers);
+	INIT_LIST_HEAD(&cls->intf_list);
+
+	pr_debug("registering device class '%s'\n",cls->name);
+
+	spin_lock(&device_lock);
+	list_add_tail(&cls->node,&class_list);
+	spin_unlock(&device_lock);
+	devclass_make_dir(cls);
+	return 0;
+}
+
+void devclass_unregister(struct device_class * cls)
+{
+	pr_debug("unregistering device class '%s'\n",cls->name);
+	devclass_remove_dir(cls);
+	spin_lock(&device_lock);
+	list_del_init(&class_list);
+	spin_unlock(&device_lock);
+}
+
+EXPORT_SYMBOL(devclass_register);
+EXPORT_SYMBOL(devclass_unregister);
+
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/base/core.c	Tue Aug 27 12:27:59 2002
@@ -12,19 +12,17 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/err.h>
 #include "base.h"
 
-struct device device_root = {
-	bus_id:		"root",
-	name:		"System root",
-};
+LIST_HEAD(global_device_list);
 
 int (*platform_notify)(struct device * dev) = NULL;
 int (*platform_notify_remove)(struct device * dev) = NULL;
 
 spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
 
+#define to_dev(node) container_of(node,struct device,driver_list)
+
 
 /**
  * found_match - do actual binding of device to driver
@@ -53,10 +51,11 @@
 	pr_debug("bound device '%s' to driver '%s'\n",
 		 dev->bus_id,drv->name);
 
-	write_lock(&drv->lock);
+	spin_lock(&device_lock);
 	list_add_tail(&dev->driver_list,&drv->devices);
-	write_unlock(&drv->lock);
-	
+	spin_unlock(&device_lock);
+	devclass_add_device(dev);
+
 	goto Done;
 
  ProbeFailed:
@@ -101,19 +100,15 @@
 	struct device_driver * drv; 
 
 	if (dev->driver) {
-		lock_device(dev);
+		devclass_remove_device(dev);
+		spin_lock(&device_lock);
 		drv = dev->driver;
 		dev->driver = NULL;
-		unlock_device(dev);
-
-		write_lock(&drv->lock);
-		list_del_init(&dev->driver_list);
-		write_unlock(&drv->lock);
+		spin_unlock(&device_lock);
 
 		/* detach from driver */
-		if (drv->remove)
+		if (drv && drv->remove)
 			drv->remove(dev);
-		put_driver(drv);
 	}
 }
 
@@ -134,47 +129,26 @@
 	return bus_for_each_dev(drv->bus,drv,do_driver_attach);
 }
 
-static int do_driver_detach(struct device * dev, struct device_driver * drv)
-{
-	lock_device(dev);
-	if (dev->driver == drv) {
-		dev->driver = NULL;
-		unlock_device(dev);
-		if (drv->remove)
-			drv->remove(dev);
-	} else
-		unlock_device(dev);
-	return 0;
-}
-
 void driver_detach(struct device_driver * drv)
 {
-	struct device * next;
-	struct device * dev = NULL;
 	struct list_head * node;
-	int error = 0;
+	struct device * prev = NULL;
 
-	write_lock(&drv->lock);
-	node = drv->devices.next;
-	while (node != &drv->devices) {
-		next = list_entry(node,struct device,driver_list);
-		get_device(next);
-		list_del_init(&next->driver_list);
-		write_unlock(&drv->lock);
-
-		if (dev)
-			put_device(dev);
-		dev = next;
-		if ((error = do_driver_detach(dev,drv))) {
-			put_device(dev);
-			break;
+	spin_lock(&device_lock);
+	list_for_each(node,&drv->devices) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			if (prev)
+				list_del_init(&prev->driver_list);
+			spin_unlock(&device_lock);
+			device_detach(dev);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
 		}
-		write_lock(&drv->lock);
-		node = drv->devices.next;
 	}
-	write_unlock(&drv->lock);
-	if (dev)
-		put_device(dev);
+	spin_unlock(&device_lock);
 }
 
 /**
@@ -191,7 +165,6 @@
 int device_register(struct device *dev)
 {
 	int error;
-	struct device *prev_dev;
 
 	if (!dev || !strlen(dev->bus_id))
 		return -EINVAL;
@@ -199,23 +172,19 @@
 	INIT_LIST_HEAD(&dev->node);
 	INIT_LIST_HEAD(&dev->children);
 	INIT_LIST_HEAD(&dev->g_list);
+	INIT_LIST_HEAD(&dev->driver_list);
+	INIT_LIST_HEAD(&dev->bus_list);
+	INIT_LIST_HEAD(&dev->intf_list);
 	spin_lock_init(&dev->lock);
 	atomic_set(&dev->refcount,2);
-
+	
 	spin_lock(&device_lock);
-	if (dev != &device_root) {
-		if (!dev->parent)
-			dev->parent = &device_root;
-		get_device(dev->parent);
-
-		if (list_empty(&dev->parent->children))
-			prev_dev = dev->parent;
-		else
-			prev_dev = list_entry(dev->parent->children.prev, struct device, node);
-		list_add(&dev->g_list, &prev_dev->g_list);
-
+	if (dev->parent) {
+		get_device_locked(dev->parent);
+		list_add_tail(&dev->g_list,&dev->parent->g_list);
 		list_add_tail(&dev->node,&dev->parent->children);
-	}
+	} else
+		list_add_tail(&dev->g_list,&global_device_list);
 	spin_unlock(&device_lock);
 
 	pr_debug("DEV: registering device: ID = '%s', name = %s\n",
@@ -234,12 +203,37 @@
 		platform_notify(dev);
 
  register_done:
+	if (error) {
+		spin_lock(&device_lock);
+		list_del_init(&dev->g_list);
+		list_del_init(&dev->node);
+		spin_unlock(&device_lock);
+		if (dev->parent)
+			put_device(dev->parent);
+	}
 	put_device(dev);
-	if (error && dev->parent)
-		put_device(dev->parent);
 	return error;
 }
 
+struct device * get_device_locked(struct device * dev)
+{
+	struct device * ret = dev;
+	if (dev && atomic_read(&dev->refcount) > 0)
+		atomic_inc(&dev->refcount);
+	else
+		ret = NULL;
+	return ret;
+}
+
+struct device * get_device(struct device * dev)
+{
+	struct device * ret;
+	spin_lock(&device_lock);
+	ret = get_device_locked(dev);
+	spin_unlock(&device_lock);
+	return ret;
+}
+
 /**
  * put_device - decrement reference count, and clean up when it hits 0
  * @dev:	device in question
@@ -250,6 +244,8 @@
 		return;
 	list_del_init(&dev->node);
 	list_del_init(&dev->g_list);
+	list_del_init(&dev->bus_list);
+	list_del_init(&dev->driver_list);
 	spin_unlock(&device_lock);
 
 	pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
@@ -270,12 +266,8 @@
 	if (dev->release)
 		dev->release(dev);
 
-	put_device(dev->parent);
-}
-
-static int __init device_init_root(void)
-{
-	return device_register(&device_root);
+	if (dev->parent)
+		put_device(dev->parent);
 }
 
 static int __init device_init(void)
@@ -283,17 +275,13 @@
 	int error;
 
 	error = init_driverfs_fs();
-	if (error) {
-		panic("DEV: could not initialize driverfs");
-		return error;
-	}
-	error = device_init_root();
 	if (error)
-		printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
-	return error;
+		panic("DEV: could not initialize driverfs");
+	return 0;
 }
 
 core_initcall(device_init);
 
 EXPORT_SYMBOL(device_register);
+EXPORT_SYMBOL(get_device);
 EXPORT_SYMBOL(put_device);
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/base/driver.c	Tue Aug 27 12:28:08 2002
@@ -10,35 +10,31 @@
 #include <linux/errno.h>
 #include "base.h"
 
+#define to_dev(node) container_of(node,struct device,driver_list)
 
-int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback)(struct device *, void * ))
+int driver_for_each_dev(struct device_driver * drv, void * data, 
+			int (*callback)(struct device *, void * ))
 {
-	struct device * next;
-	struct device * dev = NULL;
 	struct list_head * node;
+	struct device * prev = NULL;
 	int error = 0;
 
 	get_driver(drv);
-	read_lock(&drv->lock);
-	node = drv->devices.next;
-	while (node != &drv->devices) {
-		next = list_entry(node,struct device,driver_list);
-		get_device(next);
-		read_unlock(&drv->lock);
-
-		if (dev)
-			put_device(dev);
-		dev = next;
-		if ((error = callback(dev,data))) {
-			put_device(dev);
-			break;
+	spin_lock(&device_lock);
+	list_for_each(node,&drv->devices) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			spin_unlock(&device_lock);
+			error = callback(dev,data);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
+			if (error)
+				break;
 		}
-		read_lock(&drv->lock);
-		node = dev->driver_list.next;
 	}
-	read_unlock(&drv->lock);
-	if (dev)
-		put_device(dev);
+	spin_unlock(&device_lock);
 	put_driver(drv);
 	return error;
 }
@@ -60,9 +56,9 @@
 	atomic_set(&drv->refcount,2);
 	rwlock_init(&drv->lock);
 	INIT_LIST_HEAD(&drv->devices);
-	write_lock(&drv->bus->lock);
+	spin_lock(&device_lock);
 	list_add(&drv->bus_list,&drv->bus->drivers);
-	write_unlock(&drv->bus->lock);
+	spin_unlock(&device_lock);
 	driver_make_dir(drv);
 	driver_attach(drv);
 	put_driver(drv);
@@ -81,10 +77,10 @@
 
 void remove_driver(struct device_driver * drv)
 {
-	write_lock(&drv->bus->lock);
+	spin_lock(&device_lock);
 	atomic_set(&drv->refcount,0);
 	list_del_init(&drv->bus_list);
-	write_unlock(&drv->bus->lock);
+	spin_unlock(&device_lock);
 	__remove_driver(drv);
 }
 
@@ -94,13 +90,10 @@
  */
 void put_driver(struct device_driver * drv)
 {
-	write_lock(&drv->bus->lock);
-	if (!atomic_dec_and_test(&drv->refcount)) {
-		write_unlock(&drv->bus->lock);
+	if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
 		return;
-	}
 	list_del_init(&drv->bus_list);
-	write_unlock(&drv->bus->lock);
+	spin_unlock(&device_lock);
 	__remove_driver(drv);
 }
 
diff -Nru a/drivers/base/fs/Makefile b/drivers/base/fs/Makefile
--- a/drivers/base/fs/Makefile	Tue Aug 27 12:28:06 2002
+++ b/drivers/base/fs/Makefile	Tue Aug 27 12:28:06 2002
@@ -1,5 +1,5 @@
-obj-y		:= device.o bus.o driver.o
+obj-y		:= device.o bus.o driver.o class.o intf.o
 
-export-objs	:= device.o bus.o driver.o
+export-objs	:= device.o bus.o driver.o class.o intf.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/base/fs/bus.c b/drivers/base/fs/bus.c
--- a/drivers/base/fs/bus.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/base/fs/bus.c	Tue Aug 27 12:27:59 2002
@@ -56,10 +56,10 @@
 }
 
 static struct driverfs_ops bus_attr_ops = {
-	open:	bus_attr_open,
-	close:	bus_attr_close,
-	show:	bus_attr_show,
-	store:	bus_attr_store,
+	.open	= bus_attr_open,
+	.close	= bus_attr_close,
+	.show	= bus_attr_show,
+	.store	= bus_attr_store,
 };
 
 int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
@@ -107,8 +107,8 @@
 }
 
 static struct driver_dir_entry bus_dir = {
-	name:	"bus",
-	mode:	(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
+	.name	= "bus",
+	.mode	= (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
 };
 
 static int __init bus_init(void)
diff -Nru a/drivers/base/fs/class.c b/drivers/base/fs/class.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/fs/class.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,215 @@
+/*
+ * class.c - driverfs bindings for device classes.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "fs.h"
+
+static struct driver_dir_entry class_dir;
+
+
+#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
+
+#define to_class(d) container_of(d,struct device_class,dir)
+
+
+static ssize_t
+devclass_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
+	      char * buf, size_t count, loff_t off)
+{
+	struct devclass_attribute * class_attr = to_class_attr(attr);
+	struct device_class * dc = to_class(dir);
+	ssize_t ret = 0;
+
+	if (class_attr->show)
+		ret = class_attr->show(dc,buf,count,off);
+	return ret;
+}
+
+static ssize_t
+devclass_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
+	       const char * buf, size_t count, loff_t off)
+{
+	struct devclass_attribute * class_attr = to_class_attr(attr);
+	struct device_class * dc = to_class(dir);
+	ssize_t ret = 0;
+
+	if (class_attr->store)
+		ret = class_attr->store(dc,buf,count,off);
+	return ret;
+}
+
+static struct driverfs_ops devclass_attr_ops = {
+	show:	devclass_attr_show,
+	store:	devclass_attr_store,
+};
+
+int devclass_create_file(struct device_class * dc, struct devclass_attribute * attr)
+{
+	int error;
+	if (dc) {
+		error = driverfs_create_file(&attr->attr,&dc->dir);
+	} else
+		error = -EINVAL;
+	return error;
+}
+
+void devclass_remove_file(struct device_class * dc, struct devclass_attribute * attr)
+{
+	if (dc)
+		driverfs_remove_file(&dc->dir,attr->attr.name);
+}
+
+/**
+ *	devclass_dev_link - create symlink to device's directory
+ *	@cls - device class we're a part of 
+ *	@dev - device we're linking to 
+ *
+ *	Create a symlink in the class's devices/ directory to @dev's 
+ *	directory in the physical hierarchy. The name is the device's 
+ *	class-enumerated value (struct device::class_num). We're 
+ *	creating:
+ *		class/<class name>/devices/<link name> ->
+ *		root/<path to device>/<device's dir>
+ *	So, the link looks like:
+ *		../../../root/<path to device>/
+ */
+int devclass_dev_link(struct device_class * cls, struct device * dev)
+{
+	char	linkname[16];
+	char	* path;
+	int	length;
+	int	error;
+
+	length = get_devpath_length(dev);
+	length += strlen("../../../root");
+
+	if (length > PATH_MAX)
+		return -ENAMETOOLONG;
+
+	if (!(path = kmalloc(length,GFP_KERNEL)))
+		return -ENOMEM;
+	memset(path,0,length);
+	strcpy(path,"../../../root");
+	fill_devpath(dev,path,length);
+	
+	snprintf(linkname,16,"%u",dev->class_num);
+	error = driverfs_create_symlink(&cls->device_dir,linkname,path);
+	kfree(path);
+	return error;
+}
+
+void devclass_dev_unlink(struct device_class * cls, struct device * dev)
+{
+	char	linkname[16];
+
+	snprintf(linkname,16,"%u",dev->class_num);
+	driverfs_remove_file(&cls->device_dir,linkname);
+}
+
+/**
+ *	devclass_drv_link - create symlink to driver's directory
+ *	@drv:	driver we're linking up
+ *
+ *	Create a symlink in the class's drivers/ directory to @drv's
+ *	directory (in the bus's directory). It's name is <bus>:<driver>
+ *	to prevent naming conflicts.
+ *
+ *	We're creating 
+ *		class/<class name>/drivers/<link name> -> 
+ *		bus/<bus name>/drivers/<driver name>/
+ *	So, the link looks like: 
+ *		../../../bus/<bus name>/drivers/<driver name>
+ */
+int devclass_drv_link(struct device_driver * drv)
+{
+	char	* name;
+	char	* path;
+	int	namelen;
+	int	pathlen;
+	int	error = 0;
+
+	namelen = strlen(drv->name) + strlen(drv->bus->name) + 2;
+	name = kmalloc(namelen,GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+	snprintf(name,namelen,"%s:%s",drv->bus->name,drv->name);
+
+	pathlen = strlen("../../../bus/") + 
+		strlen(drv->bus->name) + 
+		strlen("/drivers/") + 
+		strlen(drv->name) + 1;
+	if (!(path = kmalloc(pathlen,GFP_KERNEL))) {
+		error = -ENOMEM;
+		goto Done;
+	}
+	snprintf(path,pathlen,"%s%s%s%s",
+		 "../../../bus/",
+		 drv->bus->name,
+		 "/drivers/",
+		 drv->name);
+
+	error = driverfs_create_symlink(&drv->devclass->driver_dir,name,path);
+ Done:
+	kfree(name);
+	kfree(path);
+	return error;
+}
+
+void devclass_drv_unlink(struct device_driver * drv)
+{
+	char	* name;
+	int	length;
+
+	length = strlen(drv->name) + strlen(drv->bus->name) + 2;
+	if ((name = kmalloc(length,GFP_KERNEL))) {
+		driverfs_remove_file(&drv->devclass->driver_dir,name);
+		kfree(name);
+	}
+}
+
+void devclass_remove_dir(struct device_class * dc)
+{
+	driverfs_remove_dir(&dc->device_dir);
+	driverfs_remove_dir(&dc->driver_dir);
+	driverfs_remove_dir(&dc->dir);
+}
+
+int devclass_make_dir(struct device_class * dc)
+{
+	int error;
+
+	dc->dir.name = dc->name;
+	dc->dir.ops = &devclass_attr_ops;
+	error = device_create_dir(&dc->dir,&class_dir);
+	if (!error) {
+		dc->driver_dir.name = "drivers";
+		error = device_create_dir(&dc->driver_dir,&dc->dir);
+		if (!error) {
+			dc->device_dir.name = "devices";
+			error = device_create_dir(&dc->device_dir,&dc->dir);
+		}
+		if (error)
+			driverfs_remove_dir(&dc->dir);
+	}
+	return error;
+}
+
+static struct driver_dir_entry class_dir = {
+	name:	"class",
+	mode:	(S_IRWXU | S_IRUGO | S_IXUGO),
+};
+
+static int __init devclass_driverfs_init(void)
+{
+	return driverfs_create_dir(&class_dir,NULL);
+}
+
+core_initcall(devclass_driverfs_init);
+
+EXPORT_SYMBOL(devclass_create_file);
+EXPORT_SYMBOL(devclass_remove_file);
diff -Nru a/drivers/base/fs/device.c b/drivers/base/fs/device.c
--- a/drivers/base/fs/device.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/base/fs/device.c	Tue Aug 27 12:28:06 2002
@@ -10,11 +10,17 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/stat.h>
 #include <linux/limits.h>
 
+static struct driver_dir_entry device_root_dir = {
+	.name	= "root",
+	.mode	= (S_IRWXU | S_IRUGO | S_IXUGO),
+};
+
 extern struct device_attribute * device_default_files[];
 
 #define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
@@ -67,10 +73,10 @@
 }
 
 static struct driverfs_ops dev_attr_ops = {
-	open:	dev_attr_open,
-	close:	dev_attr_close,
-	show:	dev_attr_show,
-	store:	dev_attr_store,
+	.open	= dev_attr_open,
+	.close	= dev_attr_close,
+	.show	= dev_attr_show,
+	.store	= dev_attr_store,
 };
 
 /**
@@ -117,7 +123,7 @@
 		driverfs_remove_dir(&dev->dir);
 }
 
-static int get_devpath_length(struct device * dev)
+int get_devpath_length(struct device * dev)
 {
 	int length = 1;
 	struct device * parent = dev;
@@ -132,7 +138,7 @@
 	return length;
 }
 
-static void fill_devpath(struct device * dev, char * path, int length)
+void fill_devpath(struct device * dev, char * path, int length)
 {
 	struct device * parent;
 	--length;
@@ -164,7 +170,7 @@
 	 * one to get to the 'bus' directory, and one to get to the root 
 	 * of the fs.)
 	 */
-	length += strlen("../../..");
+	length += strlen("../../../root");
 
 	if (length > PATH_MAX)
 		return -ENAMETOOLONG;
@@ -174,7 +180,7 @@
 	memset(path,0,length);
 
 	/* our relative position */
-	strcpy(path,"../../..");
+	strcpy(path,"../../../root");
 
 	fill_devpath(dev,path,length);
 	error = driverfs_create_symlink(&dev->bus->device_dir,dev->bus_id,path);
@@ -207,13 +213,12 @@
  */
 int device_make_dir(struct device * dev)
 {
-	struct driver_dir_entry * parent = NULL;
+	struct driver_dir_entry * parent;
 	struct device_attribute * entry;
 	int error;
 	int i;
 
-	if (dev->parent)
-		parent = &dev->parent->dir;
+	parent = dev->parent ? &dev->parent->dir : &device_root_dir;
 	dev->dir.name = dev->bus_id;
 	dev->dir.ops = &dev_attr_ops;
 
@@ -229,6 +234,12 @@
 	return error;
 }
 
+static int device_driverfs_init(void)
+{
+	return driverfs_create_dir(&device_root_dir,NULL);
+}
+
+core_initcall(device_driverfs_init);
+
 EXPORT_SYMBOL(device_create_file);
 EXPORT_SYMBOL(device_remove_file);
-
diff -Nru a/drivers/base/fs/driver.c b/drivers/base/fs/driver.c
--- a/drivers/base/fs/driver.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/base/fs/driver.c	Tue Aug 27 12:27:57 2002
@@ -54,10 +54,10 @@
 }
 
 static struct driverfs_ops drv_attr_ops = {
-	open:	drv_attr_open,
-	close:	drv_attr_close,
-	show:	drv_attr_show,
-	store:	drv_attr_store,
+	.open	= drv_attr_open,
+	.close	= drv_attr_close,
+	.show	= drv_attr_show,
+	.store	= drv_attr_store,
 };
 
 int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
diff -Nru a/drivers/base/fs/fs.h b/drivers/base/fs/fs.h
--- a/drivers/base/fs/fs.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/base/fs/fs.h	Tue Aug 27 12:28:02 2002
@@ -1,2 +1,7 @@
 
 extern int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent);
+
+int get_devpath_length(struct device * dev);
+
+void fill_devpath(struct device * dev, char * path, int length);
+
diff -Nru a/drivers/base/fs/intf.c b/drivers/base/fs/intf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/fs/intf.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,54 @@
+/*
+ * intf.c - driverfs glue for device interfaces
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include "fs.h"
+
+/**
+ * intf_dev_link - symlink from interface's directory to device's directory
+ *
+ */
+int intf_dev_link(struct intf_data * data)
+{
+	char	linkname[16];
+	char	* path;
+	int	length;
+	int	error;
+
+	length = get_devpath_length(data->dev);
+	length += strlen("../../../root");
+
+	if (length > PATH_MAX)
+		return -ENAMETOOLONG;
+
+	if (!(path = kmalloc(length,GFP_KERNEL)))
+		return -ENOMEM;
+	memset(path,0,length);
+	strcpy(path,"../../../root");
+	fill_devpath(data->dev,path,length);
+
+	snprintf(linkname,16,"%u",data->intf_num);
+	error = driverfs_create_symlink(&data->intf->dir,linkname,path);
+	kfree(path);
+	return error;
+}
+
+void intf_dev_unlink(struct intf_data * data)
+{
+	char	linkname[16];
+	snprintf(linkname,16,"%u",data->intf_num);
+	driverfs_remove_file(&data->intf->dir,linkname);
+}
+
+void intf_remove_dir(struct device_interface * intf)
+{
+	driverfs_remove_dir(&intf->dir);
+}
+
+int intf_make_dir(struct device_interface * intf)
+{
+	intf->dir.name = intf->name;
+	return device_create_dir(&intf->dir,&intf->devclass->dir);
+}
diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c
--- a/drivers/base/interface.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/base/interface.c	Tue Aug 27 12:27:59 2002
@@ -14,7 +14,7 @@
 	return off ? 0 : sprintf(buf,"%s\n",dev->name);
 }
 
-static DEVICE_ATTR(name,"name",S_IRUGO,device_read_name,NULL);
+static DEVICE_ATTR(name,S_IRUGO,device_read_name,NULL);
 
 static ssize_t
 device_read_power(struct device * dev, char * page, size_t count, loff_t off)
@@ -85,7 +85,7 @@
 	return error < 0 ? error : count;
 }
 
-static DEVICE_ATTR(power,"power",S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(power,S_IWUSR | S_IRUGO,
 		   device_read_power,device_write_power);
 
 struct device_attribute * device_default_files[] = {
diff -Nru a/drivers/base/intf.c b/drivers/base/intf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/intf.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,96 @@
+/*
+ * intf.c - class-specific interface management
+ */
+
+#define DEBUG 1
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include "base.h"
+
+
+#define to_intf(node) container_of(node,struct device_interface,node)
+
+int interface_register(struct device_interface * intf)
+{
+	struct device_class * cls = intf->devclass;
+
+	if (cls) {
+		pr_debug("register interface '%s' with class '%s\n",
+			 intf->name,cls->name);
+		intf_make_dir(intf);
+		spin_lock(&device_lock);
+		list_add_tail(&intf->node,&cls->intf_list);
+		spin_unlock(&device_lock);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+void interface_unregister(struct device_interface * intf)
+{
+	pr_debug("unregistering interface '%s' from class '%s'\n",
+		 intf->name,intf->devclass->name);
+	spin_lock(&device_lock);
+	list_del_init(&intf->node);
+	spin_unlock(&device_lock);
+
+	intf_remove_dir(intf);
+}
+
+int interface_add(struct device_class * cls, struct device * dev)
+{
+	struct list_head * node;
+	int error = 0;
+
+	pr_debug("adding '%s' to %s class interfaces\n",dev->name,cls->name);
+
+	list_for_each(node,&cls->intf_list) {
+		struct device_interface * intf = to_intf(node);
+		if (intf->add_device) {
+			error = intf->add_device(dev);
+			if (error)
+				pr_debug("%s:%s: adding '%s' failed: %d\n",
+					 cls->name,intf->name,dev->name,error);
+		}
+		
+	}
+	return 0;
+}
+
+void interface_remove(struct device_class * cls, struct device * dev)
+{
+	struct list_head * node;
+	struct list_head * next;
+
+	pr_debug("remove '%s' from %s class interfaces: ",dev->name,cls->name);
+
+	spin_lock(&device_lock);
+	list_for_each_safe(node,next,&dev->intf_list) {
+		struct intf_data * intf_data = container_of(node,struct intf_data,node);
+		list_del_init(&intf_data->node);
+		spin_unlock(&device_lock);
+
+		intf_dev_unlink(intf_data);
+		pr_debug("%s ",intf_data->intf->name);
+		if (intf_data->intf->remove_device)
+			intf_data->intf->remove_device(intf_data);
+
+		spin_lock(&device_lock);
+	}
+	spin_unlock(&device_lock);
+	pr_debug("\n");
+}
+
+int interface_add_data(struct intf_data * data)
+{
+	spin_lock(&device_lock);
+	list_add_tail(&data->node,&data->dev->intf_list);
+	data->intf_num = ++data->intf->devnum;
+	spin_unlock(&device_lock);
+	intf_dev_link(data);
+	return 0;
+}
+
+EXPORT_SYMBOL(interface_register);
+EXPORT_SYMBOL(interface_unregister);
diff -Nru a/drivers/base/power.c b/drivers/base/power.c
--- a/drivers/base/power.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/base/power.c	Tue Aug 27 12:27:59 2002
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include "base.h"
 
+#define to_dev(node) container_of(node,struct device,g_list)
+
 /**
  * device_suspend - suspend all devices on the device tree
  * @state:	state we're entering
@@ -25,30 +27,26 @@
  */
 int device_suspend(u32 state, u32 level)
 {
-	struct device * dev;
-	struct device * prev = &device_root;
+	struct list_head * node;
+	struct device * prev = NULL;
 	int error = 0;
 
 	printk(KERN_EMERG "Suspending Devices\n");
 
-	get_device(prev);
-
 	spin_lock(&device_lock);
-	dev = g_list_to_dev(prev->g_list.next);
-	while(dev != &device_root && !error) {
-		get_device(dev);
-		spin_unlock(&device_lock);
-		put_device(prev);
-
-		if (dev->driver && dev->driver->suspend)
-			error = dev->driver->suspend(dev,state,level);
-
-		spin_lock(&device_lock);
-		prev = dev;
-		dev = g_list_to_dev(prev->g_list.next);
+	list_for_each(node,&global_device_list) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			spin_unlock(&device_lock);
+			if (dev->driver && dev->driver->suspend)
+				error = dev->driver->suspend(dev,state,level);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
+		}
 	}
 	spin_unlock(&device_lock);
-	put_device(prev);
 
 	return error;
 }
@@ -63,27 +61,23 @@
  */
 void device_resume(u32 level)
 {
-	struct device * dev;
-	struct device * prev = &device_root;
-
-	get_device(prev);
+	struct list_head * node;
+	struct device * prev = NULL;
 
 	spin_lock(&device_lock);
-	dev = g_list_to_dev(prev->g_list.prev);
-	while(dev != &device_root) {
-		get_device(dev);
-		spin_unlock(&device_lock);
-		put_device(prev);
-
-		if (dev->driver && dev->driver->resume)
-			dev->driver->resume(dev,level);
-
-		spin_lock(&device_lock);
-		prev = dev;
-		dev = g_list_to_dev(prev->g_list.prev);
+	list_for_each_prev(node,&global_device_list) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			spin_unlock(&device_lock);
+			if (dev->driver && dev->driver->resume)
+				dev->driver->resume(dev,level);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
+		}
 	}
 	spin_unlock(&device_lock);
-	put_device(prev);
 
 	printk(KERN_EMERG "Devices Resumed\n");
 }
@@ -98,29 +92,25 @@
  */
 void device_shutdown(void)
 {
-	struct device * dev;
-	struct device * prev = &device_root;
+	struct list_head * node;
+	struct device * prev = NULL;
 
 	printk(KERN_EMERG "Shutting down devices\n");
 
-	get_device(prev);
-
 	spin_lock(&device_lock);
-	dev = g_list_to_dev(prev->g_list.next);
-	while(dev != &device_root) {
-		get_device(dev);
-		spin_unlock(&device_lock);
-		put_device(prev);
-
-		if (dev->driver && dev->driver->remove)
-			dev->driver->remove(dev);
-
-		spin_lock(&device_lock);
-		prev = dev;
-		dev = g_list_to_dev(prev->g_list.next);
+	list_for_each(node,&global_device_list) {
+		struct device * dev = get_device_locked(to_dev(node));
+		if (dev) {
+			spin_unlock(&device_lock);
+			if (dev->driver && dev->driver->remove)
+				dev->driver->remove(dev);
+			if (prev)
+				put_device(prev);
+			prev = dev;
+			spin_lock(&device_lock);
+		}
 	}
 	spin_unlock(&device_lock);
-	put_device(prev);
 }
 
 EXPORT_SYMBOL(device_suspend);
diff -Nru a/drivers/base/sys.c b/drivers/base/sys.c
--- a/drivers/base/sys.c	Tue Aug 27 12:27:39 2002
+++ b/drivers/base/sys.c	Tue Aug 27 12:27:39 2002
@@ -17,8 +17,8 @@
 #include <linux/errno.h>
 
 static struct device system_bus = {
-       name:           "System Bus",
-       bus_id:         "sys",
+       .name           = "System Bus",
+       .bus_id         = "sys",
 };
 
 int register_sys_device(struct device * dev)
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/block/DAC960.c	Tue Aug 27 12:28:08 2002
@@ -75,17 +75,19 @@
   *DAC960_Controllers[DAC960_MaxControllers] =	{ NULL };
 
 
+static int DAC960_revalidate(kdev_t);
 /*
   DAC960_BlockDeviceOperations is the Block Device Operations structure for
   DAC960 Logical Disk Devices.
 */
 
-static BlockDeviceOperations_T
-  DAC960_BlockDeviceOperations =
-    { owner:		    THIS_MODULE,
-      open:		    DAC960_Open,
-      release:		    DAC960_Release,
-      ioctl:		    DAC960_IOCTL };
+static struct block_device_operations DAC960_BlockDeviceOperations = {
+	owner:		THIS_MODULE,
+	open:		DAC960_Open,
+	release:	DAC960_Release,
+	ioctl:		DAC960_IOCTL,
+	revalidate:	DAC960_revalidate,
+};
 
 
 /*
@@ -306,9 +308,9 @@
 
 static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
 {
-  spin_unlock_irq(&Controller->RequestQueue->queue_lock);
+  spin_unlock_irq(Controller->RequestQueue->queue_lock);
   __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
-  spin_lock_irq(&Controller->RequestQueue->queue_lock);
+  spin_lock_irq(Controller->RequestQueue->queue_lock);
 }
 
 
@@ -1920,7 +1922,6 @@
   return true;
 }
 
-
 /*
   DAC960_RegisterBlockDevice registers the Block Device structures
   associated with Controller.
@@ -1929,8 +1930,16 @@
 static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
 {
   int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+  char *names;
   RequestQueue_T *RequestQueue;
   int MinorNumber;
+  int n;
+
+  names = kmalloc(9 * DAC960_MaxLogicalDrives, GFP_KERNEL);
+  if (!names) {
+      DAC960_Error("out of memory", Controller);
+      return false;
+  }
   /*
     Register the Block Device Major Number for this DAC960 Controller.
   */
@@ -1939,13 +1948,15 @@
     {
       DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
 		   Controller, MajorNumber);
+      kfree(names);
       return false;
     }
   /*
     Initialize the I/O Request Queue.
   */
   RequestQueue = BLK_DEFAULT_QUEUE(MajorNumber);
-  blk_init_queue(RequestQueue, DAC960_RequestFunction);
+  Controller->queue_lock = SPIN_LOCK_UNLOCKED;
+  blk_init_queue(RequestQueue, DAC960_RequestFunction, &Controller->queue_lock);
   RequestQueue->queuedata = Controller;
   blk_queue_max_hw_segments(RequestQueue,
 			    Controller->DriverScatterGatherLimit);
@@ -1953,27 +1964,19 @@
   blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
 
   Controller->RequestQueue = RequestQueue;
-  /*
-    Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
-    array, and Max Sectors per Request array.
-  */
-  for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
-    Controller->MaxSectorsPerRequest[MinorNumber] =
-      Controller->MaxBlocksPerCommand;
-  Controller->GenericDiskInfo.part = Controller->DiskPartitions;
-  /*
-    Complete initialization of the Generic Disk Information structure.
-  */
-  Controller->GenericDiskInfo.major = MajorNumber;
-  Controller->GenericDiskInfo.major_name = "rd";
-  Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
-  Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.next = NULL;
-  Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
-  /*
-    Install the Generic Disk Information structure at the end of the list.
-  */
-  add_gendisk(&Controller->GenericDiskInfo);
+  for (n = 0; n < DAC960_MaxLogicalDrives; n++) {
+	struct gendisk *disk = &Controller->disks[n];
+	memset(disk, 0, sizeof(struct gendisk));
+	sprintf(names + 9 * n, "rd/c%dd%d", Controller->ControllerNumber, n);
+	disk->part = Controller->DiskPartitions + (n<<DAC960_MaxPartitionsBits);
+	disk->major = MajorNumber;
+	disk->first_minor = n << DAC960_MaxPartitionsBits;
+	disk->major_name = names + 9 * n;
+	disk->minor_shift = DAC960_MaxPartitionsBits;
+	disk->nr_real = 1;
+	disk->fops = &DAC960_BlockDeviceOperations;
+	add_gendisk(disk);
+   }
   /*
     Indicate the Block Device Registration completed successfully,
   */
@@ -1989,6 +1992,11 @@
 static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
 {
   int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+  int disk;
+  for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) {
+	  del_gendisk(&Controller->disks[disk]);
+	  kfree(Controller->disks[0].major_name);
+  }
   /*
     Unregister the Block Device Major Number for this DAC960 Controller.
   */
@@ -2001,14 +2009,23 @@
     Remove the Disk Partitions array, Partition Sizes array, Block Sizes
     array, Max Sectors per Request array, and Max Segments per Request array.
   */
-  Controller->GenericDiskInfo.part = NULL;
   blk_clear(MajorNumber);
-  /*
-    Remove the Generic Disk Information structure from the list.
-  */
-  del_gendisk(&Controller->GenericDiskInfo);
 }
 
+static long disk_size(DAC960_Controller_T *Controller, int disk)
+{
+	if (Controller->FirmwareType == DAC960_V1_Controller) {
+		if (disk >= Controller->LogicalDriveCount)
+			return 0;
+		return Controller->V1.LogicalDriveInformation[disk].LogicalDriveSize;
+	} else {
+		DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+			Controller->V2.LogicalDeviceInformation[disk];
+		if (LogicalDeviceInfo == NULL)
+			return 0;
+		return LogicalDeviceInfo->ConfigurableDeviceSize;
+	}
+}
 
 /*
   DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk
@@ -2017,59 +2034,21 @@
 
 static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
 {
-  GenericDiskInfo_T *GenericDiskInfo = &Controller->GenericDiskInfo;
-  int LogicalDriveNumber, i;
-  for (LogicalDriveNumber = 0;
-       LogicalDriveNumber < DAC960_MaxLogicalDrives;
-       LogicalDriveNumber++)
-    {
-      int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, 0);
-      if (Controller->FirmwareType == DAC960_V1_Controller)
-	{
-	  if (LogicalDriveNumber < Controller->LogicalDriveCount)
-	    GenericDiskInfo->part[MinorNumber].nr_sects =
-	      Controller->V1.LogicalDriveInformation
-			     [LogicalDriveNumber].LogicalDriveSize;
-	  else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
-	}
-      else
-	{
-	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
-	    Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
-	  if (LogicalDeviceInfo != NULL)
-	    GenericDiskInfo->part[MinorNumber].nr_sects =
-	      LogicalDeviceInfo->ConfigurableDeviceSize;
-	  else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
-	}
-    }
+	struct gendisk *disks = Controller->disks;
+	int disk;
+	for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++)
+		disks->part[0].nr_sects = disk_size(Controller, disk);
 }
 
-
-/*
-  DAC960_RegisterDisk registers the DAC960 Logical Disk Device for Logical
-  Drive Number if it exists.
-*/
-
-static void DAC960_RegisterDisk(DAC960_Controller_T *Controller,
-				int LogicalDriveNumber)
-{
-  long size;
-  if (Controller->FirmwareType == DAC960_V1_Controller) {
-      if (LogicalDriveNumber > Controller->LogicalDriveCount - 1) return;
-      size = Controller->V1.LogicalDriveInformation
-				   [LogicalDriveNumber].LogicalDriveSize;
-  } else {
-      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
-	Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
-      if (LogicalDeviceInfo == NULL) return;
-      size = LogicalDeviceInfo->ConfigurableDeviceSize;
-  }
-  register_disk(&Controller->GenericDiskInfo,
-    DAC960_KernelDevice(Controller->ControllerNumber, LogicalDriveNumber, 0),
-    DAC960_MaxPartitions, &DAC960_BlockDeviceOperations, size);
+static int DAC960_revalidate(kdev_t dev)
+{
+	int ctlr = DAC960_ControllerNumber(dev);
+	int disk = DAC960_LogicalDriveNumber(dev);
+	DAC960_Controller_T *p = DAC960_Controllers[ctlr];
+	p->disks[disk].part[0].nr_sects = disk_size(p, disk);
+	return 0;
 }
 
-
 /*
   DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
   the Error Status Register when the driver performs the BIOS handshaking.
@@ -2642,14 +2621,15 @@
        ControllerNumber++)
     {
       DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-      int LogicalDriveNumber;
+      int disk;
       if (Controller == NULL) continue;
       DAC960_InitializeController(Controller);
-      DAC960_ComputeGenericDiskInfo(Controller);
-      for (LogicalDriveNumber = 0;
-	   LogicalDriveNumber < DAC960_MaxLogicalDrives;
-	   LogicalDriveNumber++)
-	DAC960_RegisterDisk(Controller, LogicalDriveNumber);
+      for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) {
+	long size = disk_size(Controller, disk);
+	register_disk(&Controller->disks[disk],
+	    DAC960_KernelDevice(Controller->ControllerNumber, disk, 0),
+	    DAC960_MaxPartitions, &DAC960_BlockDeviceOperations, size);
+      }
     }
   DAC960_CreateProcEntries();
   register_reboot_notifier(&DAC960_NotifierBlock);
@@ -2732,17 +2712,17 @@
 	  if (bio_data(BufferHeader) == LastDataEndPointer)
 	    {
 	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
-		bio_size(BufferHeader);
-	      LastDataEndPointer += bio_size(BufferHeader);
+		BufferHeader->bi_size;
+	      LastDataEndPointer += BufferHeader->bi_size;
 	    }
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
 		Virtual_to_Bus32(bio_data(BufferHeader));
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
-		bio_size(BufferHeader);
+		BufferHeader->bi_size;
 	      LastDataEndPointer = bio_data(BufferHeader) +
-		bio_size(BufferHeader);
+		BufferHeader->bi_size;
 	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
 		panic("DAC960: Scatter/Gather Segment Overflow\n");
 	    }
@@ -2823,17 +2803,17 @@
 	  if (bio_data(BufferHeader) == LastDataEndPointer)
 	    {
 	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
-		bio_size(BufferHeader);
-	      LastDataEndPointer += bio_size(BufferHeader);
+		BufferHeader->bi_size;
+	      LastDataEndPointer += BufferHeader->bi_size;
 	    }
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
 		Virtual_to_Bus64(bio_data(BufferHeader));
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
-		bio_size(BufferHeader);
+		BufferHeader->bi_size;
 	      LastDataEndPointer = bio_data(BufferHeader) +
-		bio_size(BufferHeader);
+		BufferHeader->bi_size;
 	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
 		panic("DAC960: Scatter/Gather Segment Overflow\n");
 	    }
@@ -3055,7 +3035,7 @@
 	      Command->CommandType = DAC960_WriteRetryCommand;
 	      CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
 	    }
-	  Command->BlockCount = bio_size(BufferHeader) >> DAC960_BlockSizeBits;
+	  Command->BlockCount = BufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.BusAddress =
 	    Virtual_to_Bus32(bio_data(BufferHeader));
@@ -3104,9 +3084,9 @@
 	  DAC960_V1_CommandMailbox_T *CommandMailbox =
 	    &Command->V1.CommandMailbox;
 	  Command->BlockNumber +=
-	    bio_size(BufferHeader) >> DAC960_BlockSizeBits;
+	    BufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  Command->BlockCount =
-	    bio_size(NextBufferHeader) >> DAC960_BlockSizeBits;
+	    NextBufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  Command->BufferHeader = NextBufferHeader;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
@@ -4152,7 +4132,7 @@
 	  if (CommandType == DAC960_ReadCommand)
 	    Command->CommandType = DAC960_ReadRetryCommand;
 	  else Command->CommandType = DAC960_WriteRetryCommand;
-	  Command->BlockCount = bio_size(BufferHeader) >> DAC960_BlockSizeBits;
+	  Command->BlockCount = BufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->SCSI_10.CommandControlBits
 				 .AdditionalScatterGatherListMemory = false;
 	  CommandMailbox->SCSI_10.DataTransferSize =
@@ -4208,9 +4188,9 @@
       if (NextBufferHeader != NULL)
 	{
 	  Command->BlockNumber +=
-	    bio_size(BufferHeader) >> DAC960_BlockSizeBits;
+	    BufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  Command->BlockCount =
-	    bio_size(NextBufferHeader) >> DAC960_BlockSizeBits;
+	    NextBufferHeader->bi_size >> DAC960_BlockSizeBits;
 	  Command->BufferHeader = NextBufferHeader;
 	  CommandMailbox->SCSI_10.DataTransferSize =
 	    Command->BlockCount << DAC960_BlockSizeBits;
@@ -5289,11 +5269,15 @@
     }
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
+      long size;
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
-      DAC960_ComputeGenericDiskInfo(Controller);
-      DAC960_RegisterDisk(Controller, LogicalDriveNumber);
+      size = disk_size(Controller, LogicalDriveNumber);
+      /* BROKEN, same as modular ide-floppy/ide-disk; same fix - ->probe() */
+      register_disk(&Controller->disks[LogicalDriveNumber],
+	    DAC960_KernelDevice(Controller->ControllerNumber, LogicalDriveNumber, 0),
+	    DAC960_MaxPartitions, &DAC960_BlockDeviceOperations, size);
     }
-  if (Controller->GenericDiskInfo.part[minor(Inode->i_rdev)].nr_sects == 0)
+  if (Controller->disks[LogicalDriveNumber].part[0].nr_sects == 0)
     return -ENXIO;
   /*
     Increment Controller and Logical Drive Usage Counts.
@@ -5391,18 +5375,6 @@
       Geometry.start = get_start_sect(Inode->i_bdev);
       return (copy_to_user(UserGeometry, &Geometry,
 			   sizeof(DiskGeometry_T)) ? -EFAULT : 0);
-
-    case BLKRRPART:
-      /* Re-Read Partition Table. */
-      if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-      if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
-	return -EBUSY;
-      res = wipe_partitions(Inode->i_rdev);
-      if (res) /* nothing */
-	return res;
-
-      DAC960_RegisterDisk(Controller, LogicalDriveNumber);
-      return 0;
     }
   return -EINVAL;
 }
@@ -5528,11 +5500,11 @@
 	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
 						     [DCDB.TargetID])
 	      {
-		spin_unlock_irq(&Controller->RequestQueue->queue_lock);
+		spin_unlock_irq(Controller->RequestQueue->queue_lock);
 		__wait_event(Controller->CommandWaitQueue,
 			     !Controller->V1.DirectCommandActive
 					     [DCDB.Channel][DCDB.TargetID]);
-		spin_lock_irq(&Controller->RequestQueue->queue_lock);
+		spin_lock_irq(Controller->RequestQueue->queue_lock);
 	      }
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = true;
@@ -5570,7 +5542,6 @@
 			     DataTransferBuffer, DataTransferLength))
 		ErrorCode = -EFAULT;
 		goto Failure1;
-	  }
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
diff -Nru a/drivers/block/DAC960.h b/drivers/block/DAC960.h
--- a/drivers/block/DAC960.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/block/DAC960.h	Tue Aug 27 12:28:08 2002
@@ -2195,7 +2195,6 @@
 typedef struct file File_T;
 typedef struct block_device_operations BlockDeviceOperations_T;
 typedef struct completion Completion_T;
-typedef struct gendisk GenericDiskInfo_T;
 typedef struct hd_geometry DiskGeometry_T;
 typedef struct hd_struct DiskPartition_T;
 typedef struct inode Inode_T;
@@ -2362,11 +2361,12 @@
   boolean MonitoringAlertMode;
   boolean SuppressEnclosureMessages;
   Timer_T MonitoringTimer;
-  GenericDiskInfo_T GenericDiskInfo;
+  struct gendisk disks[DAC960_MaxLogicalDrives];
   DAC960_Command_T *FreeCommands;
   unsigned char *CombinedStatusBuffer;
   unsigned char *CurrentStatusBuffer;
   RequestQueue_T *RequestQueue;
+  spinlock_t queue_lock;
   WaitQueue_T CommandWaitQueue;
   WaitQueue_T HealthStatusWaitQueue;
   DAC960_Command_T InitialCommand;
@@ -2506,7 +2506,7 @@
 void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
 				  ProcessorFlags_T *ProcessorFlags)
 {
-  spin_lock_irqsave(&Controller->RequestQueue->queue_lock, *ProcessorFlags);
+  spin_lock_irqsave(Controller->RequestQueue->queue_lock, *ProcessorFlags);
 }
 
 
@@ -2518,7 +2518,7 @@
 void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
 				  ProcessorFlags_T *ProcessorFlags)
 {
-  spin_unlock_irqrestore(&Controller->RequestQueue->queue_lock, *ProcessorFlags);
+  spin_unlock_irqrestore(Controller->RequestQueue->queue_lock, *ProcessorFlags);
 }
 
 
@@ -2555,7 +2555,7 @@
 void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
 				    ProcessorFlags_T *ProcessorFlags)
 {
-  spin_lock_irqsave(&Controller->RequestQueue->queue_lock, *ProcessorFlags);
+  spin_lock_irqsave(Controller->RequestQueue->queue_lock, *ProcessorFlags);
 }
 
 
@@ -2568,7 +2568,7 @@
 void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
 				    ProcessorFlags_T *ProcessorFlags)
 {
-  spin_unlock_irqrestore(&Controller->RequestQueue->queue_lock, *ProcessorFlags);
+  spin_unlock_irqrestore(Controller->RequestQueue->queue_lock, *ProcessorFlags);
 }
 
 #error I am a non-portable driver, please convert me to use the Documentation/DMA-mapping.txt interfaces
@@ -4229,13 +4229,5 @@
 			   DAC960_Controller_T *, ...);
 static void DAC960_CreateProcEntries(void);
 static void DAC960_DestroyProcEntries(void);
-
-
-/*
-  Export the Kernel Mode IOCTL interface.
-*/
-
-EXPORT_SYMBOL(DAC960_KernelIOCTL);
-
 
 #endif /* DAC960_DriverVersion */
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/block/acsi.c	Tue Aug 27 12:28:05 2002
@@ -244,9 +244,10 @@
 char 			*acsi_buffer;
 unsigned long 	phys_acsi_buffer;
 
-static int				NDevices = 0;
-static struct hd_struct	acsi_part[MAX_DEV<<4] = { {0,0}, };
-static int 				access_count[MAX_DEV] = { 0, };
+static int NDevices;
+static struct hd_struct	acsi_part[MAX_DEV<<4];
+static char acsi_names[MAX_DEV*4];
+static int access_count[MAX_DEV];
 
 static int				CurrentNReq;
 static int				CurrentNSect;
@@ -1345,14 +1346,8 @@
 
 extern struct block_device_operations acsi_fops;
 
-static struct gendisk acsi_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"ad",
-	minor_shift:	4,
-	part:		acsi_part,
-	fops:		&acsi_fops,
-};
-	
+static struct gendisk acsi_gendisk[MAX_DEV];
+
 #define MAX_SCSI_DEVICE_CODE 10
 
 static const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
@@ -1700,12 +1695,22 @@
 			NDevices, n_slm );
 #endif
 					 
-	for( i = 0; i < NDevices; ++i )
-		register_disk(&acsi_gendisk, mk_kdev(MAJOR_NR,i<<4),
-				(acsi_info[i].type==HARDDISK)?1<<4:1,
-				&acsi_fops,
+	for( i = 0; i < NDevices; ++i ) {
+		struct gendisk *disk = acsi_gendisk + i;
+		sprintf(acsi_names + 4*i, "ad%c", 'a'+i);
+		disk->major = MAJOR_NR;
+		disk->first_minor = i << 4;
+		disk->major_name = acsi_names + 4*i;
+		disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0;
+		disk->part = acsi_part + (i<<4);
+		disk->fops = &acsi_fops;
+		disk->nr_real = 1;
+		add_gendisk(disk);
+		register_disk(disk, mk_kdev(disk->major, disk->first_minor),
+				1<<disk->minor_shift,
+				disk->fops,
 				acsi_info[i].size);
-	acsi_gendisk.nr_real = NDevices;
+	}
 }
 
 #ifdef CONFIG_ATARI_SLM_MODULE
@@ -1744,8 +1749,6 @@
 	STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;
 	
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_acsi_request, &acsi_lock);
-	add_gendisk(&acsi_gendisk);
-
 #ifdef CONFIG_ATARI_SLM
 	err = slm_init();
 #endif
@@ -1771,6 +1774,7 @@
 
 void cleanup_module(void)
 {
+	int i;
 	del_timer( &acsi_timer );
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 	atari_stram_free( acsi_buffer );
@@ -1778,7 +1782,8 @@
 	if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
 		printk( KERN_ERR "acsi: cleanup_module failed\n");
 
-	del_gendisk(&acsi_gendisk);
+	for (i = 0; i < NDevices; i++)
+		del_gendisk(acsi_gendisk + i);
 }
 #endif
 
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/block/cciss.c	Tue Aug 27 12:28:08 2002
@@ -105,10 +105,9 @@
 		unsigned int cmd, unsigned long arg);
 
 static int revalidate_allvol(kdev_t dev);
-static int revalidate_logvol(kdev_t dev, int maxusage);
 static int cciss_revalidate(kdev_t dev);
 static int deregister_disk(int ctlr, int logvol);
-static int register_new_disk(kdev_t dev, int cltr);
+static int register_new_disk(int cltr);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -333,27 +332,6 @@
         }
 }
 
-/*  
- * fills in the disk information. 
- */
-static void cciss_geninit( int ctlr)
-{
-	drive_info_struct *drv;
-	int i;
-	
-	/* Loop through each real device */ 
-	hba[ctlr]->gendisk.nr_real = 0; 
-	for(i=0; i< NWD; i++)
-	{
-		drv = &(hba[ctlr]->drv[i]);
-		if( !(drv->nr_blocks))
-			continue;
-		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = drv->nr_blocks;
-		//hba[ctlr]->gendisk.nr_real++;
-		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
-	}
-	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
-}
 /*
  * Open.  Make sure the device is really there.
  */
@@ -599,7 +577,7 @@
 
 	case CCISS_REGNEWD:
 	{
-		return(register_new_disk(inode->i_rdev, ctlr));
+		return(register_new_disk(ctlr));
 	}	
 	case CCISS_PASSTHRU:
 	{
@@ -726,49 +704,11 @@
 {
         int ctlr = major(dev) - MAJOR_NR;
 	int target = minor(dev) >> NWD_SHIFT;
-        struct gendisk *gdev = &(hba[ctlr]->gendisk);
-	gdev->part[minor(dev)].nr_sects = hba[ctlr]->drv[target].nr_blocks;
+        struct gendisk *disk = &hba[ctlr]->gendisk[target];
+	disk->part[0].nr_sects = hba[ctlr]->drv[target].nr_blocks;
 	return 0;
 }
 
-/* Borrowed and adapted from sd.c */
-/*
- * FIXME: we are missing the exclusion with ->open() here - it can happen
- * just as we are rereading partition tables.
- */
-static int revalidate_logvol(kdev_t dev, int maxusage)
-{
-        int ctlr, target;
-        struct gendisk *gdev;
-        unsigned long flags;
-        int res;
-
-        target = minor(dev) >> NWD_SHIFT;
-        ctlr = major(dev) - MAJOR_NR;
-        gdev = &(hba[ctlr]->gendisk);
-
-        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-        if (hba[ctlr]->drv[target].usage_count > maxusage) {
-                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-                printk(KERN_WARNING "cciss: Device busy for "
-                        "revalidation (usage=%d)\n",
-                        hba[ctlr]->drv[target].usage_count);
-                return -EBUSY;
-        }
-        hba[ctlr]->drv[target].usage_count++;
-        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-
-	res = wipe_partitions(dev);
-	if (res)
-		goto leave;
-
-	/* setup partitions per disk */
-	grok_partitions(dev, hba[ctlr]->drv[target].nr_blocks);
-leave:
-        hba[ctlr]->drv[target].usage_count--;
-        return res;
-}
-
 /*
  * revalidate_allvol is for online array config utilities.  After a
  * utility reconfigures the drives in the array, it can use this function
@@ -799,6 +739,15 @@
         hba[ctlr]->usage_count++;
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
+	for(i=0; i< NWD; i++) {
+		struct gendisk *disk = &hba[ctlr]->gendisk[i];
+		if (disk->major_name) {
+			wipe_partitions(mk_kdev(disk->major, disk->first_minor));
+			del_gendisk(disk);
+			disk->major_name = NULL;
+		}
+	}
+
         /*
          * Set the partition and block size structures for all volumes
          * on this controller to zero.  We will reread all of this data
@@ -806,8 +755,6 @@
 	memset(hba[ctlr]->hd,         0, sizeof(struct hd_struct) * 256);
         memset(hba[ctlr]->drv,        0, sizeof(drive_info_struct)
 						* CISS_MAX_LUN);
-        hba[ctlr]->gendisk.nr_real = 0;
-
         /*
          * Tell the array controller not to give us any interrupts while
          * we check the new geometry.  Then turn interrupts back on when
@@ -817,13 +764,20 @@
         cciss_getgeometry(ctlr);
         hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON);
 
-        cciss_geninit(ctlr);
-        for(i=0; i<NWD; i++) {
-		kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT);
-                if (hba[ctlr]->gendisk.part[ i<<NWD_SHIFT ].nr_sects)
-                        revalidate_logvol(kdev, 2);
+	/* Loop through each real device */ 
+	for (i = 0; i < NWD; i++) {
+		struct gendisk *disk = &hba[ctlr]->gendisk[i];
+		drive_info_struct *drv = &(hba[ctlr]->drv[i]);
+		if (!drv->nr_blocks)
+			continue;
+		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
+		disk->major_name = hba[ctlr]->names + 12 * i;
+		add_gendisk(disk);
+		register_disk(disk,
+			      mk_kdev(disk->major, disk->first_minor),
+			      1<<disk->minor_shift, disk->fops,
+			      drv->nr_blocks);
 	}
-
         hba[ctlr]->usage_count--;
         return 0;
 }
@@ -831,18 +785,15 @@
 static int deregister_disk(int ctlr, int logvol)
 {
 	unsigned long flags;
-	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	struct gendisk *disk = &hba[ctlr]->gendisk[logvol];
 	ctlr_info_t  *h = hba[ctlr];
-	int start, max_p;
-
 
 	if (!capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
 	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 	/* make sure logical volume is NOT is use */
-	if( h->drv[logvol].usage_count > 1)
-	{
+	if( h->drv[logvol].usage_count > 1) {
 		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
                 return -EBUSY;
 	}
@@ -850,25 +801,24 @@
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
 	/* invalidate the devices and deregister the disk */ 
-	max_p = 1 << gdev->minor_shift;
-	start = logvol << gdev->minor_shift;
-	wipe_partitions(mk_kdev(MAJOR_NR+ctlr, start));
+	if (disk->major_name) {
+		wipe_partitions(mk_kdev(disk->major, disk->first_minor));
+		del_gendisk(disk);
+		disk->major_name = NULL;
+	}
 	/* check to see if it was the last disk */
-	if (logvol == h->highest_lun)
-	{
+	if (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
 		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++)
-		{
+		for(i=0; i<h->highest_lun; i++) {
 			/* if the disk has size > 0, it is available */
-			if (h->gendisk.part[i << gdev->minor_shift].nr_sects)
+			if (h->drv[i].nr_blocks)
 				newhighest = i;
 		}
 		h->highest_lun = newhighest;
 				
 	}
 	--h->num_luns;
-	gdev->nr_real = h->highest_lun+1; 
 	/* zero out the disk size info */ 
 	h->drv[logvol].nr_blocks = 0;
 	h->drv[logvol].block_size = 0;
@@ -1065,11 +1015,11 @@
         return(return_status);
 
 }
-static int register_new_disk(kdev_t dev, int ctlr)
+static int register_new_disk(int ctlr)
 {
-        struct gendisk *gdev = &(hba[ctlr]->gendisk);
+        struct gendisk *disk;
         ctlr_info_t  *h = hba[ctlr];
-        int start, max_p, i;
+        int i;
 	int num_luns;
 	int logvol;
 	int new_lun_found = 0;
@@ -1084,7 +1034,6 @@
 	__u32 lunid = 0;
 	unsigned int block_size;
 	unsigned int total_size;
-	kdev_t kdev;
 
         if (!capable(CAP_SYS_RAWIO))
                 return -EPERM;
@@ -1292,15 +1241,16 @@
 			hba[ctlr]->drv[logvol].sectors,
 			hba[ctlr]->drv[logvol].cylinders);
 	hba[ctlr]->drv[logvol].usage_count = 0;
-	max_p = 1 << gdev->minor_shift;
-        start = logvol<< gdev->minor_shift;
-	kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift);
-
-	wipe_partitions(kdev);
 	++hba[ctlr]->num_luns;
-	gdev->nr_real = hba[ctlr]->highest_lun + 1;
 	/* setup partitions per disk */
-	grok_partitions(kdev, hba[ctlr]->drv[logvol].nr_blocks);
+        disk = &hba[ctlr]->gendisk[logvol];
+	disk->major_name = hba[ctlr]->names + 12 * logvol;
+	add_gendisk(disk);
+	register_disk(disk,
+		      mk_kdev(disk->major, disk->first_minor),
+		      1<<disk->minor_shift,
+		      disk->fops,
+		      hba[ctlr]->drv[logvol].nr_blocks);
 	
 	kfree(ld_buff);
 	kfree(size_buff);
@@ -2488,22 +2438,28 @@
 
 	blk_queue_max_sectors(q, 512);
 
-	/* Fill in the gendisk data */ 	
-	hba[i]->gendisk.major = MAJOR_NR + i;
-	hba[i]->gendisk.major_name = "cciss";
-	hba[i]->gendisk.minor_shift = NWD_SHIFT;
-	hba[i]->gendisk.part = hba[i]->hd;
-	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;  
-
-	/* Get on the disk list */ 
-	add_gendisk(&(hba[i]->gendisk));
-
-	cciss_geninit(i);
-	for(j=0; j<NWD; j++)
-		register_disk(&(hba[i]->gendisk),
-			mk_kdev(MAJOR_NR+i, j <<4), 
-			MAX_PART, &cciss_fops, 
-			hba[i]->drv[j].nr_blocks);
+
+	for(j=0; j<NWD; j++) {
+		drive_info_struct *drv = &(hba[i]->drv[j]);
+		struct gendisk *disk = hba[i]->gendisk + j;
+
+		sprintf(hba[i]->names + 12 * j, "cciss/c%dd%d", i, j);
+		disk->major = MAJOR_NR + i;
+		disk->first_minor = j << NWD_SHIFT;
+		disk->major_name = NULL;
+		disk->minor_shift = NWD_SHIFT;
+		disk->part = hba[i]->hd + (j << NWD_SHIFT);
+		disk->nr_real = 1;
+		if( !(drv->nr_blocks))
+			continue;
+		(BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size;
+		disk->major_name = hba[i]->names + 12 * j;
+		add_gendisk(disk);
+		register_disk(disk,
+			      mk_kdev(disk->major, disk->first_minor),
+			      1<<disk->minor_shift, disk->fops,
+			      drv->nr_blocks);
+	}
 
 	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
 
@@ -2513,7 +2469,7 @@
 static void __devexit cciss_remove_one (struct pci_dev *pdev)
 {
 	ctlr_info_t *tmp_ptr;
-	int i;
+	int i, j;
 	char flush_buf[4];
 	int return_code; 
 
@@ -2548,7 +2504,13 @@
 	remove_proc_entry(hba[i]->devname, proc_cciss);	
 	
 	/* remove it from the disk list */
-	del_gendisk(&(hba[i]->gendisk));
+	for (j = 0; j < NWD; j++) {
+		struct gendisk *disk = &hba[i]->gendisk[j];
+		if (disk->major_name) {
+			del_gendisk(disk);
+			disk->major_name = NULL;
+		}
+	}
 
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
 			    hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Tue Aug 27 12:27:42 2002
+++ b/drivers/block/cciss.h	Tue Aug 27 12:27:42 2002
@@ -81,7 +81,8 @@
 	int			nr_frees; 
 
 	// Disk structures we need to pass back
-	struct gendisk   gendisk;
+	struct gendisk   gendisk[NWD];
+	char names[12 * NWD];
 	   // indexed by minor numbers
 	struct hd_struct hd[256];
 	int		 sizes[256];
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/block/cpqarray.c	Tue Aug 27 12:28:01 2002
@@ -1483,6 +1483,7 @@
 		if (!drv->nr_blks)
 			continue;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->blk_size;
+		disk->major_name = ida_names + (ctlr*NWD+i)*10;
 		add_gendisk(disk);
 		register_disk(disk,
 			      mk_kdev(disk->major,disk->first_minor),
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Tue Aug 27 12:27:51 2002
+++ b/drivers/block/loop.c	Tue Aug 27 12:27:51 2002
@@ -74,6 +74,7 @@
 #include <linux/slab.h>
 #include <linux/loop.h>
 #include <linux/suspend.h>
+#include <linux/writeback.h>
 #include <linux/buffer_head.h>		/* for invalidate_bdev() */
 
 #include <asm/uaccess.h>
@@ -235,6 +236,7 @@
 	up(&mapping->host->i_sem);
 out:
 	kunmap(bvec->bv_page);
+	balance_dirty_pages(mapping);
 	return ret;
 
 unlock:
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/block/ps2esdi.c	Tue Aug 27 12:27:42 2002
@@ -157,7 +157,7 @@
 	nr_real:	1
 },{
 	major:		MAJOR_NR,
-	first_minor:	64
+	first_minor:	64,
 	major_name:	"edb",
 	minor_shift:	6,
 	part:		ps2esdi+64,
@@ -491,7 +491,6 @@
 	u_int block, count;
 	/* since, this routine is called with interrupts cleared - they 
 	   must be before it finishes  */
-	sti();
 
 #if 0
 	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
@@ -604,13 +603,16 @@
 	     CURRENT->current_nr_sectors, drive);
 
 	/* send the command block to the controller */
+	spin_unlock_irq(&ps2esdi_lock);
 	if (ps2esdi_out_cmd_blk(cmd_blk)) {
+		spin_lock_irq(&ps2esdi_lock);
 		printk("%s: Controller failed\n", DEVICE_NAME);
 		if ((++CURRENT->errors) >= MAX_RETRIES)
 			end_request(CURRENT, FAIL);
 	}
 	/* check for failure to put out the command block */ 
 	else {
+		spin_lock_irq(&ps2esdi_lock);
 #if 0
 		printk("%s: waiting for xfer\n", DEVICE_NAME);
 #endif
@@ -1099,7 +1101,7 @@
 	put_user(ps2esdi_info[dev].head, (char *) &geometry->heads);
 	put_user(ps2esdi_info[dev].sect, (char *) &geometry->sectors);
 	put_user(ps2esdi_info[dev].cyl, (short *) &geometry->cylinders);
-	put_user(get_start_sect(inode->b_rdev), (long *) &geometry->start);
+	put_user(get_start_sect(inode->i_bdev), (long *) &geometry->start);
 	return 0;
 }
 
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/block/umem.c	Tue Aug 27 12:28:08 2002
@@ -164,14 +164,8 @@
 
 static int num_cards = 0;
 
-struct gendisk mm_gendisk = {
-    major:         0,			/* Major number assigned later */
-    major_name:    "umem",		/* Name of the major device */
-    minor_shift:   MM_SHIFT,		/* Shift to get device number */
-    fops:          &mm_fops,   		/* Block dev operations */
-/* everything else is dynamic */
-};
-
+static struct gendisk mm_gendisk[MM_MAXCARDS];
+static char mm_names[MM_MAXCARDS * 6];
 
 static void check_batteries(struct cardinfo *card);
 
@@ -818,7 +812,7 @@
 static int mm_revalidate(kdev_t i_rdev)
 {
 	int card_number = DEVICE_NR(i_rdev);
-	mm_partitions[minor(i_rdev)] = cards[card_number].mm_size << 1;
+	mm_partitions[minor(i_rdev)].nr_sects = cards[card_number].mm_size << 1;
 	return 0;
 }
 /*
@@ -828,7 +822,7 @@
 */
 static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
 {
-	if (cmd == case HDIO_GETGEO) {
+	if (cmd == HDIO_GETGEO) {
 		unsigned int minor = minor(i->i_rdev);
 		int err, size, card_number = (minor >> MM_SHIFT);
 		struct hd_geometry geo;
@@ -1182,10 +1176,6 @@
 
 	printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
 
-	memset (cards,    0, MM_MAXCARDS * sizeof(struct cardinfo));
-	memset (mm_partitions, 0,
-		(MM_MAXCARDS << MM_SHIFT) * sizeof(struct hd_struct));
-
 	retval = pci_module_init(&mm_pci_driver);
 	if (retval)
 		return -ENOMEM;
@@ -1197,23 +1187,23 @@
 	}
 	devfs_handle = devfs_mk_dir(NULL, "umem", NULL);
 
-
-	/* Initialize partition size: partion 0 of each card is the entire card */
+	blk_dev[MAJOR_NR].queue = mm_queue_proc;
 	for (i = 0; i < num_cards; i++) {
+		struct gendisk *disk = mm_gendisk + i;
+		sprintf(mm_names + i*6, "umem%c", 'a'+i);
 		spin_lock_init(&cards[i].lock);
-		mm_partitions[i << MM_SHIFT].nr_sects =
-			cards[i].mm_size * (1024 / MM_HARDSECT);
-	}
-
-	mm_gendisk.part      = mm_partitions;
-	mm_gendisk.nr_real   = num_cards;
-
-	blk_dev[MAJOR_NR].queue = mm_queue_proc;
-	add_gendisk(&mm_gendisk);
-
-        for (i = 0; i < num_cards; i++) {
-		register_disk(&mm_gendisk, mk_kdev(MAJOR_NR, i<<MM_SHIFT), MM_SHIFT,
-			      &mm_fops, cards[i].mm_size << 1);
+		disk->part  = mm_partitions + (i << MM_SHIFT);
+		disk->nr_real = 1;
+		disk->major = major_nr;
+		disk->first_minor  = i << MM_SHIFT;
+		disk->major_name = mm_names + i*6;
+		disk->minor_shift = MM_SHIFT;
+		disk->fops = &mm_fops;
+		add_gendisk(disk);
+		register_disk(disk, mk_kdev(disk->major, disk->first_minor),
+			      1<<disk->minor_shift,
+			      disk->fops,
+			      cards[i].mm_size << 1);
 	}
 
 	init_battery_timer();
@@ -1232,8 +1222,10 @@
 
 	del_battery_timer();
 
-	for (i=0; i < num_cards ; i++)
-		devfs_register_partitions(&mm_gendisk, i<<MM_SHIFT, 1);
+	for (i=0; i < num_cards ; i++) {
+		devfs_register_partitions(mm_gendisk + i, i<<MM_SHIFT, 1);
+		del_gendisk(mm_gendisk + i);
+	}
 	if (devfs_handle)
 		devfs_unregister(devfs_handle);
 	devfs_handle = NULL;
@@ -1241,11 +1233,6 @@
 	pci_unregister_driver(&mm_pci_driver);
 
 	unregister_blkdev(MAJOR_NR, "umem");
-
-	/*
-	 * Get our gendisk structure off the list.
-	 */
-	del_gendisk(&mm_gendisk);
 }
 
 module_init(mm_init);
diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/block/xd.c	Tue Aug 27 12:28:02 2002
@@ -127,12 +127,24 @@
 
 extern struct block_device_operations xd_fops;
 
-static struct gendisk xd_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"xd",
-	minor_shift:	6,
-	part:		xd_struct,
-	fops:		&xd_fops,
+static struct gendisk xd_gendisk[2] = {
+{
+	.major =	MAJOR_NR,
+	.first_minor =	0,
+	.major_name =	"xda",
+	.minor_shift =	6,
+	.part =		xd_struct,
+	.fops =		&xd_fops,
+	.nr_real =	1
+},{
+	.major =	MAJOR_NR,
+	.first_minor =	64,
+	.major_name =	"xdb",
+	.minor_shift =	6,
+	.part =		xd_struct + 64,
+	.fops =		&xd_fops,
+	.nr_real =	1
+}
 };
 
 static struct block_device_operations xd_fops = {
@@ -147,9 +159,7 @@
 static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
 
 static volatile int xdc_busy;
-static DECLARE_WAIT_QUEUE_HEAD(xdc_wait);
-
-static struct timer_list xd_timer, xd_watchdog_int;
+static struct timer_list xd_watchdog_int;
 
 static volatile u_char xd_error;
 static int nodma = XD_DONT_USE_DMA;
@@ -159,51 +169,24 @@
 /* xd_init: register the block device number and set up pointer tables */
 int __init xd_init (void)
 {
-	init_timer (&xd_timer); xd_timer.function = xd_wakeup;
+	u_char i,controller;
+	unsigned int address;
+
 	init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
 
+	if (!xd_dma_buffer)
+		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+	if (!xd_dma_buffer) {
+		printk(KERN_ERR "xd: Out of memory.\n");
+		return -ENOMEM;
+	}
+
 	if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 		printk("xd: Unable to get major number %d\n",MAJOR_NR);
 		return -1;
 	}
 	devfs_handle = devfs_mk_dir (NULL, "xd", NULL);
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_xd_request, &xd_lock);
-	add_gendisk(&xd_gendisk);
-	xd_geninit();
-
-	return 0;
-}
-
-/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char __init xd_detect (u_char *controller, unsigned int *address)
-{
-	u_char i,j,found = 0;
-
-	if (xd_override)
-	{
-		*controller = xd_type;
-		*address = 0;
-		return(1);
-	}
-
-	for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
-		for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
-			if (isa_check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
-				*controller = j;
-				xd_type = j;
-				*address = xd_bases[i];
-				found++;
-			}
-	return (found);
-}
-
-/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
-/* and set up the "raw" device entries in the table */
-static void __init xd_geninit (void)
-{
-	u_char i,controller;
-	unsigned int address;
-
 	if (xd_detect(&controller,&address)) {
 
 		printk("Detected a%s controller (type %d) at address %06x\n",
@@ -211,7 +194,7 @@
 		if (!request_region(xd_iobase,4,"xd")) {
 			printk("xd: Ports at 0x%x are not available\n",
 				xd_iobase);
-			return;
+			return -EBUSY;
 		}
 		if (controller)
 			xd_sigs[controller].init_controller(address);
@@ -225,26 +208,58 @@
 				xd_info[i].sectors);
 
 	}
-	if (xd_drives) {
-		if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
-			if (request_dma(xd_dma,"xd")) {
-				printk("xd: unable to get DMA%d\n",xd_dma);
-				free_irq(xd_irq, NULL);
-			}
-		}
-		else
-			printk("xd: unable to get IRQ%d\n",xd_irq);
+
+	if (!xd_drives)
+		return -ENODEV;
+
+	if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
+		printk("xd: unable to get IRQ%d\n",xd_irq);
+		return -EBUSY;
+	}
+
+	if (request_dma(xd_dma,"xd")) {
+		printk("xd: unable to get DMA%d\n",xd_dma);
+		free_irq(xd_irq, NULL);
+		return -EBUSY;
 	}
 
 	/* xd_maxsectors depends on controller - so set after detection */
 	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), xd_maxsectors);
 
-	for (i = 0; i < xd_drives; i++)
-		register_disk(&xd_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6,
-				&xd_fops,
+	for (i = 0; i < xd_drives; i++) {
+		struct gendisk *disk = xd_gendisk + i;
+		add_gendisk(disk);
+		register_disk(disk, mk_kdev(disk->major,disk->first_minor),
+				1<<disk->minor_shift,
+				disk->fops,
 				xd_info[i].heads * xd_info[i].cylinders *
 				xd_info[i].sectors);
-	xd_gendisk.nr_real = xd_drives;
+	}
+
+	return 0;
+}
+
+/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
+static u_char __init xd_detect (u_char *controller, unsigned int *address)
+{
+	u_char i,j,found = 0;
+
+	if (xd_override)
+	{
+		*controller = xd_type;
+		*address = 0;
+		return(1);
+	}
+
+	for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
+		for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
+			if (isa_check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
+				*controller = j;
+				xd_type = j;
+				*address = xd_bases[i];
+				found++;
+			}
+	return (found);
 }
 
 /* xd_open: open a device */
@@ -262,9 +277,9 @@
 	u_int block,count,retry;
 	int code;
 
-	sti();
 	if (xdc_busy)
 		return;
+
 	while (1) {
 		code = 0;
 		/* do some checking on the request structure */
@@ -297,11 +312,7 @@
 /* xd_ioctl: handle device ioctl's */
 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
 {
-	int dev;
-
-	if ((!inode) || kdev_none(inode->i_rdev))
-		return -EINVAL;
- 	dev = DEVICE_NR(inode->i_rdev);
+	int dev = DEVICE_NR(inode->i_rdev);
 
 	if (dev >= xd_drives) return -EINVAL;
 	switch (cmd) {
@@ -309,7 +320,6 @@
 		{
 			struct hd_geometry g;
 			struct hd_geometry *geometry = (struct hd_geometry *) arg;
-			if (!geometry) return -EINVAL;
 			g.heads = xd_info[dev].heads;
 			g.sectors = xd_info[dev].sectors;
 			g.cylinders = xd_info[dev].cylinders;
@@ -324,6 +334,12 @@
 				xd_dma_mem_free((unsigned long)xd_dma_buffer,
 						xd_maxsectors * 0x200);
 				xd_dma_buffer = 0;
+			} else if (!nodma && !xd_dma_buffer) {
+				xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+				if (!xd_dma_buffer) {
+					nodma = XD_DONT_USE_DMA;
+					return -ENOMEM;
+				}
 			}
 			return 0;
 		case HDIO_GET_DMA:
@@ -348,6 +364,8 @@
 	printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 #endif /* DEBUG_READWRITE */
 
+	spin_unlock_irq(&xd_lock);
+
 	control = xd_info[drive].control;
 	if (!xd_dma_buffer)
 		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
@@ -378,6 +396,7 @@
 			case 1:
 				printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
 				xd_recalibrate(drive);
+				spin_lock_irq(&xd_lock);
 				return (0);
 			case 2:
 				if (sense[0] & 0x30) {
@@ -398,6 +417,7 @@
 				/*	reported drive number = (sense[1] & 0xE0) >> 5 */
 				else
 					printk(" - no valid disk address\n");
+				spin_lock_irq(&xd_lock);
 				return (0);
 		}
 		if (xd_dma_buffer)
@@ -406,6 +426,7 @@
 
 		count -= temp, buffer += temp * 0x200, block += temp;
 	}
+	spin_lock_irq(&xd_lock);
 	return (1);
 }
 
@@ -472,13 +493,6 @@
 	return (cmdblk);
 }
 
-/* xd_wakeup is called from timer interrupt */
-static void xd_wakeup (unsigned long unused)
-{
-	wake_up(&xdc_wait);
-}
-
-/* xd_wakeup is called from timer interrupt */
 static void xd_watchdog (unsigned long unused)
 {
 	xd_error = 1;
@@ -493,12 +507,8 @@
 
 	xdc_busy = 1;
 	while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) {
-		xd_timer.expires = jiffies;
-		cli();
-		add_timer(&xd_timer);
-		sleep_on(&xdc_wait);
-		del_timer(&xd_timer);
-		sti();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 	xdc_busy = 0;
 	return (success);
@@ -600,16 +610,14 @@
 	for (i = 0; i < XD_MAXDRIVES; i++) {
 		xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 		if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 
 			init_drive(count);
 			count++;
 
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 		}
 	}
 	return (count);
@@ -730,9 +738,8 @@
 
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
 static void __init xd_wd_init_drive (u_char drive)
@@ -906,9 +913,8 @@
 	xd_maxsectors = 0x01;
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
 static void __init xd_xebec_init_drive (u_char drive)
@@ -1034,8 +1040,10 @@
 
 static void xd_done (void)
 {
+	int i;
+	for (i = 0; i < xd_drives; i++)
+		del_gendisk(xd_gendisk + i);
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-	del_gendisk(&xd_gendisk);
 	blk_clear(MAJOR_NR);
 	release_region(xd_iobase,4);
 }
diff -Nru a/drivers/block/xd.h b/drivers/block/xd.h
--- a/drivers/block/xd.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/block/xd.h	Tue Aug 27 12:28:02 2002
@@ -108,7 +108,6 @@
 #endif /* MODULE */
 static u_char xd_detect (u_char *controller, unsigned int *address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
-static void xd_geninit (void);
 
 static int xd_open (struct inode *inode,struct file *file);
 static void do_xd_request (request_queue_t * q);
@@ -119,7 +118,6 @@
 static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
 static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
-static void xd_wakeup (unsigned long unused);
 static void xd_watchdog (unsigned long unused);
 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help
--- a/drivers/char/Config.help	Tue Aug 27 12:28:02 2002
+++ b/drivers/char/Config.help	Tue Aug 27 12:28:02 2002
@@ -633,25 +633,6 @@
   The module will be called busmouse.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_PSMOUSE
-  The PS/2 mouse connects to a special mouse port that looks much like
-  the keyboard port (small circular connector with 6 pins). This way,
-  the mouse does not use any serial ports. This port can also be used
-  for other input devices like light pens, tablets, keypads. Compaq,
-  AST and IBM all use this as their mouse port on currently shipping
-  machines. The trackballs of some laptops are PS/2 mice also. In
-  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
-
-  Although PS/2 mice are not technically bus mice, they are explained
-  in detail in the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  When using a PS/2 mouse, you can get problems if you want to use the
-  mouse both on the Linux console and under X. Using the "-R" option
-  of the Linux mouse managing program gpm (available from
-  <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
-  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
-
 CONFIG_QIC02_TAPE
   If you have a non-SCSI tape drive like that, say Y. Or, if you want
   to compile this driver as a module ( = code which can be inserted in
@@ -968,6 +949,31 @@
   inserted in and removed from the running kernel whenever you want).
   The module is called rtc.o. If you want to compile it as a module,
   say M here and read <file:Documentation/modules.txt>.
+
+Generic Real Time Clock Support
+CONFIG_GEN_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  It reports status information via the file /proc/driver/rtc and its
+  behaviour is set by various ioctls on /dev/rtc. If you enable the
+  "extended RTC operation" below it will also provide an emulation
+  for RTC_UIE which is required by some programs and may improve
+  precision in some cases.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called genrtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>. To load the
+  module automaticaly add 'alias char-major-10-135 genrtc' to your
+  /etc/modules.conf
+
+Extended RTC operation
+CONFIG_GEN_RTC_X
+  Provides an emulation for RTC_UIE which is required by some programs
+  and may improve precision of the generic RTC support in some cases.
 
 CONFIG_H8
   The Hitachi H8/337 is a microcontroller used to deal with the power
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Tue Aug 27 12:28:01 2002
+++ b/drivers/char/Config.in	Tue Aug 27 12:28:01 2002
@@ -8,6 +8,9 @@
 if [ "$CONFIG_VT" = "y" ]; then
    bool '  Support for console on virtual terminal' CONFIG_VT_CONSOLE
 fi
+if [ "$CONFIG_VT" = "y" -a "$CONFIG_S390" != "y" -a "$CONFIG_UM" != "y" ]; then
+   define_bool CONFIG_HW_CONSOLE y
+fi
 bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
 if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
    tristate '  Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
@@ -57,8 +60,6 @@
    bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
    if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then
      define_bool CONFIG_IT8172_CIR y
-   else
-     bool '    Enable PS2 Keyboard Support' CONFIG_PC_KEYB
    fi
    bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0
    bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1
@@ -89,7 +90,6 @@
 mainmenu_option next_comment
 comment 'Mice'
    tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
-   bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
 endmenu
 
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
@@ -151,6 +151,12 @@
 fi
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
+if [ "$CONFIG_RTC" != "y" ]; then
+   tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC      
+   if [ "$CONFIG_GEN_RTC" != "n" ]; then
+      bool '   Extended RTC operation' CONFIG_GEN_RTC_X
+   fi
+fi
 if [ "$CONFIG_IA64" = "y" ]; then
    bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
 fi
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Tue Aug 27 12:28:08 2002
+++ b/drivers/char/Makefile	Tue Aug 27 12:28:08 2002
@@ -17,116 +17,8 @@
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \
 			ip2main.o
 
-KEYMAP   =defkeymap.o
-KEYBD    =pc_keyb.o
-CONSOLE  =console.o
-
-ifeq ($(ARCH),s390)
-  KEYMAP   =
-  KEYBD    =
-  CONSOLE  =
-endif
-
-ifeq ($(ARCH),mips)
-  ifneq ($(CONFIG_PC_KEYB),y)
-    KEYBD    =
-  endif
-endif
-
-ifeq ($(ARCH),s390x)
-  KEYMAP   =
-  KEYBD    =
-  CONSOLE  =
-endif
-
-ifeq ($(ARCH),m68k)
-   ifdef CONFIG_AMIGA
-      KEYBD = amikeyb.o
-   else
-      KEYBD =
-   endif
-endif
-
-ifdef CONFIG_Q40
-  KEYBD += q40_keyb.o
-  SERIAL = serial.o
-endif
-
-ifdef CONFIG_APOLLO
-  KEYBD += dn_keyb.o
-endif
-
-ifeq ($(ARCH),arm)
-  ifneq ($(CONFIG_PC_KEYMAP),y)
-    KEYMAP   =
-  endif
-  ifneq ($(CONFIG_PC_KEYB),y)
-    KEYBD    =
-  endif
-endif
-
-ifeq ($(ARCH),um)
-  KEYMAP   =
-  KEYBD    =
-  CONSOLE  =
-endif
-
-ifeq ($(ARCH),sh)
-  KEYMAP   =
-  KEYBD    =
-  CONSOLE  =
-  ifeq ($(CONFIG_SH_HP600),y)
-  KEYMAP   = defkeymap.o
-  KEYBD    = scan_keyb.o hp600_keyb.o
-  CONSOLE  = console.o
-  endif
-  ifeq ($(CONFIG_SH_DMIDA),y)
-  # DMIDA does not connect the HD64465 PS/2 keyboard port
-  # but we allow for USB keyboards to be plugged in.
-  KEYMAP   = defkeymap.o
-  KEYBD    = # hd64465_keyb.o pc_keyb.o
-  CONSOLE  = console.o
-  endif
-  ifeq ($(CONFIG_SH_EC3104),y)
-  KEYMAP   = defkeymap.o
-  KEYBD    = ec3104_keyb.o
-  CONSOLE  = console.o
-  endif
-  ifeq ($(CONFIG_SH_DREAMCAST),y)
-  KEYMAP   = defkeymap.o
-  KEYBD    =
-  CONSOLE  = console.o
-  endif
-endif
-
-ifeq ($(CONFIG_DECSTATION),y)
-  KEYMAP   =
-  KEYBD    =
-  SERIAL   = decserial.o
-endif
-
-ifeq ($(CONFIG_BAGET_MIPS),y)
-  KEYBD    =
-endif
-
-ifeq ($(CONFIG_QTRONIX_KEYBOARD),y)
-  KEYBD    = qtronix.o
-  KEYMAP   = qtronixmap.o
-endif
-
-ifeq ($(CONFIG_SPARC32),y)
-  KEYBD    =
-endif
-
-ifeq ($(CONFIG_SPARC64),y)
-  KEYBD    =
-endif
-
-obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
-#obj-$(CONFIG_SERIAL) += $(SERIAL) # Fix for decserial.o
-
-obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD)
-
+obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o
+obj-$(CONFIG_HW_CONSOLE) += console.o defkeymap.o
 obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
 obj-$(CONFIG_ROCKETPORT) += rocket.o
@@ -167,6 +59,7 @@
 obj-$(CONFIG_SONYPI) += sonypi.o
 obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
 obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
@@ -208,12 +101,10 @@
 obj-$(CONFIG_DRM) += drm/
 obj-$(CONFIG_PCMCIA) += pcmcia/
 
-host-progs := conmakehash
-
 include $(TOPDIR)/Rules.make
 
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(obj)/conmakehash
-	$(obj)/conmakehash $< > $@
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+	$(call do_cmd,CONMK  $(echo_target),$(objtree)/scripts/conmakehash $< > $@)
 
 $(obj)/defkeymap.o:  $(obj)/defkeymap.c
 
diff -Nru a/drivers/char/conmakehash.c b/drivers/char/conmakehash.c
--- a/drivers/char/conmakehash.c	Tue Aug 27 12:27:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,293 +0,0 @@
-/*
- * conmakehash.c
- *
- * Create arrays for initializing the kernel folded tables (using a hash
- * table turned out to be to limiting...)  Unfortunately we can't simply
- * preinitialize the tables at compile time since kfree() cannot accept
- * memory not allocated by kmalloc(), and doing our own memory management
- * just for this seems like massive overkill.
- *
- * Copyright (C) 1995-1997 H. Peter Anvin
- *
- * This program is a part of the Linux kernel, and may be freely
- * copied under the terms of the GNU General Public License (GPL),
- * version 2, or at your option any later version.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <string.h>
-#include <ctype.h>
-
-#define MAX_FONTLEN 256
-
-typedef unsigned short unicode;
-
-void usage(char *argv0)
-{
-  fprintf(stderr, "Usage: \n"
-         "        %s chartable [hashsize] [hashstep] [maxhashlevel]\n", argv0);
-  exit(EX_USAGE);
-}
-
-int getunicode(char **p0)
-{
-  char *p = *p0;
-
-  while (*p == ' ' || *p == '\t')
-    p++;
-  if (*p != 'U' || p[1] != '+' ||
-      !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
-      !isxdigit(p[5]) || isxdigit(p[6]))
-    return -1;
-  *p0 = p+6;
-  return strtol(p+2,0,16);
-}
-
-unicode unitable[MAX_FONTLEN][255];
-				/* Massive overkill, but who cares? */
-int unicount[MAX_FONTLEN];
-
-void addpair(int fp, int un)
-{
-  int i;
-
-  if ( un <= 0xfffe )
-    {
-      /* Check it isn't a duplicate */
-
-      for ( i = 0 ; i < unicount[fp] ; i++ )
-	if ( unitable[fp][i] == un )
-	  return;
-
-      /* Add to list */
-
-      if ( unicount[fp] > 254 )
-	{
-	  fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
-	  exit(EX_DATAERR);
-	}
-
-      unitable[fp][unicount[fp]] = un;
-      unicount[fp]++;
-    }
-
-  /* otherwise: ignore */
-}
-
-int main(int argc, char *argv[])
-{
-  FILE *ctbl;
-  char *tblname;
-  char buffer[65536];
-  int fontlen;
-  int i, nuni, nent;
-  int fp0, fp1, un0, un1;
-  char *p, *p1;
-
-  if ( argc < 2 || argc > 5 )
-    usage(argv[0]);
-
-  if ( !strcmp(argv[1],"-") )
-    {
-      ctbl = stdin;
-      tblname = "stdin";
-    }
-  else
-    {
-      ctbl = fopen(tblname = argv[1], "r");
-      if ( !ctbl )
-	{
-	  perror(tblname);
-	  exit(EX_NOINPUT);
-	}
-    }
-
-  /* For now we assume the default font is always 256 characters. */    
-  fontlen = 256;
-
-  /* Initialize table */
-
-  for ( i = 0 ; i < fontlen ; i++ )
-    unicount[i] = 0;
-
-  /* Now we come to the tricky part.  Parse the input table. */
-
-  while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
-    {
-      if ( (p = strchr(buffer, '\n')) != NULL )
-	*p = '\0';
-      else
-	fprintf(stderr, "%s: Warning: line too long\n", tblname);
-
-      p = buffer;
-
-/*
- * Syntax accepted:
- *	<fontpos>	<unicode> <unicode> ...
- *	<range>		idem
- *	<range>		<unicode range>
- *
- * where <range> ::= <fontpos>-<fontpos>
- * and <unicode> ::= U+<h><h><h><h>
- * and <h> ::= <hexadecimal digit>
- */
-
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (!*p || *p == '#')
-	continue;	/* skip comment or blank line */
-
-      fp0 = strtol(p, &p1, 0);
-      if (p1 == p)
-	{
-	  fprintf(stderr, "Bad input line: %s\n", buffer);
-	  exit(EX_DATAERR);
-        }
-      p = p1;
-
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (*p == '-')
-	{
-	  p++;
-	  fp1 = strtol(p, &p1, 0);
-	  if (p1 == p)
-	    {
-	      fprintf(stderr, "Bad input line: %s\n", buffer);
-	      exit(EX_DATAERR);
-	    }
-	  p = p1;
-        }
-      else
-	fp1 = 0;
-
-      if ( fp0 < 0 || fp0 >= fontlen )
-	{
-	    fprintf(stderr,
-		    "%s: Glyph number (0x%x) larger than font length\n",
-		    tblname, fp0);
-	    exit(EX_DATAERR);
-	}
-      if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
-	{
-	    fprintf(stderr,
-		    "%s: Bad end of range (0x%x)\n",
-		    tblname, fp1);
-	    exit(EX_DATAERR);
-	}
-
-      if (fp1)
-	{
-	  /* we have a range; expect the word "idem" or a Unicode range of the
-	     same length */
-	  while (*p == ' ' || *p == '\t')
-	    p++;
-	  if (!strncmp(p, "idem", 4))
-	    {
-	      for (i=fp0; i<=fp1; i++)
-		addpair(i,i);
-	      p += 4;
-	    }
-	  else
-	    {
-	      un0 = getunicode(&p);
-	      while (*p == ' ' || *p == '\t')
-		p++;
-	      if (*p != '-')
-		{
-		  fprintf(stderr,
-"%s: Corresponding to a range of font positions, there should be a Unicode range\n",
-			  tblname);
-		  exit(EX_DATAERR);
-	        }
-	      p++;
-	      un1 = getunicode(&p);
-	      if (un0 < 0 || un1 < 0)
-		{
-		  fprintf(stderr,
-"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
-			  tblname, fp0, fp1);
-		  exit(EX_DATAERR);
-	        }
-	      if (un1 - un0 != fp1 - fp0)
-		{
-		  fprintf(stderr,
-"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n",
-			  tblname, un0, un1, fp0, fp1);
-		  exit(EX_DATAERR);
-	        }
-	      for(i=fp0; i<=fp1; i++)
-		addpair(i,un0-fp0+i);
-	    }
-        }
-      else
-	{
-	    /* no range; expect a list of unicode values for a single font position */
-
-	    while ( (un0 = getunicode(&p)) >= 0 )
-	      addpair(fp0, un0);
-	}
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (*p && *p != '#')
-	fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
-    }
-
-  /* Okay, we hit EOF, now output hash table */
-  
-  fclose(ctbl);
-  
-
-  /* Compute total size of Unicode list */
-  nuni = 0;
-  for ( i = 0 ; i < fontlen ; i++ )
-    nuni += unicount[i];
-  
-  printf("\
-/*\n\
- * Do not edit this file; it was automatically generated by\n\
- *\n\
- * conmakehash %s > [this file]\n\
- *\n\
- */\n\
-\n\
-#include <linux/types.h>\n\
-\n\
-u8 dfont_unicount[%d] = \n\
-{\n\t", argv[1], fontlen);
-
-  for ( i = 0 ; i < fontlen ; i++ )
-    {
-      printf("%3d", unicount[i]);
-      if ( i == fontlen-1 )
-        printf("\n};\n");
-      else if ( i % 8 == 7 )
-        printf(",\n\t");
-      else
-        printf(", ");
-    }
-  
-  printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni);
-  
-  fp0 = 0;
-  nent = 0;
-  for ( i = 0 ; i < nuni ; i++ )
-    {
-      while ( nent >= unicount[fp0] )
-	{
-	  fp0++;
-	  nent = 0;
-	}
-      printf("0x%04x", unitable[fp0][nent++]);
-      if ( i == nuni-1 )
-         printf("\n};\n");
-       else if ( i % 8 == 7 )
-         printf(",\n\t");
-       else
-         printf(", ");
-    }
-
-  exit(EX_OK);
-}
diff -Nru a/drivers/char/console.c b/drivers/char/console.c
--- a/drivers/char/console.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/char/console.c	Tue Aug 27 12:28:08 2002
@@ -128,10 +128,6 @@
 extern void vcs_make_devfs (unsigned int index, int unregister);
 extern void console_map_init(void);
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 static struct tty_struct *console_table[MAX_NR_CONSOLES];
 static struct termios *console_termios[MAX_NR_CONSOLES];
 static struct termios *console_termios_locked[MAX_NR_CONSOLES];
@@ -748,7 +744,7 @@
 		video_size_row = sr;
 		screenbuf_size = ss;
 
-		rlth = MIN(osr, sr);
+		rlth = min(osr, sr);
 		rrem = sr - rlth;
 		ol = origin;
 		nl = (long) newscreens[currcons];
@@ -2395,10 +2391,15 @@
 
 static void con_close(struct tty_struct *tty, struct file * filp)
 {
+	struct vt_struct *vt;
+	
 	if (!tty)
 		return;
 	if (tty->count != 1) return;
 	vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1);
+	vt = (struct vt_struct*)tty->driver_data;
+	if (vt)
+		vc_cons[vt->vc_num].d->vc_tty = NULL;
 	tty->driver_data = 0;
 }
 
@@ -3023,9 +3024,7 @@
 EXPORT_SYMBOL(vc_resize);
 EXPORT_SYMBOL(fg_console);
 EXPORT_SYMBOL(console_blank_hook);
-#ifdef CONFIG_VT
 EXPORT_SYMBOL(vt_cons);
-#endif
 #ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
 EXPORT_SYMBOL(give_up_console);
diff -Nru a/drivers/char/genrtc.c b/drivers/char/genrtc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/genrtc.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,518 @@
+/*
+ *	Real Time Clock interface for q40 and other m68k machines
+ *      emulate some RTC irq capabilities in software
+ *
+ *      Copyright (C) 1999 Richard Zidlicky
+ *
+ *	based on Paul Gortmaker's rtc.c device and
+ *           Sam Creasey Generic rtc driver
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/dev/rtc
+ *	pseudo-file for status information.
+ *
+ *	The ioctls can be used to set the interrupt behaviour where
+ *  supported.
+ *
+ *	The /dev/rtc interface will block on reads until an interrupt
+ *	has been received. If a RTC interrupt has already happened,
+ *	it will output an unsigned long and then block. The output value
+ *	contains the interrupt status in the low byte and the number of
+ *	interrupts since the last read in the remaining high bytes. The
+ *	/dev/rtc interface can also be used with the select(2) call.
+ *
+ *	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.
+ *
+
+ *      1.01 fix for 2.3.X                    rz@linux-m68k.org
+ *      1.02 merged with code from genrtc.c   rz@linux-m68k.org
+ *      1.03 make it more portable            zippel@linux-m68k.org
+ *      1.04 removed useless timer code       rz@linux-m68k.org
+ *      1.05 portable RTC_UIE emulation       rz@linux-m68k.org
+ *      1.06 set_rtc_time can return an error trini@kernel.crashing.org
+ */
+
+#define RTC_VERSION	"1.06"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/rtc.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
+
+static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg);
+
+/*
+ *	Bits in gen_rtc_status.
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+
+unsigned char gen_rtc_status;		/* bitmapped status byte.	*/
+unsigned long gen_rtc_irq_data;		/* our output to the world	*/
+
+/* months start at 0 now */
+unsigned char days_in_mo[] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int irq_active;
+
+#ifdef CONFIG_GEN_RTC_X
+struct tq_struct genrtc_task;
+static struct timer_list timer_task;
+
+static unsigned int oldsecs;
+static int lostint;
+static int tt_exp;
+
+void gen_rtc_timer(unsigned long data);
+
+static volatile int stask_active;              /* schedule_task */
+static volatile int ttask_active;              /* timer_task */
+static int stop_rtc_timers;                    /* don't requeue tasks */
+static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Routine to poll RTC seconds field for change as often as posible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+void genrtc_troutine(void *data)
+{
+	unsigned int tmp = get_rtc_ss();
+	
+	if (stop_rtc_timers) {
+		stask_active = 0;
+		return;
+	}
+
+	if (oldsecs != tmp){
+		oldsecs = tmp;
+
+		timer_task.function = gen_rtc_timer;
+		timer_task.expires = jiffies + HZ - (HZ/10);
+		tt_exp=timer_task.expires;
+		ttask_active=1;
+		stask_active=0;
+		add_timer(&timer_task);
+
+		gen_rtc_interrupt(0);
+	} else if (schedule_task(&genrtc_task) == 0)
+		stask_active = 0;
+}
+
+void gen_rtc_timer(unsigned long data)
+{
+	lostint = get_rtc_ss() - oldsecs ;
+	if (lostint<0) 
+		lostint = 60 - lostint;
+	if (time_after(jiffies, tt_exp))
+		printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n",
+		       jiffies-tt_exp);
+	ttask_active=0;
+	stask_active=1;
+	if ((schedule_task(&genrtc_task) == 0))
+		stask_active = 0;
+}
+
+/* 
+ * call gen_rtc_interrupt function to signal an RTC_UIE,
+ * arg is unused.
+ * Could be invoked either from a real interrupt handler or
+ * from some routine that periodically (eg 100HZ) monitors
+ * whether RTC_SECS changed
+ */
+void gen_rtc_interrupt(unsigned long arg)
+{
+	/*  We store the status in the low byte and the number of
+	 *	interrupts received since the last read in the remainder
+	 *	of rtc_irq_data.  */
+
+	gen_rtc_irq_data += 0x100;
+	gen_rtc_irq_data &= ~0xff;
+	gen_rtc_irq_data |= RTC_UIE;
+
+	if (lostint){
+		printk("genrtc: system delaying clock ticks?\n");
+		/* increment count so that userspace knows something is wrong */
+		gen_rtc_irq_data += ((lostint-1)<<8);
+		lostint = 0;
+	}
+
+	wake_up_interruptible(&gen_rtc_wait);
+}
+
+/*
+ *	Now all the various file operations that we export.
+ */
+static ssize_t gen_rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+
+        if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
+		return -EAGAIN;
+
+	add_wait_queue(&gen_rtc_wait, &wait);
+	retval = -ERESTARTSYS;
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		data = xchg(&gen_rtc_irq_data, 0);
+		if (data)
+			break;
+		if (signal_pending(current))
+			goto out;
+		schedule();
+	}
+
+	/* first test allows optimizer to nuke this case for 32-bit machines */
+	if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
+		unsigned int uidata = data;
+		retval = put_user(uidata, (unsigned long *)buf);
+	}
+	else {
+		retval = put_user(data, (unsigned long *)buf);
+	}
+	if (!retval)
+		retval = sizeof(unsigned long);
+ out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&gen_rtc_wait, &wait);
+
+	return retval;
+}
+
+static unsigned int gen_rtc_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	poll_wait(file, &gen_rtc_wait, wait);
+	if (gen_rtc_irq_data != 0)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+#endif
+
+/*
+ * Used to disable/enable interrupts, only RTC_UIE supported
+ * We also clear out any old irq data after an ioctl() that
+ * meddles with the interrupt enable/disable bits.
+ */
+
+static inline void gen_clear_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	stop_rtc_timers = 1;
+	if (ttask_active){
+		del_timer_sync(&timer_task);
+		ttask_active = 0;
+	}
+	while (stask_active)
+		schedule();
+
+	spin_lock(&gen_rtc_lock);
+	irq_active = 0;
+	spin_unlock(&gen_rtc_lock);
+#endif
+}
+
+static inline int gen_set_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	spin_lock(&gen_rtc_lock);
+	if ( !irq_active ) {
+		irq_active = 1;
+		stop_rtc_timers = 0;
+		lostint = 0;
+		genrtc_task.routine = genrtc_troutine;
+		oldsecs = get_rtc_ss();
+		init_timer(&timer_task);
+
+		stask_active = 1;
+		if (schedule_task(&genrtc_task) == 0){
+			stask_active = 0;
+		}
+	}
+	spin_unlock(&gen_rtc_lock);
+	gen_rtc_irq_data = 0;
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	struct rtc_time wtime;
+	struct rtc_pll_info pll;
+
+	switch (cmd) {
+
+	case RTC_PLL_GET:
+	    if (get_rtc_pll(&pll))
+	 	    return -EINVAL;
+	    else
+		    return copy_to_user((void *)arg, &pll, sizeof pll) ? -EFAULT : 0;
+
+	case RTC_PLL_SET:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+		if (copy_from_user(&pll, (struct rtc_pll_info*)arg,
+				   sizeof(pll)))
+			return -EFAULT;
+	    return set_rtc_pll(&pll);
+
+	case RTC_UIE_OFF:	/* disable ints from RTC updates.	*/
+		gen_clear_rtc_irq_bit(RTC_UIE);
+		return 0;
+
+	case RTC_UIE_ON:	/* enable ints for RTC updates.	*/
+	        return gen_set_rtc_irq_bit(RTC_UIE);
+
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		/* this doesn't get week-day, who cares */
+		memset(&wtime, 0, sizeof(wtime));
+		get_rtc_time(&wtime);
+
+		return copy_to_user((void *)arg, &wtime, sizeof(wtime)) ? -EFAULT : 0;
+
+	case RTC_SET_TIME:	/* Set the RTC */
+	    {
+		int year;
+		unsigned char leap_yr;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&wtime, (struct rtc_time *)arg,
+				   sizeof(wtime)))
+			return -EFAULT;
+
+		year = wtime.tm_year + 1900;
+		leap_yr = ((!(year % 4) && (year % 100)) ||
+			   !(year % 400));
+
+		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
+			return -EINVAL;
+
+		if (wtime.tm_mday < 0 || wtime.tm_mday >
+		    (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
+			return -EINVAL;
+
+		if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
+		    wtime.tm_min < 0 || wtime.tm_min >= 60 ||
+		    wtime.tm_sec < 0 || wtime.tm_sec >= 60)
+			return -EINVAL;
+
+		return set_rtc_time(&wtime);
+	    }
+	}
+
+	return -EINVAL;
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int gen_rtc_open(struct inode *inode, struct file *file)
+{
+	if (gen_rtc_status & RTC_IS_OPEN)
+		return -EBUSY;
+
+	MOD_INC_USE_COUNT;
+
+	gen_rtc_status |= RTC_IS_OPEN;
+	gen_rtc_irq_data = 0;
+	irq_active = 0;
+
+	return 0;
+}
+
+static int gen_rtc_release(struct inode *inode, struct file *file)
+{
+	/*
+	 * Turn off all interrupts once the device is no longer
+	 * in use and clear the data.
+	 */
+
+	gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
+
+	gen_rtc_status &= ~RTC_IS_OPEN;
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations gen_rtc_fops = {
+	.owner =	THIS_MODULE,
+#ifdef CONFIG_GEN_RTC_X
+	.read =		gen_rtc_read,
+	.poll =		gen_rtc_poll,
+#endif
+	.ioctl =	gen_rtc_ioctl,
+	.open =		gen_rtc_open,
+	.release =	gen_rtc_release
+};
+
+static struct miscdevice rtc_gen_dev =
+{
+	RTC_MINOR,
+	"rtc",
+	&gen_rtc_fops
+};
+
+int __init rtc_generic_init(void)
+{
+
+		printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
+
+	misc_register(&rtc_gen_dev);
+	create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL);
+
+	return 0;
+}
+
+static void __exit rtc_generic_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister(&rtc_gen_dev);
+}
+
+module_init(rtc_generic_init);
+module_exit(rtc_generic_exit);
+EXPORT_NO_SYMBOLS;
+
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+int gen_rtc_proc_output(char *buf)
+{
+	char *p;
+	struct rtc_time tm;
+	unsigned tmp;
+	struct rtc_pll_info pll;
+
+	p = buf;
+
+	get_rtc_time(&tm);
+
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+		     "rtc_epoch\t: %04u\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
+
+	tm.tm_hour=0;tm.tm_min=0;tm.tm_sec=0;
+
+	p += sprintf(p, "alarm\t\t: ");
+	if (tm.tm_hour <= 24)
+		p += sprintf(p, "%02d:", tm.tm_hour);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_min <= 59)
+		p += sprintf(p, "%02d:", tm.tm_min);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_sec <= 59)
+		p += sprintf(p, "%02d\n", tm.tm_sec);
+	else
+		p += sprintf(p, "**\n");
+
+	tmp= RTC_24H ;
+	p += sprintf(p,
+		     "DST_enable\t: %s\n"
+		     "BCD\t\t: %s\n"
+		     "24hr\t\t: %s\n"
+		     "square_wave\t: %s\n"
+		     "alarm_IRQ\t: %s\n"
+		     "update_IRQ\t: %s\n"
+		     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+		     "batt_status\t: %s\n",
+		     (tmp & RTC_DST_EN) ? "yes" : "no",
+		     (tmp & RTC_DM_BINARY) ? "no" : "yes",
+		     (tmp & RTC_24H) ? "yes" : "no",
+		     (tmp & RTC_SQWE) ? "yes" : "no",
+		     (tmp & RTC_AIE) ? "yes" : "no",
+		     irq_active ? "yes" : "no",
+		     (tmp & RTC_PIE) ? "yes" : "no",
+		     0L /* freq */,
+		     "okay" );
+	if (!get_rtc_pll(&pll))
+	    p += sprintf(p,
+			 "PLL adjustment\t: %d\n"
+			 "PLL max +ve adjustment\t: %d\n"
+			 "PLL max -ve adjustment\t: %d\n"
+			 "PLL +ve adjustment factor\t: %d\n"
+			 "PLL -ve adjustment factor\t: %d\n"
+			 "PLL frequency\t: %ld\n",
+			 pll.pll_value,
+			 pll.pll_max,
+			 pll.pll_min,
+			 pll.pll_posmult,
+			 pll.pll_negmult,
+			 pll.pll_clock);
+	return  p - buf;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	int len = gen_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+	return len;
+}
+
+
+MODULE_AUTHOR("Richard Zidlicky");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
--- a/drivers/char/hvc_console.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/char/hvc_console.c	Tue Aug 27 12:28:08 2002
@@ -204,7 +204,7 @@
 					sysrq_pressed = 1;
 					continue;
 				} else if (sysrq_pressed) {
-					handle_sysrq(buf[i], NULL, NULL, tty);
+					handle_sysrq(buf[i], NULL, tty);
 					sysrq_pressed = 0;
 					continue;
 				}
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/char/keyboard.c	Tue Aug 27 12:28:02 2002
@@ -21,6 +21,7 @@
  *
  * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
  * 30-07-98: Dead keys redone, aeb@cwi.nl.
+ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
  */
 
 #include <linux/config.h>
@@ -32,22 +33,18 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/init.h>
-
-#include <asm/keyboard.h>
-#include <asm/bitops.h>
+#include <linux/slab.h>
 
 #include <linux/console_struct.h>
 #include <linux/kbd_kern.h>
 #include <linux/kbd_diacr.h>
 #include <linux/vt_kern.h>
-#include <linux/kbd_ll.h>
 #include <linux/sysrq.h>
-#include <linux/pm.h>
+#include <linux/input.h>
 
+static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
 
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
 /*
  * Exported functions/variables
  */
@@ -58,8 +55,8 @@
 
 #ifndef KBD_DEFLEDS
 /*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock
- * is on. This seems a good reason to start with NumLock off.
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off.
  */
 #define KBD_DEFLEDS 0
 #endif
@@ -68,27 +65,18 @@
 #define KBD_DEFLOCK 0
 #endif
 
-void (*kbd_ledfunc)(unsigned int led);
-EXPORT_SYMBOL(handle_scancode);
-EXPORT_SYMBOL(kbd_ledfunc);
-/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-struct pt_regs * kbd_pt_regs;
+struct pt_regs *kbd_pt_regs;
 void compute_shiftstate(void);
 
 /*
  * Handler Tables.
  */
 
-/* Key types processed even in raw modes */
-
-#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT))
-#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK))
-
 #define K_HANDLERS\
 	k_self,		k_fn,		k_spec,		k_pad,\
 	k_dead,		k_cons,		k_cur,		k_shift,\
 	k_meta,		k_ascii,	k_lock,		k_lowercase,\
-	k_slock,	k_dead2,	k_ignore,	k_ignore	
+	k_slock,	k_dead2,	k_ignore,	k_ignore
 
 typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, 
 			    char up_flag);
@@ -107,74 +95,200 @@
 static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
 
 /*
- * Variables/functions exported for vt.c
+ * Variables exported for vt_ioctl.c
  */
 
 /* maximum values each key_handler can handle */
 const int max_vals[] = {
-	255, SIZE(func_table) - 1, SIZE(fn_handler) - 1, NR_PAD - 1,
+	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
 	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
 	255, NR_LOCK - 1, 255
 };
 
-const int NR_TYPES = SIZE(max_vals);
+const int NR_TYPES = ARRAY_SIZE(max_vals);
+
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct kbd_struct *kbd = kbd_table;
+static struct kbd_struct kbd0;
 
 int spawnpid, spawnsig;
 
 /*
- * Translation of escaped scancodes to keycodes.
- * This is now user-settable (for machines were it makes sense).
+ * Variables exported for vt.c
  */
-int getkeycode(unsigned int scancode)
-{
-    return kbd_getkeycode(scancode);
-}
 
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-    return kbd_setkeycode(scancode, keycode);
-}
-
-/*
- * Variables/function exported for console.c
- */
 int shift_state = 0;
 
 /*
  * Internal Data.
  */
 
-static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */
-static unsigned char shift_down[NR_SHIFT];	/* shift state counters.. */	
+static struct input_handler kbd_handler;
+static unsigned long key_down[256/BITS_PER_LONG];	/* keyboard key bitmap */
+static unsigned char shift_down[NR_SHIFT];		/* shift state counters.. */
 static int dead_key_next;
-static int npadch = -1;			/* -1 or number assembled on pad */
+static int npadch = -1;					/* -1 or number assembled on pad */
 static unsigned char diacr;
-static char rep;			/* flag telling character repeat */
-pm_callback pm_kbd_request_override = NULL;
-typedef void (pm_kbd_func) (void);
-static struct pm_dev *pm_kbd;
+static char rep;					/* flag telling character repeat */
 
-static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char ledstate = 0xff;			/* undefined */
 static unsigned char ledioctl;
 
 static struct ledptr {
-    unsigned int *addr;
-    unsigned int mask;
-    unsigned char valid:1;
+	unsigned int *addr;
+	unsigned int mask;
+	unsigned char valid:1;
 } ledptrs[3];
 
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct kbd_struct *kbd = kbd_table;
+/* Simple translation table for the SysRq keys */
+
 #ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
+unsigned char kbd_sysrq_xlate[128] =
+        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+        "\r\000/";                                      /* 0x60 - 0x6f */
+static int sysrq_down;
 #endif
+static int sysrq_alt;
+
+/*
+ * Translation of scancodes to keycodes. We set them on only the first attached
+ * keyboard - for per-keyboard setting, /dev/input/event is more useful.
+ */
+int getkeycode(unsigned int scancode)
+{
+	struct list_head * node;
+	struct input_dev *dev = NULL;
+
+	list_for_each(node,&kbd_handler.h_list) {
+		struct input_handle * handle = to_handle_h(node);
+		if (handle->dev->keycodesize) { 
+			dev = handle->dev; 
+			break;
+		}
+	}
+
+	if (!dev)
+		return -ENODEV;
+
+	if (scancode < 0 || scancode >= dev->keycodemax)
+		return -EINVAL;
+
+	return INPUT_KEYCODE(dev, scancode);
+}
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	struct list_head * node;
+	struct input_dev *dev = NULL;
+	int i, oldkey;
+
+	list_for_each(node,&kbd_handler.h_list) {
+		struct input_handle *handle = to_handle_h(node);
+		if (handle->dev->keycodesize) { 
+			dev = handle->dev; 
+			break; 
+		}
+	}
+
+	if (!dev)
+		return -ENODEV;
+
+	if (scancode < 0 || scancode >= dev->keycodemax)
+		return -EINVAL;
+
+	oldkey = INPUT_KEYCODE(dev, scancode);
+	INPUT_KEYCODE(dev, scancode) = keycode;
+
+	for (i = 0; i < dev->keycodemax; i++)
+		if(INPUT_KEYCODE(dev, scancode) == oldkey)
+			break;
+	if (i == dev->keycodemax)
+		clear_bit(oldkey, dev->keybit);
+	set_bit(keycode, dev->keybit);
+	
+	return 0;
+}
+
+/*
+ * Making beeps and bells. 
+ */
+static void kd_nosound(unsigned long ignored)
+{
+	struct list_head * node;
+
+	list_for_each(node,&kbd_handler.h_list) {
+		struct input_handle *handle = to_handle_h(node);
+		if (test_bit(EV_SND, handle->dev->evbit)) {
+			if (test_bit(SND_TONE, handle->dev->sndbit))
+				input_event(handle->dev, EV_SND, SND_TONE, 0);
+			if (test_bit(SND_BELL, handle->dev->sndbit))
+				input_event(handle->dev, EV_SND, SND_BELL, 0);
+		}
+	}
+}
+
+static struct timer_list kd_mksound_timer = { function: kd_nosound };
+
+void kd_mksound(unsigned int hz, unsigned int ticks)
+{
+	struct list_head * node;
+
+	del_timer(&kd_mksound_timer);
+
+	if (hz) {
+		list_for_each(node,&kbd_handler.h_list) {
+			struct input_handle *handle = to_handle_h(node);
+			if (test_bit(EV_SND, handle->dev->evbit)) {
+				if (test_bit(SND_TONE, handle->dev->sndbit)) {
+					input_event(handle->dev, EV_SND, SND_TONE, hz);
+					break;
+				}
+				if (test_bit(SND_BELL, handle->dev->sndbit)) {
+					input_event(handle->dev, EV_SND, SND_BELL, 1);
+					break;
+				}
+			}
+		}
+		if (ticks)
+			mod_timer(&kd_mksound_timer, jiffies + ticks);
+	} else
+		kd_nosound(0);
+}
+
+/*
+ * Setting the keyboard rate.
+ */
+int kbd_rate(struct kbd_repeat *rep)
+{
+	struct list_head * node;
+
+	if (rep->rate < 0 || rep->delay < 0)
+		return -EINVAL;
+
+	list_for_each(node,&kbd_handler.h_list) {
+		struct input_handle *handle = to_handle_h(node);
+		if (test_bit(EV_REP, handle->dev->evbit)) {
+			if (rep->rate > HZ) rep->rate = HZ;
+			handle->dev->rep[REP_PERIOD] = rep->rate ? (HZ / rep->rate) : 0;
+			handle->dev->rep[REP_DELAY] = rep->delay * HZ / 1000;
+			if (handle->dev->rep[REP_DELAY] < handle->dev->rep[REP_PERIOD])
+				handle->dev->rep[REP_DELAY] = handle->dev->rep[REP_PERIOD];
+		}
+	}
+	return 0;
+}
 
 /*
  * Helper Functions.
  */
-void put_queue(struct vc_data *vc, int ch)
+static void put_queue(struct vc_data *vc, int ch)
 {
-	struct tty_struct *tty = vc->vc_tty;	
+	struct tty_struct *tty = vc->vc_tty;
 
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
@@ -215,23 +329,25 @@
 void to_utf8(struct vc_data *vc, ushort c) 
 {
 	if (c < 0x80)
-		/*  0*******  */
+		/*  0******* */
 		put_queue(vc, c);
     	else if (c < 0x800) {
-		/*  110***** 10******  */
+		/* 110***** 10****** */
 		put_queue(vc, 0xc0 | (c >> 6)); 
 		put_queue(vc, 0x80 | (c & 0x3f));
     	} else {
-		/*  1110**** 10****** 10*******/
+		/* 1110**** 10****** 10****** */
 		put_queue(vc, 0xe0 | (c >> 12));
 		put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
 		put_queue(vc, 0x80 | (c & 0x3f));
     	}
 }
 
-/* called after returning from RAW mode or when changing consoles -
-   recompute shift_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
+/* 
+ * Called after returning from RAW mode or when changing consoles - recompute
+ * shift_down[] and shift_state from key_down[] maybe called when keymap is
+ * undefined, so that shiftkey release is seen
+ */
 void compute_shiftstate(void)
 {
 	int i, j, k, sym, val;
@@ -239,28 +355,28 @@
 	shift_state = 0;
 	memset(shift_down, 0, sizeof(shift_down));
 	
-	for (i = 0; i < SIZE(key_down); i++) {
-	  	
+	for (i = 0; i < ARRAY_SIZE(key_down); i++) {
+
 		if (!key_down[i])
-			continue;	    
+			continue;
+
+		k = i * BITS_PER_LONG;
 
-		k = i*BITS_PER_LONG;
-	
 		for (j = 0; j < BITS_PER_LONG; j++, k++) {
-	      
+
 			if (!test_bit(k, key_down))
 				continue;
-	
-			sym = U(plain_map[k]);
+
+			sym = U(key_maps[0][k]);
 			if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
 				continue;
 
-	  		val = KVAL(sym);
-		  	if (val == KVAL(K_CAPSSHIFT))
-		    		val = KVAL(K_SHIFT);
-		  	
+			val = KVAL(sym);
+			if (val == KVAL(K_CAPSSHIFT))
+				val = KVAL(K_SHIFT);
+
 			shift_down[val]++;
-		  	shift_state |= (1<<val);
+			shift_state |= (1 << val);
 		}
 	}
 }
@@ -360,7 +476,7 @@
 static void fn_bare_num(struct vc_data *vc)
 {
 	if (!rep)
-		chg_vc_kbd_led(kbd,VC_NUMLOCK);
+		chg_vc_kbd_led(kbd, VC_NUMLOCK);
 }
 
 static void fn_lastcons(struct vc_data *vc)
@@ -453,9 +569,6 @@
 	if (tty)
 		do_SAK(tty);
 	reset_vc(fg_console);
-#if 0
-	do_unblank_screen();	/* not in interrupt routine? */
-#endif
 }
 
 static void fn_null(struct vc_data *vc)
@@ -474,17 +587,18 @@
 {
 	if (up_flag)
 		return;
-	if (value >= SIZE(fn_handler))
-		return;
-	if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) &&
-	    !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value)))
+	if (value >= ARRAY_SIZE(fn_handler))
 		return;
+	if ((kbd->kbdmode == VC_RAW || 
+	     kbd->kbdmode == VC_MEDIUMRAW) && 
+	     value != K_SAK)
+		return;		/* SAK is allowed even in raw mode */
 	fn_handler[value](vc);
 }
 
 static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
 {
-	printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
+	printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n");
 }
 
 static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
@@ -503,22 +617,6 @@
 	put_queue(vc, value);
 }
 
-#define A_GRAVE  '`'
-#define A_ACUTE  '\''
-#define A_CFLEX  '^'
-#define A_TILDE  '~'
-#define A_DIAER  '"'
-#define A_CEDIL  ','
-static unsigned char ret_diacr[NR_DEAD] =
-	{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
-
-/* Obsolete - for backwards compatibility only */
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	value = ret_diacr[value];
-	k_dead2(vc, value,up_flag);
-}
-
 /*
  * Handle dead key. Note that we now may have several
  * dead keys modifying the same character. Very useful
@@ -528,10 +626,19 @@
 {
 	if (up_flag)
 		return;
-
 	diacr = (diacr ? handle_diacr(vc, value) : value);
 }
 
+/*
+ * Obsolete - for backwards compatibility only
+ */
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
+{
+	static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+	value = ret_diacr[value];
+	k_dead2(vc, value, up_flag);
+}
+
 static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
@@ -543,13 +650,22 @@
 {
 	if (up_flag)
 		return;
-	if (value < SIZE(func_table)) {
+	if (value < ARRAY_SIZE(func_table)) {
 		if (func_table[value])
 			puts_queue(vc, func_table[value]);
 	} else
 		printk(KERN_ERR "k_fn called with value=%d\n", value);
 }
 
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
+{
+	static const char *cur_chars = "BDCA";
+
+	if (up_flag)
+		return;
+	applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+}
+
 static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	static const char *pad_chars = "0123456789+-*/\015,.?()";
@@ -559,12 +675,12 @@
 		return;		/* no action, if this is a key release */
 
 	/* kludge... shift forces cursor/number keys */
-	if (vc_kbd_mode(kbd,VC_APPLIC) && !shift_down[KG_SHIFT]) {
+	if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
 		applkey(vc, app_map[value], 1);
 		return;
 	}
 
-	if (!vc_kbd_led(kbd,VC_NUMLOCK))
+	if (!vc_kbd_led(kbd, VC_NUMLOCK))
 		switch (value) {
 			case KVAL(K_PCOMMA):
 			case KVAL(K_PDOT):
@@ -607,24 +723,16 @@
 		put_queue(vc, 10);
 }
 
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	static const char *cur_chars = "BDCA";
-
-	if (up_flag)
-		return;
-	applkey(vc, cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
-}
-
 static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	int old_state = shift_state;
 
 	if (rep)
 		return;
-
-	/* Mimic typewriter:
-	   a CapsShift key acts like Shift but undoes CapsLock */
+	/*
+	 * Mimic typewriter:
+	 * a CapsShift key acts like Shift but undoes CapsLock
+	 */
 	if (value == KVAL(K_CAPSSHIFT)) {
 		value = KVAL(K_SHIFT);
 		if (!up_flag)
@@ -632,8 +740,10 @@
 	}
 
 	if (up_flag) {
-		/* handle the case that two shift or control
-		   keys are depressed simultaneously */
+		/*
+		 * handle the case that two shift or control
+		 * keys are depressed simultaneously
+		 */
 		if (shift_down[value])
 			shift_down[value]--;
 	} else
@@ -642,14 +752,14 @@
 	if (shift_down[value])
 		shift_state |= (1 << value);
 	else
-		shift_state &= ~ (1 << value);
+		shift_state &= ~(1 << value);
 
 	/* kludge */
 	if (up_flag && shift_state != old_state && npadch != -1) {
 		if (kbd->kbdmode == VC_UNICODE)
-		  to_utf8(vc, npadch & 0xffff);
+			to_utf8(vc, npadch & 0xffff);
 		else
-		  put_queue(vc, npadch & 0xff);
+			put_queue(vc, npadch & 0xff);
 		npadch = -1;
 	}
 }
@@ -673,17 +783,19 @@
 	if (up_flag)
 		return;
 
-	if (value < 10)    /* decimal input of code, while Alt depressed */
-	    base = 10;
-	else {       /* hexadecimal input of code, while AltGr depressed */
-	    value -= 10;
-	    base = 16;
+	if (value < 10) {
+		/* decimal input of code, while Alt depressed */
+		base = 10;
+	} else {
+		/* hexadecimal input of code, while AltGr depressed */
+		value -= 10;
+		base = 16;
 	}
 
 	if (npadch == -1)
-	  npadch = value;
+		npadch = value;
 	else
-	  npadch = npadch * base + value;
+		npadch = npadch * base + value;
 }
 
 static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
@@ -695,7 +807,7 @@
 
 static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
 {
-	k_shift(vc, value,up_flag);
+	k_shift(vc, value, up_flag);
 	if (up_flag || rep)
 		return;
 	chg_vc_kbd_slock(kbd, value);
@@ -711,59 +823,54 @@
  * or (ii) whatever pattern of lights people want to show using KDSETLED,
  * or (iii) specified bits of specified words in kernel memory.
  */
-unsigned char getledstate(void) {
-    return ledstate;
+unsigned char getledstate(void)
+{
+	return ledstate;
 }
 
-void setledstate(struct kbd_struct *kbd, unsigned int led) {
-    if (!(led & ~7)) {
-	ledioctl = led;
-	kbd->ledmode = LED_SHOW_IOCTL;
-    } else
-	kbd->ledmode = LED_SHOW_FLAGS;
-    set_leds();
-}
-
-void register_leds(int console, unsigned int led,
-		   unsigned int *addr, unsigned int mask) {
-    struct kbd_struct *kbd = kbd_table + console;
-    if (led < 3) {
-	ledptrs[led].addr = addr;
-	ledptrs[led].mask = mask;
-	ledptrs[led].valid = 1;
-	kbd->ledmode = LED_SHOW_MEM;
-    } else
-	kbd->ledmode = LED_SHOW_FLAGS;
-}
-
-static inline unsigned char getleds(void){
-    struct kbd_struct *kbd = kbd_table + fg_console;
-    unsigned char leds;
-
-    if (kbd->ledmode == LED_SHOW_IOCTL)
-      return ledioctl;
-    leds = kbd->ledflagstate;
-    if (kbd->ledmode == LED_SHOW_MEM) {
-	if (ledptrs[0].valid) {
-	    if (*ledptrs[0].addr & ledptrs[0].mask)
-	      leds |= 1;
-	    else
-	      leds &= ~1;
-	}
-	if (ledptrs[1].valid) {
-	    if (*ledptrs[1].addr & ledptrs[1].mask)
-	      leds |= 2;
-	    else
-	      leds &= ~2;
-	}
-	if (ledptrs[2].valid) {
-	    if (*ledptrs[2].addr & ledptrs[2].mask)
-	      leds |= 4;
-	    else
-	      leds &= ~4;
+void setledstate(struct kbd_struct *kbd, unsigned int led)
+{
+	if (!(led & ~7)) {
+		ledioctl = led;
+		kbd->ledmode = LED_SHOW_IOCTL;
+	} else
+		kbd->ledmode = LED_SHOW_FLAGS;
+	set_leds();
+}
+
+void register_leds(struct kbd_struct *kbd, unsigned int led,
+		   unsigned int *addr, unsigned int mask)
+{
+	if (led < 3) {
+		ledptrs[led].addr = addr;
+		ledptrs[led].mask = mask;
+		ledptrs[led].valid = 1;
+		kbd->ledmode = LED_SHOW_MEM;
+	} else
+		kbd->ledmode = LED_SHOW_FLAGS;
+}
+
+static inline unsigned char getleds(void)
+{
+	struct kbd_struct *kbd = kbd_table + fg_console;
+	unsigned char leds;
+	int i;
+
+	if (kbd->ledmode == LED_SHOW_IOCTL)
+		return ledioctl;
+
+	leds = kbd->ledflagstate;
+
+	if (kbd->ledmode == LED_SHOW_MEM) {
+		for (i = 0; i < 3; i++)
+			if (ledptrs[i].valid) {
+				if (*ledptrs[i].addr & ledptrs[i].mask)
+					leds |= (1 << i);
+				else
+					leds &= ~(1 << i);
+			}
 	}
-    }
-    return leds;
+	return leds;
 }
 
 /*
@@ -782,175 +889,299 @@
 
 static void kbd_bh(unsigned long dummy)
 {
+	struct list_head * node;
 	unsigned char leds = getleds();
 
 	if (leds != ledstate) {
-		ledstate = leds;
-		kbd_leds(leds);
-		if (kbd_ledfunc) kbd_ledfunc(leds);
+		list_for_each(node,&kbd_handler.h_list) {
+			struct input_handle * handle = to_handle_h(node);
+			input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+			input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));
+			input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+		}
 	}
+
+	ledstate = leds;
 }
 
-EXPORT_SYMBOL(keyboard_tasklet);
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
-void handle_scancode(unsigned char scancode, int down)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC)
+
+static unsigned short x86_keycodes[256] =
+	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+	 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
+	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
+	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
+	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+	118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269,
+	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
+	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
+	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+extern int mac_hid_mouse_emulate_buttons(int, int, int);
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode, 
+		       unsigned char up_flag)
+{
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+	if (mac_hid_mouse_emulate_buttons(1, keycode, !up_flag))
+		return 0;
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+
+	if (keycode > 255 || !x86_keycodes[keycode])
+		return -1; 
+
+	if (keycode == KEY_PAUSE) {
+		put_queue(vc, 0xe1);
+		put_queue(vc, 0x1d | up_flag);
+		put_queue(vc, 0x45 | up_flag);
+		return 0;
+	} 
+
+	if (keycode == KEY_SYSRQ && sysrq_alt) {
+		put_queue(vc, 0x54 | up_flag);
+		return 0;
+	}
+
+	if (x86_keycodes[keycode] & 0x100)
+		put_queue(vc, 0xe0);
+
+	put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag);
+
+	if (keycode == KEY_SYSRQ) {
+		put_queue(vc, 0xe0);
+		put_queue(vc, 0x37 | up_flag);
+	}
+
+	return 0;
+}
+
+#else
+
+#warning "Cannot generate rawmode keyboard for your architecture yet."
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
+{
+	if (keycode > 127)
+		return -1;
+
+	put_queue(vc, keycode | up_flag);
+	return 0;
+}
+#endif
+
+void kbd_keycode(unsigned int keycode, int down)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
-	char up_flag = down ? 0 : 0200;
+	unsigned short keysym, *key_map;
+	unsigned char type, raw_mode;
 	struct tty_struct *tty;
-	unsigned char keycode;
-	char raw_mode;
+	int shift_final;
 
-	pm_access(pm_kbd);
-	add_keyboard_randomness(scancode | up_flag);
+	if (down != 2)
+		add_keyboard_randomness((keycode << 1) ^ down);
 
 	tty = vc->vc_tty;
 
 	if (tty && (!tty->driver_data)) {
-		/*
-		 * We touch the tty structure via the ttytab array
-		 * without knowing whether or not tty is open, which
-		 * is inherently dangerous.  We currently rely on that
-		 * fact that console_open sets tty->driver_data when
-		 * it opens it, and clears it when it closes it.
-		 */
-		tty = NULL;
-	}
-	kbd = kbd_table + fg_console;
-	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
-		put_queue(vc, scancode | up_flag);
-		/* we do not return yet, because we want to maintain
-		   the key_down array, so that we have the correct
-		   values when finishing RAW mode or when changing VT's */
+		/* No driver data? Strange. Okay we fix it then. */
+		tty->driver_data = vc;
 	}
 
-	/*
-	 *  Convert scancode to keycode
-	 */
-	if (!kbd_translate(scancode, &keycode, raw_mode))
-		goto out;
+	kbd = kbd_table + fg_console;
 
-	/*
-	 * At this point the variable `keycode' contains the keycode.
-	 * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
-	 * We keep track of the up/down status of the key, and
-	 * return the keycode if in MEDIUMRAW mode.
-	 */
+	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
+		sysrq_alt = down;
 
-	if (up_flag) {
-		rep = 0;
-		if(!test_and_clear_bit(keycode, key_down))
-		    up_flag = kbd_unexpected_up(keycode);
-	} else
-		rep = test_and_set_bit(keycode, key_down);
+	rep = (down == 2);
 
-#ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
-	if (keycode == SYSRQ_KEY) {
-		sysrq_pressed = !up_flag;
-		goto out;
-	} else if (sysrq_pressed) {
-		if (!up_flag) {
-			handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, tty);
-			goto out;
-		}
+	if ((raw_mode = (kbd->kbdmode == VC_RAW)))
+		if (emulate_raw(vc, keycode, !down << 7))
+			printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
+
+#ifdef CONFIG_MAGIC_SYSRQ	       /* Handle the SysRq Hack */
+	if (keycode == KEY_SYSRQ && !rep) {
+		sysrq_down = sysrq_alt && down;
+		return;
+	}
+	if (sysrq_down && down && !rep) {
+		handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, tty);
+		return;
 	}
 #endif
 
 	if (kbd->kbdmode == VC_MEDIUMRAW) {
-		/* soon keycodes will require more than one byte */
-		put_queue(vc, keycode + up_flag);
-		raw_mode = 1;	/* Most key classes will be ignored */
+		/*
+		 * This is extended medium raw mode, with keys above 127
+		 * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
+		 * the 'up' flag if needed. 0 is reserved, so this shouldn't
+		 * interfere with anything else. The two bytes after 0 will
+		 * always have the up flag set not to interfere with older
+		 * applications. This allows for 16384 different keycodes,
+		 * which should be enough.
+		 */
+		if (keycode < 128) {
+			put_queue(vc, keycode | (!down << 7));
+		} else {
+			put_queue(vc, !down << 7);
+			put_queue(vc, (keycode >> 7) | 0x80);
+			put_queue(vc, keycode | 0x80);
+		}
+		raw_mode = 1;
 	}
 
-	/*
-	 * Small change in philosophy: earlier we defined repetition by
-	 *	 rep = keycode == prev_keycode;
-	 *	 prev_keycode = keycode;
-	 * but now by the fact that the depressed key was down already.
-	 * Does this ever make a difference? Yes.
-	 */
+	if (down)
+		set_bit(keycode, key_down);
+	else
+		clear_bit(keycode, key_down);
 
-	/*
-	 *  Repeat a key only if the input buffers are empty or the
-	 *  characters get echoed locally. This makes key repeat usable
-	 *  with slow applications and under heavy loads.
-	 */
-	if (!rep ||
-	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
-	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
-		u_short keysym;
-		u_char type;
-
-		/* the XOR below used to be an OR */
-		int shift_final = (shift_state | kbd->slockstate) ^
-		    kbd->lockstate;
-		ushort *key_map = key_maps[shift_final];
-
-		if (key_map != NULL) {
-			keysym = key_map[keycode];
-			type = KTYP(keysym);
-
-			if (type >= 0xf0) {
-			    type -= 0xf0;
-			    if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type)))
-				goto out;
-			    if (type == KT_LETTER) {
-				type = KT_LATIN;
-				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
-				    if (key_map)
-				      keysym = key_map[keycode];
-				}
-			    }
-			    (*k_handler[type])(vc, keysym & 0xff, up_flag);
-			    if (type != KT_SLOCK)
-			      kbd->slockstate = 0;
-			} else {
-			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
-			    if (!up_flag && !raw_mode)
-			      to_utf8(vc, keysym);
-			}
-		} else {
-			/* maybe beep? */
-			/* we have at least to update shift_state */
-#if 1			/* how? two almost equivalent choices follow */
-			compute_shiftstate();
-			kbd->slockstate = 0; /* play it safe */
-#else
-			keysym =  U(plain_map[keycode]);
-			type = KTYP(keysym);
-			if (type == KT_SHIFT)
-			  (*key_handler[type])(keysym & 0xff, up_flag);
-#endif
+	if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && 
+		(!L_ECHO(tty) && tty->driver.chars_in_buffer(tty))))) {
+		/*
+		 * Don't repeat a key if the input buffers are not empty and the
+		 * characters get aren't echoed locally. This makes key repeat 
+		 * usable with slow applications and under heavy loads.
+		 */
+		return;
+	}
+
+	shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+	key_map = key_maps[shift_final];
+
+	if (!key_map) {
+		compute_shiftstate();
+		kbd->slockstate = 0;
+		return;
+	}
+
+	keysym = key_map[keycode];
+	type = KTYP(keysym);
+
+	if (type < 0xf0) {
+		if (down && !raw_mode) to_utf8(vc, keysym);
+		return;
+	}
+
+	type -= 0xf0;
+
+	if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+		return;
+
+	if (type == KT_LETTER) {
+		type = KT_LATIN;
+		if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+			key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+			if (key_map)
+				keysym = key_map[keycode];
 		}
 	}
-out:
+
+	(*k_handler[type])(vc, keysym & 0xff, !down);
+
+	if (type != KT_SLOCK)
+		kbd->slockstate = 0;
+}
+
+static void kbd_event(struct input_handle *handle, unsigned int event_type, 
+		      unsigned int keycode, int down)
+{
+	if (event_type != EV_KEY)
+		return;
+	kbd_keycode(keycode, down);
+	tasklet_schedule(&keyboard_tasklet);
 	do_poke_blanked_console = 1;
 	schedule_console_callback();
 }
 
+static char kbd_name[] = "kbd";
+
+/*
+ * When a keyboard (or other input device) is found, the kbd_connect
+ * function is called. The function then looks at the device, and if it
+ * likes it, it can open it and get events from it. In this (kbd_connect)
+ * function, we should decide which VT to bind that keyboard to initially.
+ */
+static struct input_handle *kbd_connect(struct input_handler *handler, 
+					struct input_dev *dev,
+					struct input_device_id *id)
+{
+	struct input_handle *handle;
+	int i;
+
+	for (i = KEY_RESERVED; i < BTN_MISC; i++)
+		if (test_bit(i, dev->keybit)) break;
+
+	if ((i == BTN_MISC) && !test_bit(EV_SND, dev->evbit)) 
+		return NULL;
+
+	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) 
+		return NULL;
+	memset(handle, 0, sizeof(struct input_handle));
+
+	handle->dev = dev;
+	handle->handler = handler;
+	handle->name = kbd_name;
+
+	input_open_device(handle);
+
+	return handle;
+}
+
+static void kbd_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	kfree(handle);
+}
+
+static struct input_device_id kbd_ids[] = {
+	{
+                flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+                evbit: { BIT(EV_KEY) },
+        },
+	
+	{
+                flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+                evbit: { BIT(EV_SND) },
+        },	
+
+	{ },    /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, kbd_ids);
+
+static struct input_handler kbd_handler = {
+	event:		kbd_event,
+	connect:	kbd_connect,
+	disconnect:	kbd_disconnect,
+	name:		"kbd",
+	id_table:	kbd_ids,
+};
+
 int __init kbd_init(void)
 {
 	int i;
-	struct kbd_struct kbd0;
 
-	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
-	kbd0.ledmode = LED_SHOW_FLAGS;
-	kbd0.lockstate = KBD_DEFLOCK;
-	kbd0.slockstate = 0;
-	kbd0.modeflags = KBD_DEFMODE;
-	kbd0.kbdmode = VC_XLATE;
- 
-	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
-		kbd_table[i] = kbd0;
+        kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
+        kbd0.ledmode = LED_SHOW_FLAGS;
+        kbd0.lockstate = KBD_DEFLOCK;
+        kbd0.slockstate = 0;
+        kbd0.modeflags = KBD_DEFMODE;
+        kbd0.kbdmode = VC_XLATE;
 
-	kbd_init_hw();
+        for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
+                kbd_table[i] = kbd0;
 
 	tasklet_enable(&keyboard_tasklet);
 	tasklet_schedule(&keyboard_tasklet);
-	
-	pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_kbd_request_override);
-
+	input_register_handler(&kbd_handler);
 	return 0;
 }
diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/char/mem.c	Tue Aug 27 12:28:06 2002
@@ -210,6 +210,9 @@
 	return 0;
 }
 
+extern long vread(char *buf, char *addr, unsigned long count);
+extern long vwrite(char *buf, char *addr, unsigned long count);
+
 /*
  * This function reads the *virtual* memory as seen by the kernel.
  */
@@ -272,8 +275,6 @@
  	*ppos = p;
  	return virtr + read;
 }
-
-extern long vwrite(char *buf, char *addr, unsigned long count);
 
 /*
  * This function writes to the *virtual* memory as seen by the kernel.
diff -Nru a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
--- a/drivers/char/pc_keyb.c	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1253 +0,0 @@
-/*
- * linux/drivers/char/pc_keyb.c
- *
- * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
- * See keyboard.c for the whole history.
- *
- * Major cleanup by Martin Mares, May 1997
- *
- * Combined the keyboard and PS/2 mouse handling into one file,
- * because they share the same hardware.
- * Johan Myreen <jem@iki.fi> 1998-10-08.
- *
- * Code fixes to handle mouse ACKs properly.
- * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
- *
- */
-
-#include <linux/config.h>
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/smp_lock.h>
-#include <linux/kd.h>
-#include <linux/pm.h>
-
-#include <asm/keyboard.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/io.h>
-
-/* Some configuration switches are present in the include file... */
-
-#include <linux/pc_keyb.h>
-
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char pckbd_sysrq_xlate[128] =
-	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
-	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
-	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
-	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
-	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
-	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-	"\r\000/";					/* 0x60 - 0x6f */
-#endif
-
-static void kbd_write_command_w(int data);
-static void kbd_write_output_w(int data);
-#ifdef CONFIG_PSMOUSE
-static void aux_write_ack(int val);
-static void __aux_write_ack(int val);
-static int aux_reconnect = 0;
-#endif
-
-static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
-static unsigned char handle_kbd_event(void);
-
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected;
-static volatile unsigned char acknowledge;
-static volatile unsigned char resend;
-
-
-#if defined CONFIG_PSMOUSE
-/*
- *	PS/2 Auxiliary Device
- */
-
-static int __init psaux_init(void);
-
-#define AUX_RECONNECT1 0xaa	/* scancode1 when ps2 device is plugged (back) in */
-#define AUX_RECONNECT2 0x00	/* scancode2 when ps2 device is plugged (back) in */
- 
-static struct aux_queue *queue;	/* Mouse data buffer. */
-static int aux_count;
-static spinlock_t aux_count_lock = SPIN_LOCK_UNLOCKED;
-/* used when we send commands to the mouse that expect an ACK. */
-static unsigned char mouse_reply_expected;
-
-#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
-#define AUX_INTS_ON  (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
-
-#define MAX_RETRIES	60		/* some aux operations take long time*/
-#endif /* CONFIG_PSMOUSE */
-
-/*
- * Wait for keyboard controller input buffer to drain.
- *
- * Don't use 'jiffies' so that we don't depend on
- * interrupts..
- *
- * Quote from PS/2 System Reference Manual:
- *
- * "Address hex 0060 and address hex 0064 should be written only when
- * the input-buffer-full bit and output-buffer-full bit in the
- * Controller Status register are set 0."
- */
-
-static void kb_wait(void)
-{
-	unsigned long timeout = KBC_TIMEOUT;
-
-	do {
-		/*
-		 * "handle_kbd_event()" will handle any incoming events
-		 * while we wait - keypresses or mouse movement.
-		 */
-		unsigned char status = handle_kbd_event();
-
-		if (! (status & KBD_STAT_IBF))
-			return;
-		mdelay(1);
-		timeout--;
-	} while (timeout);
-#ifdef KBD_REPORT_TIMEOUTS
-	printk(KERN_WARNING "Keyboard timed out[1]\n");
-#endif
-}
-
-/*
- * Translation of escaped scancodes to keycodes.
- * This is now user-settable.
- * The keycodes 1-88,96-111,119 are fairly standard, and
- * should probably not be changed - changing might confuse X.
- * X also interprets scancode 0x5d (KEY_Begin).
- *
- * For 1-88 keycode equals scancode.
- */
-
-#define E0_KPENTER 96
-#define E0_RCTRL   97
-#define E0_KPSLASH 98
-#define E0_PRSCR   99
-#define E0_RALT    100
-#define E0_BREAK   101  /* (control-pause) */
-#define E0_HOME    102
-#define E0_UP      103
-#define E0_PGUP    104
-#define E0_LEFT    105
-#define E0_RIGHT   106
-#define E0_END     107
-#define E0_DOWN    108
-#define E0_PGDN    109
-#define E0_INS     110
-#define E0_DEL     111
-
-#define E1_PAUSE   119
-
-/*
- * The keycodes below are randomly located in 89-95,112-118,120-127.
- * They could be thrown away (and all occurrences below replaced by 0),
- * but that would force many users to use the `setkeycodes' utility, where
- * they needed not before. It does not matter that there are duplicates, as
- * long as no duplication occurs for any single keyboard.
- */
-#define SC_LIM 89
-
-#define FOCUS_PF1 85           /* actual code! */
-#define FOCUS_PF2 89
-#define FOCUS_PF3 90
-#define FOCUS_PF4 91
-#define FOCUS_PF5 92
-#define FOCUS_PF6 93
-#define FOCUS_PF7 94
-#define FOCUS_PF8 95
-#define FOCUS_PF9 120
-#define FOCUS_PF10 121
-#define FOCUS_PF11 122
-#define FOCUS_PF12 123
-
-#define JAP_86     124
-/* tfj@olivia.ping.dk:
- * The four keys are located over the numeric keypad, and are
- * labelled A1-A4. It's an rc930 keyboard, from
- * Regnecentralen/RC International, Now ICL.
- * Scancodes: 59, 5a, 5b, 5c.
- */
-#define RGN1 124
-#define RGN2 125
-#define RGN3 126
-#define RGN4 127
-
-static unsigned char high_keys[128 - SC_LIM] = {
-  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
-  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
-  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
-  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
-  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
-};
-
-/* BTC */
-#define E0_MACRO   112
-/* LK450 */
-#define E0_F13     113
-#define E0_F14     114
-#define E0_HELP    115
-#define E0_DO      116
-#define E0_F17     117
-#define E0_KPMINPLUS 118
-/*
- * My OmniKey generates e0 4c for  the "OMNI" key and the
- * right alt key does nada. [kkoller@nyx10.cs.du.edu]
- */
-#define E0_OK	124
-/*
- * New microsoft keyboard is rumoured to have
- * e0 5b (left window button), e0 5c (right window button),
- * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
- * [or: Windows_L, Windows_R, TaskMan]
- */
-#define E0_MSLW	125
-#define E0_MSRW	126
-#define E0_MSTM	127
-
-static unsigned char e0_keys[128] = {
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
-  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
-  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
-  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
-  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
-  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
-  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
-  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
-  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
-  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
-};
-
-int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
-	  return -EINVAL;
-	if (scancode < 128)
-	  high_keys[scancode - SC_LIM] = keycode;
-	else
-	  e0_keys[scancode - 128] = keycode;
-	return 0;
-}
-
-int pckbd_getkeycode(unsigned int scancode)
-{
-	return
-	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
-	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
-	    e0_keys[scancode - 128];
-}
-
-static int do_acknowledge(unsigned char scancode)
-{
-	if (reply_expected) {
-	  /* Unfortunately, we must recognise these codes only if we know they
-	   * are known to be valid (i.e., after sending a command), because there
-	   * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
-	   * keys with such codes :(
-	   */
-		if (scancode == KBD_REPLY_ACK) {
-			acknowledge = 1;
-			reply_expected = 0;
-			return 0;
-		} else if (scancode == KBD_REPLY_RESEND) {
-			resend = 1;
-			reply_expected = 0;
-			return 0;
-		}
-		/* Should not happen... */
-#if 0
-		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
-		       scancode);
-#endif
-	}
-	return 1;
-}
-
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		    char raw_mode)
-{
-	static int prev_scancode;
-
-	/* special prefix scancodes.. */
-	if (scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
-		return 0;
-	}
-
-	/* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
-	if (scancode == 0x00 || scancode == 0xff) {
-		prev_scancode = 0;
-		return 0;
-	}
-
-	scancode &= 0x7f;
-
-	if (prev_scancode) {
-	  /*
-	   * usually it will be 0xe0, but a Pause key generates
-	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
-	   */
-	  if (prev_scancode != 0xe0) {
-	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
-		  prev_scancode = 0x100;
-		  return 0;
-	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
-		  *keycode = E1_PAUSE;
-		  prev_scancode = 0;
-	      } else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-#endif
-		  prev_scancode = 0;
-		  return 0;
-	      }
-	  } else {
-	      prev_scancode = 0;
-	      /*
-	       *  The keyboard maintains its own internal caps lock and
-	       *  num lock statuses. In caps lock mode E0 AA precedes make
-	       *  code and E0 2A follows break code. In num lock mode,
-	       *  E0 2A precedes make code and E0 AA follows break code.
-	       *  We do our own book-keeping, so we will just ignore these.
-	       */
-	      /*
-	       *  For my keyboard there is no caps lock mode, but there are
-	       *  both Shift-L and Shift-R modes. The former mode generates
-	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
-	       *  So, we should also ignore the latter. - aeb@cwi.nl
-	       */
-	      if (scancode == 0x2a || scancode == 0x36)
-		return 0;
-
-	      if (e0_keys[scancode])
-		*keycode = e0_keys[scancode];
-	      else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-			   scancode);
-#endif
-		  return 0;
-	      }
-	  }
-	} else if (scancode >= SC_LIM) {
-	    /* This happens with the FOCUS 9000 keyboard
-	       Its keys PF1..PF12 are reported to generate
-	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
-	       Moreover, unless repeated, they do not generate
-	       key-down events, so we have to zero up_flag below */
-	    /* Also, Japanese 86/106 keyboards are reported to
-	       generate 0x73 and 0x7d for \ - and \ | respectively. */
-	    /* Also, some Brazilian keyboard is reported to produce
-	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
-
-	  *keycode = high_keys[scancode - SC_LIM];
-
-	  if (!*keycode) {
-	      if (!raw_mode) {
-#ifdef KBD_REPORT_UNKN
-		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
-			 " - ignored\n", scancode);
-#endif
-	      }
-	      return 0;
-	  }
- 	} else
-	  *keycode = scancode;
- 	return 1;
-}
-
-char pckbd_unexpected_up(unsigned char keycode)
-{
-	/* unexpected, but this can happen: maybe this was a key release for a
-	   FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
-	if (keycode >= SC_LIM || keycode == 85)
-	    return 0;
-	else
-	    return 0200;
-}
-
-int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) 
-{
-#if defined CONFIG_PSMOUSE
-       unsigned long flags;
-
-       if (rqst == PM_RESUME) {
-               if (queue) {                    /* Aux port detected */
-		       spin_lock_irqsave(&aux_count_lock, flags);
-              	       if ( aux_count == 0) {   /* Mouse not in use */ 
-                               spin_lock(&kbd_controller_lock);
-			       /*
-				* Dell Lat. C600 A06 enables mouse after resume.
-				* When user touches the pad, it posts IRQ 12
-				* (which we do not process), thus holding keyboard.
-				*/
-			       kbd_write_command(KBD_CCMD_MOUSE_DISABLE);
-			       /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */
-			       kb_wait();
-			       kbd_write_command(KBD_CCMD_WRITE_MODE);
-			       kb_wait();
-			       kbd_write_output(AUX_INTS_OFF);
-			       spin_unlock(&kbd_controller_lock);
-		       }
-		       spin_unlock_irqrestore(&aux_count_lock, flags);
-	       }
-       }
-#endif
-       return 0;
-}
-
-
-static inline void handle_mouse_event(unsigned char scancode)
-{
-#ifdef CONFIG_PSMOUSE
-	unsigned long flags;
-	static unsigned char prev_code;
-	if (mouse_reply_expected) {
-		if (scancode == AUX_ACK) {
-			mouse_reply_expected--;
-			return;
-		}
-		mouse_reply_expected = 0;
-	}
-	else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1
-		&& aux_reconnect) {
-		printk (KERN_INFO "PS/2 mouse reconnect detected\n");
-		queue->head = queue->tail = 0;	/* Flush input queue */
-		__aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
-		return;
-	}
-
-	prev_code = scancode;
-	add_mouse_randomness(scancode);
-	spin_lock_irqsave(&aux_count_lock, flags);
-	if ( aux_count ) {
-		int head = queue->head;
-
-		queue->buf[head] = scancode;
-		head = (head + 1) & (AUX_BUF_SIZE-1);
-		if (head != queue->tail) {
-			queue->head = head;
-			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
-			wake_up_interruptible(&queue->proc_list);
-		}
-	}
-	spin_unlock_irqrestore(&aux_count_lock, flags);
-#endif
-}
-
-static unsigned char kbd_exists = 1;
-
-static inline void handle_keyboard_event(unsigned char scancode)
-{
-#ifdef CONFIG_VT
-	kbd_exists = 1;
-	if (do_acknowledge(scancode))
-		handle_scancode(scancode, !(scancode & 0x80));
-#endif				
-	tasklet_schedule(&keyboard_tasklet);
-}	
-
-/*
- * This reads the keyboard status port, and does the
- * appropriate action.
- *
- * It requires that we hold the keyboard controller
- * spinlock.
- */
-static unsigned char handle_kbd_event(void)
-{
-	unsigned char status = kbd_read_status();
-	unsigned int work = 10000;
-
-	while ((--work > 0) && (status & KBD_STAT_OBF)) {
-		unsigned char scancode;
-
-		scancode = kbd_read_input();
-
-		/* Error bytes must be ignored to make the 
-		   Synaptics touchpads compaq use work */
-#if 1
-		/* Ignore error bytes */
-		if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
-#endif
-		{
-			if (status & KBD_STAT_MOUSE_OBF)
-				handle_mouse_event(scancode);
-			else
-				handle_keyboard_event(scancode);
-		}
-
-		status = kbd_read_status();
-	}
-		
-	if (!work)
-		printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status);
-
-	return status;
-}
-
-
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef CONFIG_VT
-	kbd_pt_regs = regs;
-#endif
-
-	spin_lock_irq(&kbd_controller_lock);
-	handle_kbd_event();
-	spin_unlock_irq(&kbd_controller_lock);
-}
-
-/*
- * send_data sends a character to the keyboard and waits
- * for an acknowledge, possibly retrying if asked to. Returns
- * the success status.
- *
- * Don't use 'jiffies', so that we don't depend on interrupts
- */
-static int send_data(unsigned char data)
-{
-	int retries = 3;
-
-	do {
-		unsigned long timeout = KBD_TIMEOUT;
-
-		acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */
-		resend = 0;
-		reply_expected = 1;
-		kbd_write_output_w(data);
-		for (;;) {
-			if (acknowledge)
-				return 1;
-			if (resend)
-				break;
-			mdelay(1);
-			if (!--timeout) {
-#ifdef KBD_REPORT_TIMEOUTS
-				printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data);
-#endif
-				return 0;
-			}
-		}
-	} while (retries-- > 0);
-#ifdef KBD_REPORT_TIMEOUTS
-	printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
-#endif
-	return 0;
-}
-
-void pckbd_leds(unsigned char leds)
-{
-	if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) {
-		send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
-		kbd_exists = 0;
-	}
-}
-
-#define DEFAULT_KEYB_REP_DELAY	250
-#define DEFAULT_KEYB_REP_RATE	30	/* cps */
-
-static struct kbd_repeat kbdrate={
-	DEFAULT_KEYB_REP_DELAY,
-	DEFAULT_KEYB_REP_RATE
-};
-
-static unsigned char parse_kbd_rate(struct kbd_repeat *r)
-{
-	static struct r2v{
-		int rate;
-		unsigned char val;
-	} kbd_rates[]={	{5,0x14},
-			{7,0x10},
-			{10,0x0c},
-			{15,0x08},
-			{20,0x04},
-			{25,0x02},
-			{30,0x00}
-	};
-	static struct d2v{
-		int delay;
-		unsigned char val;
-	} kbd_delays[]={{250,0},
-			{500,1},
-			{750,2},
-			{1000,3}
-	};
-	int rate=0,delay=0;
-	if (r != NULL){
-		int i,new_rate=30,new_delay=250;
-		if (r->rate <= 0)
-			r->rate=kbdrate.rate;
-		if (r->delay <= 0)
-			r->delay=kbdrate.delay;
-		for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++)
-			if (kbd_rates[i].rate == r->rate){
-				new_rate=kbd_rates[i].rate;
-				rate=kbd_rates[i].val;
-				break;
-			}
-		for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++)
-			if (kbd_delays[i].delay == r->delay){
-				new_delay=kbd_delays[i].delay;
-				delay=kbd_delays[i].val;
-				break;
-			}
-		r->rate=new_rate;
-		r->delay=new_delay;
-	}
-	return (delay << 5) | rate;
-}
-
-static int write_kbd_rate(unsigned char r)
-{
-	if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){
-		send_data(KBD_CMD_ENABLE); 	/* re-enable kbd if any errors */
-		return 0;
-	}else
-		return 1;
-}
-
-static int pckbd_rate(struct kbd_repeat *rep)
-{
-	if (rep == NULL)
-		return -EINVAL;
-	else{
-		unsigned char r=parse_kbd_rate(rep);
-		struct kbd_repeat old_rep;
-		memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat));
-		if (write_kbd_rate(r)){
-			memcpy(&kbdrate,rep,sizeof(struct kbd_repeat));
-			memcpy(rep,&old_rep,sizeof(struct kbd_repeat));
-			return 0;
-		}
-	}
-	return -EIO;
-}
-
-/*
- * In case we run on a non-x86 hardware we need to initialize both the
- * keyboard controller and the keyboard.  On a x86, the BIOS will
- * already have initialized them.
- *
- * Some x86 BIOSes do not correctly initialize the keyboard, so the
- * "kbd-reset" command line options can be given to force a reset.
- * [Ranger]
- */
-#ifdef __i386__
- int kbd_startup_reset __initdata = 0;
-#else
- int kbd_startup_reset __initdata = 1;
-#endif
-
-/* for "kbd-reset" cmdline param */
-static int __init kbd_reset_setup(char *str)
-{
-	kbd_startup_reset = 1;
-	return 1;
-}
-
-__setup("kbd-reset", kbd_reset_setup);
-
-#define KBD_NO_DATA	(-1)	/* No data */
-#define KBD_BAD_DATA	(-2)	/* Parity or other error */
-
-static int __init kbd_read_data(void)
-{
-	int retval = KBD_NO_DATA;
-	unsigned char status;
-
-	status = kbd_read_status();
-	if (status & KBD_STAT_OBF) {
-		unsigned char data = kbd_read_input();
-
-		retval = data;
-		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
-			retval = KBD_BAD_DATA;
-	}
-	return retval;
-}
-
-static void __init kbd_clear_input(void)
-{
-	int maxread = 100;	/* Random number */
-
-	do {
-		if (kbd_read_data() == KBD_NO_DATA)
-			break;
-	} while (--maxread);
-}
-
-static int __init kbd_wait_for_input(void)
-{
-	long timeout = KBD_INIT_TIMEOUT;
-
-	do {
-		int retval = kbd_read_data();
-		if (retval >= 0)
-			return retval;
-		mdelay(1);
-	} while (--timeout);
-	return -1;
-}
-
-static void kbd_write_command_w(int data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_command(data);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-}
-
-static void kbd_write_output_w(int data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_output(data);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-}
-
-#if defined(__alpha__)
-/*
- * Some Alphas cannot mask some/all interrupts, so we have to
- * make sure not to allow interrupts AT ALL when polling for
- * specific return values from the keyboard.
- *
- * I think this should work on any architecture, but for now, only Alpha.
- */
-static int kbd_write_command_w_and_wait(int data)
-{
-	unsigned long flags;
-	int input;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_command(data);
-	input = kbd_wait_for_input();
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-	return input;
-}
-
-static int kbd_write_output_w_and_wait(int data)
-{
-	unsigned long flags;
-	int input;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_output(data);
-	input = kbd_wait_for_input();
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-	return input;
-}
-#else
-static int kbd_write_command_w_and_wait(int data)
-{
-	kbd_write_command_w(data);
-	return kbd_wait_for_input();
-}
-
-static int kbd_write_output_w_and_wait(int data)
-{
-	kbd_write_output_w(data);
-	return kbd_wait_for_input();
-}
-#endif /* __alpha__ */
-
-#if defined CONFIG_PSMOUSE
-static void kbd_write_cmd(int cmd)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_command(KBD_CCMD_WRITE_MODE);
-	kb_wait();
-	kbd_write_output(cmd);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-}
-#endif /* CONFIG_PSMOUSE */
-
-static char * __init initialize_kbd(void)
-{
-	int status;
-
-#ifdef CONFIG_IA64
-	/*
-	 * This is not really IA-64 specific.  Probably ought to be done on all platforms
-	 * that are (potentially) legacy-free.
-	 */
-	if (kbd_read_status() == 0xff && kbd_read_input() == 0xff) {
-		kbd_exists = 0;
-		return "No keyboard controller preset";
-	}
-#endif
-
-	/*
-	 * Test the keyboard interface.
-	 * This seems to be the only way to get it going.
-	 * If the test is successful a x55 is placed in the input buffer.
-	 */
-	kbd_write_command_w(KBD_CCMD_SELF_TEST);
-	if (kbd_wait_for_input() != 0x55)
-		return "Keyboard failed self test";
-
-	/*
-	 * Perform a keyboard interface test.  This causes the controller
-	 * to test the keyboard clock and data lines.  The results of the
-	 * test are placed in the input buffer.
-	 */
-	kbd_write_command_w(KBD_CCMD_KBD_TEST);
-	if (kbd_wait_for_input() != 0x00)
-		return "Keyboard interface failed self test";
-
-	/*
-	 * Enable the keyboard by allowing the keyboard clock to run.
-	 */
-	kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
-
-	/*
-	 * Reset keyboard. If the read times out
-	 * then the assumption is that no keyboard is
-	 * plugged into the machine.
-	 * This defaults the keyboard to scan-code set 2.
-	 *
-	 * Set up to try again if the keyboard asks for RESEND.
-	 */
-	do {
-		kbd_write_output_w(KBD_CMD_RESET);
-		status = kbd_wait_for_input();
-		if (status == KBD_REPLY_ACK)
-			break;
-		if (status != KBD_REPLY_RESEND)
-			return "Keyboard reset failed, no ACK";
-	} while (1);
-
-	if (kbd_wait_for_input() != KBD_REPLY_POR)
-		return "Keyboard reset failed, no POR";
-
-	/*
-	 * Set keyboard controller mode. During this, the keyboard should be
-	 * in the disabled state.
-	 *
-	 * Set up to try again if the keyboard asks for RESEND.
-	 */
-	do {
-		kbd_write_output_w(KBD_CMD_DISABLE);
-		status = kbd_wait_for_input();
-		if (status == KBD_REPLY_ACK)
-			break;
-		if (status != KBD_REPLY_RESEND)
-			return "Disable keyboard: no ACK";
-	} while (1);
-
-	kbd_write_command_w(KBD_CCMD_WRITE_MODE);
-	kbd_write_output_w(KBD_MODE_KBD_INT
-			      | KBD_MODE_SYS
-			      | KBD_MODE_DISABLE_MOUSE
-			      | KBD_MODE_KCC);
-
-	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
-	if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC))
-	{
-		/*
-		 * If the controller does not support conversion,
-		 * Set the keyboard to scan-code set 1.
-		 */
-		kbd_write_output_w(0xF0);
-		kbd_wait_for_input();
-		kbd_write_output_w(0x01);
-		kbd_wait_for_input();
-	}
-
-	if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK)
-		return "Enable keyboard: no ACK";
-
-	/*
-	 * Finally, set the typematic rate to maximum.
-	 */
-	if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK)
-		return "Set rate: no ACK";
-	if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK)
-		return "Set rate: no 2nd ACK";
-
-	return NULL;
-}
-
-void __init pckbd_init_hw(void)
-{
-#ifndef CONFIG_SERIO_I8042
-
-	kbd_request_region();
-
-	/* Flush any pending input. */
-	kbd_clear_input();
-
-	if (kbd_startup_reset) {
-		char *msg = initialize_kbd();
-		if (msg)
-			printk(KERN_WARNING "initialize_kbd: %s\n", msg);
-#ifdef CONFIG_IA64
-		if (!kbd_exists)
-			return;
-#endif
-	}
-
-#if defined CONFIG_PSMOUSE
-	psaux_init();
-#endif
-
-	kbd_rate = pckbd_rate;
-
-	/* Ok, finally allocate the IRQ, and off we go.. */
-	kbd_request_irq(keyboard_interrupt);
-#endif
-}
-
-#if defined CONFIG_PSMOUSE
-
-static int __init aux_reconnect_setup (char *str)
-{
-	aux_reconnect = 1;
-	return 1;
-}
-
-__setup("psaux-reconnect", aux_reconnect_setup);
-
-/*
- * Check if this is a dual port controller.
- */
-static int __init detect_auxiliary_port(void)
-{
-	unsigned long flags;
-	int loops = 10;
-	int retval = 0;
-
-	/* Check if the BIOS detected a device on the auxiliary port. */
-	if (aux_device_present == 0xaa)
-		return 1;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-
-	/* Put the value 0x5A in the output buffer using the "Write
-	 * Auxiliary Device Output Buffer" command (0xD3). Poll the
-	 * Status Register for a while to see if the value really
-	 * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF
-	 * bit is also set to 1 in the Status Register, we assume this
-	 * controller has an Auxiliary Port (a.k.a. Mouse Port).
-	 */
-	kb_wait();
-	kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
-
-	kb_wait();
-	kbd_write_output(0x5a); /* 0x5a is a random dummy value. */
-
-	do {
-		unsigned char status = kbd_read_status();
-
-		if (status & KBD_STAT_OBF) {
-			(void) kbd_read_input();
-			if (status & KBD_STAT_MOUSE_OBF) {
-				printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
-				retval = 1;
-			}
-			break;
-		}
-		mdelay(1);
-	} while (--loops);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-
-	return retval;
-}
-
-/*
- * Send a byte to the mouse.
- */
-static void aux_write_dev(int val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	kb_wait();
-	kbd_write_command(KBD_CCMD_WRITE_MOUSE);
-	kb_wait();
-	kbd_write_output(val);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-}
-
-/*
- * Send a byte to the mouse & handle returned ack
- */
-static void __aux_write_ack(int val)
-{
-	kb_wait();
-	kbd_write_command(KBD_CCMD_WRITE_MOUSE);
-	kb_wait();
-	kbd_write_output(val);
-	/* we expect an ACK in response. */
-	mouse_reply_expected++;
-	kb_wait();
-}
-
-static void aux_write_ack(int val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	__aux_write_ack(val);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-}
-
-static unsigned char get_from_queue(void)
-{
-	unsigned char result;
-	unsigned long flags;
-
-	spin_lock_irqsave(&kbd_controller_lock, flags);
-	result = queue->buf[queue->tail];
-	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
-	spin_unlock_irqrestore(&kbd_controller_lock, flags);
-	return result;
-}
-
-
-static inline int queue_empty(void)
-{
-	return queue->head == queue->tail;
-}
-
-static int fasync_aux(int fd, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &queue->fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-
-/*
- * Random magic cookie for the aux device
- */
-#define AUX_DEV ((void *)queue)
-
-static int release_aux(struct inode * inode, struct file * file)
-{
-	unsigned long flags;
-	fasync_aux(-1, file, 0);
-	spin_lock_irqsave(&aux_count_lock, flags);
-	if ( --aux_count ) {
-		spin_unlock_irqrestore(&aux_count_lock, flags);
-		return 0;
-	}
-	spin_unlock_irqrestore(&aux_count_lock, flags);
-	kbd_write_cmd(AUX_INTS_OFF);			    /* Disable controller ints */
-	kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
-	aux_free_irq(AUX_DEV);
-	return 0;
-}
-
-/*
- * Install interrupt handler.
- * Enable auxiliary device.
- */
-
-static int open_aux(struct inode * inode, struct file * file)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&aux_count_lock, flags);
-	if ( aux_count++ ) {
-		spin_unlock_irqrestore(&aux_count_lock, flags);
-		return 0;
-	}
-	queue->head = queue->tail = 0;		/* Flush input queue */
-	spin_unlock_irqrestore(&aux_count_lock, flags);
-	ret = aux_request_irq(keyboard_interrupt, AUX_DEV);
-	spin_lock_irqsave(&aux_count_lock, flags);
-	if (ret) {
-		aux_count--;
-		spin_unlock_irqrestore(&aux_count_lock, flags);
-		return -EBUSY;
-	}
-	spin_unlock_irqrestore(&aux_count_lock, flags);
-	kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE);	/* Enable the
-							   auxiliary port on
-							   controller. */
-	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
-	kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
-	
-	mdelay(2);			/* Ensure we follow the kbc access delay rules.. */
-
-	send_data(KBD_CMD_ENABLE);	/* try to workaround toshiba4030cdt problem */
-	return 0;
-}
-
-/*
- * Put bytes from input queue to buffer.
- */
-
-static ssize_t read_aux(struct file * file, char * buffer,
-			size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t i = count;
-	unsigned char c;
-
-	if (queue_empty()) {
-		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		add_wait_queue(&queue->proc_list, &wait);
-repeat:
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (queue_empty() && !signal_pending(current)) {
-			schedule();
-			goto repeat;
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(&queue->proc_list, &wait);
-	}
-	while (i > 0 && !queue_empty()) {
-		c = get_from_queue();
-		put_user(c, buffer++);
-		i--;
-	}
-	if (count-i) {
-		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-		return count-i;
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-/*
- * Write to the aux device.
- */
-
-static ssize_t write_aux(struct file * file, const char * buffer,
-			 size_t count, loff_t *ppos)
-{
-	ssize_t retval = 0;
-
-	if (count) {
-		ssize_t written = 0;
-
-		if (count > 32)
-			count = 32; /* Limit to 32 bytes. */
-		do {
-			char c;
-			get_user(c, buffer++);
-			aux_write_dev(c);
-			written++;
-		} while (--count);
-		retval = -EIO;
-		if (written) {
-			retval = written;
-			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
-		}
-	}
-
-	return retval;
-}
-
-/* No kernel lock held - fine */
-static unsigned int aux_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &queue->proc_list, wait);
-	if (!queue_empty())
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations psaux_fops = {
-	read:		read_aux,
-	write:		write_aux,
-	poll:		aux_poll,
-	open:		open_aux,
-	release:	release_aux,
-	fasync:		fasync_aux,
-};
-
-/*
- * Initialize driver.
- */
-static struct miscdevice psaux_mouse = {
-	PSMOUSE_MINOR, "psaux", &psaux_fops
-};
-
-static int __init psaux_init(void)
-{
-#ifndef CONFIG_SERIO_I8042
-	int retval;
-
-	if (!detect_auxiliary_port())
-		return -EIO;
-
-	if ((retval = misc_register(&psaux_mouse)))
-		return retval;
-
-	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-	if (queue == NULL) {
-		printk(KERN_ERR "psaux_init(): out of memory\n");
-		misc_deregister(&psaux_mouse);
-		return -ENOMEM;
-	}
-	memset(queue, 0, sizeof(*queue));
-	queue->head = queue->tail = 0;
-	init_waitqueue_head(&queue->proc_list);
-
-#ifdef INITIALIZE_MOUSE
-	kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
-	aux_write_ack(AUX_SET_SAMPLE);
-	aux_write_ack(100);			/* 100 samples/sec */
-	aux_write_ack(AUX_SET_RES);
-	aux_write_ack(3);			/* 8 counts per mm */
-	aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
-#endif /* INITIALIZE_MOUSE */
-	kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
-	kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
-#endif
-
-	return 0;
-}
-
-#endif /* CONFIG_PSMOUSE */
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/char/vt.c	Tue Aug 27 12:28:08 2002
@@ -75,78 +75,6 @@
 #define GPLAST 0x3df
 #define GPNUM (GPLAST - GPFIRST + 1)
 
-/*
- * Generates sound of some frequency for some number of clock ticks
- *
- * If freq is 0, will turn off sound, else will turn it on for that time.
- * If msec is 0, will return immediately, else will sleep for msec time, then
- * turn sound off.
- *
- * We also return immediately, which is what was implied within the X
- * comments - KDMKTONE doesn't put the process to sleep.
- */
-
-#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
-    || (defined(__mips__) && defined(CONFIG_ISA)) \
-    || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \
-    || defined(__x86_64__)
-
-static void
-kd_nosound(unsigned long ignored)
-{
-	/* disable counter 2 */
-	outb(inb_p(0x61)&0xFC, 0x61);
-	return;
-}
-
-void
-_kd_mksound(unsigned int hz, unsigned int ticks)
-{
-	static struct timer_list sound_timer = { function: kd_nosound };
-	unsigned int count = 0;
-	unsigned long flags;
-
-	if (hz > 20 && hz < 32767)
-		count = 1193180 / hz;
-	
-	local_irq_save(flags); // FIXME: is this safe?
-	del_timer(&sound_timer);
-	if (count) {
-		/* enable counter 2 */
-		outb_p(inb_p(0x61)|3, 0x61);
-		/* set command for counter 2, 2 byte write */
-		outb_p(0xB6, 0x43);
-		/* select desired HZ */
-		outb_p(count & 0xff, 0x42);
-		outb((count >> 8) & 0xff, 0x42);
-
-		if (ticks) {
-			sound_timer.expires = jiffies+ticks;
-			add_timer(&sound_timer);
-		}
-	} else
-		kd_nosound(0);
-	local_irq_restore(flags);
-	return;
-}
-
-#else
-
-void
-_kd_mksound(unsigned int hz, unsigned int ticks)
-{
-}
-
-#endif
-
-int _kbd_rate(struct kbd_repeat *rep)
-{
-	return -EINVAL;
-}
-
-void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
-int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate;
-
 #define i (tmp.kb_index)
 #define s (tmp.kb_table)
 #define v (tmp.kb_value)
diff -Nru a/drivers/i2c/Config.in b/drivers/i2c/Config.in
--- a/drivers/i2c/Config.in	Tue Aug 27 12:28:08 2002
+++ b/drivers/i2c/Config.in	Tue Aug 27 12:28:08 2002
@@ -32,10 +32,10 @@
          dep_tristate '  Embedded Planet RPX Lite/Classic suppoort' CONFIG_I2C_RPXLITE $CONFIG_I2C_ALGO8XX
       fi
    fi
-   if [ "$CONFIG_405" = "y" ]; then
-      dep_tristate 'PPC 405 I2C Algorithm' CONFIG_I2C_PPC405_ALGO $CONFIG_I2C
-      if [ "$CONFIG_I2C_PPC405_ALGO" != "n" ]; then
-         dep_tristate '  PPC 405 I2C Adapter' CONFIG_I2C_PPC405_ADAP $CONFIG_I2C_PPC405_ALGO
+   if [ "$CONFIG_IBM_OCP" = "y" ]; then
+      dep_tristate 'IBM on-chip I2C Algorithm' CONFIG_I2C_IBM_OCP_ALGO $CONFIG_I2C
+      if [ "$CONFIG_I2C_IBM_OCP_ALGO" != "n" ]; then
+         dep_tristate '  IBM on-chip I2C Adapter' CONFIG_I2C_IBM_OCP_ADAP $CONFIG_I2C_IBM_OCP_ALGO
       fi
    fi
 
diff -Nru a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
--- a/drivers/i2c/i2c-algo-bit.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/i2c/i2c-algo-bit.c	Tue Aug 27 12:28:07 2002
@@ -21,7 +21,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-algo-bit.c,v 1.34 2001/11/19 18:45:02 mds Exp $ */
+/* $Id: i2c-algo-bit.c,v 1.37 2002/07/08 00:41:49 mds Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -143,7 +143,7 @@
 	/* scl, sda may not be high */
 	DEBPROTO(printk(" Sr "));
 	setsda(adap,1);
-	setscl(adap,1);
+	sclhi(adap);
 	udelay(adap->udelay);
 	
 	sdalo(adap);
diff -Nru a/drivers/i2c/i2c-algo-ibm_ocp.c b/drivers/i2c/i2c-algo-ibm_ocp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/i2c-algo-ibm_ocp.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,966 @@
+/*
+   -------------------------------------------------------------------------
+   i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters	    
+   -------------------------------------------------------------------------
+      
+   Ian DaSilva, MontaVista Software, Inc.
+   idasilva@mvista.com or source@mvista.com
+
+   Copyright 2000 MontaVista Software Inc.
+
+   Changes made to support the IIC peripheral on the IBM PPC 405
+
+
+   ---------------------------------------------------------------------------
+   This file was highly leveraged from i2c-algo-pcf.c, which was created
+   by Simon G. Vogl and Hans Berglund:
+
+
+     Copyright (C) 1995-1997 Simon G. Vogl
+                   1998-2000 Hans Berglund
+
+   With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and 
+   Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+   <mbailey@littlefeet-inc.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.
+   ---------------------------------------------------------------------------
+
+   History: 01/20/12 - Armin
+   	akuster@mvista.com
+   	ported up to 2.4.16+	
+
+   Version 02/03/25 - Armin
+       converted to ocp format
+       removed commented out or #if 0 code
+       added Gérard Basler's fix to iic_combined_transaction() such that it 
+       returns the number of successfully completed transfers .
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <linux/i2c.h>
+#include "i2c-algo-ibm_ocp.h"
+//ACC#include <asm/ocp.h>
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+ 	/* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 5
+
+/* debugging - slow down transfer to have a look at the data .. 	*/
+/* I use this with two leds&resistors, each one connected to sda,scl 	*/
+/* respectively. This makes sure that the algorithm works. Some chips   */
+/* might not like this, as they have an internal timeout of some mils	*/
+/*
+#define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+                        if (need_resched) schedule();
+*/
+
+
+/* ----- global variables ---------------------------------------------	*/
+
+#ifdef SLO_IO
+	int jif;
+#endif
+
+/* module parameters:
+ */
+static int i2c_debug=0;
+static int iic_scan=0;	/* have a look at what's hanging 'round		*/
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+
+#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val)
+#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg))
+
+#define IICO_I2C_SDAHIGH	0x0780
+#define IICO_I2C_SDALOW		0x0781
+#define IICO_I2C_SCLHIGH	0x0782
+#define IICO_I2C_SCLLOW		0x0783
+#define IICO_I2C_LINEREAD	0x0784
+
+#define IIC_SINGLE_XFER		0
+#define IIC_COMBINED_XFER	1
+
+#define IIC_ERR_LOST_ARB        -2
+#define IIC_ERR_INCOMPLETE_XFR  -3
+#define IIC_ERR_NACK            -1
+
+/* --- other auxiliary functions --------------------------------------	*/
+
+
+//
+// Description: Puts this process to sleep for a period equal to timeout 
+//
+static inline void iic_sleep(unsigned long timeout)
+{
+	schedule_timeout( timeout * HZ);
+}
+
+
+//
+// Description: This performs the IBM PPC 405 IIC initialization sequence
+// as described in the PPC405GP data book.
+//
+static int iic_init (struct i2c_algo_iic_data *adap)
+{
+	struct iic_regs *iic;	
+	struct iic_ibm *adap_priv_data = adap->data;
+	unsigned short	retval;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+        /* Clear master low master address */
+        iic_outb(adap,iic->lmadr, 0);
+
+        /* Clear high master address */
+        iic_outb(adap,iic->hmadr, 0);
+
+        /* Clear low slave address */
+        iic_outb(adap,iic->lsadr, 0);
+
+        /* Clear high slave address */
+        iic_outb(adap,iic->hsadr, 0);
+
+        /* Clear status */
+        iic_outb(adap,iic->sts, 0x0a);
+
+        /* Clear extended status */
+        iic_outb(adap,iic->extsts, 0x8f);
+
+        /* Set clock division */
+        iic_outb(adap,iic->clkdiv, 0x04);
+
+	retval = iic_inb(adap, iic->clkdiv);
+	DEB(printk("iic_init: CLKDIV register = %x\n", retval));
+
+        /* Enable interrupts on Requested Master Transfer Complete */
+        iic_outb(adap,iic->intmsk, 0x01);
+
+        /* Clear transfer count */
+        iic_outb(adap,iic->xfrcnt, 0x0);
+
+        /* Clear extended control and status */
+        iic_outb(adap,iic->xtcntlss, 0xf0);
+
+        /* Set mode control (flush master data buf, enable hold SCL, exit */
+        /* unknown state.                                                 */
+        iic_outb(adap,iic->mdcntl, 0x47);
+
+        /* Clear control register */
+        iic_outb(adap,iic->cntl, 0x0);
+
+        DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n"));
+        return 0;
+}
+
+
+//
+// Description: After we issue a transaction on the IIC bus, this function
+// is called.  It puts this process to sleep until we get an interrupt from
+// from the controller telling us that the transaction we requested in complete.
+//
+static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status) 
+{
+
+	int timeout = DEF_TIMEOUT;
+	int retval;
+	struct iic_regs *iic;
+	struct iic_ibm *adap_priv_data = adap->data;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+
+	*status = iic_inb(adap, iic->sts);
+#ifndef STUB_I2C
+
+	while (timeout-- && (*status & 0x01)) {
+	   adap->waitforpin(adap->data);
+	   *status = iic_inb(adap, iic->sts);
+	}
+#endif
+	if (timeout <= 0) {
+	   /* Issue stop signal on the bus, and force an interrupt */
+           retval = iic_inb(adap, iic->cntl);
+           iic_outb(adap, iic->cntl, retval | 0x80);
+           /* Clear status register */
+	   iic_outb(adap, iic->sts, 0x0a);
+	   /* Exit unknown bus state */
+	   retval = iic_inb(adap, iic->mdcntl);
+	   iic_outb(adap, iic->mdcntl, (retval | 0x02));
+
+	   // Check the status of the controller.  Does it still see a
+	   // pending transfer, even though we've tried to stop any
+	   // ongoing transaction?
+           retval = iic_inb(adap, iic->sts);
+           retval = retval & 0x01;
+           if(retval) {
+	      // The iic controller is hosed.  It is not responding to any
+	      // of our commands.  We have already tried to force it into
+	      // a known state, but it has not worked.  Our only choice now
+	      // is a soft reset, which will clear all registers, and force
+	      // us to re-initialize the controller.
+	      /* Soft reset */
+              iic_outb(adap, iic->xtcntlss, 0x01);
+              udelay(500);
+              iic_init(adap);
+	      /* Is the pending transfer bit in the sts reg finally cleared? */
+              retval = iic_inb(adap, iic->sts);
+              retval = retval & 0x01;
+              if(retval) {
+                 printk(KERN_CRIT "The IIC Controller is hosed.  A processor reset is required\n");
+              }
+	      // For some reason, even though the interrupt bit in this
+	      // register was set during iic_init, it didn't take.  We
+	      // need to set it again.  Don't ask me why....this is just what
+	      // I saw when testing timeouts.
+              iic_outb(adap, iic->intmsk, 0x01);
+           }
+	   return(-1);
+	}
+	else
+	   return(0);
+}
+
+
+//------------------------------------
+// Utility functions
+//
+
+
+//
+// Description: Look at the status register to see if there was an error
+// in the requested transaction.  If there is, look at the extended status
+// register and determine the exact cause.
+//
+int analyze_status(struct i2c_algo_iic_data *adap, int *error_code)
+{
+   int ret;
+   struct iic_regs *iic;
+   struct iic_ibm *adap_priv_data = adap->data;
+   iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	
+   ret = iic_inb(adap, iic->sts);
+   if(ret & 0x04) {
+      // Error occurred
+      ret = iic_inb(adap, iic->extsts);
+      if(ret & 0x04) {
+         // Lost arbitration
+         *error_code =  IIC_ERR_LOST_ARB;
+      }
+      if(ret & 0x02) {
+         // Incomplete transfer
+         *error_code = IIC_ERR_INCOMPLETE_XFR;
+      }
+      if(ret & 0x01) {
+         // Master transfer aborted by a NACK during the transfer of the 
+	 // address byte
+         *error_code = IIC_ERR_NACK;
+      }
+      return -1;
+   }
+   return 0;
+}
+
+
+//
+// Description: This function is called by the upper layers to do the
+// grunt work for a master send transaction
+//
+static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
+                         int count, int xfer_flag)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int wrcount, status, timeout;
+	int loops, remainder, i, j;
+	int ret, error_code;
+  	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+ 
+	if( count == 0 ) return 0;
+	wrcount = 0;
+	loops =  count / 4;
+	remainder = count % 4;
+
+	if((loops > 1) && (remainder == 0)) {
+	   for(i=0; i<(loops-1); i++) {
+       	      //
+   	      // Write four bytes to master data buffer
+	      //
+	      for(j=0; j<4; j++) {
+   	         iic_outb(adap, iic->mdbuf, 
+	         buf[wrcount++]);
+  	      }
+	      //
+	      // Issue command to IICO device to begin transmission
+	      //
+	      iic_outb(adap, iic->cntl, 0x35);
+	      //
+	      // Wait for transmission to complete.  When it does, 
+	      //loop to the top of the for statement and write the 
+	      // next four bytes.
+	      //
+	      timeout = wait_for_pin(adap, &status);
+	      if(timeout < 0) {
+	         //
+	         // Error handling
+	         //
+                 //printk(KERN_ERR "Error: write timeout\n");
+                 return wrcount;
+	      }
+	      ret = analyze_status(adap, &error_code);
+	      if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+                    // Return the number of bytes transferred
+                    ret = iic_inb(adap, iic->xfrcnt);
+                    ret = ret & 0x07;
+                    return (wrcount-4+ret);
+                 }
+                 else return error_code;
+              }
+           }
+	}
+	else if((loops >= 1) && (remainder > 0)){
+	   //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n");
+	   for(i=0; i<loops; i++) {
+              //
+              // Write four bytes to master data buffer
+              //
+              for(j=0; j<4; j++) {
+                 iic_outb(adap, iic->mdbuf,
+                 buf[wrcount++]);
+              }
+              //
+              // Issue command to IICO device to begin transmission
+              //
+              iic_outb(adap, iic->cntl, 0x35);
+              //
+              // Wait for transmission to complete.  When it does,
+              //loop to the top of the for statement and write the
+              // next four bytes.
+              //
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+                 //
+                 // Error handling
+                 //
+                 //printk(KERN_ERR "Error: write timeout\n");
+                 return wrcount;
+              }
+              ret = analyze_status(adap, &error_code);
+              if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+                    // Return the number of bytes transferred
+                    ret = iic_inb(adap, iic->xfrcnt);
+                    ret = ret & 0x07;
+                    return (wrcount-4+ret);
+                 }
+                 else return error_code;
+              }
+           }
+        }
+
+	//printk(KERN_DEBUG "iic_sendbytes: expedite write\n");
+	if(remainder == 0) remainder = 4;
+	// remainder = remainder - 1;
+	//
+	// Write the remaining bytes (less than or equal to 4)
+	//
+	for(i=0; i<remainder; i++) {
+	   iic_outb(adap, iic->mdbuf, buf[wrcount++]);
+	   //printk(KERN_DEBUG "iic_sendbytes:  data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1));
+	}
+        //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n");
+
+        if(xfer_flag == IIC_COMBINED_XFER) {
+           iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4)));
+        }
+	else {
+           iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4)));
+        }
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n"));
+	timeout = wait_for_pin(adap, &status);
+        if(timeout < 0) {
+       	   //
+           // Error handling
+           //
+           //printk(KERN_ERR "Error: write timeout\n");
+           return wrcount;
+        }
+        ret = analyze_status(adap, &error_code);
+        if(ret < 0) {
+           if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+              // Return the number of bytes transferred
+              ret = iic_inb(adap, iic->xfrcnt);
+              ret = ret & 0x07;
+              return (wrcount-4+ret);
+           }
+           else return error_code;
+        }
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n"));
+	return wrcount;
+}
+
+
+//
+// Description: Called by the upper layers to do the grunt work for
+// a master read transaction.
+//
+static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type)
+{
+	struct iic_regs *iic;
+	int rdcount=0, i, status, timeout;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int loops, remainder, j;
+        int ret, error_code;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	if(count == 0) return 0;
+	loops = count / 4;
+	remainder = count % 4;
+
+	//printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder);
+
+	if((loops > 1) && (remainder == 0)) {
+	//printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n");
+	   for(i=0; i<(loops-1); i++) {
+	      //
+              // Issue command to begin master read (4 bytes maximum)
+              //
+	      //printk(KERN_DEBUG "--->Issued read command\n");
+	      iic_outb(adap, iic->cntl, 0x37);
+	      //
+              // Wait for transmission to complete.  When it does,
+              // loop to the top of the for statement and write the
+              // next four bytes.
+              //
+	      //printk(KERN_DEBUG "--->Waiting for interrupt\n");
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+	         // Error Handler
+		 //printk(KERN_ERR "Error: read timed out\n");
+                 return rdcount;
+	      }
+              //printk(KERN_DEBUG "--->Got interrupt\n");
+
+              ret = analyze_status(adap, &error_code);
+	      if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR)
+                    return rdcount;
+                 else
+                    return error_code;
+              }
+
+	      for(j=0; j<4; j++) {
+                 // Wait for data to shuffle to top of data buffer
+                 // This value needs to optimized.
+		 udelay(1);
+	         buf[rdcount] = iic_inb(adap, iic->mdbuf);
+	         rdcount++;
+		 //printk(KERN_DEBUG "--->Read one byte\n");
+              }
+           }
+	}
+
+	else if((loops >= 1) && (remainder > 0)){
+	//printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n");
+	   for(i=0; i<loops; i++) {
+              //
+              // Issue command to begin master read (4 bytes maximum)
+              //
+              //printk(KERN_DEBUG "--->Issued read command\n");
+              iic_outb(adap, iic->cntl, 0x37);
+              //
+              // Wait for transmission to complete.  When it does,
+              // loop to the top of the for statement and write the
+              // next four bytes.
+              //
+              //printk(KERN_DEBUG "--->Waiting for interrupt\n");
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+                 // Error Handler
+                 //printk(KERN_ERR "Error: read timed out\n");
+                 return rdcount;
+              }
+              //printk(KERN_DEBUG "--->Got interrupt\n");
+
+              ret = analyze_status(adap, &error_code);
+              if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR)
+                    return rdcount;
+                 else
+                    return error_code;
+              }
+
+              for(j=0; j<4; j++) {
+                 // Wait for data to shuffle to top of data buffer
+                 // This value needs to optimized.
+                 udelay(1);
+                 buf[rdcount] = iic_inb(adap, iic->mdbuf);
+                 rdcount++;
+                 //printk(KERN_DEBUG "--->Read one byte\n");
+              }
+           }
+        }
+
+	//printk(KERN_DEBUG "iic_readbytes: expedite read\n");
+	if(remainder == 0) remainder = 4;
+	DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4))));
+
+	if(xfer_type == IIC_COMBINED_XFER) {
+	   iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4)));
+        }
+        else {
+	   iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4)));
+        }
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n"));
+        timeout = wait_for_pin(adap, &status);
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n"));
+        if(timeout < 0) {
+           // Error Handler
+	   //printk(KERN_ERR "Error: read timed out\n");
+           return rdcount;
+        }
+
+        ret = analyze_status(adap, &error_code);
+        if(ret < 0) {
+           if(error_code == IIC_ERR_INCOMPLETE_XFR)
+              return rdcount;
+           else
+              return error_code;
+        }
+
+	//printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n");
+	for(i=0; i<remainder; i++) {
+	   buf[rdcount] = iic_inb(adap, iic->mdbuf);
+	   // printk(KERN_DEBUG "iic_readbytes:  Character read = %x\n", buf[rdcount]);
+           rdcount++;
+	}
+
+	return rdcount;
+}
+
+
+//
+// Description:  This function implements combined transactions.  Combined
+// transactions consist of combinations of reading and writing blocks of data.
+// Each transfer (i.e. a read or a write) is separated by a repeated start
+// condition.
+//
+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 
+{
+   int i;
+   struct i2c_msg *pmsg;
+   int ret;
+
+   DEB2(printk(KERN_DEBUG "Beginning combined transaction\n"));
+	for(i=0; i < num; i++) {
+		pmsg = &msgs[i];
+		if(pmsg->flags & I2C_M_RD) {
+
+			// Last read or write segment needs to be terminated with a stop
+			if(i < num-1) {
+				DEB2(printk(KERN_DEBUG "This one is a read\n"));
+			}
+			else {
+				DEB2(printk(KERN_DEBUG "Doing the last read\n"));
+			}
+			ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
+
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+							"only read %d bytes.\n",ret));
+				return i;
+			}
+			else {
+				DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret));
+			}
+		}
+		else if(!(pmsg->flags & I2C_M_RD)) {
+
+			// Last read or write segment needs to be terminated with a stop
+			if(i < num-1) {
+				DEB2(printk(KERN_DEBUG "This one is a write\n"));
+			}
+			else {
+				DEB2(printk(KERN_DEBUG "Doing the last write\n"));
+			}
+			ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
+
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+							"only wrote %d bytes.\n",ret));
+				return i;
+			}
+			else {
+				DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret));
+			}
+		}
+	}
+ 
+	return num;
+}
+
+
+//
+// Description: Whenever we initiate a transaction, the first byte clocked
+// onto the bus after the start condition is the address (7 bit) of the
+// device we want to talk to.  This function manipulates the address specified
+// so that it makes sense to the hardware when written to the IIC peripheral.
+//
+// Note: 10 bit addresses are not supported in this driver, although they are
+// supported by the hardware.  This functionality needs to be implemented.
+//
+static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
+                                struct i2c_msg *msg, int retries) 
+{
+	struct iic_regs *iic;
+	unsigned short flags = msg->flags;
+	unsigned char addr;
+	struct iic_ibm *adap_priv_data = adap->data;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+//
+// The following segment for 10 bit addresses needs to be ported
+//
+/* Ten bit addresses not supported right now
+	if ( (flags & I2C_M_TEN)  ) { 
+		// a ten bit address
+		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+		// try extended address code...
+		ret = try_address(adap, addr, retries);
+		if (ret!=1) {
+			printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
+			return -EREMOTEIO;
+		}
+		// the remaining 8 bit address
+		iic_outb(adap,msg->addr & 0x7f);
+		// Status check comes here
+		if (ret != 1) {
+			printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n");
+			return -EREMOTEIO;
+		}
+		if ( flags & I2C_M_RD ) {
+			i2c_repstart(adap);
+			// okay, now switch into reading mode
+			addr |= 0x01;
+			ret = try_address(adap, addr, retries);
+			if (ret!=1) {
+				printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
+				return -EREMOTEIO;
+			}
+		}
+	} else ----------> // normal 7 bit address
+
+Ten bit addresses not supported yet */
+
+	addr = ( msg->addr << 1 );
+	if (flags & I2C_M_RD )
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR )
+		addr ^= 1;
+	//
+	// Write to the low slave address
+	//
+	iic_outb(adap, iic->lmadr, addr);
+	//
+	// Write zero to the high slave register since we are
+	// only using 7 bit addresses
+	//
+	iic_outb(adap, iic->hmadr, 0);
+
+	return 0;
+}
+
+
+//
+// Description: Prepares the controller for a transaction (clearing status
+// registers, data buffers, etc), and then calls either iic_readbytes or
+// iic_sendbytes to do the actual transaction.
+//
+static int iic_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[], 
+		    int num)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	struct i2c_msg *pmsg;
+	int i = 0;
+	int ret;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	pmsg = &msgs[i];
+
+	//
+	// Clear status register
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n"));
+	iic_outb(adap, iic->sts, 0x0a);
+
+	//
+	// Wait for any pending transfers to complete
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n"));
+	while((ret = iic_inb(adap, iic->sts)) == 0x01) {
+		;
+	}
+
+	//
+	// Flush master data buf
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n"));		
+	ret = iic_inb(adap, iic->mdcntl);
+	iic_outb(adap, iic->mdcntl, ret | 0x40);
+
+	//
+	// Load slave address
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n"));
+	ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
+
+        //
+        // Check to see if the bus is busy
+        //
+        ret = iic_inb(adap, iic->extsts);
+        // Mask off the irrelevent bits
+        ret = ret & 0x70;
+        // When the bus is free, the BCS bits in the EXTSTS register are 0b100
+        if(ret != 0x40) return IIC_ERR_LOST_ARB;
+
+	//
+	// Combined transaction (read and write)
+	//
+	if(num > 1) {
+           DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n"));
+           ret = iic_combined_transaction(i2c_adap, msgs, num);
+        }
+	//
+	// Read only
+	//
+	else if((num == 1) && (pmsg->flags & I2C_M_RD)) {
+	   //
+	   // Tell device to begin reading data from the  master data 
+	   //
+	   DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n"));
+	   ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	} 
+        //
+	// Write only
+	//
+	else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) {
+	   //
+	   // Write data to master data buffers and tell our device
+	   // to begin transmitting
+	   //
+	   DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n"));
+	   ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	}	
+
+	return ret;   
+}
+
+
+//
+// Description: Implements device specific ioctls.  Higher level ioctls can
+// be found in i2c-core.c and are typical of any i2c controller (specifying
+// slave address, timeouts, etc).  These ioctls take advantage of any hardware
+// features built into the controller for which this algorithm-adapter set
+// was written.  These ioctls allow you to take control of the data and clock
+// lines on the IBM PPC 405 IIC controller and set the either high or low,
+// similar to a GPIO pin.
+//
+static int algo_control(struct i2c_adapter *adapter, 
+	unsigned int cmd, unsigned long arg)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = adapter->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int ret=0;
+	int lines;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	lines = iic_inb(adap, iic->directcntl);
+
+	if (cmd == IICO_I2C_SDAHIGH) {
+	      lines = lines & 0x01;
+	      if( lines ) lines = 0x04;
+	      else lines = 0;
+	      iic_outb(adap, iic->directcntl,(0x08|lines));
+	}
+	else if (cmd == IICO_I2C_SDALOW) {
+	      lines = lines & 0x01;
+	      if( lines ) lines = 0x04;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x00|lines));
+	}
+	else if (cmd == IICO_I2C_SCLHIGH) {
+              lines = lines & 0x02;
+              if( lines ) lines = 0x08;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x04|lines));
+	}
+	else if (cmd == IICO_I2C_SCLLOW) {
+              lines = lines & 0x02;
+	      if( lines ) lines = 0x08;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x00|lines));
+	}
+	else if (cmd == IICO_I2C_LINEREAD) {
+	      ret = lines;
+	}
+	return ret;
+}
+
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+	       I2C_FUNC_PROTOCOL_MANGLING; 
+}
+
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm iic_algo = {
+	"IBM on-chip IIC algorithm",
+	I2C_ALGO_OCP,
+	iic_xfer,
+	NULL,
+	NULL,				/* slave_xmit		*/
+	NULL,				/* slave_recv		*/
+	algo_control,			/* ioctl		*/
+	iic_func,			/* functionality	*/
+};
+
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+
+
+//
+// Description: Register bus structure
+//
+int i2c_iic_add_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_iic_data *iic_adap = adap->algo_data;
+
+	DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n",
+	            adap->name));
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= iic_algo.id;
+	adap->algo = &iic_algo;
+
+	adap->timeout = 100;	/* default values, should	*/
+	adap->retries = 3;		/* be replaced by defines	*/
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	iic_init(iic_adap);
+	i2c_add_adapter(adap);
+
+	/* scan bus */
+	/* By default scanning the bus is turned off. */
+	if (iic_scan) {
+		printk(KERN_INFO " i2c-algo-iic.o: scanning bus %s.\n",
+		       adap->name);
+	}
+	return 0;
+}
+
+
+//
+// Done
+//
+int i2c_iic_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	if ((res = i2c_del_adapter(adap)) < 0)
+		return res;
+	DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: adapter unregistered: %s\n",adap->name));
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+
+//
+// Done
+//
+int __init i2c_algo_iic_init (void)
+{
+	printk(KERN_INFO "IBM On-chip iic (i2c) algorithm module 2002.27.03\n");
+	return 0;
+}
+
+
+void i2c_algo_iic_exit(void)
+{
+	return;
+}
+
+
+EXPORT_SYMBOL(i2c_iic_add_bus);
+EXPORT_SYMBOL(i2c_iic_del_bus);
+
+//
+// The MODULE_* macros resolve to nothing if MODULES is not defined
+// when this file is compiled.
+//
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("PPC 405 iic algorithm");
+
+MODULE_PARM(iic_test, "i");
+MODULE_PARM(iic_scan, "i");
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available");
+MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,
+        "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
+
+module_init(i2c_algo_iic_init);
+module_exit(i2c_algo_iic_exit);
diff -Nru a/drivers/i2c/i2c-algo-ibm_ocp.h b/drivers/i2c/i2c-algo-ibm_ocp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/i2c-algo-ibm_ocp.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,55 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-ibm_ocp.h i2c driver algorithms for IBM PPC 405 IIC adapters         */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1995-97 Simon G. Vogl
+                   1998-99 Hans Berglund
+
+    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.                */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl> */
+
+/* Modifications by MontaVista Software, August 2000
+   Changes made to support the IIC peripheral on the IBM PPC 405 */
+
+#ifndef I2C_ALGO_IIC_H
+#define I2C_ALGO_IIC_H 1
+
+/* --- Defines for pcf-adapters ---------------------------------------	*/
+#include <linux/i2c.h>
+
+struct i2c_algo_iic_data {
+	struct iic_regs *data;		/* private data for lolevel routines	*/
+	void (*setiic) (void *data, int ctl, int val);
+	int  (*getiic) (void *data, int ctl);
+	int  (*getown) (void *data);
+	int  (*getclock) (void *data);
+	void (*waitforpin) (void *data);     
+
+	/* local settings */
+	int udelay;
+	int mdelay;
+	int timeout;
+};
+
+
+#define I2C_IIC_ADAP_MAX	16
+
+
+int i2c_iic_add_bus(struct i2c_adapter *);
+int i2c_iic_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_IIC_H */
diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/i2c/i2c-core.c	Tue Aug 27 12:28:01 2002
@@ -18,9 +18,10 @@
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
-   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
+   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
+   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com>                */
 
-/* $Id: i2c-core.c,v 1.73 2002/03/03 17:37:44 mds Exp $ */
+/* $Id: i2c-core.c,v 1.83 2002/07/08 01:37:15 mds Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -371,7 +372,7 @@
 				struct i2c_client *client = adap->clients[j];
 				if (client != NULL && 
 				    client->driver == driver) {
-					DEB2(printk("i2c-core.o: "
+					DEB2(printk(KERN_DEBUG "i2c-core.o: "
 						    "detaching client %s:\n",
 					            client->name));
 					if ((res = driver->
@@ -1002,6 +1003,123 @@
 
 /* The SMBus parts */
 
+#define POLY    (0x1070U << 3) 
+static u8
+crc8(u16 data)
+{
+	int i;
+  
+	for(i = 0; i < 8; i++) {
+		if (data & 0x8000) 
+			data = data ^ POLY;
+		data = data << 1;
+	}
+	return (u8)(data >> 8);
+}
+
+/* CRC over count bytes in the first array plus the bytes in the rest
+   array if it is non-null. rest[0] is the (length of rest) - 1
+   and is included. */
+u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
+{
+	int i;
+
+	for(i = 0; i < count; i++)
+		crc = crc8((crc ^ first[i]) << 8);
+	if(rest != NULL)
+		for(i = 0; i <= rest[0]; i++)
+			crc = crc8((crc ^ rest[i]) << 8);
+	return crc;
+}
+
+u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
+{
+	return i2c_smbus_partial_pec(0, count, first, rest);
+}
+
+/* Returns new "size" (transaction type)
+   Note that we convert byte to byte_data and byte_data to word_data
+   rather than invent new xxx_PEC transactions. */
+int i2c_smbus_add_pec(u16 addr, u8 command, int size,
+                      union i2c_smbus_data *data)
+{
+	u8 buf[3];
+
+	buf[0] = addr << 1;
+	buf[1] = command;
+	switch(size) {
+		case I2C_SMBUS_BYTE:
+			data->byte = i2c_smbus_pec(2, buf, NULL);
+			size = I2C_SMBUS_BYTE_DATA;
+			break;
+		case I2C_SMBUS_BYTE_DATA:
+			buf[2] = data->byte;
+			data->word = buf[2] ||
+			            (i2c_smbus_pec(3, buf, NULL) << 8);
+			size = I2C_SMBUS_WORD_DATA;
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			/* unsupported */
+			break;
+		case I2C_SMBUS_BLOCK_DATA:
+			data->block[data->block[0] + 1] =
+			             i2c_smbus_pec(2, buf, data->block);
+			size = I2C_SMBUS_BLOCK_DATA_PEC;
+			break;
+	}
+	return size;	
+}
+
+int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
+                        union i2c_smbus_data *data)
+{
+	u8 buf[3], rpec, cpec;
+
+	buf[1] = command;
+	switch(size) {
+		case I2C_SMBUS_BYTE_DATA:
+			buf[0] = (addr << 1) | 1;
+			cpec = i2c_smbus_pec(2, buf, NULL);
+			rpec = data->byte;
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			buf[0] = (addr << 1) | 1;
+			buf[2] = data->word & 0xff;
+			cpec = i2c_smbus_pec(3, buf, NULL);
+			rpec = data->word >> 8;
+			break;
+		case I2C_SMBUS_WORD_DATA_PEC:
+			/* unsupported */
+			cpec = rpec = 0;
+			break;
+		case I2C_SMBUS_PROC_CALL_PEC:
+			/* unsupported */
+			cpec = rpec = 0;
+			break;
+		case I2C_SMBUS_BLOCK_DATA_PEC:
+			buf[0] = (addr << 1);
+			buf[2] = (addr << 1) | 1;
+			cpec = i2c_smbus_pec(3, buf, data->block);
+			rpec = data->block[data->block[0] + 1];
+			break;
+		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+			buf[0] = (addr << 1) | 1;
+			rpec = i2c_smbus_partial_pec(partial, 1,
+			                             buf, data->block);
+			cpec = data->block[data->block[0] + 1];
+			break;
+		default:
+			cpec = rpec = 0;
+			break;
+	}
+	if(rpec != cpec) {
+		DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n",
+		           rpec, cpec));
+		return -1;
+	}
+	return 0;	
+}
+
 extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
@@ -1020,8 +1138,9 @@
 
 extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
 {
+	union i2c_smbus_data data;	/* only for PEC */
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
 }
 
 extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
@@ -1099,8 +1218,8 @@
 {
 	union i2c_smbus_data data;
 	int i;
-	if (length > 32)
-		length = 32;
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
 	for (i = 1; i <= length; i++)
 		data.block[i] = values[i-1];
 	data.block[0] = length;
@@ -1110,6 +1229,26 @@
 }
 
 /* Returns the number of read bytes */
+extern s32 i2c_smbus_block_process_call(struct i2c_client * client,
+                                        u8 command, u8 length, u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > I2C_SMBUS_BLOCK_MAX - 1)
+		return -1;
+	data.block[0] = length;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	if(i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+	                  I2C_SMBUS_WRITE, command,
+	                  I2C_SMBUS_BLOCK_PROC_CALL, &data))
+		return -1;
+	for (i = 1; i <= data.block[0]; i++)
+		values[i-1] = data.block[i];
+	return data.block[0];
+}
+
+/* Returns the number of read bytes */
 extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
                                          u8 command, u8 *values)
 {
@@ -1131,8 +1270,8 @@
 {
 	union i2c_smbus_data data;
 	int i;
-	if (length > 32)
-		length = 32;
+	if (length > I2C_SMBUS_I2C_BLOCK_MAX)
+		length = I2C_SMBUS_I2C_BLOCK_MAX;
 	for (i = 1; i <= length; i++)
 		data.block[i] = values[i-1];
 	data.block[0] = length;
@@ -1194,34 +1333,43 @@
 		break;
 	case I2C_SMBUS_PROC_CALL:
 		num = 2; /* Special case */
+		read_write = I2C_SMBUS_READ;
 		msg[0].len = 3;
 		msg[1].len = 2;
 		msgbuf0[1] = data->word & 0xff;
 		msgbuf0[2] = (data->word >> 8) & 0xff;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
+	case I2C_SMBUS_BLOCK_DATA_PEC:
 		if (read_write == I2C_SMBUS_READ) {
-			printk(KERN_ERR "i2c-core.o: Block read not supported under "
-			       "I2C emulation!\n");
-		return -1;
+			printk(KERN_ERR "i2c-core.o: Block read not supported "
+			       "under I2C emulation!\n");
+			return -1;
 		} else {
 			msg[0].len = data->block[0] + 2;
-			if (msg[0].len > 34) {
+			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
 				printk(KERN_ERR "i2c-core.o: smbus_access called with "
 				       "invalid block write size (%d)\n",
 				       data->block[0]);
 				return -1;
 			}
+			if(size == I2C_SMBUS_BLOCK_DATA_PEC)
+				(msg[0].len)++;
 			for (i = 1; i <= msg[0].len; i++)
 				msgbuf0[i] = data->block[i-1];
 		}
 		break;
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+	case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+		printk(KERN_ERR "i2c-core.o: Block process call not supported "
+		       "under I2C emulation!\n");
+		return -1;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
 		if (read_write == I2C_SMBUS_READ) {
-			msg[1].len = 32;
+			msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;
 		} else {
 			msg[0].len = data->block[0] + 2;
-			if (msg[0].len > 34) {
+			if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 2) {
 				printk("i2c-core.o: i2c_smbus_xfer_emulated called with "
 				       "invalid block write size (%d)\n",
 				       data->block[0]);
@@ -1254,8 +1402,8 @@
 				break;
 			case I2C_SMBUS_I2C_BLOCK_DATA:
 				/* fixed at 32 for now */
-				data->block[0] = 32;
-				for (i = 0; i < 32; i++)
+				data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;
+				for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)
 					data->block[i+1] = msgbuf1[i];
 				break;
 		}
@@ -1268,7 +1416,29 @@
                    union i2c_smbus_data * data)
 {
 	s32 res;
-	flags = flags & I2C_M_TEN;
+	int swpec = 0;
+	u8 partial = 0;
+
+	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+	if((flags & I2C_CLIENT_PEC) &&
+	   !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) {
+		swpec = 1;
+		if(read_write == I2C_SMBUS_READ &&
+		   size == I2C_SMBUS_BLOCK_DATA)
+			size = I2C_SMBUS_BLOCK_DATA_PEC;
+		else if(size == I2C_SMBUS_PROC_CALL)
+			size = I2C_SMBUS_PROC_CALL_PEC;
+		else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {
+			i2c_smbus_add_pec(addr, command,
+		                          I2C_SMBUS_BLOCK_DATA, data);
+			partial = data->block[data->block[0] + 1];
+			size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;
+		} else if(read_write == I2C_SMBUS_WRITE &&
+		          size != I2C_SMBUS_QUICK &&
+		          size != I2C_SMBUS_I2C_BLOCK_DATA)
+			size = i2c_smbus_add_pec(addr, command, size, data);
+	}
+
 	if (adapter->algo->smbus_xfer) {
 		I2C_LOCK(adapter);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
@@ -1277,6 +1447,14 @@
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
 	                                      command,size,data);
+
+	if(res >= 0 && swpec &&
+	   size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
+	   (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||
+	    size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {
+		if(i2c_smbus_check_pec(addr, command, size, partial, data))
+			return -1;
+	}
 	return res;
 }
 
diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/i2c/i2c-dev.c	Tue Aug 27 12:28:08 2002
@@ -28,7 +28,7 @@
 /* The devfs code is contributed by Philipp Matthias Hahn 
    <pmhahn@titan.lahn.de> */
 
-/* $Id: i2c-dev.c,v 1.44 2001/11/19 18:45:02 mds Exp $ */
+/* $Id: i2c-dev.c,v 1.46 2002/07/06 02:07:39 mds Exp $ */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -236,6 +236,12 @@
 		else
 			client->flags &= ~I2C_M_TEN;
 		return 0;
+	case I2C_PEC:
+		if (arg)
+			client->flags |= I2C_CLIENT_PEC;
+		else
+			client->flags &= ~I2C_CLIENT_PEC;
+		return 0;
 	case I2C_FUNCS:
 		funcs = i2c_get_functionality(client->adapter);
 		return (copy_to_user((unsigned long *)arg,&funcs,
@@ -312,7 +318,8 @@
 		    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
 		    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
 		    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
-		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
+		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+		    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
 #ifdef DEBUG
 			printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
 			       data_arg.size);
@@ -355,10 +362,11 @@
 		else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
 		         (data_arg.size == I2C_SMBUS_PROC_CALL))
 			datasize = sizeof(data_arg.data->word);
-		else /* size == I2C_SMBUS_BLOCK_DATA */
+		else /* size == smbus block, i2c block, or block proc. call */
 			datasize = sizeof(data_arg.data->block);
 
 		if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		    (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
 		    (data_arg.read_write == I2C_SMBUS_WRITE)) {
 			if (copy_from_user(&temp, data_arg.data, datasize))
 				return -EFAULT;
@@ -367,6 +375,7 @@
 		      data_arg.read_write,
 		      data_arg.command,data_arg.size,&temp);
 		if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		              (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
 			      (data_arg.read_write == I2C_SMBUS_READ))) {
 			if (copy_to_user(data_arg.data, &temp, datasize))
 				return -EFAULT;
@@ -534,6 +543,8 @@
 	}
 	return 0;
 }
+
+EXPORT_NO_SYMBOLS;
 
 #ifdef MODULE
 
diff -Nru a/drivers/i2c/i2c-elektor.c b/drivers/i2c/i2c-elektor.c
--- a/drivers/i2c/i2c-elektor.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/i2c/i2c-elektor.c	Tue Aug 27 12:27:57 2002
@@ -55,11 +55,7 @@
   in some functions, called from the algo-pcf module. Sometimes it's
   need to be rewriten - but for now just remove this for simpler reading */
 
-#if (LINUX_VERSION_CODE < 0x020301)
-static struct wait_queue *pcf_wait = NULL;
-#else
 static wait_queue_head_t pcf_wait;
-#endif
 static int pcf_pending;
 
 /* ----- global defines -----------------------------------------------	*/
@@ -280,9 +276,7 @@
 		base = DEFAULT_BASE;
 	}
 
-#if (LINUX_VERSION_CODE >= 0x020301)
 	init_waitqueue_head(&pcf_wait);
-#endif
 	if (pcf_isa_init() == 0) {
 		if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) {
 			pcf_isa_exit();
@@ -297,6 +291,7 @@
 	return 0;
 }
 
+EXPORT_NO_SYMBOLS;
 
 #ifdef MODULE
 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
diff -Nru a/drivers/i2c/i2c-frodo.c b/drivers/i2c/i2c-frodo.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/i2c-frodo.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,118 @@
+
+/*
+ * linux/drivers/i2c/i2c-frodo.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
+ * Development board (Frodo).
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+static void frodo_setsda (void *data,int state)
+{
+	if (state)
+		FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
+	else
+		FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
+}
+
+static void frodo_setscl (void *data,int state)
+{
+	if (state)
+		FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
+	else
+		FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
+}
+
+static int frodo_getsda (void *data)
+{
+	return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
+}
+
+static int frodo_getscl (void *data)
+{
+	return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
+}
+
+static struct i2c_algo_bit_data bit_frodo_data = {
+	setsda:		frodo_setsda,
+	setscl:		frodo_setscl,
+	getsda:		frodo_getsda,
+	getscl:		frodo_getscl,
+	udelay:		80,
+	mdelay:		80,
+	timeout:	100
+};
+
+static int frodo_client_register (struct i2c_client *client)
+{
+	return (0);
+}
+
+static int frodo_client_unregister (struct i2c_client *client)
+{
+	return (0);
+}
+
+static void frodo_inc_use (struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void frodo_dec_use (struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct i2c_adapter frodo_ops = {
+	name:				"Frodo adapter driver",
+	id:					I2C_HW_B_FRODO,
+	algo:				NULL,
+	algo_data:			&bit_frodo_data,
+	inc_use:			frodo_inc_use,
+	dec_use:			frodo_dec_use,
+	client_register:	frodo_client_register,
+	client_unregister:	frodo_client_unregister
+};
+
+static int __init i2c_frodo_init (void)
+{
+	return (i2c_bit_add_bus (&frodo_ops));
+}
+
+EXPORT_NO_SYMBOLS;
+
+static void __exit i2c_frodo_exit (void)
+{
+	i2c_bit_del_bus (&frodo_ops);
+}
+
+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
+MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE ("GPL");
+#endif	/* #ifdef MODULE_LICENSE */
+
+EXPORT_NO_SYMBOLS;
+
+module_init (i2c_frodo_init);
+module_exit (i2c_frodo_exit);
+
diff -Nru a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c
--- a/drivers/i2c/i2c-proc.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/i2c/i2c-proc.c	Tue Aug 27 12:28:07 2002
@@ -60,6 +60,7 @@
 static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX];
 
 static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX];
+static unsigned short i2c_inodes[SENSORS_ENTRY_MAX];
 
 static ctl_table sysctl_table[] = {
 	{CTL_DEV, "dev", NULL, 0, 0555},
@@ -172,7 +173,7 @@
 		printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n");
 		kfree(new_table);
 		kfree(name);
-		return -ENOMEM;
+		return -EPERM;
 	}
 
 	i2c_entries[id - 256] = new_header;
@@ -188,6 +189,8 @@
 		return id;
 	}
 #endif				/* DEBUG */
+	i2c_inodes[id - 256] =
+	    new_header->ctl_table->child->child->de->low_ino;
 	new_header->ctl_table->child->child->de->owner = controlling_mod;
 
 	return id;
@@ -208,6 +211,49 @@
 		i2c_entries[id] = NULL;
 		i2c_clients[id] = NULL;
 	}
+}
+
+/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o 
+   impossible if some process still uses it or some file in it */
+void i2c_fill_inode(struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+}
+
+/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading
+   the corresponding module impossible if some process still uses it or
+   some file in it */
+void i2c_dir_fill_inode(struct inode *inode, int fill)
+{
+	int i;
+	struct i2c_client *client;
+
+#ifdef DEBUG
+	if (!inode) {
+		printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n");
+		return;
+	}
+#endif				/* def DEBUG */
+
+	for (i = 0; i < SENSORS_ENTRY_MAX; i++)
+		if (i2c_clients[i]
+		    && (i2c_inodes[i] == inode->i_ino)) break;
+#ifdef DEBUG
+	if (i == SENSORS_ENTRY_MAX) {
+		printk
+		    (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n",
+		     inode->i_ino);
+		return;
+	}
+#endif				/* def DEBUG */
+	client = i2c_clients[i];
+	if (fill)
+		client->driver->inc_use(client);
+	else
+		client->driver->dec_use(client);
 }
 
 int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp,
diff -Nru a/drivers/i2c/i2c-rpx.c b/drivers/i2c/i2c-rpx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/i2c-rpx.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,136 @@
+/*
+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * RPX lite specific parts of the i2c interface
+ * Update:  There actually isn't anything RPXLite-specific about this module.
+ * This should work for most any 8xx board.  The console messages have been 
+ * changed to eliminate RPXLite references.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/parport.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8xx.h>
+
+static void
+rpx_iic_init(struct i2c_algo_8xx_data *data)
+{
+	volatile cpm8xx_t *cp;
+	volatile immap_t *immap;
+
+	cp = cpmp;	/* Get pointer to Communication Processor */
+	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
+
+	data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+	/* Check for and use a microcode relocation patch.
+	*/
+	if ((data->reloc = data->iip->iic_rpbase))
+		data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
+		
+	data->i2c = (i2c8xx_t *)&(immap->im_i2c);
+	data->cp = cp;
+
+	/* Initialize Port B IIC pins.
+	*/
+	cp->cp_pbpar |= 0x00000030;
+	cp->cp_pbdir |= 0x00000030;
+	cp->cp_pbodr |= 0x00000030;
+
+	/* Allocate space for two transmit and two receive buffer
+	 * descriptors in the DP ram.
+	 */
+	data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4);
+
+	/* ptr to i2c area */
+	data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
+}
+
+static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
+{
+	/* install interrupt handler */
+	cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
+
+	return 0;
+}
+
+static int rpx_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int rpx_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void rpx_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+static void rpx_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct i2c_algo_8xx_data rpx_data = {
+	setisr: rpx_install_isr
+};
+
+
+static struct i2c_adapter rpx_ops = {
+	"m8xx",
+	I2C_HW_MPC8XX_EPON,
+	NULL,
+	&rpx_data,
+	rpx_inc_use,
+	rpx_dec_use,
+	rpx_reg,
+	rpx_unreg,
+};
+
+int __init i2c_rpx_init(void)
+{
+	printk("i2c-rpx.o: i2c MPC8xx module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+
+	/* reset hardware to sane state */
+	rpx_iic_init(&rpx_data);
+
+	if (i2c_8xx_add_bus(&rpx_ops) < 0) {
+		printk("i2c-rpx: Unable to register with I2C\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void __exit i2c_rpx_exit(void)
+{
+	i2c_8xx_del_bus(&rpx_ops);
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
+
+module_init(i2c_rpx_init);
+module_exit(i2c_rpx_exit);
+#endif
+
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/Config.in	Tue Aug 27 12:28:08 2002
@@ -1,132 +1,158 @@
 #
-# ATA/ATAPI block device driver configuration
+# IDE ATA ATAPI Block device driver configuration
 #
-dep_tristate 'Enhanced ATA/ATAPI device (disk,cdrom,...) support' CONFIG_BLK_DEV_IDE $CONFIG_IDE
+# Andre Hedrick <andre@linux-ide.org>
+#
+mainmenu_option next_comment
+comment 'IDE, ATA and ATAPI Block devices'
+
+dep_tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE $CONFIG_IDE
+comment 'Please see Documentation/ide.txt for help/info on IDE drives'
 if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
-   dep_bool '  Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86
-   define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE
 
-   dep_tristate '  ATA disk support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
-   dep_bool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
-   dep_bool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
-   
-   dep_tristate '  ATAPI device support (CD-ROM, floppy)' CONFIG_ATAPI $CONFIG_BLK_DEV_IDE
-   dep_tristate '    CD-ROM support' CONFIG_BLK_DEV_IDECD $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE
-   dep_tristate '    Tape support' CONFIG_BLK_DEV_IDETAPE $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE
-   dep_tristate '    Floppy support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE
-   dep_tristate '    SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
-   
-   dep_tristate '  PCMCIA/CardBus support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
-
-   comment 'ATA host controller support'
-   dep_bool '  RZ1000 bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-   dep_bool '  CMD640 bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
-   dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
-   dep_bool '  ISA-PNP support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
-   if [ "$CONFIG_PCI" != "n" ]; then
-      comment '  PCI host controller support'
-      dep_bool '    Boot off-board controllers first' CONFIG_BLK_DEV_OFFBOARD $CONFIG_PCI
-      dep_bool '    Sharing PCI ATA interrupts' CONFIG_IDEPCI_SHARE_IRQ $CONFIG_PCI
-      dep_bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_PCI
-      dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '      Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
-      define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    Tagged command queueing (DANGEROUS)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-      dep_bool '      TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
-      if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then
-         int '      Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
-      fi
-      dep_bool '    Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL
-      dep_bool '    Acard (Artop) chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '      ATP865 burst mode' CONFIG_AEC6280_BURST $CONFIG_BLK_DEV_AEC62XX
-      dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 $CONFIG_EXPERIMENTAL
-      dep_bool '    AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '      HPT34X AUTODMA support (EXPERIMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
-      dep_bool '    HPT36X/37X chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-      if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
-         dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-         dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
-      fi
-      dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_PCI $CONFIG_EXPERIMENTAL
-      dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
-      dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-      dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-      dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-      dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    VIA chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEDMA_PCI
-   fi
-   if [ "$CONFIG_ALL_PPC" = "y" ]; then
-      bool '    Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
-      dep_bool '      PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC
-      dep_bool '        Use DMA by default' CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC
-      if [ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" ]; then
-	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC
+   dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+   dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+   dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
+
+   define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
+   dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    IBM Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
+
+   define_bool CONFIG_BLK_DEV_COMMERIAL n
+   dep_mbool '    TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL
+
+   dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
+   dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+   dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+   dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+   dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
+
+   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+#   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
+
+   comment 'IDE chipset support/bugfixes'
+   if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
+      dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
+      dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
+      dep_bool '  ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
+      if [ "$CONFIG_PCI" = "y" ]; then
+	 dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+	 define_bool CONFIG_BLK_DEV_IDEPCI y
+	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
+	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
+	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+	    dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+            dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
+	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
+	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
+	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+  	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
+	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
+	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
+	    fi
+	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
+	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
+	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
+	    fi
+	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+	    dep_bool '    Pacific Digital ADMA100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
+	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
+	    dep_bool '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_bool '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_bool '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
+	       bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	    fi
+         fi
+      fi
+      if [ "$CONFIG_ALL_PPC" = "y" ]; then
+	 bool '    Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+	 dep_bool '      PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC
+	 dep_bool '        Use DMA by default' CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC
+	 if [ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" ]; then
+	   define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC
+	 fi
+	 if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
+	   define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC
+	 fi
+      fi
+      if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
+	 bool '  SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM
+      fi
+      if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+	 dep_bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN
+	 dep_bool '      ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE
+	 dep_bool '        Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO $CONFIG_BLK_DEV_IDEDMA_ICS
+	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS
+	 dep_bool '    RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN
+      fi
+      if [ "$CONFIG_AMIGA" = "y" ]; then
+	 dep_bool '  Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA
+	 dep_mbool '    Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL
+      fi
+      if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 dep_mbool '  Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
+      fi
+      if [ "$CONFIG_ATARI" = "y" ]; then
+	 dep_bool '  Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI
+      fi
+      if [ "$CONFIG_MAC" = "y" ]; then
+	 dep_bool '  Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE $CONFIG_MAC
+      fi
+      if [ "$CONFIG_Q40" = "y" ]; then
+	 dep_bool '  Q40/Q60 IDE interface support' CONFIG_BLK_DEV_Q40IDE $CONFIG_Q40
+      fi
+      if [ "$CONFIG_8xx" = "y" ]; then
+         dep_bool '  MPC8xx IDE support' CONFIG_BLK_DEV_MPC8xx_IDE $CONFIG_8xx
       fi
-   fi
-   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-      dep_bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN
-      dep_bool '      ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE
-      dep_bool '        Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO $CONFIG_BLK_DEV_IDEDMA_ICS
-      define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS
-      dep_bool '    RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN
-   fi
-   if [ "$CONFIG_AMIGA" = "y" ]; then
-      dep_bool '  Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA
-      dep_mbool '    Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL
-   fi
-   if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_mbool '  Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
-   fi
-   if [ "$CONFIG_ATARI" = "y" ]; then
-      dep_bool '  Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI
-   fi
-   if [ "$CONFIG_MAC" = "y" ]; then
-      dep_bool '  Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE $CONFIG_MAC
-   fi
-   if [ "$CONFIG_Q40" = "y" ]; then
-      dep_bool '  Q40/Q60 IDE interface support' CONFIG_BLK_DEV_Q40IDE $CONFIG_Q40
-   fi
-   if [ "$CONFIG_8xx" = "y" ]; then
-      dep_bool '  MPC8xx IDE support' CONFIG_BLK_DEV_MPC8xx_IDE $CONFIG_8xx
-   fi
 
-   if [ "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
-      choice 'Type of MPC8xx IDE interface'		\
-	     "8xx_PCCARD	CONFIG_IDE_8xx_PCCARD	\
-	      8xx_DIRECT	CONFIG_IDE_8xx_DIRECT	\
-	      EXT_DIRECT	CONFIG_IDE_EXT_DIRECT"	8xx_PCCARD
-   fi
+      if [ "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+         choice 'Type of MPC8xx IDE interface'		\
+		"8xx_PCCARD	CONFIG_IDE_8xx_PCCARD	\
+		 8xx_DIRECT	CONFIG_IDE_8xx_DIRECT	\
+		 EXT_DIRECT	CONFIG_IDE_EXT_DIRECT"	8xx_PCCARD
+      fi
 
-   # assume no ISA -> also no VLB
-   dep_bool '  ISA/VLB IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA
-   if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
-      comment 'Note: most of these also require special kernel boot parameters'
-      bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-      bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-      bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-      if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	 bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+      bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS
+      if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
+	 comment 'Note: most of these also require special kernel boot parameters'
+	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+	 fi
+	 bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
+	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       fi
-      dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
-      bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
    fi
-   if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" != "n" -o \
-        "$CONFIG_BLK_DEV_IDEDMA_PMAC" != "n" -o \
-        "$CONFIG_BLK_DEV_IDEDMA_ICS" != "n" ]; then
-      bool '  IGNORE word93 Validation BITS' CONFIG_IDEDMA_IVB
-   fi
-else
-   bool 'Old disk only (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
-   define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_ONLY
 fi
 
 if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
@@ -137,6 +163,42 @@
    define_bool CONFIG_IDEDMA_AUTO n
 fi
 
-dep_tristate 'Support for software RAID controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
-dep_tristate '   Support Promise (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
-dep_tristate '   Highpoint 370 EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
+     "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+   bool '  IGNORE word93 Validation BITS' CONFIG_IDEDMA_IVB
+fi
+
+if [ "$CONFIG_BLK_DEV_TIVO" = "y" ]; then
+  define_bool CONFIG_DMA_NONPCI y
+else
+  define_bool CONFIG_DMA_NONPCI n
+fi
+
+if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+     "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD640" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD64X" = "y" -o \
+     "$CONFIG_BLK_DEV_CS5530" = "y" -o \
+     "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT366" = "y" -o \
+     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
+     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
+     "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
+     "$CONFIG_BLK_DEV_PIIX" = "y" -o \
+     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
+     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
+     "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \
+     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+   define_bool CONFIG_BLK_DEV_IDE_MODES y
+else
+   define_bool CONFIG_BLK_DEV_IDE_MODES n
+fi
+
+endmenu
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Tue Aug 27 12:28:07 2002
+++ b/drivers/ide/Makefile	Tue Aug 27 12:28:08 2002
@@ -7,22 +7,18 @@
 # Note : at this point, these files are compiled on all systems.
 # In the future, some of these should be built conditionally.
 #
+export-objs		:= ide-taskfile.o ide.o ide-probe.o ataraid.o
 
-export-objs	:= device.o ide-taskfile.o main.o ide.o probe.o quirks.o pcidma.o tcq.o \
-		   atapi.o ataraid.o
-
-obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
-obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o
+obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o ide-probe-mod.o
 obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
 obj-$(CONFIG_BLK_DEV_IDEDISK)   += ide-disk.o
-obj-$(CONFIG_ATAPI)		+= atapi.o
 obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
 
 obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
-obj-$(CONFIG_BLK_DEV_QD65XX)    += qd65xx.o
 
+ide-obj-$(CONFIG_BLK_DEV_ADMA100)	+= adma100.o
 ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
 ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
 ide-obj-$(CONFIG_BLK_DEV_ALI15X3)	+= alim15x3.o
@@ -40,12 +36,12 @@
 ide-obj-$(CONFIG_BLK_DEV_HPT366)	+= hpt366.o
 ide-obj-$(CONFIG_BLK_DEV_HT6560B)	+= ht6560b.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA)	+= quirks.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= pcidma.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ)	+= tcq.o
-ide-obj-$(CONFIG_PCI)			+= ide-pci.o
+ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
+ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
 ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
+ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM)	+= ide-swarm.o
 ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
 ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
 ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
@@ -53,22 +49,19 @@
 ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
 ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
 ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
+ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
 ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
 ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
+ide-obj-$(CONFIG_BLK_DEV_SLC90E66)	+= slc90e66.o
 ide-obj-$(CONFIG_BLK_DEV_SL82C105)	+= sl82c105.o
 ide-obj-$(CONFIG_BLK_DEV_TRM290)	+= trm290.o
 ide-obj-$(CONFIG_BLK_DEV_UMC8672)	+= umc8672.o
 ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)	+= via82cxxx.o
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
 
-# The virtualised raid layers MUST come after the ide itself or bad stuff
-# will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
 
-ide-mod-objs	:= device.o ide-taskfile.o main.o ide.o probe.o \
-		   ioctl.o ata-timing.o $(ide-obj-y)
+ide-mod-objs		:= ide-taskfile.o ide.o $(ide-obj-y)
+ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/adma100.c b/drivers/ide/adma100.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/adma100.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,30 @@
+/*
+ *  linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards
+ *
+ *     Created 09 Apr 2002 by Mark Lord
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void __init ide_init_adma100 (ide_hwif_t *hwif)
+{
+	u32  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	void *v_admctl;
+
+	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
+	hwif->dma_base = 0;		// disable DMA completely
+	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
+	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
+	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
+	iounmap(v_admctl);				// all done; unmap config regs
+}
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/aec62xx.c	Tue Aug 27 12:28:08 2002
@@ -1,360 +1,670 @@
 /*
+ * linux/drivers/ide/aec62xx.c		Version 0.11	March 27, 2002
  *
- * aec62xx.c, v1.2 2002/05/24
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
  *
- *  Copyright (c) 2002 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Andre Hedrick
- */
-
-/*
- * AEC 6210UF (ATP850UF), AEC6260 (ATP860) and AEC6280 (ATP865) IDE driver for Linux.
- *
- * UDMA66 and higher modes are autoenabled only in case the BIOS has detected a
- * 80 wire cable. To ignore the BIOS data and assume the cable is present, use
- * 'ide0=ata66' or 'ide1=ata66' on the kernel command line.
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
+#include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
-#define AEC_DRIVE_TIMING	0x40
-#define AEC_UDMA_NEW		0x44
-#define AEC_MISC		0x49
-#define AEC_IDE_ENABLE		0x4a
-#define AEC_UDMA_OLD		0x54
-
-#define AEC_BM_STAT_PCH		0x02
-#define AEC_BM_STAT_SCH		0x0a
-
-#define AEC_PLLCLK_ATA133	0x10
-#define AEC_CABLEPINS_INPUT	0x10
-
-static unsigned char aec_cyc2udma[9] = { 5, 5, 5, 4, 3, 2, 2, 1, 1 };
-static unsigned char aec_cyc2act[16] =
-    { 1, 1, 2, 3, 4, 5, 6, 0, 0, 7, 7, 7, 7, 7, 7, 7 };
-static unsigned char aec_cyc2rec[16] =
-    { 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 12, 13, 14 };
+#define DISPLAY_AEC62XX_TIMINGS
 
-/*
- * aec_set_speed_old() writes timing values to
- * the chipset registers for ATP850UF
- */
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
 
-static void aec_set_speed_old(struct pci_dev *dev, unsigned char dn,
-			      struct ata_timing *timing)
-{
-	unsigned char t;
 
-	pci_write_config_byte(dev, AEC_DRIVE_TIMING + (dn << 1),
-			      aec_cyc2act[FIT(timing->active, 0, 15)]);
-	pci_write_config_byte(dev, AEC_DRIVE_TIMING + (dn << 1) + 1,
-			      aec_cyc2rec[FIT(timing->recover, 0, 15)]);
-
-	pci_read_config_byte(dev, AEC_UDMA_OLD, &t);
-	t &= ~(3 << (dn << 1));
-	if (timing->udma)
-		t |= (5 - FIT(timing->udma, 2, 4)) << (dn << 1);
-	pci_write_config_byte(dev, AEC_UDMA_OLD, t);
-}
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
 
-/*
- * aec_set_speed_new() writes timing values to the chipset registers for all
- * other Artop chips
- */
+static int aec62xx_get_info(char *, char **, off_t, int);
+extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+#define AEC_MAX_DEVS		5
+
+static struct pci_dev *aec_devs[AEC_MAX_DEVS];
+static int n_aec_devs;
+
+#undef DEBUG_AEC_REGS
 
-static void aec_set_speed_new(struct pci_dev *dev, unsigned char dn,
-			      struct ata_timing *timing)
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	unsigned char t;
+	char *p = buffer;
+	char *chipset_nums[] = {"error", "error", "error", "error",
+				"error", "error", "850UF",   "860",
+				 "860R",   "865",  "865R", "error"  };
+//	char *modes_33[] = {};
+//	char *modes_34[] = {};
+	int i;
 
-	pci_write_config_byte(dev, AEC_DRIVE_TIMING + dn,
-			      (aec_cyc2act[FIT(timing->active, 0, 15)] <<
-			       4)
-			      | aec_cyc2rec[FIT(timing->recover, 0, 15)]);
-
-	pci_read_config_byte(dev, AEC_UDMA_NEW + (dn >> 1), &t);
-	t &= ~(0xf << ((dn & 1) << 2));
-	if (timing->udma) {
-		if (timing->udma >= 2)
-			t |= aec_cyc2udma[FIT(timing->udma, 2, 8)] <<
-			    ((dn & 1) << 2);
-		if (timing->mode == XFER_UDMA_5)
-			t |= 6;
-		if (timing->mode == XFER_UDMA_6)
-			t |= 7;
+	for (i = 0; i < n_aec_devs; i++) {
+		struct pci_dev *dev	= aec_devs[i];
+	//	u32 iobase		= dev->resource[4].start;
+		u32 iobase		= pci_resource_start(dev, 4);
+		u8 c0			= inb_p(iobase + 0x02);
+		u8 c1			= inb_p(iobase + 0x0a);
+		u8 art			= 0;
+#ifdef DEBUG_AEC_REGS
+		u8 uart			= 0;
+#endif /* DEBUG_AEC_REGS */
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		(void) pci_read_config_byte(dev, 0x4a, &art);
+		p += sprintf(p, "                %sabled ",
+			(art&0x02)?" en":"dis");
+		p += sprintf(p, "                        %sabled\n",
+			(art&0x04)?" en":"dis");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s ",
+			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
+		p += sprintf(p, "            %s               %s\n",
+			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+			(void) pci_read_config_byte(dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0");
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+#endif /* DEBUG_AEC_REGS */
+		} else {
+			/*
+			 * case PCI_DEVICE_ID_ARTOP_ATP860:
+			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
+			 */
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+#endif /* DEBUG_AEC_REGS */
+		}
 	}
-	pci_write_config_byte(dev, AEC_UDMA_NEW + (dn >> 1), t);
+	return p-buffer;/* => must be less than 4k! */
 }
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-/*
- * aec_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
+byte aec62xx_proc = 0;
 
-static int aec_set_drive(struct ata_device *drive, unsigned char speed)
-{
-	struct ata_timing t;
-	int T, UT;
-	int aec_old;
-
-	aec_old =
-	    (drive->channel->pci_dev->device ==
-	     PCI_DEVICE_ID_ARTOP_ATP850UF);
-
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING
-			       "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-			       drive->dn >> 1, drive->dn & 1);
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	byte		chipset_settings;
+	byte		ultra_settings;
+};
 
-	T = 1000000000 / system_bus_speed;
-	UT = T / (aec_old ? 1 : 2);
+struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	{	XFER_UDMA_6,	0x31,	0x07	},
+	{	XFER_UDMA_5,	0x31,	0x06	},
+	{	XFER_UDMA_4,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x0a,	0x00	},
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	{	XFER_PIO_4,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00	},
+	{	0,		0x00,	0x00	}
+};
 
-	ata_timing_compute(drive, speed, &t, T, UT);
-	ata_timing_merge_8bit(&t);
+struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	{	XFER_UDMA_6,	0x41,	0x06	},
+	{	XFER_UDMA_5,	0x41,	0x05	},
+	{	XFER_UDMA_4,	0x41,	0x04	},
+	{	XFER_UDMA_3,	0x41,	0x03	},
+	{	XFER_UDMA_2,	0x41,	0x02	},
+	{	XFER_UDMA_1,	0x41,	0x01	},
+	{	XFER_UDMA_0,	0x41,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00	},
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	{	XFER_PIO_4,	0x41,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00	},
+	{	0,		0x00,	0x00	}
+};
 
-	if (aec_old)
-		aec_set_speed_old(drive->channel->pci_dev, drive->dn, &t);
-	else
-		aec_set_speed_new(drive->channel->pci_dev, drive->dn, &t);
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
 
-	return 0;
+static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return chipset_table->chipset_settings;
 }
 
-/*
- * aec62xx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
- */
+static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return chipset_table->ultra_settings;
+}
 
-static void aec62xx_tune_drive(struct ata_device *drive, unsigned char pio)
+static byte aec62xx_ratemask (ide_drive_t *drive)
 {
-	if (pio == 255) {
-		aec_set_drive(drive,
-			      ata_timing_mode(drive,
-					      XFER_PIO | XFER_EPIO));
-		return;
-	}
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= 0x00;
 
-	aec_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		mode |= 0x01;
+	} else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP860) ||
+		   (dev->device == PCI_DEVICE_ID_ARTOP_ATP860R)) {
+		mode |= 0x02;
+	} else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
+		   (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
+		u32 bmide = pci_resource_start(dev, 4);
+		if (IN_BYTE(bmide+2) & 0x10)
+			mode |= 0x04;
+		else
+			mode |= 0x03;
+	}
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
 }
 
+static byte aec62xx_ratefilter (ide_drive_t *drive, byte speed)
+{
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int __init aec62xx_modes_map(struct ata_channel *ch)
+	byte mode = aec62xx_ratemask(drive);
+
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	u32 bmide = pci_resource_start(ch->pci_dev, 4);
-	int map;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte speed		= aec62xx_ratefilter(drive, xferspeed);
+	unsigned short d_conf	= 0x0000;
+	byte ultra		= 0x00;
+	byte ultra_conf		= 0x00;
+	byte tmp0		= 0x00;
+	byte tmp1		= 0x00;
+	byte tmp2		= 0x00;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+	tmp0 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+	ultra_conf = pci_bus_clock_list_ultra(speed,
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
+	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
 
-	map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
+static int aec6260_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte unit		= (drive->select.b.unit & 0x01);
+	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
+	byte speed		= aec62xx_ratefilter(drive, xferspeed);
+	byte drive_conf		= 0x00;
+	byte ultra_conf		= 0x00;
+	byte ultra		= 0x00;
+	byte tmp1		= 0x00;
+	byte tmp2		= 0x00;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
+	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+	pci_read_config_byte(dev, ultra_pci, &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed,
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, ultra_pci, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
 
-	if (ch->udma_four)
-		switch (ch->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
+static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	switch (HWIF(drive)->pci_dev->device) {
 		case PCI_DEVICE_ID_ARTOP_ATP865:
-			/* Can't use these modes simultaneously,
-			   based on which PLL clock was chosen. */
-			map |=
-			    inb(bmide +
-				AEC_BM_STAT_PCH) & AEC_PLLCLK_ATA133 ?
-			    XFER_UDMA_133 : XFER_UDMA_100;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
 		case PCI_DEVICE_ID_ARTOP_ATP860:
-			map |= XFER_UDMA_66;
-		}
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return ((int) aec6260_tune_chipset(drive, speed));
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return ((int) aec6210_tune_chipset(drive, speed));
+		default:
+			return -1;
+	}
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte mode		= aec62xx_ratemask(drive);
+	byte speed;
+
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+	
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
+
+	(void) aec62xx_tune_chipset(drive, speed);
 
-	return map;
+	return ((int)	((id->dma_ultra >> 11) & 15) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+//	return ((int) ide_dma_on);
 }
-#endif
 
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- * We return the IRQ assigned to the chip.
- */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-static unsigned int __init aec62xx_init_chipset(struct pci_dev *dev)
+static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
 {
-	u32 bmide = pci_resource_start(dev, 4);
-	unsigned char t;
+	byte speed;
+	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) aec62xx_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
 
 /*
- * Initialize if needed.
+ * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
  */
+int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 
-	switch (dev->device) {
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_lostirq:
+		case ide_dma_timeout:
+			switch(dev->device) {
+				case PCI_DEVICE_ID_ARTOP_ATP860:
+				case PCI_DEVICE_ID_ARTOP_ATP860R:
+				case PCI_DEVICE_ID_ARTOP_ATP865:
+				case PCI_DEVICE_ID_ARTOP_ATP865R:
+					printk(" AEC62XX time out ");
+#if 0
+					{
+						int i = 0;
+						byte reg49h = 0;
+						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+						for (i=0;i<256;i++)
+							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+					}
+					return 0;
+#endif
+				default:
+					break;
+			}
+		default:
+			break;
+	}
+#if 0
+	{
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		unsigned long dma_base	= hwif->dma_base;
+		byte tmp1		= 0x00;
+		byte tmp2		= 0x00;
+
+		pci_read_config_byte(dev, 0x44, &tmp1);
+		pci_read_config_byte(dev, 0x45, &tmp2);
+		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+		if (hwif->channel)
+			dma_base -= 0x08;
+		tmp1=IN_BYTE(dma_base+2) & 0x10;
+		printk(" AEC6280 133=%x ",tmp1);
+	}
+#endif
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	case PCI_DEVICE_ID_ARTOP_ATP865R:
-	case PCI_DEVICE_ID_ARTOP_ATP865:
+unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
+{
+	int bus_speed = system_bus_clock();
 
-		/* Clear reset and test bits. */
-		pci_read_config_byte(dev, AEC_MISC, &t);
-		pci_write_config_byte(dev, AEC_MISC, t & ~0x30);
-
-		/* Enable chip interrupt output. */
-		pci_read_config_byte(dev, AEC_IDE_ENABLE, &t);
-		pci_write_config_byte(dev, AEC_IDE_ENABLE, t & ~0x01);
-
-#ifdef CONFIG_AEC6280_BURST
-		/* Must be greater than 0x80 for burst mode. */
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x90);
-
-		/* Enable burst mode. */
-		pci_read_config_byte(dev, AEC_IDE_ENABLE, &t);
-		pci_write_config_byte(dev, AEC_IDE_ENABLE, t | 0x80);
-#endif
-		/* switch cable detection pins to input-only. */
-		outb(inb(bmide + AEC_BM_STAT_SCH) | AEC_CABLEPINS_INPUT,
-		     bmide + AEC_BM_STAT_SCH);
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
-/*
- * Print the boot message.
- */
+	aec_devs[n_aec_devs++] = dev;
 
-	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "AEC_IDE: %s (rev %02x) controller on pci%s\n",
-	       dev->name, t, dev->slot_name);
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		aec62xx_display_info = &aec62xx_get_info;
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	if (bus_speed <= 33)
+		dev->driver_data = (void *) aec6xxx_33_base;
+	else
+		dev->driver_data = (void *) aec6xxx_34_base;
 
 	return dev->irq;
 }
 
-static unsigned int __init aec62xx_ata66_check(struct ata_channel *ch)
+unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
 {
-	unsigned char t;
-
-	if (ch->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
-		return 0;
+	byte mask	= hwif->channel ? 0x02 : 0x01;
+	byte ata66	= 0;
 
-	pci_read_config_byte(ch->pci_dev, AEC_MISC, &t);
-	return ((t & (1 << ch->unit)) ? 0 : 1);
+	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+	return ((ata66 & mask) ? 0 : 1);
 }
 
-static void __init aec62xx_init_channel(struct ata_channel *ch)
+void __init ide_init_aec62xx (ide_hwif_t *hwif)
 {
-	int i;
-
-	ch->tuneproc = aec62xx_tune_drive;
-	ch->speedproc = aec_set_drive;
+	hwif->autodma = 0;
+	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->speedproc = &aec62xx_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
 
-	ch->io_32bit = 1;
-	ch->unmask = 1;
+	if (!hwif->dma_base)
+		return;
 
-	ch->udma_four = aec62xx_ata66_check(ch);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc = &aec62xx_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	for (i = 0; i < 2; i++) {
-		ch->drives[i].autotune = 1;
-		ch->drives[i].dn = ch->unit * 2 + i;
-	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (ch->dma_base) {
-		ch->highmem = 1;
-		ch->modes_map = aec62xx_modes_map(ch);
-		ch->udma_setup = udma_generic_setup;
-	}
-#endif
 }
 
-/*
- * We allow the BM-DMA driver only work on enabled interfaces.
- */
-static void __init aec62xx_init_dma(struct ata_channel *ch,
-				    unsigned long dmabase)
+void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
 {
-	unsigned char t;
-
-	pci_read_config_byte(ch->pci_dev, AEC_IDE_ENABLE, &t);
-	if (t & (1 << ((ch->unit << 1) + 2)))
-		ata_init_dma(ch, dmabase);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte reg54h		= 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_byte(dev, 0x54, &reg54h);
+	pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+	spin_unlock_irqrestore(&ide_lock, flags);
+	ide_setup_dma(hwif, dmabase, 8);
 }
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_ARTOP,
-		.device = PCI_DEVICE_ID_ARTOP_ATP850UF,
-		.init_chipset = aec62xx_init_chipset,
-		.init_channel = aec62xx_init_channel,
-		.init_dma = aec62xx_init_dma,
-		.enablebits = {{0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04}},
-		.bootable = OFF_BOARD,
-		.flags = ATA_F_SER | ATA_F_IRQ | ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_ARTOP,
-		.device = PCI_DEVICE_ID_ARTOP_ATP860,
-		.init_chipset = aec62xx_init_chipset,
-		.init_channel = aec62xx_init_channel,
-		.enablebits = {{0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04}},
-		.bootable = NEVER_BOARD,
-		.flags = ATA_F_IRQ | ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_ARTOP,
-		.device = PCI_DEVICE_ID_ARTOP_ATP860R,
-		.init_chipset = aec62xx_init_chipset,
-		.init_channel = aec62xx_init_channel,
-		.enablebits = {{0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04}},
-		.bootable = OFF_BOARD,
-		.flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-		.vendor = PCI_VENDOR_ID_ARTOP,
-		.device = PCI_DEVICE_ID_ARTOP_ATP865,
-		.init_chipset = aec62xx_init_chipset,
-		.init_channel = aec62xx_init_channel,
-		.enablebits = {{0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04}},
-		.bootable = NEVER_BOARD,
-		.flags = ATA_F_IRQ | ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_ARTOP,
-		.device = PCI_DEVICE_ID_ARTOP_ATP865R,
-		.init_chipset = aec62xx_init_chipset,
-		.init_channel = aec62xx_init_channel,
-		.enablebits = {{0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04}},
-		.bootable = OFF_BOARD,
-		.flags = ATA_F_IRQ | ATA_F_DMA
-	}
-};
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
 
-int __init init_aec62xx(void)
+void __init fixup_device_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
+	u32 bar4reg = pci_resource_start(dev, 4);
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); i++)
-		ata_register_chipset(chipsets + i);
+	if (IN_BYTE(bar4reg+2) & 0x10) {
+		strcpy(d->name, "AEC6880");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6880R");
+	} else {
+		strcpy(d->name, "AEC6280");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6280R");
+	}
 
-	return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
diff -Nru a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
--- a/drivers/ide/ali14xx.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/ide/ali14xx.c	Tue Aug 27 12:28:08 2002
@@ -1,4 +1,6 @@
 /*
+ *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
+ *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
@@ -13,7 +15,7 @@
  * I think the code should be pretty understandable,
  * but I'll be happy to (try to) answer questions.
  *
- * The critical part is in the ali14xx_tune_drive function.  The init_registers
+ * The critical part is in the setupDrive function.  The initRegisters
  * function doesn't seem to be necessary, but the DOS driver does it, so
  * I threw it in.
  *
@@ -35,27 +37,31 @@
  * mode 4 for a while now with no trouble.)  -Derek
  */
 
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 
 /* port addresses for auto-detection */
 #define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata =
-    { 0x074, 0x0f4, 0x034, 0x0e4 };
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
 
 /* register initialization data */
-struct reg_initializer {
-	u8 reg, data;
-};
+typedef struct { byte reg, data; } RegInitializer;
 
-static struct reg_initializer init_data[] __initdata = {
+static RegInitializer initData[] __initdata = {
 	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
 	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
 	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
@@ -65,164 +71,153 @@
 	{0x35, 0x03}, {0x00, 0x00}
 };
 
+#define ALI_MAX_PIO 4
+
 /* timing parameter registers for each drive */
-static struct {
-	u8 reg1, reg2, reg3, reg4;
-} reg_tab[4] = {
-	{
-	0x03, 0x26, 0x04, 0x27},	/* drive 0 */
-	{
-	0x05, 0x28, 0x06, 0x29},	/* drive 1 */
-	{
-	0x2b, 0x30, 0x2c, 0x31},	/* drive 2 */
-	{
-	0x2d, 0x32, 0x2e, 0x33},	/* drive 3 */
+static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
+	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
 };
 
-static int base_port;		/* base port address */
-static int reg_port;		/* port for register number */
-static int data_port;		/* port for register data */
-static u8 reg_on;		/* output to base port to access registers */
-static u8 reg_off;		/* output to base port to close registers */
+static int basePort;	/* base port address */
+static int regPort;	/* port for register number */
+static int dataPort;	/* port for register data */
+static byte regOn;	/* output to base port to access registers */
+static byte regOff;	/* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
 
 /*
  * Read a controller register.
  */
-static inline u8 in_reg(u8 reg)
+static inline byte inReg (byte reg)
 {
-	outb_p(reg, reg_port);
-	return inb(data_port);
+	outb_p(reg, regPort);
+	return IN_BYTE(dataPort);
 }
 
 /*
  * Write a controller register.
  */
-static inline void out_reg(u8 data, u8 reg)
+static void outReg (byte data, byte reg)
 {
-	outb_p(reg, reg_port);
-	outb_p(data, data_port);
+	outb_p(reg, regPort);
+	outb_p(data, dataPort);
 }
 
 /*
  * Set PIO mode for the specified drive.
  * This function computes timing parameters
  * and sets controller registers accordingly.
- * It assumes IRQ's are disabled or at least that no other process will
- * attempt to access the IDE registers concurrently.
  */
-static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
+static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
 {
-	int drive_num;
+	int driveNum;
 	int time1, time2;
-	u8 param1, param2, param3, param4;
-	struct ata_timing *t;
-
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		pio = XFER_PIO_0 + min_t(u8, pio, 4);
+	byte param1, param2, param3, param4;
+	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
 
-	t = ata_timing_data(pio);
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
 
 	/* calculate timing, according to PIO mode */
-	time1 = t->cycle;
-	time2 = t->active;
-	param3 = param1 = (time2 * system_bus_speed + 999999) / 1000000;
-	param4 = param2 =
-	    (time1 * system_bus_speed + 999999) / 1000000 - param1;
-	if (pio < XFER_PIO_3) {
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	if (pio < 3) {
 		param3 += 8;
 		param4 += 8;
 	}
-	printk(KERN_DEBUG
-	       "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-	       drive->name, pio - XFER_PIO_0, time1, time2, param1, param2,
-	       param3, param4);
+	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+		drive->name, pio, time1, time2, param1, param2, param3, param4);
 
 	/* stuff timing parameters into controller registers */
-	drive_num = (drive->channel->index << 1) + drive->select.b.unit;
-	outb_p(reg_on, base_port);
-	out_reg(param1, reg_tab[drive_num].reg1);
-	out_reg(param2, reg_tab[drive_num].reg2);
-	out_reg(param3, reg_tab[drive_num].reg3);
-	out_reg(param4, reg_tab[drive_num].reg4);
-	outb_p(reg_off, base_port);
+	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(regOn, basePort);
+	outReg(param1, regTab[driveNum].reg1);
+	outReg(param2, regTab[driveNum].reg2);
+	outReg(param3, regTab[driveNum].reg3);
+	outReg(param4, regTab[driveNum].reg4);
+	outb_p(regOff, basePort);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
  * Auto-detect the IDE controller port.
  */
-static int __init find_port(void)
+static int __init findPort (void)
 {
 	int i;
+	byte t;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	for (i = 0; i < ALI_NUM_PORTS; i++) {
-		base_port = ports[i];
-		reg_off = inb(base_port);
-		for (reg_on = 0x30; reg_on <= 0x33; reg_on++) {
-			outb_p(reg_on, base_port);
-			if (inb(base_port) == reg_on) {
-				u8 t;
-				reg_port = base_port + 4;
-				data_port = base_port + 8;
-				t = in_reg(0) & 0xf0;
-				outb_p(reg_off, base_port);
+	for (i = 0; i < ALI_NUM_PORTS; ++i) {
+		basePort = ports[i];
+		regOff = IN_BYTE(basePort);
+		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+			outb_p(regOn, basePort);
+			if (IN_BYTE(basePort) == regOn) {
+				regPort = basePort + 4;
+				dataPort = basePort + 8;
+				t = inReg(0) & 0xf0;
+				outb_p(regOff, basePort);
 				local_irq_restore(flags);
 				if (t != 0x50)
 					return 0;
-				return 1;	/* success */
+				return 1;  /* success */
 			}
 		}
-		outb_p(reg_off, base_port);
+		outb_p(regOff, basePort);
 	}
 	local_irq_restore(flags);
-
 	return 0;
 }
 
 /*
  * Initialize controller registers with default values.
  */
-static int __init init_registers(void)
-{
-	struct reg_initializer *p;
+static int __init initRegisters (void) {
+	RegInitializer *p;
+	byte t;
 	unsigned long flags;
-	u8 t;
 
 	local_irq_save(flags);
-	outb_p(reg_on, base_port);
-	for (p = init_data; p->reg != 0; ++p)
-		out_reg(p->data, p->reg);
-	outb_p(0x01, reg_port);
-	t = inb(reg_port) & 0x01;
-	outb_p(reg_off, base_port);
+	outb_p(regOn, basePort);
+	for (p = initData; p->reg != 0; ++p)
+		outReg(p->data, p->reg);
+	outb_p(0x01, regPort);
+	t = IN_BYTE(regPort) & 0x01;
+	outb_p(regOff, basePort);
 	local_irq_restore(flags);
-
 	return t;
 }
 
-void __init init_ali14xx(void)
+void __init init_ali14xx (void)
 {
 	/* auto-detect IDE controller port */
-	if (!find_port()) {
-		printk(KERN_ERR "ali14xx: not found\n");
+	if (!findPort()) {
+		printk("\nali14xx: not found");
 		return;
 	}
 
-	printk(KERN_DEBUG "ali14xx: base=%#03x, reg_on=%#02x\n",
-	       base_port, reg_on);
+	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
 	ide_hwifs[0].chipset = ide_ali14xx;
 	ide_hwifs[1].chipset = ide_ali14xx;
 	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
 	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].unit = ATA_PRIMARY;
-	ide_hwifs[1].unit = ATA_SECONDARY;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 
 	/* initialize controller registers */
-	if (!init_registers()) {
-		printk(KERN_ERR "ali14xx: Chip initialization failed\n");
+	if (!initRegisters()) {
+		printk("\nali14xx: Chip initialization failed");
 		return;
 	}
 }
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/ide/alim15x3.c	Tue Aug 27 12:28:08 2002
@@ -20,108 +20,398 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
+extern int (*ali_display_info)(char *, char **, off_t, int);  /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
+	unsigned int bibma;
+	byte c0, c1;
+	byte rev, tmp;
+	char *p = buffer;
+	char *q;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	pci_read_config_dword(bmide_dev, 0x20, &bibma);
+	bibma = (bibma & 0xfff0) ;
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = IN_BYTE((unsigned short)bibma + 0x02);
+	c1 = IN_BYTE((unsigned short)bibma + 0x0a);
 
-static u8 m5229_revision;
-static int chip_is_1543c_e;
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel"
+		"-------------------secondary channel"
+		"---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s"
+		"                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s"
+		"                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT"
+		"                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT"
+		"                                %dT\n"
+		"Command Rec. Count:   %dT"
+		"                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n\n");
+	p += sprintf(p,
+		"DMA enabled:      %s              %s"
+		"               %s              %s\n",
+		(c0&0x20) ? "Yes" : "No ",
+		(c0&0x40) ? "Yes" : "No ",
+		(c1&0x20) ? "Yes" : "No ",
+		(c1&0x40) ? "Yes" : "No " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+		p += sprintf(p, q, t1, t2, t3, t4);
+	}
 
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings"
+		"--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s"
+		"                %s               %s\n"
+		"UDMA timings:     %s             %s"
+		"              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte m5229_revision;
+static byte chip_is_1543c_e;
+
+byte ali_proc = 0;
 static struct pci_dev *isa_dev;
 
-static void ali15x3_tune_drive(struct ata_device *drive, u8 pio)
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
 {
-	struct ata_timing *t;
-	struct ata_channel *hwif = drive->channel;
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
 	int s_time, a_time, c_time;
-	u8 s_clc, a_clc, r_clc;
+	byte s_clc, a_clc, r_clc;
 	unsigned long flags;
-	int port = hwif->unit ? 0x5c : 0x58;
-	int portFIFO = hwif->unit ? 0x55 : 0x54;
-	u8 cd_dma_fifo = 0;
-
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		pio = XFER_PIO_0 + min_t(u8, pio, 4);
-
-	t = ata_timing_data(pio);
-
-	/* FIXME: use generic ata-timing library  --bkz */
-	s_time = t->setup;
-	a_time = t->active;
-	if ((s_clc = (s_time * system_bus_speed + 999999) / 1000000) >= 8)
+	int bus_speed = system_bus_clock();
+	int port = hwif->channel ? 0x5c : 0x58;
+	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	byte cd_dma_fifo = 0;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
 		s_clc = 0;
-	if ((a_clc = (a_time * system_bus_speed + 999999) / 1000000) >= 8)
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
 		a_clc = 0;
-	c_time = t->cycle;
+	c_time = ide_pio_timings[pio].cycle_time;
 
 #if 0
-	if ((r_clc = ((c_time - s_time - a_time) * system_bus_speed + 999999) / 1000000) >= 16)
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
 		r_clc = 0;
 #endif
 
-	if (!(r_clc = (c_time * system_bus_speed + 999999) / 1000000 - a_clc - s_clc)) {
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
 		r_clc = 1;
 	} else {
 		if (r_clc >= 16)
 			r_clc = 0;
 	}
-
 	local_irq_save(flags);
-
-	/*
+	
+	/* 
 	 * PIO mode => ATA FIFO on, ATAPI FIFO off
 	 */
 	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->type == ATA_DISK) {
-		if (hwif->index) {
+	if (drive->media==ide_disk) {
+		if (hwif->channel) {
 			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
 		} else {
 			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
 		}
 	} else {
-		if (hwif->index) {
+		if (hwif->channel) {
 			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
 		} else {
 			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
 		}
 	}
-
+	
 	pci_write_config_byte(dev, port, s_clc);
 	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-
 	local_irq_restore(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+static byte ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+	if (m5229_revision <= 0x20) {
+		return 0;
+	} else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+		    (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+		   (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+static byte ali15x3_ratemask (ide_drive_t *drive)
+{
+//	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= 0x00;
+	byte can_ultra		= ali15x3_can_ultra(drive);
+
+	if ((m5229_revision >= 0xC4) && (can_ultra)) {
+		mode |= 0x03;
+	} else if ((m5229_revision >= 0xC2) && (can_ultra)) {
+		mode |= 0x02;
+	} else if (can_ultra) {
+		mode |= 0x01;
+	} else {
+		return (mode &= ~0xFF);
+	}
+
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
 }
 
-static int ali15x3_tune_chipset(struct ata_device *drive, u8 speed)
+static byte ali15x3_ratefilter (ide_drive_t *drive, byte speed)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	u8 unit	= (drive->select.b.unit & 0x01);
-	u8 tmpbyte = 0x00;
-	int m5229_udma = drive->channel->unit ? 0x57 : 0x56;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = ali15x3_ratemask(drive);
+
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
+
+static int ali15x3_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte speed		= ali15x3_ratefilter(drive, xferspeed);
+	byte unit		= (drive->select.b.unit & 0x01);
+	byte tmpbyte		= 0x00;
+	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
 
 	if (speed < XFER_UDMA_0) {
-		u8 ultra_enable	= unit ? 0x7f : 0xf7;
+		byte ultra_enable	= (unit) ? 0x7f : 0xf7;
 		/*
 		 * clear "ultra enable" bit
 		 */
 		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
 		tmpbyte &= ultra_enable;
 		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-	}
 
-	if (speed < XFER_SW_DMA_0)
-		ali15x3_tune_drive(drive, speed);
+		if (speed < XFER_SW_DMA_0)
+			ali15x3_tune_drive(drive, speed);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	/* FIXME: no support for MWDMA and SWDMA modes  --bkz */
-	else if (speed >= XFER_UDMA_0) {
+	} else {
 		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
 		tmpbyte &= (0x0f << ((1-unit) << 2));
 		/*
@@ -134,54 +424,143 @@
 			tmpbyte |= 1;
 			pci_write_config_byte(dev, 0x4b, tmpbyte);
 		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	}
-#endif
-
-	return ide_config_drive_speed(drive, speed);
+	return (ide_config_drive_speed(drive, speed));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int ali15x3_udma_setup(struct ata_device *drive, int map)
+static int config_chipset_for_dma (ide_drive_t *drive)
 {
-#ifndef CONFIG_WDC_ALI15X3
-	if ((m5229_revision < 0xC2) && chip_is_1543c_e &&
-	    strstr(drive->id->model, "WDC "))
-		map &= ~XFER_UDMA_ALL;
-#endif
-	return udma_generic_setup(drive, map);
+	struct hd_driveid *id	= drive->id;
+	byte mode		= ali15x3_ratemask(drive);
+	byte speed		= 0;
+
+	switch(mode) {
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
+
+	(void) ali15x3_tune_chipset(drive, speed);
+//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
+	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
 }
 
-static int ali15x3_udma_init(struct ata_device *drive, struct request *rq)
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
 {
-	if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK))
-		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
-
-	return udma_pci_init(drive, rq);
+	struct hd_driveid *id		= drive->id;
+	ide_hwif_t *hwif		= HWIF(drive);
+	ide_dma_action_t dma_func	= ide_dma_on;
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->dmaproc(ide_dma_off_quietly, drive);
+
+	drive->init_speed = 0;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+			if (id->dma_ultra & 0x003F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+	}
+	return hwif->dmaproc(dma_func, drive);
 }
 
-static int __init ali15x3_modes_map(struct ata_channel *ch)
+static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
-
-	if (m5229_revision <= 0x20)
-		return map;
-
-	map |= XFER_UDMA;
-
-	if (m5229_revision >= 0xC2) {
-		map |= XFER_UDMA_66;
-		if (m5229_revision >= 0xC4)
-			map |= XFER_UDMA_100;
+	switch(func) {
+		case ide_dma_check:
+			return ali15x3_config_drive_for_dma(drive);
+		case ide_dma_write:
+			if ((m5229_revision < 0xC2) &&
+			    (drive->media != ide_disk))
+				return 1;	/* try PIO instead of DMA */
+			break;
+		default:
+			break;
 	}
-
-	return map;
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+#define ALI_INIT_CODE_TEST
 
-static unsigned int __init ali15x3_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
 {
 	unsigned long fixdma_base = pci_resource_start(dev, 4);
 
+#ifdef ALI_INIT_CODE_TEST
+	unsigned long flags;
+	byte tmpbyte;
+#endif /* ALI_INIT_CODE_TEST */
+
 	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
 
 	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
@@ -194,12 +573,69 @@
 		/*
 		 * enable DMA capable bit, and "not" simplex only
 		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
+		OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
+
+		if (IN_BYTE(fixdma_base+2) & 0x80)
+			printk("%s: simplex device: DMA will fail!!\n", name);
+	}
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!ali_proc) {
+		ali_proc = 1;
+		bmide_dev = dev;
+		ali_display_info = &ali_get_info;
+	}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+#ifdef ALI_INIT_CODE_TEST
+	local_irq_save(flags);
+
+	if (m5229_revision >= 0xC2) {
+		/*
+		 * 1543C-B?, 1535, 1535D, 1553
+		 * Note 1: not all "motherboard" support this detection
+		 * Note 2: if no udma 66 device, the detection may "error".
+		 *         but in this case, we will not set the device to
+		 *         ultra 66, the detection result is not important
+		 */
 
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", dev->name);
+		/*
+		 * enable "Cable Detection", m5229, 0x4b, bit3
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+		/*
+		 * set south-bridge's enable bit, m1533, 0x79
+		 */
+		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+		if (m5229_revision == 0xC2) {
+			/*
+			 * 1543C-B0 (m1533, 0x79, bit 2)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+		} else if (m5229_revision >= 0xC3) {
+			/*
+			 * 1553/1535 (m1533, 0x79, bit 1)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+		}
+	} else {
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
 	}
 
+	local_irq_save(flags);
+#endif /* ALI_INIT_CODE_TEST */
+
 	return 0;
 }
 
@@ -208,18 +644,19 @@
  * of UDMA66 transfers. It doesn't check the drives.
  * But see note 2 below!
  */
-static unsigned int __init ali15x3_ata66_check(struct ata_channel *hwif)
+unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int ata66	= 0;
-	u8 cable_80_pin[2]	= { 0, 0 };
+	byte cable_80_pin[2]	= { 0, 0 };
 
 	unsigned long flags;
-	u8 tmpbyte;
+	byte tmpbyte;
 
 	local_irq_save(flags);
 
 	if (m5229_revision >= 0xC2) {
+#ifndef ALI_INIT_CODE_TEST
 		/*
 		 * 1543C-B?, 1535, 1535D, 1553
 		 * Note 1: not all "motherboard" support this detection
@@ -249,6 +686,7 @@
 			 */
 			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
 		}
+#endif /* ALI_INIT_CODE_TEST */
 		/*
 		 * Ultra66 cable detection (from Host View)
 		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
@@ -267,8 +705,9 @@
 		/*
 		 * Allow ata66 if cable of current channel has 80 pins
 		 */
-		ata66 = (hwif->unit)?cable_80_pin[1]:cable_80_pin[0];
+		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
 	} else {
+#ifndef ALI_INIT_CODE_TEST
 		/*
 		 * revision 0x20 (1543-E, 1543-F)
 		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
@@ -279,6 +718,7 @@
 		 * clear bit 7
 		 */
 		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+#endif /* ALI_INIT_CODE_TEST */
 		/*
 		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
 		 */
@@ -299,17 +739,17 @@
 
 	local_irq_restore(flags);
 
-	return (ata66);
+	return(ata66);
 }
 
-static void __init ali15x3_init_channel(struct ata_channel *hwif)
+void __init ide_init_ali15x3 (ide_hwif_t *hwif)
 {
 #ifndef CONFIG_SPARC64
-	u8 ideic, inmir;
-	u8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+	byte ideic, inmir;
+	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
 				      1, 11, 0, 12, 0, 14, 0, 15 };
 
-	hwif->irq = hwif->unit ? 15 : 14;
+	hwif->irq = hwif->channel ? 15 : 14;
 
 	if (isa_dev) {
 		/*
@@ -321,14 +761,15 @@
 		ideic = ideic & 0x03;
 
 		/* get IRQ for IDE Controller */
-		if ((hwif->unit && ideic == 0x03) || (!hwif->unit && !ideic)) {
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
 			/*
 			 * get SIRQ1 routing table
 			 */
 			pci_read_config_byte(isa_dev, 0x44, &inmir);
 			inmir = inmir & 0x0f;
 			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->unit && !(ideic & 0x01)) {
+		} else if (hwif->channel && !(ideic & 0x01)) {
 			/*
 			 * get SIRQ2 routing table
 			 */
@@ -339,66 +780,46 @@
 	}
 #endif /* CONFIG_SPARC64 */
 
-	hwif->udma_four = ali15x3_ata66_check(hwif);
-
+	hwif->autodma = 0;
 	hwif->tuneproc = &ali15x3_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-	hwif->speedproc = ali15x3_tune_chipset;
+	hwif->speedproc = &ali15x3_tune_chipset;
+
+	if (!hwif->dma_base)
+		return;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
+	if (m5229_revision >= 0x20) {
 		/*
 		 * M1543C or newer for DMAing
 		 */
-		hwif->modes_map = ali15x3_modes_map(hwif);
-		if (m5229_revision < 0xC2)
-			hwif->no_atapi_autodma = 1;
-		hwif->udma_setup = ali15x3_udma_setup;
-		hwif->udma_init = ali15x3_udma_init;
+		hwif->dmaproc = &ali15x3_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+		if (!noautodma)
+			hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-static void __init ali15x3_init_dma(struct ata_channel *ch, unsigned long dmabase)
+void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
 {
-	if (dmabase && (m5229_revision < 0x20)) {
-		ch->autodma = 0;
+	if ((dmabase) && (m5229_revision < 0x20)) {
 		return;
 	}
-
-	ata_init_dma(ch, dmabase);
+	ide_setup_dma(hwif, dmabase, 8);
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_AL,
-	        .device = PCI_DEVICE_ID_AL_M5219,
-		/* FIXME: Perhaps we should use the same init routines
-		 * as below here. */
-		.enablebits = { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
-		.bootable = ON_BOARD,
-		.flags = ATA_F_SIMPLEX
-	},
-	{
-		.vendor = PCI_VENDOR_ID_AL,
-	        .device = PCI_DEVICE_ID_AL_M5229,
-		.init_chipset = ali15x3_init_chipset,
-		.init_channel = ali15x3_init_channel,
-		.init_dma = ali15x3_init_dma,
-		.enablebits = { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
-		.bootable = ON_BOARD
-	}
-};
-
-int __init init_ali15x3(void)
+void __init fixup_device_ali15x3 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
+	if (dev->resource[0].start != 0x01F1)
+		ide_register_xp_fix(dev);
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
-
-        return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/ide/amd74xx.c	Tue Aug 27 12:28:08 2002
@@ -1,371 +1,519 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * $Id: amd74xx.c,v 2.8 2002/03/14 11:52:20 vojtech Exp $
- *
- *  Copyright (c) 2000-2002 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Andre Hedrick
- */
-
-/*
- * AMD 755/756/766/8111 IDE driver for Linux.
- *
- * UDMA66 and higher modes are autoenabled only in case the BIOS has detected a
- * 80 wire cable. To ignore the BIOS data and assume the cable is present, use
- * 'ide0=ata66' or 'ide1=ata66' on the kernel command line.
- */
-
 /*
- * 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.
+ * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
  *
- * 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.
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
  *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
+#include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
-#define AMD_IDE_ENABLE		(0x00 + amd_config->base)
-#define AMD_IDE_CONFIG		(0x01 + amd_config->base)
-#define AMD_CABLE_DETECT	(0x02 + amd_config->base)
-#define AMD_DRIVE_TIMING	(0x08 + amd_config->base)
-#define AMD_8BIT_TIMING		(0x0e + amd_config->base)
-#define AMD_ADDRESS_SETUP	(0x0c + amd_config->base)
-#define AMD_UDMA_TIMING		(0x10 + amd_config->base)
-
-#define AMD_UDMA		0x07
-#define AMD_UDMA_33		0x01
-#define AMD_UDMA_66		0x02
-#define AMD_UDMA_100		0x03
-#define AMD_BAD_SWDMA		0x08
-#define AMD_BAD_FIFO		0x10
+#define DISPLAY_VIPER_TIMINGS
 
-/*
- * AMD SouthBridge chips.
- */
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
 
-static struct amd_ide_chip {
-	unsigned short id;
-	unsigned char rev;
-	unsigned int base;
-	unsigned char flags;
-} amd_ide_chips[] = {
-	{ PCI_DEVICE_ID_AMD_8111_IDE,  0x00, 0x40, AMD_UDMA_100 },			/* AMD-8111 */
-	{ PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 },			/* AMD-768 Opus */
-	{ PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO },	/* AMD-766 Viper */
-	{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x07, 0x40, AMD_UDMA_66 },			/* AMD-756/c4+ Viper */
-	{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_BAD_SWDMA },	/* AMD-756 Viper */
-	{ PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },	/* AMD-755 Cobra */
-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 },			/* nVidia nForce */
-	{ 0 }
-};
-
-static struct amd_ide_chip *amd_config;
-static unsigned char amd_enabled;
-static unsigned int amd_80w;
-
-static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3 };
-#if 0
-static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 1 };
-#endif
-static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
+static int amd74xx_get_info(char *, char **, off_t, int);
+extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
 
-/*
- * amd_set_speed() writes timing values to the chipset registers
- */
-
-static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing)
+static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	unsigned char t;
-
-	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
-	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-	pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8 c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = IN_BYTE((unsigned short)bibma + 0x02);
+	c1 = IN_BYTE((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"AMD %04X VIPER Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
 
-	pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
-		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-	pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
-		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+byte amd74xx_proc = 0;
 
-	switch (amd_config->flags & AMD_UDMA) {
-		case AMD_UDMA_33:  t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-		case AMD_UDMA_66:  t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
-		case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
-		default: return;
+static int amd74xx_mode5_check (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+		case PCI_DEVICE_ID_AMD_OPUS_7441:
+			return 1;
+		default:
+			return 0;
 	}
-
-	pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
 }
 
-/*
- * amd_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
-
-static int amd_set_drive(struct ata_device *drive, unsigned char speed)
+static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
 {
-	struct ata_device *peer = drive->channel->drives + (~drive->dn & 1);
-	struct ata_timing t, p;
-	int T, UT;
+	unsigned int class_rev;
 
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
+	if (amd74xx_mode5_check(dev))
+		return 1;
 
-	T = 1000000000 / system_bus_speed;
-	UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev >= 7) ? 1 : 0);
+}
 
-	ata_timing_compute(drive, speed, &t, T, UT);
+static int amd74xx_swdma_error (ide_drive_t *drive)
+{
+	printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
+	return 0;
+}
 
-	if (peer->present) {
-		ata_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ata_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+static byte amd74xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	byte mode = 0x00;
+
+        switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_OPUS_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:	{ mode |= 0x03; break; }
+		case PCI_DEVICE_ID_AMD_VIPER_7409:	{ mode |= 0x02; break; }
+		case PCI_DEVICE_ID_AMD_COBRA_7401:	{ mode |= 0x01; break; }
+		default:
+			return (mode &= ~0xFF);
 	}
 
-	if (speed == XFER_UDMA_5 && system_bus_speed <= 33333) t.udma = 1;
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
 
-	amd_set_speed(drive->channel->pci_dev, drive->dn, &t);
+static byte amd74xx_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = amd74xx_ratemask(drive);
 
-	return 0;
+	switch(mode) {
+		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
 }
 
 /*
- * amd74xx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
+ * Here is where all the hard work goes to program the chipset.
  */
-
-static void amd74xx_tune_drive(struct ata_device *drive, u8 pio)
+static int amd74xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	if (!((amd_enabled >> drive->channel->unit) & 1))
-		return;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte speed		= amd74xx_ratefilter(drive, xferspeed);
+	byte drive_pci		= 0x00;
+	byte drive_pci2		= 0x00;
+	byte ultra_timing	= 0x00;
+	byte dma_pio_timing	= 0x00;
+	byte pio_timing		= 0x00;
+
+        switch (drive->dn) {
+		case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
+		case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
+		case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
+		case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
+		default:
+                        return -1;
+        }
+
+	pci_read_config_byte(dev, drive_pci, &ultra_timing);
+	pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
+	pci_read_config_byte(dev, 0x4c, &pio_timing);
+
+	ultra_timing	&= ~0xC7;
+	dma_pio_timing	&= ~0xFF;
+	pio_timing	&= ~(0x03 << drive->dn);
 
-	if (pio == 255) {
-		amd_set_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
-	}
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			ultra_timing |= 0x46;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_4:
+			ultra_timing |= 0x45;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_3:
+			ultra_timing |= 0x44;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_2:
+			ultra_timing |= 0x40;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_1:
+			ultra_timing |= 0x41;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_0:
+			ultra_timing |= 0x42;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_2:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_1:
+			dma_pio_timing |= 0x21;
+			break;
+		case XFER_MW_DMA_0:
+			dma_pio_timing |= 0x77;
+			break;
+		case XFER_SW_DMA_2:
+			if (!amd74xx_swdma_check(dev))
+				return amd74xx_swdma_error(drive);
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_SW_DMA_1:
+			if (!amd74xx_swdma_check(dev))
+				return amd74xx_swdma_error(drive);
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_SW_DMA_0:
+			if (!amd74xx_swdma_check(dev))
+				return amd74xx_swdma_error(drive);
+			dma_pio_timing |= 0xA8;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_PIO_3:
+			dma_pio_timing |= 0x22;
+			break;
+		case XFER_PIO_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_PIO_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_PIO_0:
+		default:
+			dma_pio_timing |= 0xA8;
+			break;
+        }
 
-	amd_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
-}
+	pio_timing |= (0x03 << drive->dn);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int __init amd_modes_map(struct ata_channel *ch)
-{
-	short w80 = ch->udma_four;
-	int map = XFER_EPIO | XFER_MWDMA | XFER_UDMA |
-		  ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
-		  (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
-		  (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0);
+	pci_write_config_byte(dev, drive_pci, ultra_timing);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
+	pci_write_config_byte(dev, 0x4c, pio_timing);
 
-	return map;
+	return (ide_config_drive_speed(drive, speed));
 }
-#endif
-
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
 
-static unsigned int __init amd74xx_init_chipset(struct pci_dev *dev)
+static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
 {
-	unsigned char t;
-	unsigned int u;
-	int i;
+	byte speed;
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4;break;
+		case 3:		speed = XFER_PIO_3;break;
+		case 2:		speed = XFER_PIO_2;break;
+		case 1:		speed = XFER_PIO_1;break;
+		default:	speed = XFER_PIO_0;break;
+	}
+	(void) amd74xx_tune_chipset(drive, speed);
+}
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
 /*
- * Find out what AMD IDE is this.
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
  */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id   = drive->id;
+	byte mode		= amd74xx_ratemask(drive);
+	byte swdma		= amd74xx_swdma_check(HWIF(drive)->pci_dev);
+	byte speed		= 0;
+	int  rval;
+
+	amd74xx_tune_drive(drive, 5);
+	
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if ((id->dma_1word & 0x0004) && (swdma))
+				{ speed = XFER_SW_DMA_2; break; }
+			if ((id->dma_1word & 0x0002) && (swdma))
+				{ speed = XFER_SW_DMA_1; break; }
+			if ((id->dma_1word & 0x0001) && (swdma))
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
 
-	for (amd_config = amd_ide_chips; amd_config->id; amd_config++) {
-			pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-			if (dev->device == amd_config->id && t >= amd_config->rev)
-				break;
-		}
+	(void) amd74xx_tune_chipset(drive, speed);
+//	return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
+	rval = (int)(   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			 ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			 ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			 (((id->dma_1word >> 8) & 7) && (swdma)) ? ide_dma_on :
+						     ide_dma_off_quietly);
+	return rval;
+}
 
-	if (!amd_config->id) {
-		printk(KERN_WARNING "AMD_IDE: Unknown AMD IDE Chip, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
-		return -ENODEV;
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x003F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    ((id->dma_1word & 0x007) &&
+			     (amd74xx_swdma_check(HWIF(drive)->pci_dev)))) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+			
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		amd74xx_tune_drive(drive, 5);
 	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
 
 /*
- * Check 80-wire cable presence.
+ * amd74xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
  */
 
-	switch (amd_config->flags & AMD_UDMA) {
-
-		case AMD_UDMA_100:
-			pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
-			amd_80w = ((u & 0x3) ? 1 : 0) | ((u & 0xc) ? 2 : 0);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
-					printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n");
-					amd_80w |= (1 << (1 - (i >> 4)));
-				}
-			break;
-
-		case AMD_UDMA_66:
-			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if ((u >> i) & 4)
-					amd_80w |= (1 << (1 - (i >> 4)));
+int amd74xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default:
 			break;
 	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	pci_read_config_dword(dev, AMD_IDE_ENABLE, &u);
-	amd_enabled = ((u & 1) ? 2 : 0) | ((u & 2) ? 1 : 0);
-
-/*
- * Take care of prefetch & postwrite.
- */
-
-	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
-	pci_write_config_byte(dev, AMD_IDE_CONFIG,
-		(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
+unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
+{
+	unsigned long fixdma_base = pci_resource_start(dev, 4);
 
-/*
- * Print the boot message.
- */
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!amd74xx_swdma_check(dev))
+		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (!fixdma_base) {
+		/*
+		 *
+		 */
+	} else {
+		/*
+		 * enable DMA capable bit, and "not" simplex only
+		 */
+		OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
 
-	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n",
-		dev->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name);
+		if (IN_BYTE(fixdma_base+2) & 0x80)
+			printk("%s: simplex device: DMA will fail!!\n", name);
+	}
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!amd74xx_proc) {
+		amd74xx_proc = 1;
+		bmide_dev = dev;
+		amd74xx_display_info = &amd74xx_get_info;
+	}
+#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
 
 	return 0;
 }
 
-static unsigned int __init amd74xx_ata66_check(struct ata_channel *hwif)
+unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
 {
-	return ((amd_enabled & amd_80w) >> hwif->unit) & 1;
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte cable_80_pin[2]	= { 0, 0 };
+	byte ata66		= 0;
+	byte tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x42, &tmpbyte);
+
+	/*
+	 * 0x42, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x42, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_OPUS_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
+#ifdef CONFIG_AMD74XX_OVERRIDE
+	return(1);
+#else
+	return (unsigned int) ata66;
+#endif /* CONFIG_AMD74XX_OVERRIDE */
 }
 
-static void __init amd74xx_init_channel(struct ata_channel *hwif)
+void __init ide_init_amd74xx (ide_hwif_t *hwif)
 {
-	int i;
-
-	hwif->udma_four = amd74xx_ata66_check(hwif);
-
 	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd_set_drive;
+	hwif->speedproc = &amd74xx_tune_chipset;
 
-	hwif->io_32bit = 1;
-	hwif->unmask = 1;
-
-	for (i = 0; i < 2; i++) {
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->unit * 2 + i;
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		hwif->autodma = 0;
+		return;
 	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->highmem = 1;
-		hwif->modes_map = amd_modes_map(hwif);
-		hwif->udma_setup = udma_generic_setup;
-	}
-#endif
+#ifndef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc = &amd74xx_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-/*
- * We allow the BM-DMA driver only work on enabled interfaces.
- */
-static void __init amd74xx_init_dma(struct ata_channel *ch, unsigned long dmabase)
+void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
 {
-	if ((amd_enabled >> ch->unit) & 1)
-		ata_init_dma(ch, dmabase);
+	ide_setup_dma(hwif, dmabase, 8);
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_AMD,
-		.device = PCI_DEVICE_ID_AMD_COBRA_7401,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_AMD,
-		.device = PCI_DEVICE_ID_AMD_VIPER_7409,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		.bootable = ON_BOARD,
-		.flags = ATA_F_SIMPLEX
-	},
-	{
-		.vendor = PCI_VENDOR_ID_AMD,
-		.device = PCI_DEVICE_ID_AMD_VIPER_7411,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_AMD,
-		.device = PCI_DEVICE_ID_AMD_OPUS_7441,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_AMD,
-		.device = PCI_DEVICE_ID_AMD_8111_IDE,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_NVIDIA,
-		.device = PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
-		.init_chipset = amd74xx_init_chipset,
-		.init_channel = amd74xx_init_channel,
-		.init_dma = amd74xx_init_dma,
-		.enablebits = {{0x50,0x01,0x01}, {0x50,0x02,0x02}},
-		.bootable = ON_BOARD
-	},
-};
-
-int __init init_amd74xx(void)
+void __init fixup_device_amd74xx (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+	if (dev->resource[0].start != 0x01F1)
+		ide_register_xp_fix(dev);
 
-        return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+
diff -Nru a/drivers/ide/ata-timing.c b/drivers/ide/ata-timing.c
--- a/drivers/ide/ata-timing.c	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,299 +0,0 @@
-/*
- * $Id: ata-timing.c,v 2.0 2002/03/12 15:48:43 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- * 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., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by e-mail -
- * mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
- * Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include "timing.h"
-
-/*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).  These were taken
- * from ATA/ATAPI-6 standard, rev 0a, except for PIO 5, which is a nonstandard
- * extension and UDMA6, which is currently supported only by Maxtor drives.
- */
-
-struct ata_timing ata_timing[] = {
-
-	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
-	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
-	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
-	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
-
-	{ XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
-	{ XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
-	{ XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
-
-	{ XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0,   0, 150 },
-
-	{ XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
-	{ XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
-	{ XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
-
-	{ XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
-	{ XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
-	{ XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
-
-	{ XFER_PIO_5,     20,  50,  30, 100,  50,  30, 100,   0 },
-	{ XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
-	{ XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
-
-	{ XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
-	{ XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
-	{ XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
-
-	{ XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 },
-
-	{ -1 }
-};
-
-/*
- * Determine the best transfer mode appilcable to a particular drive.  This has
- * then to be matched agains in esp. other drives no the same channel or even
- * the whole particular host chip.
- */
-short ata_timing_mode(struct ata_device *drive, int map)
-{
-	struct hd_driveid *id = drive->id;
-	short best = 0;
-
-	if (!id)
-		return XFER_PIO_SLOW;
-
-	/* Want UDMA and UDMA bitmap valid */
-	if ((map & XFER_UDMA) && (id->field_valid & 4)) {
-		if ((map & XFER_UDMA_133) == XFER_UDMA_133)
-			if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
-
-		if ((map & XFER_UDMA_100) == XFER_UDMA_100)
-			if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
-
-		if ((map & XFER_UDMA_66_4) == XFER_UDMA_66_4)
-			if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 : 0)) return best;
-
-		if ((map & XFER_UDMA_66_3) == XFER_UDMA_66_3)
-			if ((best = (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
-
-                if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
-			    (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
-			    (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best;
-	}
-
-	/* Want MWDMA and drive has EIDE fields */
-	if ((map & XFER_MWDMA) && (id->field_valid & 2)) {
-		if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 :
-			    (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 :
-			    (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0))
-			return best;
-	}
-
-	/* Want SWDMA */
-	if (map & XFER_SWDMA) {
-
-		/* EIDE SWDMA */
-		if (id->field_valid & 2) {
-			if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 :
-				    (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 :
-				    (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0))
-				return best;
-		}
-
-		/* Pre-EIDE style SWDMA */
-		if (id->capability & 1) {
-			if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 :
-				    (id->tDMA == 1) ? XFER_SW_DMA_1 :
-				    (id->tDMA == 0) ? XFER_SW_DMA_0 : 0))
-				return best;
-		}
-	}
-
-	/* EIDE PIO modes */
-	if ((map & XFER_EPIO) && (id->field_valid & 2)) {
-		if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
-			    (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
-			    (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0))
-			return best;
-	}
-
-	return  (drive->id->tPIO == 2) ? XFER_PIO_2 :
-		(drive->id->tPIO == 1) ? XFER_PIO_1 :
-		(drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
-}
-
-/*
- * Just get a pointer to the struct describing the timing values used commonly
- * for a particular mode.
- */
-struct ata_timing* ata_timing_data(short speed)
-{
-	struct ata_timing *t;
-
-	for (t = ata_timing; t->mode != speed; t++)
-		if (t->mode < 0)
-			return NULL;
-	return t;
-}
-
-/*
- * This is just unit conversion.
- */
-void ata_timing_quantize(struct ata_timing *t, struct ata_timing *q,
-		int T, int UT)
-{
-	q->setup   = EZ(t->setup   * 1000,  T);
-	q->act8b   = EZ(t->act8b   * 1000,  T);
-	q->rec8b   = EZ(t->rec8b   * 1000,  T);
-	q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
-	q->active  = EZ(t->active  * 1000,  T);
-	q->recover = EZ(t->recover * 1000,  T);
-	q->cycle   = EZ(t->cycle   * 1000,  T);
-	q->udma    = EZ(t->udma    * 1000, UT);
-}
-
-/*
- * Match against each other the timing setup for two devices on one channel.
- * Becouse they share the electrical interface we can unsually only use the
- * lowest common denominator between them.
- */
-void ata_timing_merge(struct ata_timing *a, struct ata_timing *b,
-		struct ata_timing *m, unsigned int what)
-{
-	if (what & IDE_TIMING_SETUP)
-		m->setup   = max(a->setup,   b->setup);
-	if (what & IDE_TIMING_ACT8B)
-		m->act8b   = max(a->act8b,   b->act8b);
-	if (what & IDE_TIMING_REC8B)
-		m->rec8b   = max(a->rec8b,   b->rec8b);
-	if (what & IDE_TIMING_CYC8B)
-		m->cyc8b   = max(a->cyc8b,   b->cyc8b);
-	if (what & IDE_TIMING_ACTIVE)
-		m->active  = max(a->active,  b->active);
-	if (what & IDE_TIMING_RECOVER)
-		m->recover = max(a->recover, b->recover);
-	if (what & IDE_TIMING_CYCLE)
-		m->cycle   = max(a->cycle,   b->cycle);
-	if (what & IDE_TIMING_UDMA)
-		m->udma    = max(a->udma,    b->udma);
-}
-
-/*
- * Not all controllers can do separate timing for 8-bit command transfers
- * and 16-bit data transfers.
- */
-
-void ata_timing_merge_8bit(struct ata_timing *t)
-{
-	t->active = max(t->active, t->act8b);
-	t->recover = max(t->recover, t->rec8b);
-	t->cycle = max(t->cycle, t->cyc8b);
-}
-
-int ata_timing_compute(struct ata_device *drive, short speed, struct ata_timing *t,
-		int T, int UT)
-{
-	struct hd_driveid *id = drive->id;
-	struct ata_timing *s, p;
-
-	/* Find the mode.
-	 */
-
-	if (!(s = ata_timing_data(speed)))
-		return -EINVAL;
-
-	memcpy(t, s, sizeof(struct ata_timing));
-
-	/* If the drive is an EIDE drive, it can tell us it needs extended
-	 * PIO/MWDMA cycle timing.
-	 */
-
-	/* EIDE drive */
-	if (id && id->field_valid & 2) {
-		memset(&p, 0, sizeof(p));
-
-		switch (speed & XFER_MODE) {
-			case XFER_PIO:
-				if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio;
-						    else p.cycle = p.cyc8b = id->eide_pio_iordy;
-				break;
-
-			case XFER_MWDMA:
-				p.cycle = id->eide_dma_min;
-				break;
-		}
-
-		ata_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
-	}
-
-	/* Convert the timing to bus clock counts.
-	 */
-
-	ata_timing_quantize(t, t, T, UT);
-
-	/* Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
-	 * S.M.A.R.T and some other commands. We have to ensure that the DMA
-	 * cycle timing is slower/equal than the fastest PIO timing.
-	 */
-
-	if ((speed & XFER_MODE) != XFER_PIO) {
-		ata_timing_compute(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT);
-		ata_timing_merge(&p, t, t, IDE_TIMING_ALL);
-	}
-
-	/* Lenghten active & recovery time so that cycle time is correct.
-	 */
-
-	if (t->act8b + t->rec8b < t->cyc8b) {
-		t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
-		t->rec8b = t->cyc8b - t->act8b;
-	}
-
-	if (t->active + t->recover < t->cycle) {
-		t->active += (t->cycle - (t->active + t->recover)) / 2;
-		t->recover = t->cycle - t->active;
-	}
-
-	return 0;
-}
-
-u8 ata_best_pio_mode(struct ata_device *drive)
-{
-	static u16 eide_pio_timing[6] = { 600, 383, 240, 180, 120, 90 };
-	u16 pio_min;
-	u8 pio;
-
-	pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
-
-	/* downgrade mode if necessary */
-	pio_min = (pio > 2) ? drive->id->eide_pio_iordy : drive->id->eide_pio;
-
-	if (pio_min)
-		while (pio && pio_min > eide_pio_timing[pio])
-			pio--;
-
-	if (!pio && drive->id->tPIO)
-		return XFER_PIO_SLOW;
-
-	/* don't allow XFER_PIO_5 for now */
-	return XFER_PIO_0 + min_t(u8, pio, 4);
-}
diff -Nru a/drivers/ide/atapi.c b/drivers/ide/atapi.c
--- a/drivers/ide/atapi.c	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,186 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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.
- */
-
-/*
- * Code common among all the ATAPI device drivers.
- *
- * Ideally this should evolve in to a unified driver.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/cdrom.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/atapi.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-
-/*
- * Initializes a packet command. Used by tape and floppy driver.
- */
-void atapi_init_pc(struct atapi_packet_command *pc)
-{
-	memset(pc->c, 0, 12);
-	pc->retries = 0;
-	pc->flags = 0;
-	pc->request_transfer = 0;
-	pc->buffer = pc->pc_buffer;
-	pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
-	pc->b_data = NULL;
-	pc->bio = NULL;
-}
-
-/*
- * Too bad. The drive wants to send us data which we are not ready to accept.
- * Just throw it away.
- */
-void atapi_discard_data(struct ata_device *drive, unsigned int bcount)
-{
-	while (bcount--)
-		IN_BYTE(IDE_DATA_REG);
-}
-
-void atapi_write_zeros(struct ata_device *drive, unsigned int bcount)
-{
-	while (bcount--)
-		OUT_BYTE(0, IDE_DATA_REG);
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes, so if
- * an odd n is specified, be sure that there's at least one extra byte
- * allocated for the buffer.
- */
-void atapi_read(struct ata_device *drive, u8 *buf, unsigned int n)
-{
-	if (drive->channel->atapi_read) {
-		drive->channel->atapi_read(drive, buf, n);
-		return;
-	}
-
-	++n;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buf, n / 2);
-		return;
-	}
-#endif
-	ata_read(drive, buf, n / 4);
-	if ((n & 0x03) >= 2)
-		insw(IDE_DATA_REG, buf + (n & ~0x03), 1);
-}
-
-void atapi_write(struct ata_device *drive, u8 *buf, unsigned int n)
-{
-	if (drive->channel->atapi_write) {
-		drive->channel->atapi_write(drive, buf, n);
-		return;
-	}
-
-	++n;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buf, n / 2);
-		return;
-	}
-#endif
-	ata_write(drive, buf, n / 4);
-	if ((n & 0x03) >= 2)
-		outsw(IDE_DATA_REG, buf + (n & ~0x03), 1);
-}
-
-
-/*
- * This function issues a special IDE device request onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the request
- * queue, and the function sleeps until it has been processed.  This is for use
- * when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of the request
- * queue, displacing the currently-being-processed request and this function
- * returns immediately without waiting for the new rq to be completed.  This is
- * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom
- * driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the request queue,
- * and the function returns immediately without waiting for the new rq to be
- * completed. This is again intended for careful use by the ATAPI tape/cdrom
- * driver code.
- */
-int ide_do_drive_cmd(struct ata_device *drive, struct request *rq, ide_action_t action)
-{
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
-	unsigned int major = ch->major;
-	request_queue_t *q = &drive->queue;
-	struct list_head *queue_head = &q->queue_head;
-	DECLARE_COMPLETION(wait);
-
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (ch->chipset == ide_pdc4030 && rq->buffer)
-		return -ENOSYS;  /* special drive cmds not supported */
-#endif
-	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = mk_kdev(major, (drive->select.b.unit) << PARTN_BITS);
-	if (action == ide_wait)
-		rq->waiting = &wait;
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	if (action == ide_preempt)
-		drive->rq = NULL;
-	else if (!blk_queue_empty(&drive->queue))
-		queue_head = queue_head->prev;	/* ide_end and ide_wait */
-
-	__elv_add_request(q, rq, queue_head);
-
-	do_ide_request(q);
-
-	spin_unlock_irqrestore(ch->lock, flags);
-
-	if (action == ide_wait) {
-		wait_for_completion(&wait);	/* wait for it to be serviced */
-		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
-	}
-
-	return 0;
-}
-
-EXPORT_SYMBOL(ide_do_drive_cmd);
-EXPORT_SYMBOL(atapi_discard_data);
-EXPORT_SYMBOL(atapi_write_zeros);
-EXPORT_SYMBOL(atapi_init_pc);
-
-EXPORT_SYMBOL(atapi_read);
-EXPORT_SYMBOL(atapi_write);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/ataraid.c b/drivers/ide/ataraid.c
--- a/drivers/ide/ataraid.c	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,301 +0,0 @@
-/*
-   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/semaphore.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-#include <linux/kdev_t.h>
-#include <linux/swap.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static struct raid_device_operations *ataraid_ops[16];
-
-static int ataraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg);
-static int ataraid_open(struct inode *inode, struct file *filp);
-static int ataraid_release(struct inode *inode, struct file *filp);
-static void ataraid_split_request(request_queue_t * q, int rw,
-				  struct buffer_head *bh);
-
-
-struct gendisk ataraid_gendisk;
-static int ataraid_readahead[256];
-
-static struct block_device_operations ataraid_fops = {
-	.owner = THIS_MODULE,
-	.open = ataraid_open,
-	.release = ataraid_release,
-	.ioctl = ataraid_ioctl,
-};
-
-
-
-static DECLARE_MUTEX(ataraid_sem);
-
-/* Bitmap for the devices currently in use */
-static unsigned int ataraiduse;
-
-
-/* stub fops functions */
-
-static int ataraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	int minor;
-	minor = minor(inode->i_rdev) >> SHIFT;
-
-	if ((ataraid_ops[minor]) && (ataraid_ops[minor]->ioctl))
-		return (ataraid_ops[minor]->ioctl) (inode, file, cmd, arg);
-	return -EINVAL;
-}
-
-static int ataraid_open(struct inode *inode, struct file *filp)
-{
-	int minor;
-	minor = minor(inode->i_rdev) >> SHIFT;
-
-	if ((ataraid_ops[minor]) && (ataraid_ops[minor]->open))
-		return (ataraid_ops[minor]->open) (inode, filp);
-	return -EINVAL;
-}
-
-
-static int ataraid_release(struct inode *inode, struct file *filp)
-{
-	int minor;
-	minor = minor(inode->i_rdev) >> SHIFT;
-
-	if ((ataraid_ops[minor]) && (ataraid_ops[minor]->release))
-		return (ataraid_ops[minor]->release) (inode, filp);
-	return -EINVAL;
-}
-
-static int ataraid_make_request(request_queue_t * q, int rw,
-				struct buffer_head *bh)
-{
-	int minor;
-	int retval;
-	minor = minor(bh->b_rdev) >> SHIFT;
-
-	if ((ataraid_ops[minor]) && (ataraid_ops[minor]->make_request)) {
-
-		retval = (ataraid_ops[minor]->make_request) (q, rw, bh);
-		if (retval == -1) {
-			ataraid_split_request(q, rw, bh);
-			return 0;
-		} else
-			return retval;
-	}
-	return -EINVAL;
-}
-
-struct buffer_head *ataraid_get_bhead(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr = kmalloc(sizeof(struct buffer_head), GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_bhead);
-
-struct ataraid_bh_private *ataraid_get_private(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr = kmalloc(sizeof(struct ataraid_bh_private), GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_private);
-
-void ataraid_end_request(struct buffer_head *bh, int uptodate)
-{
-	struct ataraid_bh_private *private = bh->b_private;
-
-	if (private == NULL)
-		BUG();
-
-	if (atomic_dec_and_test(&private->count)) {
-		private->parent->b_end_io(private->parent, uptodate);
-		private->parent = NULL;
-		kfree(private);
-	}
-	kfree(bh);
-}
-
-EXPORT_SYMBOL(ataraid_end_request);
-
-static void ataraid_split_request(request_queue_t * q, int rw,
-				  struct buffer_head *bh)
-{
-	struct buffer_head *bh1, *bh2;
-	struct ataraid_bh_private *private;
-	bh1 = ataraid_get_bhead();
-	bh2 = ataraid_get_bhead();
-
-	/* If either of those ever fails we're doomed */
-	if ((!bh1) || (!bh2))
-		BUG();
-	private = ataraid_get_private();
-	if (private == NULL)
-		BUG();
-
-	memcpy(bh1, bh, sizeof(*bh));
-	memcpy(bh2, bh, sizeof(*bh));
-
-	bh1->b_end_io = ataraid_end_request;
-	bh2->b_end_io = ataraid_end_request;
-
-	bh2->b_rsector += bh->b_size >> 10;
-	bh1->b_size /= 2;
-	bh2->b_size /= 2;
-	private->parent = bh;
-
-	bh1->b_private = private;
-	bh2->b_private = private;
-	atomic_set(&private->count, 2);
-
-	bh2->b_data += bh->b_size / 2;
-
-	generic_make_request(rw, bh1);
-	generic_make_request(rw, bh2);
-}
-
-
-
-
-/* device register / release functions */
-
-
-int ataraid_get_device(struct raid_device_operations *fops)
-{
-	int bit;
-	down(&ataraid_sem);
-	if (ataraiduse == ~0U) {
-		up(&ataraid_sem);
-		return -ENODEV;
-	}
-	bit = ffz(ataraiduse);
-	ataraiduse |= 1 << bit;
-	ataraid_ops[bit] = fops;
-	up(&ataraid_sem);
-	return bit;
-}
-
-void ataraid_release_device(int device)
-{
-	down(&ataraid_sem);
-
-	if ((ataraiduse & (1 << device)) == 0)
-		BUG();		/* device wasn't registered at all */
-
-	ataraiduse &= ~(1 << device);
-	ataraid_ops[device] = NULL;
-	up(&ataraid_sem);
-}
-
-void ataraid_register_disk(int device, long size)
-{
-	register_disk(&ataraid_gendisk, mk_kdev(ATAMAJOR, 16 * device), 16,
-		      &ataraid_fops, size);
-
-}
-
-static __init int ataraid_init(void)
-{
-	int i;
-	for (i = 0; i < 256; i++)
-		ataraid_readahead[i] = 1023;
-
-	/* setup the gendisk structure */
-	ataraid_gendisk.part =
-	    kmalloc(256 * sizeof(struct hd_struct), GFP_KERNEL);
-	if (ataraid_gendisk.part == NULL) {
-		printk(KERN_ERR
-		       "ataraid: Couldn't allocate memory, aborting \n");
-		return -1;
-	}
-
-	memset(&ataraid_gendisk.part[0], 0,
-	       256 * sizeof(struct hd_struct));
-
-
-	ataraid_gendisk.major = ATAMAJOR;
-	ataraid_gendisk.major_name = "ataraid";
-	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.nr_real = 16;
-	ataraid_gendisk.fops = &ataraid_fops;
-
-
-	add_gendisk(&ataraid_gendisk);
-
-	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
-		printk(KERN_ERR "ataraid: Could not get major %d \n",
-		       ATAMAJOR);
-		return -1;
-	}
-
-
-
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),
-			       ataraid_make_request);
-
-	return 0;
-}
-
-
-static void __exit ataraid_exit(void)
-{
-	unregister_blkdev(ATAMAJOR, "ataraid");
-
-	del_gendisk(&ataraid_gendisk);
-
-	if (ataraid_gendisk.part) {
-		kfree(ataraid_gendisk.part);
-		ataraid_gendisk.part = NULL;
-	}
-}
-
-module_init(ataraid_init);
-module_exit(ataraid_exit);
-
-
-
-EXPORT_SYMBOL(ataraid_get_device);
-EXPORT_SYMBOL(ataraid_release_device);
-EXPORT_SYMBOL(ataraid_gendisk);
-EXPORT_SYMBOL(ataraid_register_disk);
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/ataraid.h b/drivers/ide/ataraid.h
--- a/drivers/ide/ataraid.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,72 +0,0 @@
-/*
-   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/semaphore.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#define ATAMAJOR 114
-#define SHIFT 4
-#define MINOR_MASK 15
-#define MAJOR_MASK 15
-
-                                        
-/* raid_device_operations is a light struct block_device_operations with an
-   added method for make_request */
-struct raid_device_operations {
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
-};
-
-
-struct geom {
-	unsigned char heads;
-	unsigned int cylinders;
-	unsigned char sectors;
-};
-
-/* structure for the splitting of bufferheads */
-
-struct ataraid_bh_private {
-	struct buffer_head *parent;
-	atomic_t count;
-};
-
-extern struct gendisk ataraid_gendisk;
-
-extern int ataraid_get_device(struct raid_device_operations *fops);
-extern void ataraid_release_device(int device);
-extern int get_blocksize(kdev_t dev);
-extern void ataraid_register_disk(int device,long size);
-extern struct buffer_head *ataraid_get_bhead(void);
-extern struct ataraid_bh_private *ataraid_get_private(void);
-extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
-
-
-
-
-
diff -Nru a/drivers/ide/buddha.c b/drivers/ide/buddha.c
--- a/drivers/ide/buddha.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/buddha.c	Tue Aug 27 12:28:08 2002
@@ -117,7 +117,7 @@
      *  Check and acknowledge the interrupt status
      */
 
-static int buddha_ack_intr(struct ata_channel *hwif)
+static int buddha_ack_intr(ide_hwif_t *hwif)
 {
     unsigned char ch;
 
@@ -127,7 +127,7 @@
     return 1;
 }
 
-static int xsurf_ack_intr(struct ata_channel *hwif)
+static int xsurf_ack_intr(ide_hwif_t *hwif)
 {
     unsigned char ch;
 
@@ -202,9 +202,9 @@
 						xsurf_offsets, 0,
 						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
 						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}
-
-			index = ide_register_hw(&hw);
+			}	
+			
+			index = ide_register_hw(&hw, NULL);
 			if (index != -1) {
 				printk("ide%d: ", index);
 				switch(type) {
diff -Nru a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
--- a/drivers/ide/cmd640.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/ide/cmd640.c	Tue Aug 27 12:28:08 2002
@@ -1,10 +1,12 @@
 /*
+ *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
+ *
  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
  */
 
 /*
  *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *			mlord@pobox.com (Mark Lord)
+ *  			mlord@pobox.com (Mark Lord)
  *
  *  See linux/MAINTAINERS for address of current maintainer.
  *
@@ -21,7 +23,7 @@
  *
  *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
  *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, martin@dalecki.de,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
  *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
  *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
  *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
@@ -96,6 +98,7 @@
  *			 (patch courtesy of Zoltan Hidvegi)
  */
 
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
 #define CMD640_PREFETCH_MASKS 1
 
 #include <linux/config.h>
@@ -106,14 +109,13 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/pci.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 
 /*
  * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
@@ -156,7 +158,7 @@
 #define	CMDTIM		0x52
 #define	ARTTIM0		0x53
 #define	DRWTIM0		0x54
-#define ARTTIM1		0x55
+#define ARTTIM1 	0x55
 #define DRWTIM1		0x56
 #define ARTTIM23	0x57
 #define   ARTTIM23_DIS_RA2	0x04
@@ -165,44 +167,38 @@
 #define BRST		0x59
 
 /*
- * Protects register file access from overlapping on primary and secondary
- * channel, since those share hardware resources.
- */
-static spinlock_t cmd640_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
-
-/*
  * Registers and masks for easy access by drive index:
  */
-static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
 
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 
-static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
 
 /*
  * Current cmd640 timing values for each drive.
  * The defaults for each are the slowest possible timings.
  */
-static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
 
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
 /*
  * These are initialized to point at the devices we control
  */
-static struct ata_channel *cmd_hwif0, *cmd_hwif1;
-static struct ata_device *cmd_drives[4];
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
 
 /*
  * Interface to access cmd640x registers
  */
 static unsigned int cmd640_key;
-static void (*put_cmd640_reg)(unsigned short reg, u8 val);
-static u8 (*get_cmd640_reg)(unsigned short reg);
+static void (*put_cmd640_reg)(unsigned short reg, byte val);
+static byte (*get_cmd640_reg)(unsigned short reg);
 
 /*
  * This is read from the CFR reg, and is used in several places.
@@ -217,81 +213,81 @@
 
 /* PCI method 1 access */
 
-static void put_cmd640_reg_pci1 (unsigned short reg, u8 val)
+static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
 {
 	unsigned long flags;
-	
-	spin_lock_irqsave(&pci_lock, flags);
+
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
 	outb_p(val, (reg & 3) | 0xcfc);
-	spin_unlock_irqrestore(&pci_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static u8 get_cmd640_reg_pci1 (unsigned short reg)
+static byte get_cmd640_reg_pci1 (unsigned short reg)
 {
-	u8 b;
+	byte b;
 	unsigned long flags;
 
-	spin_lock_irqsave(&pci_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b=inb_p((reg & 3) | 0xcfc);
-	spin_unlock_irqrestore(&pci_lock, flags);
+	b = inb_p((reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return b;
 }
 
 /* PCI method 2 access (from CMD datasheet) */
 
-static void put_cmd640_reg_pci2 (unsigned short reg, u8 val)
+static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&pci_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p(0x10, 0xcf8);
 	outb_p(val, cmd640_key + reg);
 	outb_p(0, 0xcf8);
-	spin_unlock_irqrestore(&pci_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static u8 get_cmd640_reg_pci2 (unsigned short reg)
+static byte get_cmd640_reg_pci2 (unsigned short reg)
 {
-	u8 b;
+	byte b;
 	unsigned long flags;
 
-	spin_lock_irqsave(&pci_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p(0x10, 0xcf8);
 	b = inb_p(cmd640_key + reg);
 	outb_p(0, 0xcf8);
-	spin_unlock_irqrestore(&pci_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return b;
 }
 
 /* VLB access */
 
-static void put_cmd640_reg_vlb (unsigned short reg, u8 val)
+static void put_cmd640_reg_vlb (unsigned short reg, byte val)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&cmd640_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p(reg, cmd640_key);
 	outb_p(val, cmd640_key + 4);
-	spin_unlock_irqrestore(&cmd640_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static u8 get_cmd640_reg_vlb (unsigned short reg)
+static byte get_cmd640_reg_vlb (unsigned short reg)
 {
-	u8 b;
+	byte b;
 	unsigned long flags;
 
-	spin_lock_irqsave(&cmd640_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	outb_p(reg, cmd640_key);
 	b = inb_p(cmd640_key + 4);
-	spin_unlock_irqrestore(&cmd640_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return b;
 }
 
 static int __init match_pci_cmd640_device (void)
 {
-	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
 	unsigned int i;
 	for (i = 0; i < 4; i++) {
 		if (get_cmd640_reg(i) != ven_dev[i])
@@ -313,7 +309,9 @@
 {
 	get_cmd640_reg = get_cmd640_reg_pci1;
 	put_cmd640_reg = put_cmd640_reg_pci1;
-	for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
+	for (cmd640_key = 0x80000000;
+	     cmd640_key <= 0x8000f800;
+	     cmd640_key += 0x800) {
 		if (match_pci_cmd640_device())
 			return 1; /* success */
 	}
@@ -339,7 +337,7 @@
  */
 static int __init probe_for_cmd640_vlb (void)
 {
-	u8 b;
+	byte b;
 
 	get_cmd640_reg = get_cmd640_reg_vlb;
 	put_cmd640_reg = put_cmd640_reg_vlb;
@@ -362,7 +360,7 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&cmd640_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 
 	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
 	udelay(100);
@@ -370,11 +368,11 @@
 		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
 		udelay(100);
 		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
-			spin_unlock_irqrestore(&cmd640_lock, flags);
+			spin_unlock_irqrestore(&ide_lock, flags);
 			return 0; /* nothing responded */
 		}
 	}
-	spin_unlock_irqrestore(&cmd640_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return 1; /* success */
 }
 
@@ -403,19 +401,19 @@
  */
 static void __init check_prefetch (unsigned int index)
 {
-	struct ata_device *drive = cmd_drives[index];
-	u8 b = get_cmd640_reg(prefetch_regs[index]);
+	ide_drive_t *drive = cmd_drives[index];
+	byte b = get_cmd640_reg(prefetch_regs[index]);
 
 	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->channel->no_unmask = 0;
-		drive->channel->no_io_32bit = 1;
-		drive->channel->io_32bit = 0;
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
 	} else {
 #if CMD640_PREFETCH_MASKS
-		drive->channel->no_unmask = 1;
-		drive->channel->unmask = 0;
+		drive->no_unmask = 1;
+		drive->unmask = 0;
 #endif
-		drive->channel->no_io_32bit = 0;
+		drive->no_io_32bit = 0;
 	}
 }
 
@@ -429,7 +427,7 @@
 	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
 	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
 	for (i = 0; i < MAX_HWIFS; i++) {
-		struct ata_channel *hwif = &ide_hwifs[i];
+		ide_hwif_t *hwif = &ide_hwifs[i];
 		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
 			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
 				cmd_hwif0 = hwif;
@@ -450,28 +448,28 @@
  */
 static void set_prefetch_mode (unsigned int index, int mode)
 {
-	struct ata_device *drive = cmd_drives[index];
+	ide_drive_t *drive = cmd_drives[index];
 	int reg = prefetch_regs[index];
-	u8 b;
+	byte b;
 	unsigned long flags;
 
-	spin_lock_irqsave(&cmd640_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	b = get_cmd640_reg(reg);
 	if (mode) {	/* want prefetch on? */
-# if CMD640_PREFETCH_MASKS
-		drive->channel->no_unmask = 1;
-		drive->channel->unmask = 0;
-# endif
-		drive->channel->no_io_32bit = 0;
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
 		b &= ~prefetch_masks[index];	/* enable prefetch */
 	} else {
-		drive->channel->no_unmask = 0;
-		drive->channel->no_io_32bit = 1;
-		drive->channel->io_32bit = 0;
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
 		b |= prefetch_masks[index];	/* disable prefetch */
 	}
 	put_cmd640_reg(reg, b);
-	spin_unlock_irqrestore(&cmd640_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
@@ -479,7 +477,7 @@
  */
 static void display_clocks (unsigned int index)
 {
-	u8 active_count, recovery_count;
+	byte active_count, recovery_count;
 
 	active_count = active_counts[index];
 	if (active_count == 1)
@@ -496,7 +494,7 @@
  * Pack active and recovery counts into single byte representation
  * used by controller
  */
-static inline u8 pack_nibbles (u8 upper, u8 lower)
+inline static byte pack_nibbles (byte upper, byte lower)
 {
 	return ((upper & 0x0f) << 4) | (lower & 0x0f);
 }
@@ -506,7 +504,7 @@
  */
 static void __init retrieve_drive_counts (unsigned int index)
 {
-	u8 b;
+	byte b;
 
 	/*
 	 * Get the internal setup timing, and convert to clock count
@@ -536,9 +534,9 @@
 static void program_drive_counts (unsigned int index)
 {
 	unsigned long flags;
-	u8 setup_count    = setup_counts[index];
-	u8 active_count   = active_counts[index];
-	u8 recovery_count = recovery_counts[index];
+	byte setup_count    = setup_counts[index];
+	byte active_count   = active_counts[index];
+	byte recovery_count = recovery_counts[index];
 
 	/*
 	 * Set up address setup count and drive read/write timing registers.
@@ -572,7 +570,7 @@
 	/*
 	 * Now that everything is ready, program the new timings
 	 */
-	spin_lock_irqsave(&cmd640_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	/*
 	 * Program the address_setup clocks into ARTTIM reg,
 	 * and then the active/recovery counts into the DRWTIM reg
@@ -581,21 +579,24 @@
 	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
 	put_cmd640_reg(arttim_regs[index], setup_count);
 	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-	spin_unlock_irqrestore(&cmd640_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
  * Set a specific pio_mode for a drive
  */
-static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time, unsigned int active_time, unsigned int setup_time)
+static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
 {
-	int recovery_time, clock_time;
-	u8 setup_count, active_count;
-	u8 recovery_count, recovery_count2;
-	u8 cycle_count;
-
+	int setup_time, active_time, recovery_time, clock_time;
+	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = system_bus_clock();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
 	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000000 / system_bus_speed;
+	clock_time = 1000 / bus_speed;
 	cycle_count = (cycle_time + clock_time - 1) / clock_time;
 
 	setup_count = (setup_time + clock_time - 1) / clock_time;
@@ -631,7 +632,7 @@
 	 *
 	 * But we do not, because:
 	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 *	2) in practice this is rarely, if ever, necessary
+	 * 	2) in practice this is rarely, if ever, necessary
 	 */
 	program_drive_counts (index);
 }
@@ -639,19 +640,16 @@
 /*
  * Drive PIO mode selection:
  */
-static void cmd640_tune_drive(struct ata_device *drive, u8 mode_wanted)
+static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
 {
-	u8 b;
-	struct ata_timing *t;
+	byte b;
+	ide_pio_data_t  d;
 	unsigned int index = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cmd640_lock, flags);
 
 	while (drive != cmd_drives[index]) {
 		if (++index > 3) {
-			printk(KERN_ERR "%s: bad news in cmd640_tune_drive\n", drive->name);
-			goto out_lock;
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
 		}
 	}
 	switch (mode_wanted) {
@@ -662,93 +660,70 @@
 			if (mode_wanted)
 				b |= 0x27;
 			put_cmd640_reg(CNTRL, b);
-			printk(KERN_INFO "%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
-			goto out_lock;
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
 
 		case 8: /* set prefetch off */
 		case 9: /* set prefetch on */
 			mode_wanted &= 1;
 			set_prefetch_mode(index, mode_wanted);
 			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			goto out_lock;
+			return;
 	}
 
-	if (mode_wanted == 255)
-		t = ata_timing_data(ata_timing_mode(drive, XFER_PIO | XFER_EPIO));
-	else
-		t = ata_timing_data(XFER_PIO_0 + min_t(u8, mode_wanted, 4));
-
-	cmd640_set_mode(index, t->mode - XFER_PIO_0, t->cycle, t->active, t->setup);
-
-	printk ("%s: selected cmd640 PIO mode%d (%dns)",
-		drive->name, t->mode, t->cycle);
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
 
+	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "");
 	display_clocks(index);
-
-out_lock:
-	spin_unlock_irqrestore(&cmd640_lock, flags);
-
 	return;
 }
 
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
-/**
- *	pci_conf1	-	check for PCI type 1 configuration
- *	
- *	Issues a safe probe sequence for PCI configuration type 1 and
- *	returns non-zero if conf1 is supported. Takes the pci_config lock
- */
- 
 static int pci_conf1(void)
 {
 	u32 tmp;
 	unsigned long flags;
-	
-	spin_lock_irqsave(&pci_lock, flags);
 
+	spin_lock_irqsave(&ide_lock, flags);
 	OUT_BYTE(0x01, 0xCFB);
 	tmp = inl(0xCF8);
 	outl(0x80000000, 0xCF8);
 	if (inl(0xCF8) == 0x80000000) {
-		spin_unlock_irqrestore(&pci_lock, flags);
 		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
 	outl(tmp, 0xCF8);
-	spin_unlock_irqrestore(&pci_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return 0;
 }
 
-/**
- *	pci_conf2	-	check for PCI type 2 configuration
- *	
- *	Issues a safe probe sequence for PCI configuration type 2 and
- *	returns non-zero if conf2 is supported. Takes the pci_config lock.
- */
- 
-
 static int pci_conf2(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&pci_lock, flags);
-	
+
+	spin_lock_irqsave(&ide_lock, flags);
 	OUT_BYTE(0x00, 0xCFB);
 	OUT_BYTE(0x00, 0xCF8);
 	OUT_BYTE(0x00, 0xCFA);
-	if (IN_BYTE(0xCF8) == 0x00 && IN_BYTE(0xCFA) == 0x00) {
-		spin_unlock_irqrestore(&pci_lock, flags);
+	if (IN_BYTE(0xCF8) == 0x00 && IN_BYTE(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
-	spin_unlock_irqrestore(&pci_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return 0;
 }
 
 /*
  * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
  */
-
-int __init ide_probe_for_cmd640x(void)
+int __init ide_probe_for_cmd640x (void)
 {
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	int second_port_toggled = 0;
@@ -756,12 +731,14 @@
 	int second_port_cmd640 = 0;
 	const char *bus_type, *port2;
 	unsigned int index;
-	u8 b, cfr;
+	byte b, cfr;
 
 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
 		bus_type = "VLB";
 	} else {
 		cmd640_vlb = 0;
+		/* Find out what kind of PCI probing is supported otherwise
+		   Justin Gibbs will sulk.. */
 		if (pci_conf1() && probe_for_cmd640_pci1())
 			bus_type = "PCI (type1)";
 		else if (pci_conf2() && probe_for_cmd640_pci2())
@@ -802,7 +779,7 @@
 	cmd_hwif0->chipset = ide_cmd640;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	cmd_hwif0->tuneproc = &cmd640_tune_drive;
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
 	/*
 	 * Ensure compatibility by always using the slowest timings
@@ -836,7 +813,7 @@
 				second_port_cmd640 = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 				second_port_toggled = 1;
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 				port2 = "enabled";
 			} else {
 				put_cmd640_reg(CNTRL, b); /* restore original setting */
@@ -852,10 +829,12 @@
 		cmd_hwif0->serialized = 1;
 		cmd_hwif1->serialized = 1;
 		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif1->unit = ATA_SECONDARY;
+		cmd_hwif0->mate = cmd_hwif1;
+		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		cmd_hwif1->tuneproc = &cmd640_tune_drive;
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 	}
 	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
 		cmd_hwif0->serialized ? "" : "not ", port2);
@@ -865,11 +844,11 @@
 	 * Do not unnecessarily disturb any prior BIOS setup of these.
 	 */
 	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
-		struct ata_device *drive = cmd_drives[index];
+		ide_drive_t *drive = cmd_drives[index];
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-			/*
-			 * Reset timing to the slowest speed and turn off prefetch.
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
 			 * This way, the drive identify code has a better chance.
 			 */
 			setup_counts    [index] = 4;	/* max possible */
@@ -886,7 +865,7 @@
 			retrieve_drive_counts (index);
 			check_prefetch (index);
 			printk("cmd640: drive%d timings/prefetch(%s) preserved",
-				index, drive->channel->no_io_32bit ? "off" : "on");
+				index, drive->no_io_32bit ? "off" : "on");
 			display_clocks(index);
 		}
 #else
@@ -895,8 +874,8 @@
 		 */
 		check_prefetch (index);
 		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
-			index, drive->channel->no_io_32bit ? "off" : "on");
-#endif
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 	}
 
 #ifdef CMD640_DUMP_REGS
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/cmd64x.c	Tue Aug 27 12:28:08 2002
@@ -1,16 +1,16 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
  *
  * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Note, this driver is not used at all on other systems because
  *           there the "BIOS" has done all of the following already.
- *           Due to massive hardware bugs, UDMA is not supported on the 646U.
+ *           Due to massive hardware bugs, UltraDMA is only supported
+ *           on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998		David S. Miller (davem@redhat.com)
  *
- * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1998		David S. Miller <davem@redhat.com>
  * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
  */
 
@@ -18,19 +18,22 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
 
 #define CMD_DEBUG 0
 
 #if CMD_DEBUG
-#define cmdprintk(x...)	printk(##x)
+#define cmdprintk(x...)	printk(x)
 #else
 #define cmdprintk(x...)
 #endif
@@ -77,35 +80,195 @@
 #define UDIDETCR1	0x7B
 #define DTPR1		0x7C
 
+#define DISPLAY_CMD64X_TIMINGS
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
+static char * print_sii_get_info(char *, struct pci_dev *, int);
+static int cmd64x_get_info(char *, char **, off_t, int);
+extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+byte cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS		5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+#undef DEBUG_CMD_REGS
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
+	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
+	u8 reg72 = 0, reg73 = 0;			/* primary */
+	u8 reg7a = 0, reg7b = 0;			/* secondary */
+	u8 reg50 = 0, reg71 = 0;			/* extra */
+#ifdef DEBUG_CMD_REGS
+	u8 hi_byte = 0, lo_byte = 0;
+#endif /* DEBUG_CMD_REGS */
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	(void) pci_read_config_byte(dev, CFR,       &reg50);
+	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
+	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
+	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
+	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
+	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
+	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
+	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled           "
+			"              %sabled\n",
+		(reg72&0x80)?"dis":" en",
+		(reg7a&0x80)?"dis":" en");
+	p += sprintf(p, "--------------- drive0 "
+		"--------- drive1 -------- drive0 "
+		"---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s"
+			"             %s               %s\n",
+		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+		(reg72&0x20)?(
+			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+		(reg72&0x40)?(
+			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+			"X"):"?");
+	p += sprintf(p, "         %s(%s)           %s(%s)\n",
+		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x20)?(
+			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x40)?(
+			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+			"X"):"?" );
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	p += sprintf(p, "                %s                     %s\n",
+		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
+		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+#ifdef DEBUG_CMD_REGS
+	SPLIT_BYTE(reg50, hi_byte, lo_byte);
+	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
+	SPLIT_BYTE(reg57, hi_byte, lo_byte);
+	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+	SPLIT_BYTE(reg71, hi_byte, lo_byte);
+	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
+#endif /* DEBUG_CMD_REGS */
+
+	return (char *)p;
+}
+
+static char * print_sii_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "SII%x Chipset.\n", dev->device);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_cmd_devs; i++) {
+		struct pci_dev *dev	= cmd_devs[i];
+
+		if (dev->device <= PCI_DEVICE_ID_CMD_649)
+			p = print_cmd64x_get_info(p, dev, i);
+		else
+			p = print_sii_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
 /*
  * Registers and masks for easy access by drive index:
  */
 #if 0
-static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
 #endif
 
 /*
  * This routine writes the prepared setup/active/recovery counts
  * for a drive into the cmd646 chipset registers to active them.
  */
-static void program_drive_counts(struct ata_device *drive, int setup_count, int active_count, int recovery_count)
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
 {
 	unsigned long flags;
-	struct ata_device *drives = drive->channel->drives;
-	u8 temp_b;
-	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const u8 recovery_counts[] =
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	ide_drive_t *drives = HWIF(drive)->drives;
+	byte temp_b;
+	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const byte recovery_counts[] =
 		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const u8 arttim_regs[2][2] = {
+	static const byte arttim_regs[2][2] = {
 			{ ARTTIM0, ARTTIM1 },
 			{ ARTTIM23, ARTTIM23 }
 		};
-	static const u8 drwtim_regs[2][2] = {
+	static const byte drwtim_regs[2][2] = {
 			{ DRWTIM0, DRWTIM1 },
 			{ DRWTIM2, DRWTIM3 }
 		};
-	int channel = drive->channel->unit;
+	int channel = (int) HWIF(drive)->channel;
 	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
 
 	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
@@ -119,7 +282,7 @@
 	 */
 	if (channel) {
 		drive->drive_data = setup_count;
-		setup_count = max(drives[0].drive_data, drives[1].drive_data);
+		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
 		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
 	}
 
@@ -130,7 +293,8 @@
 	active_count &= 0xf; /* Remember, max value is 16 */
 	recovery_count = (int) recovery_counts[recovery_count];
 
-	cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count);
+	cmdprintk("Final values = %d,%d,%d\n",
+		setup_count, active_count, recovery_count);
 
 	/*
 	 * Now that everything is ready, program the new timings
@@ -140,102 +304,112 @@
 	 * Program the address_setup clocks into ARTTIM reg,
 	 * and then the active/recovery counts into the DRWTIM reg
 	 */
-	(void) pci_read_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave],
-		((u8) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(drive->channel->pci_dev, drwtim_regs[channel][slave],
-		(u8) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n", ((u8) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n", (u8) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
+	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+		((byte) setup_count) | (temp_b & 0x3f));
+	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+		(byte) ((active_count << 4) | recovery_count));
+	cmdprintk ("Write %x to %x\n",
+		((byte) setup_count) | (temp_b & 0x3f),
+		arttim_regs[channel][slave]);
+	cmdprintk ("Write %x to %x\n",
+		(byte) ((active_count << 4) | recovery_count),
+		drwtim_regs[channel][slave]);
 	local_irq_restore(flags);
 }
 
 /*
- * Attempts to set the interface PIO mode. Special cases are
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is 
+ * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
  * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
  * Called with 255 at boot time.
  */
-static void cmd64x_tuneproc(struct ata_device *drive, u8 pio)
+static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
 {
-	int T;
-	u8 speed, active, recover;
-	struct ata_timing *t;
+	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
+	byte recovery_count2, cycle_count;
+	int setup_count, active_count, recovery_count;
+	int bus_speed = system_bus_clock();
+	/*byte b;*/
+	ide_pio_data_t  d;
 
-	switch (pio) {
-		/* FIXME: b0rken  --bkz */
+	switch (mode_wanted) {
 		case 8: /* set prefetch off */
 		case 9: /* set prefetch on */
-			pio &= 1;
+			mode_wanted &= 1;
 			/*set_prefetch_mode(index, mode_wanted);*/
-			cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name,
-				  pio ? "en" : "dis");
+			cmdprintk("%s: %sabled cmd640 prefetch\n",
+				drive->name, mode_wanted ? "en" : "dis");
 			return;
 	}
 
-	if (pio == 255)
-		speed = ata_best_pio_mode(drive);
-	else
-		speed = XFER_PIO_0 + min_t(u8, pio, 4);
-
-	t = ata_timing_data(speed);
+	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	pio_mode = d.pio_mode;
+	cycle_time = d.cycle_time;
 
 	/*
-	 * I copied all this complicated stuff from cmd640.c and made a few minor changes.
-	 * For now I am just going to pray that it is correct.
+	 * I copied all this complicated stuff from cmd640.c and made a few
+	 * minor changes.  For now I am just going to pray that it is correct.
 	 */
-	/* FIXME: verify it  --bkz */
-
-	T = 1000000000 / system_bus_speed;
-	ata_timing_quantize(t, t, T, T);
-
-	/* FIXME: maybe switch to ata_timing_compute()  --bkz */
-	recover = t->cycle - (t->setup + t->active);
-	active = t->active;
-
-	if (recover > 16) {
-		active += recover - 16;
-		recover = 16;
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
 	}
-	if (active > 16)
-		active = 16;	/* maximum allowed by CMD646 */
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd646 */
 
 	/*
 	 * In a perfect world, we might set the drive pio mode here
 	 * (using WIN_SETFEATURE) before continuing.
 	 *
 	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 *	1) this is the wrong place to do it
+	 *		(proper is do_special() in ide.c)
 	 * 	2) in practice this is rarely, if ever, necessary
 	 */
-	program_drive_counts(drive, t->setup, active, recover);
-
-	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns), clocks=%d/%d/%d\n",
-		drive->name, t.mode - XFER_PIO_0, pio, t->cycle,
-		t->setup, active, recover);
+	program_drive_counts (drive, setup_count, active_count, recovery_count);
 
-	ide_config_drive_speed(drive, speed);
+	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+		"clocks=%d/%d/%d\n",
+		drive->name, pio_mode, mode_wanted, cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "",
+		setup_count, active_count, recovery_count);
 }
 
-static int __init cmd6xx_modes_map(struct ata_channel *ch)
+static byte cmd64x_ratemask (ide_drive_t *drive)
 {
-	struct pci_dev *dev = ch->pci_dev;
-	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= 0x00;
 
 	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			map |= XFER_UDMA_133;
-		case PCI_DEVICE_ID_CMD_649:
-			map |= XFER_UDMA_100;
-		case PCI_DEVICE_ID_CMD_648:
-			map |= XFER_UDMA_66;
-		case PCI_DEVICE_ID_CMD_643:
-			map |= XFER_UDMA;
-			break;
+		case PCI_DEVICE_ID_CMD_680:	{ mode |= 0x04; break; }
+		case PCI_DEVICE_ID_CMD_649:	{ mode |= 0x03; break; }
+		case PCI_DEVICE_ID_CMD_648:	{ mode |= 0x02; break; }
+		case PCI_DEVICE_ID_CMD_643:	{ mode |= 0x01; break; }
+
 		case PCI_DEVICE_ID_CMD_646:
 		{
-			u32 rev;
-			pci_read_config_dword(dev, PCI_CLASS_REVISION, &rev);
-			rev &= 0xff;
+			unsigned int class_rev	= 0;
+			pci_read_config_dword(dev,
+				PCI_CLASS_REVISION, &class_rev);
+			class_rev &= 0xff;
 		/*
 		 * UltraDMA only supported on PCI646U and PCI646U2, which
 		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
@@ -248,25 +422,50 @@
 		 *
 		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
 		 */
-			switch(rev) {
+			switch(class_rev) {
 				case 0x07:
-				case 0x05:
-					map |= XFER_UDMA;
-				default: /* 0x03, 0x01 */
-					break;
+				case 0x05:	{ mode |= 0x01; break; }
+				case 0x03:
+				case 0x01:
+				default:	{ mode |= 0x00; break; }
 			}
 		}
 	}
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
+
+static byte cmd64x_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = cmd64x_ratemask(drive);
 
-	return map;
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
 }
 
-static u8 cmd680_taskfile_timing(struct ata_channel *ch)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
 {
-	u8 addr_mask = (ch->unit) ? 0xB2 : 0xA2;
-	u16 timing;
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
+	unsigned short		timing;
 
-	pci_read_config_word(ch->pci_dev, addr_mask, &timing);
+	pci_read_config_word(dev, addr_mask, &timing);
 
 	switch (timing) {
 		case 0x10c1:	return 4;
@@ -278,25 +477,12 @@
 	}
 }
 
-static void cmd680_tuneproc(struct ata_device *drive, u8 pio)
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
 {
-	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev = ch->pci_dev;
-	u8 unit	= (drive->select.b.unit & 0x01);
-	u8 addr_mask = (ch->unit) ? 0x84 : 0x80;
-	u8 drive_pci, mode_pci, speed;
-	u8 channel_timings = cmd680_taskfile_timing(ch);
-	u16 speedt;
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~(unit ? 0x30 : 0x03);
-
-	if (pio == 255)
-		pio = ata_best_pio_mode(drive) - XFER_PIO_0;
-
-	/* WARNING PIO timing mess is going to happen b/w devices, argh */
-	if ((channel_timings != pio) && (pio > channel_timings))
-		pio = channel_timings;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte			drive_pci;
+	unsigned short		speedt;
 
 	switch (drive->dn) {
 		case 0: drive_pci = 0xA4; break;
@@ -310,7 +496,7 @@
 
 	/* cheat for now and use the docs */
 //	switch(cmd680_taskfile_timing(hwif)) {
-	switch(pio) {
+	switch(mode_wanted) {
 		case 4:		speedt = 0x10c1; break;
 		case 3:		speedt = 0x10C3; break;
 		case 2:		speedt = 0x1104; break;
@@ -319,113 +505,142 @@
 		default:	speedt = 0x328A; break;
 	}
 	pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	byte speed	= 0x00;
+	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	cmd64x_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 speed		= 0x00;
+	u8 mode_pci		= 0x00;
+	u8 channel_timings	= cmd680_taskfile_timing(hwif);
+	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
 
-	speed = XFER_PIO_0 + min_t(u8, pio, 4);
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	cmd680_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
 
-	ide_config_drive_speed(drive, speed);
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			config_cmd680_chipset_for_pio(drive, set_speed);
+			return;
+		default:
+			break;
+	}
+	config_cmd64x_chipset_for_pio(drive, set_speed);
 }
 
-static int cmd64x_tune_chipset(struct ata_device *drive, u8 speed)
+static int cmd64x_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 
 	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->unit) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->unit) ? BMIDESR1 : BMIDESR0;
-	u8 regU, regD, U = 0, D = 0;
+	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+	u8 regU			= 0;
+	u8 regD			= 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
-		return 1;
+	u8 speed		= cmd64x_ratefilter(drive, xferspeed);
 
-	pci_read_config_byte(dev, pciD, &regD);
-	pci_read_config_byte(dev, pciU, &regU);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return 1;
 
-	/* unit 1 - 01000000b	unit 0 - 00100000b */
+	(void) pci_read_config_byte(dev, pciD, &regD);
+	(void) pci_read_config_byte(dev, pciU, &regU);
 	regD &= ~(unit ? 0x40 : 0x20);
-
-	/* unit 1 - 11001010b	unit 0 - 00110101b */
 	regU &= ~(unit ? 0xCA : 0x35);
+	(void) pci_write_config_byte(dev, pciD, regD);
+	(void) pci_write_config_byte(dev, pciU, regU);
+	(void) pci_read_config_byte(dev, pciD, &regD);
+	(void) pci_read_config_byte(dev, pciU, &regU);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	pci_write_config_byte(dev, pciD, regD);
-	pci_write_config_byte(dev, pciU, regU);
-
-	pci_read_config_byte(dev, pciD, &regD);
-	pci_read_config_byte(dev, pciU, &regU);
-
-	switch(speed) {
-		/* FIXME: use tables  --bkz */
-		case XFER_UDMA_5:	U = 0x05; break;
-		case XFER_UDMA_4:	U = 0x15; break;
-		case XFER_UDMA_3:	U = 0x25; break;
-		case XFER_UDMA_2:	U = 0x11; break;
-		case XFER_UDMA_1:	U = 0x21; break;
-		case XFER_UDMA_0:	U = 0x31; break;
-		case XFER_MW_DMA_2:	D = 0x10; break;
-		case XFER_MW_DMA_1:	D = 0x20; break;
-		case XFER_MW_DMA_0:	D = 0x30; break;
-		case XFER_SW_DMA_2:	D = 0x10; break;
-		case XFER_SW_DMA_1:	D = 0x20; break;
-		case XFER_SW_DMA_0:	D = 0x30; break;
-#else
 	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
+		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
+		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
+		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
+		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
+		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
+		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			cmd64x_tuneproc(drive, speed - XFER_PIO_0);
-			/* FIXME: error checking  --bkz */
-			return 0;
+		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
+
 		default:
 			return 1;
 	}
 
-	cmd64x_tuneproc(drive, 255);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-
-	if (unit) {
-		if (speed >= XFER_UDMA_0)
-			regU |= (((U & 0xf0) << 2) | ((U & 0x0f) << 1));
-		else if (speed >= XFER_SW_DMA_0)
-			regD |= ((D & 0xf0) << 2);
-	} else {
-		regU |= U;
-		regD |= D;
-	}
-
-	pci_write_config_byte(dev, pciU, regU);
-
+	(void) pci_write_config_byte(dev, pciU, regU);
 	regD |= (unit ? 0x40 : 0x20);
-	pci_write_config_byte(dev, pciD, regD);
-#endif
+	(void) pci_write_config_byte(dev, pciD, regD);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	return ide_config_drive_speed(drive, speed);
+	return (ide_config_drive_speed(drive, speed));
 }
 
-static int cmd680_tune_chipset(struct ata_device *drive, u8 speed)
+static int cmd680_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 addr_mask		= (hwif->unit) ? 0x84 : 0x80;
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
 	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 dma_pci, udma_pci;
-	u8 mode_pci, scsc, scsc_on = 0;
-	u16 ultra, multi;
+	u8 speed		= cmd64x_ratefilter(drive, xferspeed);
+	u8 dma_pci		= 0;
+	u8 udma_pci		= 0;
+	u8 mode_pci		= 0;
+	u8 scsc			= 0;
+	u16 ultra		= 0;
+	u16 multi		= 0;
 
         pci_read_config_byte(dev, addr_mask, &mode_pci);
 	pci_read_config_byte(dev, 0x8A, &scsc);
 
         switch (drive->dn) {
-		case 0: dma_pci = 0xA8; break;
-		case 1: dma_pci = 0xAA; break;
-		case 2: dma_pci = 0xB8; break;
-		case 3: dma_pci = 0xBA; break;
+		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
 		default: return 1;
 	}
-	udma_pci = dma_pci + 4;
 
 	pci_read_config_byte(dev, addr_mask, &mode_pci);
 	mode_pci &= ~((unit) ? 0x30 : 0x03);
@@ -435,40 +650,53 @@
 	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
 		pci_write_config_byte(dev, 0x8A, scsc|0x01);
 		pci_read_config_byte(dev, 0x8A, &scsc);
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		ultra &= ~0x3F;
-		multi = 0x10C1;
-		scsc_on = ((scsc & 0x30) == 0x00) ? 1 : 0;
+#if 0
+		/* if 133 clock fails, switch to 2xbus clock */
+		if (!(scsc & 0x01))
+			pci_write_config_byte(dev, 0x8A, scsc|0x10);
+#endif
 	}
 
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_UDMA_6:
-			if (scsc_on)
+			if ((scsc & 0x30) == 0x00)
 				goto speed_break;
+			multi = 0x10C1;
+			ultra &= ~0x3F;
 			ultra |= 0x01;
 			break;
 speed_break :
 			speed = XFER_UDMA_5;
 		case XFER_UDMA_5:
-			ultra |= (scsc_on ? 0x01 : 0x02);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
 			break;
 		case XFER_UDMA_4:
-			ultra |= (scsc_on ? 0x02 : 0x03);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
 			break;
 		case XFER_UDMA_3:
-			ultra |= (scsc_on ? 0x04 : 0x05);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
 			break;
 		case XFER_UDMA_2:
-			ultra |= (scsc_on ? 0x05 : 0x07);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
 			break;
 		case XFER_UDMA_1:
-			ultra |= (scsc_on ? 0x07 : 0x0B);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
 			break;
 		case XFER_UDMA_0:
-			ultra |= (scsc_on ? 0x0C : 0x0F);
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
 			break;
 		case XFER_MW_DMA_2:
 			multi = 0x10C1;
@@ -480,19 +708,18 @@
 			multi = 0x2208;
 			break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			cmd680_tuneproc(drive, speed - XFER_PIO_0);
-			/* FIXME: error checking  --bkz */
-			return 0;
+		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
 		default:
 			return 1;
 	}
+	
+	if (speed >= XFER_MW_DMA_0) 
+		config_cmd680_chipset_for_pio(drive, 0);
 
-	cmd680_tuneproc(drive, 255);
 	if (speed >= XFER_UDMA_0)
 		mode_pci |= ((unit) ? 0x30 : 0x03);
 	else if (speed >= XFER_MW_DMA_0)
@@ -504,128 +731,303 @@
 	pci_write_config_word(dev, dma_pci, multi);
 	pci_write_config_word(dev, udma_pci, ultra);
 
-	return ide_config_drive_speed(drive, speed);
+	return (ide_config_drive_speed(drive, speed));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int cmd64x_udma_stop(struct ata_device *drive)
+static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	u8 dma_stat = 0;
-	unsigned long dma_base	= ch->dma_base;
-	struct pci_dev *dev	= ch->pci_dev;
-	u8 jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
-
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	if (jack_slap) {
-		u8 dma_intr = 0;
-		u8 dma_mask = (ch->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-		u8 dma_reg = (ch->unit) ? ARTTIM2 : CFR;
-		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-		/*
-		 * DAMN BMIDE is not connected to PCI space!
-		 * Have to manually jack-slap that bitch!
-		 * To allow the PCI side to read incoming interrupts.
-		 */
-		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);	/* clear the INTR bit */
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	byte mode               = cmd64x_ratemask(drive);
+	byte speed		= 0x00;
+	byte set_pio		= 0x00;
+	int rval;
+
+	if (drive->media != ide_disk) {
+		cmdprintk("CMD64X: drive->media != ide_disk at double check,"
+			" inital check failed!!\n");
+		return ((int) ide_dma_off);
+	}
+
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			{ set_pio = 1; break; }
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	config_chipset_for_pio(drive, set_pio);
+
+	if (set_pio)
+		return ((int) ide_dma_off_quietly);
+
+	if (hwif->speedproc(drive, speed))
+		return ((int) ide_dma_off);
+
+	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+
+	return rval;
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) &&
+	    hwif->autodma && (drive->media == ide_disk)) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		default:
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+        return ide_dmaproc(func, drive);
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			return 1;
+		default:
+			break;
 	}
-	udma_destroy_table(ch);	/* purge DMA mappings */
-	return (dma_stat & 7) != 4;		/* verify good DMA status */
+	return 0;
 }
 
-static int cmd64x_udma_irq_status(struct ata_device *drive)
+static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	u8 dma_stat = 0;
-	u8 dma_alt_stat	= 0;
-	unsigned long dma_base	= ch->dma_base;
-	struct pci_dev *dev	= ch->pci_dev;
-	u8 mask	= (ch->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+	byte dma_stat		= 0;
+	byte dma_alt_stat	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	byte mask		= (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+	unsigned long dma_base	= hwif->dma_base;
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte alt_dma_stat	= cmd64x_alt_dma_status(dev);
 
-	dma_stat = inb(dma_base+2);
-	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		case ide_dma_end: /* returns 1 on error, 0 otherwise */
+			drive->waiting_for_dma = 0;
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
+			/* get DMA status */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* clear the INTR & ERROR bits */
+			OUT_BYTE(dma_stat|6, dma_base+2);
+			if (alt_dma_stat) {
+				byte dma_intr	= 0;
+				byte dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+				byte dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
+				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+				/* clear the INTR bit */
+				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+			}
+			/* purge DMA mappings */
+			ide_destroy_dmatable(drive);
+			/* verify good DMA status */
+			return (dma_stat & 7) != 4;
+		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+			(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
 #ifdef DEBUG
-	printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask);
+			printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+				"0x%02x mask: 0x%02x\n", drive->name,
+				dma_stat, dma_alt_stat, mask);
 #endif
-	if (!(dma_alt_stat & mask)) {
-		return 0;
+			if (!(dma_alt_stat & mask)) {
+				return 0;
+			}
+			/* return 1 if INTR asserted */
+			return (dma_stat & 4) == 4;
+		default:
+			break;
 	}
-	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
 }
 
 /*
  * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
  * event order for DMA transfers.
  */
-static int cmd646_1_udma_stop(struct ata_device *drive)
+static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte dma_stat;
+
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		case ide_dma_end:
+			drive->waiting_for_dma = 0;
+			/* get DMA status */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
+			/* clear the INTR & ERROR bits */
+			OUT_BYTE(dma_stat|6, dma_base+2);
+			/* and free any DMA resources */
+			ide_destroy_dmatable(drive);
+			/* verify good DMA status */
+			return (dma_stat & 7) != 4;
+		default:
+			break;
+	}
 
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* and free any DMA resources */
-	return (dma_stat & 7) != 4;		/* verify good DMA status */
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
 }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-#endif
-
-static int cmd680_busproc(struct ata_device * drive, int state)
+static int cmd680_busproc (ide_drive_t * drive, int state)
 {
 #if 0
-	struct ata_channel *ch	= drive->channel;
-	u8 addr_mask		= (ch->unit) ? 0xB0 : 0xA0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
 	u32 stat_config		= 0;
 
-        pci_read_config_dword(ch->pci_dev, addr_mask, &stat_config);
+        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
 
-	if (!ch)
+	if (!hwif)
 		return -EINVAL;
 
 	switch (state) {
 		case BUSSTATE_ON:
-			ch->drives[0].failures = 0;
-			ch->drives[1].failures = 0;
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
 			break;
 		case BUSSTATE_OFF:
-			ch->drives[0].failures = ch->drives[0].max_failures + 1;
-			ch->drives[1].failures = ch->drives[1].max_failures + 1;
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 			break;
 		case BUSSTATE_TRISTATE:
-			ch->drives[0].failures = ch->drives[0].max_failures + 1;
-			ch->drives[1].failures = ch->drives[1].max_failures + 1;
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 			break;
 		default:
 			return 0;
 	}
-	ch->bus_state = state;
+	hwif->bus_state = state;
 #endif
 	return 0;
 }
 
-static void cmd680_reset(struct ata_device *drive)
+void cmd680_reset (ide_drive_t *drive)
 {
 #if 0
-	struct ata_channel *ch = drive->channel;
-	u8 addr_mask = (ch->unit) ? 0xB0 : 0xA0;
-	u8 reset = 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	byte reset		= 0;
 
-	pci_read_config_byte(ch->pci_dev, addr_mask, &reset);
-	pci_write_config_byte(ch->pci_dev, addr_mask, reset|0x03);
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
 #endif
 }
 
-static unsigned int cmd680_pci_init(struct pci_dev *dev)
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
 {
-	u8 tmpbyte	= 0;
+	u8 tmpbyte	= 0;	
 	pci_write_config_byte(dev, 0x80, 0x00);
 	pci_write_config_byte(dev, 0x84, 0x00);
 	pci_read_config_byte(dev, 0x8A, &tmpbyte);
 	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+#if 0
+	/* if 133 clock fails, switch to 2xbus clock */	
+	if (!(tmpbyte & 0x01)) {
+		pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);		
+	}
+#endif
 	pci_write_config_word(dev, 0xA2, 0x328A);
 	pci_write_config_dword(dev, 0xA4, 0x328A);
 	pci_write_config_dword(dev, 0xA8, 0x4392);
@@ -635,13 +1037,22 @@
 	pci_write_config_dword(dev, 0xB8, 0x4392);
 	pci_write_config_dword(dev, 0xBC, 0x4009);
 
+	cmd_devs[n_cmd_devs++] = dev;
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		cmd64x_display_info = &cmd64x_get_info;
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
 	return 0;
 }
 
-static unsigned int cmd64x_pci_init(struct pci_dev *dev)
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
 {
-	u8 mrdmode;
-	u32 class_rev;
+	unsigned char mrdmode;
+	unsigned int class_rev;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
@@ -649,7 +1060,7 @@
 #ifdef __i386__
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 #endif
 
@@ -657,7 +1068,7 @@
 		case PCI_DEVICE_ID_CMD_643:
 			break;
 		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", dev->name, class_rev);
+			printk("%s: chipset revision 0x%02X, ", name, class_rev);
 			switch(class_rev) {
 				case 0x07:
 				case 0x05:
@@ -673,7 +1084,10 @@
 				}
 			printk("\n");
                         break;
-		default: /* 648, 649 */
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			break;
+		default:
 			break;
 	}
 
@@ -713,38 +1127,62 @@
 	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
 #endif /* CONFIG_PPC */
 
+	cmd_devs[n_cmd_devs++] = dev;
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		cmd64x_display_info = &cmd64x_get_info;
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
 	return 0;
 }
 
-static unsigned int __init cmd64x_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
 {
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_pci_init (dev);
-	return cmd64x_pci_init (dev);
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			return cmd680_pci_init (dev, name);
+		default:
+			break;
+	}
+	return cmd64x_pci_init (dev, name);
 }
 
-static unsigned int cmd680_ata66(struct ata_channel *hwif)
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
 {
-	u8 ata66;
-	u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
+	byte ata66	= 0;
+	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
 
 	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
 	return (ata66 & 0x01) ? 1 : 0;
 }
 
-static unsigned int cmd64x_ata66(struct ata_channel *hwif)
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
 {
-	u8 ata66;
-	u8 mask = (hwif->unit) ? 0x02 : 0x01;
+	byte ata66 = 0;
+	byte mask = (hwif->channel) ? 0x02 : 0x01;
 
 	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
 	return (ata66 & mask) ? 1 : 0;
 }
 
-static void __init cmd64x_init_channel(struct ata_channel *hwif)
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			return cmd680_ata66(hwif);
+		default:
+			break;
+	}
+	return cmd64x_ata66(hwif);
+}
+
+void __init ide_init_cmd64x (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
-	u32 class_rev;
+	unsigned int class_rev;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
@@ -754,107 +1192,45 @@
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_CMD_680:
-			hwif->busproc	= cmd680_busproc;
-			hwif->resetproc = cmd680_reset;
-			hwif->speedproc	= cmd680_tune_chipset;
-			hwif->tuneproc	= cmd680_tuneproc;
-			hwif->udma_four = cmd680_ata66(hwif);
+			hwif->busproc	= &cmd680_busproc;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+			if (hwif->dma_base)
+				hwif->dmaproc	= &cmd680_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+			hwif->resetproc = &cmd680_reset;
+			hwif->speedproc	= &cmd680_tune_chipset;
+			hwif->tuneproc	= &cmd680_tuneproc;
 			break;
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-			if (hwif->dma_base) {
-				hwif->udma_stop	= cmd64x_udma_stop;
-				hwif->udma_irq_status = cmd64x_udma_irq_status;
-			}
-#endif
-			hwif->tuneproc	= cmd64x_tuneproc;
-			hwif->speedproc = cmd64x_tune_chipset;
-			hwif->udma_four = cmd64x_ata66(hwif);
+			if (hwif->dma_base)
+				hwif->dmaproc	= &cmd64x_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc = &cmd64x_tune_chipset;
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 			if (hwif->dma_base) {
-				if (class_rev == 0x01) {
-					hwif->udma_stop = cmd646_1_udma_stop;
-				} else {
-					hwif->udma_stop = cmd64x_udma_stop;
-					hwif->udma_irq_status = cmd64x_udma_irq_status;
-				}
+				if (class_rev == 0x01)
+					hwif->dmaproc = &cmd646_1_dmaproc;
+				else
+					hwif->dmaproc = &cmd64x_dmaproc;
 			}
-#endif
-			hwif->tuneproc	= cmd64x_tuneproc;
-			hwif->speedproc	= cmd64x_tune_chipset;
-			hwif->udma_four = cmd64x_ata66(hwif);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc	= &cmd64x_tune_chipset;
 			break;
 		default:
 			break;
 	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->highmem = 1;
-		hwif->modes_map = cmd6xx_modes_map(hwif);
-		hwif->no_atapi_autodma = 1;
-		hwif->udma_setup = udma_generic_setup;
-	}
-#endif
-}
-
-
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_643,
-		.init_chipset = cmd64x_init_chipset,
-		.init_channel = cmd64x_init_channel,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_SIMPLEX,
-	},
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_646,
-		.init_chipset = cmd64x_init_chipset,
-		.init_channel = cmd64x_init_channel,
-		.enablebits = {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
-		.bootable = ON_BOARD,
-		.flags = ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_648,
-		.init_chipset = cmd64x_init_chipset,
-		.init_channel = cmd64x_init_channel,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_649,
-		.init_chipset = cmd64x_init_chipset,
-		.init_channel = cmd64x_init_channel,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_680,
-		.init_chipset = cmd64x_init_chipset,
-		.init_channel = cmd64x_init_channel,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_DMA
-	},
-};
-
-int __init init_cmd64x(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
-
-        return 0;
+#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IDEDMA_AUTO)
+	if (hwif->dma_base)
+		if (!noautodma)
+			hwif->autodma = 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA && CONFIG_IDEDMA_AUTO*/
 }
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/ide/cs5530.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,4 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*
  * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
  *
  * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
@@ -20,29 +19,74 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
-
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
+
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int cs5530_get_info(char *, char **, off_t, int);
+extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p((unsigned short)bibma + 0x02);
+	c1 = inb_p((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"Cyrix 5530 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+byte cs5530_proc = 0;
 
 /*
  * Set a new transfer mode at the drive
  */
-int cs5530_set_xfer_mode(struct ata_device *drive, u8 mode)
+int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
 {
-	int error = 0;
-
-	printk("%s: cs5530_set_xfer_mode(%02x)\n", drive->name, mode);
-	error = ide_config_drive_speed(drive, mode);
-
-	return error;
+	printk("%s: cs5530_set_xfer_mode(%s)\n",
+		drive->name, ide_xfer_verbose(mode));
+	return (ide_config_drive_speed(drive, mode));
 }
 
 /*
@@ -58,51 +102,50 @@
  * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
  */
 #define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(ch)	(((ch)->dma_base & ~0xf) + ((ch)->unit ? 0x30 : 0x20))
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
 
 /*
- * Handle selection/setting of PIO modes for both the chipset and drive.
+ * cs5530_tuneproc() handles selection/setting of PIO modes
+ * for both the chipset and drive.
  *
- * The ide_init_cs5530() routine guarantees that all drives will have valid
- * default PIO timings set up before we get here.
+ * The ide_init_cs5530() routine guarantees that all drives
+ * will have valid default PIO timings set up before we get here.
  */
-static void cs5530_tuneproc(struct ata_device *drive, u8 pio)
+static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
 {
-	unsigned int format;
-	unsigned int basereg = CS5530_BASEREG(drive->channel);
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format, basereg = CS5530_BASEREG(hwif);
+	static byte	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
 
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		pio = XFER_PIO_0 + min_t(u8, pio, 4);
-
-	if (!cs5530_set_xfer_mode(drive, pio)) {
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
 		format = (inl(basereg+4) >> 31) & 1;
-		outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3));
+		outl(cs5530_pio_timings[format][pio],
+			basereg+(drive->select.b.unit<<3));
 	}
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-
 /*
- * Handle selection/setting of DMA/UDMA modes for both the chipset and drive.
+ * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
  */
-static int cs5530_config_dma(struct ata_device *drive)
+static int cs5530_config_dma (ide_drive_t *drive)
 {
-	int udma_ok = 1;
-	int mode = 0;
-	struct ata_channel *ch = drive->channel;
-	int unit = drive->select.b.unit;
-	struct ata_device *mate = &ch->drives[unit^1];
-	struct hd_driveid *id = drive->id;
-	unsigned int basereg, reg, timings;
-
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+	unsigned int		basereg, reg, timings;
 
 	/*
 	 * Default to DMA-off in case we run into trouble here.
 	 */
-	udma_enable(drive, 0, 0);
-	outb(inb(ch->dma_base+2)&~(unit?0x40:0x20), ch->dma_base+2); /* clear DMA_capable bit */
+	(void)hwif->dmaproc(ide_dma_off_quietly, drive);
+	/* turn off DMA while we fiddle */
+	(void)hwif->dmaproc(ide_dma_host_off, drive);
+	/* clear DMA_capable bit */
 
 	/*
 	 * The CS5530 specifies that two drives sharing a cable cannot
@@ -115,10 +158,13 @@
 	 */
 	if (mate->present) {
 		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) && !udma_black_list(mate)) {
-			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+		if (mateid && (mateid->capability & 1) &&
+		    !hwif->dmaproc(ide_dma_bad_drive, mate)) {
+			if ((mateid->field_valid & 4) &&
+			    (mateid->dma_ultra & 7))
 				udma_ok = 1;
-			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+			else if ((mateid->field_valid & 2) &&
+				 (mateid->dma_mword & 7))
 				udma_ok = 0;
 			else
 				udma_ok = 1;
@@ -129,7 +175,8 @@
 	 * Now see what the current drive is capable of,
 	 * selecting UDMA only if the mate said it was ok.
 	 */
-	if (id && (id->capability & 1) && ch->autodma && !udma_black_list(drive)) {
+	if (id && (id->capability & 1) && hwif->autodma &&
+	    !hwif->dmaproc(ide_dma_bad_drive, drive)) {
 		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
 			if      (id->dma_ultra & 4)
 				mode = XFER_UDMA_2;
@@ -165,11 +212,12 @@
 		case XFER_MW_DMA_1:	timings = 0x00012121; break;
 		case XFER_MW_DMA_2:	timings = 0x00002020; break;
 		default:
-			printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode);
+			printk("%s: cs5530_config_dma: huh? mode=%02x\n",
+				drive->name, mode);
 			return 1;	/* failure */
 	}
-	basereg = CS5530_BASEREG(ch);
-	reg = inl(basereg+4);			/* get drive0 config register */
+	basereg = CS5530_BASEREG(hwif);
+	reg = inl(basereg+4);		/* get drive0 config register */
 	timings |= reg & 0x80000000;		/* preserve PIO format bit */
 	if (unit == 0) {			/* are we configuring drive0? */
 		outl(timings, basereg+4);	/* write drive0 config register */
@@ -181,33 +229,51 @@
 		outl(reg,     basereg+4);	/* write drive0 config register */
 		outl(timings, basereg+12);	/* write drive1 config register */
 	}
-	outb(inb(ch->dma_base+2)|(unit?0x40:0x20), ch->dma_base+2);	/* set DMA_capable bit */
+	(void)hwif->dmaproc(ide_dma_host_on, drive);
+	/* set DMA_capable bit */
 
 	/*
 	 * Finally, turn DMA on in software, and exit.
 	 */
-	udma_enable(drive, 1, 1);	/* success */
-
-	return 0;
+	return hwif->dmaproc(ide_dma_on, drive);	/* success */
 }
 
-static int cs5530_udma_setup(struct ata_device *drive, int map)
+/*
+ * This is a CS5530-specific wrapper for the standard ide_dmaproc().
+ * We need it for our custom "ide_dma_check" function.
+ * All other requests are forwarded to the standard ide_dmaproc().
+ */
+int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	return cs5530_config_dma(drive);
+	switch (func) {
+		case ide_dma_check:
+			return cs5530_config_dma(drive);
+		default:
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
-static unsigned int __init pci_init_cs5530(struct pci_dev *dev)
+unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
 {
-	struct pci_dev *master_0 = NULL;
-	struct pci_dev *cs5530_0 = NULL;
+	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 	unsigned short pcicmd = 0;
 	unsigned long flags;
 
-	pci_for_each_dev(dev) {
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cs5530_proc) {
+		cs5530_proc = 1;
+		bmide_dev = dev;
+		cs5530_display_info = &cs5530_get_info;
+	}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+	pci_for_each_dev (dev) {
 		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
 			switch (dev->device) {
 				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
@@ -219,23 +285,24 @@
 			}
 		}
 	}
-
 	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", dev->name);
+		printk("%s: unable to locate PCI MASTER function\n", name);
 		return 0;
 	}
 	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", dev->name);
+		printk("%s: unable to locate CS5530 LEGACY function\n", name);
 		return 0;
 	}
 
+	spin_lock_irqsave(&ide_lock, flags);
+		/* all CPUs (there should only be one CPU with this chipset) */
+
 	/*
 	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
 	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
 	 */
-	 
-	pci_set_master(cs5530_0);
-	pci_set_mwi(cs5530_0);
+	pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd);
+	pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
 
 	/*
 	 * Set PCI CacheLineSize to 16-bytes:
@@ -256,7 +323,7 @@
 	 */
 	pci_write_config_byte(master_0, 0x40, 0x1e);
 
-	/*
+	/* 
 	 * Set max PCI burst size (16-bytes seems to work best):
 	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
 	 *	all others: clear bit-1 at 0x41, and do:
@@ -274,60 +341,46 @@
 	pci_write_config_byte(master_0, 0x42, 0x00);
 	pci_write_config_byte(master_0, 0x43, 0xc1);
 
+	spin_unlock_irqrestore(&ide_lock, flags);
+
 	return 0;
 }
 
 /*
- * This gets invoked once for each channel, and performs channel-specific
- * pre-initialization before drive probing.
+ * This gets invoked by the IDE driver once for each channel,
+ * and performs channel-specific pre-initialization before drive probing.
  */
-static void __init ide_init_cs5530(struct ata_channel *ch)
+void __init ide_init_cs5530 (ide_hwif_t *hwif)
 {
-	u32 basereg;
-	u32 d0_timings;
+	unsigned int basereg, d0_timings;
+	hwif->autodma = 0;
 
-	ch->serialized = 1;
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
 
-	/* We think a 64kB transfer is a 0 byte transfer, so set our
-	   segment size to be one sector smaller than 64kB. */
-	ch->max_segment_size = (1<<16) - 512;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (ch->dma_base) {
-		ch->highmem = 1;
-		ch->udma_setup = cs5530_udma_setup;
-	}
-#endif
-
-	ch->tuneproc = &cs5530_tuneproc;
-	basereg = CS5530_BASEREG(ch);
+	hwif->tuneproc = &cs5530_tuneproc;
+	basereg = CS5530_BASEREG(hwif);
 	d0_timings = inl(basereg+0);
-	if (CS5530_BAD_PIO(d0_timings)) {	/* PIO timings not initialized? */
+	if (CS5530_BAD_PIO(d0_timings)) {
+		/* PIO timings not initialized? */
 		outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
-		if (!ch->drives[0].autotune)
-			ch->drives[0].autotune = 1;	/* needs autotuning later */
+		if (!hwif->drives[0].autotune)
+			hwif->drives[0].autotune = 1;
+			/* needs autotuning later */
 	}
-	if (CS5530_BAD_PIO(inl(basereg+8))) {	/* PIO timings not initialized? */
+	if (CS5530_BAD_PIO(inl(basereg+8))) {
+	/* PIO timings not initialized? */
 		outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
-		if (!ch->drives[1].autotune)
-			ch->drives[1].autotune = 1;	/* needs autotuning later */
+		if (!hwif->drives[1].autotune)
+			hwif->drives[1].autotune = 1;
+			/* needs autotuning later */
 	}
-}
 
-
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_CYRIX,
-	.device = PCI_DEVICE_ID_CYRIX_5530_IDE,
-	.init_chipset = pci_init_cs5530,
-	.init_channel = ide_init_cs5530,
-	.bootable = ON_BOARD,
-	.flags = ATA_F_DMA
-};
-
-int __init init_cs5530(void)
-{
-	ata_register_chipset(&chipset);
-
-        return 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc  = &cs5530_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/cy82c693.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,4 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*
  * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
  *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
@@ -9,7 +8,7 @@
  *
  * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
  * Writting the driver was quite simple, since most of the job is
- * done by the generic pci-ide support.
+ * done by the generic pci-ide support. 
  * The hard part was finding the CY82C693's datasheet on Cypress's
  * web page :-(. But Altavista solved this problem :-).
  *
@@ -18,12 +17,15 @@
  * - I recently got a 16.8G IBM DTTA, so I was able to test it with
  *   a large and fast disk - the results look great, so I'd say the
  *   driver is working fine :-)
- *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA
- * - this is my first linux driver, so there's probably a lot  of room
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
  *   for optimizations and bug fixing, so feel free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
  * - I had some problems with my IBM DHEA with PIO modes < 2
  *   (lost interrupts) ?????
- *   FIXME: probably because we set wrong timings for 8bit  --bkz
  * - first tests with DMA look okay, they seem to work, but there is a
  *   problem with sound - the BusMaster IDE TimeOut should fixed this
  *
@@ -46,14 +48,12 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
 /* the current version */
 #define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
@@ -71,7 +71,7 @@
  * note: the value for busmaster timeout is tricky and i got it by trial and error !
  *       using a to low value will cause DMA timeouts and drop IDE performance
  *       using a to high value will cause audio playback to scatter
- *       if you know a better value or how to calc it, please let me know
+ *       if you know a better value or how to calc it, please let me know 
  */
 #define BUSMASTER_TIMEOUT	0x50	/* twice the value written in cy82c693ub datasheet */
 /*
@@ -81,15 +81,12 @@
 /* here are the offset definitions for the registers */
 #define CY82_IDE_CMDREG		0x04
 #define CY82_IDE_ADDRSETUP	0x48
-
-#define CYPRESS_TIMINGS		0x4C
-
-#define CY82_IDE_MASTER_IOR	0x4C
-#define CY82_IDE_MASTER_IOW	0x4D
-#define CY82_IDE_SLAVE_IOR	0x4E
+#define CY82_IDE_MASTER_IOR	0x4C	
+#define CY82_IDE_MASTER_IOW	0x4D	
+#define CY82_IDE_SLAVE_IOR	0x4E	
 #define CY82_IDE_SLAVE_IOW	0x4F
-#define CY82_IDE_MASTER_8BIT	0x50
-#define CY82_IDE_SLAVE_8BIT	0x51
+#define CY82_IDE_MASTER_8BIT	0x50	
+#define CY82_IDE_SLAVE_8BIT	0x51	
 
 #define CY82_INDEX_PORT		0x22
 #define CY82_DATA_PORT		0x23
@@ -106,24 +103,23 @@
 #define CY82C963_MIN_BUS_SPEED	25
 #define CY82C963_MAX_BUS_SPEED	33
 
-/* the struct for the PIO mode timings (in clocks) */
+/* the struct for the PIO mode timings */
 typedef struct pio_clocks_s {
-	u8 address_time;	/* Address setup */
-	/* 0xF0=Active/data, 0x0F=Recovery */
-	u8 time_16r;		/* 16bit IOR */
-	u8 time_16w;		/* 16bit IOW */
-	u8 time_8;		/* 8bit */
+        byte	address_time;	/* Address setup (clocks) */
+	byte	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+	byte	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+	byte	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
 } pio_clocks_t;
 
 /*
  * calc clocks using bus_speed
  * returns (rounded up) time in bus clocks for time in ns
  */
-static u8 calc_clk(int time, int bus_speed)
+static int calc_clk (int time, int bus_speed)
 {
 	int clocks;
 
-	clocks = (time*bus_speed+999999)/1000000 -1;
+	clocks = (time*bus_speed+999)/1000 -1;
 
 	if (clocks < 0)
 		clocks = 0;
@@ -131,7 +127,7 @@
 	if (clocks > 0x0F)
 		clocks = 0x0F;
 
-	return (u8)clocks;
+	return clocks;
 }
 
 /*
@@ -141,62 +137,62 @@
  * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
  *       for mode 3 and 4 drives 8 and 16-bit timings are the same
  *
- */
-/* FIXME: use generic timings library  --bkz */
-static void compute_clocks(u8 pio, pio_clocks_t *p_pclk)
+ */ 
+static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
 {
-	struct ata_timing *t;
 	int clk1, clk2;
-
-	t = ata_timing_data(XFER_PIO_0 + pio);
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
 
 	/* we don't check against CY82C693's min and max speed,
 	 * so you can play with the idebus=xx parameter
-	 * FIXME: warn about going out of specification  --bkz
 	 */
 
 	if (pio > CY82C693_MAX_PIO)
 		pio = CY82C693_MAX_PIO;
 
-	/* address setup */
-	p_pclk->address_time = calc_clk(t->setup, system_bus_speed);
+	/* let's calc the address setup time clocks */
+	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+	/* let's calc the active and recovery time clocks */
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
 
-	/* active */
-	clk1 = calc_clk(t->active, system_bus_speed);
+	/* calc recovery timing */
+	clk2 =	ide_pio_timings[pio].cycle_time -
+		ide_pio_timings[pio].active_time -
+		ide_pio_timings[pio].setup_time;
 
-	/* FIXME: check why not t->cycle - t->active ?  --bkz */
-	/* recovery */
-	clk2 = calc_clk(t->cycle - t->active - t->setup, system_bus_speed);
+	clk2 = calc_clk(clk2, bus_speed);
 
-	clk1 = (clk1 << 4) | clk2; /* combine active and recovery clocks */
+	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
 
 	/* note: we use the same values for 16bit IOR and IOW
          *	those are all the same, since I don't have other
-	 *	timings than those from ata-timing.h
+	 *	timings than those from ide_modes.h
 	 */
-	p_pclk->time_16w = p_pclk->time_16r = clk1;
 
-	/* FIXME: ugh...  --bkz */
+	p_pclk->time_16r = (byte)clk1;
+	p_pclk->time_16w = (byte)clk1;
+
 	/* what are good values for 8bit ?? */
-	p_pclk->time_8 = clk1;
+	p_pclk->time_8 = (byte)clk1;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 /*
  * set DMA mode a specific channel for CY82C693
  */
-static void cy82c693_dma_enable(struct ata_device *drive, int mode, int single)
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 {
-        u8 index;
-	u8 data;
+	byte index;
+	byte data;
 
-        if (mode>2)	/* make sure we set a valid mode */
+	if (mode>2)	/* make sure we set a valid mode */
 		mode = 2;
-
+			   
 	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
 		mode = drive->id->tDMA;
-
-        index = (drive->channel->unit == 0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+	
+	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
 
 #if CY82C693_DEBUG_LOGS
 	/* for debug let's show the previous values */
@@ -204,19 +200,23 @@
 	OUT_BYTE(index, CY82_INDEX_PORT);
 	data = IN_BYTE(CY82_DATA_PORT);
 
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, (data&0x3), ((data>>2)&1));
-#endif
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		(data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
 
-	data = (u8) mode | (u8) (single << 2);
+	data = (byte)mode|(byte)(single<<2);
 
 	OUT_BYTE(index, CY82_INDEX_PORT);
 	OUT_BYTE(data, CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, mode, single);
-#endif
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		mode, single);
+#endif /* CY82C693_DEBUG_INFO */
 
-	/*
+	/* 
 	 * note: below we set the value for Bus Master IDE TimeOut Register
 	 * I'm not absolutly sure what this does, but it solved my problem
 	 * with IDE DMA and sound, so I now can play sound and work with
@@ -230,57 +230,57 @@
 	OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
 	OUT_BYTE(data, CY82_DATA_PORT);
 
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data);
-#endif
+#if CY82C693_DEBUG_INFO	
+	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+		drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
 }
 
-/*
+/* 
  * used to set DMA mode for CY82C693 (single and multi modes)
  */
-static int cy82c693_udma_setup(struct ata_device *drive, int map)
+static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
 	/*
-	 * Set dma mode for drive everything else is done by the defaul func.
+	 * if the function is dma on, set dma mode for drive everything
+	 * else is done by the defaul func
 	 */
-	struct hd_driveid *id = drive->id;
+	if (func == ide_dma_on) {
+		struct hd_driveid *id = drive->id;
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif
+		printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
 
-	if (id != NULL) {
-		/* Enable DMA on any drive that has DMA (multi or single) enabled */
-		if (id->field_valid & 2) {       /* regular DMA */
-			int mmode, smode;
-
-			mmode = id->dma_mword & (id->dma_mword >> 8);
-			smode = id->dma_1word & (id->dma_1word >> 8);
-
-			if (mmode != 0)
-				cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
-			else if (smode != 0)
-				cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
+		if (id != NULL) {		
+                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
+                       if (id->field_valid & 2) {       /* regular DMA */
+			       int mmode, smode;
+
+			       mmode = id->dma_mword & (id->dma_mword >> 8);
+			       smode = id->dma_1word & (id->dma_1word >> 8);
+			       		      
+		               if (mmode != 0)
+				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
+			       else if (smode != 0)
+				     cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
+			}
 		}
 	}
-	udma_enable(drive, 1, 1);
-
-	return 0;
+        return ide_dmaproc(func, drive);
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * tune ide drive - set PIO mode
  */
-static void cy82c693_tune_drive(struct ata_device *drive, u8 pio)
+static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
 	pio_clocks_t pclk;
 	unsigned int addrCtrl;
-	u8 ior, iow, bit8;
 
-	/* FIXME: probaly broken  --bkz */
 	/* select primary or secondary channel */
 	if (hwif->index > 0) {  /* drive is on the secondary channel */
 		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
@@ -290,105 +290,139 @@
 		}
 	}
 
-	if (drive->select.b.unit == 0) {
-		ior = CY82_IDE_MASTER_IOR;
-		iow = CY82_IDE_MASTER_IOW;
-		bit8 = CY82_IDE_MASTER_8BIT;
-	} else {
-		ior = CY82_IDE_SLAVE_IOR;
-		iow = CY82_IDE_SLAVE_IOW;
-		bit8 = CY82_IDE_SLAVE_8BIT;
-	}
-
 #if CY82C693_DEBUG_LOGS
 	/* for debug let's show the register values */
+	
+       	if (drive->select.b.unit == 0) {
+		/*
+		 * get master drive registers               	
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+		addrCtrl &= 0x0F;
 
-	/*
-	 * get address setup control register
-	 * mine master or slave data
-	 */
-	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+	} else {
+		/*
+		 * set slave drive registers
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
 
-	if (drive->select.b.unit == 0)
-		addrCtrl &= 0x0F;
-	else {
 		addrCtrl &= 0xF0;
 		addrCtrl >>= 4;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
 	}
 
-	/* now let's get the remaining registers */
-	pci_read_config_byte(dev, ior, &pclk.time_16r);
-	pci_read_config_byte(dev, iow, &pclk.time_16w);
-	pci_read_config_byte(dev, bit8, &pclk.time_8);
-
-	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X,"
-			 " ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-			 drive->name, hwif->unit, drive->select.b.unit,
-			 addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_LOGS */
 
         /* first let's calc the pio modes */
-	pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
 
 #if CY82C693_DEBUG_INFO
 	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif
+#endif /* CY82C693_DEBUG_INFO */
 
         compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
 
-	/*
-	 * set address setup control register
-	 */
-	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+	/* now let's write  the clocks registers */
 	if (drive->select.b.unit == 0) {
-		addrCtrl &= (~0x0F);
+		/*
+		 * set master drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		
+		addrCtrl &= (~0xF);
 		addrCtrl |= (unsigned int)pclk.address_time;
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+		
+		addrCtrl &= 0xF;
 	} else {
+		/*
+		 * set slave drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
 		addrCtrl &= (~0xF0);
 		addrCtrl |= ((unsigned int)pclk.address_time<<4);
-	}
-	pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
 
-	/* now let's set the remaining registers */
-	pci_write_config_byte(dev, ior, pclk.time_16r);
-	pci_write_config_byte(dev, iow, pclk.time_16w);
-	pci_write_config_byte(dev, bit8, pclk.time_8);
+		addrCtrl >>= 4;
+		addrCtrl &= 0xF;
+	}	
 
 #if CY82C693_DEBUG_INFO
-	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X,"
-			 " ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name,
-			 hwif->unit, drive->select.b.unit, addrCtrl,
-			 pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
 }
 
-static unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+/*
+ * FIXME! "pci_init_cy82c693" really should replace
+ * the "init_cy82c693_chip", it is the correct location to tinker/setup
+ * the device prior to INIT.
+ */
+
+unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
 {
 #ifdef CY82C693_SETDMA_CLOCK
-	u8 data;
-#endif
+        byte data;
+#endif /* CY82C693_SETDMA_CLOCK */ 
 
 	/* write info about this verion of the driver */
-	printk (KERN_INFO CY82_VERSION "\n");
+	printk(KERN_INFO CY82_VERSION "\n");
 
 #ifdef CY82C693_SETDMA_CLOCK
        /* okay let's set the DMA clock speed */
-
+        
         OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
         data = IN_BYTE(CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", dev->name, data);
-#endif
+	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
 
         /*
 	 * for some reason sometimes the DMA controller
 	 * speed is set to ATCLK/2 ???? - we fix this here
-	 *
+	 * 
 	 * note: i don't know what causes this strange behaviour,
 	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed
-	 *
+	 *       the ide performance is still only half the normal speed 
+	 * 
 	 *       if anybody knows what goes wrong with my machine, please
 	 *       let me know - ASK
          */
@@ -398,46 +432,47 @@
         OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
         OUT_BYTE(data, CY82_DATA_PORT);
 
-# if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", dev->name, data);
-# endif
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
 
-#endif
+#endif /* CY82C693_SETDMA_CLOCK */
 	return 0;
 }
 
 /*
  * the init function - called for each ide channel once
  */
-static void __init ide_init_cy82c693(struct ata_channel *hwif)
+void __init ide_init_cy82c693(ide_hwif_t *hwif)
 {
 	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = cy82c693_tune_drive;
+	hwif->tuneproc = &cy82c693_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
+	hwif->autodma = 0;
 
+	if (!hwif->dma_base)
+		return;
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->highmem = 1;
-		hwif->udma_setup = cy82c693_udma_setup;
-	}
-#endif
+	hwif->dmaproc = &cy82c693_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_CONTAQ,
-	.device = PCI_DEVICE_ID_CONTAQ_82C693,
-	.init_chipset = pci_init_cy82c693,
-	.init_channel = ide_init_cy82c693,
-	.bootable = ON_BOARD,
-	.flags = ATA_F_DMA
-};
-
-int __init init_cy82c693(void)
+void __init fixup_device_cy82c693 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	ata_register_chipset(&chipset);
-
-	return 0;
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+	    (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+		return;	/* CY82C693 is more than only a IDE controller */
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+
diff -Nru a/drivers/ide/device.c b/drivers/ide/device.c
--- a/drivers/ide/device.c	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,263 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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.
- */
-
-/*
- * Common low leved device access code. This is the lowest layer of hardware
- * access.
- *
- * This is the place where register set access portability will be handled in
- * the future.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-
-/*
- * Select a device for operation with possible busy waiting for the operation
- * to complete.
- */
-void ata_select(struct ata_device *drive, unsigned long delay)
-{
-	struct ata_channel *ch = drive->channel;
-
-	if (!ch)
-		return;
-
-	if (ch->selectproc)
-		ch->selectproc(drive);
-	OUT_BYTE(drive->select.all, ch->io_ports[IDE_SELECT_OFFSET]);
-
-	/* The delays during probing for drives can be georgeous.  Deal with
-	 * it.
-	 */
-	if (delay) {
-		if (delay >= 1000)
-			mdelay(delay / 1000);
-		else
-			udelay(delay);
-	}
-}
-
-EXPORT_SYMBOL(ata_select);
-
-/*
- * Handle quirky routing of interrupts.
- */
-void ata_mask(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-
-	if (!ch)
-		return;
-
-	if (ch->maskproc)
-		ch->maskproc(drive);
-}
-
-EXPORT_SYMBOL(ata_mask);
-
-/*
- * Check the state of the status register.
- */
-int ata_status(struct ata_device *drive, u8 good, u8 bad)
-{
-	struct ata_channel *ch = drive->channel;
-
-	drive->status = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
-
-	return (drive->status & (good | bad)) == good;
-}
-
-EXPORT_SYMBOL(ata_status);
-
-/*
- * This is used to check for the drive status on the IRQ handling code path.
- */
-int ata_status_irq(struct ata_device *drive)
-{
-	if (test_bit(IDE_DMA, drive->channel->active))
-		return udma_irq_status(drive);
-
-	/* Need to guarantee 400ns since last command was issued?
-	 */
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-
-	/*
-	 * We do a passive status test under shared PCI interrupts on cards
-	 * that truly share the ATA side interrupt, but may also share an
-	 * interrupt with another pci card/device.
-	 */
-
-	if (drive->channel->io_ports[IDE_CONTROL_OFFSET])
-		drive->status = IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-
-	else
-#endif
-		ata_status(drive, 0, 0);	/* Note: this may clear a pending IRQ! */
-
-	if (drive->status & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	else
-		return 1;	/* drive ready: *might* be interrupting */
-}
-
-EXPORT_SYMBOL(ata_status_irq);
-
-/*
- * Busy-wait for the drive status to be not "busy".  Check then the status for
- * all of the "good" bits and none of the "bad" bits, and if all is okay it
- * returns 0.  All other cases return 1 after invoking error handler -- caller
- * should just return.
- */
-int ata_status_poll(struct ata_device *drive, u8 good, u8 bad,
-		unsigned long timeout, struct request *rq)
-{
-	int i;
-
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures))
-		return ATA_OP_FINISHED;
-	/*
-	 * Spin until the drive is no longer busy.
-	 * Spec allows drive 400ns to assert "BUSY"
-	 */
-	udelay(1);
-	if (!ata_status(drive, 0, BUSY_STAT)) {
-		unsigned long flags;
-
-		local_save_flags(flags);
-		local_irq_enable();
-		timeout += jiffies;
-		while (!ata_status(drive, 0, BUSY_STAT)) {
-			if (time_after(jiffies, timeout)) {
-				local_irq_restore(flags);
-				return ata_error(drive, rq, "status timeout");
-			}
-		}
-		local_irq_restore(flags);
-	}
-
-	/*
-	 * Allow status to settle, then read it again.  A few rare drives
-	 * vastly violate the 400ns spec here, so we'll wait up to 10usec for a
-	 * "good" status rather than expensively fail things immediately.  This
-	 * fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (ata_status(drive, good, bad))
-			return ATA_OP_READY;
-	}
-
-	return ata_error(drive, rq, "status error");
-}
-
-EXPORT_SYMBOL(ata_status_poll);
-
-/*
- * Handle the nIEN - negated Interrupt ENable of the drive.
- * This is controlling whatever the drive will acnowlenge commands
- * with interrupts or not.
- */
-int ata_irq_enable(struct ata_device *drive, int on)
-{
-	struct ata_channel *ch = drive->channel;
-
-	if (!ch->io_ports[IDE_CONTROL_OFFSET])
-		return 0;
-
-	/* 0x08 is for legacy ATA-1 devices */
-	if (on)
-		OUT_BYTE(0x08 | 0x00, ch->io_ports[IDE_CONTROL_OFFSET]);
-	else {
-		if (!ch->intrproc)
-			OUT_BYTE(0x08 | 0x02, ch->io_ports[IDE_CONTROL_OFFSET]);
-		else
-			ch->intrproc(drive);
-	}
-
-	return 1;
-}
-
-EXPORT_SYMBOL(ata_irq_enable);
-
-/*
- * Perform a reset operation on the currently selected drive.
- */
-void ata_reset(struct ata_channel *ch)
-{
-	unsigned long timeout = jiffies + WAIT_WORSTCASE;
-	u8 stat;
-
-	if (!ch->io_ports[IDE_CONTROL_OFFSET])
-		return;
-
-	printk("%s: reset\n", ch->name);
-	/* 0x08 is for legacy ATA-1 devices */
-	OUT_BYTE(0x08 | 0x04, ch->io_ports[IDE_CONTROL_OFFSET]);
-	udelay(10);
-	/* 0x08 is for legacy ATA-1 devices */
-	OUT_BYTE(0x08 | 0x00, ch->io_ports[IDE_CONTROL_OFFSET]);
-	do {
-		mdelay(50);
-		stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
-	} while ((stat & BUSY_STAT) && time_before(jiffies, timeout));
-}
-
-EXPORT_SYMBOL(ata_reset);
-
-/*
- * Output a complete register file.
- */
-void ata_out_regfile(struct ata_device *drive, struct hd_drive_task_hdr *rf)
-{
-	struct ata_channel *ch = drive->channel;
-
-	OUT_BYTE(rf->feature, ch->io_ports[IDE_FEATURE_OFFSET]);
-	OUT_BYTE(rf->sector_count, ch->io_ports[IDE_NSECTOR_OFFSET]);
-	OUT_BYTE(rf->sector_number, ch->io_ports[IDE_SECTOR_OFFSET]);
-	OUT_BYTE(rf->low_cylinder, ch->io_ports[IDE_LCYL_OFFSET]);
-	OUT_BYTE(rf->high_cylinder, ch->io_ports[IDE_HCYL_OFFSET]);
-}
-
-EXPORT_SYMBOL(ata_out_regfile);
-
-/*
- * Input a complete register file.
- */
-void ata_in_regfile(struct ata_device *drive, struct hd_drive_task_hdr *rf)
-{
-	struct ata_channel *ch = drive->channel;
-
-	rf->sector_count = IN_BYTE(ch->io_ports[IDE_NSECTOR_OFFSET]);
-	rf->sector_number = IN_BYTE(ch->io_ports[IDE_SECTOR_OFFSET]);
-	rf->low_cylinder = IN_BYTE(ch->io_ports[IDE_LCYL_OFFSET]);
-	rf->high_cylinder = IN_BYTE(ch->io_ports[IDE_HCYL_OFFSET]);
-}
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
--- a/drivers/ide/dtc2278.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/ide/dtc2278.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,11 @@
 /*
+ *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
+ *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -9,13 +13,13 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 
 /*
  * Changing this #undef to #define may solve start up problems in some systems.
@@ -53,31 +57,33 @@
 	int i;
 
 	for(i = 0; i < 3; ++i) {
-		inb(0x3f6);
+		IN_BYTE(0x3f6);
 		outb_p(b,0xb0);
-		inb(0x3f6);
+		IN_BYTE(0x3f6);
 		outb_p(c,0xb4);
-		inb(0x3f6);
-		if(inb(0xb4) == c) {
+		IN_BYTE(0x3f6);
+		if(IN_BYTE(0xb4) == c) {
 			outb_p(7,0xb0);
-			inb(0x3f6);
+			IN_BYTE(0x3f6);
 			return;	/* success */
 		}
 	}
 }
 
-/* Assumes IRQ's are disabled or at least that no other process will
-   attempt to access the IDE registers concurrently. */
-static void tune_dtc2278(struct ata_device *drive, u8 pio)
+static void tune_dtc2278 (ide_drive_t *drive, byte pio)
 {
-	pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+	unsigned long flags;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 
 	if (pio >= 3) {
+		spin_lock_irqsave(&ide_lock, flags);
 		/*
 		 * This enables PIO mode4 (3?) on the first interface
 		 */
 		sub22(1,0xc3);
 		sub22(0,0xa0);
+		spin_unlock_irqrestore(&ide_lock, flags);
 	} else {
 		/* we don't know how to set it back again.. */
 	}
@@ -85,7 +91,8 @@
 	/*
 	 * 32bit I/O has to be enabled for *both* drives at the same time.
 	 */
-	drive->channel->io_32bit = 1;
+	drive->io_32bit = 1;
+	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
 }
 
 void __init init_dtc2278 (void)
@@ -97,9 +104,9 @@
 	 * This enables the second interface
 	 */
 	outb_p(4,0xb0);
-	inb(0x3f6);
+	IN_BYTE(0x3f6);
 	outb_p(0x20,0xb4);
-	inb(0x3f6);
+	IN_BYTE(0x3f6);
 #ifdef ALWAYS_SET_DTC2278_PIO_MODE
 	/*
 	 * This enables PIO mode4 (3?) on the first interface
@@ -115,11 +122,11 @@
 	ide_hwifs[0].chipset = ide_dtc2278;
 	ide_hwifs[1].chipset = ide_dtc2278;
 	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	/* FIXME: What about the following?!
-	ide_hwifs[1].tuneproc = &tune_dtc2278;
-	 */
-	ide_hwifs[0].no_unmask = 1;
-	ide_hwifs[1].no_unmask = 1;
-	ide_hwifs[0].unit = ATA_PRIMARY;
-	ide_hwifs[1].unit = ATA_SECONDARY;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 }
diff -Nru a/drivers/ide/falconide.c b/drivers/ide/falconide.c
--- a/drivers/ide/falconide.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/falconide.c	Tue Aug 27 12:28:08 2002
@@ -60,7 +60,7 @@
 
 	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
 			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw);
+	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1)
 	    printk("ide%d: Falcon IDE interface\n", index);
diff -Nru a/drivers/ide/gayle.c b/drivers/ide/gayle.c
--- a/drivers/ide/gayle.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/gayle.c	Tue Aug 27 12:28:08 2002
@@ -16,6 +16,7 @@
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/zorro.h>
 
 #include <asm/setup.h>
 #include <asm/amigahw.h>
@@ -84,31 +85,31 @@
      *  Check and acknowledge the interrupt status
      */
 
-static int gayle_ack_intr_a4000(struct ata_channel *hwif)
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
 {
     unsigned char ch;
 
-    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
     if (!(ch & GAYLE_IRQ_IDE))
 	return 0;
     return 1;
 }
 
-static int gayle_ack_intr_a1200(struct ata_channel *hwif)
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
 {
     unsigned char ch;
 
-    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
     if (!(ch & GAYLE_IRQ_IDE))
 	return 0;
-    (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-    outb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
     return 1;
 }
 
-/*
- *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
- */
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
 
 void __init gayle_init(void)
 {
@@ -122,7 +123,7 @@
 
     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
 	ide_ioreg_t base, ctrlport, irqport;
-	int (*ack_intr)(struct ata_channel *);
+	ide_ack_intr_t *ack_intr;
 	hw_regs_t hw;
 	int index;
 	unsigned long phys_base, res_start, res_n;
@@ -150,7 +151,7 @@
 	ide_setup_ports(&hw, base, gayle_offsets,
 			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw);
+	index = ide_register_hw(&hw, NULL);
 	if (index != -1) {
 	    switch (i) {
 		case 0:
diff -Nru a/drivers/ide/hd.c b/drivers/ide/hd.c
--- a/drivers/ide/hd.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/hd.c	Tue Aug 27 12:28:08 2002
@@ -849,7 +849,7 @@
 	}
 
 	for(drive=0; drive < NR_HD; drive++) {
-		hd_gendisk[i].nr_real = 1;
+		hd_gendisk[drive].nr_real = 1;
 		add_gendisk(hd_gendisk + drive);
 		register_disk(hd_gendisk + drive,
 			mk_kdev(MAJOR_NR,drive<<6), 1<<6,
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/ide/hpt34x.c	Tue Aug 27 12:28:08 2002
@@ -1,11 +1,22 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*
  * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
  *
  * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
  * May be copied or modified under the terms of the GNU General Public License
  *
- * ide-pci.c reference:
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
  *
  * Since there are two cards that report almost identically,
  * the only discernable difference is the values reported in pcicmd.
@@ -21,117 +32,379 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include "ide_modes.h"
 
-#include "timing.h"
-#include "pcihost.h"
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
 
 #define HPT343_DEBUG_DRIVE_INFO		0
 
-static int hpt34x_tune_chipset(struct ata_device *drive, u8 speed)
+#undef DISPLAY_HPT34X_TIMINGS
+
+#define HPT34X_MAX_DEVS			8
+static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
+static int n_hpt34x_devs;
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	u8 udma = 0, pio = 0;
-	u32 reg1, reg2, tmp1, tmp2;
-
-	if (speed >= XFER_UDMA_0)
-		udma = 0x01;
-	else if (speed >= XFER_SW_DMA_0)
-		udma = 0x10;
-	else
-		pio = speed & 7;
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"HPT34X Chipset.\n");
+	for (i = 0; i < n_hpt34x_devs; i++) {
+		struct pci_dev *dev = hpt34x_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+		u8  c0 = 0, c1 = 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((unsigned short)bibma + 0x02);
+		c1 = inb_p((unsigned short)bibma + 0x0a);
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte hpt34x_proc = 0;
+
+static byte hpt34x_ratemask (ide_drive_t *drive)
+{
+	byte mode = 0x00;
+
+	mode |= 0x01;
+
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
+
+static byte hpt34x_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+# ifdef CONFIG_HPT34X_AUTODMA
+byte mode = hpt34x_ratemask(drive);
+
+	switch(mode) {
+		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	// while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+# else /* !CONFIG_HPT34X_AUTODMA */
+	while (speed > XFER_PIO_4) speed--;
+# endif /* CONFIG_HPT34X_AUTODMA */
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	unsigned int reg1	= 0, tmp1 = 0;
+	unsigned int reg2	= 0, tmp2 = 0;
 
 	pci_read_config_dword(dev, 0x44, &reg1);
 	pci_read_config_dword(dev, 0x48, &reg2);
-	tmp1 = (pio << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)));
-	tmp2 = (udma << drive->dn) | (reg2 & ~(0x11 << drive->dn));
+	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = (reg2 & ~(0x11 << drive->dn));
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte speed		= hpt34x_ratefilter(drive, xferspeed);
+	unsigned int reg1	= 0, tmp1 = 0;
+	unsigned int reg2	= 0, tmp2 = 0;
+	byte			hi_speed, lo_speed;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = ((hi_speed << drive->dn) | reg2);
 	pci_write_config_dword(dev, 0x44, tmp1);
 	pci_write_config_dword(dev, 0x48, tmp2);
 
 #if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %02x drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, speed,
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x)\n",
+		drive->name, ide_xfer_verbose(speed),
 		drive->dn, reg1, tmp1, reg2, tmp2,
-		udma, pio, err);
-#endif
+		hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
 
-	return ide_config_drive_speed(drive, speed);
+	return(ide_config_drive_speed(drive, speed));
 }
 
-static void hpt34x_tune_drive(struct ata_device *drive, u8 pio)
+static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
 {
-	(void) hpt34x_tune_chipset(drive, XFER_PIO_0 + min_t(u8, pio, 4));
-}
+	byte speed;
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int hpt34x_udma_setup(struct ata_device *drive, int map)
-{
-#ifdef CONFIG_HPT34X_AUTODMA
-	return udma_generic_setup(drive, map);
-#else
-	return 0;
-#endif
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
 }
 
-static int hpt34x_udma_stop(struct ata_device *drive)
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
+	struct hd_driveid *id	= drive->id;
+	byte mode		= hpt34x_ratemask(drive);
+	byte speed		= 0x00;
+
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+
+	switch(mode) {
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
 
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* purge DMA mappings */
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
 
-	return (dma_stat & 7) != 4;		/* verify good DMA status */
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
 }
 
-static int hpt34x_udma_init(struct ata_device *drive, struct request *rq)
+static int config_drive_xfer_rate (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	unsigned int count;
-	u8 cmd;
-
-	if (!(count = udma_new_table(drive, rq)))
-		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
-
-	if (rq_data_dir(rq) == READ)
-		cmd = 0x09;
-	else
-		cmd = 0x01;
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
 
-	outl(ch->dmatable_dma, dma_base + 4);	/* PRD table */
-	outb(cmd, dma_base);			/* specify r/w */
-	outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
+	drive->init_speed = 0;
 
-	if (drive->type == ATA_DISK) {
-		ata_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-		OUT_BYTE((cmd == 0x09) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x0007) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		hpt34x_tune_drive(drive, 255);
 	}
 
-	return ATA_OP_CONTINUES;
+#ifndef CONFIG_HPT34X_AUTODMA
+	if (dma_func == ide_dma_on)
+		dma_func = ide_dma_off;
+#endif /* CONFIG_HPT34X_AUTODMA */
+
+	return HWIF(drive)->dmaproc(dma_func, drive);
 }
+
+/*
+ * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ *
+ * This is specific to the HPT343 UDMA bios-less chipset
+ * and HPT345 UDMA bios chipset (stamped HPT363)
+ * by HighPoint|Triones Technologies, Inc.
+ */
+
+int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+//	ide_task_t *args = HWGROUP(drive)->rq->special;
+	unsigned long dma_base = hwif->dma_base;
+	unsigned int count, reading = 0;
+	byte dma_stat;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_read:
+			reading = 1 << 3;
+		case ide_dma_write:
+			if (!(count = ide_build_dmatable(drive, func)))
+				return 1;
+				/* try PIO instead of DMA */
+			outl(hwif->dmatable_dma, dma_base + 4);
+			/* PRD table */
+			reading |= 0x01;
+			OUT_BYTE(reading, dma_base);
+			/* specify r/w */
+			OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2);
+			/* clear INTR & ERROR flags */
+			drive->waiting_for_dma = 1;
+			if (drive->media != ide_disk)
+				return 0;
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+			/* issue cmd to drive */
+			/*
+			 * FIX ME to use only ACB ide_task_t args Struct
+			 */
+#if 0
+		{
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		{
+#else
+			if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing == 1)
+				OUT_BYTE((reading == 9) ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			else
+				OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 #endif
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
+			drive->waiting_for_dma = 0;
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
+			/* get DMA status */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* clear the INTR & ERROR bits */
+			OUT_BYTE(dma_stat|6, dma_base+2);
+			/* purge DMA mappings */
+			ide_destroy_dmatable(drive);
+			/* verify good DMA status */
+			return (dma_stat & 7) != 4;
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
  */
 #define	HPT34X_PCI_INIT_REG		0x80
 
-static unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
+unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
 {
 	int i = 0;
 	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
 	unsigned short cmd;
 	unsigned long flags;
 
@@ -143,76 +416,76 @@
 	if (cmd & PCI_COMMAND_MEMORY) {
 		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
 			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+				dev->resource[PCI_ROM_RESOURCE].start);
 		}
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
 	} else {
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 	}
 
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	dev->resource[0].start = (hpt34xIoBase + 0x20);
-	dev->resource[1].start = (hpt34xIoBase + 0x34);
-	dev->resource[2].start = (hpt34xIoBase + 0x28);
-	dev->resource[3].start = (hpt34xIoBase + 0x3c);
-	for(i=0; i<4; i++)
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 	/*
 	 * Since 20-23 can be assigned and are R/W, we correct them.
 	 */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for(i=0; i<4; i++) {
+		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+		pci_write_config_dword(dev,
+				(PCI_BASE_ADDRESS_0 + (i * 4)),
+				dev->resource[i].start);
+	}
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
 
 	local_irq_restore(flags);
 
+	hpt34x_devs[n_hpt34x_devs++] = dev;
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!hpt34x_proc) {
+		hpt34x_proc = 1;
+		hpt34x_display_info = &hpt34x_get_info;
+	}
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
 	return dev->irq;
 }
 
-static void __init ide_init_hpt34x(struct ata_channel *hwif)
+void __init ide_init_hpt34x (ide_hwif_t *hwif)
 {
-	hwif->tuneproc = hpt34x_tune_drive;
-	hwif->speedproc = hpt34x_tune_chipset;
+	unsigned short pcicmd = 0;
+	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+	hwif->autodma = 0;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
+	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
 
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc = &hpt34x_dmaproc;
 #ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
 		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-#endif
-		hwif->udma_stop = hpt34x_udma_stop;
-		hwif->udma_init = hpt34x_udma_init;
-		hwif->modes_map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
-		hwif->no_atapi_autodma = 1;
-		hwif->udma_setup = hpt34x_udma_setup;
-		hwif->highmem = 1;
-	} else 
-#endif
-	{
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_TTI,
-	.device = PCI_DEVICE_ID_TTI_HPT343,
-	.init_chipset = pci_init_hpt34x,
-	.init_channel =	ide_init_hpt34x,
-	.bootable = NEVER_BOARD,
-	.extra = 16,
-	.flags = ATA_F_DMA
-};
-
-int __init init_hpt34x(void)
+void __init fixup_device_hpt343 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	ata_register_chipset(&chipset);
+	char *chipset_names[] = {"HPT343", "HPT345"};
+	unsigned short pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
 
-	return 0;
+	strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
+	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/hpt366.c	Tue Aug 27 12:28:08 2002
@@ -1,10 +1,8 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
+/*
+ * linux/drivers/ide/hpt366.c		Version 0.33	April 17, 2002
  *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
- * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
  * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
@@ -14,10 +12,10 @@
  * Note that final HPT370 support was done by force extraction of GPL.
  *
  * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma
+ * - the HPT370's state machine can get confused. reset it before each dma 
  *   xfer to prevent that from happening.
  * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma.
+ * - check for busmaster state at end of dma. 
  * - use new highpoint timings.
  * - detect bus speed using highpoint register.
  * - use pll if we don't have a clock table. added a 66MHz table that's
@@ -26,25 +24,24 @@
  *   pci clocks as the chip can glitch in those cases. the highpoint
  *   approved workaround slows everything down too much to be useful. in
  *   addition, we would have to serialize access to each chip.
- *	Adrian Sun <a.sun@sun.com>
+ * 	Adrian Sun <a.sun@sun.com>
  *
  * add drive timings for 66MHz PCI bus,
  * fix ATA Cable signal detection, fix incorrect /proc info
  * add /proc display for per-drive PIO/DMA/UDMA mode and
  * per-channel ATA-33/66 Cable detect.
- *	Duncan Laurie <void@sun.com>
+ * 	Duncan Laurie <void@sun.com>
  *
  * fixup /proc output for multiple controllers
  *	Tim Hockin <thockin@sun.com>
  *
- * On hpt366:
+ * On hpt366: 
  * Reset the hpt366 on error, reset on dma
  * Fix disabling Fast Interrupt hpt366.
- *	Mike Waychison <crlf@sun.com>
- *
- * 02 May 2002 - HPT374 support (Andre Hedrick <andre@linux-ide.org>)
+ * 	Mike Waychison <crlf@sun.com>
  */
 
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -53,26 +50,32 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
+#define DISPLAY_HPT366_TIMINGS
 
 /* various tuning parameters */
 #define HPT_RESET_STATE_ENGINE
-/*#define HPT_DELAY_INTERRUPT*/
-/*#define HPT_SERIALIZE_IO*/
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static const char *quirk_drives[] = {
+const char *quirk_drives[] = {
 	"QUANTUM FIREBALLlct08 08",
 	"QUANTUM FIREBALLP KA6.4",
 	"QUANTUM FIREBALLP LM20.4",
@@ -80,7 +83,7 @@
         NULL
 };
 
-static const char *bad_ata100_5[] = {
+const char *bad_ata100_5[] = {
 	"IBM-DTLA-307075",
 	"IBM-DTLA-307060",
 	"IBM-DTLA-307045",
@@ -99,7 +102,7 @@
 	NULL
 };
 
-static const char *bad_ata66_4[] = {
+const char *bad_ata66_4[] = {
 	"IBM-DTLA-307075",
 	"IBM-DTLA-307060",
 	"IBM-DTLA-307045",
@@ -118,12 +121,12 @@
 	NULL
 };
 
-static const char *bad_ata66_3[] = {
+const char *bad_ata66_3[] = {
 	"WDC AC310200R",
 	NULL
 };
 
-static const char *bad_ata33[] = {
+const char *bad_ata33[] = {
 	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
 	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
 	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
@@ -135,11 +138,11 @@
 };
 
 struct chipset_bus_clock_list_entry {
-	u8		xfer_speed;
+	byte		xfer_speed;
 	unsigned int	chipset_settings;
 };
 
-/* key for bus clock timings for HPT370
+/* key for bus clock timings
  * bit
  * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
  *        DMA. cycles = value + 1
@@ -161,7 +164,7 @@
  *        PIO.
  * 31     FIFO enable.
  */
-static struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
 	{	XFER_UDMA_4,	0x900fd943	},
 	{	XFER_UDMA_3,	0x900ad943	},
 	{	XFER_UDMA_2,	0x900bd943	},
@@ -180,7 +183,7 @@
 	{	0,		0x0120d9d9	}
 };
 
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
+struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
 	{	XFER_UDMA_4,	0x90c9a731	},
 	{	XFER_UDMA_3,	0x90cfa731	},
 	{	XFER_UDMA_2,	0x90caa731	},
@@ -199,7 +202,7 @@
 	{	0,		0x0120a7a7	}
 };
 
-static struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
+struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
 
 	{	XFER_UDMA_4,	0x90c98521	},
 	{	XFER_UDMA_3,	0x90cf8521	},
@@ -219,9 +222,50 @@
 	{	0,		0x01208585	}
 };
 
-#if 1
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+
 /* these are the current (4 sep 2001) timings from highpoint */
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
         {       XFER_UDMA_5,    0x12446231      },
         {       XFER_UDMA_4,    0x12446231      },
         {       XFER_UDMA_3,    0x126c6231      },
@@ -242,7 +286,7 @@
 };
 
 /* 2x 33MHz timings */
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
 	{       XFER_UDMA_5,    0x1488e673       },
 	{       XFER_UDMA_4,    0x1488e673       },
 	{       XFER_UDMA_3,    0x1498e673       },
@@ -251,7 +295,7 @@
 	{       XFER_UDMA_0,    0x14a0e73f       },
 
 	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
 	{       XFER_MW_DMA_0,  0x2480fb3f       },
 
 	{       XFER_PIO_4,     0x0c82be73       },
@@ -261,50 +305,8 @@
 	{       XFER_PIO_0,     0x0d02bf5f       },
 	{       0,              0x0d02bf5f       }
 };
-#else
-/* from highpoint documentation. these are old values */
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57	},
-	{	0,		0x06514e57	}
-};
-
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x14846231      },
-	{       XFER_UDMA_4,    0x14886231      },
-	{       XFER_UDMA_3,    0x148c6231      },
-	{       XFER_UDMA_2,    0x148c6231      },
-	{       XFER_UDMA_1,    0x14906231      },
-	{       XFER_UDMA_0,    0x14986231      },
-
-	{       XFER_MW_DMA_2,  0x26514e21      },
-	{       XFER_MW_DMA_1,  0x26514e33      },
-	{       XFER_MW_DMA_0,  0x26514e97      },
 
-	{       XFER_PIO_4,     0x06514e21      },
-	{       XFER_PIO_3,     0x06514e22      },
-	{       XFER_PIO_2,     0x06514e33      },
-	{       XFER_PIO_1,     0x06914e43      },
-	{       XFER_PIO_0,     0x06914e57      },
-	{       0,              0x06514e57      }
-};
-#endif
-
-static struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
 	{       XFER_UDMA_5,    0x12848242      },
 	{       XFER_UDMA_4,    0x12ac8242      },
 	{       XFER_UDMA_3,    0x128c8242      },
@@ -324,7 +326,7 @@
 	{       0,              0x0ac1f48a      }
 };
 
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
 	{	XFER_UDMA_6,	0x1c81dc62	},
 	{	XFER_UDMA_5,	0x1c6ddc62	},
 	{	XFER_UDMA_4,	0x1c8ddc62	},
@@ -345,7 +347,7 @@
 	{	0,		0x0d029d5e	}
 };
 
-static struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
 	{	XFER_UDMA_5,	0x12848242	},
 	{	XFER_UDMA_4,	0x12ac8242	},
 	{	XFER_UDMA_3,	0x128c8242	},
@@ -365,7 +367,7 @@
 	{	0,		0x0a81f443	}
 };
 
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
 	{	XFER_UDMA_6,	0x1c869c62	},
 	{	XFER_UDMA_5,	0x1cae9c62	},
 	{	XFER_UDMA_4,	0x1c8a9c62	},
@@ -386,7 +388,7 @@
 	{	0,		0x0d029d26	}
 };
 
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
 	{	XFER_UDMA_6,	0x12808242	},
 	{	XFER_UDMA_5,	0x12848242	},
 	{	XFER_UDMA_4,	0x12ac8242	},
@@ -408,7 +410,27 @@
 };
 
 #if 0
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
 	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
 	{	XFER_UDMA_5,	0x12446231	},
 				0x14846231
@@ -444,6 +466,8 @@
 
 #define HPT366_DEBUG_DRIVE_INFO		0
 #define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
 #define HPT372_ALLOW_ATA133_6		1
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
@@ -455,35 +479,112 @@
 #define F_LOW_PCI_50      0x2d
 #define F_LOW_PCI_66      0x42
 
-static int check_in_drive_lists(struct ata_device *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
 
-	if (quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 1;
-			}
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+static int hpt366_get_info(char *, char **, off_t, int);
+extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"302", "371",  "374" };
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370/372/374\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev = hpt_revision(dev);
+		u8 c0, c1;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb_p(iobase + 0x2);
+		c1 = inb_p(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (hpt_minimum_revision(dev, 3)) {
+			u8 cbl;
+			cbl = inb_p(iobase + 0x7b);
+			outb_p(cbl | 1, iobase + 0x7b);
+			outb_p(cbl & ~1, iobase + 0x7b);
+			cbl = inb_p(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
 		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
+
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
 		}
 	}
-	return 0;
+	p += sprintf(p, "\n");
+	
+	return p-buffer;/* => must be less than 4k! */
 }
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static unsigned int hpt_revision(struct pci_dev *dev)
+static unsigned int hpt_revision (struct pci_dev *dev)
 {
-	u32 class_rev;
+	unsigned int class_rev;
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_TTI_HPT374:
 			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
 		case PCI_DEVICE_ID_TTI_HPT372:
 			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
 		default:
@@ -492,29 +593,123 @@
 	return class_rev;
 }
 
-static int __init hpt3xx_modes_map(struct ata_channel *ch)
+static unsigned int hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static byte hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	byte mode = 0x00;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode |= (HPT374_ALLOW_ATA133_6) ? 0x04 : 0x03;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode |= (HPT371_ALLOW_ATA133_6) ? 0x04 : 0x03;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode |= (HPT302_ALLOW_ATA133_6) ? 0x04 : 0x03;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode |= (HPT372_ALLOW_ATA133_6) ? 0x04 : 0x03;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
+		if (check_in_drive_lists(drive, bad_ata33))
+			return (mode &= ~0xFF);
+	} else {					/* HPT366 and HPT368 */
+		mode |= 0x02;
+		if (check_in_drive_lists(drive, bad_ata33))
+			return (mode &= ~0xFF);
+	}
+
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
+
+static byte hpt3xx_ratefilter (ide_drive_t *drive, byte speed)
 {
-	u32 rev = hpt_revision(ch->pci_dev);
-	int map = XFER_EPIO | XFER_MWDMA | XFER_UDMA | XFER_UDMA_66;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= hpt3xx_ratemask(drive);
 
-	if (rev >= 8) {					/* HPT374 */
-		if (HPT374_ALLOW_ATA133_6)
-			map |= XFER_UDMA_133;
-		map |= XFER_UDMA_100;
-	} else if (rev >= 5) {				/* HPT372 */
-		if (HPT372_ALLOW_ATA133_6)
-			map |= XFER_UDMA_133;
-		map |= XFER_UDMA_100;
-	} else if (rev >= 3) {				/* HPT370A / HPT370 */
-		if (HPT370_ALLOW_ATA100_5)
-			map |= XFER_UDMA_100;
-	}						/* HPT366 / HPT368 */
+	if (drive->media != ide_disk)
+		while (speed > XFER_PIO_4) speed--;
 
-	return map;
+	switch(mode) {
+		case 0x04:
+			while (speed > XFER_UDMA_6) speed--;
+			break;
+		case 0x03:
+			while (speed > XFER_UDMA_5) speed--;
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				while (speed > XFER_UDMA_4) speed--;
+			break;
+		case 0x02:
+			while (speed > XFER_UDMA_4) speed--;
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				while (speed > XFER_UDMA_3) speed--;
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				while (speed > XFER_UDMA_2) speed--;
+			break;
+		case 0x01:
+			while (speed > XFER_UDMA_2) speed--;
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				while (speed > XFER_MW_DMA_2) speed--;
+			break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
 }
 
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
 
-static unsigned int pci_bus_clock_list(u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+	if (quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 1;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
@@ -523,53 +718,64 @@
 	return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset(struct ata_device *drive, u8 speed)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	struct pci_dev *dev	= drive->channel->pci_dev;
-	u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	u8 regfast = (drive->channel->unit) ? 0x55 : 0x51;
-			/*
-			 * since the channel is always 0 it does not matter.
-			 */
-
-	u32 reg1, reg2;
-	u8 drive_fast;
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
+	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	byte drive_fast		= 0;
+	unsigned int reg1	= 0;
+	unsigned int reg2	= 0;
 
 	/*
 	 * Disable the "fast interrupt" prediction.
 	 */
 	pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+	if (drive_fast & 0x02)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
 	if (drive_fast & 0x80)
 		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
 
-	pci_read_config_dword(dev, regtime, &reg1);
 	reg2 = pci_bus_clock_list(speed,
-		(struct chipset_bus_clock_list_entry *) dev->sysdata);
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
 	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
+	 * Disable on-chip PIO FIFO/buffer
+	 *  (to avoid problems handling I/O errors later)
 	 */
+	pci_read_config_dword(dev, regtime, &reg1);
 	if (speed >= XFER_MW_DMA_0) {
 		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
 	} else {
 		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}
+	}	
 	reg2 &= ~0x80000000;
 
 	pci_write_config_dword(dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset(struct ata_device *drive, u8 speed)
+static void hpt368_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	u8 regfast = (drive->channel->unit) ? 0x55 : 0x51;
-	u32 list_conf, drive_conf;
-	u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	u8 drive_pci = 0x40 + (drive->dn * 4);
-	u8 new_fast, drive_fast;
-	struct pci_dev *dev	= drive->channel->pci_dev;
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
+	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	unsigned int list_conf	= 0;
+	unsigned int drive_conf = 0;
+	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte new_fast, drive_fast		= 0;
+	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
 
 	/*
 	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
 	 */
 	pci_read_config_byte(dev, regfast, &drive_fast);
 	new_fast = drive_fast;
@@ -584,15 +790,15 @@
 		new_fast |= 0x01;
 #endif
 	if (new_fast != drive_fast)
-		pci_write_config_byte(drive->channel->pci_dev, regfast, new_fast);
+		pci_write_config_byte(dev, regfast, new_fast);
 
-	list_conf = pci_bus_clock_list(speed,
+	list_conf = pci_bus_clock_list(speed, 
 				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
+				       dev->driver_data);
 
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-
+	
 	if (speed < XFER_MW_DMA_0) {
 		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
 	}
@@ -600,14 +806,16 @@
 	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
-static void hpt372_tune_chipset(struct ata_device *drive, u8 speed)
+static void hpt372_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	u8 regfast = (drive->channel->unit) ? 0x55 : 0x51;
-	u32 list_conf, drive_conf;
-	u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	u8 drive_pci = 0x40 + (drive->dn * 4);
-	u8 drive_fast;
-	struct pci_dev *dev	= drive->channel->pci_dev;
+	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
+	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	unsigned int list_conf	= 0;
+	unsigned int drive_conf	= 0;
+	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte drive_fast		= 0;
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 
 	/*
 	 * Disable the "fast interrupt" prediction.
@@ -615,11 +823,11 @@
 	 */
 	pci_read_config_byte(dev, regfast, &drive_fast);
 	drive_fast &= ~0x07;
-	pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast);
-
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
 	list_conf = pci_bus_clock_list(speed,
 			(struct chipset_bus_clock_list_entry *)
-					dev->sysdata);
+					dev->driver_data);
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
 	if (speed < XFER_MW_DMA_0)
@@ -627,261 +835,394 @@
 	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
-static int hpt3xx_tune_chipset(struct ata_device *drive, u8 speed)
+static void hpt374_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	u32 rev;
-
-	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
-		return -1;
+	hpt372_tune_chipset(drive, speed);
+}
 
-	rev = hpt_revision(drive->channel->pci_dev);
+static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 
-	if (rev >= 5) {
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
 		hpt372_tune_chipset(drive, speed);
-	} else if (rev >= 3) {
+	else if (hpt_minimum_revision(dev, 3))
 		hpt370_tune_chipset(drive, speed);
-	} else {
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
                 hpt366_tune_chipset(drive, speed);
-        }
 
-	return ide_config_drive_speed(drive, speed);
+	return ((int) ide_config_drive_speed(drive, speed));
 }
 
-/* FIXME: pio == 255 -> ata_best_pio_mode(drive)  --bkz */
-static void hpt3xx_tune_drive(struct ata_device *drive, u8 pio)
+static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
 {
-	(void) hpt3xx_tune_chipset(drive, XFER_PIO_0 + min_t(u8, pio, 4));
+	byte speed;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) hpt3xx_tune_chipset(drive, speed);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int hpt3xx_udma_setup(struct ata_device *drive, int map)
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u32 rev;
-
-	if (drive->type != ATA_DISK)
-		return 0;
-
-	rev = hpt_revision(drive->channel->pci_dev);
-
-	/* FIXME: badlists need futher investigation  --bkz */
-
-	/* bad_ata100_5 is for HPT370/370A,
-	   bad_ata66_4, bad_ata66_3 and bad_ata33 are for HPT366/368 */
-
-	if (rev < 5 && check_in_drive_lists(drive, bad_ata100_5))
-		map &= ~XFER_UDMA_100;
-
-	if (rev < 3) {
-		if (check_in_drive_lists(drive, bad_ata66_4))
-			map &= ~XFER_UDMA_66_4;
-
-		if (check_in_drive_lists(drive, bad_ata66_3))
-			map &= ~XFER_UDMA_66_3;
-
-		if (check_in_drive_lists(drive, bad_ata33))
-			map &= ~XFER_UDMA_ALL;
+	struct hd_driveid *id	= drive->id;
+	byte mode		= hpt3xx_ratemask(drive);
+	byte speed		= 0x00;
+
+	if (drive->media != ide_disk)
+		mode |= 0x08;
+
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
 	}
 
-	return udma_generic_setup(drive, map);
+	(void) hpt3xx_tune_chipset(drive, speed);
+
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
 }
 
-static int hpt3xx_quirkproc(struct ata_device *drive)
+int hpt3xx_quirkproc (ide_drive_t *drive)
 {
 	return ((int) check_in_drive_lists(drive, quirk_drives));
 }
 
-static void hpt3xx_intrproc(struct ata_device *drive)
+void hpt3xx_intrproc (ide_drive_t *drive)
 {
-	if (drive->quirk_list) {
-		/* drives in the quirk_list may not like intr setups/cleanups */
-	} else {
-		OUT_BYTE(0x02, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-	}
+	if (drive->quirk_list)
+		return;
+	/* drives in the quirk_list may not like intr setups/cleanups */
+	OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
 }
 
-static void hpt3xx_maskproc(struct ata_device *drive)
+void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	struct ata_channel *ch = drive->channel;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
 
 	if (drive->quirk_list) {
-		u32 rev = hpt_revision(dev);
-		if (rev >= 3) {
-			u8 reg5a;
+		if (hpt_minimum_revision(dev,3)) {
+			byte reg5a = 0;
 			pci_read_config_byte(dev, 0x5a, &reg5a);
-			if ((reg5a & 0x10) >> 4)
-				pci_write_config_byte(dev, 0x5a, reg5a & ~0x10);
-		} else
-			enable_irq(drive->channel->irq);
+			if (((reg5a & 0x10) >> 4) != mask)
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		} else {
+			if (mask) {
+				disable_irq(HWIF(drive)->irq);
+			} else {
+				enable_irq(HWIF(drive)->irq);
+			}
+		}
 	} else {
-		if (ch->io_ports[IDE_CONTROL_OFFSET])
-			OUT_BYTE(0x00, ch->io_ports[IDE_CONTROL_OFFSET]);
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
 	}
 }
 
-static void hpt366_udma_irq_lost(struct ata_device *drive)
+static int config_drive_xfer_rate (ide_drive_t *drive)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	u8 reg50h, reg52h, reg5ah;
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
 
-	pci_read_config_byte(dev, 0x50, &reg50h);
-	pci_read_config_byte(dev, 0x52, &reg52h);
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-			drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
-	if (reg5ah & 0x10)
-		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-}
+	drive->init_speed = 0;
 
-static void do_udma_start(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if (id->dma_mword & 0x0007) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
 
-	u8 regstate = ch->unit ? 0x54 : 0x50;
-	pci_write_config_byte(ch->pci_dev, regstate, 0x37);
-	udelay(10);
+		hpt3xx_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
-static void hpt370_udma_start(struct ata_device *drive, struct request *__rq)
+/*
+ * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ *
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-
-	do_udma_start(drive);
-
-	/* Note that this is done *after* the cmd has been issued to the drive,
-	 * as per the BM-IDE spec.  The Promise Ultra33 doesn't work correctly
-	 * when we do this part before issuing the drive cmd.
-	 */
-
-	outb(inb(ch->dma_base) | 1, ch->dma_base);	/* start DMA */
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	unsigned long dma_base	= HWIF(drive)->dma_base;
+	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:
+				/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* return 1 if INTR asserted */
+			return (dma_stat & 4) == 4;
+		case ide_dma_lostirq:
+			pci_read_config_byte(dev, 0x50, &reg50h);
+			pci_read_config_byte(dev, 0x52, &reg52h);
+			pci_read_config_byte(dev, 0x5a, &reg5ah);
+			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x,"
+				" reg5ah=0x%02x\n",
+				drive->name,
+				ide_dmafunc_verbose(func),
+				reg50h, reg52h, reg5ah);
+			if (reg5ah & 0x10)
+				pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+			/* how about we flush and reset, mmmkay? */
+			pci_write_config_byte(dev, 0x51, 0x1F);
+			/* fall through to a reset */
+		case ide_dma_begin:
+		case ide_dma_end:
+			/* reset the chips state over and over.. */
+			pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+			break;
+		case ide_dma_timeout:
+		default:
+			break;
+	}
+	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive);
 }
 
-static void do_timeout_irq(struct ata_device *drive)
+int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	u8 dma_stat;
-	u8 regstate = drive->channel->unit ? 0x54 : 0x50;
-	u8 reginfo = drive->channel->unit ? 0x56 : 0x52;
-	unsigned long dma_base = drive->channel->dma_base;
-
-	pci_read_config_byte(drive->channel->pci_dev, reginfo, &dma_stat);
-	printk(KERN_INFO "%s: %d bytes in FIFO\n", drive->name, dma_stat);
-	pci_write_config_byte(drive->channel->pci_dev, regstate, 0x37);
-	udelay(10);
-	dma_stat = inb(dma_base);
-	outb(dma_stat & ~0x1, dma_base); /* stop dma */
-	dma_stat = inb(dma_base + 2);
-	outb(dma_stat | 0x6, dma_base+2); /* clear errors */
-
-}
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long dma_base	= hwif->dma_base;
+	byte regstate		= hwif->channel ? 0x54 : 0x50;
+	byte reginfo		= hwif->channel ? 0x56 : 0x52;
+	byte dma_stat;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:
+				/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* return 1 if INTR asserted */
+			return (dma_stat & 4) == 4;
+
+		case ide_dma_end:
+			dma_stat = IN_BYTE(dma_base + 2);
+			if (dma_stat & 0x01) {
+				/* wait a little */
+				udelay(20);
+				dma_stat = IN_BYTE(dma_base + 2);
+			}
+			if ((dma_stat & 0x01) == 0) 
+				break;
 
-static void hpt370_udma_timeout(struct ata_device *drive)
-{
-	do_timeout_irq(drive);
-	do_udma_start(drive);
-}
+			func = ide_dma_timeout;
+			/* fallthrough */
 
-static void hpt370_udma_irq_lost(struct ata_device *drive)
-{
-	do_timeout_irq(drive);
-	do_udma_start(drive);
-}
+		case ide_dma_timeout:
+		case ide_dma_lostirq:
+			pci_read_config_byte(dev, reginfo, &dma_stat);
+			printk("%s: %d bytes in FIFO\n", drive->name, 
+			       dma_stat);
+			pci_write_config_byte(dev, regstate, 0x37);
+			udelay(10);
+			dma_stat = IN_BYTE(dma_base);
+			/* stop dma */
+			OUT_BYTE(dma_stat & ~0x1, dma_base);
+			dma_stat = IN_BYTE(dma_base + 2);
+			/* clear errors */
+			OUT_BYTE(dma_stat | 0x6, dma_base+2);
+			/* fallthrough */
 
-static int hpt370_udma_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
+#ifdef HPT_RESET_STATE_ENGINE
+	        case ide_dma_begin:
+#endif
+			pci_write_config_byte(dev, regstate, 0x37);
+			udelay(10);
+			break;
 
-	dma_stat = inb(dma_base + 2);
-	if (dma_stat & 0x01) {
-		udelay(20); /* wait a little */
-		dma_stat = inb(dma_base + 2);
-	}
-	if ((dma_stat & 0x01) != 0) {
-		do_timeout_irq(drive);
-		do_udma_start(drive);
+		default:
+			break;
 	}
-
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
+	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive);
 }
 
-static int hpt374_udma_stop(struct ata_device *drive)
+int hpt374_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev = drive->channel->pci_dev;
-	unsigned long dma_base = ch->dma_base;
-	u8 mscreg = ch->unit ? 0x54 : 0x50;
-	u8 dma_stat;
-	u8 bwsr_mask = ch->unit ? 0x02 : 0x01;
-	u8 bwsr_stat, msc_stat;
-	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
-	pci_read_config_byte(dev, mscreg, &msc_stat);
-	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
-	        pci_write_config_byte(dev, mscreg, msc_stat|0x30);
-
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-}
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long dma_base	= hwif->dma_base;
+	byte mscreg		= hwif->channel ? 0x54 : 0x50;
+//	byte reginfo		= hwif->channel ? 0x56 : 0x52;
+	byte dma_stat;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:
+				/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+#if 0  /* do not set unless you know what you are doing */
+			if (dma_stat & 4) {
+				byte stat = GET_STAT();
+				OUT_BYTE(dma_base+2, dma_stat & 0xE4);
+			}
 #endif
+			/* return 1 if INTR asserted */
+			return (dma_stat & 4) == 4;
+		case ide_dma_end:
+		{
+			byte bwsr_mask = hwif->channel ? 0x02 : 0x01;
+			byte bwsr_stat, msc_stat;
+			pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+			pci_read_config_byte(dev, mscreg, &msc_stat);
+			if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+				pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+		}
+		default:
+			break;
+	}
+	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * Since SUN Cobalt is attempting to do this operation, I should disclose
  * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
  * HOTSWAP ATA Infrastructure.
  */
-static void hpt3xx_reset(struct ata_device *drive)
+void hpt3xx_reset (ide_drive_t *drive)
 {
 #if 0
-	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
-	u8 reset		= (drive->channel->unit) ? 0x80 : 0x40;
-	u8 reg59h;
-
-	pci_read_config_byte(drive->channel->pci_dev, 0x59, &reg59h);
-	pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h|reset);
-	pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h);
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	byte reg59h		= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
 #endif
 }
 
-#if 0
-static int hpt3xx_tristate(struct ata_device * drive, int state)
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
 {
-	struct ata_channel *ch	= drive->channel;
-	struct pci_dev *dev	= ch->pci_dev;
-	u8 reset = (ch->unit) ? 0x80 : 0x40;
-	u8 state_reg = (ch->unit) ? 0x57 : 0x53;
-	u8 reg59h, regXXh;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte reset		= (hwif->channel) ? 0x80 : 0x40;
+	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
+	byte reg59h		= 0;
+	byte regXXh		= 0;
 
-	if (!ch)
+	if (!hwif)
 		return -EINVAL;
 
-//	ch->bus_state = state;
+//	hwif->bus_state = state;
 
 	pci_read_config_byte(dev, 0x59, &reg59h);
 	pci_read_config_byte(dev, state_reg, &regXXh);
 
 	if (state) {
-		// reset drives...
+		(void) ide_do_reset(drive);
 		pci_write_config_byte(dev, state_reg, regXXh|0x80);
 		pci_write_config_byte(dev, 0x59, reg59h|reset);
 	} else {
 		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
 		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
-		// reset drives...
+		(void) ide_do_reset(drive);
 	}
 	return 0;
 }
-#endif
 
-/*
+/* 
  * set/get power state for a drive.
  * turning the power off does the following things:
  *   1) soft-reset the drive
@@ -890,71 +1231,79 @@
  * when we turn things back on, we need to re-initialize things.
  */
 #define TRISTATE_BIT  0x8000
-static int hpt370_busproc(struct ata_device * drive, int state)
+static int hpt370_busproc(ide_drive_t * drive, int state)
 {
-	struct ata_channel *ch = drive->channel;
-	u8 tristate, resetmask, bus_reg;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte tristate, resetmask, bus_reg;
 	u16 tri_reg;
 
-	if (!ch)
+	if (!hwif)
 		return -EINVAL;
 
-	ch->bus_state = state;
+	hwif->bus_state = state;
 
-	if (ch->unit) {
+	if (hwif->channel) { 
 		/* secondary channel */
 		tristate = 0x56;
-		resetmask = 0x80;
-	} else {
+		resetmask = 0x80; 
+	} else { 
 		/* primary channel */
 		tristate = 0x52;
 		resetmask = 0x40;
 	}
 
 	/* grab status */
-	pci_read_config_word(ch->pci_dev, tristate, &tri_reg);
-	pci_read_config_byte(ch->pci_dev, 0x59, &bus_reg);
+	pci_read_config_word(dev, tristate, &tri_reg);
+	pci_read_config_byte(dev, 0x59, &bus_reg);
 
 	/* set the state. we don't set it if we don't need to do so.
 	 * make sure that the drive knows that it has failed if it's off */
 	switch (state) {
 	case BUSSTATE_ON:
-		ch->drives[0].failures = 0;
-		ch->drives[1].failures = 0;
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
 		if ((bus_reg & resetmask) == 0)
 			return 0;
 		tri_reg &= ~TRISTATE_BIT;
 		bus_reg &= ~resetmask;
 		break;
 	case BUSSTATE_OFF:
-		ch->drives[0].failures = ch->drives[0].max_failures + 1;
-		ch->drives[1].failures = ch->drives[1].max_failures + 1;
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
 			return 0;
 		tri_reg &= ~TRISTATE_BIT;
 		bus_reg |= resetmask;
 		break;
 	case BUSSTATE_TRISTATE:
-		ch->drives[0].failures = ch->drives[0].max_failures + 1;
-		ch->drives[1].failures = ch->drives[1].max_failures + 1;
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
 			return 0;
 		tri_reg |= TRISTATE_BIT;
 		bus_reg |= resetmask;
 		break;
 	}
-	pci_write_config_byte(ch->pci_dev, 0x59, bus_reg);
-	pci_write_config_word(ch->pci_dev, tristate, tri_reg);
+	pci_write_config_byte(dev, 0x59, bus_reg);
+	pci_write_config_word(dev, tristate, tri_reg);
 
 	return 0;
 }
 
-static void __init hpt37x_init(struct pci_dev *dev)
+static void __init init_hpt37x(struct pci_dev *dev)
 {
 	int adjust, i;
 	u16 freq;
-	u32 pll, rev = hpt_revision(dev);
-	u8 reg5bh;
+	u32 pll;
+	byte reg5bh;
+
+#if 1
+	byte reg5ah = 0;
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
 
 	/*
 	 * default to pci clock. make sure MA15/16 are set to output
@@ -963,47 +1312,48 @@
 	pci_write_config_byte(dev, 0x5b, 0x23);
 
 	/*
-	 * set up the PLL. we need to adjust it so that it's stable.
+	 * set up the PLL. we need to adjust it so that it's stable. 
 	 * freq = Tpll * 192 / Tpci
 	 */
 	pci_read_config_word(dev, 0x78, &freq);
 	freq &= 0x1FF;
 	if (freq < 0x9c) {
 		pll = F_LOW_PCI_33;
-		if (rev >= 7) {
-			dev->sysdata = (void *) thirty_three_base_hpt374;
-		} else if (rev >= 5) {
-			dev->sysdata = (void *) thirty_three_base_hpt372;
-		} else {
-			dev->sysdata = (void *) thirty_three_base_hpt370;
-		}
+		if (hpt_minimum_revision(dev,8))
+			dev->driver_data = (void *) thirty_three_base_hpt374;
+		else if (hpt_minimum_revision(dev,5))
+			dev->driver_data = (void *) thirty_three_base_hpt372;
+		else if (hpt_minimum_revision(dev,4))
+			dev->driver_data = (void *) thirty_three_base_hpt370a;
+		else
+			dev->driver_data = (void *) thirty_three_base_hpt370;
 		printk("HPT37X: using 33MHz PCI clock\n");
 	} else if (freq < 0xb0) {
 		pll = F_LOW_PCI_40;
 	} else if (freq < 0xc8) {
 		pll = F_LOW_PCI_50;
-		if (rev >= 7) {
-	//		dev->sysdata = (void *) fifty_base_hpt374;
+		if (hpt_minimum_revision(dev,8))
 			BUG();
-		} else if (rev >= 5) {
-			dev->sysdata = (void *) fifty_base_hpt372;
-		} else {
-			dev->sysdata = (void *) fifty_base_hpt370;
-		}
+		else if (hpt_minimum_revision(dev,5))
+			dev->driver_data = (void *) fifty_base_hpt372;
+		else if (hpt_minimum_revision(dev,4))
+			dev->driver_data = (void *) fifty_base_hpt370a;
+		else
+			dev->driver_data = (void *) fifty_base_hpt370a;
 		printk("HPT37X: using 50MHz PCI clock\n");
 	} else {
 		pll = F_LOW_PCI_66;
-		if (rev >= 7) {
-	//		dev->sysdata = (void *) sixty_six_base_hpt374;
+		if (hpt_minimum_revision(dev,8))
 			BUG();
-		} else if (rev >= 5) {
-			dev->sysdata = (void *) sixty_six_base_hpt372;
-		} else {
-			dev->sysdata = (void *) sixty_six_base_hpt370;
-		}
+		else if (hpt_minimum_revision(dev,5))
+			dev->driver_data = (void *) sixty_six_base_hpt372;
+		else if (hpt_minimum_revision(dev,4))
+			dev->driver_data = (void *) sixty_six_base_hpt370a;
+		else
+			dev->driver_data = (void *) sixty_six_base_hpt370;
 		printk("HPT37X: using 66MHz PCI clock\n");
 	}
-
+	
 	/*
 	 * only try the pll if we don't have a table for the clock
 	 * speed that we're running at. NOTE: the internal PLL will
@@ -1011,9 +1361,9 @@
 	 * don't like to use the PLL because it will cause glitches
 	 * on PRST/SRST when the HPT state engine gets reset.
 	 */
-	if (dev->sysdata)
+	if (dev->driver_data) 
 		goto init_hpt37X_done;
-
+	
 	/*
 	 * adjust PLL based upon PCI clock, enable it, and wait for
 	 * stabilization.
@@ -1030,23 +1380,23 @@
 			if (reg5bh & 0x80) {
 				/* spin looking for the clock to destabilize */
 				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b,
+					pci_read_config_byte(dev, 0x5b, 
 							     &reg5bh);
 					if ((reg5bh & 0x80) == 0)
 						goto pll_recal;
 				}
 				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c,
+				pci_write_config_dword(dev, 0x5c, 
 						       pll & ~0x100);
 				pci_write_config_byte(dev, 0x5b, 0x21);
-				if (rev >= 7) {
-	//	dev->sysdata = (void *) fifty_base_hpt374;
+				if (hpt_minimum_revision(dev,8))
 					BUG();
-				} else if (rev >= 5) {
-					dev->sysdata = (void *) fifty_base_hpt372;
-				} else {
-					dev->sysdata = (void *) fifty_base_hpt370;
-				}
+				else if (hpt_minimum_revision(dev,5))
+					dev->driver_data = (void *) fifty_base_hpt372;
+				else if (hpt_minimum_revision(dev,4))
+					dev->driver_data = (void *) fifty_base_hpt370a;
+				else
+					dev->driver_data = (void *) fifty_base_hpt370a;
 				printk("HPT37X: using 50MHz internal PLL\n");
 				goto init_hpt37X_done;
 			}
@@ -1056,19 +1406,19 @@
 			pll -= (adjust >> 1);
 		else
 			pll += (adjust >> 1);
-	}
+	} 
 
 init_hpt37X_done:
 	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37);
-	pci_write_config_byte(dev, 0x54, 0x37);
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
 	udelay(100);
 }
 
-static void __init hpt366_init(struct pci_dev *dev)
+static void __init init_hpt366 (struct pci_dev *dev)
 {
-	u32 reg1;
-	u8 drive_fast;
+	unsigned int reg1	= 0;
+	byte drive_fast		= 0;
 
 	/*
 	 * Disable the "fast interrupt" prediction.
@@ -1077,26 +1427,28 @@
 	if (drive_fast & 0x80)
 		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
 	pci_read_config_dword(dev, 0x40, &reg1);
-
+									
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
-			dev->sysdata = (void *) forty_base_hpt366;
+			dev->driver_data = (void *) forty_base_hpt366;
 			break;
 		case 9:
-			dev->sysdata = (void *) twenty_five_base_hpt366;
+			dev->driver_data = (void *) twenty_five_base_hpt366;
 			break;
 		case 7:
 		default:
-			dev->sysdata = (void *) thirty_three_base_hpt366;
+			dev->driver_data = (void *) thirty_three_base_hpt366;
 			break;
 	}
+
+	if (!dev->driver_data)
+		BUG();
 }
 
-static unsigned int __init hpt366_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
-	u32 rev = hpt_revision(dev);
-	u8 test;
+	byte test = 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start)
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -1117,147 +1469,227 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-	if (rev >= 3)
-		hpt37x_init(dev);
-	else
-		hpt366_init(dev);
+	if (hpt_minimum_revision(dev, 3)) {
+		init_hpt37x(dev);
+		hpt_devs[n_hpt_devs++] = dev;
+	} else {
+		init_hpt366(dev);
+		hpt_devs[n_hpt_devs++] = dev;
+	}
+	
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!hpt366_proc) {
+		hpt366_proc = 1;
+		hpt366_display_info = &hpt366_get_info;
+	}
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
 
 	return dev->irq;
 }
 
-static unsigned int __init hpt366_ata66_check(struct ata_channel *ch)
+unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 {
-	u8 ata66;
-	u8 regmask = (ch->unit) ? 0x01 : 0x02;
+	byte ata66 = 0;
+	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
 
-	pci_read_config_byte(ch->pci_dev, 0x5a, &ata66);
+	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
 		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(ch->pci_dev->devfn));
-#endif
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
 	return ((ata66 & regmask) ? 0 : 1);
 }
 
-static void __init hpt366_init_channel(struct ata_channel *ch)
+void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev = ch->pci_dev;
-	u32 rev = hpt_revision(dev);
-
-	ch->udma_four = hpt366_ata66_check(ch);
-
-	ch->tuneproc = hpt3xx_tune_drive;
-	ch->speedproc = hpt3xx_tune_chipset;
-	ch->quirkproc = hpt3xx_quirkproc;
-	ch->intrproc = hpt3xx_intrproc;
-	ch->maskproc = hpt3xx_maskproc;
+	struct pci_dev *dev		= hwif->pci_dev;
+	hwif->tuneproc			= &hpt3xx_tune_drive;
+	hwif->speedproc			= &hpt3xx_tune_chipset;
+	hwif->quirkproc			= &hpt3xx_quirkproc;
+	hwif->intrproc			= &hpt3xx_intrproc;
+	hwif->maskproc			= &hpt3xx_maskproc;
 
 #ifdef HPT_SERIALIZE_IO
 	/* serialize access to this device */
-	if (ch->mate)
-		ch->serialized = ch->mate->serialized = 1;
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
 #endif
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (ch->dma_base) {
-		if (rev >= 3) {
-			u8 reg5ah;
-			pci_read_config_byte(dev, 0x5a, &reg5ah);
-			if (reg5ah & 0x10)	/* interrupt force enable */
-				pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-			/*
-			 * set up ioctl for power status.
-			 * note: power affects both
-			 * drives on each channel
-			 */
-			ch->resetproc	= hpt3xx_reset;
-			ch->busproc	= hpt370_busproc;
-
-			if (rev >= 5) {
-				ch->udma_stop = hpt374_udma_stop;
-			} else { /* rev >= 3 */
-			        ch->udma_start = hpt370_udma_start;
-				ch->udma_stop = hpt370_udma_stop;
-				ch->udma_timeout = hpt370_udma_timeout;
-				ch->udma_irq_lost = hpt370_udma_irq_lost;
-			}
-		} else {
-			ch->udma_irq_lost = hpt366_udma_irq_lost;
-//			ch->resetproc = hpt3xx_reset;
-//			ch->busproc = hpt3xx_tristate;
-		}
-		ch->modes_map = hpt3xx_modes_map(ch);
-		ch->udma_setup = hpt3xx_udma_setup;
-		ch->highmem = 1;
-	} else
-#endif
-	{
-		ch->drives[0].autotune = 1;
-		ch->drives[1].autotune = 1;
+	if (hpt_minimum_revision(dev,3)) {
+		byte reg5ah = 0;
+			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	} else if (hpt_minimum_revision(dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
+		hwif->resetproc = &hpt3xx_reset;
+		hwif->busproc   = &hpt3xx_tristate;
 	}
+
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (hpt_minimum_revision(dev,8))
+		hwif->dmaproc   = &hpt374_dmaproc;
+	else if (hpt_minimum_revision(dev,5))
+		hwif->dmaproc   = &hpt374_dmaproc;
+	else if (hpt_minimum_revision(dev,3))
+		hwif->dmaproc   = &hpt370_dmaproc;
+	else if (hpt_minimum_revision(dev,2))
+		hwif->dmaproc   = &hpt366_dmaproc;
+	else
+		hwif->dmaproc   = &hpt366_dmaproc;
+
+
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-static void __init hpt366_init_dma(struct ata_channel *ch, unsigned long dmabase)
-{
-	u8 masterdma, slavedma;
-	u8 dma_old = inb(dmabase + 2);
-	u8 dma_new = dma_old;
-	u8 primary = ch->unit ? 0x4b : 0x43;
-
-	pci_read_config_byte(ch->pci_dev, primary, &masterdma);
-	pci_read_config_byte(ch->pci_dev, primary + 4, &slavedma);
-
-	if (masterdma & 0x30)
-		dma_new |= 0x20;
-	if (slavedma & 0x30)
-		dma_new |= 0x40;
-	if (dma_new != dma_old)
-		outb(dma_new, dmabase+2);
-
-	ata_init_dma(ch, dmabase);
+void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	byte masterdma = 0, slavedma = 0;
+	byte dma_new = 0, dma_old = IN_BYTE(dmabase+2);
+	byte primary	= hwif->channel ? 0x4b : 0x43;
+	byte secondary	= hwif->channel ? 0x4f : 0x47;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old) OUT_BYTE(dma_new, dmabase+2);
+
+	local_irq_restore(flags);
+
+	ide_setup_dma(hwif, dmabase, 8);
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_TTI,
-		.device = PCI_DEVICE_ID_TTI_HPT366,
-		.init_chipset = hpt366_init_chipset,
-		.init_channel = hpt366_init_channel,
-		.init_dma = hpt366_init_dma,
-		.bootable = OFF_BOARD,
-		.extra = 240,
-		.flags = ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_TTI,
-		.device = PCI_DEVICE_ID_TTI_HPT372,
-		.init_chipset = hpt366_init_chipset,
-		.init_channel = hpt366_init_channel,
-		.init_dma = hpt366_init_dma,
-		.bootable = OFF_BOARD,
-		.extra = 0,
-		.flags = ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_TTI,
-		.device = PCI_DEVICE_ID_TTI_HPT374,
-		.init_chipset = hpt366_init_chipset,
-		.init_channel = hpt366_init_channel,
-		.init_dma = hpt366_init_dma,
-		.bootable = OFF_BOARD,
-		.extra = 0,
-		.flags = ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
-	},
-};
+void __init fixup_device_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			dev2 = findev;
+			break;
+		}
+	}
 
-int __init init_hpt366(void)
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2) {
+		return;
+	} else {
+		byte irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+			dev2->irq = dev->irq;
+			printk("%s: pci-config space interrupt fixed.\n",
+				d->name);
+		}
+	}
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
+
+}
+
+void __init fixup_device_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
+	unsigned char pin1 = 0, pin2 = 0;
+	unsigned int class_rev;
+	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
+				 "HPT370", "HPT370A", "HPT372"};
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
 
-	return 0;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	strcpy(d->name, chipset_names[class_rev]);
+
+	switch(class_rev) {
+		case 5:
+		case 4:
+		case 3:	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+				d->name, dev->bus->number, dev->devfn);
+			ide_setup_pci_device(dev, d);
+			return;
+		default:	break;
+	}
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			dev2 = findev;
+			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+			hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
+			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
+			if (hpt363_shared_pin && hpt363_shared_irq) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, "
+					"pin1=%d pin2=%d\n", d->name,
+					pin1, pin2);
+#if 0
+				/*
+				 * This is the third undocumented detection
+				 * method and is generally required for the
+				 * ABIT-BP6 boards.
+				 */
+				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
+				printk("PCI: %s: Fixing interrupt %d pin %d "
+					"to ZERO \n", d->name, dev2->irq, pin2);
+				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
+#endif
+			}
+			break;
+		}
+	}
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
 }
+
diff -Nru a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c
--- a/drivers/ide/hptraid.c	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,438 +0,0 @@
-/*
-   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-
-   Based on work
-   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
-	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
-   Based on work done by Søren Schmidt for FreeBSD
-
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int hptraid_open(struct inode *inode, struct file *filp);
-static int hptraid_release(struct inode *inode, struct file *filp);
-static int hptraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg);
-static int hptraid_make_request(request_queue_t * q, int rw,
-				struct buffer_head *bh);
-
-
-
-struct hptdisk {
-	kdev_t device;
-	unsigned long sectors;
-	struct block_device *bdev;
-};
-
-struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-
-	struct hptdisk disk[8];
-
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations hptraid_ops = {
-	.open = hptraid_open,
-	.release = hptraid_release,
-	.ioctl = hptraid_ioctl,
-	.make_request = hptraid_make_request
-};
-
-static struct hptraid raid[16];
-
-static int hptraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned char val;
-	unsigned long sectors;
-
-	if (!inode || kdev_none(inode->i_rdev))
-		return -EINVAL;
-
-	minor = minor(inode->i_rdev) >> SHIFT;
-
-	switch (cmd) {
-	case BLKGETSIZE:	/* Return device size */
-		if (!arg)
-			return -EINVAL;
-		sectors =
-		    ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects;
-		if (minor(inode->i_rdev) & 15)
-			return put_user(sectors, (unsigned long *) arg);
-		return put_user(raid[minor].sectors,
-				(unsigned long *) arg);
-		break;
-
-
-	case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc =
-			    (struct hd_geometry *) arg;
-			unsigned short bios_cyl;
-
-			if (!loc)
-				return -EINVAL;
-			val = 255;
-			if (put_user(val, (u8 *) & loc->heads))
-				return -EFAULT;
-			val = 63;
-			if (put_user(val, (u8 *) & loc->sectors))
-				return -EFAULT;
-			bios_cyl = raid[minor].sectors / 63 / 255;
-			if (put_user
-			    (bios_cyl, (unsigned short *) &loc->cylinders))
-				return -EFAULT;
-			if (put_user
-			    ((unsigned) ataraid_gendisk.
-			     part[minor(inode->i_rdev)].start_sect,
-			     (unsigned long *) &loc->start))
-				return -EFAULT;
-			return 0;
-		}
-
-	default:
-		return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-static int hptraid_make_request(request_queue_t * q, int rw,
-				struct buffer_head *bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left, rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk = 0, real_disk = 0;
-	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-
-	device = (bh->b_rdev >> SHIFT) & MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride == 0)
-		thisraid->stride = 1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-
-	rsect += ataraid_gendisk.part[minor(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect / thisraid->stride) !=
-	    ((rsect + (bh->b_size / 512) - 1) / thisraid->stride)) {
-		return -1;
-	}
-
-	rsect_left = rsect;
-
-	for (i = 0; i < 8; i++) {
-		if (thisraid->cutoff_disks[i] == 0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum +=
-			    thisraid->cutoff[i] /
-			    thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block =
-			    (block / thisraid->cutoff_disks[i]) *
-			    thisraid->stride;
-			rsect =
-			    rsect_accum + (rsect_left % thisraid->stride) +
-			    block;
-			break;
-		}
-	}
-
-	for (i = 0; i < 8; i++) {
-		if ((disk == 0)
-		    && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk > 0)
-		    && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-
-	}
-	disk = real_disk;
-
-	/* All but the first disk have a 10 sector offset */
-	if (i > 0)
-		rsect += 10;
-
-
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-
-#include "hptraid.h"
-
-static int __init read_disk_sb(struct block_device *bdev,
-			       struct highpoint_raid_conf *buf)
-{
-	/* Superblock is at 9*512 bytes */
-	Sector sect;
-	unsigned char *p = read_dev_sector(bdev, 9, &sect);
-
-	if (p) {
-		memcpy(buf, p, 512);
-		put_dev_sector(&sect);
-		return 0;
-	}
-	printk(KERN_ERR "hptraid: Error reading superblock.\n");
-	return -1;
-}
-
-static unsigned long maxsectors(int major, int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	struct ata_device *ideinfo;
-
-	dev = mk_kdev(major, minor);
-	ideinfo = get_info_ptr(dev);
-	if (ideinfo == NULL)
-		return 0;
-
-
-	/* first sector of the last cluster */
-	if (ideinfo->head == 0)
-		return 0;
-	if (ideinfo->sect == 0)
-		return 0;
-	lba = (ideinfo->capacity);
-
-	return lba;
-}
-
-static struct highpoint_raid_conf __initdata prom;
-static void __init probedisk(int major, int minor, int device)
-{
-	int i;
-	struct block_device *bdev = bdget(mk_kdev(major, minor));
-	struct gendisk *gd;
-
-	if (!bdev)
-		return;
-
-	if (blkdev_get(bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW) < 0)
-		return;
-
-	if (maxsectors(major, minor) == 0)
-		goto out;
-
-	if (read_disk_sb(bdev, &prom))
-		goto out;
-
-	if (prom.magic != 0x5a7816f0)
-		goto out;
-	if (prom.type) {
-		printk(KERN_INFO
-		       "hptraid: only RAID0 is supported currently\n");
-		goto out;
-	}
-
-	i = prom.disk_number;
-	if (i < 0)
-		goto out;
-	if (i > 8)
-		goto out;
-
-	raid[device].disk[i].bdev = bdev;
-	/* This is supposed to prevent others from stealing our underlying disks */
-	/* now blank the /proc/partitions table for the wrong partition table,
-	   so that scripts don't accidentally mount it and crash the kernel */
-	/* XXX: the 0 is an utter hack  --hch */
-	gd = get_gendisk(mk_kdev(major, 0));
-	if (gd != NULL) {
-		int j;
-		for (j = 1 + (minor << gd->minor_shift);
-		     j < ((minor + 1) << gd->minor_shift); j++)
-			gd->part[j].nr_sects = 0;
-	}
-
-	raid[device].disk[i].device = mk_kdev(major, minor);
-	raid[device].disk[i].sectors = maxsectors(major, minor);
-	raid[device].stride = (1 << prom.raid0_shift);
-	raid[device].disks = prom.raid_disks;
-	raid[device].sectors = prom.total_secs;
-	return;
-      out:
-	blkdev_put(bdev);
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i, j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-
-	bar = 0;
-	for (i = 0; i < 8; i++) {
-		smallest = ~0;
-		for (j = 0; j < 8; j++)
-			if ((raid[device].disk[j].sectors < smallest)
-			    && (raid[device].disk[j].sectors > bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j = 0; j < 8; j++)
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-
-	}
-}
-
-
-static __init int hptraid_init_one(int device)
-{
-	int i, count;
-
-	probedisk(IDE0_MAJOR, 0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR, 0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR, 0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR, 0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-
-	fill_cutoff(device);
-
-	/* Initialize the gendisk structure */
-
-	ataraid_register_disk(device, raid[device].sectors);
-
-	count = 0;
-	printk(KERN_INFO
-	       "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
-
-	for (i = 0; i < 8; i++) {
-		if (raid[device].disk[i].device != 0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-			       i, raid[device].disk[i].sectors / 2048);
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",
-		       count);
-		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
-	}
-
-}
-
-static __init int hptraid_init(void)
-{
-	int retval, device;
-
-	device = ataraid_get_device(&hptraid_ops);
-	if (device < 0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
-}
-
-static void __exit hptraid_exit(void)
-{
-	int i, device;
-	for (device = 0; device < 16; device++) {
-		for (i = 0; i < 8; i++) {
-			struct block_device *bdev =
-			    raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int hptraid_open(struct inode *inode, struct file *filp)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int hptraid_release(struct inode *inode, struct file *filp)
-{
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(hptraid_init);
-module_exit(hptraid_exit);
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/hptraid.h b/drivers/ide/hptraid.h
--- a/drivers/ide/hptraid.h	Tue Aug 27 12:28:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-                            
-struct highpoint_raid_conf
-{
-       int8_t  filler1[32];
-       u_int32_t       magic;
-#define HPT_MAGIC_OK   0x5a7816f0
-#define HPT_MAGIC_BAD  0x5a7816fd  
-
-       u_int32_t       magic_0;
-       u_int32_t       magic_1;
-       u_int32_t       order;  
-#define HPT_O_MIRROR   0x01  
-#define HPT_O_STRIPE   0x02
-#define HPT_O_OK       0x04
-
-       u_int8_t        raid_disks;
-       u_int8_t        raid0_shift; 
-       u_int8_t        type;
-#define HPT_T_RAID_0   0x00 
-#define HPT_T_RAID_1   0x01
-#define HPT_T_RAID_01_RAID_0   0x02
-#define HPT_T_SPAN             0x03
-#define HPT_T_RAID_3           0x04   
-#define HPT_T_RAID_5           0x05
-#define HPT_T_SINGLEDISK       0x06
-#define HPT_T_RAID_01_RAID_1   0x07
-
-       u_int8_t        disk_number;
-       u_int32_t       total_secs; 
-       u_int32_t       disk_mode;  
-       u_int32_t       boot_mode;
-       u_int8_t        boot_disk; 
-       u_int8_t        boot_protect;
-       u_int8_t        error_log_entries;
-       u_int8_t        error_log_index;  
-       struct
-       {
-               u_int32_t       timestamp;
-               u_int8_t        reason;   
-#define HPT_R_REMOVED          0xfe      
-#define HPT_R_BROKEN           0xff      
-
-               u_int8_t        disk;
-               u_int8_t        status;
-               u_int8_t        sectors;
-               u_int32_t       lba;
-       } errorlog[32];
-       u_int8_t        filler[60];
-};
diff -Nru a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
--- a/drivers/ide/ht6560b.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/ht6560b.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,10 @@
 /*
+ *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
+ *
  *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+ */
+
+/*
  *
  *  Version 0.01        Initial version hacked out of ide.c
  *
@@ -31,6 +36,8 @@
 
 #define HT6560B_VERSION "v0.07"
 
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -38,13 +45,13 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 
 /* #define DEBUG */  /* remove comments for DEBUG messages */
 
@@ -61,7 +68,7 @@
  *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
  */
 #define HT_CONFIG_PORT	  0x3e6
-#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
 /*
  * FIFO + PREFETCH (both a/b-model)
  */
@@ -107,7 +114,7 @@
  * Active Time for each drive. Smaller value gives higher speed.
  * In case of failures you should probably fall back to a higher value.
  */
-#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
 #define HT_TIMING_DEFAULT 0xff
 
 /*
@@ -120,35 +127,36 @@
 /*
  * This routine is invoked from ide.c to prepare for access to a given drive.
  */
-static void ht6560b_selectproc(struct ata_device *drive)
+static void ht6560b_selectproc (ide_drive_t *drive)
 {
 	unsigned long flags;
-	static u8 current_select = 0;
-	static u8 current_timing = 0;
-	u8 select, timing;
-
+	static byte current_select = 0;
+	static byte current_timing = 0;
+	byte select, timing;
+	
 	local_irq_save(flags);
-
+	
 	select = HT_CONFIG(drive);
 	timing = HT_TIMING(drive);
-
+	
 	if (select != current_select || timing != current_timing) {
 		current_select = select;
 		current_timing = timing;
-		if (drive->type != ATA_DISK || !drive->present)
+		if (drive->media != ide_disk || !drive->present)
 			select |= HT_PREFETCH_MODE;
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		outb(select, HT_CONFIG_PORT);
+		(void) IN_BYTE(HT_CONFIG_PORT);
+		(void) IN_BYTE(HT_CONFIG_PORT);
+		(void) IN_BYTE(HT_CONFIG_PORT);
+		(void) IN_BYTE(HT_CONFIG_PORT);
+		OUT_BYTE(select, HT_CONFIG_PORT);
 		/*
 		 * Set timing for this drive:
 		 */
-		outb(timing, IDE_SELECT_REG);
-		ata_status(drive, 0, 0);
+		OUT_BYTE(timing, IDE_SELECT_REG);
+		(void) IN_BYTE(IDE_STATUS_REG);
 #ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
+		printk("ht6560b: %s: select=%#x timing=%#x\n",
+			drive->name, select, timing);
 #endif
 	}
 	local_irq_restore(flags);
@@ -159,32 +167,32 @@
  */
 static int __init try_to_init_ht6560b(void)
 {
-	u8 orig_value;
+	byte orig_value;
 	int i;
-
+	
 	/* Autodetect ht6560b */
-	if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
+	if ((orig_value = IN_BYTE(HT_CONFIG_PORT)) == 0xff)
 		return 0;
-
+	
 	for (i=3;i>0;i--) {
-		outb(0x00, HT_CONFIG_PORT);
-		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
-			outb(orig_value, HT_CONFIG_PORT);
+		OUT_BYTE(0x00, HT_CONFIG_PORT);
+		if (!( (~IN_BYTE(HT_CONFIG_PORT)) & 0x3f )) {
+			OUT_BYTE(orig_value, HT_CONFIG_PORT);
 			return 0;
 		}
 	}
-	outb(0x00, HT_CONFIG_PORT);
-	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
-		outb(orig_value, HT_CONFIG_PORT);
+	OUT_BYTE(0x00, HT_CONFIG_PORT);
+	if ((~IN_BYTE(HT_CONFIG_PORT))& 0x3f) {
+		OUT_BYTE(orig_value, HT_CONFIG_PORT);
 		return 0;
 	}
 	/*
 	 * Ht6560b autodetected
 	 */
-	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-	outb(HT_TIMING_DEFAULT, 0x1f6);  /* SELECT */
-	(void) inb(0x1f7);               /* STATUS */
-
+	OUT_BYTE(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+	OUT_BYTE(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+	(void) IN_BYTE(0x1f7);               /* IDE_STATUS_REG */
+	
 	printk("\nht6560b " HT6560B_VERSION
 	       ": chipset detected and initialized"
 #ifdef DEBUG
@@ -194,32 +202,30 @@
 	return 1;
 }
 
-static u8 ht_pio2timings(struct ata_device *drive, u8 pio)
+static byte ht_pio2timings(ide_drive_t *drive, byte pio)
 {
 	int active_time, recovery_time;
 	int active_cycles, recovery_cycles;
-	struct ata_timing *t;
-
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+	
         if (pio) {
-		if (pio == 255)
-			pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-		else
-			pio = XFER_PIO_0 + min_t(u8, pio, 4);
-
-		t = ata_timing_data(pio);
-
+		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+		
 		/*
 		 *  Just like opti621.c we try to calculate the
 		 *  actual cycle time for recovery and activity
 		 *  according system bus speed.
 		 */
-		active_time = t->active;
-		recovery_time = t->cycle - active_time - t->setup;
+		active_time = ide_pio_timings[pio].active_time;
+		recovery_time = d.cycle_time 
+			- active_time
+			- ide_pio_timings[pio].setup_time;
 		/*
 		 *  Cycle times should be Vesa bus cycles
 		 */
-		active_cycles   = (active_time   * system_bus_speed + 999999) / 1000000;
-		recovery_cycles = (recovery_time * system_bus_speed + 999999) / 1000000;
+		active_cycles   = (active_time   * bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
 		/*
 		 *  Upper and lower limits
 		 */
@@ -227,19 +233,18 @@
 		if (recovery_cycles < 2)  recovery_cycles = 2;
 		if (active_cycles   > 15) active_cycles   = 15;
 		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-
+		
 #ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n",
-			drive->name, pio - XFER_PIO_0, recovery_cycles, recovery_time, active_cycles, active_time);
+		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
 #endif
-
-		return (u8)((recovery_cycles << 4) | active_cycles);
+		
+		return (byte)((recovery_cycles << 4) | active_cycles);
 	} else {
-
+		
 #ifdef DEBUG
 		printk("ht6560b: drive %s setting pio=0\n", drive->name);
 #endif
-
+		
 		return HT_TIMING_DEFAULT;    /* default setting */
 	}
 }
@@ -247,46 +252,53 @@
 /*
  *  Enable/Disable so called prefetch mode
  */
-static void ht_set_prefetch(struct ata_device *drive, u8 state)
+static void ht_set_prefetch(ide_drive_t *drive, byte state)
 {
+	unsigned long flags;
 	int t = HT_PREFETCH_MODE << 8;
-
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	
 	/*
 	 *  Prefetch mode and unmask irq seems to conflict
 	 */
 	if (state) {
 		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->channel->no_unmask = 1;
-		drive->channel->unmask = 0;
+		drive->no_unmask = 1;
+		drive->unmask = 0;
 	} else {
 		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->channel->no_unmask = 0;
+		drive->no_unmask = 0;
 	}
-
+	
+	spin_unlock_irqrestore(&ide_lock, flags);
+	
 #ifdef DEBUG
 	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
 #endif
 }
 
-/* Assumes IRQ's are disabled or at least that no other process will attempt to
- * access the IDE registers concurrently.
- */
-static void tune_ht6560b(struct ata_device *drive, u8 pio)
+static void tune_ht6560b (ide_drive_t *drive, byte pio)
 {
-	u8 timing;
-
+	unsigned long flags;
+	byte timing;
+	
 	switch (pio) {
 	case 8:         /* set prefetch off */
 	case 9:         /* set prefetch on */
 		ht_set_prefetch(drive, pio & 1);
 		return;
 	}
-
+	
 	timing = ht_pio2timings(drive, pio);
-
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	
 	drive->drive_data &= 0xff00;
 	drive->drive_data |= timing;
-
+	
+	spin_unlock_irqrestore(&ide_lock, flags);
+	
 #ifdef DEBUG
 	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
 #endif
@@ -295,7 +307,7 @@
 void __init init_ht6560b (void)
 {
 	int t;
-
+	
 	if (check_region(HT_CONFIG_PORT,1)) {
 		printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
 	} else {
@@ -309,9 +321,10 @@
 			ide_hwifs[1].tuneproc = &tune_ht6560b;
 			ide_hwifs[0].serialized = 1;  /* is this needed? */
 			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].unit = ATA_PRIMARY;
-			ide_hwifs[1].unit = ATA_SECONDARY;
-
+			ide_hwifs[0].mate = &ide_hwifs[1];
+			ide_hwifs[1].mate = &ide_hwifs[0];
+			ide_hwifs[1].channel = 1;
+			
 			/*
 			 * Setting default configurations for drives
 			 */
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/ide/icside.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/ide/icside.c
  *
- * Copyright (c) 1996-2002 Russell King.
+ * Copyright (c) 1996,1997 Russell King.
  *
  * Changelog:
  *  08-Jun-1996	RMK	Created
@@ -25,7 +25,6 @@
 #include <asm/dma.h>
 #include <asm/ecard.h>
 #include <asm/io.h>
-#include <asm/page.h>
 
 /*
  * Maximum number of interfaces per card
@@ -74,12 +73,6 @@
 	ICS_ARCIN_V6_IDESTEPPING
 };
 
-struct icside_state {
-	unsigned int channel;
-	unsigned int enabled;
-	unsigned int irq_port;
-};
-
 static const card_ids icside_cids[] = {
 	{ MANU_ICS,  PROD_ICS_IDE  },
 	{ MANU_ICS2, PROD_ICS2_IDE },
@@ -99,7 +92,7 @@
 static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
 	unsigned int memc_port = (unsigned int)ec->irq_data;
-	outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+	OUT_BYTE(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
@@ -108,7 +101,7 @@
 static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
 	unsigned int memc_port = (unsigned int)ec->irq_data;
-	inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
+	IN_BYTE(memc_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v5 = {
@@ -127,21 +120,10 @@
  */
 static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
 {
-	struct icside_state *state = ec->irq_data;
-	unsigned int base = state->irq_port;
-
-	state->enabled = 1;
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
 
-	switch (state->channel) {
-	case 0:
-		outb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-		inb(base + ICS_ARCIN_V6_INTROFFSET_2);
-		break;
-	case 1:
-		outb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-		inb(base + ICS_ARCIN_V6_INTROFFSET_1);
-		break;
-	}
+	OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
 
 /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
@@ -149,12 +131,10 @@
  */
 static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 {
-	struct icside_state *state = ec->irq_data;
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
 
-	state->enabled = 0;
-
-	inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+	IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
 
 /* Prototype: icside_irqprobe(struct expansion_card *ec)
@@ -162,10 +142,10 @@
  */
 static int icside_irqpending_arcin_v6(struct expansion_card *ec)
 {
-	struct icside_state *state = ec->irq_data;
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
 
-	return inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-	       inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+	return IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v6 = {
@@ -191,10 +171,10 @@
 
 	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
 
-	id = inb (addr) & 1;
-	id |= (inb (addr + 1) & 1) << 1;
-	id |= (inb (addr + 2) & 1) << 2;
-	id |= (inb (addr + 3) & 1) << 3;
+	id = IN_BYTE(addr) & 1;
+	id |= (IN_BYTE(addr + 1) & 1) << 1;
+	id |= (IN_BYTE(addr + 2) & 1) << 2;
+	id |= (IN_BYTE(addr + 3) & 1) << 3;
 
 	switch (id) {
 	case 0: /* A3IN */
@@ -228,40 +208,6 @@
 	return iftype;
 }
 
-/*
- * Handle routing of interrupts.  This is called before
- * we write the command to the drive.
- */
-static void icside_maskproc(struct ata_device *drive)
-{
-	const int mask = 0;
-	struct ata_channel *ch = drive->channel;
-	struct icside_state *state = ch->hw.priv;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	state->channel = ch->unit;
-
-	if (state->enabled && !mask) {
-		switch (ch->unit) {
-		case 0:
-			outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-			inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-			break;
-		case 1:
-			outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-			inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-			break;
-		}
-	} else {
-		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-	}
-
-	local_irq_restore(flags);
-}
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
 /*
  * SG-DMA support.
@@ -275,393 +221,450 @@
 #define NR_ENTRIES 256
 #define TABLE_SIZE (NR_ENTRIES * 8)
 
-static int ide_build_sglist(struct ata_device *drive, struct request *rq)
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
 {
-	struct ata_channel *ch = drive->channel;
-	struct scatterlist *sg = ch->sg_table;
-	int nents;
-
-	if ((rq->flags & REQ_SPECIAL) && (drive->type == ATA_DISK)) {
-		struct ata_taskfile *args = rq->special;
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
 
-		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-
-		memset(sg, 0, sizeof(*sg));
-		sg->page   = virt_to_page(rq->buffer);
-		sg->offset = ((unsigned long)rq->buffer) & ~PAGE_MASK;
-		sg->length = rq->nr_sectors * SECTOR_SIZE;
-		nents = 1;
-	} else {
-		nents = blk_rq_map_sg(&drive->queue, rq, sg);
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
 
-		if (rq->q && nents > rq->nr_phys_segments)
-			printk("icside: received %d segments, build %d\n",
-				rq->nr_phys_segments, nents);
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
 
-		if (rq_data_dir(rq) == READ)
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-	}
+	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
 
-	return pci_map_sg(NULL, sg, nents, ch->sg_dma_direction);
+static int
+icside_build_dmatable(ide_drive_t *drive, int reading)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
 }
 
 /* Teardown mappings after DMA has completed.  */
-static void icside_destroy_dmatable(struct ata_device *drive)
+static void icside_destroy_dmatable(ide_drive_t *drive)
 {
-	struct scatterlist *sg = drive->channel->sg_table;
-	int nents = drive->channel->sg_nents;
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
 
-	pci_unmap_sg(NULL, sg, nents, drive->channel->sg_dma_direction);
+	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
 }
 
-/*
- * Configure the IOMD to give the appropriate timings for the transfer
- * mode being requested.  We take the advice of the ATA standards, and
- * calculate the cycle time based on the transfer mode, and the EIDE
- * MW DMA specs that the drive provides in the IDENTIFY command.
- *
- * We have the following IOMD DMA modes to choose from:
- *
- *	Type	Active		Recovery	Cycle
- *	A	250 (250)	312 (550)	562 (800)
- *	B	187		250		437
- *	C	125 (125)	125 (375)	250 (500)
- *	D	62		125		187
- *
- * (figures in brackets are actual measured timings)
- *
- * However, we also need to take care of the read/write active and
- * recovery timings:
- *
- *			Read	Write
- *  	Mode	Active	-- Recovery --	Cycle	IOMD type
- *	MW0	215	50	215	480	A
- *	MW1	80	50	50	150	C
- *	MW2	70	25	25	120	C
- */
 static int
-icside_config_if(struct ata_device *drive, int xfer_mode)
+icside_config_if(ide_drive_t *drive, int xfer_mode)
 {
-	int on = 0, cycle_time = 0, use_dma_info = 0;
+	int func = ide_dma_off;
 
 	switch (xfer_mode) {
-	case XFER_MW_DMA_2: cycle_time = 250; use_dma_info = 1;	break;
-	case XFER_MW_DMA_1: cycle_time = 250; use_dma_info = 1;	break;
-	case XFER_MW_DMA_0: cycle_time = 480;			break;
-	}
+	case XFER_MW_DMA_2:
+		/*
+		 * The cycle time is limited to 250ns by the r/w
+		 * pulse width (90ns), however we should still
+		 * have a maximum burst transfer rate of 8MB/s.
+		 */
+		drive->drive_data = 250;
+		break;
 
-	/*
-	 * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
-	 * take care to note the values in the ID...
-	 */
-	if (use_dma_info && drive->id->eide_dma_time > cycle_time)
-		cycle_time = drive->id->eide_dma_time;
+	case XFER_MW_DMA_1:
+		drive->drive_data = 250;
+		break;
 
-	drive->drive_data = cycle_time;
+	case XFER_MW_DMA_0:
+		drive->drive_data = 480;
+		break;
 
-	if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
-		on = 1;
+	default:
+		drive->drive_data = 0;
+		break;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = (byte) xfer_mode;
+
+	if (drive->drive_data &&
+	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
+		func = ide_dma_on;
 	else
 		drive->drive_data = 480;
 
-	printk("%s: %02x selected (peak %dMB/s)\n", drive->name,
-		xfer_mode, 2000 / drive->drive_data);
+	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 
-	drive->current_speed = xfer_mode;
+	drive->current_speed = (byte) xfer_mode;
 
-	return on;
+	return func;
 }
 
-static int icside_set_speed(struct ata_device *drive, u8 speed)
+static int
+icside_set_speed(ide_drive_t *drive, byte speed)
 {
 	return icside_config_if(drive, speed);
 }
 
-static void icside_dma_enable(struct ata_device *drive, int on, int verbose)
-{
-	if (!on) {
-		if (verbose)
-			printk("%s: DMA disabled\n", drive->name);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-		udma_tcq_enable(drive, 0);
-#endif
-	}
-
-	/*
-	 * We don't need any bouncing.  Yes, this looks the
-	 * wrong way around, but it is correct.
-	 */
-	blk_queue_bounce_limit(&drive->queue, BLK_BOUNCE_ANY);
-	drive->using_dma = on;
-
-#ifdef CONFIG_CLK_DEV_IDE_TCQ_DEFAULT
-	if (on)
-		udma_tcq_enable(drive, 1);
-#endif
-}
-
-static int icside_dma_check(struct ata_device *drive, int map)
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *ch = drive->channel;
-	int xfer_mode = XFER_PIO_2;
-	int on;
+	int i;
+	byte stat, dma_stat;
 
-	if (!id || !(id->capability & 1) || !ch->autodma)
-		goto out;
-
-	/*
-	 * Enable DMA on any drive that has multiword DMA
-	 */
-	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
+	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	stat = GET_STAT();			/* get drive status */
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
 		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
 	}
-
-out:
-	on = icside_config_if(drive, xfer_mode);
-
-	icside_dma_enable(drive, on, 0);
-
-	return 0;
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
-static int icside_dma_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
+/*
+ * The following is a sick duplication from ide-dma.c ;(
+ *
+ * This should be defined in one place only.
+ */
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
 
-	disable_dma(ch->hw.dma);
-	icside_destroy_dmatable(drive);
+static struct drive_list_entry drive_whitelist [] = {
+	{ "Micropolis 2112A",			"ALL"		},
+	{ "CONNER CTMA 4000",			"ALL"		},
+	{ "CONNER CTT8000-A",			"ALL"		},
+	{ "ST34342A",				"ALL"		},
+	{ NULL,					0		}
+};
 
-	return get_dma_residue(ch->hw.dma) != 0;
-}
+static struct drive_list_entry drive_blacklist [] = {
+	{ "WDC AC11000H",			"ALL"		},
+	{ "WDC AC22100H",			"ALL"		},
+	{ "WDC AC32500H",			"ALL"		},
+	{ "WDC AC33100H",			"ALL"		},
+	{ "WDC AC31600H",			"ALL"		},
+	{ "WDC AC32100H",			"24.09P07"	},
+	{ "WDC AC23200L",			"21.10N21"	},
+	{ "Compaq CRD-8241B",			"ALL"		},
+	{ "CRD-8400B",				"ALL"		},
+	{ "CRD-8480B",				"ALL"		},
+	{ "CRD-8480C",				"ALL"		},
+	{ "CRD-8482B",				"ALL"		},
+ 	{ "CRD-84",				"ALL"		},
+	{ "SanDisk SDP3B",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SANYO CD-ROM CRD",			"ALL"		},
+	{ "HITACHI CDR-8",			"ALL"		},
+	{ "HITACHI CDR-8335",			"ALL"		},
+	{ "HITACHI CDR-8435",			"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
+	{ "CD-532E-A",				"ALL"		},
+	{ "E-IDE CD-ROM CR-840",		"ALL"		},
+	{ "CD-ROM Drive/F5A",			"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
+	{ "WPI CDD-820",			"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",			"ALL"		},
+	{ NULL,					0		}
+};
 
-static void icside_dma_start(struct ata_device *drive, struct request *rq)
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
 {
-	struct ata_channel *ch = drive->channel;
-
-	/* We can not enable DMA on both channels simultaneously. */
-	BUG_ON(dma_channel_active(ch->hw.dma));
-	enable_dma(ch->hw.dma);
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
 }
 
 /*
- * dma_intr() is the handler for disk read/write DMA interrupts
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
  */
-static ide_startstop_t icside_dmaintr(struct ata_device *drive, struct request *rq)
+static int check_drive_lists(ide_drive_t *drive, int good_bad)
 {
-	int dma_stat;
+	struct hd_driveid *id = drive->id;
 
-	dma_stat = icside_dma_stop(drive);
-	if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
-		if (!dma_stat) {
-			__ide_end_request(drive, rq, 1, rq->nr_sectors);
-			return ATA_OP_FINISHED;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
-		       drive->name, dma_stat);
+	if (good_bad) {
+		return in_drive_list(id, drive_whitelist);
+	} else {
+		int blacklist = in_drive_list(id, drive_blacklist);
+		if (blacklist)
+			printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+		return(blacklist);
 	}
-	return ata_error(drive, rq, __FUNCTION__);
+	return 0;
 }
 
 static int
-icside_dma_common(struct ata_device *drive, struct request *rq,
-		  unsigned int dma_mode)
+icside_dma_check(ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned int count;
-
-	/*
-	 * We can not enable DMA on both channels.
-	 */
-	BUG_ON(dma_channel_active(ch->hw.dma));
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	int autodma = hwif->autodma;
+	int xfer_mode = XFER_PIO_2;
+	int func = ide_dma_off_quietly;
 
-	count = ch->sg_nents = ide_build_sglist(drive, rq);
-	if (!count)
-		return 1;
+	if (!id || !(id->capability & 1) || !autodma)
+		goto out;
 
 	/*
-	 * Route the DMA signals to to this channel.
+	 * Consult the list of known "bad" drives
 	 */
-	outb(ch->select_data, ch->config_data);
+	if (check_drive_lists(drive, 0)) {
+		func = ide_dma_off;
+		goto out;
+	}
 
 	/*
-	 * Select the correct timing for this drive.
+	 * Enable DMA on any drive that has multiword DMA
 	 */
-	set_dma_speed(ch->hw.dma, drive->drive_data);
+	if (id->field_valid & 2) {
+		if (id->dma_mword & 4) {
+			xfer_mode = XFER_MW_DMA_2;
+			func = ide_dma_on;
+		} else if (id->dma_mword & 2) {
+			xfer_mode = XFER_MW_DMA_1;
+			func = ide_dma_on;
+		} else if (id->dma_mword & 1) {
+			xfer_mode = XFER_MW_DMA_0;
+			func = ide_dma_on;
+		}
+		goto out;
+	}
 
 	/*
-	 * Tell the DMA engine about the SG table and
-	 * data direction.
+	 * Consult the list of known "good" drives
 	 */
-	set_dma_sg(ch->hw.dma, ch->sg_table, count);
-	set_dma_mode(ch->hw.dma, dma_mode);
-
-	return 0;
-}
-
-static int icside_dma_init(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	u8 int cmd;
-
-	if (icside_dma_common(drive, rq, DMA_MODE_WRITE))
-		return ATA_OP_FINISHED;
-
-	if (drive->type != ATA_DISK)
-		return ATA_OP_CONTINUES;
-
-	ata_set_handler(drive, icside_dmaintr, WAIT_CMD, NULL);
-
-	if ((rq->flags & REQ_SPECIAL) && drive->addressing == 1) {
-		struct ata_taskfile *args = rq->special;
-		cmd = args->cmd;
-	} else if (drive->addressing) {
-		cmd = rq_data_dir(rq) == WRITE ? WIN_WRITEDMA_EXT : WIN_READDMA_EXT;
-	} else {
-		cmd = rq_data_dir(rq) == WRITE ? WIN_WRITEDMA : WIN_READDMA;
+	if (check_drive_lists(drive, 1)) {
+		if (id->eide_dma_time > 150)
+			goto out;
+		xfer_mode = XFER_MW_DMA_1;
+		func = ide_dma_on;
 	}
-	OUT_BYTE(cmd, IDE_COMMAND_REG);
-
-	enable_dma(ch->hw.dma);
 
-	return ATA_OP_CONTINUES;
-}
-
-static int icside_irq_status(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	struct icside_state *state = ch->hw.priv;
+out:
+	func = icside_config_if(drive, xfer_mode);
 
-	return inb(state->irq_port +
-		   (ch->unit ?
-			ICS_ARCIN_V6_INTRSTAT_2 :
-			ICS_ARCIN_V6_INTRSTAT_1)) & 1;
+	return hwif->dmaproc(func, drive);
 }
 
-static void icside_dma_timeout(struct ata_device *drive)
+static int
+icside_dma_verbose(ide_drive_t *drive)
 {
-	printk(KERN_ERR "ATA: %s: UDMA timeout occured:", drive->name);
-	ata_status(drive, 0, 0);
-	ata_dump(drive, NULL, "UDMA timeout");
+	printk(", DMA");
+	return 1;
 }
 
-static void icside_irq_lost(struct ata_device *drive)
+static int
+icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	printk(KERN_ERR "ATA: %s: IRQ lost\n", drive->name);
+	ide_hwif_t *hwif = HWIF(drive);
+//	ide_task_t *args = HWGROUP(drive)->rq->special;
+	int count, reading = 0;
+
+	switch (func) {
+	case ide_dma_off:
+		printk("%s: DMA disabled\n", drive->name);
+		/*FALLTHROUGH*/
+
+	case ide_dma_off_quietly:
+	case ide_dma_on:
+		drive->using_dma = (func == ide_dma_on);
+		return 0;
+
+	case ide_dma_check:
+		return icside_dma_check(drive);
+
+	case ide_dma_read:
+		reading = 1;
+	case ide_dma_write:
+		count = icside_build_dmatable(drive, reading);
+		if (!count)
+			return 1;
+		disable_dma(hwif->hw.dma);
+
+		/* Route the DMA signals to
+		 * to the correct interface.
+		 */
+		OUT_BYTE(hwif->select_data, hwif->config_data);
+
+		/* Select the correct timing
+		 * for this drive
+		 */
+		set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
+			     : DMA_MODE_WRITE);
+
+		drive->waiting_for_dma = 1;
+		if (drive->media != ide_disk)
+			return 0;
+
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+		/*
+		 * FIX ME to use only ACB ide_task_t args Struct
+		 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+	}
+#else
+		if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		} else if (drive->addressing == 1)
+			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+#endif
+		return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+	case ide_dma_begin:
+		enable_dma(hwif->hw.dma);
+		return 0;
+
+	case ide_dma_end:
+		drive->waiting_for_dma = 0;
+		disable_dma(hwif->hw.dma);
+		icside_destroy_dmatable(drive);
+		return get_dma_residue(hwif->hw.dma) != 0;
+
+	case ide_dma_test_irq:
+		return IN_BYTE((unsigned long)hwif->hw.priv) & 1;
+
+	case ide_dma_bad_drive:
+	case ide_dma_good_drive:
+		return check_drive_lists(drive, (func == ide_dma_good_drive));
+
+	case ide_dma_verbose:
+		return icside_dma_verbose(drive);
+
+	case ide_dma_timeout:
+	default:
+		printk("icside_dmaproc: unsupported %s func: %d\n",
+			ide_dmafunc_verbose(func), func);
+	}
+	return 1;
 }
 
-static int icside_setup_dma(struct ata_channel *ch)
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
 {
-	int autodma = 0;
-
-#ifdef CONFIG_IDEDMA_ICS_AUTO
-	autodma = 1;
-#endif
-
-	printk("    %s: SG-DMA", ch->name);
+	printk("    %s: SG-DMA", hwif->name);
 
-	ch->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
 				 GFP_KERNEL);
-	if (!ch->sg_table)
+	if (!hwif->sg_table)
 		goto failed;
 
-	ch->dmatable_cpu    = NULL;
-	ch->dmatable_dma    = 0;
-	ch->speedproc       = icside_set_speed;
-	ch->udma_setup	    = icside_dma_check;
-	ch->udma_enable     = icside_dma_enable;
-	ch->udma_start      = icside_dma_start;
-	ch->udma_stop       = icside_dma_stop;
-	ch->udma_init	    = icside_dma_init;
-	ch->udma_irq_status = icside_irq_status;
-	ch->udma_timeout    = icside_dma_timeout;
-	ch->udma_irq_lost   = icside_irq_lost;
-	ch->autodma         = autodma;
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+	hwif->speedproc = icside_set_speed;
+	hwif->dmaproc = icside_dmaproc;
+	hwif->autodma = autodma;
 
-	printk(" capable%s\n", autodma ? ", auto-enable" : "");
+	printk(" capable%s\n", autodma ?
+		", auto-enable" : "");
 
 	return 1;
 
 failed:
-	printk(" disabled, unable to allocate DMA table\n");
+	printk(" -- ERROR, unable to allocate DMA table\n");
 	return 0;
 }
-
-void ide_release_dma(struct ata_channel *ch)
-{
-	if (ch->sg_table) {
-		kfree(ch->sg_table);
-		ch->sg_table = NULL;
-	}
-}
 #endif
 
-static struct ata_channel *icside_find_hwif(unsigned long dataport)
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
 {
-	struct ata_channel *ch;
+	ide_hwif_t *hwif;
 	int index;
 
 	for (index = 0; index < MAX_HWIFS; ++index) {
-		ch = &ide_hwifs[index];
-		if (ch->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+		hwif = &ide_hwifs[index];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
 			goto found;
 	}
 
 	for (index = 0; index < MAX_HWIFS; ++index) {
-		ch = &ide_hwifs[index];
-		if (!ch->io_ports[IDE_DATA_OFFSET])
+		hwif = &ide_hwifs[index];
+		if (!hwif->io_ports[IDE_DATA_OFFSET])
 			goto found;
 	}
 
 	return NULL;
 found:
-	return ch;
+	return hwif;
 }
 
-static struct ata_channel *
+static ide_hwif_t *
 icside_setup(unsigned long base, struct cardinfo *info, int irq)
 {
 	unsigned long port = base + info->dataoffset;
-	struct ata_channel *ch;
+	ide_hwif_t *hwif;
 
-	ch = icside_find_hwif(base);
-	if (ch) {
+	hwif = icside_find_hwif(base);
+	if (hwif) {
 		int i;
 
-		memset(&ch->hw, 0, sizeof(hw_regs_t));
+		memset(&hwif->hw, 0, sizeof(hw_regs_t));
 
 		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-			ch->hw.io_ports[i] = (ide_ioreg_t)port;
-			ch->io_ports[i] = (ide_ioreg_t)port;
+			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+			hwif->io_ports[i] = (ide_ioreg_t)port;
 			port += 1 << info->stepping;
 		}
-		ch->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		ch->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		ch->hw.irq  = irq;
-		ch->irq     = irq;
-		ch->hw.dma  = NO_DMA;
-		ch->noprobe = 0;
-		ch->chipset = ide_acorn;
+		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->hw.irq  = irq;
+		hwif->irq     = irq;
+		hwif->hw.dma  = NO_DMA;
+		hwif->noprobe = 0;
+		hwif->chipset = ide_acorn;
 	}
 
-	return ch;
+	return hwif;
 }
 
-static int __init icside_register_v5(struct expansion_card *ec)
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
 {
 	unsigned long slot_port;
-	struct ata_channel *ch;
+	ide_hwif_t *hwif;
 
 	slot_port = ecard_address(ec, ECARD_MEMC, 0);
 
@@ -673,19 +676,18 @@
 	/*
 	 * Be on the safe side - disable interrupts
 	 */
-	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+	IN_BYTE(slot_port + ICS_ARCIN_V5_INTROFFSET);
 
-	ch = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
 
-	return ch ? 0 : -1;
+	return hwif ? 0 : -1;
 }
 
-static int __init icside_register_v6(struct expansion_card *ec)
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
 {
 	unsigned long slot_port, port;
-	struct icside_state *state;
-	struct ata_channel *ch0, *ch1;
-	unsigned int sel = 0;
+	ide_hwif_t *hwif, *mate;
+	int sel = 0;
 
 	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
 	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
@@ -695,59 +697,57 @@
 	else
 		sel = 1 << 5;
 
-	outb(sel, slot_port);
+	OUT_BYTE(sel, slot_port);
 
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+	ec->irq_data = (void *)port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
 
 	/*
-	 * Find and register the interfaces.
+	 * Be on the safe side - disable interrupts
 	 */
-	ch0 = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	ch1 = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+	IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_1);
+	IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_2);
 
-	if (!ch0 || !ch1)
-		return -ENODEV;
-
-	state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
-
-	state->channel    = 0;
-	state->enabled    = 0;
-	state->irq_port   = port;
-
-	ec->irq_data      = state;
-	ec->ops           = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-	ch0->maskproc     = icside_maskproc;
-	ch0->unit         = 0;
-	ch0->hw.priv      = state;
-	ch0->config_data  = slot_port;
-	ch0->select_data  = sel;
-	ch0->hw.dma       = ec->dma;
-
-	ch1->maskproc     = icside_maskproc;
-	ch1->unit         = 1;
-	ch1->hw.priv      = state;
-	ch1->config_data  = slot_port;
-	ch1->select_data  = sel | 1;
-	ch1->hw.dma       = ec->dma;
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-	if (ec->dma != NO_DMA && !request_dma(ec->dma, ch0->name)) {
-		icside_setup_dma(ch0);
-		icside_setup_dma(ch1);
+	if (ec->dma != NO_DMA) {
+		if (request_dma(ec->dma, hwif->name))
+			goto no_dma;
+
+		if (hwif) {
+			hwif->config_data = slot_port;
+			hwif->select_data = sel;
+			hwif->hw.dma  = ec->dma;
+			hwif->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_1);
+			hwif->channel = 0;
+			icside_setup_dma(hwif, autodma);
+		}
+		if (mate) {
+			mate->config_data = slot_port;
+			mate->select_data = sel | 1;
+			mate->hw.dma  = ec->dma;
+			mate->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_2);
+			mate->channel = 1;
+			icside_setup_dma(mate, autodma);
+		}
 	}
+no_dma:
 #endif
-	return 0;
+	return hwif || mate ? 0 : -1;
 }
 
 int __init icside_init(void)
 {
+	int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+	autodma = 1;
+#endif
+
 	ecard_startfind ();
 
 	do {
@@ -762,11 +762,11 @@
 
 		switch (icside_identifyif(ec)) {
 		case ics_if_arcin_v5:
-			result = icside_register_v5(ec);
+			result = icside_register_v5(ec, autodma);
 			break;
 
 		case ics_if_arcin_v6:
-			result = icside_register_v6(ec);
+			result = icside_register_v6(ec, autodma);
 			break;
 
 		default:
diff -Nru a/drivers/ide/ide-adma.c b/drivers/ide/ide-adma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-adma.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,9 @@
+/*
+ *  linux/drivers/ide/ide-adma.c         Version 0.00	June 24, 2001
+ *
+ *  Copyright (c) 2001		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Asynchronous DMA -- TBA, this is a holding file.
+ *
+ */
+
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/ide/ide-cd.c	Tue Aug 27 12:28:08 2002
@@ -1,4 +1,6 @@
 /*
+ * linux/drivers/ide/ide-cd.c
+ *
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
  * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
@@ -11,10 +13,9 @@
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
  * For those wishing to work on this driver, please be sure you download
- * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
- * (SFF-8020i rev 2.6) standards. These documents can be obtained by
+ * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI 
+ * (SFF-8020i rev 2.6) standards. These documents can be obtained by 
  * anonymous ftp from:
- *
  * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
  * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
  *
@@ -53,18 +54,18 @@
  *                       Aztech drives, which seem to have the same problem.
  * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
  * 2.05  Jun  8, 1995 -- Don't attempt to retry after an illegal request
- *                       or data protect error.
+ *                        or data protect error.
  *                       Use HWIF and DEV_HWIF macros as in ide.c.
  *                       Always try to do a request_sense after
- *                       a failed command.
+ *                        a failed command.
  *                       Include an option to give textual descriptions
- *                       of ATAPI errors.
+ *                        of ATAPI errors.
  *                       Fix a bug in handling the sector cache which
- *                       showed up if the drive returned data in 512 byte
- *                       blocks (like Pioneer drives).  Thanks to
- *                       Richard Hirst <srh@gpt.co.uk> for diagnosing this.
+ *                        showed up if the drive returned data in 512 byte
+ *                        blocks (like Pioneer drives).  Thanks to
+ *                        Richard Hirst <srh@gpt.co.uk> for diagnosing this.
  *                       Properly supply the page number field in the
- *                       MODE_SELECT command.
+ *                        MODE_SELECT command.
  *                       PLAYAUDIO12 is broken on the Aztech; work around it.
  * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
  *                       (my apologies to Scott, but now ide-cd.c is independent)
@@ -73,28 +74,28 @@
  *                       Use input_ide_data() and output_ide_data().
  *                       Add door locking.
  *                       Fix usage count leak in cdrom_open, which happened
- *                       when a read-write mount was attempted.
+ *                        when a read-write mount was attempted.
  *                       Try to load the disk on open.
  *                       Implement CDROMEJECT_SW ioctl (off by default).
  *                       Read total cdrom capacity during open.
  *                       Rearrange logic in cdrom_decode_status.  Issue
- *                       request sense commands for failed packet commands
- *                       from here instead of from cdrom_queue_packet_command.
- *                       Fix a race condition in retrieving error information.
+ *                        request sense commands for failed packet commands
+ *                        from here instead of from cdrom_queue_packet_command.
+ *                        Fix a race condition in retrieving error information.
  *                       Suppress printing normal unit attention errors and
- *                       some drive not ready errors.
+ *                        some drive not ready errors.
  *                       Implement CDROMVOLREAD ioctl.
  *                       Implement CDROMREADMODE1/2 ioctls.
  *                       Fix race condition in setting up interrupt handlers
- *                       when the `serialize' option is used.
+ *                        when the `serialize' option is used.
  * 3.01  Sep  2, 1995 -- Fix ordering of reenabling interrupts in
- *                       cdrom_queue_request.
+ *                        cdrom_queue_request.
  *                       Another try at using ide_[input,output]_data.
  * 3.02  Sep 16, 1995 -- Stick total disk capacity in partition table as well.
  *                       Make VERBOSE_IDE_CD_ERRORS dump failed command again.
  *                       Dump out more information for ILLEGAL REQUEST errs.
  *                       Fix handling of errors occurring before the
- *                       packet command is transferred.
+ *                        packet command is transferred.
  *                       Fix transfers with odd bytelengths.
  * 3.03  Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
  *                       `DCI-2S10' drives are broken too.
@@ -102,17 +103,17 @@
  * 3.05  Dec  1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
  * 3.06  Dec 16, 1995 -- Add support needed for partitions.
  *                       More workarounds for Vertos bugs (based on patches
- *                       from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
+ *                        from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
  *                       Try to eliminate byteorder assumptions.
  *                       Use atapi_cdrom_subchnl struct definition.
  *                       Add STANDARD_ATAPI compilation option.
  * 3.07  Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
- *                       Vertos 300.
+ *                        Vertos 300.
  *                       Add NO_DOOR_LOCKING configuration option.
  *                       Handle drive_cmd requests w/NULL args (for hdparm -t).
  *                       Work around sporadic Sony55e audio play problem.
  * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
- *                       problem with "hde=cdrom" with no drive present.  -ml
+ *                        problem with "hde=cdrom" with no drive present.  -ml
  * 3.08  Mar  6, 1996 -- More Vertos workarounds.
  * 3.09  Apr  5, 1996 -- Add CDROMCLOSETRAY ioctl.
  *                       Switch to using MSF addressing for audio commands.
@@ -128,47 +129,47 @@
  * 3.14  May 29, 1996 -- Add work-around for Vertos 600.
  *                        (From Hennus Bergman <hennus@sky.ow.nl>.)
  * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
- *                       from Ben Galliart <bgallia@luc.edu> with
- *                       special help from Jeff Lightfoot
- *                       <jeffml@pobox.com>
+ *                        from Ben Galliart <bgallia@luc.edu> with 
+ *                        special help from Jeff Lightfoot 
+ *                        <jeffml@pobox.com>
  * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
  * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
  * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
  *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
  * 3.18  Oct 31, 1996 -- Added module and DMA support.
- *
- *
+ *                       
+ *                       
  * 4.00  Nov 5, 1996   -- New ide-cd maintainer,
- *                        Erik B. Andersen <andersee@debian.org>
+ *                                 Erik B. Andersen <andersee@debian.org>
  *                     -- Newer Creative drives don't always set the error
- *                        register correctly.  Make sure we see media changes
- *                        regardless.
+ *                          register correctly.  Make sure we see media changes
+ *                          regardless.
  *                     -- Integrate with generic cdrom driver.
  *                     -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
- *                        a patch from Ciro Cattuto <>.
+ *                          a patch from Ciro Cattuto <>.
  *                     -- Call set_device_ro.
  *                     -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
- *                        ioctls, based on patch by Erik Andersen
+ *                          ioctls, based on patch by Erik Andersen
  *                     -- Add some probes of drive capability during setup.
  *
  * 4.01  Nov 11, 1996  -- Split into ide-cd.c and ide-cd.h
- *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE
- *                        ioctls in favor of a generalized approach
- *                        using the generic cdrom driver.
+ *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE 
+ *                          ioctls in favor of a generalized approach 
+ *                          using the generic cdrom driver.
  *                     -- Fully integrated with the 2.1.X kernel.
  *                     -- Other stuff that I forgot (lots of changes)
  *
  * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio@netvision.net.il>
- *                        to fix the drive door locking problems.
+ *                          to fix the drive door locking problems.
  *
  * 4.03  Dec 04, 1996  -- Added DSC overlap support.
- * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch
- *                        by Aleks Makarov (xmakarov@sun.felk.cvut.cz)
+ * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch 
+ *                          by Ales Makarov (xmakarov@sun.felk.cvut.cz)
  *
  * 4.05  Nov 20, 1997  -- Modified to print more drive info on init
  *                        Minor other changes
  *                        Fix errors on CDROMSTOP (If you have a "Dolphin",
- *                        you must define IHAVEADOLPHIN)
+ *                          you must define IHAVEADOLPHIN)
  *                        Added identifier so new Sanyo CD-changer works
  *                        Better detection if door locking isn't supported
  *
@@ -177,40 +178,40 @@
  * 4.08  Dec 18, 1997  -- spew less noise when tray is empty
  *                     -- fix speed display for ACER 24X, 18X
  * 4.09  Jan 04, 1998  -- fix handling of the last block so we return
- *                        an end of file instead of an I/O error (Gadi)
+ *                         an end of file instead of an I/O error (Gadi)
  * 4.10  Jan 24, 1998  -- fixed a bug so now changers can change to a new
- *                        slot when there is no disc in the current slot.
+ *                         slot when there is no disc in the current slot.
  *                     -- Fixed a memory leak where info->changer_info was
- *                        malloc'ed but never free'd when closing the device.
+ *                         malloc'ed but never free'd when closing the device.
  *                     -- Cleaned up the global namespace a bit by making more
- *                        functions static that should already have been.
+ *                         functions static that should already have been.
  * 4.11  Mar 12, 1998  -- Added support for the CDROM_SELECT_SPEED ioctl
- *                        based on a patch for 2.0.33 by Jelle Foks
- *                        <jelle@scintilla.utwente.nl>, a patch for 2.0.33
- *                        by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
- *                        version, and my own efforts.  -erik
+ *                         based on a patch for 2.0.33 by Jelle Foks 
+ *                         <jelle@scintilla.utwente.nl>, a patch for 2.0.33
+ *                         by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
+ *                         version, and my own efforts.  -erik
  *                     -- Fixed a stupid bug which egcs was kind enough to
- *                        inform me of where "Illegal mode for this track"
- *                        was never returned due to a comparison on data
- *                        types of limited range.
- * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is
- *                        now set ionly for CD-R and CD-RW drives.  I had
- *                        removed this support because it produced errors.
- *                        It produced errors _only_ for non-writers. duh.
+ *                         inform me of where "Illegal mode for this track"
+ *                         was never returned due to a comparison on data
+ *                         types of limited range.
+ * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is 
+ *                         now set ionly for CD-R and CD-RW drives.  I had 
+ *                         removed this support because it produced errors.
+ *                         It produced errors _only_ for non-writers. duh.
  * 4.13  May 05, 1998  -- Suppress useless "in progress of becoming ready"
- *                        messages, since this is not an error.
+ *                         messages, since this is not an error.
  *                     -- Change error messages to be const
  *                     -- Remove a "\t" which looks ugly in the syslogs
  * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
- *                        since the .pdf version doesn't seem to work...
+ *                         since the .pdf version doesn't seem to work...
  *                     -- Updated the TODO list to something more current.
  *
- * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess,
- *                        patch thanks to "Eddie C. Dost" <ecd@skynet.be>
+ * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess, 
+ *                         patch thanks to "Eddie C. Dost" <ecd@skynet.be>
  *
  * 4.50  Oct 19, 1998  -- New maintainers!
- *                        Jens Axboe <axboe@image.dk>
- *                        Chris Zwilling <chris@cloudnet.com>
+ *                         Jens Axboe <axboe@image.dk>
+ *                         Chris Zwilling <chris@cloudnet.com>
  *
  * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@image.dk>
  *                      - ide_cdrom_reset enabled since the ide subsystem
@@ -223,17 +224,17 @@
  *                      - Detect DVD-ROM/RAM drives
  *
  * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
- *                        drive in transfer size limit.
+ *                         drive in transfer size limit.
  *                      - Fix the I/O error when doing eject without a medium
- *                        loaded on some drives.
+ *                         loaded on some drives.
  *                      - CDROMREADMODE2 is now implemented through
- *                        CDROMREADRAW, since many drives don't support
- *                        MODE2 (even though ATAPI 2.6 says they must).
+ *                         CDROMREADRAW, since many drives don't support
+ *                         MODE2 (even though ATAPI 2.6 says they must).
  *                      - Added ignore parameter to ide-cd (as a module), eg
- *			  insmod ide-cd ignore='hda hdb'
- *                        Useful when using ide-cd in conjunction with
- *                        ide-scsi. TODO: non-modular way of doing the
- *                        same.
+ *                         	insmod ide-cd ignore='hda hdb'
+ *                         Useful when using ide-cd in conjunction with
+ *                         ide-scsi. TODO: non-modular way of doing the
+ *                         same.
  *
  * 4.54  Aug 5, 1999	- Support for MMC2 class commands through the generic
  *			  packet interface to cdrom.c.
@@ -269,7 +270,7 @@
  *			- Mode sense and mode select moved to the
  *			  Uniform layer.
  *			- Fixed a problem with WPI CDS-32X drive - it
- *			  failed the capabilities
+ *			  failed the capabilities 
  *
  * 4.57  Apr 7, 2000	- Fixed sense reporting.
  *			- Fixed possible oops in ide_cdrom_get_last_session()
@@ -292,7 +293,7 @@
  *			  Michael D Johnson <johnsom@orst.edu>
  *
  *************************************************************************/
-
+ 
 #define IDECD_VERSION "4.59"
 
 #include <linux/config.h>
@@ -305,9 +306,8 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
-#include <linux/completion.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/completion.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -315,7 +315,6 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include <linux/atapi.h>
 #include "ide-cd.h"
 
 /****************************************************************************
@@ -324,72 +323,66 @@
 
 /* Mark that we've seen a media change, and invalidate our internal
    buffers. */
-static void cdrom_saw_media_change(struct ata_device *drive)
+static void cdrom_saw_media_change (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
-
+	
 	CDROM_STATE_FLAGS (drive)->media_changed = 1;
 	CDROM_STATE_FLAGS (drive)->toc_valid = 0;
 	info->nsectors_buffered = 0;
 }
 
-static void cdrom_analyze_sense_data(struct ata_device *drive, struct request *rq)
+static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc,
+			   struct request_sense *sense)
 {
 	int log = 0;
-	/* FIXME --mdcki */
-	struct packet_command *pc = (struct packet_command *) rq->special;
-	struct packet_command *failed_command = pc->failed_command;
-
-	/* Decode sense data from drive */
-	struct request_sense *sense = (struct request_sense *) (pc->buffer - rq->cmd[4]);
-	unsigned char fail_cmd;
 
-	if (sense == NULL || failed_command == NULL || failed_command->quiet)
-		return;
-
-	fail_cmd = rq->cmd[0];
+	if (sense == NULL || pc == NULL || pc->quiet)
+		return 0;
 
-	/* Check whatever this error should be logged:
-	 */
 	switch (sense->sense_key) {
-		case NO_SENSE:
-		case RECOVERED_ERROR:
+		case NO_SENSE: case RECOVERED_ERROR:
 			break;
-
 		case NOT_READY:
-
-			/* Don't care about tray state messages for e.g.
-			 * capacity commands or in-progress or becoming ready.
+			/*
+			 * don't care about tray state messages for
+			 * e.g. capacity commands or in-progress or
+			 * becoming ready
 			 */
 			if (sense->asc == 0x3a || sense->asc == 0x04)
 				break;
 			log = 1;
 			break;
-
 		case UNIT_ATTENTION:
-
-			/* Make good and sure we've seen this potential media
+			/*
+			 * Make good and sure we've seen this potential media
 			 * change. Some drives (i.e. Creative) fail to present
 			 * the correct sense key in the error register.
 			 */
 			cdrom_saw_media_change(drive);
 			break;
-
 		default:
 			log = 1;
 			break;
 	}
+	return log;
+}
+
+static
+void cdrom_analyze_sense_data(ide_drive_t *drive,
+			      struct packet_command *failed_command,
+			      struct request_sense *sense)
+{
 
-	if (!log)
+	if (!cdrom_log_sense(drive, failed_command, sense))
 		return;
 
 	/*
-	 * If a read toc is executed for a CD-R or CD-RW medium where the first
-	 * toc has not been recorded yet, it will fail with 05/24/00 (which is
-	 * a confusing error).
+	 * If a read toc is executed for a CD-R or CD-RW medium where
+	 * the first toc has not been recorded yet, it will fail with
+	 * 05/24/00 (which is a confusing error)
 	 */
-
-	if (fail_cmd == GPCMD_READ_TOC_PMA_ATIP)
+	if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP)
 		if (sense->sense_key == 0x05 && sense->asc == 0x24)
 			return;
 
@@ -452,26 +445,28 @@
 		printk("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
 			s, sense->asc, sense->ascq);
 
-		{
+		if (failed_command != NULL) {
 
 			int lo=0, mid, hi= ARY_LEN (packet_command_texts);
 			s = NULL;
 
 			while (hi > lo) {
 				mid = (lo + hi) / 2;
-				if (packet_command_texts[mid].packet_command == fail_cmd) {
+				if (packet_command_texts[mid].packet_command ==
+				    failed_command->c[0]) {
 					s = packet_command_texts[mid].text;
 					break;
 				}
-				if (packet_command_texts[mid].packet_command > fail_cmd)
+				if (packet_command_texts[mid].packet_command >
+				    failed_command->c[0])
 					hi = mid;
 				else
 					lo = mid+1;
 			}
 
 			printk ("  The failed \"%s\" packet command was: \n  \"", s);
-			for (i=0; i < CDROM_PACKET_SIZE; i++)
-				printk ("%02x ", rq->cmd[i]);
+			for (i=0; i<sizeof (failed_command->c); i++)
+				printk ("%02x ", failed_command->c[i]);
 			printk ("\"\n");
 		}
 
@@ -500,7 +495,7 @@
 		}
 	}
 
-#else
+#else /* not VERBOSE_IDE_CD_ERRORS */
 
 	/* Suppress printing unit attention and `in progress of becoming ready'
 	   errors when we're not being verbose. */
@@ -514,10 +509,10 @@
 		drive->name,
 		sense->error_code, sense->sense_key,
 		sense->asc, sense->ascq);
-#endif
+#endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
-static void cdrom_queue_request_sense(struct ata_device *drive,
+static void cdrom_queue_request_sense(ide_drive_t *drive, 
 				      struct completion *wait,
 				      struct request_sense *sense,
 				      struct packet_command *failed_command)
@@ -529,51 +524,159 @@
 	if (sense == NULL)
 		sense = &info->sense_data;
 
-	memset(pc, 0, sizeof(*pc));
-	pc->buffer = (void *) sense;
-	pc->buflen = 18;
-	pc->failed_command = failed_command;
+	memset(pc, 0, sizeof(struct packet_command));
+	pc->c[0] = GPCMD_REQUEST_SENSE;
+	pc->c[4] = pc->buflen = 18;
+	pc->buffer = (char *) sense;
+	pc->sense = (struct request_sense *) failed_command;
 
 	/* stuff the sense request in front of our current request */
 	rq = &info->request_sense_request;
-	memset(rq, 0, sizeof(*rq));
-	rq->cmd[0] = GPCMD_REQUEST_SENSE;
-	rq->cmd[4] = pc->buflen;
+	ide_init_drive_cmd(rq);
 	rq->flags = REQ_SENSE;
+	rq->buffer = (char *) pc;
+	rq->waiting = wait;
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
+}
 
-	/* FIXME --mdcki */
-	rq->special = (char *) pc;
 
-	rq->waiting = wait;
-	ide_do_drive_cmd(drive, rq, ide_preempt);
+/*
+ * This is our end_request replacement function.
+ */
+static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+		add_blkdev_randomness(major(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
 }
 
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
+
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return err;
+}
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_cdrom_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if ((rq->flags & REQ_DRIVE_CMD) || (rq->flags & REQ_DRIVE_TASK)) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		++rq->errors;
+	}
+	return ide_stopped;
+}
 
-static void cdrom_end_request(struct ata_device *drive, struct request *rq, int uptodate)
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
-	if ((rq->flags & REQ_SENSE) && uptodate)
-		cdrom_analyze_sense_data(drive, rq);
+	struct request *rq = HWGROUP(drive)->rq;
 
+	if ((rq->flags & REQ_SENSE) && uptodate) {
+		struct packet_command *pc = (struct packet_command *) rq->buffer;
+		cdrom_analyze_sense_data(drive,
+			(struct packet_command *) pc->sense,
+			(struct request_sense *) (pc->buffer - pc->c[4]));
+	}
 	if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors)
-		uptodate = 1;
+			uptodate = 1;
 
-	ata_end_request(drive, rq, uptodate, 0);
+	ide_cdrom_end_request(drive, uptodate);
 }
 
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status(ide_startstop_t *startstop, struct ata_device *drive, struct request *rq,
+static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
 				int good_stat, int *stat_ret)
 {
-	int err, sense_key;
+	struct request *rq = HWGROUP(drive)->rq;
+	int stat, err, sense_key;
 	struct packet_command *pc;
-	int ok;
-
+	
 	/* Check for errors. */
-	ok = ata_status(drive, good_stat, BAD_R_STAT);
-	*stat_ret = drive->status;
-	if (ok)
+	stat = GET_STAT();
+	*stat_ret = stat;
+
+	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
 	/* Get the IDE error register. */
@@ -581,8 +684,8 @@
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
-		printk("%s: missing rq in %s\n", drive->name, __FUNCTION__);
-		*startstop = ATA_OP_FINISHED;
+		printk("%s: missing rq in cdrom_decode_status\n", drive->name);
+		*startstop = ide_stopped;
 		return 1;
 	}
 
@@ -591,19 +694,16 @@
 		   from the drive (probably while trying
 		   to recover from a former error).  Just give up. */
 
-		/* FIXME --mdcki */
-		pc = (struct packet_command *) rq->special;
+		pc = (struct packet_command *) rq->buffer;
 		pc->stat = 1;
-		cdrom_end_request(drive, rq, 1);
-		*startstop = ata_error(drive, rq, "request sense failure");
-
+		cdrom_end_request(drive, 1);
+		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
-	} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
+
+	} else if (rq->flags & REQ_PC) {
 		/* All other functions, except for READ. */
 		struct completion *wait = NULL;
-
-		/* FIXME --mdcki */
-		pc = (struct packet_command *) rq->special;
+		pc = (struct packet_command *) rq->buffer;
 
 		/* Check for tray open. */
 		if (sense_key == NOT_READY) {
@@ -615,30 +715,27 @@
 			return 0;
 		} else if (!pc->quiet) {
 			/* Otherwise, print an error. */
-			ata_dump(drive, rq, "packet command error");
+			ide_dump_status(drive, "packet command error", stat);
 		}
-
+		
 		/* Set the error flag and complete the request.
-		   Then, if we have a CHECK CONDITION status, queue a request
-		   sense command.  We must be careful, though: we don't want
-		   the thread in cdrom_queue_packet_command to wake up until
-		   the request sense has completed.  We do this by transferring
-		   the semaphore from the packet command request to the request
-		   sense request. */
+		   Then, if we have a CHECK CONDITION status,
+		   queue a request sense command.  We must be careful,
+		   though: we don't want the thread in
+		   cdrom_queue_packet_command to wake up until
+		   the request sense has completed.  We do this
+		   by transferring the semaphore from the packet
+		   command request to the request sense request. */
 
-		if (drive->status & ERR_STAT) {
+		if ((stat & ERR_STAT) != 0) {
 			wait = rq->waiting;
 			rq->waiting = NULL;
 		}
 
 		pc->stat = 1;
-		cdrom_end_request(drive, rq, 1);
+		cdrom_end_request(drive, 1);
 
-		/* FIXME: this is the only place where pc->sense get's used.
-		 * Think hard about how to get rid of it...
-		 */
-
-		if (drive->status & ERR_STAT)
+		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
 	} else if (rq->flags & REQ_CMD) {
 		/* Handle errors from READ and WRITE requests. */
@@ -649,7 +746,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request(drive, rq, 0);
+			cdrom_end_request(drive, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -658,61 +755,58 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request(drive, rq, 0);
+				cdrom_end_request(drive, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
-			ata_dump(drive, rq, "command error");
-			cdrom_end_request(drive, rq,  0);
-		} else if (sense_key == MEDIUM_ERROR) {
-			/* No point in re-trying a zillion times on a bad
-			 * sector.  The error is not correctable at all.
-			 */
-			ata_dump(drive, rq, "media error (bad sector)");
-			cdrom_end_request(drive, rq, 0);
+			ide_dump_status (drive, "command error", stat);
+			cdrom_end_request(drive, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ata_error(drive, rq, __FUNCTION__);
+			*startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
 			return 1;
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
-			cdrom_end_request(drive, rq, 0);
+			cdrom_end_request(drive, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
 		   queue a request sense command. */
-		if (drive->status & ERR_STAT)
+		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, NULL, NULL, NULL);
 	} else
 		blk_dump_rq_flags(rq, "ide-cd bad flags");
 
 	/* Retry, or handle the next request. */
-	*startstop = ATA_OP_FINISHED;
+	*startstop = ide_stopped;
 	return 1;
 }
 
-static ide_startstop_t cdrom_timer_expiry(struct ata_device *drive, struct request *rq, unsigned long *wait)
+static int cdrom_timer_expiry(ide_drive_t *drive)
 {
+	struct request *rq = HWGROUP(drive)->rq;
+	struct packet_command *pc = (struct packet_command *) rq->buffer;
+	unsigned long wait = 0;
+
 	/*
 	 * Some commands are *slow* and normally take a long time to
 	 * complete. Usually we can use the ATAPI "disconnect" to bypass
 	 * this, but not all commands/drives support that. Let
 	 * ide_timer_expiry keep polling us for these.
 	 */
-	switch (rq->cmd[0]) {
+	switch (pc->c[0]) {
 		case GPCMD_BLANK:
 		case GPCMD_FORMAT_UNIT:
 		case GPCMD_RESERVE_RZONE_TRACK:
-			*wait = WAIT_CMD;
-			return ATA_OP_CONTINUES;
+			wait = WAIT_CMD;
+			break;
 		default:
-			*wait = 0;
+			wait = 0;
 			break;
 	}
-
-	return ATA_OP_FINISHED;
+	return wait;
 }
 
 /* Set up the device registers for transferring a packet command on DEV,
@@ -722,24 +816,25 @@
    called when the interrupt from the drive arrives.  Otherwise, HANDLER
    will be called immediately after the drive is prepared for the transfer. */
 
-static ide_startstop_t cdrom_start_packet_command(struct ata_device *drive,
-						  struct request *rq,
+static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
 						  int xferlen,
-						  ata_handler_t handler)
+						  ide_handler_t *handler)
 {
+	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
-	int ret;
 
 	/* Wait for the controller to be idle. */
-	ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_READY, rq);
-	if (ret != ATA_OP_READY)
-		return ret;
+	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+		return startstop;
 
 	if (info->dma) {
-		if (info->cmd == READ || info->cmd == WRITE)
-			info->dma = udma_init(drive, rq);
-		else
+		if (info->cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (info->cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
 			printk("ide-cd: DMA set, but not allowed\n");
+		}
 	}
 
 	/* Set up the controller registers. */
@@ -749,32 +844,40 @@
 
 	OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG);
 	OUT_BYTE(xferlen >> 8  , IDE_HCYL_REG);
-	ata_irq_enable(drive, 1);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+ 
 	if (info->dma)
-		udma_start(drive, rq);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ata_set_handler(drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		ret = ATA_OP_CONTINUES;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		ret = handler(drive, rq);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return (*handler) (drive);
 	}
-
-	return ret;
 }
 
+/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
+   The device registers must have already been prepared
+   by cdrom_start_packet_command.
+   HANDLER is the interrupt handler to call when the command completes
+   or there's data ready. */
 /*
- * Send a packet command cmd to the drive.  The device registers must have
- * already been prepared by cdrom_start_packet_command.  "handler" is the
- * interrupt handler to call when the command completes or there's data ready.
+ * changed 5 parameters to 3 for dvd-ram
+ * struct packet_command *pc; now packet_command_t *pc;
  */
-static ide_startstop_t cdrom_transfer_packet_command(struct ata_device *drive,
-		struct request *rq,
-		unsigned char *cmd, unsigned long timeout,
-		ata_handler_t handler)
-{
+static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+					  struct packet_command *pc,
+					  ide_handler_t *handler)
+{
+	unsigned char *cmd_buf	= pc->c;
+	int cmd_len		= sizeof(pc->c);
+	unsigned int timeout	= pc->timeout;
 	ide_startstop_t startstop;
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
@@ -783,21 +886,23 @@
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status(&startstop, drive, rq, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
-		startstop = ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq);
-		if (startstop != ATA_OP_READY)
+		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
-	/* Arm the interrupt handler and send the command to the device. */
-	ata_set_handler(drive, handler, timeout, cdrom_timer_expiry);
-	atapi_write(drive, cmd, CDROM_PACKET_SIZE);
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
+	/* Arm the interrupt handler. */
+	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
 
-	return ATA_OP_CONTINUES;
+	/* Send the command to the device. */
+	atapi_output_bytes (drive, cmd_buf, cmd_len);
+	return ide_started;
 }
 
 /****************************************************************************
@@ -811,7 +916,7 @@
  * sector added, SECTOR is its sector number.  (SECTOR is then ignored until
  * the buffer is cleared.)
  */
-static void cdrom_buffer_sectors(struct ata_device *drive, unsigned long sector,
+static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
                                   int sectors_to_transfer)
 {
 	struct cdrom_info *info = drive->driver_data;
@@ -834,7 +939,7 @@
 	/* Read the data into the buffer. */
 	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
-		atapi_read(drive, dest, SECTOR_SIZE);
+		atapi_input_bytes (drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
 		--sectors_to_transfer;
 		++info->nsectors_buffered;
@@ -844,7 +949,7 @@
 	/* Throw away any remaining data. */
 	while (sectors_to_transfer > 0) {
 		char dum[SECTOR_SIZE];
-		atapi_read(drive, dum, sizeof (dum));
+		atapi_input_bytes (drive, dum, sizeof (dum));
 		--sectors_to_transfer;
 	}
 }
@@ -855,7 +960,7 @@
  * ok; nonzero if the request has been terminated.
  */
 static inline
-int cdrom_read_check_ireason(struct ata_device *drive, struct request *rq, int len, int ireason)
+int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 {
 	ireason &= 3;
 	if (ireason == 2) return 0;
@@ -869,16 +974,15 @@
 		/* Throw some data at the drive so it doesn't hang
 		   and quit this request. */
 		while (len > 0) {
-			u8 dummy[4];
-
-			atapi_write(drive, dummy, sizeof(dummy));
-			len -= sizeof(dummy);
+			int dum = 0;
+			atapi_output_bytes (drive, &dum, sizeof (dum));
+			len -= sizeof (dum);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
 		 * info is available. just get it and ignore.
 		 */
-		ata_status(drive, 0, 0);
+		GET_STAT();
 		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -886,60 +990,64 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(drive, rq, 0);
+	cdrom_end_request(drive, 0);
 	return -1;
 }
 
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
-static ide_startstop_t cdrom_read_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
 {
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
-	int dma = info->dma, dma_error = 0;
+	int i, dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
+	struct request *rq = HWGROUP(drive)->rq;
+
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = udma_stop(drive)))
-			udma_enable(drive, 0, 1);
+		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
+			HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 
-	if (cdrom_decode_status(&startstop, drive, rq, 0, &stat))
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
 		return startstop;
-
+ 
 	if (dma) {
 		if (!dma_error) {
-			ata_end_request(drive, rq, 1, rq->nr_sectors);
-
-			return ATA_OP_FINISHED;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				ide_cdrom_end_request(drive, 1);
+			}
+			return ide_stopped;
 		} else
-			return ata_error(drive, rq, "dma error");
+			return DRIVER(drive)->error(drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = IN_BYTE(IDE_NSECTOR_REG);
+	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
 		/* If we're not done filling the current buffer, complain.
 		   Otherwise, complete the command normally. */
 		if (rq->current_nr_sectors > 0) {
-			printk ("%s: cdrom_read_intr: data underrun (%u blocks)\n",
+			printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request(drive, rq, 0);
+			cdrom_end_request(drive, 0);
 		} else
-			cdrom_end_request(drive, rq, 1);
-		return ATA_OP_FINISHED;
+			cdrom_end_request(drive, 1);
+		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
-	if (cdrom_read_check_ireason(drive, rq, len, ireason))
-		return ATA_OP_FINISHED;
+	if (cdrom_read_check_ireason (drive, len, ireason))
+		return ide_stopped;
 
 	/* Assume that the drive will always provide data in multiples
 	   of at least SECTOR_SIZE, as it gets hairy to keep track
@@ -953,8 +1061,8 @@
 			printk ("  Trying to limit transfer sizes\n");
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		}
-		cdrom_end_request(drive, rq, 0);
-		return ATA_OP_FINISHED;
+		cdrom_end_request(drive, 0);
+		return ide_stopped;
 	}
 
 	/* The number of sectors we need to read from the drive. */
@@ -967,7 +1075,7 @@
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
 		char dum[SECTOR_SIZE];
-		atapi_read(drive, dum, SECTOR_SIZE);
+		atapi_input_bytes (drive, dum, sizeof (dum));
 
 		--rq->current_nr_sectors;
 		--nskip;
@@ -981,7 +1089,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request(drive, rq, 1);
+			cdrom_end_request(drive, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -998,7 +1106,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_read(drive, rq->buffer, SECTOR_SIZE);
+				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -1009,19 +1117,22 @@
 		}
 	}
 
-	/* Done moving data! Wait for another interrupt. */
-	ata_set_handler(drive, cdrom_read_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
+		BUG();
 
-	return ATA_OP_CONTINUES;
+	/* Done moving data!  Wait for another interrupt. */
+	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+	return ide_started;
 }
 
 /*
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
  */
-static int cdrom_read_from_buffer(struct ata_device *drive, struct request *rq)
+static int cdrom_read_from_buffer (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
 
 	/* Can't do anything if there's no buffer. */
 	if (info->buffer == NULL) return 0;
@@ -1032,7 +1143,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request(drive, rq, 1);
+			cdrom_end_request(drive, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1047,13 +1158,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request(drive, rq, 1);
+		cdrom_end_request(drive, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request(drive, rq, 1);
+		cdrom_end_request(drive, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1061,9 +1172,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < bio_sectors(rq->bio) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: %s: buffer botch (%ld)\n",
-			drive->name, __FUNCTION__, rq->sector);
-		cdrom_end_request(drive, rq, 0);
+		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+			drive->name, rq->sector);
+		cdrom_end_request(drive, 0);
 		return -1;
 	}
 
@@ -1071,12 +1182,15 @@
 }
 
 /*
- * Routine to send a read packet command to the drive.  This is usually called
- * directly from cdrom_start_read.  However, for drq_interrupt devices, it is
- * called from an interrupt when the drive is ready to accept the command.
+ * Routine to send a read packet command to the drive.
+ * This is usually called directly from cdrom_start_read.
+ * However, for drq_interrupt devices, it is called from an interrupt
+ * when the drive is ready to accept the command.
  */
-static ide_startstop_t cdrom_start_read_continuation(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
 {
+	struct packet_command pc;
+	struct request *rq = HWGROUP(drive)->rq;
 	int nsect, sector, nframes, frame, nskip;
 
 	/* Number of sectors to transfer. */
@@ -1097,10 +1211,10 @@
 		/* Sanity check... */
 		if (rq->current_nr_sectors != bio_sectors(rq->bio) &&
 			(rq->sector % CD_FRAMESIZE != 0)) {
-			printk ("%s: %s: buffer botch (%u)\n",
-				drive->name, __FUNCTION__, rq->current_nr_sectors);
-			cdrom_end_request(drive, rq, 0);
-			return ATA_OP_FINISHED;
+			printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n",
+				drive->name, rq->current_nr_sectors);
+			cdrom_end_request(drive, 0);
+			return ide_stopped;
 		}
 		sector -= nskip;
 		nsect += nskip;
@@ -1114,11 +1228,15 @@
 
 	/* Largest number of frames was can transfer at once is 64k-1. For
 	   some drives we need to limit this even more. */
-	nframes = MIN(nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ?
+	nframes = MIN (nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ?
 		(65534 / CD_FRAMESIZE) : 65535);
 
+	/* Set up the command */
+	memcpy(pc.c, rq->cmd, sizeof(pc.c));
+	pc.timeout = WAIT_CMD;
+
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, rq, rq->cmd, WAIT_CMD, &cdrom_read_intr);
+	return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);
 }
 
 
@@ -1126,18 +1244,18 @@
 #define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
 #define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */
 
-static ide_startstop_t cdrom_seek_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int stat;
 	static int retry = 10;
 	ide_startstop_t startstop;
 
-	if (cdrom_decode_status (&startstop, drive, rq, 0, &stat))
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
-	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
+	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0) {
 			/*
 			 * this condition is far too common, to bother
@@ -1149,14 +1267,14 @@
 			drive->dsc_overlap = 0;
 		}
 	}
-	return ATA_OP_FINISHED;
+	return ide_stopped;
 }
 
-static ide_startstop_t cdrom_start_seek_continuation(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
 {
-	unsigned char cmd[CDROM_PACKET_SIZE];
-	sector_t sector;
-	int frame, nskip;
+	struct packet_command pc;
+	struct request *rq = HWGROUP(drive)->rq;
+	int sector, frame, nskip;
 
 	sector = rq->sector;
 	nskip = (sector % SECTORS_PER_FRAME);
@@ -1165,27 +1283,25 @@
 	frame = sector / SECTORS_PER_FRAME;
 
 	memset(rq->cmd, 0, sizeof(rq->cmd));
-	cmd[0] = GPCMD_SEEK;
-	put_unaligned(cpu_to_be32(frame), (unsigned int *) &cmd[2]);
+	pc.c[0] = GPCMD_SEEK;
+	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
 
-	return cdrom_transfer_packet_command(drive, rq, cmd, WAIT_CMD, &cdrom_seek_intr);
+	pc.timeout = WAIT_CMD;
+	return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);
 }
 
-static ide_startstop_t cdrom_start_seek(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command(drive, rq, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
 }
 
-/*
- * Fix up a possibly partially-processed request so that we can
- * start it over entirely -- remember to call prep_rq_fn again since we
- * may have changed the layout
- */
+/* Fix up a possibly partially-processed request so that we can
+   start it over entirely, or even put it back on the request queue. */
 static void restore_request (struct request *rq)
 {
 	if (rq->buffer != bio_data(rq->bio)) {
@@ -1203,15 +1319,18 @@
 /*
  * Start a read request from the CD-ROM.
  */
-static ide_startstop_t cdrom_start_read(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
 
+	/* We may be retrying this request after an error.  Fix up
+	   any weirdness which might be present in the request packet. */
 	restore_request(rq);
 
 	/* Satisfy whatever we can of this request from our cached sector. */
-	if (cdrom_read_from_buffer(drive, rq))
-		return ATA_OP_FINISHED;
+	if (cdrom_read_from_buffer(drive))
+		return ide_stopped;
 
 	blk_attempt_remerge(&drive->queue, rq);
 
@@ -1227,24 +1346,27 @@
 
 	info->cmd = READ;
 	/* Start sending the read request to the drive. */
-	return cdrom_start_packet_command(drive, rq, 32768, cdrom_start_read_continuation);
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
 
 /****************************************************************************
  * Execute all other packet commands.
  */
 
+/* Forward declarations. */
+static int cdrom_lockdoor(ide_drive_t *drive, int lockflag,
+			  struct request_sense *sense);
+
 /* Interrupt routine for packet command completion. */
-static ide_startstop_t cdrom_pc_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
 {
 	int ireason, len, stat, thislen;
-
-	/* FIXME --mdcki */
-	struct packet_command *pc = (struct packet_command *) rq->special;
+	struct request *rq = HWGROUP(drive)->rq;
+	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, rq, 0, &stat))
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
@@ -1256,7 +1378,7 @@
 	if ((stat & DRQ_STAT) == 0) {
 		/* Some of the trailing request sense fields are optional, and
 		   some drives don't send them.  Sigh. */
-		if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+		if (pc->c[0] == GPCMD_REQUEST_SENSE &&
 		    pc->buflen > 0 &&
 		    pc->buflen <= 5) {
 			while (pc->buflen > 0) {
@@ -1266,19 +1388,19 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request(drive, rq, 1);
+			cdrom_end_request(drive, 1);
 		else {
-			/* Comment this out, because this always happens
-			   right after a reset occurs, and it is annoying to
+			/* Comment this out, because this always happens 
+			   right after a reset occurs, and it is annoying to 
 			   always print expected stuff.  */
 			/*
 			printk ("%s: cdrom_pc_intr: data underrun %d\n",
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request(drive, rq, 1);
+			cdrom_end_request(drive, 1);
 		}
-		return ATA_OP_FINISHED;
+		return ide_stopped;
 	}
 
 	/* Figure out how much data to transfer. */
@@ -1288,15 +1410,14 @@
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
 		/* Transfer the data. */
-		atapi_write(drive, pc->buffer, thislen);
+		atapi_output_bytes (drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
-			u8 dummy[4];
-
-			atapi_write(drive, dummy, sizeof(dummy));
-			len -= sizeof(dummy);
+			int dum = 0;
+			atapi_output_bytes (drive, &dum, sizeof (dum));
+			len -= sizeof (dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1306,16 +1427,16 @@
 
 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
+
 		/* Transfer the data. */
-		atapi_read(drive, pc->buffer, thislen);
+		atapi_input_bytes (drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
-			u8 dummy[4];
-
-			atapi_read(drive, dummy, sizeof(dummy));
-			len -= sizeof(dummy);
+			int dum = 0;
+			atapi_input_bytes (drive, &dum, sizeof (dum));
+			len -= sizeof (dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1328,34 +1449,33 @@
 		pc->stat = 1;
 	}
 
-	/* Now we wait for another interrupt. */
-	ata_set_handler(drive, cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 
-	return ATA_OP_CONTINUES;
+	/* Now we wait for another interrupt. */
+	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	return ide_started;
 }
 
-static ide_startstop_t cdrom_do_pc_continuation(struct ata_device *drive, struct request *rq)
-{
-	unsigned long timeout;
 
-	/* FIXME --mdcki */
-	struct packet_command *pc = (struct packet_command *) rq->special;
+static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
-	if (pc->timeout)
-		timeout = pc->timeout;
-	else
-		timeout = WAIT_CMD;
+	if (!pc->timeout)
+		pc->timeout = WAIT_CMD;
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, rq, rq->cmd, timeout, &cdrom_pc_intr);
+	return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);
 }
 
-static ide_startstop_t cdrom_do_packet_command(struct ata_device *drive, struct request *rq)
+
+static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 {
 	int len;
-
-	/* FIXME --mdcki */
-	struct packet_command *pc = (struct packet_command *) rq->special;
+	struct request *rq = HWGROUP(drive)->rq;
+	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
@@ -1364,7 +1484,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, rq, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1382,42 +1502,33 @@
 }
 
 static
-int cdrom_queue_packet_command(struct ata_device *drive, unsigned char *cmd,
-		struct request_sense *sense, struct packet_command *pc)
+int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
 {
-	struct request rq;
+	struct request_sense sense;
+	struct request req;
 	int retries = 10;
 
+	if (pc->sense == NULL)
+		pc->sense = &sense;
+
 	/* Start of retry loop. */
 	do {
-		memset(&rq, 0, sizeof(rq));
-		memcpy(rq.cmd, cmd, CDROM_PACKET_SIZE);
-		rq.flags = REQ_PC;
-
-		/* FIXME --mdcki */
-		rq.special = (void *) pc;
-		if (ide_do_drive_cmd(drive, &rq, ide_wait)) {
-			printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",
-				drive->name, rq.buffer[0], rq.buffer[1]);
-
-			/* FIXME: we should probably abort/retry or something */
-			if (sense) {
-
-				/* Decode the error here at least for error
-				 * reporting to upper layers.!
-				 */
-
-			}
-		}
+		ide_init_drive_cmd (&req);
+		req.flags = REQ_PC;
+		req.buffer = (char *)pc;
+		ide_do_drive_cmd (drive, &req, ide_wait);
+		/* FIXME: we should probably abort/retry or something 
+		 * in case of failure */
 		if (pc->stat != 0) {
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
 			   (usually means media was changed). */
+			struct request_sense *reqbuf = pc->sense;
 
-			if (sense && sense->sense_key == UNIT_ATTENTION)
+			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change (drive);
-			else if (sense && sense->sense_key == NOT_READY &&
-				 sense->asc == 4 && sense->ascq != 4) {
+			else if (reqbuf->sense_key == NOT_READY &&
+				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
 				   a disk.  Retry, but wait a little to give
 				   the drive time to complete the load. */
@@ -1439,8 +1550,7 @@
 /*
  * Write handling
  */
-static inline int cdrom_write_check_ireason(struct ata_device *drive, struct request *rq,
-	int len, int ireason)
+static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
 {
 	/* Two notes about IDE interrupt reason here - 0 means that
 	 * the drive wants to receive data from us, 2 means that
@@ -1456,9 +1566,9 @@
 		/* Throw some data at the drive so it doesn't hang
 		   and quit this request. */
 		while (len > 0) {
-			u8 dummy[4];
-			atapi_write(drive, dummy, sizeof(dummy));
-			len -= sizeof(dummy);
+			int dum = 0;
+			atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -1466,41 +1576,46 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(drive, rq, 0);
+	cdrom_end_request(drive, 0);
 	return 1;
 }
 
-static ide_startstop_t cdrom_write_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
 {
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
-	int dma_error = 0, dma = info->dma;
+	int i, dma_error = 0, dma = info->dma;
 	ide_startstop_t startstop;
 
+	struct request *rq = HWGROUP(drive)->rq;
+
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = udma_stop(drive))) {
+		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
 			printk("ide-cd: write dma error\n");
-			udma_enable(drive, 0, 1);
+			HWIF(drive)->dmaproc(ide_dma_off, drive);
 		}
 	}
 
-	if (cdrom_decode_status(&startstop, drive, rq, 0, &stat)) {
+	if (cdrom_decode_status(&startstop, drive, 0, &stat)) {
 		printk("ide-cd: write_intr decode_status bad\n");
 		return startstop;
 	}
-
+ 
 	/*
 	 * using dma, transfer is complete now
 	 */
 	if (dma) {
 		if (dma_error)
-			return ata_error(drive, rq, "dma error");
-
-		ata_end_request(drive, rq, 1, rq->nr_sectors);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 
-		return ATA_OP_FINISHED;
+		rq = HWGROUP(drive)->rq;
+		for (i = rq->nr_sectors; i > 0;) {
+			i -= rq->current_nr_sectors;
+			ide_cdrom_end_request(drive, 1);
+		}
+		return ide_stopped;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
@@ -1514,18 +1629,18 @@
 		 */
 		uptodate = 1;
 		if (rq->current_nr_sectors > 0) {
-			printk("%s: write_intr: data underrun (%u blocks)\n",
+			printk("%s: write_intr: data underrun (%d blocks)\n",
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(drive, rq, uptodate);
-		return ATA_OP_FINISHED;
+		cdrom_end_request(drive, uptodate);
+		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
 	if (ireason & 3)
-		if (cdrom_write_check_ireason(drive, rq, len, ireason))
-			return ATA_OP_FINISHED;
+		if (cdrom_write_check_ireason(drive, len, ireason))
+			return ide_stopped;
 
 	sectors_to_transfer = len / SECTOR_SIZE;
 
@@ -1546,7 +1661,7 @@
 		this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);
 
 		while (this_transfer > 0) {
-			atapi_write(drive, rq->buffer, SECTOR_SIZE);
+			atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
 			rq->buffer += SECTOR_SIZE;
 			--rq->nr_sectors;
 			--rq->current_nr_sectors;
@@ -1559,21 +1674,36 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request(drive, rq, 1);
+			cdrom_end_request(drive, 1);
 	}
 
-	/* re-arm handler */
-	ata_set_handler(drive, cdrom_write_intr, 5 * WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 
-	return ATA_OP_CONTINUES;
+	/* re-arm handler */
+	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
+	return ide_started;
 }
 
-static ide_startstop_t cdrom_start_write_cont(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
 {
-	return cdrom_transfer_packet_command(drive, rq, rq->cmd, 2 * WAIT_CMD, cdrom_write_intr);
+	struct packet_command pc;	/* packet_command_t pc; */
+	struct request *rq = HWGROUP(drive)->rq;
+	unsigned nframes, frame;
+
+	nframes = rq->nr_sectors >> 2;
+	frame = rq->sector >> 2;
+
+	memcpy(pc.c, rq->cmd, sizeof(pc.c));
+#if 0	/* the immediate bit */
+	pc.c[1] = 1 << 3;
+#endif
+	pc.timeout = 2 * WAIT_CMD;
+
+	return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);
 }
 
-static ide_startstop_t cdrom_start_write(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
 
@@ -1581,8 +1711,8 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(drive, rq, 0);
-		return ATA_OP_FINISHED;
+		cdrom_end_request(drive, 0);
+		return ide_stopped;
 	}
 
 	/*
@@ -1601,77 +1731,75 @@
 	info->cmd = WRITE;
 
 	/* Start sending the read request to the drive. */
-	return cdrom_start_packet_command(drive, rq, 32768, cdrom_start_write_cont);
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
 }
 
-#define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
+static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
+{
+	struct packet_command pc;
+	ide_startstop_t startstop;
+
+	memset(&pc, 0, sizeof(pc));
+	memcpy(pc.c, rq->cmd, sizeof(pc.c));
+	pc.quiet = 1;
+	pc.timeout = 60 * HZ;
+	rq->buffer = (char *) &pc;
+
+	startstop = cdrom_do_packet_command(drive);
+	if (pc.stat)
+		rq->errors++;
+
+	return startstop;
+}
 
 /****************************************************************************
  * cdrom driver request routine.
  */
 static ide_startstop_t
-ide_cdrom_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	int ret;
+	ide_startstop_t action;
 	struct cdrom_info *info = drive->driver_data;
 
 	if (rq->flags & REQ_CMD) {
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-			if (ATA_OP_READY != ata_status_poll(drive, SEEK_STAT, 0, IDECD_SEEK_TIMEOUT, rq)) {
+			unsigned long elpased = jiffies - info->start_seek;
+			int stat = GET_STAT();
+
+			if ((stat & SEEK_STAT) != SEEK_STAT) {
+				if (elpased < IDECD_SEEK_TIMEOUT) {
+					ide_stall_queue(drive, IDECD_SEEK_TIMER);
+					return ide_stopped;
+				}
 				printk ("%s: DSC timeout\n", drive->name);
-				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
-			} else
-				return ATA_OP_FINISHED;
+			}
+			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 		}
 		if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
-			ret = cdrom_start_seek(drive, rq, block);
+			action = cdrom_start_seek(drive, block);
 		} else {
 			if (rq_data_dir(rq) == READ)
-				ret = cdrom_start_read(drive, rq, block);
+				action = cdrom_start_read(drive, block);
 			else
-				ret = cdrom_start_write(drive, rq);
+				action = cdrom_start_write(drive, rq);
 		}
 		info->last_block = block;
-		return ret;
+		return action;
 	} else if (rq->flags & (REQ_PC | REQ_SENSE)) {
-		ret = cdrom_do_packet_command(drive, rq);
-
-		return ret;
+		return cdrom_do_packet_command(drive);
 	} else if (rq->flags & REQ_SPECIAL) {
 		/*
-		 * FIXME: Kill REQ_SEPCIAL and replace it with commands queued
-		 * at the request queue instead as suggested by Linus.
-		 *
 		 * right now this can only be a reset...
 		 */
-
-		cdrom_end_request(drive, rq, 1);
-
-		return ATA_OP_FINISHED;
+		cdrom_end_request(drive, 1);
+		return ide_stopped;
 	} else if (rq->flags & REQ_BLOCK_PC) {
-		struct packet_command pc;
-		ide_startstop_t startstop;
-
-		memset(&pc, 0, sizeof(pc));
-		pc.quiet = 1;
-		pc.timeout = 60 * HZ;
-
-		/* FIXME --mdcki */
-		rq->special = (char *) &pc;
-
-		startstop = cdrom_do_packet_command(drive, rq);
-
-		if (pc.stat)
-			++rq->errors;
-
-		return startstop;
+		return cdrom_do_block_pc(drive, rq);
 	}
 
 	blk_dump_rq_flags(rq, "ide-cd bad flags");
-
-	cdrom_end_request(drive, rq, 0);
-
-	return ATA_OP_FINISHED;
+	cdrom_end_request(drive, 0);
+	return ide_stopped;
 }
 
 
@@ -1712,7 +1840,7 @@
 
 
 static inline
-void lba_to_msf(int lba, u8 *m, u8 *s, u8 *f)
+void lba_to_msf (int lba, byte *m, byte *s, byte *f)
 {
 	lba += CD_MSF_OFFSET;
 	lba &= 0xffffff;  /* negative lbas use only 24 bits */
@@ -1724,14 +1852,13 @@
 
 
 static inline
-int msf_to_lba(u8 m, u8 s, u8 f)
+int msf_to_lba (byte m, byte s, byte f)
 {
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
-static int cdrom_check_status(struct ata_device *drive, struct request_sense *sense)
+static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
@@ -1739,37 +1866,39 @@
 	memset(&pc, 0, sizeof(pc));
 	pc.sense = sense;
 
-	cmd[0] = GPCMD_TEST_UNIT_READY;
+	pc.c[0] = GPCMD_TEST_UNIT_READY;
 
-#if !STANDARD_ATAPI
-        /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
+#if ! STANDARD_ATAPI
+        /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
            switch CDs instead of supporting the LOAD_UNLOAD opcode   */
 
-        cmd[7] = cdi->sanyo_slot % 3;
-#endif
+        pc.c[7] = cdi->sanyo_slot % 3;
+#endif /* not STANDARD_ATAPI */
 
-	return cdrom_queue_packet_command(drive, cmd, sense, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
 static int
-cdrom_lockdoor(struct ata_device *drive, int lockflag, struct request_sense *sense)
+cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
 {
+	struct request_sense my_sense;
 	struct packet_command pc;
 	int stat;
 
+	if (sense == NULL)
+		sense = &my_sense;
+
 	/* If the drive cannot lock the door, just pretend. */
 	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
 	} else {
-		unsigned char cmd[CDROM_PACKET_SIZE];
-
 		memset(&pc, 0, sizeof(pc));
 		pc.sense = sense;
-		cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-		cmd[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command(drive, cmd, sense, &pc);
+		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+		pc.c[4] = lockflag ? 1 : 0;
+		stat = cdrom_queue_packet_command (drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1782,7 +1911,7 @@
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
 		stat = 0;
 	}
-
+	
 	/* no medium, that's alright. */
 	if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
 		stat = 0;
@@ -1796,15 +1925,14 @@
 
 /* Eject the disk if EJECTFLAG is 0.
    If EJECTFLAG is 1, try to reload the disk. */
-static int cdrom_eject(struct ata_device *drive, int ejectflag,
+static int cdrom_eject(ide_drive_t *drive, int ejectflag,
 		       struct request_sense *sense)
 {
 	struct packet_command pc;
-	unsigned char cmd[CDROM_PACKET_SIZE];
 
 	if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
 		return -EDRIVE_CANT_DO_THIS;
-
+	
 	/* reload fails on some drives, if the tray is locked */
 	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
 		return 0;
@@ -1812,12 +1940,12 @@
 	memset(&pc, 0, sizeof (pc));
 	pc.sense = sense;
 
-	cmd[0] = GPCMD_START_STOP_UNIT;
-	cmd[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command(drive, cmd, sense, &pc);
+	pc.c[0] = GPCMD_START_STOP_UNIT;
+	pc.c[4] = 0x02 + (ejectflag != 0);
+	return cdrom_queue_packet_command (drive, &pc);
 }
 
-static int cdrom_read_capacity(struct ata_device *drive, u32 *capacity,
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
 			       struct request_sense *sense)
 {
 	struct {
@@ -1826,27 +1954,26 @@
 	} capbuf;
 
 	int stat;
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
 	pc.sense = sense;
 
-	cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+	pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
 	pc.buffer = (char *)&capbuf;
 	pc.buflen = sizeof(capbuf);
-	stat = cdrom_queue_packet_command(drive, cmd, sense, &pc);
+
+	stat = cdrom_queue_packet_command(drive, &pc);
 	if (stat == 0)
 		*capacity = 1 + be32_to_cpu(capbuf.lba);
 
 	return stat;
 }
 
-static int cdrom_read_tocentry(struct ata_device *drive, int trackno, int msf_flag,
+static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
 				int format, char *buf, int buflen,
 				struct request_sense *sense)
 {
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
@@ -1855,21 +1982,21 @@
 	pc.buffer =  buf;
 	pc.buflen = buflen;
 	pc.quiet = 1;
+	pc.c[0] = GPCMD_READ_TOC_PMA_ATIP;
+	pc.c[6] = trackno;
+	pc.c[7] = (buflen >> 8);
+	pc.c[8] = (buflen & 0xff);
+	pc.c[9] = (format << 6);
 
-	cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
 	if (msf_flag)
-		cmd[1] = 2;
-	cmd[6] = trackno;
-	cmd[7] = (buflen >> 8);
-	cmd[8] = (buflen & 0xff);
-	cmd[9] = (format << 6);
+		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command(drive, cmd, sense, &pc);
+	return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 /* Try to read the entire TOC for the disk into our internal buffer. */
-static int cdrom_read_toc(struct ata_device *drive, struct request_sense *sense)
+static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 {
 	int stat, ntracks, i;
 	struct cdrom_info *info = drive->driver_data;
@@ -1893,7 +2020,7 @@
 
 	/* Check to see if the existing data is still valid.
 	   If it is, just return. */
-	cdrom_check_status(drive, sense);
+	(void) cdrom_check_status(drive, sense);
 
 	if (CDROM_STATE_FLAGS(drive)->toc_valid)
 		return 0;
@@ -1932,7 +2059,7 @@
 		   If we get an error for the regular case, we assume
 		   a CDI without additional audio tracks. In this case
 		   the readable TOC is empty (CDI tracks are not included)
-		   and only holds the Leadout entry. Heiko EiÃ^ßfeldt */
+		   and only holds the Leadout entry. Heiko Eißfeldt */
 		ntracks = 0;
 		stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
 					   (char *)&toc->hdr,
@@ -2005,8 +2132,7 @@
 	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
 	/* Now try to get the total cdrom capacity. */
-	/* FIXME: This is making worng assumptions about register layout. */
-	stat = cdrom_get_last_written(cdi, (unsigned long *) &toc->capacity);
+	stat = cdrom_get_last_written(cdi, (long *) &toc->capacity);
 	if (stat)
 		stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat)
@@ -2021,10 +2147,9 @@
 }
 
 
-static int cdrom_read_subchannel(struct ata_device *drive, int format, char *buf,
+static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
 				 int buflen, struct request_sense *sense)
 {
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
@@ -2032,22 +2157,20 @@
 
 	pc.buffer = buf;
 	pc.buflen = buflen;
-	cmd[0] = GPCMD_READ_SUBCHANNEL;
-	cmd[1] = 2;     /* MSF addressing */
-	cmd[2] = 0x40;  /* request subQ data */
-	cmd[3] = format;
-	cmd[7] = (buflen >> 8);
-	cmd[8] = (buflen & 0xff);
-
-	return cdrom_queue_packet_command(drive, cmd, sense, &pc);
+	pc.c[0] = GPCMD_READ_SUBCHANNEL;
+	pc.c[1] = 2;     /* MSF addressing */
+	pc.c[2] = 0x40;  /* request subQ data */
+	pc.c[3] = format;
+	pc.c[7] = (buflen >> 8);
+	pc.c[8] = (buflen & 0xff);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 /* ATAPI cdrom drives are free to select the speed you request or any slower
    rate :-( Requesting too fast a speed will _not_ produce an error. */
-static int cdrom_select_speed(struct ata_device *drive, int speed,
+static int cdrom_select_speed(ide_drive_t *drive, int speed,
 			      struct request_sense *sense)
 {
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 	memset(&pc, 0, sizeof(pc));
 	pc.sense = sense;
@@ -2057,40 +2180,39 @@
 	else
 		speed *= 177;   /* Nx to kbytes/s */
 
-	cmd[0] = GPCMD_SET_SPEED;
+	pc.c[0] = GPCMD_SET_SPEED;
 	/* Read Drive speed in kbytes/second MSB */
-	cmd[2] = (speed >> 8) & 0xff;
+	pc.c[2] = (speed >> 8) & 0xff;	
 	/* Read Drive speed in kbytes/second LSB */
-	cmd[3] = speed & 0xff;
+	pc.c[3] = speed & 0xff;
 	if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
 	    CDROM_CONFIG_FLAGS(drive)->cd_rw ||
 	    CDROM_CONFIG_FLAGS(drive)->dvd_r) {
 		/* Write Drive speed in kbytes/second MSB */
-		cmd[4] = (speed >> 8) & 0xff;
+		pc.c[4] = (speed >> 8) & 0xff;
 		/* Write Drive speed in kbytes/second LSB */
-		cmd[5] = speed & 0xff;
+		pc.c[5] = speed & 0xff;
        }
 
-	return cdrom_queue_packet_command(drive, cmd, sense, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
-static int cdrom_play_audio(struct ata_device *drive, int lba_start, int lba_end)
+static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
 {
 	struct request_sense sense;
-	unsigned char cmd[CDROM_PACKET_SIZE];
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof (pc));
 	pc.sense = &sense;
 
-	cmd[0] = GPCMD_PLAY_AUDIO_MSF;
-	lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]);
-	lba_to_msf(lba_end-1, &cmd[6], &cmd[7], &cmd[8]);
+	pc.c[0] = GPCMD_PLAY_AUDIO_MSF;
+	lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
+	lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
 
-	return cdrom_queue_packet_command(drive, cmd, &sense, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
-static int cdrom_get_toc_entry(struct ata_device *drive, int track,
+static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
 				struct atapi_toc_entry **ent)
 {
 	struct cdrom_info *info = drive->driver_data;
@@ -2122,7 +2244,7 @@
 			    struct cdrom_generic_command *cgc)
 {
 	struct packet_command pc;
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 	if (cgc->timeout <= 0)
 		cgc->timeout = WAIT_CMD;
@@ -2131,19 +2253,18 @@
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
 	memset(&pc, 0, sizeof(pc));
+	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
 	pc.quiet = cgc->quiet;
 	pc.timeout = cgc->timeout;
 	pc.sense = cgc->sense;
-	cgc->stat = cdrom_queue_packet_command(drive, cgc->cmd, cgc->sense, &pc);
+	cgc->stat = cdrom_queue_packet_command(drive, &pc);
 	if (!cgc->stat)
 		cgc->buflen -= pc.buflen;
-
 	return cgc->stat;
 }
 
-
 static
 int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
 			 unsigned int cmd, unsigned long arg)
@@ -2156,34 +2277,34 @@
 
 	/* These will be moved into the Uniform layer shortly... */
 	switch (cmd) {
-	case CDROMSETSPINDOWN: {
-		char spindown;
-
-		if (copy_from_user(&spindown, (void *) arg, sizeof(char)))
+ 	case CDROMSETSPINDOWN: {
+ 		char spindown;
+ 
+ 		if (copy_from_user(&spindown, (void *) arg, sizeof(char)))
 			return -EFAULT;
-
+ 
                 if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
 			return stat;
 
-		buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
-
-		return cdrom_mode_select(cdi, &cgc);
-	}
-
-	case CDROMGETSPINDOWN: {
-		char spindown;
+ 		buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
 
+ 		return cdrom_mode_select(cdi, &cgc);
+ 	} 
+ 
+ 	case CDROMGETSPINDOWN: {
+ 		char spindown;
+ 
                 if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
 			return stat;
-
-		spindown = buffer[11] & 0x0f;
-
+ 
+ 		spindown = buffer[11] & 0x0f;
+ 
 		if (copy_to_user((void *) arg, &spindown, sizeof (char)))
 			return -EFAULT;
-
-		return 0;
-	}
-
+ 
+ 		return 0;
+ 	}
+  
 	default:
 		return -EINVAL;
 	}
@@ -2193,8 +2314,9 @@
 static
 int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
 			   unsigned int cmd, void *arg)
+			   
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
 	int stat;
 
@@ -2270,12 +2392,12 @@
 static
 int ide_cdrom_reset (struct cdrom_device_info *cdi)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct request_sense sense;
 	struct request req;
 	int ret;
 
-	memset(&req, 0, sizeof(req));
+	ide_init_drive_cmd (&req);
 	req.flags = REQ_SPECIAL;
 	ret = ide_do_drive_cmd(drive, &req, ide_wait);
 
@@ -2284,40 +2406,37 @@
 	 * lock it again.
 	 */
 	if (CDROM_STATE_FLAGS(drive)->door_locked)
-		cdrom_lockdoor(drive, 1, &sense);
+		(void) cdrom_lockdoor(drive, 1, &sense);
 
 	return ret;
 }
 
 
 static
-int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
+int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct request_sense sense;
 
 	if (position) {
 		int stat = cdrom_lockdoor(drive, 0, &sense);
-		if (stat)
-			return stat;
+		if (stat) return stat;
 	}
 
 	return cdrom_eject(drive, !position, &sense);
 }
 
 static
-int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
+int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
-	struct request_sense sense;
-
-	return cdrom_lockdoor(drive, lock, &sense);
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	return cdrom_lockdoor(drive, lock, NULL);
 }
 
 static
 int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct request_sense sense;
 	int stat;
 
@@ -2331,7 +2450,7 @@
 static
 int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 	if (slot_nr == CDSL_CURRENT) {
 		struct request_sense sense;
@@ -2366,7 +2485,7 @@
 				struct cdrom_multisession *ms_info)
 {
 	struct atapi_toc *toc;
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
 	struct request_sense sense;
 	int ret;
@@ -2388,7 +2507,7 @@
 {
 	int stat;
 	char mcnbuf[24];
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 /* get MCN */
 	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
@@ -2412,11 +2531,11 @@
 int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
 				       int slot_nr)
 {
-	struct ata_device *drive = (struct ata_device *) cdi->handle;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	int retval;
-
+	
 	if (slot_nr == CDSL_CURRENT) {
-		cdrom_check_status(drive, NULL);
+		(void) cdrom_check_status(drive, NULL);
 		retval = CDROM_STATE_FLAGS (drive)->media_changed;
 		CDROM_STATE_FLAGS (drive)->media_changed = 0;
 		return retval;
@@ -2448,42 +2567,42 @@
  * Device initialization.
  */
 static struct cdrom_device_ops ide_cdrom_dops = {
-	.open =			ide_cdrom_open_real,
-	.release =		ide_cdrom_release_real,
-	.drive_status =		ide_cdrom_drive_status,
-	.media_changed =	ide_cdrom_check_media_change_real,
-	.tray_move =		ide_cdrom_tray_move,
-	.lock_door =		ide_cdrom_lock_door,
-	.select_speed =		ide_cdrom_select_speed,
-	.get_last_session =	ide_cdrom_get_last_session,
-	.get_mcn =		ide_cdrom_get_mcn,
-	.reset =		ide_cdrom_reset,
-	.audio_ioctl =		ide_cdrom_audio_ioctl,
-	.dev_ioctl =		ide_cdrom_dev_ioctl,
-	.capability =		CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
+	open:			ide_cdrom_open_real,
+	release:		ide_cdrom_release_real,
+	drive_status:		ide_cdrom_drive_status,
+	media_changed:		ide_cdrom_check_media_change_real,
+	tray_move:		ide_cdrom_tray_move,
+	lock_door:		ide_cdrom_lock_door,
+	select_speed:		ide_cdrom_select_speed,
+	get_last_session:	ide_cdrom_get_last_session,
+	get_mcn:		ide_cdrom_get_mcn,
+	reset:			ide_cdrom_reset,
+	audio_ioctl:		ide_cdrom_audio_ioctl,
+	dev_ioctl:		ide_cdrom_dev_ioctl,
+	capability:		CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
 				CDC_SELECT_SPEED | CDC_SELECT_DISC |
 				CDC_MULTI_SESSION | CDC_MCN |
 				CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
 				CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R |
 				CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
 				CDC_GENERIC_PACKET,
-	.generic_packet =	ide_cdrom_packet,
+	generic_packet:		ide_cdrom_packet,
 };
 
-static int ide_cdrom_register(struct ata_device *drive, int nslots)
+static int ide_cdrom_register (ide_drive_t *drive, int nslots)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = mk_kdev(drive->channel->major, minor);
+	devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
-	devinfo->capacity = nslots;
+	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	*(int *)&devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
-
+	
 	/* set capability mask to match the probe. */
 	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
 		devinfo->mask |= CDC_CD_R;
@@ -2502,13 +2621,8 @@
 	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
-	/* FIXME: I'm less that sure that this is the proper thing to do, since
-	 * ware already adding the devices to devfs int ide.c upon device
-	 * registration.
-	 */
-
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
-				     drive->channel->major, minor,
+				     HWIF(drive)->major, minor,
 				     S_IFBLK | S_IRUGO | S_IWUGO,
 				     ide_fops, NULL);
 
@@ -2516,7 +2630,7 @@
 }
 
 static
-int ide_cdrom_get_capabilities(struct ata_device *drive, struct atapi_capabilities_page *cap)
+int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
@@ -2539,7 +2653,7 @@
 	 * registered with the Uniform layer yet, it can't do this.
 	 * Same goes for cdi->ops.
 	 */
-	cdi->handle = (struct ata_device *) drive;
+	cdi->handle = (ide_drive_t *) drive;
 	cdi->ops = &ide_cdrom_dops;
 	init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN);
 	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
@@ -2551,7 +2665,7 @@
 }
 
 static
-int ide_cdrom_probe_capabilities(struct ata_device *drive)
+int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
@@ -2559,8 +2673,8 @@
 	int nslots = 1;
 
 	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
 		return nslots;
 	}
 
@@ -2592,7 +2706,9 @@
 	 * but they do support reading TOC & audio datas
 	 */
 	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0)
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
 		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
@@ -2613,14 +2729,14 @@
 
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
 	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  =
+		CDROM_STATE_FLAGS (drive)->current_speed  = 
 			(((unsigned int)cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed =
+		CDROM_CONFIG_FLAGS (drive)->max_speed = 
 			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  =
+		CDROM_STATE_FLAGS (drive)->current_speed  = 
 			(ntohs(cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed =
+		CDROM_CONFIG_FLAGS (drive)->max_speed = 
 			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
 
@@ -2632,31 +2748,35 @@
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
 	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-		printk (" DVD%s%s",
-		(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "",
-		(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw)
-		printk (" CD%s%s",
-		(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "",
-		(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->is_changer)
-		printk (" changer w/%d slots", nslots);
-        else
-		printk (" drive");
+        	printk (" DVD%s%s", 
+        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
+
+        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
+        	printk (" CD%s%s", 
+        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+
+        if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
+        	printk (" changer w/%d slots", nslots);
+        else 	
+        	printk (" drive");
 
 	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		udma_print(drive);
-#endif
+		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
 	return nslots;
 }
 
+static void ide_cdrom_add_settings(ide_drive_t *drive)
+{
+	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
+}
 
 /*
  * standard prep_rq_fn that builds 10 byte cmds
@@ -2698,7 +2818,8 @@
 	return 0;
 }
 
-static int ide_cdrom_setup(struct ata_device *drive)
+static
+int ide_cdrom_setup (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
@@ -2708,11 +2829,12 @@
 	/*
 	 * default to read-only always and fix latter at the bottom
 	 */
-	set_device_ro(mk_kdev(drive->channel->major, minor), 1);
+	set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
 	blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
 	blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
 
+	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
 	CDROM_STATE_FLAGS (drive)->media_changed = 1;
@@ -2742,7 +2864,7 @@
 	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
 	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
 	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
-
+	
 	/* limit transfer size per interrupt. */
 	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
 	if (drive->id != NULL) {
@@ -2777,12 +2899,16 @@
 			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
 			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
 			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-		} else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
+		}
+
+		else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
 		    drive->id->fw_rev[4] == '1' &&
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 600 ESD. */
 			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-		} else if (strcmp (drive->id->model,
+		}
+
+		else if (strcmp (drive->id->model,
 				 "NEC CD-ROM DRIVE:260") == 0 &&
 			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
 			/* Old NEC260 (not R).
@@ -2792,7 +2918,9 @@
 			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
 			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
 			CDROM_CONFIG_FLAGS (drive)->nec260         = 1;
-		} else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
+		}
+
+		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
 			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
 			/* Wearnes */
 			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
@@ -2823,26 +2951,28 @@
 	nslots = ide_cdrom_probe_capabilities (drive);
 
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-		set_device_ro(mk_kdev(drive->channel->major, minor), 0);
+		set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
 
 	if (ide_cdrom_register (drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
 		info->devinfo.handle = NULL;
 		return 1;
 	}
-
+	ide_cdrom_add_settings(drive);
 	return 0;
 }
 
 /* Forwarding functions to generic routines. */
-static int ide_cdrom_ioctl(struct ata_device *drive,
+static
+int ide_cdrom_ioctl (ide_drive_t *drive,
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	return cdrom_ioctl(inode, file, cmd, arg);
+	return cdrom_ioctl (inode, file, cmd, arg);
 }
 
-static int ide_cdrom_open (struct inode *ip, struct file *fp, struct ata_device *drive)
+static
+int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int rc = -ENOMEM;
@@ -2850,7 +2980,7 @@
 	MOD_INC_USE_COUNT;
 	if (info->buffer == NULL)
 		info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL);
-	if ((info->buffer == NULL) || (rc = cdrom_open(ip, fp))) {
+        if ((info->buffer == NULL) || (rc = cdrom_open(ip, fp))) {
 		drive->usage--;
 		MOD_DEC_USE_COUNT;
 	}
@@ -2859,29 +2989,36 @@
 
 static
 void ide_cdrom_release (struct inode *inode, struct file *file,
-			struct ata_device *drive)
+			ide_drive_t *drive)
 {
 	cdrom_release (inode, file);
 	MOD_DEC_USE_COUNT;
 }
 
 static
-int ide_cdrom_check_media_change(struct ata_device *drive)
+int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(mk_kdev (drive->channel->major,
+	return cdrom_media_changed(mk_kdev(HWIF (drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
 static
-void ide_cdrom_revalidate(struct ata_device *drive)
+void ide_cdrom_revalidate (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
+	int unit = drive - hwif->drives;
+	struct gendisk *g = hwif->gd[unit];
 	struct request_sense sense;
+
 	cdrom_read_toc(drive, &sense);
+	g->minor_shift = 0;
+	grok_partitions(mk_kdev(g->major, drive->select.b.unit), current_capacity(drive));
 }
 
-static sector_t ide_cdrom_capacity(struct ata_device *drive)
+static
+unsigned long ide_cdrom_capacity (ide_drive_t *drive)
 {
-	u32 capacity;
+	unsigned long capacity;
 
 	if (cdrom_read_capacity(drive, &capacity, NULL))
 		return 0;
@@ -2890,12 +3027,12 @@
 }
 
 static
-int ide_cdrom_cleanup(struct ata_device *drive)
+int ide_cdrom_cleanup(ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	if (ata_unregister_device(drive))
+	if (ide_unregister_subdriver (drive))
 		return 1;
 	if (info->buffer != NULL)
 		kfree(info->buffer);
@@ -2910,88 +3047,147 @@
 	return 0;
 }
 
-static void ide_cdrom_attach(struct ata_device *drive);
+int ide_cdrom_init(void);
+int ide_cdrom_reinit (ide_drive_t *drive);
 
-static struct ata_operations ide_cdrom_driver = {
-	.owner =		THIS_MODULE,
-	.attach =		ide_cdrom_attach,
-	.cleanup =		ide_cdrom_cleanup,
-	.standby =		NULL,
-	.do_request =		ide_cdrom_do_request,
-	.end_request =		NULL,
-	.ioctl =		ide_cdrom_ioctl,
-	.open =			ide_cdrom_open,
-	.release =		ide_cdrom_release,
-	.check_media_change =	ide_cdrom_check_media_change,
-	.revalidate =		ide_cdrom_revalidate,
-	.capacity =		ide_cdrom_capacity,
+static ide_driver_t ide_cdrom_driver = {
+	name:			"ide-cdrom",
+	version:		IDECD_VERSION,
+	media:			ide_cdrom,
+	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
+	supports_dma:		1,
+#endif
+	supports_dsc_overlap:	1,
+	cleanup:		ide_cdrom_cleanup,
+	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
+	flushcache:		NULL,
+	do_request:		ide_do_rw_cdrom,
+	end_request:		ide_cdrom_end_request,
+	sense:			ide_cdrom_dump_status,
+	error:			ide_cdrom_error,
+	ioctl:			ide_cdrom_ioctl,
+	open:			ide_cdrom_open,
+	release:		ide_cdrom_release,
+	media_change:		ide_cdrom_check_media_change,
+	revalidate:		ide_cdrom_revalidate,
+	pre_reset:		NULL,
+	capacity:		ide_cdrom_capacity,
+	special:		NULL,
+	proc:			NULL,
+	init:			ide_cdrom_init,
+	reinit:			ide_cdrom_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
+};
+
+static ide_module_t ide_cdrom_module = {
+	IDE_DRIVER_MODULE,
+	ide_cdrom_init,
+	&ide_cdrom_driver,
+	NULL
 };
 
 /* options */
-static char *ignore = NULL;
+char *ignore = NULL;
+
+MODULE_PARM(ignore, "s");
+MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static void ide_cdrom_attach(struct ata_device *drive)
+int ide_cdrom_reinit (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
-	char *req;
-	struct ata_channel *channel;
-	struct gendisk *disk;
-	int unit;
+	int failed = 0;
 
-	if (drive->type != ATA_ROM)
-		return;
-
-	req = drive->driver_req;
-	if (req[0] != '\0' && strcmp(req, "ide-cdrom"))
-		return;
-
-	/* skip drives that we were told to ignore */
-	if (ignore && !strcmp(ignore, drive->name)) {
-		printk(KERN_INFO "%s: ignored\n", drive->name);
-		return;
-	}
+	MOD_INC_USE_COUNT;
 	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
-	if (!info) {
-		printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
-		return;
+	if (info == NULL) {
+		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		return 1;
 	}
-	if (ata_register_device(drive, &ide_cdrom_driver)) {
-		printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name);
+	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
 		kfree (info);
-		return;
+		return 1;
 	}
-
-
-	memset(info, 0, sizeof (struct cdrom_info));
+	memset (info, 0, sizeof (struct cdrom_info));
 	drive->driver_data = info;
-
+	DRIVER(drive)->busy++;
 	if (ide_cdrom_setup (drive)) {
+		DRIVER(drive)->busy--;
 		if (ide_cdrom_cleanup (drive))
-			printk (KERN_ERR "%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
-		return;
+			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		return 1;
 	}
+	DRIVER(drive)->busy--;
+	failed--;
 
-	channel = drive->channel;
-	unit = drive - channel->drives;
-	disk = channel->gd[unit];
-	disk->minor_shift = 0;
-	ide_cdrom_revalidate(drive);
-	register_disk(disk, mk_kdev(disk->major, disk->first_minor),
-			1<<disk->minor_shift, disk->fops,
-			ide_cdrom_capacity(drive));
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
-MODULE_PARM(ignore, "s");
-MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
-
 static void __exit ide_cdrom_exit(void)
 {
-	unregister_ata_driver(&ide_cdrom_driver);
-}
+	ide_drive_t *drive;
+	int failed = 0;
 
+	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
+		if (ide_cdrom_cleanup (drive)) {
+			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+			failed++;
+		}
+	ide_unregister_module (&ide_cdrom_module);
+}
+ 
 int ide_cdrom_init(void)
 {
-	return ata_driver_module(&ide_cdrom_driver);
+	ide_drive_t *drive;
+	struct cdrom_info *info;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+		/* skip drives that we were told to ignore */
+		if (ignore != NULL) {
+			if (strstr(ignore, drive->name)) {
+				printk("ide-cd: ignoring drive %s\n", drive->name);
+				continue;
+			}
+		}
+		if (drive->scsi) {
+			printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+		if (info == NULL) {
+			printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+			printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (info);
+			continue;
+		}
+		memset (info, 0, sizeof (struct cdrom_info));
+		drive->driver_data = info;
+		DRIVER(drive)->busy++;
+		if (ide_cdrom_setup (drive)) {
+			DRIVER(drive)->busy--;
+			if (ide_cdrom_cleanup (drive))
+				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+			continue;
+		}
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 module_init(ide_cdrom_init);
diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
--- a/drivers/ide/ide-cd.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/ide-cd.h	Tue Aug 27 12:28:08 2002
@@ -15,7 +15,7 @@
    memory, though. */
 
 #ifndef VERBOSE_IDE_CD_ERRORS
-# define VERBOSE_IDE_CD_ERRORS 1
+#define VERBOSE_IDE_CD_ERRORS 1
 #endif
 
 
@@ -24,7 +24,7 @@
    this will give you a slightly smaller kernel. */
 
 #ifndef STANDARD_ATAPI
-# define STANDARD_ATAPI 0
+#define STANDARD_ATAPI 0
 #endif
 
 
@@ -32,14 +32,14 @@
    This is apparently needed for supermount. */
 
 #ifndef NO_DOOR_LOCKING
-# define NO_DOOR_LOCKING 0
+#define NO_DOOR_LOCKING 0
 #endif
 
 /************************************************************************/
 
-#define SECTOR_BITS		9
+#define SECTOR_BITS 		9
 #ifndef SECTOR_SIZE
-# define SECTOR_SIZE		(1 << SECTOR_BITS)
+#define SECTOR_SIZE		(1 << SECTOR_BITS)
 #endif
 #define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
@@ -50,6 +50,12 @@
 
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
+/* special command codes for strategy routine. */
+#define PACKET_COMMAND        4315
+#define REQUEST_SENSE_COMMAND 4316
+#define RESET_DRIVE_COMMAND   4317
+
+
 /* Configuration flags.  These describe the capabilities of the drive.
    They generally do not change after initialization, unless we learn
    more about the drive from stuff failing. */
@@ -80,10 +86,11 @@
 	__u8 close_tray		: 1; /* can close the tray */
 	__u8 writing		: 1; /* pseudo write in progress */
 	__u8 reserved		: 3;
-	u8 max_speed;		     /* Max speed of the drive */
+	byte max_speed;		     /* Max speed of the drive */
 };
 #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
 
+ 
 /* State flags.  These give information about the current state of the
    drive, and will change during normal operation. */
 struct ide_cd_state_flags {
@@ -92,7 +99,7 @@
 	__u8 door_locked   : 1; /* We think that the drive door is locked. */
 	__u8 writing       : 1; /* the drive is currently writing */
 	__u8 reserved      : 4;
-	u8 current_speed;	/* Current speed of the drive */
+	byte current_speed;	/* Current speed of the drive */
 };
 
 #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
@@ -104,35 +111,27 @@
 	int quiet;
 	int timeout;
 	struct request_sense *sense;
-
-	/* This is currently used to pass failed commands through the request
-	 * queue.  Is this for asynchronos error reporting?
-	 *
-	 * Can we always be sure that this didn't valish from stack beneath us
-	 * - we can't!
-	 */
-
-	struct packet_command *failed_command;
+	unsigned char c[12];
 };
 
 /* Structure of a MSF cdrom address. */
 struct atapi_msf {
-	u8 __reserved;
-	u8 minute;
-	u8 second;
-	u8 frame;
-} __attribute__((packed));
+	byte reserved;
+	byte minute;
+	byte second;
+	byte frame;
+};
 
 /* Space to hold the disk TOC. */
 #define MAX_TRACKS 99
 struct atapi_toc_header {
-	u16 toc_length;
-	u8 first_track;
-	u8 last_track;
-} __attribute__((packed));
+	unsigned short toc_length;
+	byte first_track;
+	byte last_track;
+};
 
 struct atapi_toc_entry {
-	u8 reserved1;
+	byte reserved1;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 adr     : 4;
 	__u8 control : 4;
@@ -142,8 +141,8 @@
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
-	u8 track;
-	u8 reserved2;
+	byte track;
+	byte reserved2;
 	union {
 		unsigned lba;
 		struct atapi_msf msf;
@@ -151,33 +150,34 @@
 };
 
 struct atapi_toc {
-	int last_session_lba;
-	int xa_flag;
-	u32 capacity;
+	int    last_session_lba;
+	int    xa_flag;
+	unsigned long capacity;
 	struct atapi_toc_header hdr;
-	struct atapi_toc_entry ent[MAX_TRACKS+1];  /* one extra for the leadout. */
+	struct atapi_toc_entry  ent[MAX_TRACKS+1];
+	  /* One extra for the leadout. */
 };
 
 
 /* This structure is annoyingly close to, but not identical with,
    the cdrom_subchnl structure from cdrom.h. */
 struct atapi_cdrom_subchnl {
-	u8	acdsc_reserved;
-	u8	acdsc_audiostatus;
-	u16	acdsc_length;
-	u8	acdsc_format;
+ 	u_char  acdsc_reserved;
+ 	u_char  acdsc_audiostatus;
+ 	u_short acdsc_length;
+	u_char  acdsc_format;
 
 #if defined(__BIG_ENDIAN_BITFIELD)
-	u8	acdsc_ctrl:     4;
-	u8	acdsc_adr:      4;
+	u_char  acdsc_ctrl:     4;
+	u_char  acdsc_adr:      4;
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-	u8	acdsc_adr:	4;
-	u8	acdsc_ctrl:	4;
+	u_char  acdsc_adr:	4;
+	u_char  acdsc_ctrl:	4;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
-	u8	acdsc_trk;
-	u8	acdsc_ind;
+	u_char  acdsc_trk;
+	u_char  acdsc_ind;
 	union {
 		struct atapi_msf msf;
 		int	lba;
@@ -207,7 +207,7 @@
 #error "Please fix <asm/byteorder.h>"
 #endif
 
-	u8 page_length;
+	byte     page_length;
 
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 reserved2           : 2;
@@ -435,9 +435,9 @@
 #error "Please fix <asm/byteorder.h>"
 #endif
 
-	u8 curlba[3];
-	u8 nslots;
-	__u16 slot_tablelen;
+	byte     curlba[3];
+	byte     nslots;
+	__u8 short slot_tablelen;
 };
 
 
@@ -454,7 +454,7 @@
 #error "Please fix <asm/byteorder.h>"
 #endif
 
-	u8 reserved2[3];
+	byte reserved2[3];
 };
 
 struct atapi_changer_info {
@@ -514,11 +514,13 @@
 #define ABORTED_COMMAND         0x0b
 #define MISCOMPARE              0x0e
 
+ 
+
 /* This stuff should be in cdrom.h, since it is now generic... */
 #if VERBOSE_IDE_CD_ERRORS
 
  /* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ 
 const struct {
 	unsigned short packet_command;
 	const char * const text;
diff -Nru a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
--- a/drivers/ide/ide-cs.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/ide-cs.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,5 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*======================================================================
+
     A driver for PCMCIA IDE/ATA disk cards
 
     ide_cs.c 1.26 1999/11/16 02:10:49
@@ -28,8 +28,8 @@
     and other provisions required by the GPL.  If you do not delete
     the provisions above, a recipient may use your version of this
     file under either the MPL or the GPL.
- *
- */
+    
+======================================================================*/
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -54,12 +54,12 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
 
-#define PCMCIA_DEBUG 100
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static const char *version = "ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+static char *version =
+"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -81,23 +81,23 @@
 /*====================================================================*/
 
 static const char ide_major[] = {
-	IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
 #ifdef IDE4_MAJOR
-	IDE4_MAJOR, IDE5_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
 #endif
 };
 
 typedef struct ide_info_t {
-	dev_link_t link;
-	int ndev;
-	dev_node_t node;
-	int hd;
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
 } ide_info_t;
 
-static void ide_config(dev_link_t * link);
+static void ide_config(dev_link_t *link);
 static void ide_release(u_long arg);
 static int ide_event(event_t event, int priority,
-		     event_callback_args_t * args);
+		     event_callback_args_t *args);
 
 static dev_info_t dev_info = "ide-cs";
 
@@ -110,11 +110,8 @@
 
 static void cs_error(client_handle_t handle, int func, int ret)
 {
-	error_info_t err = { func, ret };
-
-	DEBUG(0, "cs_error\n");
-
-	CardServices(ReportError, handle, &err);
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
 }
 
 /*======================================================================
@@ -127,58 +124,56 @@
 
 static dev_link_t *ide_attach(void)
 {
-	ide_info_t *info;
-	dev_link_t *link;
-	client_reg_t client_reg;
-	int i, ret;
-
-	DEBUG(0, "ide_attach\n");
-
-	/* Create new ide device */
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return NULL;
-	memset(info, 0, sizeof(*info));
-	link = &info->link;
-	link->priv = info;
-
-	link->release.function = &ide_release;
-	link->release.data = (u_long) link;
-	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-	link->io.IOAddrLines = 3;
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-	if (irq_list[0] == -1)
-		link->irq.IRQInfo2 = irq_mask;
-	else
-		for (i = 0; i < 4; i++)
-			link->irq.IRQInfo2 |= 1 << irq_list[i];
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-
-	/* Register with Card Services */
-	link->next = dev_list;
-	dev_list = link;
-	client_reg.dev_info = &dev_info;
-	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-	client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &ide_event;
-	client_reg.Version = 0x0210;
-	client_reg.event_callback_args.client_data = link;
-	ret = CardServices(RegisterClient, &link->handle, &client_reg);
-	if (ret != CS_SUCCESS) {
-		cs_error(link->handle, RegisterClient, ret);
-		ide_detach(link);
-		return NULL;
-	}
-
-	return link;
-}				/* ide_attach */
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ide_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
 
 /*======================================================================
 
@@ -189,35 +184,34 @@
 
 ======================================================================*/
 
-static void ide_detach(dev_link_t * link)
+static void ide_detach(dev_link_t *link)
 {
-	dev_link_t **linkp;
-	int ret;
-
-	DEBUG(0, "ide_detach(0x%p)\n", link);
-
-	/* Locate device structure */
-	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-		if (*linkp == link)
-			break;
-	if (*linkp == NULL)
-		return;
+    dev_link_t **linkp;
+    int ret;
 
-	del_timer(&link->release);
-	if (link->state & DEV_CONFIG)
-		ide_release((u_long) link);
-
-	if (link->handle) {
-		ret = CardServices(DeregisterClient, link->handle);
-		if (ret != CS_SUCCESS)
-			cs_error(link->handle, DeregisterClient, ret);
-	}
-
-	/* Unlink, free device structure */
-	*linkp = link->next;
-	kfree(link->priv);
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
 
-}				/* ide_detach */
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	ide_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* ide_detach */
 
 /*======================================================================
 
@@ -233,224 +227,198 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-int idecs_register(int arg1, int arg2, int irq)
+int idecs_register (int arg1, int arg2, int irq)
 {
-	hw_regs_t hw;
-
-	DEBUG(0, "idecs_register\n");
-
-	ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2,
-			    NULL);
-	hw.irq = irq;
-	hw.chipset = ide_pci;	/* this enables IRQ sharing w/ PCI irqs */
-
-	return ide_register_hw(&hw);
+        hw_regs_t hw;
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+        hw.irq = irq;
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
+        return ide_register_hw(&hw, NULL);
 }
 
-void ide_config(dev_link_t * link)
+void ide_config(dev_link_t *link)
 {
-	client_handle_t handle = link->handle;
-	ide_info_t *info = link->priv;
-	tuple_t tuple;
-	u_short buf[128];
-	cisparse_t parse;
-	config_info_t conf;
-	cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-	cistpl_cftable_entry_t dflt = { 0 };
-	int i, pass, last_ret, last_fn, hd = -1, io_base, ctl_base;
-
-	DEBUG(0, "ide_config(0x%p)\n", link);
-
-	tuple.TupleData = (cisdata_t *) buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, handle, &tuple);
-	CS_CHECK(GetTupleData, handle, &tuple);
-	CS_CHECK(ParseTuple, handle, &tuple, &parse);
-	link->conf.ConfigBase = parse.config.base;
-	link->conf.Present = parse.config.rmask[0];
-
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
-	/* Not sure if this is right... look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo, handle, &conf);
-	link->conf.Vcc = conf.Vcc;
-
-	pass = io_base = ctl_base = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	tuple.Attributes = 0;
-	CS_CHECK(GetFirstTuple, handle, &tuple);
-	while (1) {
-		CFG_CHECK(GetTupleData, handle, &tuple);
-		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-		/* Check for matching Vcc, unless we're desperate */
-		if (!pass) {
-			if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-				if (conf.Vcc !=
-				    cfg->vcc.param[CISTPL_POWER_VNOM] /
-				    10000)
-					goto next_entry;
-			} else if (dflt.vcc.
-				   present & (1 << CISTPL_POWER_VNOM)) {
-				if (conf.Vcc !=
-				    dflt.vcc.param[CISTPL_POWER_VNOM] /
-				    10000)
-					goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
-			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
-			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io =
-			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->conf.ConfigIndex = cfg->index;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.IOAddrLines =
-			    io->flags & CISTPL_IO_LINES_MASK;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_8;
-			if (io->nwin == 2) {
-				link->io.NumPorts1 = 8;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = 1;
-				CFG_CHECK(RequestIO, link->handle,
-					  &link->io);
-				io_base = link->io.BasePort1;
-				ctl_base = link->io.BasePort2;
-			} else if ((io->nwin == 1)
-				   && (io->win[0].len >= 16)) {
-				link->io.NumPorts1 = io->win[0].len;
-				link->io.NumPorts2 = 0;
-				CFG_CHECK(RequestIO, link->handle,
-					  &link->io);
-				io_base = link->io.BasePort1;
-				ctl_base = link->io.BasePort1 + 0x0e;
-			} else
-				goto next_entry;
-			/* If we've got this far, we're done */
-			break;
-		}
-
-	      next_entry:
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		if (pass) {
-			CS_CHECK(GetNextTuple, handle, &tuple);
-		} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
-			CS_CHECK(GetFirstTuple, handle, &tuple);
-			memset(&dflt, 0, sizeof(dflt));
-			pass++;
-		}
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
 	}
-
-	CS_CHECK(RequestIRQ, handle, &link->irq);
-	CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-	/* deal with brain dead IDE resource management */
-	release_region(link->io.BasePort1, link->io.NumPorts1);
-	if (link->io.NumPorts2)
-		release_region(link->io.BasePort2, link->io.NumPorts2);
-
-	/* retry registration in case device is still spinning up */
-	for (i = 0; i < 10; i++) {
-		if (ctl_base)
-			outb(0x02, ctl_base);	/* Set nIEN = disable device interrupts */
-		hd = idecs_register(io_base, ctl_base,
-				    link->irq.AssignedIRQ);
-		if (hd >= 0)
-			break;
-		if (link->io.NumPorts1 == 0x20) {
-			if (ctl_base)
-				outb(0x02, ctl_base + 0x10);
-			hd = idecs_register(io_base + 0x10,
-					    ctl_base + 0x10,
-					    link->irq.AssignedIRQ);
-			if (hd >= 0) {
-				io_base += 0x10;
-				ctl_base += 0x10;
-				break;
-			}
-		}
-		__set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 10);
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
 	}
-
-	if (hd < 0) {
-		printk(KERN_NOTICE
-		       "ide_cs: ide_register() at 0x%03x & 0x%03x"
-		       ", irq %u failed\n", io_base, ctl_base,
-		       link->irq.AssignedIRQ);
-		goto failed;
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
 	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* retry registration in case device is still spinning up */
+    for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    OUT_BYTE(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (hd >= 0) break;
+	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		OUT_BYTE(0x02, ctl_base+0x10);
+	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
+			      link->irq.AssignedIRQ);
+	    if (hd >= 0) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release((u_long)link);
 
-	MOD_INC_USE_COUNT;
-	info->ndev = 1;
-	sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2));
-	info->node.major = ide_major[hd];
-	info->node.minor = 0;
-	info->hd = hd;
-	link->dev = &info->node;
-	printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	       info->node.dev_name, link->conf.Vcc / 10,
-	       link->conf.Vcc % 10, link->conf.Vpp1 / 10,
-	       link->conf.Vpp1 % 10);
-
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
-
-      cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
-      failed:
-	ide_release((u_long) link);
-
-}				/* ide_config */
+} /* ide_config */
 
 /*======================================================================
 
     After a card is removed, ide_release() will unregister the net
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
-
+    
 ======================================================================*/
 
 void ide_release(u_long arg)
 {
-	dev_link_t *link = (dev_link_t *) arg;
-	ide_info_t *info = link->priv;
-
-	DEBUG(0, "ide_release(0x%p)\n", link);
-
-	if (info->ndev) {
-		ide_unregister(&ide_hwifs[info->hd]);
-		MOD_DEC_USE_COUNT;
-	}
-
-	request_region(link->io.BasePort1, link->io.NumPorts1, "ide-cs");
-	if (link->io.NumPorts2)
-		request_region(link->io.BasePort2, link->io.NumPorts2,
-			       "ide-cs");
-
-	info->ndev = 0;
-	link->dev = NULL;
-
-	CardServices(ReleaseConfiguration, link->handle);
-	CardServices(ReleaseIO, link->handle, &link->io);
-	CardServices(ReleaseIRQ, link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
+    dev_link_t *link = (dev_link_t *)arg;
+    ide_info_t *info = link->priv;
+    
+    DEBUG(0, "ide_release(0x%p)\n", link);
+
+    if (info->ndev) {
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+
+    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+    if (link->io.NumPorts2)
+	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+    
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
 
-}				/* ide_release */
+} /* ide_release */
 
 /*======================================================================
 
@@ -458,67 +426,66 @@
     stuff to run after an event is received.  A CARD_REMOVAL event
     also sets some flags to discourage the ide drivers from
     talking to the ports.
-
+    
 ======================================================================*/
 
-int ide_event(event_t event, int priority, event_callback_args_t * args)
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
 {
-	dev_link_t *link = args->client_data;
-
-	DEBUG(1, "ide_event(0x%06x)\n", event);
+    dev_link_t *link = args->client_data;
 
-	switch (event) {
-	case CS_EVENT_CARD_REMOVAL:
-		link->state &= ~DEV_PRESENT;
-		if (link->state & DEV_CONFIG)
-			mod_timer(&link->release, jiffies + HZ / 20);
-		break;
-	case CS_EVENT_CARD_INSERTION:
-		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-		ide_config(link);
-		break;
-	case CS_EVENT_PM_SUSPEND:
-		link->state |= DEV_SUSPEND;
-		/* Fall through... */
-	case CS_EVENT_RESET_PHYSICAL:
-		if (link->state & DEV_CONFIG)
-			CardServices(ReleaseConfiguration, link->handle);
-		break;
-	case CS_EVENT_PM_RESUME:
-		link->state &= ~DEV_SUSPEND;
-		/* Fall through... */
-	case CS_EVENT_CARD_RESET:
-		if (DEV_OK(link))
-			CardServices(RequestConfiguration, link->handle,
-				     &link->conf);
-		break;
-	}
-	return 0;
-}				/* ide_event */
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
 
 /*====================================================================*/
 
 static int __init init_ide_cs(void)
 {
-	servinfo_t serv;
-	DEBUG(0, "%s\n", version);
-	CardServices(GetCardServicesInfo, &serv);
-	if (serv.Revision != CS_RELEASE_CODE) {
-		printk(KERN_NOTICE "ide_cs: Card Services release "
-		       "does not match!\n");
-		return -1;
-	}
-	register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-
-	return 0;
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
 }
 
 static void __exit exit_ide_cs(void)
 {
-	DEBUG(0, "ide_cs: unloading\n");
-	unregister_pccard_driver(&dev_info);
-	while (dev_list != NULL)
-		ide_detach(dev_list);
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
 }
 
 module_init(init_ide_cs);
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/ide/ide-disk.c	Tue Aug 27 12:28:08 2002
@@ -1,16 +1,49 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ *  linux/drivers/ide/ide-disk.c	Version 1.16	April 7, 2002
+ *
+ *  Copyright (C) 1998-2002  Linux ATA Developemt
+ *				Andre Hedrick <andre@linux-ide.org>
+ *
  *
- *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *                and Andre Hedrick <andre@linux-ide.org>
  *
- *	Mark Lord	<mlord@pobox.com>
- *	Gadi Oxman	<gadio@netvision.net.il>
- *	Andre Hedrick	<andre@linux-ide.org>
- *	Jens Axboe	<axboe@suse.de>
- *	Marcin Dalecki	<martin@dalecki.de>
+ * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
  *
- * This is the ATA disk device driver, as evolved from hd.c and ide.c.
+ * Version 1.00		move disk only code from ide.c to ide-disk.c
+ *			support optional byte-swapping of all data
+ * Version 1.01		fix previous byte-swapping code
+ * Version 1.02		remove ", LBA" from drive identification msgs
+ * Version 1.03		fix display of id->buf_size for big-endian
+ * Version 1.04		add /proc configurable settings and S.M.A.R.T support
+ * Version 1.05		add capacity support for ATA3 >= 8GB
+ * Version 1.06		get boot-up messages to show full cyl count
+ * Version 1.07		disable door-locking if it fails
+ * Version 1.08		fixed CHS/LBA translations for ATA4 > 8GB,
+ *			process of adding new ATA4 compliance.
+ *			fixed problems in allowing fdisk to see
+ *			the entire disk.
+ * Version 1.09		added increment of rq->sector in ide_multwrite
+ *			added UDMA 3/4 reporting
+ * Version 1.10		request queue changes, Ultra DMA 100
+ * Version 1.11		added 48-bit lba
+ * Version 1.12		adding taskfile io access method
+ * Version 1.13		added standby and flush-cache for notifier
+ * Version 1.14		added acoustic-wcache
+ * Version 1.15		convert all calls to ide_raw_taskfile
+ *				since args will return register content.
+ * Version 1.16		added suspend-resume-checkpower
  */
 
+#define IDEDISK_VERSION	"1.16"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -24,9 +57,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/buffer_head.h>		/* for invalidate_bdev() */
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/suspend.h>
+#include <linux/buffer_head.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -34,31 +67,24 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-# define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
+#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
 #else
-# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
 
-/*
- * for now, taskfile requests are special :/
- */
-static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
-{
-	if (rq->bio)
-		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
-	else
-		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
-}
+static int driver_blocked;
 
-static inline void ide_unmap_rq(struct request *rq, char *to,
-				unsigned long *flags)
+static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	if (rq->bio)
-		bio_kunmap_irq(to, flags);
+	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
 }
 
+static int idedisk_end_request(ide_drive_t *drive, int uptodate);
+
 /*
- * Perform a sanity check on the claimed "lba_capacity"
+ * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
  *
  * Returns:	1 if lba_capacity looks sensible
@@ -66,7 +92,7 @@
  *
  * It is called only once for each drive.
  */
-static int lba_capacity_is_ok(struct hd_driveid *id)
+static int lba_capacity_is_ok (struct hd_driveid *id)
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 
@@ -107,944 +133,1395 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
+#ifndef CONFIG_IDE_TASKFILE_IO
+
 /*
- * Handler for command with PIO data-in phase.
+ * read_intr() is the handler for disk read/multread interrupts
  */
-static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t read_intr (ide_drive_t *drive)
 {
-	int ret;
-
-	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT | DRQ_STAT))
-			return ata_error(drive, rq, __FUNCTION__);
-
-		/* no data yet, so wait for another interrupt */
-		ata_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
-
-		ret = ATA_OP_CONTINUES;
-	} else {
-		//	printk("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
-		{
-			unsigned long flags;
-			char *buf;
-
-			buf = ide_map_rq(rq, &flags);
-			ata_read(drive, buf, SECTOR_WORDS);
-			ide_unmap_rq(rq, buf, &flags);
-		}
-
-		/* First segment of the request is complete. note that this does not
-		 * necessarily mean that the entire request is done!! this is only true
-		 * if ata_end_request() returns 0.
-		 */
-		rq->errors = 0;
-		--rq->current_nr_sectors;
-
-		if (rq->current_nr_sectors <= 0) {
-			if (!ata_end_request(drive, rq, 1, 0)) {
-			//		printk("Request Ended stat: %02x\n", drive->status);
-
-				return ATA_OP_FINISHED;
-			}
+	byte stat;
+	int i;
+	unsigned int msect, nsect;
+	struct request *rq;
+	unsigned long flags;
+	char *to;
+
+	/* new way for dealing with premature shared PCI interrupts */
+	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return DRIVER(drive)->error(drive, "read_intr", stat);
 		}
-
-		/* still data left to transfer */
-		ata_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);
-
-		ret = ATA_OP_CONTINUES;
+		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+	msect = drive->mult_count;
+	
+read_next:
+	rq = HWGROUP(drive)->rq;
+	if (msect) {
+		if ((nsect = rq->current_nr_sectors) > msect)
+			nsect = msect;
+		msect -= nsect;
+	} else
+		nsect = 1;
+	to = ide_map_buffer(rq, &flags);
+	taskfile_input_data(drive, to, nsect * SECTOR_WORDS);
+#ifdef DEBUG
+	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
+		drive->name, rq->sector, rq->sector+nsect-1,
+		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
+#endif
+	ide_unmap_buffer(to, &flags);
+	rq->sector += nsect;
+	rq->errors = 0;
+	i = (rq->nr_sectors -= nsect);
+	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
+		idedisk_end_request(drive, 1);
+	/*
+	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
+	 * If passed back up on multimode read, BAD DATA could be ACKED
+	 * to FILE SYSTEMS above ...
+	 */
+	if (i > 0) {
+		if (msect)
+			goto read_next;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+                return ide_started;
 	}
-
-	return ret;
+        return ide_stopped;
 }
 
 /*
- * Handler for command with PIO data-out phase.
+ * write_intr() is the handler for disk write interrupts
  */
-static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t write_intr (ide_drive_t *drive)
 {
-	int ret;
-
-	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
-		return ata_error(drive, rq, __FUNCTION__);
-
-	if (!rq->current_nr_sectors && !ata_end_request(drive, rq, 1, 0)) {
-		ret = ATA_OP_FINISHED;
-	} else {
-		if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
-			unsigned long flags;
-			char *buf;
-
-//			printk("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
-			buf = ide_map_rq(rq, &flags);
-			ata_write(drive, buf, SECTOR_WORDS);
-			ide_unmap_rq(rq, buf, &flags);
+	byte stat;
+	int i;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
 
+	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+        } else {
+#ifdef DEBUG
+		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
+			drive->name, rq->sector, (unsigned long) rq->buffer,
+			rq->nr_sectors-1);
+#endif
+		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
+			rq->sector++;
 			rq->errors = 0;
+			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
+			if (((long)rq->current_nr_sectors) <= 0)
+				idedisk_end_request(drive, 1);
+			if (i > 0) {
+				unsigned long flags;
+				char *to = ide_map_buffer(rq, &flags);
+				taskfile_output_data(drive, to, SECTOR_WORDS);
+				ide_unmap_buffer(to, &flags);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+                                return ide_started;
+			}
+                        return ide_stopped;
 		}
-		ata_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
-
-		ret = ATA_OP_CONTINUES;
+		return ide_stopped;	/* the original code did this here (?) */
 	}
-
-	return ret;
+	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
 
 /*
- * Handler for command with Read Multiple
+ * ide_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ *
+ * The update and return to BH is a BLOCK Layer Fakey to get more data
+ * to satisfy the hardware atomic segment.  If the hardware atomic segment
+ * is shorter or smaller than the BH segment then we should be OKAY.
+ * This is only valid if we can rewind the rq->current_nr_sectors counter.
  */
-static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
-	int ret;
-
-	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT | DRQ_STAT))
-			return ata_error(drive, rq, __FUNCTION__);
-
-		/* no data yet, so wait for another interrupt */
-		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
-
-		ret = ATA_OP_CONTINUES;
-	} else {
-		unsigned int msect;
+ 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
+ 	struct request	*rq = &hwgroup->wrq;
+ 
+  	do {
+  		char *buffer;
+  		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+ 
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct bio *bio = rq->bio;
 
-		/* (ks/hs): Fixed Multi-Sector transfer */
-		msect = drive->mult_count;
-
-		do {
-			unsigned int nsect;
-
-			nsect = rq->current_nr_sectors;
-			if (nsect > msect)
-				nsect = msect;
-
-#if 0
-			printk("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
-					buf, nsect, rq->current_nr_sectors);
-#endif
-			{
-				unsigned long flags;
-				char *buf;
-
-				buf = ide_map_rq(rq, &flags);
-				ata_read(drive, buf, nsect * SECTOR_WORDS);
-				ide_unmap_rq(rq, buf, &flags);
+			/*
+			 * only move to next bio, when we have processed
+			 * all bvecs in this one.
+			 */
+			if (++bio->bi_idx >= bio->bi_vcnt) {
+				bio->bi_idx = 0;
+				bio = bio->bi_next;
 			}
 
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-
-			/* FIXME: this seems buggy */
-			if (rq->current_nr_sectors <= 0) {
-				if (!ata_end_request(drive, rq, 1, 0))
-					return ATA_OP_FINISHED;
+			/* end early early we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
 			}
-			msect -= nsect;
-		} while (msect);
-
-		/* more data left */
-		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		}
 
-		ret = ATA_OP_CONTINUES;
-	}
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+		ide_unmap_buffer(buffer, &flags);
+	} while (mcount);
 
-	return ret;
+        return 0;
 }
 
-static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
+/*
+ * multwrite_intr() is the handler for disk multwrite interrupts
+ */
+static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
-	int ok;
-	int ret;
-
-	/*
-	 * FIXME: the drive->status checks here seem to be messy.
-	 *
-	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent in this chunk
-	 */
-
-	ok = ata_status(drive, DATA_READY, BAD_R_STAT);
-
-	if (!ok || !rq->nr_sectors) {
-		if (drive->status & (ERR_STAT | DRQ_STAT))
-			return ata_error(drive, rq, __FUNCTION__);
-	}
-	if (!rq->nr_sectors) {
-		ata_end_request(drive, rq, 1, rq->hard_nr_sectors);
-		rq->bio = NULL;
-		ret = ATA_OP_FINISHED;
-	} else if (!ok) {
-		/* not ready yet, so wait for next IRQ */
-		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-
-		ret = ATA_OP_CONTINUES;
-	} else {
-		int mcount = drive->mult_count;
-
-		/* prepare for next IRQ */
-		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-
-		do {
-			char *buf;
-			int nsect = rq->current_nr_sectors;
-			unsigned long flags;
+	byte stat;
+	int i;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
 
-			if (nsect > mcount)
-				nsect = mcount;
-			mcount -= nsect;
-
-			buf = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
-			rq->sector += nsect;
-			rq->nr_sectors -= nsect;
-			rq->current_nr_sectors -= nsect;
-
-			/* Do we move to the next bio after this? */
-			if (!rq->current_nr_sectors) {
-				/* remember to fix this up /jens */
-				struct bio *bio = rq->bio->bi_next;
-
-				/* end early if we ran out of requests */
-				if (!bio) {
-					mcount = 0;
-				} else {
-					rq->bio = bio;
-					rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
-				}
+	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+		if (stat & DRQ_STAT) {
+			/*
+			 *	The drive wants data. Remember rq is the copy
+			 *	of the request
+			 */
+			if (rq->nr_sectors) {
+				if (ide_multwrite(drive, drive->mult_count))
+					return ide_stopped;
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
+				return ide_started;
 			}
-			rq->errors = 0; /* FIXME: why?  --bzolnier */
-
+		} else {
 			/*
-			 * Ok, we're all setup for the interrupt re-entering us on the
-			 * last transfer.
+			 *	If the copy has all the blocks completed then
+			 *	we can end the original request.
 			 */
-			ata_write(drive, buf, nsect * SECTOR_WORDS);
-			bio_kunmap_irq(buf, &flags);
-		} while (mcount);
-
-		ret = ATA_OP_CONTINUES;
+			if (!rq->nr_sectors) {	/* all done? */
+				rq = hwgroup->rq;
+				for (i = rq->nr_sectors; i > 0;){
+					i -= rq->current_nr_sectors;
+					idedisk_end_request(drive, 1);
+				}
+				return ide_stopped;
+			}
+		}
+		return ide_stopped;	/* the original code did this here (?) */
 	}
-
-	return ret;
+	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
- * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
- * otherwise, to address sectors.  It also takes care of issuing special
- * DRIVE_CMDs.
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
  */
-static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	struct ata_taskfile args;
-	struct ata_taskfile *ar;
-	struct hd_driveid *id = drive->id;
-	u8 cmd;
-
-	/* Special drive commands don't need any kind of setup.
-	 */
-	if (rq->flags & REQ_SPECIAL) {
-		ar = rq->special;
-		cmd  = ar->cmd;
-	} else  {
-		unsigned int sectors;
-
-		/* FIXME: this check doesn't make sense */
-		if (!(rq->flags & REQ_CMD)) {
-			blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
-			ata_end_request(drive, rq, 0, 0);
-
-			return ATA_OP_FINISHED;
-		}
-
-		if (IS_PDC4030_DRIVE) {
-			extern ide_startstop_t promise_do_request(struct ata_device *, struct request *, sector_t);
-
-			return promise_do_request(drive, rq, block);
-		}
-
-		/*
-		 * start a tagged operation
-		 */
-		if (drive->using_tcq) {
-			int st = blk_queue_start_tag(&drive->queue, rq);
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "do_rw_disk - bad command");
+		idedisk_end_request(drive, 0);
+		return ide_stopped;
+	}
 
-			if (ata_pending_commands(drive) > drive->max_depth)
-				drive->max_depth = ata_pending_commands(drive);
-			if (ata_pending_commands(drive) > drive->max_last_depth)
-				drive->max_last_depth = ata_pending_commands(drive);
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+		return promise_rw_disk(drive, rq, block);
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
 
-			if (st) {
-				BUG_ON(!ata_pending_commands(drive));
+	if ((drive->id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1))		/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
 
-				return ATA_OP_CONTINUES;
-			}
-		}
-		ar = &args;
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
+}
 
-		memset(&args, 0, sizeof(args));
-		sectors = rq->nr_sectors;
-		/* Dispatch depending up on the drive access method. */
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			/* LBA 48 bit */
-			/*
-			 * 268435455  == 137439 MB or 28bit limit
-			 * 320173056  == 163929 MB or 48bit addressing
-			 * 1073741822 == 549756 MB or 48bit addressing fake drive
-			 */
-			if (sectors == 65536)
-				sectors = 0;
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
-			if (blk_rq_tagged(rq)) {
-				args.taskfile.feature = sectors;
-				args.hobfile.feature = sectors >> 8;
-				args.taskfile.sector_count = rq->tag << 3;
-			} else {
-				args.taskfile.sector_count = sectors;
-				args.hobfile.sector_count = sectors >> 8;
-			}
+#if 1
+	lba48bit = (drive->addressing == 1) ? 1 : 0;
+#endif
 
-			args.taskfile.sector_number = block;		/* low lba */
-			args.taskfile.low_cylinder = (block >>= 8);	/* mid lba */
-			args.taskfile.high_cylinder = (block >>= 8);	/* hi  lba */
-			args.taskfile.device_head = drive->select.all;
-
-			args.hobfile.sector_number = (block >>= 8);	/* low lba */
-			args.hobfile.low_cylinder = (block >>= 8);	/* mid lba */
-			args.hobfile.high_cylinder = (block >>= 8);	/* hi  lba */
-		} else if (drive->select.b.lba) {
-			/* LBA 28 bit  */
-			if (sectors == 256)
-				sectors = 0;
-
-			if (blk_rq_tagged(rq)) {
-				args.taskfile.feature = sectors;
-				args.taskfile.sector_count = rq->tag << 3;
-			} else
-				args.taskfile.sector_count = sectors;
-
-			args.taskfile.sector_number = block;
-			args.taskfile.low_cylinder = (block >>= 8);
-			args.taskfile.high_cylinder = (block >>= 8);
-			args.taskfile.device_head = ((block >> 8) & 0x0f);
-		} else {
-			/* CHS */
-			unsigned int track	= (block / drive->sect);
-			unsigned int sect	= (block % drive->sect) + 1;
-			unsigned int head	= (track % drive->head);
-			unsigned int cyl	= (track / drive->head);
-
-			if (sectors == 256)
-				sectors = 0;
-
-			if (blk_rq_tagged(rq)) {
-				args.taskfile.feature = sectors;
-				args.taskfile.sector_count = rq->tag << 3;
-			} else
-				args.taskfile.sector_count = sectors;
-
-			args.taskfile.sector_number = sect;
-			args.taskfile.low_cylinder = cyl;
-			args.taskfile.high_cylinder = (cyl>>8);
-			args.taskfile.device_head = head;
-		}
-		args.taskfile.device_head |= drive->select.all;
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
 
-		/*
-		 * Decode with physical ATA command to use and setup associated data.
-		 */
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
 
-		if (rq_data_dir(rq) == READ) {
-			args.command_type = IDE_DRIVE_TASK_IN;
-			if (drive->addressing) {
-				if (drive->using_tcq) {
-					cmd = WIN_READDMA_QUEUED_EXT;
-				} else if (drive->using_dma) {
-					cmd = WIN_READDMA_EXT;
-				} else if (drive->mult_count) {
-					args.XXX_handler = task_mulin_intr;
-					cmd = WIN_MULTREAD_EXT;
-				} else {
-					args.XXX_handler = task_in_intr;
-					cmd = WIN_READ_EXT;
-				}
-			} else {
-				if (drive->using_tcq) {
-					cmd = WIN_READDMA_QUEUED;
-				} else if (drive->using_dma) {
-					cmd = WIN_READDMA;
-				} else if (drive->mult_count) {
-					args.XXX_handler = task_mulin_intr;
-					cmd = WIN_MULTREAD;
-				} else {
-					args.XXX_handler = task_in_intr;
-					cmd = WIN_READ;
-				}
-			}
-		} else {
-			args.command_type = IDE_DRIVE_TASK_RAW_WRITE;
-			if (drive->addressing) {
-				if (drive->using_tcq) {
-					cmd = WIN_WRITEDMA_QUEUED_EXT;
-				} else if (drive->using_dma) {
-					cmd = WIN_WRITEDMA_EXT;
-				} else if (drive->mult_count) {
-					args.XXX_handler = task_mulout_intr;
-					cmd = WIN_MULTWRITE_EXT;
-				} else {
-					args.XXX_handler = task_out_intr;
-					cmd = WIN_WRITE_EXT;
-				}
-			} else {
-				if (drive->using_tcq) {
-					cmd = WIN_WRITEDMA_QUEUED;
-				} else if (drive->using_dma) {
-					cmd = WIN_WRITEDMA;
-				} else if (drive->mult_count) {
-					args.XXX_handler = task_mulout_intr;
-					cmd = WIN_MULTWRITE;
-				} else {
-					args.XXX_handler = task_out_intr;
-					cmd = WIN_WRITE;
-				}
-			}
-		}
 #ifdef DEBUG
-		printk("%s: %sing: ", drive->name,
-				(rq_data_dir(rq)==READ) ? "read" : "writ");
-		if (lba)	printk("LBAsect=%lld, ", block);
-		else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-		printk("sectors=%ld, ", rq->nr_sectors);
-		printk("buffer=%p\n", rq->buffer);
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
-		ar->cmd = cmd;
-		rq->special = ar;
-	}
 
-	/* (ks/hs): Moved to start, do not use for multiple out commands.
-	 * FIXME: why not?! */
-	if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
-	      cmd == WIN_MULTWRITE ||
-	      cmd == WIN_MULTWRITE_EXT)) {
-		ata_irq_enable(drive, 1);
-		ata_mask(drive);
-	}
-
-	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1))
-		ata_out_regfile(drive, &ar->hobfile);
-
-	ata_out_regfile(drive, &ar->taskfile);
-
-	OUT_BYTE((ar->taskfile.device_head & (drive->addressing ? 0xE0 : 0xEF)) | drive->select.all,
-			IDE_SELECT_REG);
-
-	/* FIXME: this is actually distingushing between PIO and DMA requests.
-	 */
-	if (ar->XXX_handler) {
-		if (ar->command_type == IDE_DRIVE_TASK_IN ||
-		    ar->command_type == IDE_DRIVE_TASK_NO_DATA) {
+	memset(&args, 0, sizeof(ide_task_t));
 
-			ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
-			OUT_BYTE(cmd, IDE_COMMAND_REG);
+	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
+	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
+	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= head;
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
-			return ATA_OP_CONTINUES;
-		}
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-		/* FIXME: Warning check for race between handlers for writing
-		 * first block of data.  However since we are well inside the
-		 * boundaries of the seek, we should be okay.
-		 */
-		if (ar->command_type == IDE_DRIVE_TASK_RAW_WRITE) {
-			ide_startstop_t ret;
+	memset(&args, 0, sizeof(ide_task_t));
 
-			OUT_BYTE(cmd, IDE_COMMAND_REG);
+	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
 
-			ret = ata_status_poll(drive, DATA_READY, drive->bad_wstat,
-						WAIT_DRQ, rq);
-			if (ret != ATA_OP_READY) {
-				printk(KERN_ERR "%s: no DRQ after issuing %s\n",
-						drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
 
-				return ret;
-			}
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
-			/* FIXME: This doesn't make the slightest sense.
-			 * (ks/hs): Fixed Multi Write
-			 */
-			if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
-			      cmd == WIN_MULTWRITE ||
-			      cmd == WIN_MULTWRITE_EXT)) {
-				unsigned long flags;
-				char *buf = ide_map_rq(rq, &flags);
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-				ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
 
-				/* For Write_sectors we need to stuff the first sector */
-				/* FIXME: what if !rq->current_nr_sectors  --bzolnier */
-				ata_write(drive, buf, SECTOR_WORDS);
+	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
 
-				rq->current_nr_sectors--;
-				ide_unmap_rq(rq, buf, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
 
-				return ATA_OP_CONTINUES;
-			} else {
-				int i;
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "do_rw_disk - bad command");
+		return ide_stopped;
+	}
 
-				/* Polling wait until the drive is ready.
-				 *
-				 * Stuff the first sector(s) by calling the
-				 * handler driectly therafter.
-				 *
-				 * FIXME: Replace hard-coded 100, what about
-				 * error handling?
-				 *
-				 * FIXME: Whatabout the IRE clearing and not clearing case?!
-				 */
-
-				for (i = 0; i < 100; ++i) {
-					if (ata_status_irq(drive))
-						break;
-				}
-				if (!ata_status_irq(drive)) {
-					/* We are compleatly missing an error
-					 * return path here.
-					 * FIXME: We have only one? -alat
-					 */
-					printk(KERN_ERR "DISASTER WAITING TO HAPPEN! Try to Stop it!\n");
-					return ata_error(drive, rq, __FUNCTION__);
-				}
+	if (driver_blocked)
+		panic("Request while ide driver is blocked?");
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
 
-				/* will set handler for us */
-				return ar->XXX_handler(drive, rq);
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
+#else /* !CONFIG_BLK_DEV_PDC4030 */
+	if (drive->select.b.lba) {
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+		if ((drive->id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task_ioreg_t tasklets[10];
+
+			tasklets[0] = 0;
+			tasklets[1] = 0;
+			tasklets[2] = rq->nr_sectors;
+			tasklets[3] = (rq->nr_sectors>>8);
+			if (rq->nr_sectors == 65536) {
+				tasklets[2] = 0x00;
+				tasklets[3] = 0x00;
 			}
+			tasklets[4] = (task_ioreg_t) block;
+			tasklets[5] = (task_ioreg_t) (block>>8);
+			tasklets[6] = (task_ioreg_t) (block>>16);
+			tasklets[7] = (task_ioreg_t) (block>>24);
+			tasklets[8] = (task_ioreg_t) 0;
+			tasklets[9] = (task_ioreg_t) 0;
+//			tasklets[8] = (task_ioreg_t) (block>>32);
+//			tasklets[9] = (task_ioreg_t) (block>>40);
+#ifdef DEBUG
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+				drive->name,
+				(rq_data_dir(rq)==READ)?"read":"writ",
+				block,
+				rq->nr_sectors,
+				(unsigned long) rq->buffer,
+				block);
+			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+				drive->name, tasklets[3], tasklets[2],
+				tasklets[9], tasklets[8], tasklets[7],
+				tasklets[6], tasklets[5], tasklets[4]);
+#endif
+			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
+			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
+			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
+			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
+			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
+
+			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
+			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
+			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
+			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
+			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
+			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+		} else {
+#ifdef DEBUG
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+				drive->name, (rq_data_dir(rq)==READ)?"read":"writ",
+				block, rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+			OUT_BYTE(0x00, IDE_FEATURE_REG);
+			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
+			OUT_BYTE(block,IDE_SECTOR_REG);
+			OUT_BYTE(block>>=8,IDE_LCYL_REG);
+			OUT_BYTE(block>>=8,IDE_HCYL_REG);
+			OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
 		}
 	} else {
-		/*
-		 * FIXME: This is a gross hack, need to unify tcq dma proc and
-		 * regular dma proc. It should now be easier.
-		 *
-		 * FIXME: Handle the alternateives by a command type.
-		 */
-
-		/* FIXME: ATA_OP_CONTINUES?  --bzolnier */
-		/* Not started a request - BUG() ot ATA_OP_FINISHED to avoid lockup ? - alat*/
-		if (!drive->using_dma)
-			return ATA_OP_CONTINUES;
-
-		/* for dma commands we don't set the handler */
-		if (cmd == WIN_WRITEDMA ||
-		    cmd == WIN_WRITEDMA_EXT ||
-		    cmd == WIN_READDMA ||
-		    cmd == WIN_READDMA_EXT)
-			return udma_init(drive, rq);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-		else if (cmd == WIN_WRITEDMA_QUEUED ||
-			 cmd == WIN_WRITEDMA_QUEUED_EXT ||
-			 cmd == WIN_READDMA_QUEUED ||
-			 cmd == WIN_READDMA_QUEUED_EXT)
-			return udma_tcq_init(drive, rq);
+		unsigned int sect,head,cyl,track;
+		track = block / drive->sect;
+		sect  = block % drive->sect + 1;
+		OUT_BYTE(sect,IDE_SECTOR_REG);
+		head  = track % drive->head;
+		cyl   = track / drive->head;
+
+		OUT_BYTE(0x00, IDE_FEATURE_REG);
+		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
+		OUT_BYTE(cyl,IDE_LCYL_REG);
+		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
+		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+#ifdef DEBUG
+		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
+			drive->name, (rq_data_dir(rq)==READ)?"read":"writ", cyl,
+			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
-		else {
-			printk(KERN_ERR "%s: unknown command %x\n",
-					__FUNCTION__, cmd);
-
-			return ATA_OP_FINISHED;
+	}
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
+		return do_pdc4030_io (drive, rq);
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+	if (rq_data_dir(rq) == READ) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+			return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+		if ((drive->id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		}
+		return ide_started;
+	} else if (rq_data_dir(rq) == WRITE) {
+		ide_startstop_t startstop;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+			return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		if ((drive->id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		}
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
+				drive->mult_count ? "MULTWRITE" : "WRITE");
+			return startstop;
+		}
+		if (!drive->unmask)
+			local_irq_disable();
+		if (drive->mult_count) {
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	/*
+	 * Ugh.. this part looks ugly because we MUST set up
+	 * the interrupt handler before outputting the first block
+	 * of data to be written.  If we hit an error (corrupted buffer list)
+	 * in ide_multwrite(), then we need to remove the handler/timer
+	 * before returning.  Fortunately, this NEVER happens (right?).
+	 *
+	 * Except when you get an error it seems...
+	 *
+	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
+	 */
+			hwgroup->wrq = *rq; /* scratchpad */
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
+			if (ide_multwrite(drive, drive->mult_count)) {
+				unsigned long flags;
+				spin_lock_irqsave(&ide_lock, flags);
+				hwgroup->handler = NULL;
+				del_timer(&hwgroup->timer);
+				spin_unlock_irqrestore(&ide_lock, flags);
+				return ide_stopped;
+			}
+		} else {
+			unsigned long flags;
+			char *buffer = ide_map_buffer(rq, &flags);
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+			taskfile_output_data(drive, buffer, SECTOR_WORDS);
+			ide_unmap_buffer(buffer, &flags);
 		}
+		return ide_started;
 	}
-
-	/* not reached */
-	return ATA_OP_CONTINUES;
+	printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+	idedisk_end_request(drive, 0);
+	return ide_stopped;
 }
 
-static int idedisk_open(struct inode *inode, struct file *__fp, struct ata_device *drive)
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		check_disk_change(inode->i_bdev);
-
 		/*
-		 * Ignore the return code from door_lock, since the open() has
-		 * already succeeded once, and the door_lock is irrelevant at this
-		 * time.
+		 * Ignore the return code from door_lock,
+		 * since the open() has already succeeded,
+		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking) {
-			struct ata_taskfile args;
-
-			memset(&args, 0, sizeof(args));
-			args.cmd = WIN_DOORLOCK;
-			if (ide_raw_taskfile(drive, &args, NULL))
-				drive->doorlocking = 0;
-		}
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+			drive->doorlocking = 0;
 	}
-
 	return 0;
 }
 
-static int flush_cache(struct ata_device *drive)
-{
-	struct ata_taskfile args;
-
-	memset(&args, 0, sizeof(args));
-
-	if (drive->id->cfs_enable_2 & 0x2400)
-		args.cmd = WIN_FLUSH_CACHE_EXT;
-	else
-		args.cmd = WIN_FLUSH_CACHE;
+static int do_idedisk_flushcache(ide_drive_t *drive);
 
-	return ide_raw_taskfile(drive, &args, NULL);
-}
-
-static void idedisk_release(struct inode *inode, struct file *filp, struct ata_device *drive)
+static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
-		/* XXX I don't think this is up to the lowlevel drivers..  --hch */
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		invalidate_bdev(inode->i_bdev, 0);
-
-		if (drive->doorlocking) {
-			struct ata_taskfile args;
-
-			memset(&args, 0, sizeof(args));
-			args.cmd = WIN_DOORUNLOCK;
-			if (ide_raw_taskfile(drive, &args, NULL))
-				drive->doorlocking = 0;
-		}
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
-		if (flush_cache(drive))
+		if (do_idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
 				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
-static int idedisk_check_media_change(struct ata_device *drive)
+static int idedisk_media_change (ide_drive_t *drive)
 {
-	/* if removable, always assume it was changed */
-	return drive->removable;
+	return drive->removable;	/* if removable, always assume it was changed */
 }
 
-static sector_t idedisk_capacity(struct ata_device *drive)
+static void idedisk_revalidate (ide_drive_t *drive)
 {
-	return drive->capacity;
+	ide_revalidate_drive(drive);
 }
 
-/*
- * This is tightly woven into the driver->special can not touch.
- * DON'T do it again until a total personality rewrite is committed.
- */
-static int set_multcount(struct ata_device *drive, int arg)
+static int idedisk_end_request (ide_drive_t *drive, int uptodate)
 {
-	struct ata_taskfile args;
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
 
-	/* Setting multi mode count on this channel type is not supported/not
-	 * handled.
-	 */
-	if (IS_PDC4030_DRIVE)
-		return -EIO;
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
 
-	/* Hugh, we still didn't detect the devices capabilities.
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
 	 */
-	if (!drive->id)
-		return -EIO;
-
-	if (arg > drive->id->max_multsect)
-		arg = drive->id->max_multsect;
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+	}
 
-	memset(&args, 0, sizeof(args));
-	args.taskfile.sector_count = arg;
-	args.cmd = WIN_SETMULT;
-	if (!ide_raw_taskfile(drive, &args, NULL)) {
-		/* all went well track this setting as valid */
-		drive->mult_count = arg;
+	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+		add_blkdev_randomness(major(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
 
-		return 0;
-	} else
-		drive->mult_count = 0; /* reset */
+static byte idedisk_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
 
-	return -EIO;
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if ((drive->id->command_set_2 & 0x0400) &&
+			    (drive->id->cfs_enable_2 & 0x0400) &&
+			    (drive->addressing == 1)) {
+				__u64 sectors = 0;
+				u32 low = 0, high = 0;
+				low = idedisk_read_24(drive);
+				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+				high = idedisk_read_24(drive);
+				sectors = ((__u64)high << 24) | low;
+				printk(", LBAsect=%llu, high=%d, low=%d",
+				       (unsigned long long) sectors,
+				       high, low);
+			} else {
+				byte cur = IN_BYTE(IDE_SELECT_REG);
+				if (cur & 0x40) {	/* using LBA? */
+					printk(", LBAsect=%ld", (unsigned long)
+					 ((cur&0xf)<<24)
+					 |(IN_BYTE(IDE_HCYL_REG)<<16)
+					 |(IN_BYTE(IDE_LCYL_REG)<<8)
+					 | IN_BYTE(IDE_SECTOR_REG));
+				} else {
+					printk(", CHS=%d/%d/%d",
+					 (IN_BYTE(IDE_HCYL_REG)<<8) +
+					  IN_BYTE(IDE_LCYL_REG),
+					  cur & 0xf,
+					  IN_BYTE(IDE_SECTOR_REG));
+				}
+			}
+			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+				printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+		}
+	}
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	local_irq_restore(flags);
+	return err;
 }
 
-static int set_nowerr(struct ata_device *drive, int arg)
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, byte stat)
 {
-	drive->nowerr = arg;
-	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+	struct request *rq;
+	byte err;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
-	return 0;
+	err = idedisk_dump_status(drive, msg, stat);
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+#if 0
+	else if (rq->flags & REQ_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+#endif
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else if (stat & ERR_STAT) {
+		/* err has different meaning on cdrom and tape */
+		if (err == ABRT_ERR) {
+			if (drive->select.b.lba &&
+			    /* some newer drives don't support WIN_SPECIFY */
+			    IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+				return ide_stopped;
+		} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+			/* UDMA crc error, just retry the operation */
+			drive->crc_count++;
+		} else if (err & (BBD_ERR | ECC_ERR))
+			/* retries won't help these */
+			rq->errors = ERROR_MAX;
+		else if (err & TRK0_ERR)
+			/* help it find track zero */
+			rq->errors |= ERROR_RECAL;
+	}
+	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
+		/*
+		 * try_to_flush_leftover_data() is invoked in response to
+		 * a drive unexpectedly having its DRQ_STAT bit set.  As
+		 * an alternative to resetting the drive, this routine
+		 * tries to clear the condition by read a sector's worth
+		 * of data from the drive.  Of course, this may not help
+		 * if the drive is *waiting* for data from *us*.
+		 */
+		while (i > 0) {
+			u32 buffer[16];
+			unsigned int wcount = (i > 16) ? 16 : i;
+			i -= wcount;
+			ata_input_data(drive, buffer, wcount);
+		}
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX)
+		DRIVER(drive)->end_request(drive, 0);
+	else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
 }
 
-static int write_cache(struct ata_device *drive, int arg)
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
 {
-	struct ata_taskfile args;
+	ide_task_t args;
+	unsigned long addr = 0;
 
-	if (!(drive->id->cfs_enable_2 & 0x3000))
-		return 1;
+#if 0
+	if (!(drive->id->command_set_1 & 0x0400) &&
+	    !(drive->id->cfs_enable_2 & 0x0100))
+		return addr;
+#endif
 
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-	args.cmd = WIN_SETFEATURES;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+	args.command_type			= ide_cmd_type_parser(&args);
+	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
-	drive->wcache = arg;
-
-	return 0;
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
 }
 
-static int idedisk_standby(struct ata_device *drive)
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
 {
-	struct ata_taskfile args;
+	ide_task_t args;
+	unsigned long long addr = 0;
 
-	memset(&args, 0, sizeof(args));
-	args.cmd = WIN_STANDBYNOW1;
-	return ide_raw_taskfile(drive, &args, NULL);
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+	args.command_type			= ide_cmd_type_parser(&args);
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr = ((__u64)high << 24) | low;
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
 }
 
-static int set_acoustic(struct ata_device *drive, int arg)
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
 {
-	struct ata_taskfile args;
+	ide_task_t args;
+	unsigned long addr_set = 0;
+	
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+	args.command_type			= ide_cmd_type_parser(&args);
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, read new maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr_set++;
+	return addr_set;
+}
 
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
-	args.taskfile.sector_count = arg;
-	args.cmd = WIN_SETFEATURES;
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+	ide_task_t args;
+	unsigned long long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr_set = ((__u64)high << 24) | low;
+	}
+	return addr_set;
+}
 
-	drive->acoustic = arg;
+#endif /* CONFIG_IDEDISK_STROKE */
 
-	return 0;
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+	if (flag)
+		printk("%s: host protected area => %d\n", drive->name, flag);
+	return flag;
 }
 
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-static int set_using_tcq(struct ata_device *drive, int arg)
+/*
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
+ */
+static void init_idedisk_capacity (ide_drive_t  *drive)
 {
-	if (!drive->driver)
-		return -EPERM;
+	struct hd_driveid *id = drive->id;
+	unsigned long capacity = drive->cyl * drive->head * drive->sect;
+	unsigned long set_max = idedisk_read_native_max_address(drive);
+	unsigned long long capacity_2 = capacity;
+	unsigned long long set_max_ext;
 
-	if (!drive->channel->udma_setup)
-		return -EPERM;
+	drive->capacity48 = 0;
+	drive->select.b.lba = 0;
 
-	if (arg == drive->queue_depth && drive->using_tcq)
-		return 0;
+	(void) idedisk_supports_host_protected_area(drive);
 
-	/*
-	 * set depth, but check also id for max supported depth
-	 */
-	drive->queue_depth = arg ? arg : 1;
-	if (drive->id) {
-		if (drive->queue_depth > drive->id->queue_depth + 1)
-			drive->queue_depth = drive->id->queue_depth + 1;
+	if (id->cfs_enable_2 & 0x0400) {
+		capacity_2 = id->lba_capacity_2;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->head		= drive->bios_head = 255;
+		drive->sect		= drive->bios_sect = 63;
+		drive->select.b.lba	= 1;
+		set_max_ext = idedisk_read_native_max_address_ext(drive);
+		if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+			set_max_ext = idedisk_read_native_max_address_ext(drive);
+			set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+			if (set_max_ext) {
+				drive->capacity48 = capacity_2 = set_max_ext;
+				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+				drive->select.b.lba = 1;
+				drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+				drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+		}
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->bios_cyl		= drive->cyl;
+		drive->capacity48	= capacity_2;
+		drive->capacity		= (unsigned long) capacity_2;
+		return;
+	/* Determine capacity, and use LBA if the drive properly supports it */
+	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+		capacity = id->lba_capacity;
+		drive->cyl = capacity / (drive->head * drive->sect);
+		drive->select.b.lba = 1;
+	}
+
+	if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+		set_max = idedisk_read_native_max_address(drive);
+		set_max = idedisk_set_max_address(drive, set_max);
+		if (set_max) {
+			drive->capacity = capacity = set_max;
+			drive->cyl = set_max / (drive->head * drive->sect);
+			drive->select.b.lba = 1;
+			drive->id->lba_capacity = capacity;
+		}
+#else /* !CONFIG_IDEDISK_STROKE */
+		printk("%s: setmax LBA %lu, native  %lu\n",
+			drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
 	}
 
-	if (udma_tcq_enable(drive, arg))
-		return -EIO;
+	drive->capacity = capacity;
 
-	return 0;
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+		drive->capacity48 = id->lba_capacity_2;
+		drive->head = 255;
+		drive->sect = 63;
+		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+	}
+}
+
+static unsigned long idedisk_capacity (ide_drive_t *drive)
+{
+	if (drive->id->cfs_enable_2 & 0x0400)
+		return (drive->capacity48 - drive->sect0);
+	return (drive->capacity - drive->sect0);
+}
+
+static ide_startstop_t idedisk_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+	if (s->b.set_geometry) {
+		s->b.set_geometry	= 0;
+		if (!IS_PDC4030_DRIVE) {
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
+		}
+	} else if (s->b.recalibrate) {
+		s->b.recalibrate = 0;
+		if (!IS_PDC4030_DRIVE) {
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
+		}
+	} else if (s->b.set_multmode) {
+		s->b.set_multmode = 0;
+		if (drive->id && drive->mult_req > drive->id->max_multsect)
+			drive->mult_req = drive->id->max_multsect;
+		if (!IS_PDC4030_DRIVE) {
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
+		}
+	} else if (s->all) {
+		int special = s->all;
+		s->all = 0;
+		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+		return ide_stopped;
+	}
+	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
+}
+
+static void idedisk_pre_reset (ide_drive_t *drive)
+{
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
+	drive->special.all = 0;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
+	if (OK_TO_RESET_CONTROLLER)
+		drive->mult_count = 0;
+	if (!drive->keep_settings && !drive->using_dma)
+		drive->mult_req = 0;
+	if (drive->mult_req != drive->mult_count)
+		drive->special.b.set_multmode = 1;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int smart_enable(ide_drive_t *drive)
+{
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
-#endif
 
-static int probe_lba_addressing(struct ata_device *drive, int arg)
+static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
-	drive->addressing =  0;
+	ide_task_t args;
 
-	if (!(drive->id->cfs_enable_2 & 0x0400))
-                return -EIO;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) smart_enable(drive);
+	return ide_raw_taskfile(drive, &args, buf);
+}
+
+static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+{
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) smart_enable(drive);
+	return ide_raw_taskfile(drive, &args, buf);
+}
+
+static int proc_idedisk_read_cache
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		*out = page;
+	int		len;
 
-	drive->addressing = arg;
-	return 0;
+	if (drive->id)
+		len = sprintf(out,"%i\n", drive->id->buf_size / 2);
+	else
+		len = sprintf(out,"(none)\n");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int set_lba_addressing(struct ata_device *drive, int arg)
+static int proc_idedisk_read_smart_thresholds
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	return (probe_lba_addressing(drive, arg));
+	ide_drive_t	*drive = (ide_drive_t *)data;
+	int		len = 0, i = 0;
+
+	if (!get_smart_thresholds(drive, page)) {
+		unsigned short *val = (unsigned short *) page;
+		char *out = ((char *)val) + (SECTOR_WORDS * 4);
+		page = out;
+		do {
+			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			val += 1;
+		} while (i < (SECTOR_WORDS * 2));
+		len = out - page;
+	}
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int idedisk_suspend(struct device *dev, u32 state, u32 level)
+static int proc_idedisk_read_smart_values
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	struct ata_device *drive = dev->driver_data;
+	ide_drive_t	*drive = (ide_drive_t *)data;
+	int		len = 0, i = 0;
 
-	/* I hope that every freeze operations from the upper levels have
-	 * already been done...
-	 */
+	if (!get_smart_values(drive, page)) {
+		unsigned short *val = (unsigned short *) page;
+		char *out = ((char *)val) + (SECTOR_WORDS * 4);
+		page = out;
+		do {
+			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			val += 1;
+		} while (i < (SECTOR_WORDS * 2));
+		len = out - page;
+	}
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
 
-	BUG_ON(in_interrupt());
+static ide_proc_entry_t idedisk_proc[] = {
+	{ "cache",		S_IFREG|S_IRUGO,	proc_idedisk_read_cache,		NULL },
+	{ "geometry",		S_IFREG|S_IRUGO,	proc_ide_read_geometry,			NULL },
+	{ "smart_values",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_values,		NULL },
+	{ "smart_thresholds",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_thresholds,	NULL },
+	{ NULL, 0, NULL, NULL }
+};
 
-	if (level != SUSPEND_SAVE_STATE)
-		return 0;
+#else
 
-	/* wait until all commands are finished */
-	/* FIXME: waiting for spinlocks should be done instead. */
-	while (drive->channel->handler)
-		yield();
-
-	/* set the drive to standby */
-	printk(KERN_INFO "suspending: %s ", drive->name);
-	if (ata_ops(drive)) {
-		if (ata_ops(drive)->standby)
-			ata_ops(drive)->standby(drive);
-	}
-	drive->blocked = 1;
+#define	idedisk_proc	NULL
 
-	return 0;
-}
+#endif	/* CONFIG_PROC_FS */
 
-static int idedisk_resume(struct device *dev, u32 level)
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
+static int set_multcount(ide_drive_t *drive, int arg)
 {
-	struct ata_device *drive = dev->driver_data;
+	struct request rq;
 
-	if (level != RESUME_RESTORE_STATE)
-		return 0;
-	if (!drive->blocked)
-		panic("ide: Resume but not suspended?\n");
+	if (drive->special.b.set_multmode)
+		return -EBUSY;
+	ide_init_drive_cmd (&rq);
+	rq.flags = REQ_DRIVE_CMD;
+	drive->mult_req = arg;
+	drive->special.b.set_multmode = 1;
+	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	return (drive->mult_count == arg) ? 0 : -EIO;
+}
 
-	drive->blocked = 0;
+static int set_nowerr(ide_drive_t *drive, int arg)
+{
+	if (ide_spin_wait_hwgroup(drive))
+		return -EBUSY;
+	drive->nowerr = arg;
+	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+	spin_unlock_irq(&ide_lock);
 	return 0;
 }
 
-
-/* This is just a hook for the overall driver tree.
- */
-
-static struct device_driver disk_devdrv = {
-	.lock = RW_LOCK_UNLOCKED,
-	.suspend = idedisk_suspend,
-	.resume = idedisk_resume,
-};
-
-/*
- * Queries for true maximum capacity of the drive.
- * Returns maximum LBA address (> 0) of the drive, 0 if failed.
- */
-static unsigned long native_max_address(struct ata_device *drive)
+static int write_cache (ide_drive_t *drive, int arg)
 {
-	struct ata_taskfile args;
-	unsigned long addr = 0;
+	ide_task_t args;
 
-	if (!(drive->id->command_set_1 & 0x0400) &&
-	    !(drive->id->cfs_enable_2 & 0x0100))
-		return addr;
+	if (!(drive->id->cfs_enable_2 & 0x3000))
+		return 1;
 
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(args));
-	args.taskfile.device_head = 0x40;
-	args.cmd = WIN_READ_NATIVE_MAX;
-	ide_raw_taskfile(drive, &args, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) ide_raw_taskfile(drive, &args, NULL);
 
-	/* if OK, compute maximum address value */
-	if (!(drive->status & ERR_STAT)) {
-		addr = ((args.taskfile.device_head & 0x0f) << 24)
-		     | (args.taskfile.high_cylinder << 16)
-		     | (args.taskfile.low_cylinder <<  8)
-		     | args.taskfile.sector_number;
-	}
+	drive->wcache = arg;
+	return 0;
+}
 
-	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+static int call_idedisk_standby (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	byte standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= standby;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
 
-	return addr;
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+	return call_idedisk_standby(drive, 0);
 }
 
-static u64 native_max_address_ext(struct ata_device *drive)
+static int call_idedisk_suspend (ide_drive_t *drive, int arg)
 {
-	struct ata_taskfile args;
-	u64 addr = 0;
+	ide_task_t args;
+	byte suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= suspend;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
 
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(args));
-	args.taskfile.device_head = 0x40;
-	args.cmd = WIN_READ_NATIVE_MAX_EXT;
-        ide_raw_taskfile(drive, &args, NULL);
+static int do_idedisk_suspend (ide_drive_t *drive)
+{
+	if (drive->suspend_reset)
+		return 1;
 
-	/* if OK, compute maximum address value */
-	if (!(drive->status & ERR_STAT)) {
-		u32 high = (args.hobfile.high_cylinder << 16) |
-			   (args.hobfile.low_cylinder << 8) |
-			    args.hobfile.sector_number;
-		u32 low  = (args.taskfile.high_cylinder << 16) |
-			   (args.taskfile.low_cylinder << 8) |
-			    args.taskfile.sector_number;
-		addr = ((u64)high << 24) | low;
-	}
+	return call_idedisk_suspend(drive, 0);
+}
 
-	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+#if 0
+static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	byte ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= ckpw;
+	args.command_type			= ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
+#if 0
+if (errno != EIO || args[0] != 0 || args[1] != 0)
+   state = "unknown";
+else
+   state = "sleeping";
+} else {
+   state = (args[2] == 255) ? "active/idle" : "standby";
+#endif
+	return 0;
+}
 
-	return addr;
+static int do_idedisk_checkpower (ide_drive_t *drive)
+{
+	return call_idedisk_checkpower(drive, 0);
 }
+#endif
 
-#ifdef CONFIG_IDEDISK_STROKE
-/*
- * Sets maximum virtual LBA address of the drive.
- * Returns new maximum virtual LBA address (> 0) or 0 on failure.
- */
-static sector_t set_max_address(struct ata_device *drive, sector_t addr_req)
+static int do_idedisk_resume (ide_drive_t *drive)
 {
-	struct ata_taskfile args;
-	sector_t addr_set = 0;
+	if (!drive->suspend_reset)
+		return 1;
+	return 0;
+}
 
-	addr_req--;
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(args));
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+	ide_task_t args;
 
-	args.taskfile.sector_number = (addr_req >> 0);
-	args.taskfile.low_cylinder = (addr_req >> 8);
-	args.taskfile.high_cylinder = (addr_req >> 16);
+	memset(&args, 0, sizeof(ide_task_t));
+	if (drive->id->cfs_enable_2 & 0x2400)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+	args.command_type	 		= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
 
-	args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
-	args.cmd = WIN_SET_MAX;
-	ide_raw_taskfile(drive, &args, NULL);
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
 
-	/* if OK, read new maximum address value */
-	if (!(drive->status & ERR_STAT)) {
-		addr_set = ((args.taskfile.device_head & 0x0f) << 24)
-			 | (args.taskfile.high_cylinder << 16)
-			 | (args.taskfile.low_cylinder <<  8)
-			 | args.taskfile.sector_number;
-	}
-	addr_set++;
-	return addr_set;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+							  SETFEATURES_DIS_AAM;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type = ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
+	drive->acoustic = arg;
+	return 0;
 }
 
-static u64 set_max_address_ext(struct ata_device *drive, u64 addr_req)
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
 {
-	struct ata_taskfile args;
-	u64 addr_set = 0;
-
-	addr_req--;
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(args));
+	drive->addressing =  0;
 
-	args.taskfile.sector_number = (addr_req >>  0);
-	args.taskfile.low_cylinder = (addr_req >>= 8);
-	args.taskfile.high_cylinder = (addr_req >>= 8);
-	args.taskfile.device_head = 0x40;
-	args.cmd = WIN_SET_MAX_EXT;
-
-	args.hobfile.sector_number = (addr_req >>= 8);
-	args.hobfile.low_cylinder = (addr_req >>= 8);
-	args.hobfile.high_cylinder = (addr_req >>= 8);
-	args.hobfile.device_head = 0x40;
+	if (HWIF(drive)->addressing)
+		return 0;
 
-	ide_raw_taskfile(drive, &args, NULL);
+	if (!(drive->id->cfs_enable_2 & 0x0400))
+                return -EIO;
+	drive->addressing = arg;
+	return 0;
+}
 
-	/* if OK, compute maximum address value */
-	if (!(drive->status & ERR_STAT)) {
-		u32 high = (args.hobfile.high_cylinder << 16) |
-			   (args.hobfile.low_cylinder << 8) |
-			    args.hobfile.sector_number;
-		u32 low  = (args.taskfile.high_cylinder << 16) |
-			   (args.taskfile.low_cylinder << 8) |
-			    args.taskfile.sector_number;
-		addr_set = ((u64)high << 24) | low;
-	}
-	return addr_set;
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+	return (probe_lba_addressing(drive, arg));
 }
 
-#endif
+static void idedisk_add_settings(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
+	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
+	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
+	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
+	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
+	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
+	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
+	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
+ 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
+ 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
+}
 
-static void idedisk_setup(struct ata_device *drive)
+static void idedisk_setup (ide_drive_t *drive)
 {
 	int i;
-
+	
 	struct hd_driveid *id = drive->id;
-	sector_t capacity;
-	sector_t set_max;
-	int drvid = -1;
-	struct ata_channel *ch = drive->channel;
+	unsigned long capacity;
+	
+	idedisk_add_settings(drive);
 
 	if (id == NULL)
 		return;
@@ -1054,32 +1531,30 @@
 	 * to us, but they are removable and don't have a doorlock mechanism.
 	 */
 	if (drive->removable && !drive_is_flashcard(drive)) {
-		/* Removable disks (eg. SYQUEST); ignore 'WD' drives.
+		/*
+		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
 		 */
-		if (!strncmp(id->model, "WD", 2))
+		if (id->model[0] != 'W' || id->model[1] != 'D') {
 			drive->doorlocking = 1;
+		}
 	}
-
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		if (drive != &ch->drives[i])
-		    continue;
-		drvid = i;
-		ch->gd[i]->de_arr[0] = drive->de;
+		ide_hwif_t *hwif = HWIF(drive);
+
+		if (drive != &hwif->drives[i]) continue;
+		hwif->gd[i]->de_arr[i] = drive->de;
 		if (drive->removable)
-			ch->gd[i]->flags[0] |= GENHD_FL_REMOVABLE;
+			hwif->gd[i]->flags[i] |= GENHD_FL_REMOVABLE;
 		break;
 	}
 
-	/* Register us within the device tree.
-	 */
-	if (drvid != -1) {
-		sprintf(drive->dev.bus_id, "sd@%x,%x", ch->unit, drvid);
-		strcpy(drive->dev.name, "ATA-Disk");
-		drive->dev.driver = &disk_devdrv;
-		drive->dev.parent = &ch->dev;
-		drive->dev.driver_data = drive;
-		device_register(&drive->dev);
-	}
+#if 1
+	(void) probe_lba_addressing(drive, 1);
+#else
+	/* if using 48-bit addressing bump the request size up */
+	if (probe_lba_addressing(drive, 1))
+		blk_queue_max_sectors(&drive->queue, 2048);
+#endif
 
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
@@ -1088,7 +1563,7 @@
 		drive->sect    = drive->bios_sect = id->sectors;
 	}
 
-	/* Handle logical geometry translation by the drive. */
+	/* Handle logical geometry translation by the drive */
 	if ((id->field_valid & 1) && id->cur_cyls &&
 	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
 		drive->cyl  = id->cur_cyls;
@@ -1096,414 +1571,263 @@
 		drive->sect = id->cur_sectors;
 	}
 
-	/* Use physical geometry if what we have still makes no sense. */
+	/* Use physical geometry if what we have still makes no sense */
 	if (drive->head > 16 && id->heads && id->heads <= 16) {
 		drive->cyl  = id->cyls;
 		drive->head = id->heads;
 		drive->sect = id->sectors;
 	}
 
-	/* Calculate drive capacity, and select LBA if possible.
-	 * drive->id != NULL is spected
-	 *
-	 * To compute capacity, this uses either of
-	 *
-	 *    1. CHS value set by user       (whatever user sets will be trusted)
-	 *    2. LBA value from target drive (require new ATA feature)
-	 *    3. LBA value from system BIOS  (new one is OK, old one may break)
-	 *    4. CHS value from system BIOS  (traditional style)
-	 *
-	 * in above order (i.e., if value of higher priority is available,
-	 * reset will be ignored).
-	 */
-	capacity = drive->cyl * drive->head * drive->sect;
-	set_max = native_max_address(drive);
-
-	drive->capacity = 0;
-	drive->select.b.lba = 0;
-
-	if (id->cfs_enable_2 & 0x0400) {
-		u64 set_max_ext;
-		u64 capacity_2;
-		capacity_2 = capacity;
-		capacity_2 = id->lba_capacity_2;
-
-		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
-		drive->head = drive->bios_head = 255;
-		drive->sect = drive->bios_sect = 63;
-
-		drive->select.b.lba = 1;
-		set_max_ext = native_max_address_ext(drive);
-		if (set_max_ext > capacity_2) {
-#ifdef CONFIG_IDEDISK_STROKE
-			set_max_ext = native_max_address_ext(drive);
-			set_max_ext = set_max_address_ext(drive, set_max_ext);
-			if (set_max_ext) {
-				drive->capacity = capacity_2 = set_max_ext;
-				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
-				drive->select.b.lba = 1;
-				drive->id->lba_capacity_2 = capacity_2;
-                        }
-#else
-			printk("%s: setmax_ext LBA %llu, native  %llu\n",
-				drive->name,
-			       (long long) set_max_ext,
-			       (long long) capacity_2);
-#endif
-		}
-		drive->bios_cyl	= drive->cyl;
-		drive->capacity	= capacity_2;
-	} else {
-
-		/*
-		 * Determine capacity, and use LBA if the drive properly
-		 * supports it.
-		 */
-
-		if ((id->capability & 2) && lba_capacity_is_ok(id)) {
-			capacity = id->lba_capacity;
-			drive->cyl = capacity / (drive->head * drive->sect);
-			drive->select.b.lba = 1;
-		}
-
-		if (set_max > capacity) {
-#ifdef CONFIG_IDEDISK_STROKE
-			set_max = native_max_address(drive);
-			set_max = set_max_address(drive, set_max);
-			if (set_max) {
-				drive->capacity = capacity = set_max;
-				drive->cyl = set_max / (drive->head * drive->sect);
-				drive->select.b.lba = 1;
-				drive->id->lba_capacity = capacity;
-			}
-#else
-			printk("%s: setmax LBA %lu, native  %lu\n",
-					drive->name, set_max, capacity);
-#endif
-		}
-
-		drive->capacity = capacity;
-
-		if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
-			drive->capacity = id->lba_capacity_2;
-			drive->head = 255;
-			drive->sect = 63;
-			drive->cyl = (unsigned long)(drive->capacity) / (drive->head * drive->sect);
-		}
-	}
+	/* calculate drive capacity, and select LBA if possible */
+	init_idedisk_capacity (drive);
 
 	/*
-	 * If possible, give fdisk access to more of the drive,
+	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
-	capacity = idedisk_capacity(drive);
+	capacity = idedisk_capacity (drive);
 	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
 	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-	printk(KERN_INFO " %s: %ld sectors", drive->name, capacity);
-
-#if 0
-	/* Right now we avoid this calculation, since it can result in the
-	 * usage of not supported compiler internal functions on 32 bit hosts.
-	 * However since the calculation appears to be an interesting piece of
-	 * number theory let's preserve the formula here.
-	 */
+	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
 
-	/* Give size in megabytes (MB), not mebibytes (MiB).
-	 * We compute the exact rounded value, avoiding overflow.
-	 */
-	printk(" (%ld MB)", (capacity - capacity/625 + 974)/1950);
-#endif
+	/* Give size in megabytes (MB), not mebibytes (MiB). */
+	/* We compute the exact rounded value, avoiding overflow. */
+	printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
 
-	/* Only print cache size when it was specified.
-	 */
+	/* Only print cache size when it was specified */
 	if (id->buf_size)
 		printk (" w/%dKiB Cache", id->buf_size/2);
 
-	printk(", CHS=%d/%d/%d",
+	printk(", CHS=%d/%d/%d", 
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		udma_print(drive);
-#endif
+		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
 	drive->mult_count = 0;
-#if 0
 	if (id->max_multsect) {
-
-		/* FIXME: reenable this again after making it to use
-		 * the same code path as the ioctl stuff.
-		 */
-
 #ifdef CONFIG_IDEDISK_MULTI_MODE
 		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
 		id->multsect_valid = id->multsect ? 1 : 0;
 		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
-		if (drive->mult_req)
-			drive->special_cmd |= ATA_SPECIAL_MMODE;
-#else
-		/* original, pre IDE-NFG, per request of AC */
+		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else	/* original, pre IDE-NFG, per request of AC */
 		drive->mult_req = INITIAL_MULT_COUNT;
 		if (drive->mult_req > id->max_multsect)
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
-			drive->special_cmd |= ATA_SPECIAL_MMODE;
-#endif
+			drive->special.b.set_multmode = 1;
+#endif	/* CONFIG_IDEDISK_MULTI_MODE */
 	}
-#endif
-
-	/* FIXME: Nowadays there are many chipsets out there which *require* 32
-	 * bit IO. Those will most propably not work properly with drives not
-	 * supporting this. But right now we don't do anything about this. We
-	 * dont' even *warn* the user!
-	 */
-
-	drive->channel->no_io_32bit = id->dword_io ? 1 : 0;
-
+	drive->no_io_32bit = id->dword_io ? 1 : 0;
 	if (drive->id->cfs_enable_2 & 0x3000)
 		write_cache(drive, (id->cfs_enable_2 & 0x3000));
-
-	probe_lba_addressing(drive, 1);
 }
 
-static int idedisk_cleanup(struct ata_device *drive)
+static int idedisk_cleanup (ide_drive_t *drive)
 {
-	int ret;
-
-	if (!drive)
-	    return 0;
-
-	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) {
-		if (flush_cache(drive))
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
 				drive->name);
-	}
-	ret = ata_unregister_device(drive);
-
-	/* FIXME: This is killing the kernel with BUG 185 at asm/spinlocks.h
-	 * horribly.  Check whatever we did REGISTER the device properly
-	 * in front?
-	 */
-#if 0
-	put_device(&drive->device);
-#endif
-
-	return ret;
+	return ide_unregister_subdriver(drive);
 }
 
-static int idedisk_ioctl(struct ata_device *drive,
-		struct inode *inode, struct file *__fp,
-		unsigned int cmd, unsigned long arg)
-{
-	struct hd_driveid *id = drive->id;
-
-	switch (cmd) {
-		case HDIO_GET_ADDRESS: {
-			unsigned long val = drive->addressing;
+int idedisk_init (void);
+int idedisk_reinit(ide_drive_t *drive);
 
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_SET_ADDRESS: {
-			int val;
-
-			if (arg < 0 || arg > 2)
-				return -EINVAL;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			val = set_lba_addressing(drive, arg);
-			spin_unlock_irq(drive->channel->lock);
-
-			return val;
-		}
-
-		case HDIO_GET_MULTCOUNT: {
-			unsigned long val = drive->mult_count & 0xFF;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_SET_MULTCOUNT: {
-			int val;
-
-			if (!id)
-				return -EBUSY;
-
-			if (arg < 0 || arg > (id ? id->max_multsect : 0))
-				return -EINVAL;
-
-			val = set_multcount(drive, arg);
-
-			return val;
-		}
-
-		case HDIO_GET_NOWERR: {
-			unsigned long val = drive->nowerr;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_SET_NOWERR: {
-			int val;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			val = set_nowerr(drive, arg);
-
-			return val;
-		}
-
-		case HDIO_GET_WCACHE: {
-			unsigned long val = drive->wcache;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_SET_WCACHE: {
-			int val;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			val = write_cache(drive, arg);
-
-			return val;
-		}
-
-		case HDIO_GET_ACOUSTIC: {
-			unsigned long val = drive->acoustic;
-
-			if (put_user(val, (u8 *) arg))
-				return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_SET_ACOUSTIC: {
-			int val;
-
-			if (arg < 0 || arg > 254)
-				return -EINVAL;
-
-			val = set_acoustic(drive, arg);
-
-			return val;
-		}
+/*
+ *      IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idedisk_driver = {
+	name:			"ide-disk",
+	version:		IDEDISK_VERSION,
+	media:			ide_disk,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
+	cleanup:		idedisk_cleanup,
+	standby:		do_idedisk_standby,
+	suspend:		do_idedisk_suspend,
+	resume:			do_idedisk_resume,
+	flushcache:		do_idedisk_flushcache,
+	do_request:		do_rw_disk,
+	end_request:		idedisk_end_request,
+	sense:			idedisk_dump_status,
+	error:			idedisk_error,
+	ioctl:			NULL,
+	open:			idedisk_open,
+	release:		idedisk_release,
+	media_change:		idedisk_media_change,
+	revalidate:		idedisk_revalidate,
+	pre_reset:		idedisk_pre_reset,
+	capacity:		idedisk_capacity,
+	special:		idedisk_special,
+	proc:			idedisk_proc,
+	init:			idedisk_init,
+	reinit:			idedisk_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
+};
 
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-		case HDIO_GET_QDMA: {
-			/* Foolup hdparm 0 means off 1 on -alat */
-			/* FIXME: hdparm have only -Q do we need something like:
-			 * hdparm -q 1/0 - TCQ on/off
-			 * hdparm -Q 1-MAX - TCQ queue_depth ?
-			 */
-			u8 val = ( drive->using_tcq ?  drive->queue_depth : 0 );
+static ide_module_t idedisk_module = {
+	IDE_DRIVER_MODULE,
+	idedisk_init,
+	&idedisk_driver,
+	NULL
+};
 
-			if (put_user(val, (u8 *) arg))
-				return -EFAULT;
+MODULE_DESCRIPTION("ATA DISK Driver");
 
-			return 0;
-		}
+int idedisk_reinit (ide_drive_t *drive)
+{
+	int failed = 0;
 
-		case HDIO_SET_QDMA: {
-			int val;
+	MOD_INC_USE_COUNT;
 
-			if (arg < 0 || arg > IDE_MAX_TAG)
-				return -EINVAL;
+	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy++;
+	idedisk_setup(drive);
+	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			drive->name, drive->head);
+		(void) idedisk_cleanup(drive);
+		DRIVER(drive)->busy--;
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
 
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
-			val = set_using_tcq(drive, arg);
-			spin_unlock_irq(drive->channel->lock);
+static void __exit idedisk_exit (void)
+{
+	ide_drive_t *drive;
+	int failed = 0;
 
-			return val;
-		}
+	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+		if (idedisk_cleanup (drive)) {
+			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+			failed++;
+		}
+		/* We must remove proc entries defined in this module.
+		   Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
+		if (drive->proc)
+			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
-		default:
-			return -EINVAL;
 	}
+	ide_unregister_module(&idedisk_module);
 }
 
-static void idedisk_attach(struct ata_device *drive);
-
-/*
- * Subdriver functions.
- */
-static struct ata_operations idedisk_driver = {
-	.owner =		THIS_MODULE,
-	.attach =		idedisk_attach,
-	.cleanup =		idedisk_cleanup,
-	.standby =		idedisk_standby,
-	.do_request =		idedisk_do_request,
-	.end_request =		NULL,
-	.ioctl =		idedisk_ioctl,
-	.open =			idedisk_open,
-	.release =		idedisk_release,
-	.check_media_change =	idedisk_check_media_change,
-	.revalidate =		NULL, /* use default method */
-	.capacity =		idedisk_capacity,
-};
-
-static void idedisk_attach(struct ata_device *drive)
+int idedisk_init (void)
 {
-	char *req;
-	struct ata_channel *channel;
-	struct gendisk *disk;
-	int unit;
-
-	if (drive->type != ATA_DISK)
-		return;
+	ide_drive_t *drive;
+	int failed = 0;
+	
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
+		if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idedisk_setup(drive);
+		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+			(void) idedisk_cleanup(drive);
+			DRIVER(drive)->busy--;
+			continue;
+		}
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
-	req = drive->driver_req;
-	if (req[0] != '\0' && strcmp(req, "ide-disk"))
-		return;
+ide_startstop_t panic_box(ide_drive_t *drive)
+{
+#if 0
+	panic("%s: Attempted to corrupt something: ide operation "
+#else
+	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
+#endif
+		"was pending accross suspend/resume.\n", drive->name);
+	return ide_stopped;
+}
 
-	if (ata_register_device(drive, &idedisk_driver)) {
-		printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name);
-		return;
+int ide_disks_busy(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+		if (!hwgroup) continue;
+		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
+			return 1;
 	}
+	return 0;
+}
 
-	idedisk_setup(drive);
-	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
-		idedisk_cleanup(drive);
-		return;
+void ide_disk_suspend(void)
+{
+	int i;
+	while (ide_disks_busy()) {
+		printk("*");
+		schedule();
 	}
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
 
-	channel = drive->channel;
-	unit = drive - channel->drives;
-	disk = channel->gd[unit];
-	disk->minor_shift = PARTN_BITS;
-	register_disk(disk, mk_kdev(disk->major, disk->first_minor),
-			1<<disk->minor_shift, disk->fops, drive->capacity);
+		if (!hwgroup) continue;
+		hwgroup->handler_save = hwgroup->handler;
+		hwgroup->handler = panic_box;
+	}
+	driver_blocked = 1;
+	if (ide_disks_busy())
+		panic("How did you get that request through?!");
 }
 
-static void __exit idedisk_exit(void)
+/* unsuspend and resume should be equal in the ideal world */
+
+void ide_disk_unsuspend(void)
 {
-	unregister_ata_driver(&idedisk_driver);
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler = NULL; /* hwgroup->handler_save; */
+		hwgroup->handler_save = NULL;
+	}
+	driver_blocked = 0;
 }
 
-int __init idedisk_init(void)
+void ide_disk_resume(void)
 {
-	return ata_driver_module(&idedisk_driver);
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		if (hwgroup->handler != panic_box)
+			panic("Handler was not set to panic?");
+		hwgroup->handler_save = NULL;
+		hwgroup->handler = NULL;
+	}
+	driver_blocked = 0;
 }
 
 module_init(idedisk_init);
 module_exit(idedisk_exit);
-
-MODULE_DESCRIPTION("ATA DISK Driver");
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-dma.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,906 @@
+/*
+ *  linux/drivers/ide/ide-dma.c		Version 4.10	June 9, 2000
+ *
+ *  Copyright (c) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ *  Special Thanks to Mark for his Six years of work.
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA functions
+ * of various PCI chipsets, including the Intel PIIX (i82371FB for
+ * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and 
+ * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
+ * ("PIIX" stands for "PCI ISA IDE Xcellerator").
+ *
+ * Pretty much the same code works for other IDE PCI bus-mastering chipsets.
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
+ *
+ * By default, DMA support is prepared for use, but is currently enabled only
+ * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single),
+ * or which are recognized as "good" (see table below).  Drives with only mode0
+ * or mode1 (multi/single) DMA should also work with this chipset/driver
+ * (eg. MC2112A) but are not enabled by default.
+ *
+ * Use "hdparm -i" to view modes supported by a given drive.
+ *
+ * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
+ * DMA support, but must be (re-)compiled against this kernel version or later.
+ *
+ * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+ * If problems arise, ide.c will disable DMA operation after a few retries.
+ * This error recovery mechanism works and has been extremely well exercised.
+ *
+ * IDE drives, depending on their vintage, may support several different modes
+ * of DMA operation.  The boot-time modes are indicated with a "*" in
+ * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
+ * the "hdparm -X" feature.  There is seldom a need to do this, as drives
+ * normally power-up with their "best" PIO/DMA modes enabled.
+ *
+ * Testing has been done with a rather extensive number of drives,
+ * with Quantum & Western Digital models generally outperforming the pack,
+ * and Fujitsu & Conner (and some Seagate which are really Conner) drives
+ * showing more lackluster throughput.
+ *
+ * Keep an eye on /var/adm/messages for "DMA disabled" messages.
+ *
+ * Some people have reported trouble with Intel Zappa motherboards.
+ * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
+ * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
+ * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
+ *
+ * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
+ * fixing the problem with the BIOS on some Acer motherboards.
+ *
+ * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
+ * "TX" chipset compatibility and for providing patches for the "TX" chipset.
+ *
+ * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
+ * at generic DMA -- his patches were referred to when preparing this code.
+ *
+ * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
+ * for supplying a Promise UDMA board & WD UDMA drive for this work!
+ *
+ * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
+ *
+ * check_drive_lists(ide_drive_t *drive, int good_bad)
+ *
+ * ATA-66/100 and recovery functions, I forgot the rest......
+ * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed.  Oh the things we forget.  I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+struct drive_list_entry drive_whitelist [] = {
+
+	{ "Micropolis 2112A"	,       "ALL"		},
+	{ "CONNER CTMA 4000"	,       "ALL"		},
+	{ "CONNER CTT8000-A"	,       "ALL"		},
+	{ "ST34342A"		,	"ALL"		},
+	{ 0			,	0		}
+};
+
+struct drive_list_entry drive_blacklist [] = {
+
+	{ "WDC AC11000H"	,	"ALL"		},
+	{ "WDC AC22100H"	,	"ALL"		},
+	{ "WDC AC32500H"	,	"ALL"		},
+	{ "WDC AC33100H"	,	"ALL"		},
+	{ "WDC AC31600H"	,	"ALL"		},
+	{ "WDC AC32100H"	,	"24.09P07"	},
+	{ "WDC AC23200L"	,	"21.10N21"	},
+	{ "Compaq CRD-8241B"	,	"ALL"		},
+	{ "CRD-8400B"		,	"ALL"		},
+	{ "CRD-8480B",			"ALL"		},
+	{ "CRD-8480C",			"ALL"		},
+	{ "CRD-8482B",			"ALL"		},
+ 	{ "CRD-84"		,	"ALL"		},
+	{ "SanDisk SDP3B"	,	"ALL"		},
+	{ "SanDisk SDP3B-64"	,	"ALL"		},
+	{ "SANYO CD-ROM CRD"	,	"ALL"		},
+	{ "HITACHI CDR-8"	,	"ALL"		},
+	{ "HITACHI CDR-8335"	,	"ALL"		},
+	{ "HITACHI CDR-8435"	,	"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B"	,	"ALL"		},
+	{ "CD-532E-A"		,	"ALL"		},
+	{ "E-IDE CD-ROM CR-840",	"ALL"		},
+	{ "CD-ROM Drive/F5A",	"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",	"ALL"		},
+	{ "WPI CDD-820",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",	"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",	"ALL"		},
+	{ "SAMSUNG CD-ROM SC",	"ALL"		},
+	{ "SanDisk SDP3B-64"	,	"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",	"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",	"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",               "ALL"           },  
+	{ 0			,	0		}
+
+};
+
+int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
+}
+
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mode2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+const char *good_dma_drives[] = {"Micropolis 2112A",
+				 "CONNER CTMA 4000",
+				 "CONNER CTT8000-A",
+				 "ST34342A",	/* for Sun Ultra */
+				 NULL};
+
+/*
+ * bad_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which supposedly support (U)DMA but which are
+ * known to corrupt data with this interface under Linux.
+ *
+ * This is an empirical list. Its generated from bug reports. That means
+ * while it reflects actual problem distributions it doesn't answer whether
+ * the drive or the controller, or cabling, or software, or some combination
+ * thereof is the fault. If you don't happen to agree with the kernel's 
+ * opinion of your drive - use hdparm to turn DMA on.
+ */
+const char *bad_dma_drives[] = {"WDC AC11000H",
+				"WDC AC22100H",
+				"WDC AC32100H",
+				"WDC AC32500H",
+				"WDC AC33100H",
+				"WDC AC31600H",
+ 				NULL};
+
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+{
+	int i;
+	byte stat, dma_stat;
+
+	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	stat = GET_STAT();			/* get drive status */
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
+		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+static int ide_build_sglist (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct scatterlist *sg = hwif->sg_table;
+	int nents;
+
+	if (hwif->sg_dma_active)
+		BUG();
+
+	nents = blk_rq_map_sg(&drive->queue, rq, hwif->sg_table);
+		
+	if (rq_data_dir(rq) == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
+static int ide_raw_build_sglist (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+#if 1
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].page = virt_to_page(virt_addr);
+		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].page = virt_to_page(virt_addr);
+	sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+#else
+        while (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address	= virt_to_page(virt_addr);
+		sg[nents].offset	= (unsigned long)virt_addr & ~PAGE_MASK;
+		sg[nents].length	= 128 * SECTOR_SIZE;
+		nents++;
+		virt_addr		= virt_addr + (128 * SECTOR_SIZE);
+		sector_count		-= 128;
+	};
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].page		= virt_to_page(virt_addr);
+	sg[nents].offset	= (unsigned long) virt_addr & ~PAGE_MASK;
+	sg[nents].length	= sector_count * SECTOR_SIZE;
+	nents++;
+#endif
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
+/*
+ * ide_build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ * May also be invoked from trm290.c
+ */
+int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
+{
+	unsigned int *table = HWIF(drive)->dmatable_cpu;
+#ifdef CONFIG_BLK_DEV_TRM290
+	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
+#else
+	const int is_trm290_chipset = 0;
+#endif
+	unsigned int count = 0;
+	int i;
+	struct scatterlist *sg;
+
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
+		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(drive, HWGROUP(drive)->rq);
+	else
+		HWIF(drive)->sg_nents = i = ide_build_sglist(drive, HWGROUP(drive)->rq);
+
+	if (!i)
+		return 0;
+
+	sg = HWIF(drive)->sg_table;
+	while (i) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		/*
+		 * Fill in the dma table, without crossing any 64kB boundaries.
+		 * Most hardware requires 16-bit alignment of all blocks,
+		 * but the trm290 requires 32-bit alignment.
+		 */
+
+		while (cur_len) {
+			if (count++ >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xffff;
+				if (is_trm290_chipset)
+					xcount = ((xcount >> 2) - 1) << 16;
+				if (xcount == 0x0000) {
+					/* 
+					 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+					 * but at least one (e.g. CS5530) misinterprets it as zero (!).
+					 * So here we break the 64KB entry into two 32KB entries instead.
+					 */
+					if (count++ >= PRD_ENTRIES) {
+						printk("%s: DMA table too small\n", drive->name);
+						goto use_pio_instead;
+					}
+					*table++ = cpu_to_le32(0x8000);
+					*table++ = cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
+			}
+		}
+
+		sg++;
+		i--;
+	}
+
+	if (count) {
+		if (!is_trm290_chipset)
+			*--table |= cpu_to_le32(0x80000000);
+		return count;
+	}
+	printk("%s: empty DMA table?\n", drive->name);
+use_pio_instead:
+	pci_unmap_sg(HWIF(drive)->pci_dev,
+		     HWIF(drive)->sg_table,
+		     HWIF(drive)->sg_nents,
+		     HWIF(drive)->sg_dma_direction);
+	HWIF(drive)->sg_dma_active = 0;
+	return 0; /* revert to PIO for this request */
+}
+
+/* Teardown mappings after DMA has completed.  */
+void ide_destroy_dmatable (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
+
+	pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+	HWIF(drive)->sg_dma_active = 0;
+}
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_lists (ide_drive_t *drive, int good_bad)
+{
+	struct hd_driveid *id = drive->id;
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	if (good_bad) {
+		return in_drive_list(id, drive_whitelist);
+	} else {
+		int blacklist = in_drive_list(id, drive_blacklist);
+		if (blacklist)
+			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+
+	if (good_bad) {
+		/* Consult the list of known "good" drives */
+		list = good_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model))
+				return 1;
+		}
+	} else {
+		/* Consult the list of known "bad" drives */
+		list = bad_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				printk("%s: Disabling (U)DMA for %s\n",
+					drive->name, id->model);
+				return 1;
+			}
+		}
+	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
+
+int report_drive_dmaing (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+		if ((id->dma_ultra >> 15) & 1) {
+			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+		if ((id->dma_ultra >> 13) & 1) {
+			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
+		} else if ((id->dma_ultra >> 12) & 1) {
+			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) &&
+		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+		if ((id->dma_ultra >> 10) & 1) {
+			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
+		} else if ((id->dma_ultra >> 9) & 1) {
+			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
+		}
+	} else if (id->field_valid & 4) {
+		printk(", (U)DMA");	/* Can be BIOS-enabled! */
+	} else {
+		printk(", DMA");
+	}
+	return 1;
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (id && (id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive))
+			return hwif->dmaproc(ide_dma_off, drive);
+
+		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+		if (id->field_valid & 4)	/* UltraDMA */
+			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		if (id->field_valid & 2)	/* regular DMA */
+			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Consult the list of known "good" drives */
+		if (ide_dmaproc(ide_dma_good_drive, drive))
+			return hwif->dmaproc(ide_dma_on, drive);
+	}
+	return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+#ifndef __IDEDMA_TIMEOUT
+/*
+ * 1 dmaing, 2 error, 4 intr
+ */
+static int dma_timer_expiry (ide_drive_t *drive)
+{
+	byte dma_stat = IN_BYTE(HWIF(drive)->dma_base+2);
+
+#ifdef DEBUG
+	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
+#endif /* DEBUG */
+
+#if 0
+	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+#endif
+
+	if (dma_stat & 2) {	/* ERROR */
+		byte stat = GET_STAT();
+		return DRIVER(drive)->error(drive, "dma_timer_expiry", stat);
+	}
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+	return 0;
+}
+#else /* __IDEDMA_TIMEOUT */
+static int ide_dma_timeout_recovery (ide_drive_t *drive)
+{
+	struct request *rq	= HWGROUP(drive)->rq;
+	int enable_dma		= drive->using_dma;
+	int speed		= drive->current_speed;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	HWGROUP(drive)->handler	= NULL;
+	del_timer(&HWGROUP(drive)->timer);
+	HWGROUP(drive)->expiry	= NULL;
+	HWGROUP(drive)->rq	= NULL;
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	drive->waiting_for_dma = 0;
+
+	(void) ide_do_reset(drive);
+
+	if (!(drive_is_ready(drive))) {
+		/* FIXME: Replace hard-coded 100, error handling? */
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+
+	if ((HWIF(drive)->speedproc) != NULL) {
+		HWIF(drive)->speedproc(drive, speed);
+		drive->current_speed = speed;
+	}
+
+	if ((enable_dma) && !(drive->using_dma))
+		(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
+
+	return restart_request(drive, rq);
+}
+#endif /* __IDEDMA_TIMEOUT */
+
+static void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;
+
+	if (on && drive->media == ide_disk && !HWIF(drive)->no_highmem) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+/*
+ * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * For ATAPI devices, we just prepare for DMA and return. The caller should
+ * then issue the packet command to the drive and call us again with
+ * ide_dma_begin afterwards.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ * May also be invoked from trm290.c
+ */
+int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+//	ide_task_t *args		= HWGROUP(drive)->rq->special;
+	unsigned long dma_base		= hwif->dma_base;
+	byte unit			= (drive->select.b.unit & 0x01);
+	unsigned int count, reading	= 0;
+	unsigned int set_high		= 1;
+	byte dma_stat;
+
+	switch (func) {
+		case ide_dma_off:
+			printk("%s: DMA disabled\n", drive->name);
+		case ide_dma_off_quietly:
+		case ide_dma_host_off:
+			OUT_BYTE(IN_BYTE(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+			if (func == ide_dma_host_off)
+				return 0;
+			set_high = 0;
+		case ide_dma_on:
+			drive->using_dma = (func == ide_dma_on);
+			if (!drive->using_dma)
+				return 0;
+		case ide_dma_host_on:
+			if (drive->using_dma)
+				OUT_BYTE(IN_BYTE(dma_base+2)|(1<<(5+unit)), dma_base+2);
+			ide_toggle_bounce(drive, set_high);
+			return 0;
+		case ide_dma_check:
+			return config_drive_for_dma (drive);
+		case ide_dma_read:
+			reading = 1 << 3;
+		case ide_dma_write:
+			SELECT_READ_WRITE(hwif,drive,func);
+			if (!(count = ide_build_dmatable(drive, func)))
+				/* try PIO instead of DMA */
+				return 1;
+			/* PRD table */
+			outl(hwif->dmatable_dma, dma_base + 4);
+			/* specify r/w */
+			OUT_BYTE(reading, dma_base);
+			/* clear INTR & ERROR flags */
+			OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2);
+			drive->waiting_for_dma = 1;
+			if (drive->media != ide_disk)
+				return 0;
+			/* paranoia check */
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+#ifndef __IDEDMA_TIMEOUT
+			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+#else /* __IDEDMA_TIMEOUT */
+			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);
+#endif /* __IDEDMA_TIMEOUT */
+			/* issue cmd to drive */
+			/*
+			 * FIX ME to use only ACB ide_task_t args Struct
+			 */
+#if 0
+		{
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		}
+#else
+			if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing == 1)
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			else
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+#endif
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+		case ide_dma_begin:
+			/* Note that this is done *after* the cmd has
+			 * been issued to the drive, as per the BM-IDE spec.
+			 * The Promise Ultra33 doesn't work correctly when
+			 * we do this part before issuing the drive cmd.
+			 */
+			/* start DMA */
+			OUT_BYTE(IN_BYTE(dma_base)|1, dma_base);
+			return 0;
+		case ide_dma_end: /* returns 1 on error, 0 otherwise */
+			drive->waiting_for_dma = 0;
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
+			/* get DMA status */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* clear the INTR & ERROR bits */
+			OUT_BYTE(dma_stat|6, dma_base+2);
+			/* purge DMA mappings */
+			ide_destroy_dmatable(drive);
+			/* verify good DMA status */
+			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+#if 0  /* do not set unless you know what you are doing */
+			if (dma_stat & 4) {
+				byte stat = GET_STAT();
+				OUT_BYTE(dma_base+2, dma_stat & 0xE4);
+			}
+#endif
+			/* return 1 if INTR asserted */
+			return (dma_stat & 4) == 4;
+		case ide_dma_bad_drive:
+		case ide_dma_good_drive:
+			return check_drive_lists(drive, (func == ide_dma_good_drive));
+		case ide_dma_verbose:
+			return report_drive_dmaing(drive);
+		case ide_dma_timeout:
+	// FIXME: Many IDE chipsets do not permit command file register access
+	// FIXME: while the bus-master function is still active.
+	// FIXME: To prevent deadlock with those chipsets, we must be extremely
+	// FIXME: careful here (and in ide_intr() as well) to NOT access any
+	// FIXME: registers from the 0x1Fx/0x17x sets before terminating the
+	// FIXME: bus-master operation via the bus-master control reg.
+	// FIXME: Otherwise, chipset deadlock will occur, and some systems will
+	// FIXME: lock up completely!!
+#ifdef __IDEDMA_TIMEOUT
+			/*
+			 * Have to issue an abort and requeue the request
+			 * DMA engine got turned off by a goofy ASIC, and
+			 * we have to clean up the mess, and here is as good
+			 * as any.  Do it globally for all chipsets.
+			 */
+#if 0
+			dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+#else
+			drive->waiting_for_dma = 0;
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
+//			OUT_BYTE(0x00, dma_base);
+			/* get DMA status */
+			dma_stat = IN_BYTE(dma_base+2);
+			/* clear the INTR & ERROR bits */
+			OUT_BYTE(dma_stat|6, dma_base+2);
+			/* purge DMA mappings */
+			ide_destroy_dmatable(drive);
+#endif
+			printk("%s: %s: Lets do it again!" \
+				"stat = 0x%02x, dma_stat = 0x%02x\n",
+				drive->name, ide_dmafunc_verbose(func),
+				GET_STAT(), dma_stat);
+
+			if (dma_stat & 0xF0)
+				return ide_dma_timeout_recovery(drive);
+#endif /* __IDEDMA_TIMEOUT */
+		case ide_dma_retune:
+		case ide_dma_lostirq:
+			printk("ide_dmaproc: chipset supported %s "
+				"func only: %d\n",
+				ide_dmafunc_verbose(func),  func);
+			return 1;
+		default:
+			printk("ide_dmaproc: unsupported %s func: %d\n",
+				ide_dmafunc_verbose(func), func);
+			return 1;
+	}
+}
+
+/*
+ * Needed for allowing full modular support of ide-driver
+ */
+int ide_release_dma (ide_hwif_t *hwif)
+{
+	if (hwif->dmatable_cpu) {
+		pci_free_consistent(hwif->pci_dev,
+				    PRD_ENTRIES * PRD_BYTES,
+				    hwif->dmatable_cpu,
+				    hwif->dmatable_dma);
+		hwif->dmatable_cpu = NULL;
+	}
+	if (hwif->sg_table) {
+		kfree(hwif->sg_table);
+		hwif->sg_table = NULL;
+	}
+	if ((hwif->dma_extra) && (hwif->channel == 0))
+		release_region((hwif->dma_base + 16), hwif->dma_extra);
+	release_region(hwif->dma_base, 8);
+	return 1;
+}
+
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+ 
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
+	if (check_region(dma_base, num_ports)) {
+		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
+		return;
+	}
+	request_region(dma_base, num_ports, hwif->name);
+	hwif->dma_base = dma_base;
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &hwif->dmatable_dma);
+	if (hwif->dmatable_cpu == NULL)
+		goto dma_alloc_failure;
+
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
+				 GFP_KERNEL);
+	if (hwif->sg_table == NULL) {
+		pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
+				    hwif->dmatable_cpu, hwif->dmatable_dma);
+		goto dma_alloc_failure;
+	}
+
+	hwif->dmaproc = &ide_dmaproc;
+
+	if (hwif->chipset != ide_trm290) {
+		byte dma_stat = IN_BYTE(dma_base+2);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	}
+	printk("\n");
+	return;
+
+dma_alloc_failure:
+	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+}
+
+/*
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ */
+unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else {
+		dma_base = pci_resource_start(dev, 4);
+		if (!dma_base) {
+			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
+			dma_base = 0;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	if ((!dma_base) && (!second_chance)) {
+		unsigned long set_bmiba = 0;
+		second_chance++;
+		switch(dev->vendor) {
+			case PCI_VENDOR_ID_AL:
+				set_bmiba = DEFAULT_BMALIBA; break;
+			case PCI_VENDOR_ID_VIA:
+				set_bmiba = DEFAULT_BMCRBA; break;
+			case PCI_VENDOR_ID_INTEL:
+				set_bmiba = DEFAULT_BMIBA; break;
+			default:
+				return dma_base;
+		}
+		pci_write_config_dword(dev, 0x20, set_bmiba|1);
+		goto second_chance_to_dma;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (dma_base) {
+		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
+			request_region(dma_base+16, extra, name);
+		dma_base += hwif->channel ? 8 : 0;
+		hwif->dma_extra = extra;
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_AL_M5219:
+			case PCI_DEVICE_ID_AMD_VIPER_7409:
+			case PCI_DEVICE_ID_CMD_643:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				OUT_BYTE(IN_BYTE(dma_base+2) & 0x60, dma_base+2);
+				if (IN_BYTE(dma_base+2) & 0x80) {
+					printk("%s: simplex device: DMA forced\n", name);
+				}
+				break;
+			default:
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				if ((IN_BYTE(dma_base+2) & 0x80)) {	/* simplex device? */
+					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
+					    (hwif->mate && hwif->mate->dma_base)) {
+						printk("%s: simplex device:  DMA disabled\n", name);
+						dma_base = 0;
+					}
+				}
+		}
+	}
+	return dma_base;
+}
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/ide-floppy.c	Tue Aug 27 12:28:08 2002
@@ -1,4 +1,6 @@
 /*
+ * linux/drivers/ide/ide-floppy.c	Version 0.99	Feb 24 2002
+ *
  * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
  * Copyright (C) 2000 - 2002 Paul Bristow <paul@paulbristow.net>
  */
@@ -74,11 +76,11 @@
  *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
  *                        drive before the drive was actually ready.
  * Ver 0.98a Oct 29 01   Expose delay value so we can play.
- * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code
- *                       to support new PocketZip drives
+ * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code 
+ *                        to support new PocketZip drives 
  */
 
-#define IDEFLOPPY_VERSION "0.99"
+#define IDEFLOPPY_VERSION "0.99.newide"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -94,10 +96,7 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/cdrom.h>
-#include <linux/buffer_head.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/atapi.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -129,6 +128,12 @@
 #define IDEFLOPPY_MAX_PC_RETRIES	3
 
 /*
+ *	With each packet command, we allocate a buffer of
+ *	IDEFLOPPY_PC_BUFFER_SIZE bytes.
+ */
+#define IDEFLOPPY_PC_BUFFER_SIZE	256
+
+/*
  *	In various places in the driver, we need to allocate storage
  *	for packet commands and requests, which will remain valid while
  *	we leave the driver to wait for an interrupt or a timeout event.
@@ -136,6 +141,37 @@
 #define IDEFLOPPY_PC_STACK		(10 + IDEFLOPPY_MAX_PC_RETRIES)
 
 /*
+ *	Our view of a packet command.
+ */
+typedef struct idefloppy_packet_command_s {
+	u8 c[12];				/* Actual packet bytes */
+	int retries;				/* On each retry, we increment retries */
+	int error;				/* Error code */
+	int request_transfer;			/* Bytes to transfer */
+	int actually_transferred;		/* Bytes actually transferred */
+	int buffer_size;			/* Size of our data buffer */
+	char *b_data;				/* Pointer which runs on the buffers */
+	int b_count;				/* Missing/Available data on the current buffer */
+	struct request *rq;			/* The corresponding request */
+	byte *buffer;				/* Data buffer */
+	byte *current_position;			/* Pointer into the above buffer */
+	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
+	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
+} idefloppy_pc_t;
+
+/*
+ *	Packet command flag bits.
+ */
+#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
+#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
+#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
+#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
+#define	PC_WRITING			5	/* Data direction */
+
+#define	PC_SUPPRESS_ERROR		6	/* Suppress error reporting */
+
+/*
  *	Removable Block Access Capabilities Page
  */
 typedef struct {
@@ -234,11 +270,11 @@
  *	of type idefloppy_floppy_t, defined below.
  */
 typedef struct {
-	struct ata_device *drive;
+	ide_drive_t *drive;
 
-	struct atapi_packet_command *pc;		/* Current packet command */
-	struct atapi_packet_command *failed_pc;		/* Last failed packet command */
-	struct atapi_packet_command pc_stack[IDEFLOPPY_PC_STACK];	/* Packet command stack */
+	idefloppy_pc_t *pc;			/* Current packet command */
+	idefloppy_pc_t *failed_pc; 		/* Last failed packet command */
+	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];/* Packet command stack */
 	int pc_stack_index;			/* Next free packet command storage space */
 	struct request rq_stack[IDEFLOPPY_PC_STACK];
 	int rq_stack_index;			/* We implement a circular array */
@@ -246,8 +282,8 @@
 	/*
 	 *	Last error information
 	 */
-	u8 sense_key, asc, ascq;
-	u8 ticks;		/* delay this long before sending packet command */
+	byte sense_key, asc, ascq;
+	byte ticks;		/* delay this long before sending packet command */
 	int progress_indication;
 
 	/*
@@ -310,6 +346,27 @@
 #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
 
+#if 0
+/*
+ *	Special requests for our block device strategy routine.
+ */
+#define	IDEFLOPPY_FIRST_RQ		90
+
+/*
+ * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
+ */
+#define	IDEFLOPPY_PC_RQ			90
+
+#define IDEFLOPPY_LAST_RQ		90
+
+/*
+ *	A macro which can be used to check if a given request command
+ *	originated in the driver or in the buffer cache layer.
+ */
+#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+
+#endif
+
 /*
  *	Error codes which are returned in rq->errors to the higher part
  *	of the driver.
@@ -317,6 +374,270 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
+ *	The ATAPI Status Register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned check		:1;	/* Error occurred */
+		unsigned idx		:1;	/* Reserved */
+		unsigned corr		:1;	/* Correctable error occurred */
+		unsigned drq		:1;	/* Data is request by the device */
+		unsigned dsc		:1;	/* Media access command finished */
+		unsigned reserved5	:1;	/* Reserved */
+		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
+		unsigned bsy		:1;	/* The device has access to the command block */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bsy		:1;	/* The device has access to the command block */
+		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
+		unsigned reserved5	:1;	/* Reserved */
+		unsigned dsc		:1;	/* Media access command finished */
+		unsigned drq		:1;	/* Data is request by the device */
+		unsigned corr		:1;	/* Correctable error occurred */
+		unsigned idx		:1;	/* Reserved */
+		unsigned check		:1;	/* Error occurred */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_status_reg_t;
+
+/*
+ *	The ATAPI error register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned ili		:1;	/* Illegal Length Indication */
+		unsigned eom		:1;	/* End Of Media Detected */
+		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
+		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
+		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
+		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
+		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
+		unsigned eom		:1;	/* End Of Media Detected */
+		unsigned ili		:1;	/* Illegal Length Indication */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_error_reg_t;
+
+/*
+ *	ATAPI Feature Register
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned dma		:1;	/* Using DMA or PIO */
+		unsigned reserved321	:3;	/* Reserved */
+		unsigned reserved654	:3;	/* Reserved (Tag Type) */
+		unsigned reserved7	:1;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved7	:1;	/* Reserved */
+		unsigned reserved654	:3;	/* Reserved (Tag Type) */
+		unsigned reserved321	:3;	/* Reserved */
+		unsigned dma		:1;	/* Using DMA or PIO */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_feature_reg_t;
+
+/*
+ *	ATAPI Byte Count Register.
+ */
+typedef union {
+	unsigned all			:16;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned low		:8;	/* LSB */
+		unsigned high		:8;	/* MSB */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned high		:8;	/* MSB */
+		unsigned low		:8;	/* LSB */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_bcount_reg_t;
+
+/*
+ *	ATAPI Interrupt Reason Register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
+		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
+		unsigned reserved	:6;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	:6;	/* Reserved */
+		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
+		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_ireason_reg_t;
+
+/*
+ *	ATAPI floppy Drive Select Register
+ */
+typedef union {	
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned sam_lun	:3;	/* Logical unit number */
+		unsigned reserved3	:1;	/* Reserved */
+		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
+		unsigned one5		:1;	/* Should be set to 1 */
+		unsigned reserved6	:1;	/* Reserved */
+		unsigned one7		:1;	/* Should be set to 1 */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned one7		:1;	/* Should be set to 1 */
+		unsigned reserved6	:1;	/* Reserved */
+		unsigned one5		:1;	/* Should be set to 1 */
+		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
+		unsigned reserved3	:1;	/* Reserved */
+		unsigned sam_lun	:3;	/* Logical unit number */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_drivesel_reg_t;
+
+/*
+ *	ATAPI Device Control Register
+ */
+typedef union {			
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned zero0		:1;	/* Should be set to zero */
+		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
+		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
+		unsigned one3		:1;	/* Should be set to 1 */
+		unsigned reserved4567	:4;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved4567	:4;	/* Reserved */
+		unsigned one3		:1;	/* Should be set to 1 */
+		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
+		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
+		unsigned zero0		:1;	/* Should be set to zero */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	} b;
+} idefloppy_control_reg_t;
+
+/*
+ *	The following is used to format the general configuration word of
+ *	the ATAPI IDENTIFY DEVICE command.
+ */
+struct idefloppy_id_gcw {	
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned packet_size		:2;	/* Packet Size */
+	unsigned reserved234		:3;	/* Reserved */
+	unsigned drq_type		:2;	/* Command packet DRQ type */
+	unsigned removable		:1;	/* Removable media */
+	unsigned device_type		:5;	/* Device type */
+	unsigned reserved13		:1;	/* Reserved */
+	unsigned protocol		:2;	/* Protocol type */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned protocol		:2;	/* Protocol type */
+	unsigned reserved13		:1;	/* Reserved */
+	unsigned device_type		:5;	/* Device type */
+	unsigned removable		:1;	/* Removable media */
+	unsigned drq_type		:2;	/* Command packet DRQ type */
+	unsigned reserved234		:3;	/* Reserved */
+	unsigned packet_size		:2;	/* Packet Size */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+};
+
+/*
+ *	INQUIRY packet command - Data Format
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	response_format :4;	/* Response Data Format */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	response_format :4;	/* Response Data Format */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	u8		additional_length;	/* Additional Length (total_length-4) */
+	u8		rsv5, rsv6, rsv7;	/* Reserved */
+	u8		vendor_id[8];		/* Vendor Identification */
+	u8		product_id[16];		/* Product Identification */
+	u8		revision_level[4];	/* Revision Level */
+	u8		vendor_specific[20];	/* Vendor Specific - Optional */
+	u8		reserved56t95[40];	/* Reserved - Optional */
+						/* Additional information may be returned */
+} idefloppy_inquiry_result_t;
+
+/*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned	error_code	:7;	/* Current error (0x70) */
+	unsigned	valid		:1;	/* The information field conforms to SFF-8070i */
+	u8		reserved1	:8;	/* Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	reserved2_67	:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;	/* The information field conforms to SFF-8070i */
+	unsigned	error_code	:7;	/* Current error (0x70) */
+	u8		reserved1	:8;	/* Reserved */
+	unsigned	reserved2_67	:2;
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+	u32		information __attribute__ ((packed));
+	u8		asl;			/* Additional sense length (n-7) */
+	u32		command_specific;	/* Additional command specific information */
+	u8		asc;			/* Additional Sense Code */
+	u8		ascq;			/* Additional Sense Code Qualifier */
+	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	u8		sksv[3];
+	u8		pad[2];			/* Padding to 20 bytes */
+} idefloppy_request_sense_result_t;
+
+/*
  *	Pages of the SELECT SENSE / MODE SENSE packet commands.
  */
 #define	IDEFLOPPY_CAPABILITIES_PAGE	0x1b
@@ -340,22 +661,74 @@
 	u8		reserved[4];
 } idefloppy_mode_parameter_header_t;
 
+#define IDEFLOPPY_MIN(a,b)	((a)<(b) ? (a):(b))
+#define	IDEFLOPPY_MAX(a,b)	((a)>(b) ? (a):(b))
+
 /*
- *	idefloppy_end_request is used to finish servicing a request.
+ *	Too bad. The drive wants to send us data which we are not ready to accept.
+ *	Just throw it away.
+ */
+static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		IN_BYTE(IDE_DATA_REG);
+}
+
+#if IDEFLOPPY_DEBUG_BUGS
+static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		OUT_BYTE(0, IDE_DATA_REG);
+}
+#endif /* IDEFLOPPY_DEBUG_BUGS */
+
+
+static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	BUG_ON(!(rq->flags & REQ_STARTED));
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+		add_blkdev_randomness(major(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
+
+/*
+ *	idefloppy_do_end_request is used to finish servicing a request.
  *
- *	For read/write requests, we will call ata_end_request to pass to the
+ *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static int idefloppy_end_request(struct ata_device *drive, struct request *rq, int uptodate)
+static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Reached idefloppy_end_request\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
 	switch (uptodate) {
 		case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
@@ -367,27 +740,20 @@
 	/* Why does this happen? */
 	if (!rq)
 		return 0;
-
-	if (!(rq->flags & REQ_SPECIAL)) {
-		ata_end_request(drive, rq, uptodate, 0);
+	if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+		/* our real local end request function */
+		idefloppy_end_request(drive, uptodate);
 		return 0;
 	}
-
-	spin_lock_irqsave(ch->lock, flags);
-
 	rq->errors = error;
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
-
-	spin_unlock_irqrestore(ch->lock, flags);
-
+	/* fixme: need to move this local also */
+	ide_end_drive_cmd (drive, 0, 0);
 	return 0;
 }
 
-static void idefloppy_input_buffers(struct ata_device *drive, struct request *rq,
-	struct atapi_packet_command *pc, unsigned int bcount)
+static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
 {
+	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 	int count;
 
@@ -395,32 +761,32 @@
 		if (pc->b_count == bio->bi_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request(drive, rq, 1);
+			idefloppy_do_end_request(drive, 1);
 			if ((bio = rq->bio) != NULL)
 				pc->b_count = 0;
 		}
 		if (bio == NULL) {
-			printk (KERN_ERR "%s: bio == NULL in %s, bcount == %d\n", drive->name, __FUNCTION__, bcount);
-			atapi_discard_data(drive, bcount);
+			printk (KERN_ERR "%s: bio == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
+			idefloppy_discard_data(drive, bcount);
 			return;
 		}
-		count = min_t(unsigned int, bio->bi_size - pc->b_count, bcount);
-		atapi_read(drive, bio_data(bio) + pc->b_count, count);
+		count = IDEFLOPPY_MIN(bio->bi_size - pc->b_count, bcount);
+		atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count; pc->b_count += count;
 	}
 }
 
-static void idefloppy_output_buffers(struct ata_device *drive, struct request *rq,
-		struct atapi_packet_command *pc, unsigned int bcount)
+static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
 {
+	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 	int count;
-
+	
 	while (bcount) {
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request(drive, rq, 1);
+			idefloppy_do_end_request(drive, 1);
 			if ((bio = rq->bio) != NULL) {
 				pc->b_data = bio_data(bio);
 				pc->b_count = bio->bi_size;
@@ -428,41 +794,40 @@
 		}
 		if (bio == NULL) {
 			printk (KERN_ERR "%s: bio == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
-			atapi_write_zeros (drive, bcount);
+			idefloppy_write_zeros (drive, bcount);
 			return;
 		}
-		count = min_t(unsigned int, pc->b_count, bcount);
-		atapi_write(drive, pc->b_data, count);
+		count = IDEFLOPPY_MIN (pc->b_count, bcount);
+		atapi_output_bytes (drive, pc->b_data, count);
 		bcount -= count; pc->b_data += count; pc->b_count -= count;
 	}
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static void idefloppy_update_buffers(struct ata_device *drive, struct request *rq)
+static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
+	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 
 	while ((bio = rq->bio) != NULL)
-		idefloppy_end_request(drive, rq, 1);
+		idefloppy_do_end_request(drive, 1);
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  *	idefloppy_queue_pc_head generates a new packet command request in front
  *	of the request queue, before the current request, so that it will be
  *	processed immediately, on the next pass through the driver.
  */
-static void idefloppy_queue_pc_head(struct ata_device *drive,
-		struct atapi_packet_command *pc, struct request *rq)
+static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	memset(rq, 0, sizeof(*rq));
-	rq->flags = REQ_SPECIAL;
-	/* FIXME: --mdcki */
+	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
+	rq->flags = REQ_SPECIAL;	//rq->cmd = IDEFLOPPY_PC_RQ;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
-static struct atapi_packet_command *idefloppy_next_pc_storage(struct ata_device *drive)
+static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -471,7 +836,7 @@
 	return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
 
-static struct request *idefloppy_next_rq_storage(struct ata_device *drive)
+static struct request *idefloppy_next_rq_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -484,54 +849,70 @@
  *	idefloppy_analyze_error is called on each failed packet command retry
  *	to analyze the request sense.
  */
-static void idefloppy_analyze_error(struct ata_device *drive, atapi_request_sense_result_t *result)
+static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv ?
-		(unsigned short)get_unaligned((u16 *)(result->sk_specific)):0x10000;
+	floppy->progress_indication= result->sksv[0] & 0x80 ?
+		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
 		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
 	else
 		printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
-static void idefloppy_request_sense_callback(struct ata_device *drive, struct request *rq)
+static void idefloppy_request_sense_callback (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error(drive,(atapi_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_end_request(drive, rq, 1);
+		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1);
 	} else {
 		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request(drive, rq, 0);
+		idefloppy_do_end_request(drive, 0);
 	}
 }
 
 /*
  *	General packet command callback function.
  */
-static void idefloppy_pc_callback(struct ata_device *drive, struct request *rq)
+static void idefloppy_pc_callback (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-
+	
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
+
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
+}
 
-	idefloppy_end_request(drive, rq, floppy->pc->error ? 0:1);
+/*
+ *	idefloppy_init_pc initializes a packet command.
+ */
+static void idefloppy_init_pc (idefloppy_pc_t *pc)
+{
+	memset (pc->c, 0, 12);
+	pc->retries = 0;
+	pc->flags = 0;
+	pc->request_transfer = 0;
+	pc->buffer = pc->pc_buffer;
+	pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
+	pc->b_data = NULL;
+//	pc->bio = NULL;
+	pc->callback = &idefloppy_pc_callback;
 }
 
-static void idefloppy_create_request_sense_cmd(struct atapi_packet_command *pc)
+static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idefloppy_init_pc (pc);	
 	pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
 	pc->c[4] = 255;
 	pc->request_transfer = 18;
@@ -543,136 +924,133 @@
  *	last packet command. We queue a request sense packet command in
  *	the head of the request list.
  */
-static void idefloppy_retry_pc(struct ata_device *drive)
+static void idefloppy_retry_pc (ide_drive_t *drive)
 {
-	struct atapi_packet_command *pc;
+	idefloppy_pc_t *pc;
 	struct request *rq;
-	atapi_error_reg_t error;
+	idefloppy_error_reg_t error;
 
-	error.all = IN_BYTE(IDE_ERROR_REG);
-	pc = idefloppy_next_pc_storage(drive);
-	rq = idefloppy_next_rq_storage(drive);
-	idefloppy_create_request_sense_cmd(pc);
-	idefloppy_queue_pc_head(drive, pc, rq);
+	error.all = IN_BYTE (IDE_ERROR_REG);
+	pc = idefloppy_next_pc_storage (drive);
+	rq = idefloppy_next_rq_storage (drive);
+	idefloppy_create_request_sense_cmd (pc);
+	idefloppy_queue_pc_head (drive, pc, rq);
 }
 
 /*
  *	idefloppy_pc_intr is the usual interrupt handler which will be called
  *	during a packet command.
  */
-static ide_startstop_t idefloppy_pc_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_status_reg_t status;
-	atapi_bcount_reg_t bcount;
-	atapi_ireason_reg_t ireason;
-	struct atapi_packet_command *pc = floppy->pc;
+	idefloppy_status_reg_t status;
+	idefloppy_bcount_reg_t bcount;
+	idefloppy_ireason_reg_t ireason;
+	idefloppy_pc_t *pc=floppy->pc;
+	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */	
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (udma_stop(drive)) {
+	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
 			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else {
 			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers(drive, rq);
+			idefloppy_update_buffers (drive, pc);
 		}
-# if IDEFLOPPY_DEBUG_LOG
+#if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
-# endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	ata_status(drive, 0, 0);
-	status.all = drive->status;					/* Clear the interrupt */
+	status.all = GET_STAT();	/* Clear the interrupt */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {		/* No more interrupts */
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 #endif /* IDEFLOPPY_DEBUG_LOG */
-		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
 
 		local_irq_enable();
 
-		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDEFLOPPY_DEBUG_LOG
 			printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ATA_OP_FINISHED;
+				return ide_do_reset (drive);
 			}
 			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ATA_OP_FINISHED; /* queued, but not started */
+			return ide_stopped; /* queued, but not started */
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
 			floppy->failed_pc=NULL;
-		pc->callback(drive, rq);    /* Command finished - Call the callback function */
-		return ATA_OP_FINISHED;
+		pc->callback(drive);			/* Command finished - Call the callback function */
+		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		udma_enable(drive, 0, 1);
-
-		return ATA_OP_FINISHED;
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		return ide_do_reset (drive);
 	}
-#endif
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
 	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-
-		return ATA_OP_FINISHED;
+		return ide_do_reset (drive);
 	}
-	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
+	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
 		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-
-		return ATA_OP_FINISHED;
+		return ide_do_reset (drive);
 	}
-	if (!test_bit(PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
 		if ( temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
-
-				atapi_discard_data (drive,bcount.all);
-				ata_set_handler(drive, idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
-
-				return ATA_OP_CONTINUES;
+				idefloppy_discard_data (drive,bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
 			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 		}
 	}
 	if (test_bit (PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
-			atapi_write(drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
 		else
-			idefloppy_output_buffers(drive, rq, pc, bcount.all);
+			idefloppy_output_buffers (drive, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
-			atapi_read(drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
 		else
-			idefloppy_input_buffers (drive, rq, pc, bcount.all);
+			idefloppy_input_buffers (drive, pc, bcount.all);
 	}
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	ata_set_handler(drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
-
-	return ATA_OP_CONTINUES;
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	return ide_started;
 }
 
 /*
@@ -680,31 +1058,28 @@
  * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
  * for that drive below. The algorithm is chosen based on drive type
  */
-static ide_startstop_t idefloppy_transfer_pc(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
+	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_ireason_reg_t ireason;
-	int ret;
+	idefloppy_ireason_reg_t ireason;
 
-	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
-	if (ret != ATA_OP_READY) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
-
-		return ret;
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
+		return startstop;
 	}
-
 	ireason.all = IN_BYTE(IDE_IREASON_REG);
-
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ret = ATA_OP_FINISHED;
-	} else {
-		ata_set_handler(drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-		atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
-		ret = ATA_OP_CONTINUES;
-	}
-
-	return ret;
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
+	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+	return ide_started;
 }
 
 
@@ -720,121 +1095,119 @@
  * packet, we schedule the packet transfer to occur about 2-3 ticks
  * later in transfer_pc2.
  */
-static ide_startstop_t idefloppy_transfer_pc2(struct ata_device *drive, struct request *__rq, unsigned long *wait)
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
-	*wait = IDEFLOPPY_WAIT_CMD;	/* Timeout for the packet command */
-
-	return ATA_OP_CONTINUES;
+	atapi_output_bytes(drive, floppy->pc->c, 12); /* Send the actual packet */
+	return IDEFLOPPY_WAIT_CMD;	/* Timeout for the packet command */
 }
 
-static ide_startstop_t idefloppy_transfer_pc1(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_ireason_reg_t ireason;
-	int ret;
+	ide_startstop_t startstop;
+	idefloppy_ireason_reg_t ireason;
 
-	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
-	if (ret != ATA_OP_READY) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
-
-		return ret;
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
+		return startstop;
 	}
-
 	ireason.all = IN_BYTE(IDE_IREASON_REG);
-
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ret = ATA_OP_FINISHED;
-	} else {
-
-		/*
-		 * The following delay solves a problem with ATAPI Zip 100 drives where
-		 * the Busy flag was apparently being deasserted before the unit was
-		 * ready to receive data. This was happening on a 1200 MHz Athlon
-		 * system. 10/26/01 25msec is too short, 40 and 50msec work well.
-		 * idefloppy_pc_intr will not be actually used until after the packet
-		 * is moved in about 50 msec.
-		 */
-		ata_set_handler(drive,
-				idefloppy_pc_intr,	/* service routine for packet command */
-				floppy->ticks,		/* wait this long before "failing" */
-				idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
-		ret = ATA_OP_CONTINUES;
-	}
-
-	return ret;
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+				"while issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	/* 
+	 * The following delay solves a problem with ATAPI Zip 100 drives where the
+	 * Busy flag was apparently being deasserted before the unit was ready to
+	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+	 * not be actually used until after the packet is moved in about 50 msec.
+	 */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, 
+	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	  floppy->ticks,		/* wait this long before "failing" */
+	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static ide_startstop_t idefloppy_issue_pc(struct ata_device *drive, struct request *rq,
-		struct atapi_packet_command *pc)
+static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_bcount_reg_t bcount;
+	idefloppy_bcount_reg_t bcount;
 	int dma_ok = 0;
-	ata_handler_t *pkt_xfer_routine;
+	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
 	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
+		printk (KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
 	}
-#endif
+#endif /* IDEFLOPPY_DEBUG_BUGS */
 
 	if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
 		floppy->failed_pc=pc;
 	floppy->pc=pc;							/* Set the current packet command */
 
-	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit(PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received.
 		 */
-		if (!test_bit(PC_ABORT, &pc->flags)) {
-			if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
+		if (!test_bit (PC_ABORT, &pc->flags)) {
+			if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
 				;
-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+				printk(KERN_ERR "ide-floppy: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						drive->name, pc->c[0],
+						floppy->sense_key,
+						floppy->asc, floppy->ascq);
 			}
-			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDEFLOPPY_ERROR_GENERAL;
 		}
-		floppy->failed_pc = NULL;
-		pc->callback(drive, rq);
-		return ATA_OP_FINISHED;
+		floppy->failed_pc=NULL;
+		pc->callback(drive);
+		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
+	pc->actually_transferred=0;	/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
 	bcount.all = min(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags))
-		udma_enable(drive, 0, 1);
-
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = udma_init(drive, rq);
-#endif
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	ata_irq_enable(drive, 1);
-	OUT_BYTE(dma_ok ? 1:0,IDE_FEATURE_REG);			/* Use PIO/DMA */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE(dma_ok ? 1:0,IDE_FEATURE_REG);		/* Use PIO/DMA */
 	OUT_BYTE(bcount.b.high,IDE_BCOUNTH_REG);
 	OUT_BYTE(bcount.b.low,IDE_BCOUNTL_REG);
 	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {							/* Begin DMA, if necessary */
-		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		udma_start(drive, rq);
+	if (dma_ok) {				/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	/* Can we transfer the packet when we get the interrupt or wait? */
 	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
@@ -842,54 +1215,53 @@
 	} else {
 		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
 	}
-
-	if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ata_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
-
-		return ATA_OP_CONTINUES;
+	
+	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return pkt_xfer_routine(drive, rq);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return (*pkt_xfer_routine) (drive);
 	}
 }
 
-static void idefloppy_rw_callback(struct ata_device *drive, struct request *rq)
+static void idefloppy_rw_callback (ide_drive_t *drive)
 {
-#if IDEFLOPPY_DEBUG_LOG
+#if IDEFLOPPY_DEBUG_LOG	
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(drive, rq, 1);
+	idefloppy_do_end_request(drive, 1);
 	return;
 }
 
-static void idefloppy_create_prevent_cmd(struct atapi_packet_command *pc, int prevent)
+static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
 {
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent);
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
-	atapi_init_pc (pc);
+	idefloppy_init_pc (pc);
 	pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
 	pc->c[4] = prevent;
-	pc->callback = idefloppy_pc_callback;
 }
 
-static void idefloppy_create_read_capacity_cmd(struct atapi_packet_command *pc)
+static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idefloppy_init_pc (pc);
 	pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
 	pc->request_transfer = 255;
-	pc->callback = idefloppy_pc_callback;
 }
 
-static void idefloppy_create_format_unit_cmd(struct atapi_packet_command *pc,
-		int b, int l, int flags)
+static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
+					      int flags)
 {
-	atapi_init_pc (pc);
+	idefloppy_init_pc (pc);
 	pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
 	pc->c[1] = 0x17;
 
@@ -903,19 +1275,18 @@
 
 	put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4]));
 	put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8]));
-	pc->buffer_size = 12;
+	pc->buffer_size=12;
 	set_bit(PC_WRITING, &pc->flags);
-	pc->callback = idefloppy_pc_callback;
 }
 
 /*
  *	A mode sense command is used to "sense" floppy parameters.
  */
-static void idefloppy_create_mode_sense_cmd(struct atapi_packet_command *pc, u8 page_code, u8 type)
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, byte page_code, byte type)
 {
-	unsigned short length = sizeof(idefloppy_mode_parameter_header_t);
-
-	atapi_init_pc(pc);
+	unsigned short length = sizeof (idefloppy_mode_parameter_header_t);
+	
+	idefloppy_init_pc (pc);
 	pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
 	pc->c[1] = 0;
 	pc->c[2] = page_code + (type << 6);
@@ -930,28 +1301,24 @@
 		default:
 			printk (KERN_ERR "ide-floppy: unsupported page code in create_mode_sense_cmd\n");
 	}
-	put_unaligned(htons(length), (unsigned short *) &pc->c[7]);
+	put_unaligned (htons (length), (unsigned short *) &pc->c[7]);
 	pc->request_transfer = length;
-	pc->callback = idefloppy_pc_callback;
 }
 
-static void idefloppy_create_start_stop_cmd(struct atapi_packet_command *pc, int start)
+static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
 {
-	atapi_init_pc(pc);
+	idefloppy_init_pc (pc);
 	pc->c[0] = IDEFLOPPY_START_STOP_CMD;
 	pc->c[4] = start;
-	pc->callback = idefloppy_pc_callback;
 }
 
-static void idefloppy_create_test_unit_ready_cmd(struct atapi_packet_command *pc)
+static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
-	pc->callback = idefloppy_pc_callback;
 }
 
-static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
-		struct atapi_packet_command *pc, struct request *rq, sector_t sector)
+static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
 {
 	int block = sector / floppy->bs_factor;
 	int blocks = rq->nr_sectors / floppy->bs_factor;
@@ -960,9 +1327,9 @@
 #if IDEFLOPPY_DEBUG_LOG
 	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
 		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
-	atapi_init_pc(pc);
+	idefloppy_init_pc (pc);
 	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
 		put_unaligned(htonl (blocks), (unsigned int *) &pc->c[6]);
@@ -970,89 +1337,93 @@
 		pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
 		put_unaligned(htons (blocks), (unsigned short *) &pc->c[7]);
 	}
-	put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
-	pc->callback = idefloppy_rw_callback;
+	put_unaligned(htonl (block), (unsigned int *) &pc->c[2]);
+	pc->callback = &idefloppy_rw_callback;
+	pc->rq = rq;
 	pc->b_data = rq->buffer;
 	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
 	if (rq->flags & REQ_RW)
-		set_bit(PC_WRITING, &pc->flags);
+		set_bit (PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-	set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+	set_bit (PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
- * This is our request handling function.
+ *	idefloppy_do_request is our request handling function.	
  */
-static ide_startstop_t idefloppy_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command *pc;
+	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
-#endif
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",
+			rq->rq_status, (unsigned int) rq->rq_dev,
+			rq->flags, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+			"current_nr_sectors: %ld\n", rq->sector,
+			rq->nr_sectors, rq->current_nr_sectors);
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc != NULL)
-			printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+			printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+					" key = %2x, asc = %2x, ascq = %2x\n",
+				drive->name, floppy->failed_pc->c[0],
+				floppy->sense_key, floppy->asc, floppy->ascq);
 		else
-			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-
-		idefloppy_end_request(drive, rq, 0);
-
-		return ATA_OP_FINISHED;
+			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+				drive->name);
+		idefloppy_do_end_request(drive, 0);
+		return ide_stopped;
 	}
 	if (rq->flags & REQ_CMD) {
-		if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-			printk ("%s: unsupported r/w request size\n", drive->name);
-
-			idefloppy_end_request(drive, rq, 0);
-
-			return ATA_OP_FINISHED;
+		if ((rq->sector % floppy->bs_factor) ||
+		    (rq->nr_sectors % floppy->bs_factor)) {
+			printk("%s: unsupported r/w request size\n",
+				drive->name);
+			idefloppy_do_end_request(drive, 0);
+			return ide_stopped;
 		}
-		pc = idefloppy_next_pc_storage(drive);
+		pc = idefloppy_next_pc_storage (drive);
 		idefloppy_create_rw_cmd (floppy, pc, rq, block);
 	} else if (rq->flags & REQ_SPECIAL) {
-		/* FIXME: --mdcki */
-		pc = (struct atapi_packet_command *) rq->buffer;
+		pc = (idefloppy_pc_t *) rq->buffer;
 	} else {
-		blk_dump_rq_flags(rq, "ide-floppy: unsupported command in queue");
-
-		idefloppy_end_request(drive, rq, 0);
-
-		return ATA_OP_FINISHED;
+		blk_dump_rq_flags(rq,
+			"ide-floppy: unsupported command in queue");
+		idefloppy_do_end_request(drive, 0);
+		return ide_stopped;
 	}
 
-	return idefloppy_issue_pc(drive, rq, pc);
+	pc->rq = rq;
+	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
  *	idefloppy_queue_pc_tail adds a special packet command request to the
  *	tail of the request queue, and waits for it to be serviced.
  */
-static int idefloppy_queue_pc_tail(struct ata_device *drive, struct atapi_packet_command *pc)
+static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
 {
 	struct request rq;
 
-	memset(&rq, 0, sizeof(rq));
-	/* FIXME: --mdcki */
+	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.flags = REQ_SPECIAL;
+	rq.flags = REQ_SPECIAL;		//	rq.cmd = IDEFLOPPY_PC_RQ;
 
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
 /*
  *	Look at the flexible disk page parameters. We will ignore the CHS
  *	capacity parameters and use the LBA parameters instead.
  */
-static int idefloppy_get_flexible_disk_page(struct ata_device *drive)
+static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_flexible_disk_page_t *page;
 	int capacity, lba_capacity;
@@ -1072,8 +1443,10 @@
 	page->rpm = ntohs (page->rpm);
 	capacity = page->cyls * page->heads * page->sectors * page->sector_size;
 	if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
-		printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
-			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
+		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+				"%d sector size, %d rpm\n",
+			drive->name, capacity / 1024, page->cyls,
+			page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 
 	floppy->flexible_disk_page = *page;
@@ -1082,23 +1455,23 @@
 	drive->bios_sect = page->sectors;
 	lba_capacity = floppy->blocks * floppy->block_size;
 	if (capacity < lba_capacity) {
-		printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
-			"but the drive only handles %d\n",
+		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
 	}
 	return 0;
 }
 
-static int idefloppy_get_capability_page(struct ata_device *drive)
+static int idefloppy_get_capability_page(ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_capabilities_page_t *page;
 
 	floppy->srfp=0;
-	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE,
 						 MODE_SENSE_CURRENT);
 
 	set_bit(PC_SUPPRESS_ERROR, &pc.flags);
@@ -1116,14 +1489,14 @@
  *	Determine if a media is present in the floppy drive, and if so,
  *	its LBA capacity.
  */
-static int idefloppy_get_capacity(struct ata_device *drive)
+static int idefloppy_get_capacity (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 	idefloppy_capacity_header_t *header;
 	idefloppy_capacity_descriptor_t *descriptor;
 	int i, descriptors, rc = 1, blocks, length;
-
+	
 	drive->bios_cyl = 0;
 	drive->bios_head = drive->bios_sect = 0;
 	floppy->blocks = floppy->bs_factor = 0;
@@ -1142,9 +1515,9 @@
                 blocks = descriptor->blocks = ntohl (descriptor->blocks);
                 length = descriptor->length = ntohs (descriptor->length);
 
-		if (!i)
+		if (!i) 
 		{
-			switch (descriptor->dc) {
+          	switch (descriptor->dc) {
                 case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */
                         if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
                                 break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */
@@ -1178,8 +1551,7 @@
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-	{
+        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
 		(void) idefloppy_get_flexible_disk_page (drive);
 	}
 
@@ -1208,12 +1580,12 @@
 **
 */
 
-static int idefloppy_get_format_capacities(struct ata_device *drive,
-		struct inode *inode,
-		struct file *file,
-		int *arg)	/* Cheater */
+static int idefloppy_get_format_capacities (ide_drive_t *drive,
+					    struct inode *inode,
+					    struct file *file,
+					    int *arg)	/* Cheater */
 {
-        struct atapi_packet_command pc;
+        idefloppy_pc_t pc;
 	idefloppy_capacity_header_t *header;
         idefloppy_capacity_descriptor_t *descriptor;
 	int i, descriptors, blocks, length;
@@ -1227,8 +1599,8 @@
 	if (u_array_size <= 0)
 		return (-EINVAL);
 
-	idefloppy_create_read_capacity_cmd(&pc);
-	if (idefloppy_queue_pc_tail(drive, &pc)) {
+	idefloppy_create_read_capacity_cmd (&pc);
+	if (idefloppy_queue_pc_tail (drive, &pc)) {
 		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                 return (-EIO);
         }
@@ -1288,7 +1660,7 @@
 **        0x01 - verify media after format.
 */
 
-static int idefloppy_begin_format(struct ata_device *drive,
+static int idefloppy_begin_format(ide_drive_t *drive,
 				  struct inode *inode,
 				  struct file *file,
 				  int *arg)
@@ -1296,7 +1668,7 @@
 	int blocks;
 	int length;
 	int flags;
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 
 	if (get_user(blocks, arg)
 	    || get_user(length, arg+1)
@@ -1307,9 +1679,10 @@
 
 	(void) idefloppy_get_capability_page (drive);	/* Get the SFRP bit */
 	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-	if (idefloppy_queue_pc_tail(drive, &pc))
-                return -EIO;
-
+	if (idefloppy_queue_pc_tail (drive, &pc))
+	{
+                return (-EIO);
+        }
 	return (0);
 }
 
@@ -1323,13 +1696,13 @@
 ** the dsc bit, and return either 0 or 65536.
 */
 
-static int idefloppy_get_format_progress(struct ata_device *drive,
-		struct inode *inode,
-		struct file *file,
-		int *arg)
+static int idefloppy_get_format_progress(ide_drive_t *drive,
+					 struct inode *inode,
+					 struct file *file,
+					 int *arg)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 	int progress_indication=0x10000;
 
 	if (floppy->srfp)
@@ -1346,17 +1719,15 @@
 			progress_indication=floppy->progress_indication;
 		}
 		/* Else assume format_unit has finished, and we're
-		 * at 0x10000
-		 */
+		** at 0x10000 */
 	}
 	else
 	{
-		atapi_status_reg_t status;
+		idefloppy_status_reg_t status;
 		unsigned long flags;
 
 		local_irq_save(flags);
-		ata_status(drive, 0, 0);
-		status.all = drive->status;
+		status.all=GET_STAT();
 		local_irq_restore(flags);
 
 		progress_indication= !status.b.dsc ? 0:0x10000;
@@ -1372,10 +1743,10 @@
  *
  *	Currently there aren't any ioctl's.
  */
-static int idefloppy_ioctl(struct ata_device *drive, struct inode *inode, struct file *file,
+static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 				 unsigned int cmd, unsigned long arg)
 {
-	struct atapi_packet_command pc;
+	idefloppy_pc_t pc;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	int prevent = (arg) ? 1 : 0;
 
@@ -1389,8 +1760,8 @@
 
 		/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd(&pc, prevent);
-			(void) idefloppy_queue_pc_tail(drive, &pc);
+			idefloppy_create_prevent_cmd (&pc, prevent);
+			(void) idefloppy_queue_pc_tail (drive, &pc);
 		}
 		if (cmd == CDROMEJECT) {
 			idefloppy_create_start_stop_cmd (&pc, 2);
@@ -1452,14 +1823,14 @@
 /*
  *	Our open/release functions
  */
-static int idefloppy_open(struct inode *inode, struct file *filp, struct ata_device *drive)
+static int idefloppy_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct atapi_packet_command pc;
-
+	idefloppy_pc_t pc;
+	
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Reached idefloppy_open\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
 	MOD_INC_USE_COUNT;
 	if (drive->usage == 1) {
@@ -1489,7 +1860,7 @@
 			drive->usage--;
 			MOD_DEC_USE_COUNT;
 			return -EROFS;
-		}
+		}		
 		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
@@ -1507,13 +1878,13 @@
 	return 0;
 }
 
-static void idefloppy_release(struct inode *inode, struct file *filp, struct ata_device *drive)
+static void idefloppy_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
-	struct atapi_packet_command pc;
-
+	idefloppy_pc_t pc;
+	
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Reached idefloppy_release\n");
-#endif
+#endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (!drive->usage) {
 		idefloppy_floppy_t *floppy = drive->driver_data;
@@ -1532,17 +1903,25 @@
 /*
  *	Check media change. Use a simple algorithm for now.
  */
-static int idefloppy_check_media_change(struct ata_device *drive)
+static int idefloppy_media_change (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
+	
+	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+}
 
-	return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+/*
+ *	Revalidate the new media. Should set blk_size[]
+ */
+static void idefloppy_revalidate (ide_drive_t *drive)
+{
+	ide_revalidate_drive(drive);
 }
 
 /*
  *	Return the current floppy capacity to ide.c.
  */
-static unsigned long idefloppy_capacity(struct ata_device *drive)
+static unsigned long idefloppy_capacity (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	unsigned long capacity = floppy->blocks * floppy->bs_factor;
@@ -1554,9 +1933,9 @@
  *	idefloppy_identify_device checks if we can support a drive,
  *	based on the ATAPI IDENTIFY command results.
  */
-static int idefloppy_identify_device(struct ata_device *drive,struct hd_driveid *id)
+static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
 {
-	struct atapi_id_gcw gcw;
+	struct idefloppy_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
 	unsigned short mask,i;
 	char buffer[80];
@@ -1666,12 +2045,26 @@
 	return 0;
 }
 
+static void idefloppy_add_settings(ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+
+/*
+ *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ */
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
+	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
+
+}
+
 /*
  *	Driver initialization.
  */
-static void idefloppy_setup(struct ata_device *drive, idefloppy_floppy_t *floppy)
+static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
 {
-	struct atapi_id_gcw gcw;
+	struct idefloppy_id_gcw gcw;
 	int i;
 
 	*((unsigned short *) &gcw) = drive->id->config;
@@ -1694,120 +2087,203 @@
 	 */
 
 	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
+	{
+		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
+		/* This value will be visible in the /proc/ide/hdx/settings */
+		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
 		blk_queue_max_sectors(&drive->queue, 64);
+	}
 
 	/*
 	*      Guess what?  The IOMEGA Clik! drive also needs the
 	*      above fix.  It makes nasty clicking noises without
 	*      it, so please don't remove this.
 	*/
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
+	{
 		blk_queue_max_sectors(&drive->queue, 64);
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
-	(void) idefloppy_get_capacity (drive);
 
+	(void) idefloppy_get_capacity (drive);
+	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_channel *hwif = drive->channel;
+		ide_hwif_t *hwif = HWIF(drive);
 
 		if (drive != &hwif->drives[i]) continue;
-		hwif->gd[i]->de_arr[0] = drive->de;
+		hwif->gd[i]->de_arr[i] = drive->de;
 		if (drive->removable)
-			hwif->gd[i]->flags[0] |= GENHD_FL_REMOVABLE;
+			hwif->gd[i]->flags[i] |= GENHD_FL_REMOVABLE;
 		break;
 	}
 }
 
-static int idefloppy_cleanup(struct ata_device *drive)
+static int idefloppy_cleanup (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (ata_unregister_device(drive))
+	if (ide_unregister_subdriver (drive))
 		return 1;
 	drive->driver_data = NULL;
-	kfree(floppy);
+	kfree (floppy);
 	return 0;
 }
 
-static void idefloppy_attach(struct ata_device *drive);
+#ifdef CONFIG_PROC_FS
+
+static ide_proc_entry_t idefloppy_proc[] = {
+	{ "geometry",	S_IFREG|S_IRUGO,	proc_ide_read_geometry,	NULL },
+	{ NULL, 0, NULL, NULL }
+};
+
+#else
+
+#define	idefloppy_proc	NULL
+
+#endif	/* CONFIG_PROC_FS */
+
+int idefloppy_init (void);
+int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
  */
-static struct ata_operations idefloppy_driver = {
-	.owner =		THIS_MODULE,
-	.attach =		idefloppy_attach,
-	.cleanup =		idefloppy_cleanup,
-	.standby =		NULL,
-	.do_request =		idefloppy_do_request,
-	.end_request =		idefloppy_end_request,
-	.ioctl =		idefloppy_ioctl,
-	.open =			idefloppy_open,
-	.release =		idefloppy_release,
-	.check_media_change =	idefloppy_check_media_change,
-	.revalidate =		NULL, /* use default method */
-	.capacity =		idefloppy_capacity,
+static ide_driver_t idefloppy_driver = {
+	name:			"ide-floppy",
+	version:		IDEFLOPPY_VERSION,
+	media:			ide_floppy,
+	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
+	supports_dma:		1,
+#endif
+	supports_dsc_overlap:	0,
+	cleanup:		idefloppy_cleanup,
+	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
+	flushcache:		NULL,
+	do_request:		idefloppy_do_request,
+	end_request:		idefloppy_do_end_request,
+	sense:			NULL,
+	error:			NULL,
+	ioctl:			idefloppy_ioctl,
+	open:			idefloppy_open,
+	release:		idefloppy_release,
+	media_change:		idefloppy_media_change,
+	revalidate:		idefloppy_revalidate,
+	pre_reset:		NULL,
+	capacity:		idefloppy_capacity,
+	special:		NULL,
+	proc:			idefloppy_proc,
+	init:			idefloppy_init,
+	reinit:			idefloppy_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
+};
+
+static ide_module_t idefloppy_module = {
+	IDE_DRIVER_MODULE,
+	idefloppy_init,
+	&idefloppy_driver,
+	NULL
 };
 
-static void idefloppy_attach(struct ata_device *drive)
+int idefloppy_reinit (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	char *req;
-	struct ata_channel *channel;
-	struct gendisk *disk;
-	int unit;
-
-	if (drive->type != ATA_FLOPPY)
-		return;
-
-	req = drive->driver_req;
-	if (req[0] != '\0' && strcmp(req, "ide-floppy"))
-		return;
+	int failed = 0;
 
-	if (!idefloppy_identify_device (drive, drive->id)) {
-		printk (KERN_ERR "ide-floppy: %s: not supported by this version of driver\n",
-				drive->name);
-		return;
-	}
-
-	if (drive->scsi) {
-		printk(KERN_INFO "ide-floppy: passing drive %s to ide-scsi emulation.\n",
-				drive->name);
-		return;
-	}
-	if (!(floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL))) {
-		printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n",
-				drive->name);
-		return;
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
 	}
-	if (ata_register_device(drive, &idefloppy_driver)) {
-		printk(KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (floppy);
-		return;
-	}
-
-	idefloppy_setup(drive, floppy);
-
-	channel = drive->channel;
-	unit = drive - channel->drives;
-	disk = channel->gd[unit];
-	disk->minor_shift = PARTN_BITS;
-	register_disk(disk, mk_kdev(disk->major, disk->first_minor),
-			1<<disk->minor_shift, disk->fops,
-			idefloppy_capacity(drive));
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
-static void __exit idefloppy_exit(void)
+static void __exit idefloppy_exit (void)
 {
-	unregister_ata_driver(&idefloppy_driver);
+	ide_drive_t *drive;
+	int failed = 0;
+
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
+		if (idefloppy_cleanup (drive)) {
+			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+			failed++;
+		}
+		/* We must remove proc entries defined in this module.
+		   Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
+		if (drive->proc)
+			ide_remove_proc_entries(drive->proc, idefloppy_proc);
+#endif
+	}
+	ide_unregister_module(&idefloppy_module);
 }
 
-int __init idefloppy_init(void)
+/*
+ *	idefloppy_init will register the driver for each floppy.
+ */
+int idefloppy_init (void)
 {
-	return ata_driver_module(&idefloppy_driver);
+	ide_drive_t *drive;
+	idefloppy_floppy_t *floppy;
+	int failed = 0;
+
+	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 module_init(idefloppy_init);
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-geometry.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,224 @@
+/*
+ * linux/drivers/ide/ide-geometry.c
+ */
+#include <linux/config.h>
+#include <linux/ide.h>
+#include <linux/mc146818rtc.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_IDE
+
+/*
+ * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
+ * controller that is BIOS compatible with ST-506, and thus showing up in our
+ * BIOS table, but not register compatible, and therefore not present in CMOS.
+ *
+ * Furthermore, we will assume that our ST-506 drives <if any> are the primary
+ * drives in the system -- the ones reflected as drive 1 or 2.  The first
+ * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
+ * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
+ * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
+ * means we have an AT controller hard disk for that drive.
+ *
+ * Of course, there is no guarantee that either drive is actually on the
+ * "primary" IDE interface, but we don't bother trying to sort that out here.
+ * If a drive is not actually on the primary interface, then these parameters
+ * will be ignored.  This results in the user having to supply the logical
+ * drive geometry as a boot parameter for each drive not on the primary i/f.
+ */
+/*
+ * The only "perfect" way to handle this would be to modify the setup.[cS] code
+ * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
+ * for us during initialization.  I have the necessary docs -- any takers?  -ml
+ */
+/*
+ * I did this, but it doesnt work - there is no reasonable way to find the
+ * correspondence between the BIOS numbering of the disks and the Linux
+ * numbering. -aeb
+ *
+ * The code below is bad. One of the problems is that drives 1 and 2
+ * may be SCSI disks (even when IDE disks are present), so that
+ * the geometry we read here from BIOS is attributed to the wrong disks.
+ * Consequently, also the former "drive->present = 1" below was a mistake.
+ *
+ * Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
+ */
+
+void probe_cmos_for_drives (ide_hwif_t *hwif)
+{
+#ifdef __i386__
+	extern struct drive_info_struct drive_info;
+	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	int unit;
+	unsigned long flags;
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
+		return;
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+	spin_lock_irqsave(&rtc_lock, flags);
+	cmos_disks = CMOS_READ(0x12);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	/* Extract drive geometry from CMOS+BIOS if not already setup */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if ((cmos_disks & (0xf0 >> (unit*4)))
+		   && !drive->present && !drive->nobios) {
+			unsigned short cyl = *(unsigned short *)BIOS;
+			unsigned char head = *(BIOS+2);
+			unsigned char sect = *(BIOS+14);
+			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
+				drive->cyl   = drive->bios_cyl  = cyl;
+				drive->head  = drive->bios_head = head;
+				drive->sect  = drive->bios_sect = sect;
+				drive->ctl   = *(BIOS+8);
+			} else {
+				printk("hd%c: C/H/S=%d/%d/%d from BIOS ignored\n",
+				       unit+'a', cyl, head, sect);
+			}
+		}
+
+		BIOS += 16;
+	}
+#endif
+}
+#endif /* CONFIG_BLK_DEV_IDE */
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+
+extern ide_drive_t * get_info_ptr(kdev_t);
+extern unsigned long current_capacity (ide_drive_t *);
+
+/*
+ * If heads is nonzero: find a translation with this many heads and S=63.
+ * Otherwise: find out how OnTrack Disk Manager would translate the disk.
+ */
+static void
+ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
+	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const byte *headp = dm_head_vals;
+	unsigned long total;
+
+	/*
+	 * The specs say: take geometry as obtained from Identify,
+	 * compute total capacity C*H*S from that, and truncate to
+	 * 1024*255*63. Now take S=63, H the first in the sequence
+	 * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+	 * [Please tell aeb@cwi.nl in case this computes a
+	 * geometry different from what OnTrack uses.]
+	 */
+	total = DRIVER(drive)->capacity(drive);
+
+	*s = 63;
+
+	if (heads) {
+		*h = heads;
+		*c = total / (63 * heads);
+		return;
+	}
+
+	while (63 * headp[0] * 1024 < total && headp[1] != 0)
+		 headp++;
+	*h = headp[0];
+	*c = total / (63 * headp[0]);
+}
+
+/*
+ * This routine is called from the partition-table code in pt/msdos.c.
+ * It has two tasks:
+ * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
+ *  or to handle EZdrive by remapping sector 0 to sector 1.
+ * (ii) to invent a translated geometry.
+ * Part (i) is suppressed if the user specifies the "noremap" option
+ * on the command line.
+ * Part (ii) is suppressed if the user specifies an explicit geometry.
+ *
+ * The ptheads parameter is either 0 or tells about the number of
+ * heads shown by the end of the first nonempty partition.
+ * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
+ *
+ * The xparm parameter has the following meaning:
+ *	 0 = convert to CHS with fewer than 1024 cyls
+ *	     using the same method as Ontrack DiskManager.
+ *	 1 = same as "0", plus offset everything by 63 sectors.
+ *	-1 = similar to "0", plus redirect sector 0 to sector 1.
+ *	 2 = convert to a CHS geometry with "ptheads" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not 
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
+ */
+int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
+{
+	ide_drive_t *drive;
+	const char *msg1 = "";
+	int heads = 0;
+	int c, h, s;
+	int transl = 1;		/* try translation */
+	int ret = 0;
+
+	drive = get_info_ptr(i_rdev);
+	if (!drive)
+		return 0;
+
+	/* remap? */
+	if (drive->remap_0_to_1 != 2) {
+		if (xparm == 1) {		/* DM */
+			drive->sect0 = 63;
+			msg1 = " [remap +63]";
+			ret = 1;
+		} else if (xparm == -1) {	/* EZ-Drive */
+			if (drive->remap_0_to_1 == 0) {
+				drive->remap_0_to_1 = 1;
+				msg1 = " [remap 0->1]";
+				ret = 1;
+			}
+		}
+	}
+
+	/* There used to be code here that assigned drive->id->CHS
+	   to drive->CHS and that to drive->bios_CHS. However,
+	   some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
+	   In such cases that code was wrong.  Moreover,
+	   there seems to be no reason to do any of these things. */
+
+	/* translate? */
+	if (drive->forced_geom)
+		transl = 0;
+
+	/* does ptheads look reasonable? */
+	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
+	    ptheads == 240 || ptheads == 255)
+		heads = ptheads;
+
+	if (xparm == 2) {
+		if (!heads ||
+		   (drive->bios_head >= heads && drive->bios_sect == 63))
+			transl = 0;
+	}
+	if (xparm == -1) {
+		if (drive->bios_head > 16)
+			transl = 0;     /* we already have a translation */
+	}
+
+	if (transl) {
+		ontrack(drive, heads, &c, &h, &s);
+		drive->bios_cyl = c;
+		drive->bios_head = h;
+		drive->bios_sect = s;
+		ret = 1;
+	}
+
+	drive->part[0].nr_sects = current_capacity(drive);
+
+	if (ret)
+		printk("%s%s [%d/%d/%d]", msg, msg1,
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	return ret;
+}
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -Nru a/drivers/ide/ide-m8xx.c b/drivers/ide/ide-m8xx.c
--- a/drivers/ide/ide-m8xx.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/ide/ide-m8xx.c	Tue Aug 27 12:28:08 2002
@@ -29,9 +29,8 @@
 #include <linux/init.h>
 #include <linux/blk.h>
 #include <linux/ioport.h>
-#include <linux/bootmem.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/bootmem.h>
 
 #include <asm/mpc8xx.h>
 #include <asm/mmu.h>
@@ -44,15 +43,14 @@
 #include <asm/machdep.h>
 #include <asm/irq.h>
 
-#include "timing.h"
-
+#include "ide_modes.h"
 static int identify  (volatile unsigned char *p);
 static void print_fixed (volatile unsigned char *p);
 static void print_funcid (int func);
 static int check_ide_device (unsigned long base);
 
-static int ide_interrupt_ack(struct ata_channel *);
-static void m8xx_ide_tuneproc(struct ata_device *drive, u8 pio);
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio);
 
 typedef	struct ide_ioport_desc {
 	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
@@ -97,12 +95,6 @@
 #endif	/* IDE0_BASE_OFFSET */
 };
 
-typedef struct ide_pio_timings_s {
-	int	setup_time;	/* Address setup (ns) minimum */
-	int	active_time;	/* Active pulse (ns) minimum */
-	int	cycle_time;	/* Cycle time (ns) minimum = (setup + active + recovery) */
-} ide_pio_timings_t;
-
 ide_pio_timings_t ide_pio_clocks[6];
 int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
 
@@ -236,19 +228,19 @@
 		/* Compute clock cycles for PIO timings */
 		for (i=0; i<6; ++i) {
 			bd_t	*binfo = (bd_t *)__res;
-			struct ata_timing *t;
-
-			t = ata_timing_data(i + XFER_PIO_0);
 
 			hold_time[i]   =
 				PCMCIA_MK_CLKS (hold_time[i],
 						binfo->bi_busfreq);
 			ide_pio_clocks[i].setup_time  =
-				PCMCIA_MK_CLKS (t->setup, binfo->bi_busfreq);
+				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+						binfo->bi_busfreq);
 			ide_pio_clocks[i].active_time =
-				PCMCIA_MK_CLKS (t->active, binfo->bi_busfreq);
+				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+						binfo->bi_busfreq);
 			ide_pio_clocks[i].cycle_time  =
-				PCMCIA_MK_CLKS (t->cycle, binfo->bi_busfreq);
+				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+						binfo->bi_busfreq);
 #if 0
 			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
 				i,
@@ -256,7 +248,10 @@
 				ide_pio_clocks[i].active_time,
 				ide_pio_clocks[i].hold_time,
 				ide_pio_clocks[i].cycle_time,
-				t->setup, t->active, hold_time[i], t->cycle);
+				ide_pio_timings[i].setup_time,
+				ide_pio_timings[i].active_time,
+				ide_pio_timings[i].hold_time,
+				ide_pio_timings[i].cycle_time);
 #endif
 		}
 	}
@@ -327,7 +322,7 @@
 	/* register routine to tune PIO mode */
 	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
 
-	hw->ack_intr = ide_interrupt_ack;
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
 	/* Enable Harddisk Interrupt,
 	 * and make it edge sensitive
 	 */
@@ -402,7 +397,7 @@
 			ioport_dsc[data_port].reg_off[i],
 			i, base + ioport_dsc[data_port].reg_off[i]);
 #endif
-		*p++ = base + ioport_dsc[data_port].reg_off[i];
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
 	}
 
 	if (irq) {
@@ -413,16 +408,16 @@
 	/* register routine to tune PIO mode */
 	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
 
-	hw->ack_intr = ide_interrupt_ack;
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
 	/* Enable Harddisk Interrupt,
 	 * and make it edge sensitive
 	 */
 	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
 	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
 			(0x80000000 >> ioport_dsc[data_port].irq);
-}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */
+}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
 
-#endif
+#endif	/* CONFIG_IDE_8xx_DIRECT */
 
 
 /* -------------------------------------------------------------------- */
@@ -438,15 +433,15 @@
 
 /* Calculate PIO timings */
 static void
-m8xx_ide_tuneproc(struct ata_device *drive, u8 pio)
+m8xx_ide_tuneproc(ide_drive_t *drive, byte pio)
 {
+	ide_pio_data_t d;
 #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
 	volatile pcmconf8xx_t	*pcmp;
 	ulong timing, mask, reg;
 #endif
 
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
 
 #if 1
 	printk("%s[%d] %s: best PIO mode: %d\n",
@@ -494,10 +489,11 @@
 
 	printk("%s[%d] %s: not implemented yet!\n",
 		__FILE__,__LINE__,__FUNCTION__);
-#endif
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
 }
 
-static int ide_interrupt_ack(struct ata_channel *ch)
+static void
+ide_interrupt_ack (void *dev)
 {
 #ifdef CONFIG_IDE_8xx_PCCARD
 	u_int pscr, pipr;
@@ -529,18 +525,18 @@
 	/* clear the interrupt sources */
 	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
 
-#else
+#else /* ! CONFIG_IDE_8xx_PCCARD */
 	/*
 	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
 	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
 	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
 	 * The interrupt is handled somewhere else.	-- Steven
 	 */
-#endif
-
-	return 0;
+#endif /* CONFIG_IDE_8xx_PCCARD */
 }
 
+
+
 /*
  * CIS Tupel codes
  */
@@ -655,7 +651,7 @@
 				q+= 2;
 			}
 		}
-#endif
+#endif	/* DEBUG_PCMCIA */
 		switch (code) {
 		case CISTPL_VERS_1:
 			ident = p + 4;
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/ide-pci.c	Tue Aug 27 12:28:08 2002
@@ -1,15 +1,22 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
  *
- *  Copyright (C) 2002	     Marcin Dalecki <martin@dalecki.de>
- *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 1995-1998  Mark Lord
+ *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
  *
+ *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
- *  This module provides support for automatic detection and configuration of
- *  all PCI ATA host chip chanells interfaces present in a system.
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
+ */
+
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
  */
 
 #include <linux/config.h>
@@ -20,125 +27,621 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "pcihost.h"
+#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
+#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
+#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
+#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
+#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_PIIX4E	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
+#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
+#define DEVID_PIIX4U	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
+#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
+#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
+#define DEVID_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
+#define DEVID_PIIX4U4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
+#define DEVID_PIIX4U5	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
+#define DEVID_PIIX4U6	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
+#define DEVID_PIIX4U7	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
+#define DEVID_PIIX4U8   ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
+#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
+#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
+#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
+#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
+#define DEVID_PDC20263	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263})
+#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
+#define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
+#define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
+#define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20271	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271})
+#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
+#define DEVID_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
+#define DEVID_PDC20277	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277})
+#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
+#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
+#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
+#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
+#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
+#define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
+#define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
+#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
+#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
+#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
+#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
+#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
+#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
+#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
+#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
+#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
+#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
+#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
+#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
+#define DEVID_AEC6280	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865})
+#define DEVID_AEC6880	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865R})
+#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
+#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
+#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
+#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
+#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
+#define DEVID_HPT372	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT372})
+#define DEVID_HPT302	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT302})
+#define DEVID_HPT371	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT371}) 
+#define DEVID_HPT374	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT374})
+#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
+#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
+#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
+#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
+#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
+#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
+#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
+#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_OPUS_7441})
+#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
+#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
+#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
+#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
+#define DEVID_CSB6	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE})
+#define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
+
+#define	IDE_IGNORE	((void *)-1)
+#define IDE_NO_DRIVER	((void *)-2)
+
+#ifdef CONFIG_BLK_DEV_AEC62XX
+extern void fixup_device_aec6x80(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
+extern unsigned int ata66_aec62xx(ide_hwif_t *);
+extern void ide_init_aec62xx(ide_hwif_t *);
+extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
+#define FIXUP_AEC62XX	&fixup_device_aec6x80
+#define PCI_AEC62XX	&pci_init_aec62xx
+#define ATA66_AEC62XX	&ata66_aec62xx
+#define INIT_AEC62XX	&ide_init_aec62xx
+#define DMA_AEC62XX	&ide_dmacapable_aec62xx
+#else
+#define FIXUP_AEC62XX	NULL
+#define PCI_AEC62XX	NULL
+#define ATA66_AEC62XX	NULL
+#define INIT_AEC62XX	IDE_NO_DRIVER
+#define DMA_AEC62XX	NULL
+#endif
 
-/*
- * This is the list of registered PCI chipset driver data structures.
- */
-static struct ata_pci_device *ata_pci_device_list; /* = NULL */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+extern void fixup_device_ali15x3(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+extern unsigned int ata66_ali15x3(ide_hwif_t *);
+extern void ide_init_ali15x3(ide_hwif_t *);
+extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
+#define FIXUP_ALI15X3	&fixup_device_ali15x3
+#define PCI_ALI15X3	&pci_init_ali15x3
+#define ATA66_ALI15X3	&ata66_ali15x3
+#define INIT_ALI15X3	&ide_init_ali15x3
+#define DMA_ALI15X3	&ide_dmacapable_ali15x3
+#else
+#define FIXUP_ALI15X3	NULL
+#define PCI_ALI15X3	NULL
+#define ATA66_ALI15X3	NULL
+#define INIT_ALI15X3	IDE_NO_DRIVER
+#define DMA_ALI15X3	NULL
+#endif
 
-/*
- * This function supplies the data necessary to detect the particular chipset.
- *
- * Please note that we don't copy data over. We are just linking it in to the
- * list.
- */
-void ata_register_chipset(struct ata_pci_device *d)
-{
-	struct ata_pci_device *tmp;
+#ifdef CONFIG_BLK_DEV_AMD74XX
+extern void fixup_device_amd74xx(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
+extern unsigned int ata66_amd74xx(ide_hwif_t *);
+extern void ide_init_amd74xx(ide_hwif_t *);
+extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
+#define FIXUP_AMD74XX	&fixup_device_amd74xx
+#define PCI_AMD74XX	&pci_init_amd74xx
+#define ATA66_AMD74XX	&ata66_amd74xx
+#define INIT_AMD74XX	&ide_init_amd74xx
+#define DMA_AMD74XX	&ide_dmacapable_amd74xx
+#else
+#define FIXUP_AMD74XX	NULL
+#define PCI_AMD74XX	NULL
+#define ATA66_AMD74XX	NULL
+#define INIT_AMD74XX	IDE_NO_DRIVER
+#define DMA_AMD74XX	NULL
+#endif
 
-	if (!d)
-		return;
+#ifdef CONFIG_BLK_DEV_CMD64X
+extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
+extern unsigned int ata66_cmd64x(ide_hwif_t *);
+extern void ide_init_cmd64x(ide_hwif_t *);
+extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
+#define PCI_CMD64X	&pci_init_cmd64x
+#define ATA66_CMD64X	&ata66_cmd64x
+#define INIT_CMD64X	&ide_init_cmd64x
+#else
+#define PCI_CMD64X	NULL
+#define ATA66_CMD64X	NULL
+#ifdef __sparc_v9__
+#define INIT_CMD64X	IDE_IGNORE
+#else
+#define INIT_CMD64X	IDE_NO_DRIVER
+#endif
+#endif
 
-	d->next = NULL;
+#ifdef CONFIG_BLK_DEV_CY82C693
+extern void fixup_device_cy82c693(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
+extern void ide_init_cy82c693(ide_hwif_t *);
+#define FIXUP_CY82C693	&fixup_device_cy82c693
+#define PCI_CY82C693	&pci_init_cy82c693
+#define INIT_CY82C693	&ide_init_cy82c693
+#else
+#define FIXUP_CY82C693	NULL
+#define PCI_CY82C693	NULL
+#define INIT_CY82C693	IDE_NO_DRIVER
+#endif
 
-	if (!ata_pci_device_list) {
-		ata_pci_device_list = d;
+#ifdef CONFIG_BLK_DEV_CS5530
+extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
+extern void ide_init_cs5530(ide_hwif_t *);
+#define PCI_CS5530	&pci_init_cs5530
+#define INIT_CS5530	&ide_init_cs5530
+#else
+#define PCI_CS5530	NULL
+#define INIT_CS5530	IDE_NO_DRIVER
+#endif
 
-		return;
-	}
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern void fixup_device_hpt343(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
+extern void ide_init_hpt34x(ide_hwif_t *);
+#define FIXUP_HPT34X	&fixup_device_hpt343
+#define PCI_HPT34X	&pci_init_hpt34x
+#define INIT_HPT34X	&ide_init_hpt34x
+#else
+#define FIXUP_HPT34X	NULL
+#define PCI_HPT34X	NULL
+#define INIT_HPT34X	IDE_IGNORE
+#endif
 
-	tmp = ata_pci_device_list;
-	while (tmp->next) {
-		tmp = tmp->next;
-	}
+#ifdef CONFIG_BLK_DEV_HPT366
+extern void fixup_device_hpt366(struct pci_dev *, ide_pci_device_t *);
+extern void fixup_device_hpt374(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
+extern unsigned int ata66_hpt366(ide_hwif_t *);
+extern void ide_init_hpt366(ide_hwif_t *);
+extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
+#define FIXUP_HPT366	&fixup_device_hpt366
+#define FIXUP_HPT374	&fixup_device_hpt374
+#define PCI_HPT366	&pci_init_hpt366
+#define ATA66_HPT366	&ata66_hpt366
+#define INIT_HPT366	&ide_init_hpt366
+#define DMA_HPT366	&ide_dmacapable_hpt366
+#else
+#define FIXUP_HPT366	NULL
+#define FIXUP_HPT374	NULL
+#define PCI_HPT366	NULL
+#define ATA66_HPT366	NULL
+#define INIT_HPT366	IDE_NO_DRIVER
+#define DMA_HPT366	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_NS87415
+extern void ide_init_ns87415(ide_hwif_t *);
+#define INIT_NS87415	&ide_init_ns87415
+#else
+#define INIT_NS87415	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void fixup_device_opti621(struct pci_dev *, ide_pci_device_t *);
+extern void ide_init_opti621(ide_hwif_t *);
+#define FIXUP_OPTI621	&fixup_device_opti621
+#define INIT_OPTI621	&ide_init_opti621
+#else
+#define FIXUP_OPTI621	NULL
+#define INIT_OPTI621	IDE_NO_DRIVER
+#endif
+
+#ifdef CONFIG_BLK_DEV_PDC_ADMA
+extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
+extern unsigned int ata66_pdcadma(ide_hwif_t *);
+extern void ide_init_pdcadma(ide_hwif_t *);
+extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
+#define PCI_PDCADMA	&pci_init_pdcadma
+#define ATA66_PDCADMA	&ata66_pdcadma
+#define INIT_PDCADMA	&ide_init_pdcadma
+#define DMA_PDCADMA	&ide_dmacapable_pdcadma
+#else
+#define PCI_PDCADMA	IDE_IGNORE
+#define ATA66_PDCADMA	IDE_IGNORE
+#define INIT_PDCADMA	IDE_IGNORE
+#define DMA_PDCADMA	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern void fixup_device_pdc20265(struct pci_dev *, ide_pci_device_t *);
+extern void fixup_device_pdc20270(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern unsigned int ata66_pdc202xx(ide_hwif_t *);
+extern void ide_init_pdc202xx(ide_hwif_t *);
+#define FIXUP_PDC20265	&fixup_device_pdc20265
+#define FIXUP_PDC20270	&fixup_device_pdc20270
+#define PCI_PDC202XX	&pci_init_pdc202xx
+#define ATA66_PDC202XX	&ata66_pdc202xx
+#define INIT_PDC202XX	&ide_init_pdc202xx
+#else
+#define FIXUP_PDC20265	IDE_IGNORE
+#define FIXUP_PDC20270	IDE_IGNORE
+#define PCI_PDC202XX	IDE_IGNORE
+#define ATA66_PDC202XX	IDE_IGNORE
+#define INIT_PDC202XX	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_PIIX
+extern void fixup_device_piix(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_piix(struct pci_dev *, const char *);
+extern unsigned int ata66_piix(ide_hwif_t *);
+extern void ide_init_piix(ide_hwif_t *);
+#define FIXUP_PIIX	&fixup_device_piix
+#define PCI_PIIX	&pci_init_piix
+#define ATA66_PIIX	&ata66_piix
+#define INIT_PIIX	&ide_init_piix
+#else
+#define FIXUP_PIIX	NULL
+#define PCI_PIIX	NULL
+#define ATA66_PIIX	NULL
+#define INIT_PIIX	IDE_NO_DRIVER
+#endif
+
+#ifdef CONFIG_BLK_DEV_IT8172
+extern void fixup_device_it8172(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
+extern unsigned int ata66_it8172(ide_hwif_t *);
+extern void ide_init_it8172(ide_hwif_t *);
+#define FIXUP_IT8172	&fixup_device_it8172
+#define PCI_IT8172	&pci_init_it8172
+#define ATA66_IT8172	&ata66_it8172
+#define INIT_IT8172	&ide_init_it8172
+#else
+#define FIXUP_IT8172	NULL
+#define PCI_IT8172	NULL
+#define ATA66_IT8172	NULL
+#define INIT_IT8172	IDE_NO_DRIVER
+#endif
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_init_rz1000(ide_hwif_t *);
+#define INIT_RZ1000	&ide_init_rz1000
+#else
+#define INIT_RZ1000	IDE_IGNORE
+#endif
+
+#define INIT_SAMURAI	NULL
+
+#ifdef CONFIG_BLK_DEV_SVWKS
+extern void fixup_device_csb6(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
+extern unsigned int ata66_svwks(ide_hwif_t *);
+extern void ide_init_svwks(ide_hwif_t *);
+extern void ide_dmacapable_svwks(ide_hwif_t *, unsigned long);
+#define FIXUP_CSB6	&fixup_device_csb6
+#define PCI_SVWKS	&pci_init_svwks
+#define ATA66_SVWKS	&ata66_svwks
+#define INIT_SVWKS	&ide_init_svwks
+#define DMA_SVWKS	&ide_dmacapable_svwks
+#else
+#define FIXUP_CSB6	NULL
+#define PCI_SVWKS	NULL
+#define ATA66_SVWKS	NULL
+#define INIT_SVWKS	IDE_NO_DRIVER
+#define DMA_SVWKS	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern void fixup_device_sis5513(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
+extern unsigned int ata66_sis5513(ide_hwif_t *);
+extern void ide_init_sis5513(ide_hwif_t *);
+#define FIXUP_SIS5513	&fixup_device_sis5513
+#define PCI_SIS5513	&pci_init_sis5513
+#define ATA66_SIS5513	&ata66_sis5513
+#define INIT_SIS5513	&ide_init_sis5513
+#else
+#define FIXUP_SIS5513	NULL
+#define PCI_SIS5513	NULL
+#define ATA66_SIS5513	NULL
+#define INIT_SIS5513	IDE_NO_DRIVER
+#endif
+
+#ifdef CONFIG_BLK_DEV_SLC90E66
+extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
+extern unsigned int ata66_slc90e66(ide_hwif_t *);
+extern void ide_init_slc90e66(ide_hwif_t *);
+#define PCI_SLC90E66	&pci_init_slc90e66
+#define ATA66_SLC90E66	&ata66_slc90e66
+#define INIT_SLC90E66	&ide_init_slc90e66
+#else
+#define PCI_SLC90E66	NULL
+#define ATA66_SLC90E66	NULL
+#define INIT_SLC90E66	IDE_NO_DRIVER
+#endif
+
+#ifdef CONFIG_BLK_DEV_SL82C105
+extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
+extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
+extern void ide_init_sl82c105(ide_hwif_t *);
+#define PCI_W82C105	&pci_init_sl82c105
+#define DMA_W82C105	&dma_init_sl82c105
+#define INIT_W82C105	&ide_init_sl82c105
+#else
+#define PCI_W82C105	NULL
+#define DMA_W82C105	NULL
+#define INIT_W82C105	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290	&ide_init_trm290
+#else
+#define INIT_TRM290	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
+extern unsigned int ata66_via82cxxx(ide_hwif_t *);
+extern void ide_init_via82cxxx(ide_hwif_t *);
+extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+#define PCI_VIA82CXXX	&pci_init_via82cxxx
+#define ATA66_VIA82CXXX	&ata66_via82cxxx
+#define INIT_VIA82CXXX	&ide_init_via82cxxx
+#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
+#else
+#define PCI_VIA82CXXX	NULL
+#define ATA66_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	IDE_NO_DRIVER
+#define DMA_VIA82CXXX	NULL
+#endif
+
+static ide_pci_device_t ide_pci_chipsets[] __initdata = {
+	{DEVID_PIIXa,	"PIIX",		FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIXb,	"PIIX",		FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_MPIIX,	"MPIIX",	FIXUP_PIIX,	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX3,	"PIIX3",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX4,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX4E,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4E2,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U2,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4NX,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U3,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U4, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U5, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U6,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U7,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U8, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_MR_IDE,	"VP_IDE",	NULL,		PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
+	{DEVID_VP_IDE,	"VP_IDE",	NULL,		PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
+#ifdef CONFIG_PDC202XX_FORCE
+	{DEVID_PDC20246,"PDC20246",	NULL,		PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20262,"PDC20262",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+	{DEVID_PDC20263,"PDC20263",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+	{DEVID_PDC20265,"PDC20265",	FIXUP_PDC20265,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
+	{DEVID_PDC20267,"PDC20267",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+#else /* !CONFIG_PDC202XX_FORCE */
+	{DEVID_PDC20246,"PDC20246",	NULL,		PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
+	{DEVID_PDC20262,"PDC20262",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+	{DEVID_PDC20263,"PDC20263",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+	{DEVID_PDC20265,"PDC20265",	FIXUP_PDC20265,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+	{DEVID_PDC20267,"PDC20267",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+#endif
+	{DEVID_PDC20268,"PDC20268",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	/*
+	 * Promise used a different PCI ident for the raid card apparently
+	 * to try and prevent Linux detecting it and using our own raid code.
+	 * We want to detect it for the ataraid drivers, so we have to list
+	 * both here..
+	 */
+	{DEVID_PDC20268R,"PDC20270",	FIXUP_PDC20270,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20269,"PDC20269",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20271,"PDC20271",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20275,"PDC20275",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20276,"PDC20276",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20277,"PDC20277",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
+	{DEVID_SIS5513,	"SIS5513",	FIXUP_SIS5513,	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
+	{DEVID_CMD643,	"CMD643",	NULL,		PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD646,	"CMD646",	NULL,		PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_CMD648,	"CMD648",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD649,	"CMD649",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD680,	"CMD680",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_OPTI621,	"OPTI621",	FIXUP_OPTI621,	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_OPTI621X,"OPTI621X",	FIXUP_OPTI621,	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_AEC6210,	"AEC6210",	NULL,		PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
+	{DEVID_AEC6260,	"AEC6260",	NULL,		PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
+	{DEVID_AEC6260R,"AEC6260R",	NULL,		PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
+	{DEVID_AEC6280,	"AEC6X80",	FIXUP_AEC62XX,	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
+	{DEVID_AEC6880,	"AEC6X80R",	FIXUP_AEC62XX,	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
+	{DEVID_W82C105,	"W82C105",	NULL,		PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
+	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_HPT34X,	"HPT34X",	FIXUP_HPT34X,	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
+	{DEVID_HPT366,	"HPT366",	FIXUP_HPT366,	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
+	{DEVID_HPT372,	"HPT372A",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_HPT302,	"HPT302",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_HPT371,	"HPT371",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_HPT374,	"HPT374",	FIXUP_HPT374,	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_ALI15X3,	"ALI15X3",	FIXUP_ALI15X3,	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CY82C693,"CY82C693",	FIXUP_CY82C693,	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CS5530,	"CS5530",	NULL,		PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_AMD7401,	"AMD7401",	FIXUP_AMD74XX,	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7409,	"AMD7409",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7411,	"AMD7411",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7441,	"AMD7441",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_PDCADMA,	"PDCADMA",	NULL,		PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_SLC90E66,"SLC90E66",	NULL,		PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_OSB4,	"SvrWks OSB4",	NULL,		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CSB5,	"SvrWks CSB5",	NULL,		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	DMA_SVWKS,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CSB6,	"SvrWks CSB6",	FIXUP_CSB6,	PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	DMA_SVWKS,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_ITE8172G,"IT8172G",	FIXUP_IT8172,	PCI_IT8172,	NULL,		INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
+	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
 
-	tmp->next = d;
+/*
+ * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
+ * settings of split-mirror pci-config space, place chipset into init-mode,
+ * and/or preserve an interrupt if the card is not native ide support.
+ */
+static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_TTI_HPT366:
+		case PCI_DEVICE_ID_TTI_HPT372:
+		case PCI_DEVICE_ID_TTI_HPT302:
+		case PCI_DEVICE_ID_TTI_HPT371:
+		case PCI_DEVICE_ID_TTI_HPT374:
+		case PCI_DEVICE_ID_PROMISE_20246:
+		case PCI_DEVICE_ID_PROMISE_20262:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20277:
+	/*
+	 *	case PCI_DEVICE_ID_ARTOP_ATP850UF:
+	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT372
+	 *	case PCI_DEVICE_ID_ARTOP_ATP860:
+	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT302
+	 *	case PCI_DEVICE_ID_ARTOP_ATP860R:
+	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT371
+	 *	case PCI_DEVICE_ID_ARTOP_ATP865:
+	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT374
+	 */
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+			return dev->irq;
+		default:
+			break;
+	}
+	return 0;
 }
 
 /*
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-static struct ata_channel __init *lookup_channel(unsigned long io_base, int bootable, const char *name)
+static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
 {
 	int h;
-	struct ata_channel *ch;
+	ide_hwif_t *hwif;
 
 	/*
-	 * Look for a channel with matching io_base default value.  If chipset is
-	 * "ide_unknown", then claim that channel slot.  Otherwise, some other
-	 * chipset has already claimed it..  :(
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
 	 */
 	for (h = 0; h < MAX_HWIFS; ++h) {
-		ch = &ide_hwifs[h];
-		if (ch->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (ch->chipset == ide_generic)
-				return ch; /* a perfect match */
-			if (ch->chipset == ide_unknown)
-				return ch; /* match */
-			printk(KERN_INFO "%s: port 0x%04lx already claimed by %s\n",
-					name, io_base, ch->name);
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk("%s: port 0x%04lx already claimed by %s\n",
+				name, io_base, hwif->name);
 			return NULL;	/* already claimed */
 		}
 	}
-
 	/*
-	 * Okay, there is no ch matching our io_base, so we'll just claim an
-	 * unassigned slot.
-	 *
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
 	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned which uses
-	 * ports 1f0/170 (the ide0/ide1 defaults).
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
 	 *
-	 * Unless there is a bootable card that does not use the standard ports
-	 * 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 * Unless there is a bootable card that does not use the standard
+	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
 	 */
-
-	if (bootable == ON_BOARD) {
+	if (bootable) {
 		for (h = 0; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if (ch->chipset == ide_unknown)
-				return ch;	/* pick an unused entry */
+			hwif = &ide_hwifs[h];
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
 		}
 	} else {
 		for (h = 2; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if (ch->chipset == ide_unknown)
-				return ch;	/* pick an unused entry */
+			hwif = ide_hwifs + h;
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
 		}
 	}
 	for (h = 0; h < 2; ++h) {
-		ch = &ide_hwifs[h];
-		if (ch->chipset == ide_unknown)
-			return ch;	/* pick an unused entry */
+		hwif = ide_hwifs + h;
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
 	}
-	printk(KERN_INFO "%s: too many ATA interfaces.\n", name);
-
+	printk("%s: too many IDE interfaces, no room in table\n", name);
 	return NULL;
 }
 
-static int __init setup_pci_baseregs(struct pci_dev *dev, const char *name)
+static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
 {
-	u8 reg;
-	u8 progif = 0;
+	byte reg, progif = 0;
 
 	/*
 	 * Place both IDE interfaces into PCI "native" mode:
 	 */
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+			 (progif & 5) != 5) {
 		if ((progif & 0xa) != 0xa) {
-			printk("%s: device not capable of full native PCI mode\n", name);
+			printk("%s: device not capable of full "
+				"native PCI mode\n", name);
 			return 1;
 		}
 		printk("%s: placing both ports into native PCI mode\n", name);
-		pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
 		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
 			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
 			return 1;
@@ -159,625 +662,331 @@
 	return 0;
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * Setup DMA transfers on the channel.
- */
-static void __init setup_channel_dma(struct pci_dev *dev,
-		struct ata_pci_device* d,
-		int autodma,
-		struct ata_channel *ch)
-{
-	unsigned long dma_base;
-
-	if (d->flags & ATA_F_NOADMA)
-		autodma = 0;
-
-	if (autodma)
-		ch->autodma = 1;
-
-	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
-		return;
-
-	/*
-	 * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
-	 */
-	dma_base = pci_resource_start(dev, 4);
-	if (dma_base) {
-		/* PDC20246, PDC20262, HPT343, & HPT366 */
-		if ((ch->unit == ATA_PRIMARY) && d->extra) {
-			request_region(dma_base + 16, d->extra, dev->name);
-			ch->dma_extra = d->extra;
-		}
-
-		/* If we are on the second channel, the dma base address will
-		 * be one entry away from the primary interface.
-		 */
-		if (ch->unit == ATA_SECONDARY)
-				dma_base += 8;
-
-		if (d->flags & ATA_F_SIMPLEX) {
-			outb(inb(dma_base + 2) & 0x60, dma_base + 2);
-			if (inb(dma_base + 2) & 0x80)
-				printk(KERN_INFO "%s: simplex device: DMA forced\n", dev->name);
-		} else {
-			/* If the device claims "simplex" DMA, this means only
-			 * one of the two interfaces can be trusted with DMA at
-			 * any point in time.  So we should enable DMA only on
-			 * one of the two interfaces.
-			 */
-			if ((inb(dma_base + 2) & 0x80)) {
-				if ((!ch->drives[0].present && !ch->drives[1].present) ||
-				    ch->unit == ATA_SECONDARY) {
-					printk(KERN_INFO "%s: simplex device:  DMA disabled\n", dev->name);
-					dma_base = 0;
-				}
-			}
-		}
-	} else {
-		printk(KERN_INFO "%s: %s Bus-Master DMA was disabled by BIOS\n",
-		       ch->name, dev->name);
-
-		return;
-	}
-
-	/* The function below will check itself whatever there is something to
-	 * be done or not. We don't have therefore to care whatever it was
-	 * already enabled by the primary channel run.
-	 */
-	pci_set_master(dev);
-	if (d->init_dma)
-		d->init_dma(ch, dma_base);
-	else
-		ata_init_dma(ch, dma_base);
-}
-#endif
-
-/*
- * Setup a particular port on an ATA host controller.
- *
- * This gets called once for the master and for the slave interface.
- */
-static int __init setup_host_channel(struct pci_dev *dev,
-		struct ata_pci_device *d,
-		int port,
-		u8 class_rev,
-		int pciirq,
-		int autodma)
-{
-	unsigned long base = 0;
-	unsigned long ctl = 0;
-	ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	struct ata_channel *ch;
-
-	u8 tmp;
-	if (port == ATA_SECONDARY) {
-
-		/* If this is a Promise FakeRaid controller, the 2nd controller
-		 * will be marked as disabled while it is actually there and
-		 * enabled by the bios for raid purposes.  Skip the normal "is
-		 * it enabled" test for those.
-		 */
-		if (d->flags & ATA_F_PHACK)
-			goto controller_ok;
-	}
-
-	/* Test whatever the port is enabled.
-	 */
-	if (e->reg) {
-		if (pci_read_config_byte(dev, e->reg, &tmp))
-			return 0; /* error! */
-		if ((tmp & e->mask) != e->val)
-			return 0;
-	}
-
-	/* Nothing to be done for the second port.
-	 */
-	if (port == ATA_SECONDARY) {
-		if ((d->flags & ATA_F_HPTHACK) && (class_rev < 0x03))
-			return 0;
-	}
-controller_ok:
-	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-		ctl  = dev->resource[(2 * port) + 1].start;
-		base = dev->resource[2 * port].start;
-		if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-			printk(KERN_WARNING "%s: error: IO reported as MEM by BIOS!\n", dev->name);
-			/* try it with the default values */
-			ctl = 0;
-			base = 0;
-		}
-	}
-	if (ctl && !base) {
-		printk(KERN_WARNING "%s: error: missing MEM base info from BIOS!\n", dev->name);
-		/* we will still try to get along with the default */
-	}
-	if (base && !ctl) {
-		printk(KERN_WARNING "%s: error: missing IO base info from BIOS!\n", dev->name);
-		/* we will still try to get along with the default */
-	}
-
-	/* Fill in the default values: */
-	if (!ctl)
-		ctl = port ? 0x374 : 0x3f4;
-	if (!base)
-		base = port ? 0x170 : 0x1f0;
-
-	if ((ch = lookup_channel(base, d->bootable, dev->name)) == NULL)
-		return -ENOMEM;	/* no room */
-
-	if (ch->io_ports[IDE_DATA_OFFSET] != base) {
-		ide_init_hwif_ports(&ch->hw, base, (ctl | 2), NULL);
-		memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports));
-		ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET];
-	}
-
-	ch->chipset = ide_pci;
-	ch->pci_dev = dev;
-	ch->unit = port;
-	if (!ch->irq)
-		ch->irq = pciirq;
-
-	/* Serialize the interfaces if requested by configuration information.
-	 */
-	if (d->flags & ATA_F_SER)
-	    ch->serialized = 1;
-
-	/* Cross wired IRQ lines on UMC chips and no DMA transfers.*/
-	if (d->flags & ATA_F_FIXIRQ) {
-		ch->irq = port ? 15 : 14;
-		goto no_dma;
-	}
-	if (d->flags & ATA_F_NODMA)
-		goto no_dma;
-
-	if (ch->udma_four)
-		printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name);
-
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	/*
-	 * Setup DMA transfers on the channel.
-	 */
-	setup_channel_dma(dev, d, autodma, ch);
-#endif
-no_dma:
-	/* Call chipset-specific routine for each enabled channel. */
-	if (d->init_channel)
-		d->init_channel(ch);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((d->flags & ATA_F_NOADMA) || noautodma)
-		ch->autodma = 0;
-#endif
-
-	return 0;
-}
-
 /*
- * Looks at the primary/secondary channels on a PCI IDE device and, if they are
- * enabled, prepares the IDE driver for use with them.  This generic code works
- * for most PCI chipsets.
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
  *
- * One thing that is not standardized is the location of the primary/secondary
- * interface "enable/disable" bits.  For chipsets that we "know" about, this
- * information is in the struct ata_pci_device struct; for all other chipsets,
- * we just assume both interfaces are enabled.
- */
-static void __init setup_pci_device(struct pci_dev *dev, struct ata_pci_device *d)
-{
-	int autodma = 0;
-	int pciirq = 0;
-	unsigned short pcicmd = 0;
-	unsigned short tried_config = 0;
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
+	unsigned short pcicmd = 0, tried_config = 0;
+	byte tmp = 0;
+	ide_hwif_t *hwif, *mate = NULL;
 	unsigned int class_rev;
+	static int secondpdc = 0;
 
 #ifdef CONFIG_IDEDMA_AUTO
 	if (!noautodma)
 		autodma = 1;
 #endif
 
+	if (d->init_hwif == IDE_NO_DRIVER) {
+		printk(KERN_WARNING "%s: detected chipset, "
+			"but driver not compiled in!\n", d->name);
+		d->init_hwif = NULL;
+	}
+
 	if (pci_enable_device(dev)) {
-		printk(KERN_WARNING "%s: Could not enable PCI device.\n", dev->name);
+		printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+			"Could not enable device.\n", d->name);
 		return;
 	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk(KERN_ERR "%s: error accessing PCI regs\n", dev->name);
+		printk("%s: error accessing PCI regs\n", d->name);
 		return;
 	}
 	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
 		/*
 		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned
-		 * an IRQ (or possibly the device is using a "legacy header"
-		 * for IRQs).  Maybe the user deliberately *disabled* the
-		 * device, but we'll eventually ignore it again if no drives
-		 * respond.
+		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
+		 *  (or possibly the device is using a "legacy header" for IRQs).
+		 * Maybe the user deliberately *disabled* the device,
+		 * but we'll eventually ignore it again if no drives respond.
 		 */
 		if (tried_config++
-		 || setup_pci_baseregs(dev, dev->name)
+		 || ide_setup_pci_baseregs(dev, d->name)
 		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", dev->name);
+			printk("%s: device disabled (BIOS)\n", d->name);
 			return;
 		}
 		autodma = 0;	/* default DMA off if we had to configure it here */
 		goto check_if_enabled;
 	}
 	if (tried_config)
-		printk("%s: device enabled (Linux)\n", dev->name);
+		printk("%s: device enabled (Linux)\n", d->name);
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
-
-	if (d->vendor == PCI_VENDOR_ID_TTI && PCI_DEVICE_ID_TTI_HPT343) {
-		/* see comments in hpt34x.c to see why... */
-		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	}
-
-	printk(KERN_INFO "ATA: chipset rev.: %d\n", class_rev);
+	printk("%s: chipset revision %d\n", d->name, class_rev);
 
 	/*
 	 * Can we trust the reported IRQ?
 	 */
 	pciirq = dev->irq;
-
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) {
-		/* By rights we want to ignore these, but the Promise Fastrak
-		   people have some strange ideas about proprietary so we have
-		   to act otherwise on those. The Supertrak however we need
-		   to skip */
-		if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20265) {
-			printk(KERN_INFO "ATA: Found promise 20265 in RAID mode.\n");
-			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
-				dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
-			{
-				printk(KERN_INFO "ATA: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
-				return;
-			}
-		}
-		/* Its attached to something else, just a random bridge.
-		   Suspect a fastrak and fall through */
-	}
+	
 	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk(KERN_INFO "ATA: non-legacy mode: IRQ probe delayed\n");
-
+		printk("%s: not 100%% native mode: "
+			"will probe irqs later\n", d->name);
 		/*
-		 * This allows off board ide-pci cards to enable a BIOS,
+		 * This allows offboard ide-pci cards the enable a BIOS,
 		 * verify interrupt settings of split-mirror pci-config
 		 * space, place chipset into init-mode, and/or preserve
 		 * an interrupt if the card is not native ide support.
 		 */
-		if (d->init_chipset)
-			pciirq = d->init_chipset(dev);
-		else {
-			if (d->flags & ATA_F_IRQ)
-				pciirq = dev->irq;
-			else
-				pciirq =  0;
-		}
+		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
 	} else if (tried_config) {
-		printk(KERN_INFO "ATA: will probe IRQs later\n");
+		printk("%s: will probe irqs later\n", d->name);
 		pciirq = 0;
 	} else if (!pciirq) {
-		printk(KERN_INFO "ATA: invalid IRQ (%d): will probe later\n", pciirq);
+		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
 		pciirq = 0;
 	} else {
 		if (d->init_chipset)
-			d->init_chipset(dev);
+			(void) d->init_chipset(dev, d->name);
 #ifdef __sparc__
-		printk(KERN_INFO "ATA: 100%% native mode on irq %s\n", __irq_itoa(pciirq));
+		printk("%s: 100%% native mode on irq %s\n",
+		       d->name, __irq_itoa(pciirq));
 #else
-		printk(KERN_INFO "ATA: 100%% native mode on irq %d\n", pciirq);
+		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
 #endif
 	}
 
 	/*
-	 * Set up IDE chanells. First the primary, then the secondary.
+	 * Set up the IDE ports
 	 */
-	setup_host_channel(dev, d, ATA_PRIMARY, class_rev, pciirq, autodma);
-	setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma);
-}
-
-/*
- * Fix crossover IRQ line setups between primary and secondary channel.  Quite
- * a common bug apparently.
- */
-static void __init pdc20270_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
-{
-	struct pci_dev *dev2 = NULL;
-	struct pci_dev *findev;
-	struct ata_pci_device *d2;
-
-	if (dev->bus->self &&
-	    dev->bus->self->vendor == PCI_VENDOR_ID_DEC &&
-	    dev->bus->self->device == PCI_DEVICE_ID_DEC_21150) {
-		if (PCI_SLOT(dev->devfn) & 2) {
+	for (port = 0; port <= 1; ++port) {
+		unsigned long base = 0, ctl = 0;
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	
+		/* 
+		 * If this is a Promise FakeRaid controller,
+		 * the 2nd controller will be marked as 
+		 * disabled while it is actually there and enabled
+		 * by the bios for raid purposes. 
+		 * Skip the normal "is it enabled" test for those.
+		 */
+		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) &&
+		    (secondpdc++==1) && (port==1)) 
+			goto controller_ok;
+		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) &&
+		    (secondpdc++==1) && (port==1)) 
+			goto controller_ok;
+			
+		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+		    (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+controller_ok:			
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) &&
+		    (port) && (class_rev < 0x03))
 			return;
-		}
-		d->extra = 0;
-		pci_for_each_dev(findev) {
-			if ((findev->vendor == dev->vendor) &&
-			    (findev->device == dev->device) &&
-			    (PCI_SLOT(findev->devfn) & 2)) {
-				u8 irq = 0;
-				u8 irq2 = 0;
-				dev2 = findev;
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-                                if (irq != irq2) {
-					dev2->irq = dev->irq;
-                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-                                }
-
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) && (port))
+			return;
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+		    (port) && (!(PCI_FUNC(dev->devfn) & 1)))
+			return;
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE ||
+		    (dev->class & (port ? 4 : 1)) != 0) {
+			ctl  = dev->resource[(2*port)+1].start;
+			base = dev->resource[2*port].start;
+			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
+			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
+				printk("%s: IO baseregs (BIOS) are reported "
+					"as MEM, report to "
+					"<andre@linux-ide.org>.\n", d->name);
+#if 0
+				/*
+				 * FIXME! This really should check that
+				 * it really gets the IO/MEM part right!
+				 */
+				continue;
+#endif
 			}
 		}
-	}
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-			dev->name, dev->slot_name);
-	setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-			dev2->name, dev2->slot_name);
-	setup_pci_device(dev2, d2);
-}
-
-static void __init hpt374_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
-{
-	struct pci_dev *dev2 = NULL;
-	struct pci_dev *findev;
-	struct ata_pci_device *d2;
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			break;
+		if ((ctl && !base) || (base && !ctl)) {
+			printk("%s: inconsistent baseregs (BIOS) "
+				"for port %d, skipping\n", d->name, port);
+			continue;
 		}
-	}
-
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-		dev->name, dev->slot_name);
-	setup_pci_device(dev, d);
-	if (!dev2) {
-		return;
-	} else {
-		u8 irq = 0;
-		u8 irq2 = 0;
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-		pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-		if (irq != irq2) {
-			pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-			dev2->irq = dev->irq;
-			printk("%s: pci-config space interrupt fixed.\n",
-				dev2->name);
+		if (!ctl)
+			ctl = port ? 0x374 : 0x3f4;	/* use default value */
+		if (!base)
+			base = port ? 0x170 : 0x1f0;	/* use default value */
+		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+			continue;	/* no room in ide_hwifs[] */
+		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+		}
+		hwif->chipset = ide_pci;
+		hwif->pci_dev = dev;
+		hwif->pci_devid = d->devid;
+		hwif->channel = port;
+		if (!hwif->irq)
+			hwif->irq = pciirq;
+		if (mate) {
+			hwif->mate = mate;
+			mate->mate = hwif;
+			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
+				hwif->serialized = 1;
+				mate->serialized = 1;
+			}
 		}
-	}
-	d2 = d;
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-		dev2->name, dev2->slot_name);
-	setup_pci_device(dev2, d2);
-
-}
-
-static void __init hpt366_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	struct ata_pci_device *d2;
-	unsigned char pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	switch(class_rev) {
-		case 5:
-		case 4:
-		case 3:	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-					dev->name, dev->slot_name);
-			setup_pci_device(dev, d);
-			return;
-		default:	break;
-	}
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	pci_for_each_dev(findev) {
-		if (findev->vendor == dev->vendor &&
-		    findev->device == dev->device &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-			if ((pin1 != pin2) && (dev->irq == dev2->irq)) {
-				d->bootable = ON_BOARD;
-				printk(KERN_INFO "ATAL: %s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2);
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
+			hwif->irq = hwif->channel ? 15 : 14;
+			goto bypass_umc_dma;
+		}
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
+			goto bypass_piix_dma;
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
+			goto bypass_legacy_dma;
+		if (hwif->udma_four) {
+			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n",
+				d->name);
+		} else {
+			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
+		}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
+
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20263) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20271) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20277) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6880) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT372) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT374) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
+		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
+			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
+			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+				/*
+ 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
+ 	 			 */
+		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
+					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
+				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
+				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
+					dma_base = 0;
+				}
+			}
+			if (dma_base) {
+				if (d->dma_init) {
+					d->dma_init(hwif, dma_base);
+				} else {
+					ide_setup_dma(hwif, dma_base, 8);
+				}
+			} else {
+				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
 			}
-			break;
 		}
+#endif	/* CONFIG_BLK_DEV_IDEDMA */
+bypass_legacy_dma:
+bypass_piix_dma:
+bypass_umc_dma:
+		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
+			d->init_hwif(hwif);
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
 	}
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-			dev->name, dev->slot_name);
-	setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk(KERN_INFO "ATA: %s: controller, PCI slot %s\n",
-			dev2->name, dev2->slot_name);
-	setup_pci_device(dev2, d2);
+	if (!at_least_one_hwif_enabled)
+		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
 }
 
-
-
 /*
- * This finds all PCI IDE controllers and calls appropriate initialization
- * functions for them.
+ * ide_scan_pcibus() gets invoked at boot time from ide.c.
+ * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
  */
-static void __init scan_pcidev(struct pci_dev *dev)
+void __init ide_scan_pcidev (struct pci_dev *dev)
 {
-	unsigned short vendor;
-	unsigned short device;
-	struct ata_pci_device *d;
-
-	vendor = dev->vendor;
-	device = dev->device;
-
-
-
-	/* Look up the chipset information.
-	 * We expect only one match.
-	 */
-	for (d = ata_pci_device_list; d; d = d->next) {
-		if (d->vendor == vendor && d->device == device)
-			break;
-	}
-
-	if (!d) {
-		/* Only check the device calls, if it wasn't listed, since
-		 * there are in esp. some pdc202xx chips which "work around"
-		 * beeing grabbed by generic drivers.
-		 */
-		if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-			printk(KERN_INFO "ATA: unknown interface: %s, PCI slot %s\n",
-					dev->name, dev->slot_name);
-		}
-		return;
-	}
+	ide_pci_devid_t		devid;
+	ide_pci_device_t	*d;
 
-	if (d->init_channel == ATA_PCI_IGNORE)
-		printk(KERN_INFO "ATA: %s: ignored by PCI bus scan\n", dev->name);
-	else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1))
+	devid.vid = dev->vendor;
+	devid.did = dev->device;
+	for (d = ide_pci_chipsets;
+	     d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+
+	if (d->init_hwif == IDE_IGNORE)
+		printk("%s: ignored by ide_scan_pci_device() "
+			"(uses own driver)\n", d->name);
+	else if (d->fixup_device)
+		d->fixup_device(dev, d);
+#if 0
+	else if (((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) &&
+		 (!(PCI_FUNC(dev->devfn) & 1)))
 		return;
-	else if ((d->vendor == PCI_VENDOR_ID_CONTAQ && d->device == PCI_DEVICE_ID_CONTAQ_82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* CY82C693 is more than only a IDE controller */
-	else if ((d->vendor == PCI_VENDOR_ID_ITE && d->device == PCI_DEVICE_ID_ITE_IT8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* IT8172G is also more than only an IDE controller */
-	else if ((d->vendor == PCI_VENDOR_ID_UMC && d->device == PCI_DEVICE_ID_UMC_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
+#endif
+	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) &&
+		 (!(PCI_FUNC(dev->devfn) & 1)))
 		return;	/* UM8886A/BF pair */
-	else if (d->flags & ATA_F_HPTHACK) {
-		if (d->device == PCI_DEVICE_ID_TTI_HPT366)
-			hpt366_device_order_fixup(dev, d);
-		if (d->device == PCI_DEVICE_ID_TTI_HPT374)
-			hpt374_device_order_fixup(dev, d);
-	} else if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20268R)
-		pdc20270_device_order_fixup(dev, d);
-	else {
-		printk(KERN_INFO "ATA: %s, PCI slot %s\n",
-				dev->name, dev->slot_name);
-		setup_pci_device(dev, d);
+	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) ||
+		 (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
+			printk("%s: unknown IDE controller on PCI bus "
+				"%02x device %02x, VID=%04x, DID=%04x\n",
+				d->name, dev->bus->number, dev->devfn,
+				devid.vid, devid.did);
+		else
+			printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+				d->name, dev->bus->number, dev->devfn);
+		ide_setup_pci_device(dev, d);
 	}
 }
 
-void __init ide_scan_pcibus(int scan_direction)
+void __init ide_scan_pcibus (int scan_direction)
 {
 	struct pci_dev *dev;
 
 	if (!scan_direction) {
 		pci_for_each_dev(dev) {
-			scan_pcidev(dev);
+			ide_scan_pcidev(dev);
 		}
 	} else {
 		pci_for_each_dev_reverse(dev) {
-			scan_pcidev(dev);
+			ide_scan_pcidev(dev);
 		}
 	}
-}
-
-/* known chips without particular chipset driver module data table */
-/* Those are id's of chips we don't deal currently with, but which still need
- * some generic quirk handling.
- */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_PCTECH,
-		.device = PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_CMD,
-		.device = PCI_DEVICE_ID_CMD_640,
-		.init_channel = ATA_PCI_IGNORE,
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_NS,
-		.device = PCI_DEVICE_ID_NS_87410,
-		.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_HINT,
-		.device = PCI_DEVICE_ID_HINT_VXPROII_IDE,
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_HOLTEK,
-		.device = PCI_DEVICE_ID_HOLTEK_6565,
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82371MX,
-		.enablebits = {{0x6D,0x80,0x80}, {0x00,0x00,0x00}},
-		.bootable = ON_BOARD,
-		.flags = ATA_F_NODMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_UMC,
-		.device = PCI_DEVICE_ID_UMC_UM8673F,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_FIXIRQ
-	},
-	{
-		.vendor = PCI_VENDOR_ID_UMC,
-		.device = PCI_DEVICE_ID_UMC_UM8886A,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_FIXIRQ
-	},
-	{
-		.vendor = PCI_VENDOR_ID_UMC,
-		.device = PCI_DEVICE_ID_UMC_UM8886BF,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_FIXIRQ
-	},
-	{
-		.vendor = PCI_VENDOR_ID_VIA,
-		.device = PCI_DEVICE_ID_VIA_82C561,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_NOADMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_VIA,
-		.device = PCI_DEVICE_ID_VIA_82C586_1,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_NOADMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_TTI,
-		.device = PCI_DEVICE_ID_TTI_HPT366,
-		.bootable = OFF_BOARD,
-		.extra = 240,
-		.flags = ATA_F_IRQ | ATA_F_HPTHACK
-	}
-};
-
-int __init init_ata_pci_misc(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
-		ata_register_chipset(&chipsets[i]);
-	}
-
-	return 0;
 }
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/ide-pmac.c	Tue Aug 27 12:28:08 2002
@@ -1,4 +1,6 @@
 /*
+ * linux/drivers/ide/ide-pmac.c
+ *
  * Support for IDE interfaces on PowerMacs.
  * These IDE interfaces are memory-mapped and have a DBDMA channel
  * for doing DMA.
@@ -14,29 +16,17 @@
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *
- * TODO:
- *
- *  - Find a way to duplicate less code with ide-dma and use the
- *    dma fileds in the hwif structure instead of our own
- *
- *  - Fix check_disk_change() call
- *
- *  - Make module-able (includes setting ppc_md. hooks from within
- *    this file and not from arch code, and handling module deps with
- *    mediabay (by having both modules do dynamic lookup of each other
- *    symbols or by storing hooks at arch level).
- *
  */
-
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/jiffies.h>
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
@@ -52,9 +42,11 @@
 #include <linux/adb.h>
 #include <linux/pmu.h>
 #endif
-#include "timing.h"
+#include "ide_modes.h"
 
-#undef IDE_PMAC_DEBUG
+extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+
+#define IDE_PMAC_DEBUG
 
 #define DMA_WAIT_TIMEOUT	500
 
@@ -78,7 +70,7 @@
 	int				sg_nents;
 	int				sg_dma_direction;
 #endif
-
+	
 } pmac_ide[MAX_HWIFS] __pmacdata;
 
 static int pmac_ide_count;
@@ -110,7 +102,7 @@
 /* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
  * 40 connector cable and to 4 on 80 connector one.
  * Clock unit is 15ns (66Mhz)
- *
+ * 
  * 3 Values can be programmed:
  *  - Write data setup, which appears to match the cycle time. They
  *    also call it DIOW setup.
@@ -145,7 +137,7 @@
 
 /* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
  * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- *
+ * 
  * The access time and recovery time can be programmed. Some older
  * Darwin code base limit OHare to 150ns cycle time. I decided to do
  * the same here fore safety against broken old hardware ;)
@@ -175,11 +167,8 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
-# define BAD_DMA_DRIVE		0
-# define GOOD_DMA_DRIVE		1
-
 /* Rounded Multiword DMA timings
- *
+ * 
  * I gave up finding a generic formula for all controller
  * types and instead, built tables based on timing values
  * used by Apple in Darwin's implementation.
@@ -255,17 +244,11 @@
 #define IDE_WAKEUP_DELAY_MS	2000
 
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
-
-static void pmac_udma_enable(struct ata_device *drive, int on, int verbose);
-static void pmac_udma_start(struct ata_device *drive, struct request *rq);
-static int pmac_udma_stop(struct ata_device *drive);
-static int pmac_udma_init(struct ata_device *drive, struct request *rq);
-static int pmac_udma_irq_status(struct ata_device *drive);
-static int pmac_udma_setup(struct ata_device *drive, int map);
-static int pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr);
-static int pmac_ide_tune_chipset(struct ata_device *drive, u8 speed);
-static void pmac_ide_tuneproc(struct ata_device *drive, u8 pio);
-static void pmac_ide_selectproc(struct ata_device *drive);
+static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
@@ -276,13 +259,20 @@
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
+static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *);
+static struct notifier_block pmac_ide_reboot_notifier = {
+	pmac_ide_notify_reboot,
+	NULL,
+	0
+};
+
 static int __pmac
-pmac_ide_find(struct ata_device *drive)
+pmac_ide_find(ide_drive_t *drive)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	ide_ioreg_t base;
 	int i;
-
+	
 	for (i=0; i<pmac_ide_count; i++) {
 		base = pmac_ide[i].regbase;
 		if (base && base == hwif->io_ports[0])
@@ -328,25 +318,34 @@
 	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
 	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
 	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].udma_enable = pmac_udma_enable;
-		ide_hwifs[ix].udma_start = pmac_udma_start;
-		ide_hwifs[ix].udma_stop = pmac_udma_stop;
-		ide_hwifs[ix].udma_init = pmac_udma_init;
-		ide_hwifs[ix].udma_irq_status = pmac_udma_irq_status;
-		ide_hwifs[ix].udma_setup = pmac_udma_setup;
+		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 		if (!noautodma)
 			ide_hwifs[ix].autodma = 1;
 #endif
-		ide_hwifs[ix].unmask = 1;
 	}
 }
 
+#if 0
+/* This one could be later extended to handle CMD IDE and be used by some kind
+ * of /proc interface. I want to be able to get the devicetree path of a block
+ * device for yaboot configuration
+ */
+struct device_node*
+pmac_ide_get_devnode(ide_drive_t *drive)
+{
+	int i = pmac_ide_find(drive);
+	if (i < 0)
+		return NULL;
+	return pmac_ide[i].node;
+}
+#endif
+
 /* Setup timings for the selected drive (master/slave). I still need to verify if this
  * is enough, I beleive selectproc will be called whenever an IDE command is started,
  * but... */
 static void __pmac
-pmac_ide_selectproc(struct ata_device *drive)
+pmac_ide_selectproc(ide_drive_t *drive)
 {
 	int i = pmac_ide_find(drive);
 	if (i < 0)
@@ -362,73 +361,37 @@
 }
 
 
-/* Note: We don't use the generic routine here because for some
- * yet unexplained reasons, it cause some media-bay CD-ROMs to
- * lockup the bus. Strangely, this new version of the code is
- * almost identical to the generic one and works, I've not yet
- * managed to figure out what bit is causing the lockup in the
- * generic code, possibly a timing issue...
- *
- * --BenH
- */
-static int __pmac
-wait_for_ready(struct ata_device *drive)
-{
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
-
-	while (--timeout) {
-		if(ata_status(drive, 0, BUSY_STAT)) {
-			if (drive->ready_stat == 0)
-				break;
-			else if((drive->status & drive->ready_stat)
-				|| (drive->status & ERR_STAT))
-				break;
-		}
-		mdelay(1);
-	}
-	if((drive->status & ERR_STAT) || timeout <= 0) {
-		if (drive->status & ERR_STAT) {
-			printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n",
-				drive->status);
-		}
-		return 1;
-	}
-	return 0;
-}
-
 static int __pmac
-pmac_ide_do_setfeature(struct ata_device *drive, u8 command)
+pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
 {
 	int result = 1;
 	unsigned long flags;
-	struct ata_channel *hwif = drive->channel;
-
+	ide_hwif_t *hwif = HWIF(drive);
+	
 	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
 	udelay(1);
-	ata_select(drive, 0);
-	ata_mask(drive);
+	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_MASK(HWIF(drive), drive, 0);
 	udelay(1);
-	ata_status(drive, 0, 0); /* Get rid of pending error state */
-	if (wait_for_ready(drive)) {
+	(void)GET_STAT(); /* Get rid of pending error state */
+	if(wait_for_ready(drive, 2000)) {	/* Timeout bumped for some powerbooks */
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
 		goto out;
 	}
 	udelay(10);
-	ata_irq_enable(drive, 0);
+	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
 	OUT_BYTE(command, IDE_NSECTOR_REG);
 	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
 	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
 	udelay(1);
-	local_save_flags(flags);
-	local_irq_enable();
-	result = wait_for_ready(drive);
+	local_irq_set(flags);
+	result = wait_for_ready(drive, 2000);	/* Timeout bumped for some powerbooks */
 	local_irq_restore(flags);
-	ata_irq_enable(drive, 1);
+	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
 	if (result)
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
 out:
-	ata_mask(drive);
+	SELECT_MASK(HWIF(drive), drive, 0);
 	if (result == 0) {
 		drive->id->dma_ultra &= ~0xFF00;
 		drive->id->dma_mword &= ~0x0F00;
@@ -452,37 +415,34 @@
 		}
 	}
 	enable_irq(hwif->irq);
-
 	return result;
 }
 
 /* Calculate PIO timings */
 static void __pmac
-pmac_ide_tuneproc(struct ata_device *drive, u8 pio)
+pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
 {
-	struct ata_timing *t;
+	ide_pio_data_t d;
 	int i;
 	u32 *timings;
 	unsigned accessTicks, recTicks;
 	unsigned accessTime, recTime;
-
+	
 	i = pmac_ide_find(drive);
 	if (i < 0)
 		return;
-
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
+		
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+	if (drive->select.b.unit & 0x01)
+		timings = &pmac_ide[i].timings[1];
 	else
-		pio = XFER_PIO_0 + min_t(u8, pio, 4);
+		timings = &pmac_ide[i].timings[0];
 
-	t = ata_timing_data(pio);
-
-	accessTicks = SYSCLK_TICKS(t->active);
-	timings = &pmac_ide[i].timings[drive->select.b.unit & 0x01];
-
-	recTime = t->cycle - t->active - t->setup;
+	recTime = d.cycle_time - ide_pio_timings[pio].active_time
+			- ide_pio_timings[pio].setup_time;
 	recTime = max(recTime, 150U);
-	accessTime = t->active;
+	accessTime = ide_pio_timings[pio].active_time;
 	accessTime = max(accessTime, 150U);
 	if (pmac_ide[i].kind == controller_kl_ata4 ||
 		pmac_ide[i].kind == controller_kl_ata4_80) {
@@ -517,14 +477,15 @@
 #ifdef IDE_PMAC_DEBUG
 	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
 		pio,  *timings);
-#endif
-
+#endif	
+		
 	if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
 		pmac_ide_selectproc(drive);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int __pmac set_timings_udma(u32 *timings, u8 speed)
+static int __pmac
+set_timings_udma(u32 *timings, byte speed)
 {
 	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
 
@@ -533,20 +494,20 @@
 	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
 
 	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
 			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
 			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
 			TR_66_UDMA_EN;
 #ifdef IDE_PMAC_DEBUG
 	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
 		speed & 0xf,  *timings);
-#endif
+#endif	
 
 	return 0;
 }
 
 static int __pmac
-set_timings_mdma(int intf_type, u32 *timings, u8 speed, int drive_cycle_time)
+set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
 {
 	int cycleTime, accessTime, recTime;
 	unsigned accessTicks, recTicks;
@@ -564,7 +525,7 @@
 	/* Adjust for drive */
 	if (drive_cycle_time && drive_cycle_time > cycleTime)
 		cycleTime = drive_cycle_time;
-	/* OHare limits according to some old Apple sources */
+	/* OHare limits according to some old Apple sources */	
 	if ((intf_type == controller_ohare) && (cycleTime < 150))
 		cycleTime = 150;
 	/* Get the proper timing array for this controller */
@@ -596,7 +557,7 @@
 #ifdef IDE_PMAC_DEBUG
 	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
 		cycleTime, accessTime, recTime);
-#endif
+#endif	
 	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
 		/* 66Mhz cell */
 		accessTicks = SYSCLK_TICKS_66(accessTime);
@@ -626,7 +587,7 @@
 		int halfTick = 0;
 		int origAccessTime = accessTime;
 		int origRecTime = recTime;
-
+		
 		accessTicks = SYSCLK_TICKS(accessTime);
 		accessTicks = max(accessTicks, 1U);
 		accessTicks = min(accessTicks, 0x1fU);
@@ -638,7 +599,7 @@
 		if ((accessTicks > 1) &&
 		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
 		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-			halfTick = 1;
+            		halfTick = 1;
 			accessTicks--;
 		}
 		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
@@ -647,19 +608,19 @@
 		if (halfTick)
 			*timings |= TR_33_MDMA_HALFTICK;
 	}
-# ifdef IDE_PMAC_DEBUG
+#ifdef IDE_PMAC_DEBUG
 	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
 		speed & 0xf,  *timings);
-# endif
+#endif	
 	return 0;
 }
-#endif
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 /* You may notice we don't use this function on normal operation,
  * our, normal mdma function is supposed to be more precise
  */
 static int __pmac
-pmac_ide_tune_chipset (struct ata_device *drive, u8 speed)
+pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	int intf		= pmac_ide_find(drive);
 	int unit		= (drive->select.b.unit & 0x01);
@@ -668,21 +629,21 @@
 
 	if (intf < 0)
 		return 1;
-
+		
 	timings = &pmac_ide[intf].timings[unit];
-
+	
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 		case XFER_UDMA_4:
 		case XFER_UDMA_3:
 			if (pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;
+				return 1;		
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
 			if (pmac_ide[intf].kind != controller_kl_ata4 &&
 				pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;
+				return 1;		
 			ret = set_timings_udma(timings, speed);
 			break;
 		case XFER_MW_DMA_2:
@@ -694,7 +655,7 @@
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
 			return 1;
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 		case XFER_PIO_4:
 		case XFER_PIO_3:
 		case XFER_PIO_2:
@@ -711,8 +672,8 @@
 	ret = pmac_ide_do_setfeature(drive, speed);
 	if (ret)
 		return ret;
-
-	pmac_ide_selectproc(drive);
+		
+	pmac_ide_selectproc(drive);	
 	drive->current_speed = speed;
 
 	return 0;
@@ -722,7 +683,7 @@
 sanitize_timings(int i)
 {
 	unsigned value;
-
+	
 	switch(pmac_ide[i].kind) {
 		case controller_kl_ata4:
 		case controller_kl_ata4_80:
@@ -750,8 +711,8 @@
 pmac_ide_check_base(ide_ioreg_t base)
 {
 	int ix;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
 		if (base == pmac_ide[ix].regbase)
 			return ix;
 	return -1;
@@ -774,7 +735,7 @@
 pmac_find_ide_boot(char *bootdevice, int n)
 {
 	int i;
-
+	
 	/*
 	 * Look through the list of IDE interfaces for this one.
 	 */
@@ -785,11 +746,11 @@
 		name = pmac_ide[i].node->full_name;
 		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
 			/* XXX should cope with the 2nd drive as well... */
-			return mk_kdev(ide_majors[i], 0);
+			return MKDEV(ide_majors[i], 0);
 		}
 	}
 
-	return NODEV;
+	return 0;
 }
 
 void __init
@@ -801,7 +762,7 @@
 	struct device_node *p, **pp, *removables, **rp;
 	unsigned long base;
 	int irq, big_delay;
-	struct ata_channel *hwif;
+	ide_hwif_t *hwif;
 
 	if (_machine != _MACH_Pmac)
 		return;
@@ -832,7 +793,7 @@
 
 	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
 		struct device_node *tp;
-		struct pmac_ide_hwif *pmif;
+		struct pmac_ide_hwif* pmhw;
 		int *bidp;
 		int in_bay = 0;
 		u8 pbus, pid;
@@ -872,7 +833,7 @@
 			++i;
 		if (i >= MAX_HWIFS)
 			break;
-		pmif = &pmac_ide[i];
+		pmhw = &pmac_ide[i];
 
 		/*
 		 * Some older OFs have bogus sizes, causing request_OF_resource
@@ -901,26 +862,26 @@
 		} else {
 			irq = np->intrs[0].line;
 		}
-		pmif->regbase = base;
-		pmif->irq = irq;
-		pmif->node = np;
+		pmhw->regbase = base;
+		pmhw->irq = irq;
+		pmhw->node = np;
 		if (device_is_compatible(np, "keylargo-ata")) {
 			if (strcmp(np->name, "ata-4") == 0)
-				pmif->kind = controller_kl_ata4;
+				pmhw->kind = controller_kl_ata4;
 			else
-				pmif->kind = controller_kl_ata3;
+				pmhw->kind = controller_kl_ata3;
 		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmif->kind = controller_heathrow;
+			pmhw->kind = controller_heathrow;
 		else
-			pmif->kind = controller_ohare;
+			pmhw->kind = controller_ohare;
 
 		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+		pmhw->aapl_bus_id =  bidp ? *bidp : 0;
 
-		if (pmif->kind == controller_kl_ata4) {
+		if (pmhw->kind == controller_kl_ata4) {
 			char* cable = get_property(np, "cable-type", NULL);
 			if (cable && !strncmp(cable, "80-", 3))
-				pmif->kind = controller_kl_ata4_80;
+				pmhw->kind = controller_kl_ata4_80;
 		}
 
 		/* Make sure we have sane timings */
@@ -930,24 +891,24 @@
 		    && strcasecmp(np->parent->name, "media-bay") == 0) {
 #ifdef CONFIG_PMAC_PBOOK
 			media_bay_set_ide_infos(np->parent,base,irq,i);
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
 			in_bay = 1;
 			if (!bidp)
-				pmif->aapl_bus_id = 1;
-		} else if (pmif->kind == controller_ohare) {
+				pmhw->aapl_bus_id = 1;
+		} else if (pmhw->kind == controller_ohare) {
 			/* The code below is having trouble on some ohare machines
 			 * (timing related ?). Until I can put my hand on one of these
 			 * units, I keep the old way
 			 */
 			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
 		} else {
-			/* This is necessary to enable IDE when net-booting */
+ 			/* This is necessary to enable IDE when net-booting */
 			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmif->aapl_bus_id);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+				pmhw->aapl_bus_id);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1);
 			mdelay(10);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0);
 			big_delay = 1;
 		}
 
@@ -956,19 +917,19 @@
 		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
 		hwif->chipset = ide_pmac;
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
-		hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
 		hwif->pci_dev = pdev;
 #ifdef CONFIG_PMAC_PBOOK
 		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
 			hwif->noprobe = 0;
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (pdev && np->n_addrs >= 2) {
+		if (np->n_addrs >= 2) {
 			/* has a DBDMA controller channel */
 			pmac_ide_setup_dma(np, i);
 		}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 		++i;
 	}
@@ -978,19 +939,19 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
+	register_reboot_notifier(&pmac_ide_reboot_notifier);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
-static void __init
+static void __init 
 pmac_ide_setup_dma(struct device_node *np, int ix)
 {
 	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
 
 	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
-		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n",
-			np->name);
+		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
 		return;
 	}
 
@@ -1017,15 +978,10 @@
 	if (pmif->sg_table == NULL) {
 		pci_free_consistent(	ide_hwifs[ix].pci_dev,
 					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-					pmif->dma_table_cpu, pmif->dma_table_dma);
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
 		return;
 	}
-	ide_hwifs[ix].udma_enable = pmac_udma_enable;
-	ide_hwifs[ix].udma_start = pmac_udma_start;
-	ide_hwifs[ix].udma_stop = pmac_udma_stop;
-	ide_hwifs[ix].udma_init = pmac_udma_init;
-	ide_hwifs[ix].udma_irq_status = pmac_udma_irq_status;
-	ide_hwifs[ix].udma_setup = pmac_udma_setup;
+	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
 		ide_hwifs[ix].autodma = 1;
@@ -1035,33 +991,49 @@
 static int
 pmac_ide_build_sglist (int ix, struct request *rq)
 {
-	struct ata_channel *hwif = &ide_hwifs[ix];
+	ide_hwif_t *hwif = &ide_hwifs[ix];
 	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
+	struct buffer_head *bh;
 	struct scatterlist *sg = pmif->sg_table;
-	int nents;
-
-	nents = blk_rq_map_sg(q, rq, pmif->sg_table);
-
-	if (rq->q && nents > rq->nr_phys_segments)
-		printk("ide-pmac: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
+	int nents = 0;
 
-	if (rq_data_dir(rq) == READ)
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	if (rq->cmd == READ)
 		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
 
 	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
 }
 
 static int
-pmac_raw_build_sglist (int ix, struct request *rq)
+pmac_ide_raw_build_sglist (int ix, struct request *rq)
 {
-	struct ata_channel *hwif = &ide_hwifs[ix];
+	ide_hwif_t *hwif = &ide_hwifs[ix];
 	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct scatterlist *sg = pmif->sg_table;
+	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
-	struct ata_taskfile *args = rq->special;
+	ide_task_t *args = rq->special;
 	unsigned char *virt_addr = rq->buffer;
 	int sector_count = rq->nr_sectors;
 
@@ -1069,22 +1041,20 @@
 		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
 	else
 		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-
+	
 	if (sector_count > 128) {
 		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].page = virt_to_page(virt_addr);
-		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+		sg[nents].address = virt_addr;
 		sg[nents].length = 128  * SECTOR_SIZE;
 		nents++;
 		virt_addr = virt_addr + (128 * SECTOR_SIZE);
 		sector_count -= 128;
 	}
 	memset(&sg[nents], 0, sizeof(*sg));
-	sg[nents].page = virt_to_page(virt_addr);
-	sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+	sg[nents].address = virt_addr;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
-
+   
 	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
 }
 
@@ -1093,10 +1063,11 @@
  * for a transfer and sets the DBDMA channel to point to it.
  */
 static int
-pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr)
+pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
 {
 	struct dbdma_cmd *table;
 	int i, count = 0;
+	struct request *rq = HWGROUP(drive)->rq;
 	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
 	struct scatterlist *sg;
 
@@ -1109,11 +1080,10 @@
 		udelay(1);
 
 	/* Build sglist */
-	if (rq->flags & REQ_SPECIAL) {
-		pmac_ide[ix].sg_nents = i = pmac_raw_build_sglist(ix, rq);
-	} else {
+	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
+		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
+	else
 		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
-	}
 	if (!i)
 		return 0;
 
@@ -1164,9 +1134,9 @@
 
 /* Teardown mappings after DMA has completed.  */
 static void
-pmac_ide_destroy_dmatable(struct ata_channel *ch, int ix)
+pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
 {
-	struct pci_dev *dev = ch->pci_dev;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
 	struct scatterlist *sg = pmac_ide[ix].sg_table;
 	int nents = pmac_ide[ix].sg_nents;
 
@@ -1176,7 +1146,6 @@
 	}
 }
 
-
 static __inline__ unsigned char
 dma_bits_to_command(unsigned char bits)
 {
@@ -1209,23 +1178,26 @@
 
 /* Calculate MultiWord DMA timings */
 static int __pmac
-pmac_ide_mdma_enable(struct ata_device *drive, int idx)
+pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
 {
-	u8 bits = drive->id->dma_mword & 0x07;
-	u8 feature = dma_bits_to_command(bits);
+	byte bits = drive->id->dma_mword & 0x07;
+	byte feature = dma_bits_to_command(bits);
 	u32 *timings;
 	int drive_cycle_time;
 	struct hd_driveid *id = drive->id;
 	int ret;
 
 	/* Set feature on drive */
-	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
 	ret = pmac_ide_do_setfeature(drive, feature);
 	if (ret) {
-		printk(KERN_WARNING "%s: Failed !\n", drive->name);
-		return 0;
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
+	    	return 0;
 	}
 
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+	
 	/* which drive is it ? */
 	if (drive->select.b.unit & 0x01)
 		timings = &pmac_ide[idx].timings[1];
@@ -1241,27 +1213,30 @@
 	/* Calculate controller timings */
 	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
 
-	drive->current_speed = feature;
+	drive->current_speed = feature;	
 	return 1;
 }
 
 /* Calculate Ultra DMA timings */
 static int __pmac
-pmac_ide_udma_enable(struct ata_device *drive, int idx, int high_speed)
+pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
 {
-	u8 bits = drive->id->dma_ultra & 0x1f;
-	u8 feature = udma_bits_to_command(bits, high_speed);
+	byte bits = drive->id->dma_ultra & 0x1f;
+	byte feature = udma_bits_to_command(bits, high_speed);
 	u32 *timings;
 	int ret;
 
 	/* Set feature on drive */
-	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
 	ret = pmac_ide_do_setfeature(drive, feature);
 	if (ret) {
 		printk(KERN_WARNING "%s: Failed !\n", drive->name);
 		return 0;
 	}
 
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+
 	/* which drive is it ? */
 	if (drive->select.b.unit & 0x01)
 		timings = &pmac_ide[idx].timings[1];
@@ -1270,24 +1245,24 @@
 
 	set_timings_udma(timings, feature);
 
-	drive->current_speed = feature;
+	drive->current_speed = feature;	
 	return 1;
 }
 
 static int __pmac
-pmac_ide_check_dma(struct ata_device *drive)
+pmac_ide_check_dma(ide_drive_t *drive)
 {
 	int ata4, udma, idx;
 	struct hd_driveid *id = drive->id;
 	int enable = 1;
 
 	drive->using_dma = 0;
-
+	
 	idx = pmac_ide_find(drive);
 	if (idx < 0)
 		return 0;
-
-	if (drive->type == ATA_FLOPPY)
+		
+	if (drive->media == ide_floppy)
 		enable = 0;
 	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
 		enable = 0;
@@ -1297,9 +1272,9 @@
 	udma = 0;
 	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
 		pmac_ide[idx].kind == controller_kl_ata4_80);
-
+			
 	if(enable) {
-		if (ata4 && (drive->type == ATA_DISK) &&
+		if (ata4 && (drive->media == ide_disk) &&
 		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
 			/* UltraDMA modes. */
 			drive->using_dma = pmac_ide_udma_enable(drive, idx,
@@ -1309,236 +1284,181 @@
 			/* Normal MultiWord DMA modes. */
 			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
 		}
-		ata_irq_enable(drive, 1);
+		OUT_BYTE(0, IDE_CONTROL_REG);
 		/* Apply settings to controller */
 		pmac_ide_selectproc(drive);
 	}
 	return 0;
 }
 
-static void ide_toggle_bounce(struct ata_device *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
-
-	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = drive->channel->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
-static void pmac_udma_enable(struct ata_device *drive, int on, int verbose)
-{
-	if (verbose) {
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	}
-
-	drive->using_dma = 0;
-	ide_toggle_bounce(drive, 0);
-}
-
-static void pmac_udma_start(struct ata_device *drive, struct request *rq)
-{
-	int ix, ata4;
-	volatile struct dbdma_regs *dma;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return;
-
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-
-	out_le32(&dma->control, (RUN << 16) | RUN);
-	/* Make sure it gets to the controller right now */
-	(void)in_le32(&dma->control);
-
-	return;
-}
-
-static int pmac_udma_stop(struct ata_device *drive)
+static int __pmac
+pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	int ix, dstat, ata4;
+//	ide_task_t *args = HWGROUP(drive)->rq->special;
+	int ix, dstat;
 	volatile struct dbdma_regs *dma;
+	byte unit = (drive->select.b.unit & 0x01);
+	byte ata4;
+	int reading = 0;
 
 	/* Can we stuff a pointer to our intf structure in config_data
 	 * or select_data in hwif ?
 	 */
 	ix = pmac_ide_find(drive);
 	if (ix < 0)
-		return 0;
+		return 0;		
 	dma = pmac_ide[ix].dma_regs;
 	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
 		pmac_ide[ix].kind == controller_kl_ata4_80);
-
-	dstat = in_le32(&dma->status);
-	out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-	pmac_ide_destroy_dmatable(drive->channel, ix);
-	/* verify good dma status */
-	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-}
-
-static int pmac_udma_init(struct ata_device *drive, struct request *rq)
-{
-	int ix, ata4;
-	volatile struct dbdma_regs *dma;
-	u8 unit = (drive->select.b.unit & 0x01);
-	int reading;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return ATA_OP_FINISHED;
-
-	if (rq_data_dir(rq) == READ)
+	
+	switch (func) {
+	case ide_dma_off:
+		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+	case ide_dma_off_quietly:
+		drive->using_dma = 0;
+		break;
+	case ide_dma_on:
+	case ide_dma_check:
+		pmac_ide_check_dma(drive);
+		break;
+	case ide_dma_read:
 		reading = 1;
-	else
-		reading = 0;
-
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-
-	if (!pmac_ide_build_dmatable(drive, rq, ix, !reading))
-		return ATA_OP_FINISHED;
-	/* Apple adds 60ns to wrDataSetup on reads */
-	if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[ix].timings[unit] +
-			((reading) ? 0x00800000UL : 0));
-		(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-	}
-
-	if (drive->type != ATA_DISK)
-		return ATA_OP_CONTINUES;
-
-	ata_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
-	if ((rq->flags & REQ_SPECIAL) &&
-		(drive->addressing == 1)) {
-		struct ata_taskfile *args = rq->special;
-		/* FIXME: this is never reached */
-		OUT_BYTE(args->cmd, IDE_COMMAND_REG);
-	} else if (drive->addressing) {
-		OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-	} else {
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-	}
-
-	udma_start(drive, rq);
-
-	return ATA_OP_CONTINUES;
-}
-
-/*
- * FIXME: This should be attached to a channel as we can see now!
- */
-static int pmac_udma_irq_status(struct ata_device *drive)
-{
-	int ix, ata4;
-	volatile struct dbdma_regs *dma;
+	case ide_dma_write:
+		SELECT_READ_WRITE(HWIF(drive),drive,func);
+		if (!pmac_ide_build_dmatable(drive, ix, !reading))
+			return 1;
+		/* Apple adds 60ns to wrDataSetup on reads */
+		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
+			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+				pmac_ide[ix].timings[unit] + 
+				(reading ? 0x00800000UL : 0));
+			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
+		}
+		drive->waiting_for_dma = 1;
+		if (drive->media != ide_disk)
+			return 0;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+	}
+#else
+		if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		} else if (drive->addressing == 1)
+			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+#endif
+	case ide_dma_begin:
+		out_le32(&dma->control, (RUN << 16) | RUN);
+		/* Make sure it gets to the controller right now */
+		(void)in_le32(&dma->control);
+		break;
+	case ide_dma_end: /* returns 1 on error, 0 otherwise */
+		drive->waiting_for_dma = 0;
+		dstat = in_le32(&dma->status);
+		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
+		pmac_ide_destroy_dmatable(drive, ix);
+		/* verify good dma status */
+		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+		/* We have to things to deal with here:
+		 * 
+		 * - The dbdma won't stop if the command was started
+		 * but completed with an error without transfering all
+		 * datas. This happens when bad blocks are met during
+		 * a multi-block transfer.
+		 * 
+		 * - The dbdma fifo hasn't yet finished flushing to
+		 * to system memory when the disk interrupt occurs.
+		 * 
+		 * The trick here is to increment drive->waiting_for_dma,
+		 * and return as if no interrupt occured. If the counter
+		 * reach a certain timeout value, we then return 1. If
+		 * we really got the interrupt, it will happen right away
+		 * again.
+		 * Apple's solution here may be more elegant. They issue
+		 * a DMA channel interrupt (a separate irq line) via a DBDMA
+		 * NOP command just before the STOP, and wait for both the
+		 * disk and DBDMA interrupts to have completed.
+		 */
+		 
+		/* If ACTIVE is cleared, the STOP command have passed and
+		 * transfer is complete.
+		 */
+		if (!(in_le32(&dma->status) & ACTIVE))
+			return 1;
+		if (!drive->waiting_for_dma)
+			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+				called while not waiting\n", ix);
 
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
+		/* If dbdma didn't execute the STOP command yet, the
+		 * active bit is still set */
+		drive->waiting_for_dma++;
+		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+			printk(KERN_WARNING "ide%d, timeout waiting \
+				for dbdma command stop\n", ix);
+			return 1;
+		}
+		udelay(1);
 		return 0;
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
 
-	/* We have to things to deal with here:
-	 *
-	 * - The dbdma won't stop if the command was started but completed with
-	 * an error without transfering all datas. This happens when bad blocks
-	 * are met during a multi-block transfer.
-	 *
-	 * - The dbdma fifo hasn't yet finished flushing to to system memory
-	 * when the disk interrupt occurs.
-	 *
-	 * FIXME: The following *trick* is broken:
-	 *
-	 * The trick here is to increment drive->waiting_for_dma, and return as
-	 * if no interrupt occured. If the counter reach a certain timeout
-	 * value, we then return 1. If we really got the interrupt, it will
-	 * happen right away again.  Apple's solution here may be more elegant.
-	 * They issue a DMA channel interrupt (a separate irq line) via a DBDMA
-	 * NOP command just before the STOP, and wait for both the disk and
-	 * DBDMA interrupts to have completed.
-	 */
-
-	/* If ACTIVE is cleared, the STOP command have passed and
-	 * transfer is complete.
-	 */
-	if (!(in_le32(&dma->status) & ACTIVE))
+		/* Let's implement tose just in case someone wants them */
+	case ide_dma_bad_drive:
+	case ide_dma_good_drive:
+		return check_drive_lists(drive, (func == ide_dma_good_drive));
+	case ide_dma_verbose:
+		return report_drive_dmaing(drive);
+	case ide_dma_retune:
+	case ide_dma_lostirq:
+	case ide_dma_timeout:
+		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
 		return 1;
-
-	if (!test_bit(IDE_DMA, drive->channel->active))
-		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
-
-	/* If dbdma didn't execute the STOP command yet, the
-	 * active bit is still set */
-	set_bit(IDE_DMA, drive->channel->active);
-//	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-//		printk(KERN_WARNING "ide%d, timeout waiting \
-//				for dbdma command stop\n", ix);
-//		return 1;
-//	}
-	udelay(1);
-	return 0;
-}
-
-static int pmac_udma_setup(struct ata_device *drive, int map)
-{
-	/* Change this to better match ide-dma.c */
-	pmac_ide_check_dma(drive);
-	ide_toggle_bounce(drive, drive->using_dma);
-
+	default:
+		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+		return 1;
+	}
 	return 0;
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
-static void idepmac_sleep_device(struct ata_device *drive, int i, unsigned base)
+static void __pmac
+idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
 	int j;
-
+	
 	/* FIXME: We only handle the master IDE disk, we shoud
 	 *        try to fix CD-ROMs here
 	 */
-	switch (drive->type) {
-	case ATA_DISK:
+	switch (drive->media) {
+	case ide_disk:
 		/* Spin down the drive */
-		outb(drive->select.all, base+0x60);
-		(void)inb(base+0x60);
+		OUT_BYTE(drive->select.all, base+0x60);
+		(void) IN_BYTE(base+0x60);
 		udelay(100);
-		outb(0x0, base+0x30);
-		outb(0x0, base+0x20);
-		outb(0x0, base+0x40);
-		outb(0x0, base+0x50);
-		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);
+		OUT_BYTE(0x0, base+0x30);
+		OUT_BYTE(0x0, base+0x20);
+		OUT_BYTE(0x0, base+0x40);
+		OUT_BYTE(0x0, base+0x50);
+		OUT_BYTE(0xe0, base+0x70);
+		OUT_BYTE(0x2, base+0x160);   
 		for (j = 0; j < 10; j++) {
 			int status;
 			mdelay(100);
-			status = inb(base+0x70);
+			status = IN_BYTE(base+0x70);
 			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
 				break;
 		}
 		break;
-	case ATA_ROM:
+	case ide_cdrom:
 		// todo
 		break;
-	case ATA_FLOPPY:
+	case ide_floppy:
 		// todo
 		break;
 	}
@@ -1546,7 +1466,7 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 static void __pmac
-idepmac_wake_device(struct ata_device *drive, int used_dma)
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
 {
 	/* We force the IDE subdriver to check for a media change
 	 * This must be done first or we may lost the condition
@@ -1554,12 +1474,12 @@
 	 * Problem: This can schedule. I moved the block device
 	 * wakeup almost late by priority because of that.
 	 */
-	if (drive->driver != NULL && ata_ops(drive)->check_media_change)
-		ata_ops(drive)->check_media_change(drive);
+	if (DRIVER(drive) && DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
 
 	/* We kick the VFS too (see fix in ide.c revalidate) */
-	__check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
-
+	__check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* We re-enable DMA on the drive if it was active. */
 	/* This doesn't work with the CD-ROM in the media-bay, probably
@@ -1568,12 +1488,14 @@
 	 */
 	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
 		/* Lock HW group */
-		set_bit(IDE_BUSY, drive->channel->active);
+		HWGROUP(drive)->busy = 1;
 		pmac_ide_check_dma(drive);
-		clear_bit(IDE_BUSY, drive->channel->active);
-		spin_unlock_irq(drive->channel->lock);
+		HWGROUP(drive)->busy = 0;
+		if (!list_empty(&drive->queue.queue_head))
+			ide_do_request(HWGROUP(drive), 0);
+		spin_unlock_irq(&ide_lock);
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 }
 
 static void __pmac
@@ -1584,11 +1506,11 @@
 	/* We clear the timings */
 	pmac_ide[i].timings[0] = 0;
 	pmac_ide[i].timings[1] = 0;
-
+	
 	/* The media bay will handle itself just fine */
 	if (mediabay)
 		return;
-
+	
 	/* Disable the bus */
 	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
 }
@@ -1608,49 +1530,53 @@
 }
 
 static void
-idepmac_sleep_drive(struct ata_device *drive, int idx, unsigned long base)
+idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
 {
+	int unlock = 0;
+
 	/* Wait for HW group to complete operations */
-	if (ide_spin_wait_hwgroup(drive))
+	if (ide_spin_wait_hwgroup(drive)) {
 		// What can we do here ? Wake drive we had already
 		// put to sleep and return an error ?
-		return;
-	else {
+	} else {
+		unlock = 1;
 		/* Lock HW group */
-		set_bit(IDE_BUSY, drive->channel->active);
+		HWGROUP(drive)->busy = 1;
 		/* Stop the device */
 		idepmac_sleep_device(drive, idx, base);
-		spin_unlock_irq(drive->channel->lock);
 	}
+	if (unlock)
+		spin_unlock_irq(&ide_lock);
 }
 
 static void
-idepmac_wake_drive(struct ata_device *drive, unsigned long base)
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
 {
+	unsigned long flags;
 	int j;
-
+	
 	/* Reset timings */
 	pmac_ide_selectproc(drive);
 	mdelay(10);
-
+	
 	/* Wait up to 20 seconds for the drive to be ready */
 	for (j = 0; j < 200; j++) {
 		int status;
 		mdelay(100);
-		outb(drive->select.all, base + 0x60);
-		if (inb(base + 0x60) != drive->select.all)
+		OUT_BYTE(drive->select.all, base + 0x60);
+		if (IN_BYTE(base + 0x60) != drive->select.all)
 			continue;
-		status = inb(base + 0x70);
+		status = IN_BYTE(base + 0x70);
 		if (!(status & BUSY_STAT))
 			break;
 	}
 
-	/* We resume processing on the lock group */
-	spin_lock_irq(drive->channel->lock);
-	clear_bit(IDE_BUSY, drive->channel->active);
+	/* We resume processing on the HW group */
+	spin_lock_irqsave(&ide_lock, flags);
+	HWGROUP(drive)->busy = 0;
 	if (!list_empty(&drive->queue.queue_head))
-		do_ide_request(&drive->queue);
-	spin_unlock_irq(drive->channel->lock);
+		ide_do_request(HWGROUP(drive), 0);
+	spin_unlock_irqrestore(&ide_lock, flags);			
 }
 
 /* Note: We support only master drives for now. This will have to be
@@ -1663,7 +1589,7 @@
 	int i, ret;
 	unsigned long base;
 	int big_delay;
-
+ 
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 		break;
@@ -1671,7 +1597,7 @@
 		break;
 	case PBOOK_SLEEP_NOW:
 		for (i = 0; i < pmac_ide_count; ++i) {
-			struct ata_channel *hwif;
+			ide_hwif_t *hwif;
 			int dn;
 
 			if ((base = pmac_ide[i].regbase) == 0)
@@ -1685,7 +1611,7 @@
 			}
 			/* Disable irq during sleep */
 			disable_irq(pmac_ide[i].irq);
-
+			
 			/* Check if this is a media bay with an IDE device or not
 			 * a media bay.
 			 */
@@ -1700,8 +1626,8 @@
 
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
-
-			/* Make sure we have sane timings */
+				
+			/* Make sure we have sane timings */		
 			sanitize_timings(i);
 
 			/* Check if this is a media bay with an IDE device or not
@@ -1709,7 +1635,7 @@
 			 */
 			ret = check_media_bay_by_base(base, MB_CD);
 			if ((ret == 0) || (ret == -ENODEV)) {
-				idepmac_wake_interface(i, base, (ret == 0));
+				idepmac_wake_interface(i, base, (ret == 0));				
 				big_delay = 1;
 			}
 
@@ -1717,18 +1643,18 @@
 		/* Let hardware get up to speed */
 		if (big_delay)
 			mdelay(IDE_WAKEUP_DELAY_MS);
-
+	
 		for (i = 0; i < pmac_ide_count; ++i) {
-			struct ata_channel *hwif;
+			ide_hwif_t *hwif;
 			int used_dma, dn;
 			int irq_on = 0;
-
+			
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
-
+				
 			hwif = &ide_hwifs[i];
 			for (dn=0; dn<MAX_DRIVES; dn++) {
-				struct ata_device *drive = &hwif->drives[dn];
+				ide_drive_t *drive = &hwif->drives[dn];
 				if (!drive->present)
 					continue;
 				/* We don't have re-configured DMA yet */
@@ -1749,3 +1675,50 @@
 	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
+
+static int __pmac
+pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+	int i, gotone;
+	unsigned long base;
+
+	if (code != SYS_HALT && code != SYS_POWER_OFF)
+		return 0;
+
+	gotone = 0;
+	for (i = 0; i < pmac_ide_count; ++i) {
+		ide_hwif_t *hwif;
+		ide_drive_t *drive;
+		int unlock = 0;
+		int dn;
+
+		if ((base = pmac_ide[i].regbase) == 0)
+				continue;	
+
+		hwif = &ide_hwifs[i];
+		for (dn=0; dn<MAX_DRIVES; dn++) {
+			drive = &hwif->drives[dn];
+			if (drive->present) {
+				gotone = 1;
+				/* Wait for HW group to complete operations */
+				if (ide_spin_wait_hwgroup(drive)) {
+					// What can we do here ? Wake drive we had already
+					// put to sleep and return an error ?
+				} else {
+					unlock = 1;
+					/* Lock HW group */
+					HWGROUP(drive)->busy = 1;
+
+					/* Stop the device */
+					idepmac_sleep_device(drive, i, base);
+				}
+			}
+			if (unlock)
+				spin_unlock_irq(&ide_lock);
+		}
+	}
+	if (gotone)
+		mdelay(1000);
+		
+	return NOTIFY_DONE;
+}
diff -Nru a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
--- a/drivers/ide/ide-pnp.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/ide-pnp.c	Tue Aug 27 12:28:08 2002
@@ -1,4 +1,5 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ * linux/drivers/ide/ide-pnp.c
  *
  * This file provides autodetection for ISA PnP IDE interfaces.
  * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
@@ -12,10 +13,9 @@
  *
  * You should have received a copy of the GNU General Public License
  * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
  */
 
-#include <linux/types.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -32,6 +32,21 @@
 
 #define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")
 
+#define GENERIC_HD_DATA		0
+#define GENERIC_HD_ERROR	1
+#define GENERIC_HD_NSECTOR	2
+#define GENERIC_HD_SECTOR	3
+#define GENERIC_HD_LCYL		4
+#define GENERIC_HD_HCYL		5
+#define GENERIC_HD_SELECT	6
+#define GENERIC_HD_STATUS	7
+
+static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
+	GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, 
+	GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
+	GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
+};
+
 /* ISA PnP device table entry */
 struct pnp_dev_t {
 	unsigned short card_vendor, card_device, vendor, device;
@@ -43,7 +58,6 @@
 {
 	hw_regs_t hw;
 	int index;
-	int i;
 
 	if (!enable)
 		return 0;
@@ -51,24 +65,14 @@
 	if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
 		return 1;
 
-	/* Initialize register access base values. */
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-		hw.io_ports[i] = DEV_IO(dev, 0) + i;
-	hw.io_ports[IDE_CONTROL_OFFSET] = DEV_IO(dev, 1);
-
-	hw.irq = DEV_IRQ(dev, 0);
-	hw.dma = NO_DMA;
-	hw.ack_intr = NULL;
+	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
+			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
+			0, NULL, DEV_IRQ(dev, 0));
 
-	index = ide_register_hw(&hw);
+	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1) {
-		struct ata_channel *ch;
-
-		ch = &ide_hwifs[index];
-		ch->pci_dev = dev;
-		printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
-
+	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
@@ -76,13 +80,11 @@
 }
 
 /* Add your devices here :)) */
-static struct pnp_dev_t pnp_devices[] __initdata = {
-	/* Generic ESDI/IDE/ATA compatible hard disk controller */
-	{
-		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+struct pnp_dev_t idepnp_devices[] __initdata = {
+  	/* Generic ESDI/IDE/ATA compatible hard disk controller */
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
-		pnpide_generic_init
-	},
+		pnpide_generic_init },
 	{	0 }
 };
 
@@ -120,20 +122,20 @@
 		return;
 	}
 #endif
-	for (dev_type = pnp_devices; dev_type->vendor; dev_type++) {
+	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
 
 			if (dev->active)
 				continue;
 
-			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-				printk(KERN_ERR "ide: %s prepare failed\n", DEV_NAME(dev));
+       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+				printk("ide: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
 
 			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-				printk(KERN_ERR "ide: %s activate failed\n", DEV_NAME(dev));
+				printk("ide: %s activate failed\n", DEV_NAME(dev));
 				continue;
 			}
 
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-probe.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,1027 @@
+/*
+ *  linux/drivers/ide/ide-probe.c	Version 1.07	March 18, 2001
+ *
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *                and Andre Hedrick <andre@linux-ide.org>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This is the IDE probe module, as evolved from hd.c and ide.c.
+ *
+ * Version 1.00		move drive probing code from ide.c to ide-probe.c
+ * Version 1.01		fix compilation problem for m68k
+ * Version 1.02		increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
+ *			 by Andrea Arcangeli
+ * Version 1.03		fix for (hwif->chipset == ide_4drives)
+ * Version 1.04		fixed buggy treatments of known flash memory cards
+ *
+ * Version 1.05		fix for (hwif->chipset == ide_pdc4030)
+ *			added ide6/7/8/9
+ *			allowed for secondary flash card to be detectable
+ *			 with new flag : drive->ata_flash : 1;
+ * Version 1.06		stream line request queue and prep for cascade project.
+ * Version 1.07		max_sect <= 255; slower disks would get behind and
+ * 			then fall over when they get to 256.	Paul G.
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static inline void do_identify (ide_drive_t *drive, byte cmd)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int bswap = 1;
+	struct hd_driveid *id;
+
+	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	if (!id) {
+		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		goto err_kmalloc;
+	}
+	/* read 512 bytes of id info */
+#if 1
+	ata_input_data(drive, id, SECTOR_WORDS);
+#else
+	{
+		unsigned long	*ptr = (unsigned long *)id ;
+		unsigned long	lcount = 256/2 ;
+                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
+		while( lcount-- )
+			*ptr++ = inl(IDE_DATA_REG);
+	}
+#endif
+	local_irq_enable();
+	ide_fix_driveid(id);
+
+	if (id->word156 == 0x4d42) {
+		printk("%s: drive->id->word156 == 0x%04x \n",
+			drive->name, drive->id->word156);
+	}
+
+	if (!drive->forced_lun)
+		drive->last_lun = id->last_lun & 0x7;
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
+	/*
+	 * EATA SCSI controllers do a hardware ATA emulation:
+	 * Ignore them if there is a driver for them available.
+	 */
+	if ((id->model[0] == 'P' && id->model[1] == 'M')
+	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
+		goto err_misc;
+	}
+#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
+
+	/*
+	 *  WIN_IDENTIFY returns little-endian info,
+	 *  WIN_PIDENTIFY *usually* returns little-endian info.
+	 */
+	if (cmd == WIN_PIDENTIFY) {
+		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+			bswap ^= 1;	/* Vertos drives may still be weird */
+	}
+	ide_fixstring (id->model,     sizeof(id->model),     bswap);
+	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+
+	if (strstr(id->model, "E X A B Y T E N E S T"))
+		goto err_misc;
+
+	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	printk("%s: %s, ", drive->name, id->model);
+	drive->present = 1;
+
+	/*
+	 * Check for an ATAPI device
+	 */
+	if (cmd == WIN_PIDENTIFY) {
+		byte type = (id->config >> 8) & 0x1f;
+		printk("ATAPI ");
+#ifdef CONFIG_BLK_DEV_PDC4030
+		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
+			printk(" -- not supported on 2nd Promise port\n");
+			goto err_misc;
+		}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+		switch (type) {
+			case ide_floppy:
+				if (!strstr(id->model, "CD-ROM")) {
+					if (!strstr(id->model, "oppy") &&
+					    !strstr(id->model, "poyp") &&
+					    !strstr(id->model, "ZIP"))
+						printk("cdrom or floppy?, assuming ");
+					if (drive->media != ide_cdrom) {
+						printk ("FLOPPY");
+						break;
+					}
+				}
+				type = ide_cdrom;	/* Early cdrom models used zero */
+			case ide_cdrom:
+				drive->removable = 1;
+#ifdef CONFIG_PPC
+				/* kludge for Apple PowerBook internal zip */
+				if (!strstr(id->model, "CD-ROM") &&
+				    strstr(id->model, "ZIP")) {
+					printk ("FLOPPY");
+					type = ide_floppy;
+					break;
+				}
+#endif
+				printk ("CD/DVD-ROM");
+				break;
+			case ide_tape:
+				printk ("TAPE");
+				break;
+			case ide_optical:
+				printk ("OPTICAL");
+				drive->removable = 1;
+				break;
+			default:
+				printk("UNKNOWN (type %d)", type);
+				break;
+		}
+		printk (" drive\n");
+		drive->media = type;
+		return;
+	}
+
+	/*
+	 * Not an ATAPI device: looks like a "regular" hard disk
+	 */
+	if (id->config & (1<<7))
+		drive->removable = 1;
+	/*
+	 * Prevent long system lockup probing later for non-existant
+	 * slave drive if the hwif is actually a flash memory card of
+	 * some variety:
+	 */
+	if (drive_is_flashcard(drive)) {
+		ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];
+		if (!mate->ata_flash) {
+			mate->present = 0;
+			mate->noprobe = 1;
+		}
+	}
+	drive->media = ide_disk;
+	printk("ATA DISK drive\n");
+	QUIRK_LIST(hwif, drive);
+	return;
+
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+	return;
+}
+
+/*
+ * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
+ * and waits for a response.  It also monitors irqs while this is
+ * happening, in hope of automatically determining which one is
+ * being used by the interface.
+ *
+ * Returns:	0  device was identified
+ *		1  device timed-out (no response to identify request)
+ *		2  device aborted the command (refused to identify itself)
+ */
+static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+{
+//	ide_hwif_t *hwif = HWIF(drive);
+	int rc;
+	ide_ioreg_t hd_status;
+	unsigned long timeout;
+	byte s, a;
+
+	if (IDE_CONTROL_REG) {
+		/* take a deep breath */
+		ide_delay_50ms();
+		a = IN_BYTE(IDE_ALTSTATUS_REG);
+		s = IN_BYTE(IDE_STATUS_REG);
+		if ((a ^ s) & ~INDEX_STAT) {
+			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+		} else {
+			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+		}
+	} else {
+		ide_delay_50ms();
+		hd_status = IDE_STATUS_REG;
+	}
+
+	/* set features register for atapi identify command to be sure of reply */
+	if ((cmd == WIN_PIDENTIFY))
+		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+
+#if CONFIG_BLK_DEV_PDC4030
+	if (HWIF(drive)->chipset == ide_pdc4030) {
+		/* DC4030 hosted drives need their own identify... */
+		extern int pdc4030_identify(ide_drive_t *);
+		if (pdc4030_identify(drive)) {
+			return 1;
+		}
+	} else
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+	timeout += jiffies;
+	do {
+		if (time_after(jiffies, timeout)) {
+			return 1;	/* drive timed-out */
+		}
+		ide_delay_50ms();		/* give drive a breather */
+	} while (IN_BYTE(hd_status) & BUSY_STAT);
+
+	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
+	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+		unsigned long flags;
+		local_irq_save(flags);
+			/* local CPU only; some systems need this */
+		do_identify(drive, cmd); /* drive returned ID */
+		rc = 0;			/* drive responded with ID */
+		(void) GET_STAT();	/* clear drive IRQ */
+		local_irq_restore(flags);
+	} else
+		rc = 2;			/* drive refused ID */
+	return rc;
+}
+
+static int try_to_identify (ide_drive_t *drive, byte cmd)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int retval;
+	int autoprobe = 0;
+	unsigned long cookie = 0;
+
+	if (IDE_CONTROL_REG && !hwif->irq) {
+		autoprobe = 1;
+		cookie = probe_irq_on();
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+	}
+
+	retval = actual_try_to_identify(drive, cmd);
+
+	if (autoprobe) {
+		int irq;
+		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
+		(void) GET_STAT();			/* clear drive IRQ */
+		udelay(5);
+		irq = probe_irq_off(cookie);
+		if (!hwif->irq) {
+			if (irq > 0) {
+				hwif->irq = irq;
+			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
+				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+#ifdef CONFIG_BLK_DEV_CMD640
+#ifdef CMD640_DUMP_REGS
+				if (hwif->chipset == ide_cmd640) {
+					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+					CMD640_DUMP_REGS;
+				}
+#endif /* CMD640_DUMP_REGS */
+#endif /* CONFIG_BLK_DEV_CMD640 */
+			}
+		}
+	}
+	return retval;
+}
+
+
+/*
+ * do_probe() has the difficult job of finding a drive if it exists,
+ * without getting hung up if it doesn't exist, without trampling on
+ * ethernet cards, and without leaving any IRQs dangling to haunt us later.
+ *
+ * If a drive is "known" to exist (from CMOS or kernel parameters),
+ * but does not respond right away, the probe will "hang in there"
+ * for the maximum wait time (about 30 seconds), otherwise it will
+ * exit much more quickly.
+ *
+ * Returns:	0  device was identified
+ *		1  device timed-out (no response to identify request)
+ *		2  device aborted the command (refused to identify itself)
+ *		3  bad status from device (possible for ATAPI drives)
+ *		4  probe was not attempted because failure was obvious
+ */
+static int do_probe (ide_drive_t *drive, byte cmd)
+{
+	int rc;
+	ide_hwif_t *hwif = HWIF(drive);
+	if (drive->present) {	/* avoid waiting for inappropriate probes */
+		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
+			return 4;
+	}
+#ifdef DEBUG
+	printk("probing for %s: present=%d, media=%d, probetype=%s\n",
+		drive->name, drive->present, drive->media,
+		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
+#endif
+	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
+	SELECT_DRIVE(hwif,drive);
+	ide_delay_50ms();
+	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+		if (drive->select.b.unit != 0) {
+			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
+		}
+		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+	}
+
+	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) ||
+	    drive->present || cmd == WIN_PIDENTIFY) {
+		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
+			rc = try_to_identify(drive,cmd); /* failed: try again */
+		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+			unsigned long timeout;
+			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			ide_delay_50ms();
+			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			ide_delay_50ms();
+			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			timeout = jiffies;
+			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+				ide_delay_50ms();
+			rc = try_to_identify(drive, cmd);
+		}
+		if (rc == 1)
+			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
+		(void) GET_STAT();		/* ensure drive irq is clear */
+	} else {
+		rc = 3;				/* not present or maybe ATAPI */
+	}
+	if (drive->select.b.unit != 0) {
+		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		ide_delay_50ms();
+		(void) GET_STAT();		/* ensure drive irq is clear */
+	}
+	return rc;
+}
+
+/*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long timeout;
+
+	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+	SELECT_DRIVE(hwif, drive);
+	ide_delay_50ms();
+	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			printk("failed (timeout)\n");
+			return;
+		}
+		ide_delay_50ms();
+	} while (GET_STAT() & BUSY_STAT);
+	ide_delay_50ms();
+	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
+		printk("failed (status = 0x%02x)\n", GET_STAT());
+	else
+		printk("success\n");
+
+	if (do_probe(drive, WIN_IDENTIFY) >= 2)	/* if !(success||timed-out) */
+		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+}
+
+/*
+ * probe_for_drive() tests for existence of a given drive using do_probe().
+ *
+ * Returns:	0  no device was found
+ *		1  device was found (note: drive->present might still be 0)
+ */
+static inline byte probe_for_drive (ide_drive_t *drive)
+{
+	if (drive->noprobe)			/* skip probing? */
+		return drive->present;
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
+		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+	}
+	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
+		enable_nest(drive);
+	if (!drive->present)
+		return 0;			/* drive not found */
+	if (drive->id == NULL) {		/* identification failed? */
+		if (drive->media == ide_disk) {
+			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
+			 drive->name, drive->cyl, drive->head, drive->sect);
+		} else if (drive->media == ide_cdrom) {
+			printk("%s: ATAPI cdrom (?)\n", drive->name);
+		} else {
+			drive->present = 0;	/* nuke it */
+		}
+	}
+	return 1;	/* drive was found */
+}
+
+/*
+ * Calculate the region that this interface occupies,
+ * handling interfaces where the registers may not be
+ * ordered sanely.  We deal with the CONTROL register
+ * separately.
+ */
+static int hwif_check_regions (ide_hwif_t *hwif)
+{
+	int region_errors = 0;
+
+	hwif->straight8 = 0;
+	region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+	region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+
+	if (hwif->io_ports[IDE_CONTROL_OFFSET])
+		region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (hwif->io_ports[IDE_IRQ_OFFSET])
+		region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+	/*
+	 * If any errors are return, we drop the hwif interface.
+	 */
+	return(region_errors);
+}
+
+static void hwif_register (ide_hwif_t *hwif)
+{
+	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
+		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+		hwif->straight8 = 1;
+		goto jump_straight8;
+	}
+
+	if (hwif->io_ports[IDE_DATA_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_ERROR_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_SECTOR_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_LCYL_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_HCYL_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_SELECT_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
+	if (hwif->io_ports[IDE_STATUS_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+
+jump_straight8:
+	if (hwif->io_ports[IDE_CONTROL_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (hwif->io_ports[IDE_IRQ_OFFSET])
+		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+}
+
+/*
+ * This routine only knows how to look for drive units 0 and 1
+ * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
+ */
+static void probe_hwif (ide_hwif_t *hwif)
+{
+	unsigned int unit;
+	unsigned long flags;
+
+	if (hwif->noprobe)
+		return;
+#ifdef CONFIG_BLK_DEV_IDE
+	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
+		extern void probe_cmos_for_drives(ide_hwif_t *);
+
+		probe_cmos_for_drives (hwif);
+	}
+#endif
+
+	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
+#if CONFIG_BLK_DEV_PDC4030
+	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+	    (hwif_check_regions(hwif))) {
+		int msgout = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				drive->present = 0;
+				printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
+				msgout = 1;
+			}
+		}
+		if (!msgout)
+			printk("%s: ports already in use, skipping probe\n", hwif->name);
+		return;	
+	}
+
+	local_irq_set(flags);
+	/*
+	 * Second drive should only exist if first drive was found,
+	 * but a lot of cdrom drives are configured as single slaves.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		(void) probe_for_drive (drive);
+		if (drive->present && !hwif->present) {
+			hwif->present = 1;
+			if (hwif->chipset != ide_4drives ||
+			    !hwif->mate->present) {
+				hwif_register(hwif);
+			}
+		}
+	}
+	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
+		unsigned long timeout = jiffies + WAIT_WORSTCASE;
+		byte stat;
+
+		printk("%s: reset\n", hwif->name);
+		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			ide_delay_50ms();
+			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+
+	}
+	local_irq_restore(flags);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		if (drive->present) {
+			if (hwif->tuneproc != NULL && drive->autotune == 1)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+		}
+	}
+}
+
+#if MAX_HWIFS > 1
+/*
+ * save_match() is used to simplify logic in init_irq() below.
+ *
+ * A loophole here is that we may not know about a particular
+ * hwif's irq until after that hwif is actually probed/initialized..
+ * This could be a problem for the case where an hwif is on a
+ * dual interface that requires serialization (eg. cmd640) and another
+ * hwif using one of the same irqs is initialized beforehand.
+ *
+ * This routine detects and reports such situations, but does not fix them.
+ */
+static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+{
+	ide_hwif_t *m = *match;
+
+	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
+		if (!new->hwgroup)
+			return;
+		printk("%s: potential irq problem with %s and %s\n",
+			hwif->name, new->name, m->name);
+	}
+	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
+		*match = new;
+}
+#endif /* MAX_HWIFS > 1 */
+
+/*
+ * init request queue
+ */
+static void ide_init_queue(ide_drive_t *drive)
+{
+	request_queue_t *q = &drive->queue;
+	int max_sectors;
+
+	q->queuedata = HWGROUP(drive);
+	blk_init_queue(q, do_ide_request, &ide_lock);
+	blk_queue_segment_boundary(q, 0xffff);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	max_sectors = 127;
+#else
+	max_sectors = 255;
+#endif
+	blk_queue_max_sectors(q, max_sectors);
+
+	/* IDE DMA can do PRD_ENTRIES number of segments. */
+	blk_queue_max_hw_segments(q, PRD_ENTRIES);
+
+	/* This is a driver limit and could be eliminated. */
+	blk_queue_max_phys_segments(q, PRD_ENTRIES);
+}
+
+/*
+ * This routine sets up the irq for an ide interface, and creates a new
+ * hwgroup for the irq/hwif if none was previously assigned.
+ *
+ * Much of the code is for correctly detecting/handling irq sharing
+ * and irq serialization situations.  This is somewhat complex because
+ * it handles static as well as dynamic (PCMCIA) IDE interfaces.
+ *
+ * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
+ * interrupts completely disabled.  This can be bad for interrupt latency,
+ * but anything else has led to problems on some machines.  We re-enable
+ * interrupts as much as we can safely do in most places.
+ */
+static int init_irq (ide_hwif_t *hwif)
+{
+	unsigned long flags;
+	unsigned int index;
+	ide_hwgroup_t *hwgroup, *new_hwgroup;
+	ide_hwif_t *match = NULL;
+
+	
+	/* Allocate the buffer and potentially sleep first */
+	
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+	
+	spin_lock_irqsave(&ide_lock, flags);
+
+	hwif->hwgroup = NULL;
+#if MAX_HWIFS > 1
+	/*
+	 * Group up with any other hwifs that share our irq(s).
+	 */
+	for (index = 0; index < MAX_HWIFS; index++) {
+		ide_hwif_t *h = &ide_hwifs[index];
+		if (h->hwgroup) {  /* scan only initialized hwif's */
+			if (hwif->irq == h->irq) {
+				hwif->sharing_irq = h->sharing_irq = 1;
+				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+					save_match(hwif, h, &match);
+				}
+			}
+			if (hwif->serialized) {
+				if (hwif->mate && hwif->mate->irq == h->irq)
+					save_match(hwif, h, &match);
+			}
+			if (h->serialized) {
+				if (h->mate && hwif->irq == h->mate->irq)
+					save_match(hwif, h, &match);
+			}
+		}
+	}
+#endif /* MAX_HWIFS > 1 */
+	/*
+	 * If we are still without a hwgroup, then form a new one
+	 */
+	if (match) {
+		hwgroup = match->hwgroup;
+		if(new_hwgroup)
+			kfree(new_hwgroup);
+	} else {
+		hwgroup = new_hwgroup;
+		if (!hwgroup) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 1;
+		}
+		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
+		hwgroup->hwif     = hwif->next = hwif;
+		hwgroup->rq       = NULL;
+		hwgroup->handler  = NULL;
+		hwgroup->drive    = NULL;
+		hwgroup->busy     = 0;
+		init_timer(&hwgroup->timer);
+		hwgroup->timer.function = &ide_timer_expiry;
+		hwgroup->timer.data = (unsigned long) hwgroup;
+	}
+
+	/*
+	 * Allocate the irq, if not already obtained for another hwif
+	 */
+	if (!match || match->irq != hwif->irq) {
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
+#else /* !CONFIG_IDEPCI_SHARE_IRQ */
+		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
+		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
+			if (!match)
+				kfree(hwgroup);
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 1;
+		}
+	}
+
+	/*
+	 * Everything is okay, so link us into the hwgroup
+	 */
+	hwif->hwgroup = hwgroup;
+	hwif->next = hwgroup->hwif->next;
+	hwgroup->hwif->next = hwif;
+
+	for (index = 0; index < MAX_DRIVES; ++index) {
+		ide_drive_t *drive = &hwif->drives[index];
+		if (!drive->present)
+			continue;
+		if (!hwgroup->drive)
+			hwgroup->drive = drive;
+		drive->next = hwgroup->drive->next;
+		hwgroup->drive->next = drive;
+		ide_init_queue(drive);
+	}
+	if (!hwgroup->hwif) {
+		hwgroup->hwif = HWIF(hwgroup->drive);
+#ifdef DEBUG
+		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
+#endif
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+		/* all CPUs; safe now that hwif->hwgroup is set up */
+
+#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+		hwif->io_ports[IDE_DATA_OFFSET],
+		hwif->io_ports[IDE_DATA_OFFSET]+7,
+		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
+#elif defined(__sparc__)
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name,
+		hwif->io_ports[IDE_DATA_OFFSET],
+		hwif->io_ports[IDE_DATA_OFFSET]+7,
+		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
+#else
+	printk("%s at %p on irq 0x%08x", hwif->name,
+		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
+#endif /* __mc68000__ && CONFIG_APUS */
+	if (match)
+		printk(" (%sed with %s)",
+			hwif->sharing_irq ? "shar" : "serializ", match->name);
+	printk("\n");
+	return 0;
+}
+
+/*
+ * init_gendisk() (as opposed to ide_geninit) is called for each major device,
+ * after probing for drives, to allocate partition tables and other data
+ * structures needed for the routines in genhd.c.  ide_geninit() gets called
+ * somewhat later, during the partition check.
+ */
+static void init_gendisk (ide_hwif_t *hwif)
+{
+	struct gendisk *gd;
+	struct hd_struct *part;
+	devfs_handle_t *de_arr;
+	char *flags;
+	unsigned int unit, units, minors;
+	extern devfs_handle_t ide_devfs_handle;
+	char *names;
+
+#if 1
+	units = MAX_DRIVES;
+#else
+	/* figure out maximum drive number on the interface */
+	for (units = MAX_DRIVES; units > 0; --units) {
+		if (hwif->drives[units-1].present)
+			break;
+	}
+#endif
+
+	minors    = units * (1<<PARTN_BITS);
+	gd        = kmalloc(MAX_DRIVES * sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
+	memset(gd, 0, MAX_DRIVES * sizeof(struct gendisk));
+
+	part  = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!part)
+		goto err_kmalloc_gd_part;
+
+	memset(part, 0, minors * sizeof(struct hd_struct));
+
+	de_arr = kmalloc(sizeof(devfs_handle_t) * MAX_DRIVES, GFP_KERNEL);
+	if (!de_arr)
+		goto err_kmalloc_gd_de_arr;
+	memset(de_arr, 0, sizeof(devfs_handle_t) * MAX_DRIVES);
+
+	flags = kmalloc(sizeof(char) * MAX_DRIVES, GFP_KERNEL);
+	if (!flags)
+		goto err_kmalloc_gd_flags;
+	memset(flags, 0, sizeof(char) * MAX_DRIVES);
+
+	names = kmalloc (4 * MAX_DRIVES, GFP_KERNEL);
+	if (!names)
+		goto err_kmalloc_gd_names;
+	memset(names, 0, 4 * MAX_DRIVES);
+
+	for (unit = 0; unit < units; ++unit) {
+		gd[unit].part = part + (unit << PARTN_BITS);
+		gd[unit].de_arr = de_arr + unit;
+		gd[unit].flags = flags + unit;
+		hwif->drives[unit].part = gd[unit].part;
+		gd[unit].major  = hwif->major;
+		gd[unit].first_minor = unit << PARTN_BITS;
+		sprintf(names + 4*unit, "hd%c",'a'+hwif->index*MAX_DRIVES+unit);
+		gd[unit].major_name = names + 4*unit;
+		gd[unit].minor_shift = PARTN_BITS; 
+		gd[unit].nr_real = 1;
+		gd[unit].fops = ide_fops;
+		hwif->gd[unit] = gd + unit;
+		add_gendisk(gd + unit);
+	}
+
+	for (unit = 0; unit < units; ++unit) {
+#if 1
+		char name[64];
+		ide_add_generic_settings(hwif->drives + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		sprintf (name, "host%d/bus%d/target%d/lun%d",
+			(hwif->channel && hwif->mate) ?
+			hwif->mate->index : hwif->index,
+			hwif->channel, unit, hwif->drives[unit].lun);
+		if (hwif->drives[unit].present)
+			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+#else
+		if (hwif->drives[unit].present) {
+			char name[64];
+
+			ide_add_generic_settings(hwif->drives + unit);
+			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+			sprintf (name, "host%d/bus%d/target%d/lun%d",
+				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
+				 hwif->channel, unit, hwif->drives[unit].lun);
+			hwif->drives[unit].de =
+				devfs_mk_dir (ide_devfs_handle, name, NULL);
+		}
+#endif
+	}
+	return;
+
+err_kmalloc_gd_names:
+	kfree(names);
+err_kmalloc_gd_flags:
+	kfree(de_arr);
+err_kmalloc_gd_de_arr:
+	kfree(part);
+err_kmalloc_gd_part:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+}
+
+static int hwif_init (ide_hwif_t *hwif)
+{
+	if (!hwif->present)
+		return 0;
+	if (!hwif->irq) {
+		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
+		{
+			printk("%s: DISABLED, NO IRQ\n", hwif->name);
+			return (hwif->present = 0);
+		}
+	}
+#ifdef CONFIG_BLK_DEV_HD
+	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+		printk("%s: CANNOT SHARE IRQ WITH OLD "
+			"HARDDISK DRIVER (hd.c)\n", hwif->name);
+		return (hwif->present = 0);
+	}
+#endif /* CONFIG_BLK_DEV_HD */
+	
+	hwif->present = 0; /* we set it back to 1 if all is ok below */
+
+	if (register_blkdev (hwif->major, hwif->name, ide_fops)) {
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
+			hwif->name, hwif->major);
+		return (hwif->present = 0);
+	}
+	
+	if (init_irq(hwif)) {
+		int i = hwif->irq;
+		/*
+		 *	It failed to initialise. Find the default IRQ for 
+		 *	this port and try that.
+		 */
+		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+			printk("%s: Disabled unable to get IRQ %d.\n",
+				hwif->name, i);
+			(void) unregister_blkdev (hwif->major, hwif->name);
+			return (hwif->present = 0);
+		}
+		if (init_irq(hwif)) {
+			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
+				hwif->name, i, hwif->irq);
+			(void) unregister_blkdev (hwif->major, hwif->name);
+			return (hwif->present = 0);
+		}
+		printk("%s: probed IRQ %d failed, using default.\n",
+			hwif->name, hwif->irq);
+	}
+	
+	init_gendisk(hwif);
+	blk_dev[hwif->major].data = hwif;
+	blk_dev[hwif->major].queue = ide_get_queue;
+	hwif->present = 1;	/* success */
+
+#if (DEBUG_SPINLOCK > 0)
+{
+	static int done = 0;
+	if (!done++)
+		printk("ide_lock is %p\n", &ide_lock);    /* FIXME */
+}
+#endif
+	return hwif->present;
+}
+
+void export_ide_init_queue (ide_drive_t *drive)
+{
+	ide_init_queue(drive);
+}
+
+byte export_probe_for_drive (ide_drive_t *drive)
+{
+	return probe_for_drive(drive);
+}
+
+EXPORT_SYMBOL(export_ide_init_queue);
+EXPORT_SYMBOL(export_probe_for_drive);
+
+int ideprobe_init (void);
+static ide_module_t ideprobe_module = {
+	IDE_PROBE_MODULE,
+	ideprobe_init,
+	NULL
+};
+
+int ideprobe_init (void)
+{
+	unsigned int index;
+	int probe[MAX_HWIFS];
+	
+	MOD_INC_USE_COUNT;
+	memset(probe, 0, MAX_HWIFS * sizeof(int));
+	for (index = 0; index < MAX_HWIFS; ++index)
+		probe[index] = !ide_hwifs[index].present;
+
+	/*
+	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
+	 */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			probe_hwif(&ide_hwifs[index]);
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			hwif_init(&ide_hwifs[index]);
+	if (!ide_probe)
+		ide_probe = &ideprobe_module;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
+int init_module (void)
+{
+	unsigned int index;
+	
+	for (index = 0; index < MAX_HWIFS; ++index)
+		ide_unregister(index);
+	ideprobe_init();
+	create_proc_ide_interfaces();
+	ide_xlate_1024_hook = ide_xlate_1024;
+	return 0;
+}
+
+void cleanup_module (void)
+{
+	ide_probe = NULL;
+	ide_xlate_1024_hook = 0;
+}
+MODULE_LICENSE("GPL");
+#endif /* MODULE */
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-proc.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,961 @@
+/*
+ *  linux/drivers/ide/ide-proc.c	Version 1.03	January  2, 1998
+ *
+ *  Copyright (C) 1997-1998	Mark Lord
+ */
+
+/*
+ * This is the /proc/ide/ filesystem implementation.
+ *
+ * The major reason this exists is to provide sufficient access
+ * to driver and config data, such that user-mode programs can
+ * be developed to handle chipset tuning for most PCI interfaces.
+ * This should provide better utilities, and less kernel bloat.
+ *
+ * The entire pci config space for a PCI interface chipset can be
+ * retrieved by just reading it.  e.g.    "cat /proc/ide3/config"
+ *
+ * To modify registers *safely*, do something like:
+ *   echo "P40:88" >/proc/ide/ide3/config
+ * That expression writes 0x88 to pci config register 0x40
+ * on the chip which controls ide3.  Multiple tuples can be issued,
+ * and the writes will be completed as an atomic set:
+ *   echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
+ *
+ * All numbers must be specified using pairs of ascii hex digits.
+ * It is important to note that these writes will be performed
+ * after waiting for the IDE controller (both interfaces)
+ * to be completely idle, to ensure no corruption of I/O in progress.
+ *
+ * Non-PCI registers can also be written, using "R" in place of "P"
+ * in the above examples.  The size of the port transfer is determined
+ * by the number of pairs of hex digits given for the data.  If a two
+ * digit value is given, the write will be a byte operation; if four
+ * digits are used, the write will be performed as a 16-bit operation;
+ * and if eight digits are specified, a 32-bit "dword" write will be
+ * performed.  Odd numbers of digits are not permitted.
+ *
+ * If there is an error *anywhere* in the string of registers/data
+ * then *none* of the writes will be performed.
+ *
+ * Drive/Driver settings can be retrieved by reading the drive's
+ * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
+ * To write a new value "val" into a specific setting "name", use:
+ *   echo "name:val" >/proc/ide/ide0/hda/settings
+ *
+ * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
+ * smart_thresholds, capabilities]" will issue an IDENTIFY /
+ * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
+ * SENSE CAPABILITIES command to /dev/hda, and then dump out the
+ * returned data as 256 16-bit words.  The "hdparm" utility will
+ * be updated someday soon to use this mechanism.
+ *
+ * Feel free to develop and distribute fancy GUI configuration
+ * utilities for your favorite PCI chipsets.  I'll be working on
+ * one for the Promise 20246 someday soon.  -ml
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifdef CONFIG_BLK_DEV_AEC62XX
+extern byte aec62xx_proc;
+int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_AEC62XX */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+extern byte ali_proc;
+int (*ali_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD74XX
+extern byte amd74xx_proc;
+int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_AMD74XX */
+#ifdef CONFIG_BLK_DEV_CMD64X
+extern byte cmd64x_proc;
+int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+extern byte cs5530_proc;
+int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern byte hpt34x_proc;
+int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+extern byte hpt366_proc;
+int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern byte pdc202xx_proc;
+int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_PDC202XX */
+#ifdef CONFIG_BLK_DEV_PIIX
+extern byte piix_proc;
+int (*piix_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_PIIX */
+#ifdef CONFIG_BLK_DEV_SVWKS
+extern byte svwks_proc;
+int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_SVWKS */
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern byte sis_proc;
+int (*sis_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_SLC90E66
+extern byte slc90e66_proc;
+int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_SLC90E66 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte via_proc;
+int (*via_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
+static int ide_getxdigit(char c)
+{
+	int digit;
+	if (isdigit(c))
+		digit = c - '0';
+	else if (isxdigit(c))
+		digit = tolower(c) - 'a' + 10;
+	else
+		digit = -1;
+	return digit;
+}
+
+static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
+{
+	char errbuf[16];
+	int i;
+	if (len >= sizeof(errbuf))
+		len = sizeof(errbuf) - 1;
+	for (i = 0; i < len; ++i) {
+		char c = data[i];
+		if (!c || c == '\n')
+			c = '\0';
+		else if (iscntrl(c))
+			c = '?';
+		errbuf[i] = c;
+	}
+	errbuf[i] = '\0';
+	printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
+	return -EINVAL;
+}
+
+static struct proc_dir_entry * proc_ide_root = NULL;
+
+static int proc_ide_write_config
+	(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *)data;
+	int		for_real = 0;
+	unsigned long	startn = 0, n, flags;
+	const char	*start = NULL, *msg = NULL;
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		return -EACCES;
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	/*
+	 * Do one full pass to verify all parameters,
+	 * then do another to actually write the regs.
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	do {
+		const char *p;
+		if (for_real) {
+			unsigned long timeout = jiffies + (3 * HZ);
+			ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
+			ide_hwgroup_t *mategroup = NULL;
+			if (hwif->mate && hwif->mate->hwgroup)
+				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
+			spin_lock_irqsave(&ide_lock, flags);
+			while (mygroup->busy ||
+			       (mategroup && mategroup->busy)) {
+				spin_unlock_irqrestore(&ide_lock, flags);
+				if (time_after(jiffies, timeout)) {
+					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
+					spin_unlock_irqrestore(&ide_lock, flags);
+					return -EBUSY;
+				}
+				spin_lock_irqsave(&ide_lock, flags);
+			}
+		}
+		p = buffer;
+		n = count;
+		while (n > 0) {
+			int d, digits;
+			unsigned int reg = 0, val = 0, is_pci;
+			start = p;
+			startn = n--;
+			switch (*p++) {
+				case 'R':	is_pci = 0;
+						break;
+				case 'P':	is_pci = 1;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+							break;
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+						msg = "not a PCI device";
+						goto parse_error;
+				default:	msg = "expected 'R' or 'P'";
+						goto parse_error;
+			}
+			digits = 0;
+			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+				reg = (reg << 4) | d;
+				--n;
+				++p;
+				++digits;
+			}
+			if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
+				msg = "bad/missing register number";
+				goto parse_error;
+			}
+			if (n-- == 0 || *p++ != ':') {
+				msg = "missing ':'";
+				goto parse_error;
+			}
+			digits = 0;
+			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+				val = (val << 4) | d;
+				--n;
+				++p;
+				++digits;
+			}
+			if (digits != 2 && digits != 4 && digits != 8) {
+				msg = "bad data, 2/4/8 digits required";
+				goto parse_error;
+			}
+			if (n > 0 && !isspace(*p)) {
+				msg = "expected whitespace after data";
+				goto parse_error;
+			}
+			while (n > 0 && isspace(*p)) {
+				--n;
+				++p;
+			}
+#ifdef CONFIG_BLK_DEV_IDEPCI
+			if (is_pci && (reg & ((digits >> 1) - 1))) {
+				msg = "misaligned access";
+				goto parse_error;
+			}
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+			if (for_real) {
+#if 0
+				printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
+#endif
+				if (is_pci) {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+					int rc = 0;
+					struct pci_dev *dev = hwif->pci_dev;
+					switch (digits) {
+						case 2:	msg = "byte";
+							rc = pci_write_config_byte(dev, reg, val);
+							break;
+						case 4:	msg = "word";
+							rc = pci_write_config_word(dev, reg, val);
+							break;
+						case 8:	msg = "dword";
+							rc = pci_write_config_dword(dev, reg, val);
+							break;
+					}
+					if (rc) {
+						spin_unlock_irqrestore(&ide_lock, flags);
+						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
+							msg, dev->bus->number, dev->devfn, reg, val);
+						printk("proc_ide_write_config: error %d\n", rc);
+						return -EIO;
+					}
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+				} else {	/* not pci */
+#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+
+/*
+ * Geert Uytterhoeven
+ *
+ * unless you can explain me what it really does.
+ * On m68k, we don't have outw() and outl() yet,
+ * and I need a good reason to implement it.
+ * 
+ * BTW, IMHO the main remaining portability problem with the IDE driver 
+ * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
+ * 
+ * I think all accesses should be done using
+ * 
+ *     ide_in[bwl](ide_device_instance, offset)
+ *     ide_out[bwl](ide_device_instance, value, offset)
+ * 
+ * so the architecture specific code can #define ide_{in,out}[bwl] to the
+ * appropriate function.
+ * 
+ */
+					switch (digits) {
+						case 2:	OUT_BYTE(val, reg);
+							break;
+						case 4:	OUT_WORD(val, reg);
+							break;
+						case 8:	outl(val, reg);
+							break;
+					}
+#endif /* !__mc68000__ && !CONFIG_APUS */
+				}
+			}
+		}
+	} while (!for_real++);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return count;
+parse_error:
+	spin_unlock_irqrestore(&ide_lock, flags);
+	printk("parse error\n");
+	return xx_xx_parse_error(start, startn, msg);
+}
+
+static int proc_ide_read_config
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	char		*out = page;
+	int		len;
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_hwif_t	*hwif = (ide_hwif_t *)data;
+	struct pci_dev	*dev = hwif->pci_dev;
+	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
+		int reg = 0;
+
+		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
+			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+		do {
+			byte val;
+			int rc = pci_read_config_byte(dev, reg, &val);
+			if (rc) {
+				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
+					rc, dev->bus->number, dev->devfn, reg);
+				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+			} else
+				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+		} while (reg < 0x100);
+	} else
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		out += sprintf(out, "(none)\n");
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+
+static int ide_getdigit(char c)
+{
+	int digit;
+	if (isdigit(c))
+		digit = c - '0';
+	else
+		digit = -1;
+	return digit;
+}
+
+static int proc_ide_read_drivers
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	char		*out = page;
+	int		len;
+	ide_module_t	*p = ide_modules;
+	ide_driver_t	*driver;
+
+	while (p) {
+		driver = (ide_driver_t *) p->info;
+		if (driver)
+			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
+		p = p->next;
+	}
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_imodel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+	const char	*name;
+
+	switch (hwif->chipset) {
+		case ide_unknown:	name = "(none)";	break;
+		case ide_generic:	name = "generic";	break;
+		case ide_pci:		name = "pci";		break;
+		case ide_cmd640:	name = "cmd640";	break;
+		case ide_dtc2278:	name = "dtc2278";	break;
+		case ide_ali14xx:	name = "ali14xx";	break;
+		case ide_qd65xx:	name = "qd65xx";	break;
+		case ide_umc8672:	name = "umc8672";	break;
+		case ide_ht6560b:	name = "ht6560b";	break;
+		case ide_pdc4030:	name = "pdc4030";	break;
+		case ide_rz1000:	name = "rz1000";	break;
+		case ide_trm290:	name = "trm290";	break;
+		case ide_cmd646:	name = "cmd646";	break;
+		case ide_cy82c693:	name = "cy82c693";	break;
+		case ide_4drives:	name = "4drives";	break;
+		case ide_pmac:		name = "mac-io";	break;
+		default:		name = "(unknown)";	break;
+	}
+	len = sprintf(page, "%s\n", name);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_mate
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+
+	if (hwif && hwif->mate && hwif->mate->present)
+		len = sprintf(page, "%s\n", hwif->mate->name);
+	else
+		len = sprintf(page, "(none)\n");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_channel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+
+	page[0] = hwif->channel ? '1' : '0';
+	page[1] = '\n';
+	len = 2;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_identify
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *)data;
+	int		len = 0, i = 0;
+
+	if (drive && !taskfile_lib_get_identify(drive, page)) {
+		unsigned short *val = (unsigned short *) page;
+		char *out = ((char *)val) + (SECTOR_WORDS * 4);
+		page = out;
+		do {
+			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			val += 1;
+		} while (i < (SECTOR_WORDS * 2));
+		len = out - page;
+	}
+	else
+		len = sprintf(page, "\n");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_settings
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	ide_settings_t	*setting = (ide_settings_t *) drive->settings;
+	char		*out = page;
+	int		len, rc, mul_factor, div_factor;
+
+	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
+	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
+	while(setting) {
+		mul_factor = setting->mul_factor;
+		div_factor = setting->div_factor;
+		out += sprintf(out, "%-24s", setting->name);
+		if ((rc = ide_read_setting(drive, setting)) >= 0)
+			out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
+		else
+			out += sprintf(out, "%-16s", "write-only");
+		out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
+		if (setting->rw & SETTING_READ)
+			out += sprintf(out, "r");
+		if (setting->rw & SETTING_WRITE)
+			out += sprintf(out, "w");
+		out += sprintf(out, "\n");
+		setting = setting->next;
+	}
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+#define MAX_LEN	30
+
+static int proc_ide_write_settings
+	(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		name[MAX_LEN + 1];
+	int		for_real = 0, len;
+	unsigned long	n;
+	const char	*start = NULL;
+	ide_settings_t	*setting;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	/*
+	 * Do one full pass to verify all parameters,
+	 * then do another to actually write the new settings.
+	 */
+	do {
+		const char *p;
+		p = buffer;
+		n = count;
+		while (n > 0) {
+			int d, digits;
+			unsigned int val = 0;
+			start = p;
+
+			while (n > 0 && *p != ':') {
+				--n;
+				p++;
+			}
+			if (*p != ':')
+				goto parse_error;
+			len = IDE_MIN(p - start, MAX_LEN);
+			strncpy(name, start, IDE_MIN(len, MAX_LEN));
+			name[len] = 0;
+
+			if (n > 0) {
+				--n;
+				p++;
+			} else
+				goto parse_error;
+			
+			digits = 0;
+			while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
+				val = (val * 10) + d;
+				--n;
+				++p;
+				++digits;
+			}
+			if (n > 0 && !isspace(*p))
+				goto parse_error;
+			while (n > 0 && isspace(*p)) {
+				--n;
+				++p;
+			}
+			setting = ide_find_setting_by_name(drive, name);
+			if (!setting)
+				goto parse_error;
+
+			if (for_real)
+				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
+		}
+	} while (!for_real++);
+	return count;
+parse_error:
+	printk("proc_ide_write_settings(): parse error\n");
+	return -EINVAL;
+}
+
+int proc_ide_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	ide_driver_t    *driver = (ide_driver_t *) drive->driver;
+	int		len;
+
+	if (!driver)
+		len = sprintf(page, "(none)\n");
+        else
+		len = sprintf(page,"%llu\n",
+			      (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_geometry
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		*out = page;
+	int		len;
+
+	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_dmodel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	struct hd_driveid *id = drive->id;
+	int		len;
+
+	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_driver
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	ide_driver_t	*driver = (ide_driver_t *) drive->driver;
+	int		len;
+
+	if (!driver)
+		len = sprintf(page, "(none)\n");
+	else
+		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_write_driver
+	(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (ide_replace_subdriver(drive, buffer))
+		return -EINVAL;
+	return count;
+}
+
+static int proc_ide_read_media
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	const char	*media;
+	int		len;
+
+	switch (drive->media) {
+		case ide_disk:	media = "disk\n";
+				break;
+		case ide_cdrom:	media = "cdrom\n";
+				break;
+		case ide_tape:	media = "tape\n";
+				break;
+		case ide_floppy:media = "floppy\n";
+				break;
+		default:	media = "UNKNOWN\n";
+				break;
+	}
+	strcpy(page,media);
+	len = strlen(media);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static ide_proc_entry_t generic_drive_entries[] = {
+	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
+	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
+	{ "media",	S_IFREG|S_IRUGO,	proc_ide_read_media,	NULL },
+	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_dmodel,	NULL },
+	{ "settings",	S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings,	proc_ide_write_settings },
+	{ NULL,	0, NULL, NULL }
+};
+
+void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
+{
+	struct proc_dir_entry *ent;
+
+	if (!dir || !p)
+		return;
+	while (p->name != NULL) {
+		ent = create_proc_entry(p->name, p->mode, dir);
+		if (!ent) return;
+		ent->nlink = 1;
+		ent->data = data;
+		ent->read_proc = p->read_proc;
+		ent->write_proc = p->write_proc;
+		p++;
+	}
+}
+
+void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
+{
+	if (!dir || !p)
+		return;
+	while (p->name != NULL) {
+		remove_proc_entry(p->name, dir);
+		p++;
+	}
+}
+
+static void create_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
+	char name[64];
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+		ide_driver_t *driver = drive->driver;
+
+		if (!drive->present)
+			continue;
+		if (drive->proc)
+			continue;
+
+		drive->proc = proc_mkdir(drive->name, parent);
+		if (drive->proc) {
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+			if (driver) {
+				ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+				ide_add_proc_entries(drive->proc, driver->proc, drive);
+			}
+		}
+		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+		ent = proc_symlink(drive->name, proc_ide_root, name);
+		if (!ent) return;
+	}
+}
+
+void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
+	char name[64];
+//	ide_driver_t *driver = drive->driver;
+
+	if (drive->present && !drive->proc) {
+		drive->proc = proc_mkdir(drive->name, parent);
+		if (drive->proc)
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+
+/*
+ * assume that we have these already, however, should test FIXME!
+ * if (driver) {
+ *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ *      ide_add_proc_entries(drive->proc, driver->proc, drive);
+ * }
+ *
+ */
+		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+		ent = proc_symlink(drive->name, proc_ide_root, name);
+		if (!ent)
+			return;
+	}
+}
+
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	ide_driver_t *driver = drive->driver;
+
+	if (drive->proc) {
+		if (driver)
+			ide_remove_proc_entries(drive->proc, driver->proc);
+		ide_remove_proc_entries(drive->proc, generic_drive_entries);
+		remove_proc_entry(drive->name, proc_ide_root);
+		remove_proc_entry(drive->name, hwif->proc);
+		drive->proc = NULL;
+	}
+}
+
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+//		ide_driver_t *driver = drive->driver;
+
+		if (drive->proc)
+			destroy_proc_ide_device(hwif, drive);
+	}
+}
+
+static ide_proc_entry_t hwif_entries[] = {
+	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
+	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
+	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
+	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
+	{ NULL,	0, NULL, NULL }
+};
+
+void create_proc_ide_interfaces(void)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+
+		if (!hwif->present)
+			continue;
+		if (!hwif->proc) {
+			hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
+			if (!hwif->proc)
+				return;
+			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
+		}
+		create_proc_ide_drives(hwif);
+	}
+}
+
+static void destroy_proc_ide_interfaces(void)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		int exist = (hwif->proc != NULL);
+#if 0
+		if (!hwif->present)
+			continue;
+#endif
+		if (exist) {
+			destroy_proc_ide_drives(hwif);
+			ide_remove_proc_entries(hwif->proc, hwif_entries);
+			remove_proc_entry(hwif->name, proc_ide_root);
+			hwif->proc = NULL;
+		} else
+			continue;
+	}
+}
+
+void proc_ide_create(void)
+{
+	proc_ide_root = proc_mkdir("ide", 0);
+	if (!proc_ide_root) return;
+
+	create_proc_ide_interfaces();
+
+	create_proc_read_entry("drivers", 0, proc_ide_root,
+				proc_ide_read_drivers, NULL);
+
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	if ((aec62xx_display_info) && (aec62xx_proc))
+		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
+#endif /* CONFIG_BLK_DEV_AEC62XX */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+	if ((ali_display_info) && (ali_proc))
+		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD74XX
+	if ((amd74xx_display_info) && (amd74xx_proc))
+		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
+#endif /* CONFIG_BLK_DEV_AMD74XX */
+#ifdef CONFIG_BLK_DEV_CMD64X
+	if ((cmd64x_display_info) && (cmd64x_proc))
+		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+	if ((cs5530_display_info) && (cs5530_proc))
+		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+	if ((hpt34x_display_info) && (hpt34x_proc))
+		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+	if ((hpt366_display_info) && (hpt366_proc))
+		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_SVWKS
+	if ((svwks_display_info) && (svwks_proc))
+		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
+#endif /* CONFIG_BLK_DEV_SVWKS */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+	if ((pdc202xx_display_info) && (pdc202xx_proc))
+		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
+#endif /* CONFIG_BLK_DEV_PDC202XX */
+#ifdef CONFIG_BLK_DEV_PIIX
+	if ((piix_display_info) && (piix_proc))
+		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
+#endif /* CONFIG_BLK_DEV_PIIX */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	if ((sis_display_info) && (sis_proc))
+		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_SLC90E66
+	if ((slc90e66_display_info) && (slc90e66_proc))
+		create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
+#endif /* CONFIG_BLK_DEV_SLC90E66 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	if ((via_display_info) && (via_proc))
+		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+}
+
+void proc_ide_destroy(void)
+{
+	/*
+	 * Mmmm.. does this free up all resources,
+	 * or do we need to do a more proper cleanup here ??
+	 */
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	if ((aec62xx_display_info) && (aec62xx_proc))
+		remove_proc_entry("ide/aec62xx",0);
+#endif /* CONFIG_BLK_DEV_AEC62XX */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+	if ((ali_display_info) && (ali_proc))
+		remove_proc_entry("ide/ali",0);
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD74XX
+	if ((amd74xx_display_info) && (amd74xx_proc))
+		remove_proc_entry("ide/amd74xx",0);
+#endif /* CONFIG_BLK_DEV_AMD74XX */
+#ifdef CONFIG_BLK_DEV_CMD64X
+	if ((cmd64x_display_info) && (cmd64x_proc))
+		remove_proc_entry("ide/cmd64x",0);
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+	if ((cs5530_display_info) && (cs5530_proc))
+		remove_proc_entry("ide/cs5530",0);
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+	if ((hpt34x_display_info) && (hpt34x_proc))
+		remove_proc_entry("ide/hpt34x",0);
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+	if ((hpt366_display_info) && (hpt366_proc))
+		remove_proc_entry("ide/hpt366",0);
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+	if ((pdc202xx_display_info) && (pdc202xx_proc))
+		remove_proc_entry("ide/pdc202xx",0);
+#endif /* CONFIG_BLK_DEV_PDC202XX */
+#ifdef CONFIG_BLK_DEV_PIIX
+	if ((piix_display_info) && (piix_proc))
+		remove_proc_entry("ide/piix",0);
+#endif /* CONFIG_BLK_DEV_PIIX */
+#ifdef CONFIG_BLK_DEV_SVWKS
+	if ((svwks_display_info) && (svwks_proc))
+		remove_proc_entry("ide/svwks",0);
+#endif /* CONFIG_BLK_DEV_SVWKS */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	if ((sis_display_info) && (sis_proc))
+		remove_proc_entry("ide/sis", 0);
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_SLC90E66
+	if ((slc90e66_display_info) && (slc90e66_proc))
+		remove_proc_entry("ide/slc90e66",0);
+#endif /* CONFIG_BLK_DEV_SLC90E66 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	if ((via_display_info) && (via_proc))
+		remove_proc_entry("ide/via",0);
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
+	remove_proc_entry("ide/drivers", 0);
+	destroy_proc_ide_interfaces();
+	remove_proc_entry("ide", 0);
+}
diff -Nru a/drivers/ide/ide-swarm.c b/drivers/ide/ide-swarm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-swarm.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/swarm_ide.h>
+
+void __init swarm_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Set up our stuff */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
+	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
+//	hwif->hw->ack_intr                     = swarm_ide_ack_intr;
+	hwif->hw.irq                          = SWARM_IDE_INT;
+	hwif->ideproc                         = swarm_ideproc;
+
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->irq = hwif->hw.irq;
+	printk("SWARM onboard IDE configured as device %i\n", i);
+}
+
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/ide-tape.c	Tue Aug 27 12:28:08 2002
@@ -1,23 +1,406 @@
 /*
+ * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
+ * $Header$
+ *
  * This driver was constructed as a student project in the software laboratory
  * of the faculty of electrical engineering in the Technion - Israel's
  * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
  *
  * It is hereby placed under the terms of the GNU general public license.
  * (See linux/COPYING).
+ */
+ 
+/*
+ * IDE ATAPI streaming tape driver.
  *
- * Contributors:
+ * This driver is a part of the Linux ide driver and works in co-operation
+ * with linux/drivers/block/ide.c.
  *
- * Oct 1999		Arnold Niessen, <niessen@iae.nl>, <arnold.niessen@philips.com>
- * Nov 2000, Jan 2001	Marcel Mol,	<marcel@mesa.nl>
- * Apr 2001		Willem Riede,	<osst@riede.org>
+ * The driver, in co-operation with ide.c, basically traverses the 
+ * request-list for the block device interface. The character device
+ * interface, on the other hand, creates new requests, adds them
+ * to the request-list of the block device, and waits for their completion.
+ *
+ * Pipelined operation mode is now supported on both reads and writes.
+ *
+ * The block device major and minor numbers are determined from the
+ * tape's relative position in the ide interfaces, as explained in ide.c.
+ *
+ * The character device interface consists of the following devices:
+ *
+ * ht0		major 37, minor 0	first  IDE tape, rewind on close.
+ * ht1		major 37, minor 1	second IDE tape, rewind on close.
+ * ...
+ * nht0		major 37, minor 128	first  IDE tape, no rewind on close.
+ * nht1		major 37, minor 129	second IDE tape, no rewind on close.
+ * ...
+ *
+ * Run linux/scripts/MAKEDEV.ide to create the above entries.
+ *
+ * The general magnetic tape commands compatible interface, as defined by
+ * include/linux/mtio.h, is accessible through the character device.
+ *
+ * General ide driver configuration options, such as the interrupt-unmask
+ * flag, can be configured by issuing an ioctl to the block device interface,
+ * as any other ide device.
+ *
+ * Our own ide-tape ioctl's can be issued to either the block device or
+ * the character device interface.
+ *
+ * Maximal throughput with minimal bus load will usually be achieved in the
+ * following scenario:
+ *
+ *	1.	ide-tape is operating in the pipelined operation mode.
+ *	2.	No buffering is performed by the user backup program.
+ *
+ * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
+ * 
+ * Ver 0.1   Nov  1 95   Pre-working code :-)
+ * Ver 0.2   Nov 23 95   A short backup (few megabytes) and restore procedure
+ *                        was successful ! (Using tar cvf ... on the block
+ *                        device interface).
+ *                       A longer backup resulted in major swapping, bad
+ *                        overall Linux performance and eventually failed as
+ *                        we received non serial read-ahead requests from the
+ *                        buffer cache.
+ * Ver 0.3   Nov 28 95   Long backups are now possible, thanks to the
+ *                        character device interface. Linux's responsiveness
+ *                        and performance doesn't seem to be much affected
+ *                        from the background backup procedure.
+ *                       Some general mtio.h magnetic tape operations are
+ *                        now supported by our character device. As a result,
+ *                        popular tape utilities are starting to work with
+ *                        ide tapes :-)
+ *                       The following configurations were tested:
+ *                       	1. An IDE ATAPI TAPE shares the same interface
+ *                       	   and irq with an IDE ATAPI CDROM.
+ *                        	2. An IDE ATAPI TAPE shares the same interface
+ *                          	   and irq with a normal IDE disk.
+ *                        Both configurations seemed to work just fine !
+ *                        However, to be on the safe side, it is meanwhile
+ *                        recommended to give the IDE TAPE its own interface
+ *                        and irq.
+ *                       The one thing which needs to be done here is to
+ *                        add a "request postpone" feature to ide.c,
+ *                        so that we won't have to wait for the tape to finish
+ *                        performing a long media access (DSC) request (such
+ *                        as a rewind) before we can access the other device
+ *                        on the same interface. This effect doesn't disturb
+ *                        normal operation most of the time because read/write
+ *                        requests are relatively fast, and once we are
+ *                        performing one tape r/w request, a lot of requests
+ *                        from the other device can be queued and ide.c will
+ *			  service all of them after this single tape request.
+ * Ver 1.0   Dec 11 95   Integrated into Linux 1.3.46 development tree.
+ *                       On each read / write request, we now ask the drive
+ *                        if we can transfer a constant number of bytes
+ *                        (a parameter of the drive) only to its buffers,
+ *                        without causing actual media access. If we can't,
+ *                        we just wait until we can by polling the DSC bit.
+ *                        This ensures that while we are not transferring
+ *                        more bytes than the constant referred to above, the
+ *                        interrupt latency will not become too high and
+ *                        we won't cause an interrupt timeout, as happened
+ *                        occasionally in the previous version.
+ *                       While polling for DSC, the current request is
+ *                        postponed and ide.c is free to handle requests from
+ *                        the other device. This is handled transparently to
+ *                        ide.c. The hwgroup locking method which was used
+ *                        in the previous version was removed.
+ *                       Use of new general features which are provided by
+ *                        ide.c for use with atapi devices.
+ *                        (Programming done by Mark Lord)
+ *                       Few potential bug fixes (Again, suggested by Mark)
+ *                       Single character device data transfers are now
+ *                        not limited in size, as they were before.
+ *                       We are asking the tape about its recommended
+ *                        transfer unit and send a larger data transfer
+ *                        as several transfers of the above size.
+ *                        For best results, use an integral number of this
+ *                        basic unit (which is shown during driver
+ *                        initialization). I will soon add an ioctl to get
+ *                        this important parameter.
+ *                       Our data transfer buffer is allocated on startup,
+ *                        rather than before each data transfer. This should
+ *                        ensure that we will indeed have a data buffer.
+ * Ver 1.1   Dec 14 95   Fixed random problems which occurred when the tape
+ *                        shared an interface with another device.
+ *                        (poll_for_dsc was a complete mess).
+ *                       Removed some old (non-active) code which had
+ *                        to do with supporting buffer cache originated
+ *                        requests.
+ *                       The block device interface can now be opened, so
+ *                        that general ide driver features like the unmask
+ *                        interrupts flag can be selected with an ioctl.
+ *                        This is the only use of the block device interface.
+ *                       New fast pipelined operation mode (currently only on
+ *                        writes). When using the pipelined mode, the
+ *                        throughput can potentially reach the maximum
+ *                        tape supported throughput, regardless of the
+ *                        user backup program. On my tape drive, it sometimes
+ *                        boosted performance by a factor of 2. Pipelined
+ *                        mode is enabled by default, but since it has a few
+ *                        downfalls as well, you may want to disable it.
+ *                        A short explanation of the pipelined operation mode
+ *                        is available below.
+ * Ver 1.2   Jan  1 96   Eliminated pipelined mode race condition.
+ *                       Added pipeline read mode. As a result, restores
+ *                        are now as fast as backups.
+ *                       Optimized shared interface behavior. The new behavior
+ *                        typically results in better IDE bus efficiency and
+ *                        higher tape throughput.
+ *                       Pre-calculation of the expected read/write request
+ *                        service time, based on the tape's parameters. In
+ *                        the pipelined operation mode, this allows us to
+ *                        adjust our polling frequency to a much lower value,
+ *                        and thus to dramatically reduce our load on Linux,
+ *                        without any decrease in performance.
+ *                       Implemented additional mtio.h operations.
+ *                       The recommended user block size is returned by
+ *                        the MTIOCGET ioctl.
+ *                       Additional minor changes.
+ * Ver 1.3   Feb  9 96   Fixed pipelined read mode bug which prevented the
+ *                        use of some block sizes during a restore procedure.
+ *                       The character device interface will now present a
+ *                        continuous view of the media - any mix of block sizes
+ *                        during a backup/restore procedure is supported. The
+ *                        driver will buffer the requests internally and
+ *                        convert them to the tape's recommended transfer
+ *                        unit, making performance almost independent of the
+ *                        chosen user block size.
+ *                       Some improvements in error recovery.
+ *                       By cooperating with ide-dma.c, bus mastering DMA can
+ *                        now sometimes be used with IDE tape drives as well.
+ *                        Bus mastering DMA has the potential to dramatically
+ *                        reduce the CPU's overhead when accessing the device,
+ *                        and can be enabled by using hdparm -d1 on the tape's
+ *                        block device interface. For more info, read the
+ *                        comments in ide-dma.c.
+ * Ver 1.4   Mar 13 96   Fixed serialize support.
+ * Ver 1.5   Apr 12 96   Fixed shared interface operation, broken in 1.3.85.
+ *                       Fixed pipelined read mode inefficiency.
+ *                       Fixed nasty null dereferencing bug.
+ * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
+ *                       Fixed end of media bug.
+ * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
+ *                        interactive response and high system throughput.
+ * Ver 1.9   Nov  5 96   Automatically cross encountered filemarks rather
+ *                        than requiring an explicit FSF command.
+ *                       Abort pending requests at end of media.
+ *                       MTTELL was sometimes returning incorrect results.
+ *                       Return the real block size in the MTIOCGET ioctl.
+ *                       Some error recovery bug fixes.
+ * Ver 1.10  Nov  5 96   Major reorganization.
+ *                       Reduced CPU overhead a bit by eliminating internal
+ *                        bounce buffers.
+ *                       Added module support.
+ *                       Added multiple tape drives support.
+ *                       Added partition support.
+ *                       Rewrote DSC handling.
+ *                       Some portability fixes.
+ *                       Removed ide-tape.h.
+ *                       Additional minor changes.
+ * Ver 1.11  Dec  2 96   Bug fix in previous DSC timeout handling.
+ *                       Use ide_stall_queue() for DSC overlap.
+ *                       Use the maximum speed rather than the current speed
+ *                        to compute the request service time.
+ * Ver 1.12  Dec  7 97   Fix random memory overwriting and/or last block data
+ *                        corruption, which could occur if the total number
+ *                        of bytes written to the tape was not an integral
+ *                        number of tape blocks.
+ *                       Add support for INTERRUPT DRQ devices.
+ * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
+ * Ver 1.14  Dec 30 98   Partial fixes for the Sony/AIWA tape drives.
+ *                       Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15  Mar 25 99   Fix SMP race condition by replacing hwgroup
+ *                        spinlock with private per-tape spinlock.
+ * Ver 1.16  Sep  1 99   Add OnStream tape support.
+ *                       Abort read pipeline on EOD.
+ *                       Wait for the tape to become ready in case it returns
+ *                        "in the process of becoming ready" on open().
+ *                       Fix zero padding of the last written block in
+ *                        case the tape block size is larger than PAGE_SIZE.
+ *                       Decrease the default disconnection time to tn.
+ * Ver 1.16e Oct  3 99   Minor fixes.
+ * Ver 1.16e1 Oct 13 99  Patches by Arnold Niessen,
+ *                          niessen@iae.nl / arnold.niessen@philips.com
+ *                   GO-1)  Undefined code in idetape_read_position
+ *				according to Gadi's email
+ *                   AJN-1) Minor fix asc == 11 should be asc == 0x11
+ *                               in idetape_issue_packet_command (did effect
+ *                               debugging output only)
+ *                   AJN-2) Added more debugging output, and
+ *                              added ide-tape: where missing. I would also
+ *				like to add tape->name where possible
+ *                   AJN-3) Added different debug_level's 
+ *                              via /proc/ide/hdc/settings
+ * 				"debug_level" determines amount of debugging output;
+ * 				can be changed using /proc/ide/hdx/settings
+ * 				0 : almost no debugging output
+ * 				1 : 0+output errors only
+ * 				2 : 1+output all sensekey/asc
+ * 				3 : 2+follow all chrdev related procedures
+ * 				4 : 3+follow all procedures
+ * 				5 : 4+include pc_stack rq_stack info
+ * 				6 : 5+USE_COUNT updates
+ *                   AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ *				from 5 to 10 minutes
+ *                   AJN-5) Changed maximum number of blocks to skip when
+ *                              reading tapes with multiple consecutive write
+ *                              errors from 100 to 1000 in idetape_get_logical_blk
+ *                   Proposed changes to code:
+ *                   1) output "logical_blk_num" via /proc
+ *                   2) output "current_operation" via /proc
+ *                   3) Either solve or document the fact that `mt rewind' is
+ *                      required after reading from /dev/nhtx to be
+ *			able to rmmod the idetape module;
+ *			Also, sometimes an application finishes but the
+ *			device remains `busy' for some time. Same cause ?
+ *                   Proposed changes to release-notes:
+ *		     4) write a simple `quickstart' section in the
+ *                      release notes; I volunteer if you don't want to
+ * 		     5) include a pointer to video4linux in the doc
+ *                      to stimulate video applications
+ *                   6) release notes lines 331 and 362: explain what happens
+ *			if the application data rate is higher than 1100 KB/s; 
+ *			similar approach to lower-than-500 kB/s ?
+ *		     7) 6.6 Comparison; wouldn't it be better to allow different 
+ *			strategies for read and write ?
+ *			Wouldn't it be better to control the tape buffer
+ *			contents instead of the bandwidth ?
+ *		     8) line 536: replace will by would (if I understand
+ *			this section correctly, a hypothetical and unwanted situation
+ *			 is being described)
+ * Ver 1.16f Dec 15 99   Change place of the secondary OnStream header frames.
+ * Ver 1.17  Nov 2000 / Jan 2001  Marcel Mol, marcel@mesa.nl
+ *			- Add idetape_onstream_mode_sense_tape_parameter_page
+ *			  function to get tape capacity in frames: tape->capacity.
+ *			- Add support for DI-50 drives( or any DI- drive).
+ *			- 'workaround' for read error/blank block arround block 3000.
+ *			- Implement Early warning for end of media for Onstream.
+ *			- Cosmetic code changes for readability.
+ *			- Idetape_position_tape should not use SKIP bit during
+ *			  Onstream read recovery.
+ *			- Add capacity, logical_blk_num and first/last_frame_position
+ *			  to /proc/ide/hd?/settings.
+ *			- Module use count was gone in the Linux 2.4 driver.
+ * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
+ * 			- Get drive's actual block size from mode sense block descriptor
+ * 			- Limit size of pipeline
+ *
+ * Here are some words from the first releases of hd.c, which are quoted
+ * in ide.c and apply here as well:
+ *
+ * | Special care is recommended.  Have Fun!
+ *
+ */
+
+/*
+ * An overview of the pipelined operation mode.
+ *
+ * In the pipelined write mode, we will usually just add requests to our
+ * pipeline and return immediately, before we even start to service them. The
+ * user program will then have enough time to prepare the next request while
+ * we are still busy servicing previous requests. In the pipelined read mode,
+ * the situation is similar - we add read-ahead requests into the pipeline,
+ * before the user even requested them.
+ *
+ * The pipeline can be viewed as a "safety net" which will be activated when
+ * the system load is high and prevents the user backup program from keeping up
+ * with the current tape speed. At this point, the pipeline will get
+ * shorter and shorter but the tape will still be streaming at the same speed.
+ * Assuming we have enough pipeline stages, the system load will hopefully
+ * decrease before the pipeline is completely empty, and the backup program
+ * will be able to "catch up" and refill the pipeline again.
+ * 
+ * When using the pipelined mode, it would be best to disable any type of
+ * buffering done by the user program, as ide-tape already provides all the
+ * benefits in the kernel, where it can be done in a more efficient way.
+ * As we will usually not block the user program on a request, the most
+ * efficient user code will then be a simple read-write-read-... cycle.
+ * Any additional logic will usually just slow down the backup process.
+ *
+ * Using the pipelined mode, I get a constant over 400 KBps throughput,
+ * which seems to be the maximum throughput supported by my tape.
+ *
+ * However, there are some downfalls:
+ *
+ *	1.	We use memory (for data buffers) in proportional to the number
+ *		of pipeline stages (each stage is about 26 KB with my tape).
+ *	2.	In the pipelined write mode, we cheat and postpone error codes
+ *		to the user task. In read mode, the actual tape position
+ *		will be a bit further than the last requested block.
+ *
+ * Concerning (1):
+ *
+ *	1.	We allocate stages dynamically only when we need them. When
+ *		we don't need them, we don't consume additional memory. In
+ *		case we can't allocate stages, we just manage without them
+ *		(at the expense of decreased throughput) so when Linux is
+ *		tight in memory, we will not pose additional difficulties.
+ *
+ *	2.	The maximum number of stages (which is, in fact, the maximum
+ *		amount of memory) which we allocate is limited by the compile
+ *		time parameter IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ *	3.	The maximum number of stages is a controlled parameter - We
+ *		don't start from the user defined maximum number of stages
+ *		but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
+ *		will not even allocate this amount of stages if the user
+ *		program can't handle the speed). We then implement a feedback
+ *		loop which checks if the pipeline is empty, and if it is, we
+ *		increase the maximum number of stages as necessary until we
+ *		reach the optimum value which just manages to keep the tape
+ *		busy with minimum allocated memory or until we reach
+ *		IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * Concerning (2):
+ *
+ *	In pipelined write mode, ide-tape can not return accurate error codes
+ *	to the user program since we usually just add the request to the
+ *      pipeline without waiting for it to be serviced. In case an error
+ *      occurs, I will report it on the next user request.
+ *
+ *	In the pipelined read mode, subsequent read requests or forward
+ *	filemark spacing will perform correctly, as we preserve all blocks
+ *	and filemarks which we encountered during our excess read-ahead.
+ * 
+ *	For accurate tape positioning and error reporting, disabling
+ *	pipelined mode might be the best option.
+ *
+ * You can enable/disable/tune the pipelined operation mode by adjusting
+ * the compile time parameters below.
+ */
+
+/*
+ *	Possible improvements.
+ *
+ *	1.	Support for the ATAPI overlap protocol.
+ *
+ *		In order to maximize bus throughput, we currently use the DSC
+ *		overlap method which enables ide.c to service requests from the
+ *		other device while the tape is busy executing a command. The
+ *		DSC overlap method involves polling the tape's status register
+ *		for the DSC bit, and servicing the other device while the tape
+ *		isn't ready.
+ *
+ *		In the current QIC development standard (December 1995),
+ *		it is recommended that new tape drives will *in addition* 
+ *		implement the ATAPI overlap protocol, which is used for the
+ *		same purpose - efficient use of the IDE bus, but is interrupt
+ *		driven and thus has much less CPU overhead.
+ *
+ *		ATAPI overlap is likely to be supported in most new ATAPI
+ *		devices, including new ATAPI cdroms, and thus provides us
+ *		a method by which we can achieve higher throughput when
+ *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-/*
- * FIXME: clean tape->spinlock locking  --bzolnier
- */
+#define IDETAPE_VERSION "1.17a"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -34,13 +417,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
-#include <linux/buffer_head.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/atapi.h>
-#include <linux/delay.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -64,7 +443,6 @@
 
 #define OS_DATA_STARTFRAME1	20
 #define OS_DATA_ENDFRAME1	2980
-
 /*
  * partition
  */
@@ -237,6 +615,13 @@
 #define IDETAPE_MAX_PC_RETRIES		3
 
 /*
+ *	With each packet command, we allocate a buffer of
+ *	IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
+ *	commands (Not for READ/WRITE commands).
+ */
+#define IDETAPE_PC_BUFFER_SIZE		256
+
+/*
  *	In various places in the driver, we need to allocate storage
  *	for packet commands and requests, which will remain valid while
  *	we leave the driver to wait for an interrupt or a timeout event.
@@ -327,14 +712,44 @@
 } idetape_chrdev_direction_t;
 
 /*
+ *	Our view of a packet command.
+ */
+typedef struct idetape_packet_command_s {
+	u8 c[12];				/* Actual packet bytes */
+	int retries;				/* On each retry, we increment retries */
+	int error;				/* Error code */
+	int request_transfer;			/* Bytes to transfer */
+	int actually_transferred;		/* Bytes actually transferred */
+	int buffer_size;			/* Size of our data buffer */
+	struct bio *bio;
+	char *b_data;
+	int b_count;
+	byte *buffer;				/* Data buffer */
+	byte *current_position;			/* Pointer into the above buffer */
+	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
+} idetape_pc_t;
+
+/*
+ *	Packet command flag bits.
+ */
+#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
+#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
+#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
+#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
+#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
+#define	PC_WRITING			5	/* Data direction */
+
+/*
  *	Capabilities and Mechanical Status Page
  */
 typedef struct {
 	unsigned	page_code	:6;	/* Page code - Should be 0x2a */
-	u8		reserved0_6	:1;
-	u8		ps		:1;	/* parameters saveable */
-	u8		page_length;		/* Page Length - Should be 0x12 */
-	u8		reserved2, reserved3;
+	__u8		reserved0_6	:1;
+	__u8		ps		:1;	/* parameters saveable */
+	__u8		page_length;		/* Page Length - Should be 0x12 */
+	__u8		reserved2, reserved3;
 	unsigned	ro		:1;	/* Read Only Mode */
 	unsigned	reserved4_1234	:4;
 	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
@@ -346,10 +761,10 @@
 	unsigned	reserved5_67	:2;
 	unsigned	lock		:1;	/* Supports locking the volume */
 	unsigned	locked		:1;	/* The volume is locked */
-	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */
+	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
 	unsigned	eject		:1;	/* The device can eject the volume */
-	u8		disconnect	:1;	/* The device can break request > ctl */
-	u8		reserved6_5	:1;
+	__u8		disconnect	:1;	/* The device can break request > ctl */	
+	__u8		reserved6_5	:1;
 	unsigned	ecc		:1;	/* Supports error correction */
 	unsigned	cmprs		:1;	/* Supports data compression */
 	unsigned	reserved7_0	:1;
@@ -359,12 +774,12 @@
 	unsigned	blk32768	:1;	/* slowb - the device restricts the byte count for PIO */
 						/* transfers for slow buffer memory ??? */
 						/* Also 32768 block size in some cases */
-	u16		max_speed;		/* Maximum speed supported in KBps */
-	u8		reserved10, reserved11;
-	u16		ctl;			/* Continuous Transfer Limit in blocks */
-	u16		speed;			/* Current Speed, in KBps */
-	u16		buffer_size;		/* Buffer Size, in 512 bytes */
-	u8		reserved18, reserved19;
+	__u16		max_speed;		/* Maximum speed supported in KBps */
+	__u8		reserved10, reserved11;
+	__u16		ctl;			/* Continuous Transfer Limit in blocks */
+	__u16		speed;			/* Current Speed, in KBps */
+	__u16		buffer_size;		/* Buffer Size, in 512 bytes */
+	__u8		reserved18, reserved19;
 } idetape_capabilities_page_t;
 
 /*
@@ -374,8 +789,8 @@
 	unsigned	page_code	:6;	/* Page code - Should be 0x30 */
 	unsigned	reserved1_6	:1;
 	unsigned	ps		:1;
-	u8		page_length;		/* Page Length - Should be 2 */
-	u8		reserved2;
+	__u8		page_length;		/* Page Length - Should be 2 */
+	__u8		reserved2;
 	unsigned	play32		:1;
 	unsigned	play32_5	:1;
 	unsigned	reserved2_23	:2;
@@ -396,12 +811,38 @@
 } idetape_stage_t;
 
 /*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+	unsigned	error_code	:7;	/* Current of deferred errors */
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	__u8		reserved1	:8;	/* Segment Number - Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	filemark 	:1;	/* Filemark */
+	__u32		information __attribute__ ((packed));
+	__u8		asl;			/* Additional sense length (n-7) */
+	__u32		command_specific;	/* Additional command specific information */
+	__u8		asc;			/* Additional Sense Code */
+	__u8		ascq;			/* Additional Sense Code Qualifier */
+	__u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	__u8		sk_specific2;		/* Sense Key Specific */
+	__u8		sk_specific3;		/* Sense Key Specific */
+	__u8		pad[2];			/* Padding to 20 bytes */
+} idetape_request_sense_result_t;
+
+
+/*
  *	Most of our global data which we need to save even as we leave the
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idetape_tape_t, defined below.
  */
 typedef struct {
-	struct ata_device *drive;
+	ide_drive_t *drive;
 	devfs_handle_t de_r, de_n;
 
 	/*
@@ -419,9 +860,9 @@
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	struct atapi_packet_command *pc;			/* Current packet command */
-	struct atapi_packet_command *failed_pc;		/* Last failed packet command */
-	struct atapi_packet_command pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
+	idetape_pc_t *pc;			/* Current packet command */
+	idetape_pc_t *failed_pc; 		/* Last failed packet command */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
 	int pc_stack_index;			/* Next free packet command storage space */
 	struct request rq_stack[IDETAPE_PC_STACK];
 	int rq_stack_index;			/* We implement a circular array */
@@ -447,7 +888,7 @@
 	/*
 	 *	Read position information
 	 */
-	u8 partition;
+	byte partition;
 	unsigned int first_frame_position;		/* Current block */
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
@@ -455,7 +896,7 @@
 	/*
 	 *	Last error information
 	 */
-	u8 sense_key, asc, ascq;
+	byte sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
@@ -491,7 +932,7 @@
 	struct bio *bio;
 	char *b_data;
 	int b_count;
-
+	
 	/*
 	 *	Pipeline parameters.
 	 *
@@ -519,7 +960,7 @@
 	int avg_size;
 	int avg_speed;
 
-	atapi_request_sense_result_t sense;	/* last sense information */
+	idetape_request_sense_result_t sense;	/* last sense information */
 
 	char vendor_id[10];
 	char product_id[18];
@@ -723,15 +1164,149 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
+ *	The ATAPI Status Register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+		unsigned check		:1;	/* Error occurred */
+		unsigned idx		:1;	/* Reserved */
+		unsigned corr		:1;	/* Correctable error occurred */
+		unsigned drq		:1;	/* Data is request by the device */
+		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
+		unsigned reserved5	:1;	/* Reserved */
+		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
+		unsigned bsy		:1;	/* The device has access to the command block */
+	} b;
+} idetape_status_reg_t;
+
+/*
+ *	The ATAPI error register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+		unsigned ili		:1;	/* Illegal Length Indication */
+		unsigned eom		:1;	/* End Of Media Detected */
+		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
+		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
+		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
+	} b;
+} idetape_error_reg_t;
+
+/*
+ *	ATAPI Feature Register
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+		unsigned dma		:1;	/* Using DMA or PIO */
+		unsigned reserved321	:3;	/* Reserved */
+		unsigned reserved654	:3;	/* Reserved (Tag Type) */
+		unsigned reserved7	:1;	/* Reserved */
+	} b;
+} idetape_feature_reg_t;
+
+/*
+ *	ATAPI Byte Count Register.
+ */
+typedef union {
+	unsigned all			:16;
+	struct {
+		unsigned low		:8;	/* LSB */
+		unsigned high		:8;	/* MSB */
+	} b;
+} idetape_bcount_reg_t;
+
+/*
+ *	ATAPI Interrupt Reason Register.
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
+		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
+		unsigned reserved	:6;	/* Reserved */
+	} b;
+} idetape_ireason_reg_t;
+
+/*
+ *	ATAPI Drive Select Register
+ */
+typedef union {	
+	unsigned all			:8;
+	struct {
+		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
+		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
+		unsigned one5		:1;	/* Should be set to 1 */
+		unsigned reserved6	:1;	/* Reserved */
+		unsigned one7		:1;	/* Should be set to 1 */
+	} b;
+} idetape_drivesel_reg_t;
+
+/*
+ *	ATAPI Device Control Register
+ */
+typedef union {			
+	unsigned all			:8;
+	struct {
+		unsigned zero0		:1;	/* Should be set to zero */
+		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
+		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
+		unsigned one3		:1;	/* Should be set to 1 */
+		unsigned reserved4567	:4;	/* Reserved */
+	} b;
+} idetape_control_reg_t;
+
+/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
- *	ata_device structure.
+ *	ide_drive_t structure.
  */
 typedef struct {
-	struct ata_device *drive;
+	ide_drive_t *drive;
 } idetape_chrdev_t;
 
 /*
+ *	The following is used to format the general configuration word of
+ *	the ATAPI IDENTIFY DEVICE command.
+ */
+struct idetape_id_gcw {	
+	unsigned packet_size		:2;	/* Packet Size */
+	unsigned reserved234		:3;	/* Reserved */
+	unsigned drq_type		:2;	/* Command packet DRQ type */
+	unsigned removable		:1;	/* Removable media */
+	unsigned device_type		:5;	/* Device type */
+	unsigned reserved13		:1;	/* Reserved */
+	unsigned protocol		:2;	/* Protocol type */
+};
+
+/*
+ *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
+ */
+typedef struct {
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	response_format :4;	/* Response Data Format */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	__u8		additional_length;	/* Additional Length (total_length-4) */
+	__u8		rsv5, rsv6, rsv7;	/* Reserved */
+	__u8		vendor_id[8];		/* Vendor Identification */
+	__u8		product_id[16];		/* Product Identification */
+	__u8		revision_level[4];	/* Revision Level */
+	__u8		vendor_specific[20];	/* Vendor Specific - Optional */
+	__u8		reserved56t95[40];	/* Reserved - Optional */
+						/* Additional information may be returned */
+} idetape_inquiry_result_t;
+
+/*
  *	READ POSITION packet command - Data Format (From Table 6-57)
  */
 typedef struct {
@@ -846,7 +1421,7 @@
 
 /*
  *	The variables below are used for the character device interface.
- *	Additional state variables are defined in our ata_device structure.
+ *	Additional state variables are defined in our ide_drive_t structure.
  */
 static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
 static int idetape_chrdev_present = 0;
@@ -857,7 +1432,7 @@
  * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
  */
 
-char *idetape_sense_key_verbose(u8 idetape_sense_key)
+char *idetape_sense_key_verbose (byte idetape_sense_key)
 {
 	switch (idetape_sense_key) {
 		default: {
@@ -869,7 +1444,7 @@
 	}
 }
 
-char *idetape_command_key_verbose(u8 idetape_command_key)
+char *idetape_command_key_verbose (byte idetape_command_key)
 {
 	switch (idetape_command_key) {
 		case IDETAPE_TEST_UNIT_READY_CMD:	return("TEST_UNIT_READY_CMD");
@@ -902,13 +1477,21 @@
  *      Function declarations
  *
  */
-static void idetape_onstream_mode_sense_tape_parameter_page(struct ata_device *drive, int debug);
+static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug);
 static int idetape_chrdev_release (struct inode *inode, struct file *filp);
 static void idetape_write_release (struct inode *inode);
 
-static void idetape_input_buffers(struct ata_device *drive,
-		struct atapi_packet_command *pc,
-		unsigned int bcount)
+/*
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
+ */
+static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		IN_BYTE(IDE_DATA_REG);
+}
+
+static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
 	struct bio *bio = pc->bio;
 	int count;
@@ -916,13 +1499,14 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bio == NULL) {
-			printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
-			atapi_discard_data(drive, bcount);
+			printk(KERN_ERR "ide-tape: bio == NULL in "
+				"idetape_input_buffers\n");
+			idetape_discard_data(drive, bcount);
 			return;
 		}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 		count = min(bio->bi_size - pc->b_count, bcount);
-		atapi_read(drive, bio_data(bio) + pc->b_count, count);
+		atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
 		pc->b_count += bio->bi_size;
 		if (pc->b_count == bio->bi_size) {
@@ -934,9 +1518,7 @@
 	pc->bio = bio;
 }
 
-static void idetape_output_buffers(struct ata_device *drive,
-		struct atapi_packet_command *pc,
-		unsigned int bcount)
+static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
 	struct bio *bio = pc->bio;
 	int count;
@@ -944,12 +1526,13 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bio == NULL) {
-			printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
+			printk(KERN_ERR "ide-tape: bio == NULL in "
+				"idetape_output_buffers\n");
 			return;
 		}
-#endif
-		count = min(pc->b_count, bcount);
-		atapi_write(drive, bio_data(bio), count);
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = min((unsigned long) pc->b_count, (unsigned long) bcount);
+		atapi_output_bytes(drive, /*(void *)*/ bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -964,7 +1547,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static void idetape_update_buffers(struct atapi_packet_command *pc)
+static void idetape_update_buffers (idetape_pc_t *pc)
 {
 	struct bio *bio = pc->bio;
 	int count;
@@ -973,13 +1556,14 @@
 	if (test_bit(PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
-# if IDETAPE_DEBUG_BUGS
+#if IDETAPE_DEBUG_BUGS
 		if (bio == NULL) {
-			printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
+			printk(KERN_ERR "ide-tape: bio == NULL in "
+				"idetape_update_buffers\n");
 			return;
 		}
-# endif
-		count = min(bio->bi_size, bcount);
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = min((unsigned long) bio->bi_size, (unsigned long) bcount);
 		pc->b_count = count;
 		if (pc->b_count == bio->bi_size)
 			bio = bio->bi_next;
@@ -987,7 +1571,7 @@
 	}
 	pc->bio = bio;
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  *	idetape_next_pc_storage returns a pointer to a place in which we can
@@ -995,15 +1579,16 @@
  *	driver. A storage space for a maximum of IDETAPE_PC_STACK packet
  *	commands is allocated at initialization time.
  */
-static struct atapi_packet_command *idetape_next_pc_storage(struct ata_device *drive)
+static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+		printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+			tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+	if (tape->pc_stack_index == IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
 	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
@@ -1013,36 +1598,52 @@
  *	Since we queue packet commands in the request queue, we need to
  *	allocate a request, along with the allocation of a packet command.
  */
-
+ 
 /**************************************************************
  *                                                            *
  *  This should get fixed to use kmalloc(.., GFP_ATOMIC)      *
  *  followed later on by kfree().   -ml                       *
  *                                                            *
  **************************************************************/
-
-static struct request *idetape_next_rq_storage(struct ata_device *drive)
+ 
+static struct request *idetape_next_rq_storage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
-#endif
+		printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+			tape->rq_stack_index);
+#endif /* IDETAPE_DEBUG_LOG */
 	if (tape->rq_stack_index==IDETAPE_PC_STACK)
 		tape->rq_stack_index=0;
 	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
 
 /*
+ *	idetape_init_pc initializes a packet command.
+ */
+static void idetape_init_pc (idetape_pc_t *pc)
+{
+	memset(pc->c, 0, 12);
+	pc->retries = 0;
+	pc->flags = 0;
+	pc->request_transfer = 0;
+	pc->buffer = pc->pc_buffer;
+	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
+	pc->bio = NULL;
+	pc->b_data = NULL;
+}
+
+/*
  *	idetape_analyze_error is called on each failed packet command retry
  *	to analyze the request sense. We currently do not utilize this
  *	information.
  */
-static void idetape_analyze_error(struct ata_device *drive, atapi_request_sense_result_t *result)
+static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command *pc = tape->failed_pc;
+	idetape_pc_t *pc = tape->failed_pc;
 
 	tape->sense     = *result;
 	tape->sense_key = result->sense_key;
@@ -1054,22 +1655,25 @@
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-				pc->c[0], result->sense_key, result->asc, result->ascq);
-# if IDETAPE_DEBUG_LOG_VERBOSE
+		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			pc->c[0], result->sense_key,
+			result->asc, result->ascq);
+#if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
-			idetape_command_key_verbose(pc->c[0]),
+		printk(KERN_INFO "ide-tape: pc = %s, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			idetape_command_key_verbose((byte) pc->c[0]),
 			result->sense_key,
 			result->asc,
 			result->ascq);
-# endif
-#endif
+#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
+#endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
+	if (tape->onstream && result->sense_key == 2 &&
+	    result->asc == 0x53 && result->ascq == 2) {
 		clear_bit(PC_DMA_ERROR, &pc->flags);
-		/* FIXME: we should use timeouts here */
-		mdelay(HZ / 2 * 1000);
+		ide_stall_queue(drive, HZ / 2);
 		return;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -1077,17 +1681,19 @@
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
-		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
+	if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information));
 		idetape_update_buffers(pc);
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
 		pc->error = IDETAPE_ERROR_FILEMARK;
 		set_bit(PC_ABORT, &pc->flags);
 	}
 	if (pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+		if (result->eom ||
+		    (result->sense_key == 0xd && result->asc == 0x0 &&
+		     result->ascq == 0x2)) {
 			pc->error = IDETAPE_ERROR_EOD;
 			set_bit(PC_ABORT, &pc->flags);
 		}
@@ -1097,12 +1703,13 @@
 			pc->error = IDETAPE_ERROR_EOD;
 			set_bit(PC_ABORT, &pc->flags);
 		}
-		if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred))
+		if (!test_bit(PC_ABORT, &pc->flags) &&
+		    (tape->onstream || pc->actually_transferred))
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
 
-static void idetape_abort_pipeline(struct ata_device *drive)
+static void idetape_abort_pipeline (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage = tape->next_stage;
@@ -1121,9 +1728,9 @@
 }
 
 /*
- *	idetape_active_next_stage will declare the next stage as "active".
+ * idetape_active_next_stage will declare the next stage as "active".
  */
-static void idetape_active_next_stage(struct ata_device *drive)
+static void idetape_active_next_stage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage = tape->next_stage;
@@ -1131,14 +1738,14 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+#endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
 		return;
 	}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */	
 
 	rq->buffer = NULL;
 	rq->bio = stage->bio;
@@ -1154,15 +1761,15 @@
  *	stages, and if we sense that the pipeline is empty, we try to
  *	increase it, until we reach the user compile time memory limit.
  */
-static void idetape_increase_max_pipeline_stages(struct ata_device *drive)
+static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
-
+	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
 		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
-#endif
+#endif /* IDETAPE_DEBUG_LOG */
 
 	tape->max_stages += increase;
 	tape->max_stages = max(tape->max_stages, tape->min_pipeline);
@@ -1182,58 +1789,58 @@
 		if (bio_data(bio) != NULL) {
 			size = (int) bio->bi_size;
 			while (size > 0) {
-				free_page ((unsigned long) bio_data(bio));
+				free_page((unsigned long) bio_data(bio));
 				size -= PAGE_SIZE;
 				bio->bi_size += PAGE_SIZE;
 			}
 		}
 		prev_bio = bio;
 		bio = bio->bi_next;
-		kfree (prev_bio);
+		kfree(prev_bio);
 	}
-	kfree (stage);
+	kfree(stage);
 }
 
 static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 /*
  *	idetape_remove_stage_head removes tape->first_stage from the pipeline.
  *	The caller should avoid race conditions.
  */
-static void idetape_remove_stage_head(struct ata_device *drive)
+static void idetape_remove_stage_head (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
-
+	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+#endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (tape->first_stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
-		return;
+		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		return;		
 	}
 	if (tape->active_stage == tape->first_stage) {
-		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
 		return;
 	}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 	stage = tape->first_stage;
 	tape->first_stage = stage->next;
-	idetape_kfree_stage (tape, stage);
+	idetape_kfree_stage(tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
 		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
-			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+			printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
 		if (tape->nr_stages)
-			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
-#endif
+			printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+#endif /* IDETAPE_DEBUG_BUGS */
 	}
 }
 
@@ -1241,10 +1848,11 @@
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static int idetape_end_request(struct ata_device *drive, struct request *rq, int uptodate)
+static int idetape_end_request (ide_drive_t *drive, int uptodate)
 {
+	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned long flags, flags2;
+	unsigned long flags;
 	int error;
 	int remove_stage = 0;
 #if ONSTREAM_DEBUG
@@ -1255,7 +1863,7 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
+	printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -1268,7 +1876,9 @@
 		tape->failed_pc = NULL;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+
+	/* The request was a pipelined data transfer request */
+	if (tape->active_data_request == rq) {
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1285,7 +1895,7 @@
 			}
 #endif
 			if (tape->onstream && !tape->raw) {
-				if (tape->first_frame_position == OS_DATA_ENDFRAME1) {
+				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					if (tape->debug_level >= 2)
 						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
@@ -1297,11 +1907,13 @@
 			}
 			remove_stage = 1;
 			if (error) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
-				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
-					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+					idetape_abort_pipeline(drive);
+				if (tape->onstream && !tape->raw &&
+				    error == IDETAPE_ERROR_GENERAL &&
+				    tape->sense.sense_key == 3) {
+					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
 					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
@@ -1314,61 +1926,56 @@
 			}
 		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				idetape_abort_pipeline(drive);
 			}
 		}
 		if (tape->next_stage != NULL && !tape->onstream_write_error) {
-			idetape_active_next_stage (drive);
+			idetape_active_next_stage(drive);
 
 			/*
 			 * Insert the next request into the request queue.
 			 */
-			ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
 			if (!tape->onstream)
 				idetape_increase_max_pipeline_stages (drive);
 		}
 	}
-
-	/* FIXME: replace tape->spinlock with channel->spinlock  --bzolnier */
-	spin_lock_irqsave(drive->channel->lock, flags2);
-
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
-
-	spin_unlock_irqrestore(drive->channel->lock, flags2);
+	ide_end_drive_cmd(drive, 0, 0);
+//	blkdev_dequeue_request(rq);
+//	drive->rq = NULL;
+//	end_that_request_last(rq);
 
 	if (remove_stage)
 		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
 		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
-
 	return 0;
 }
 
-static void idetape_request_sense_callback(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (atapi_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request(drive, rq, 1);
+		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request(drive, rq, 0);
+		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+		idetape_end_request(drive, 0);
 	}
+	return ide_stopped;
 }
 
-static void idetape_create_request_sense_cmd(struct atapi_packet_command *pc)
+static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
 	pc->request_transfer = 18;
@@ -1394,12 +2001,12 @@
  *	and wait for their completion using idetape_queue_pc_tail or
  *	idetape_queue_rw_tail.
  */
-static void idetape_queue_pc_head(struct ata_device *drive, struct atapi_packet_command *pc, struct request *rq)
+static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
 {
-	memset(rq, 0, sizeof(*rq));
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->flags = IDETAPE_PC_RQ1;
-	ide_do_drive_cmd(drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 /*
@@ -1407,27 +2014,28 @@
  *	last packet command. We queue a request sense packet command in
  *	the head of the request list.
  */
-static void idetape_retry_pc(struct ata_device *drive)
+static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command *pc;
+	idetape_pc_t *pc;
 	struct request *rq;
-	atapi_error_reg_t error;
+	idetape_error_reg_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
-	pc = idetape_next_pc_storage (drive);
-	rq = idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc);
-	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	idetape_queue_pc_head (drive, pc, rq);
+	error.all = IN_BYTE(IDE_ERROR_REG);
+	pc = idetape_next_pc_storage(drive);
+	rq = idetape_next_rq_storage(drive);
+	idetape_create_request_sense_cmd(pc);
+	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head(drive, pc, rq);
+	return ide_stopped;
 }
 
 /*
  *	idetape_postpone_request postpones the current request so that
  *	ide.c will be able to service requests from another device on
- *	the same interface while we are polling for DSC.
+ *	the same hwgroup while we are polling for DSC.
  */
-static void idetape_postpone_request(struct ata_device *drive, struct request *rq)
+static void idetape_postpone_request (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -1435,9 +2043,8 @@
 	if (tape->debug_level >= 4)
 		printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
 #endif
-	tape->postponed_rq = rq;
-	/* FIXME: we should use timeouts here */
-	mdelay(tape->dsc_polling_frequency * 1000);
+	tape->postponed_rq = HWGROUP(drive)->rq;
+	ide_stall_queue(drive, tape->dsc_polling_frequency);
 }
 
 /*
@@ -1448,13 +2055,13 @@
  *	algorithm described before idetape_issue_packet_command.
  *
  */
-static ide_startstop_t idetape_pc_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	atapi_status_reg_t status;
-	atapi_bcount_reg_t bcount;
-	atapi_ireason_reg_t ireason;
-	struct atapi_packet_command *pc = tape->pc;
+	idetape_status_reg_t status;
+	idetape_bcount_reg_t bcount;
+	idetape_ireason_reg_t ireason;
+	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
 	unsigned long cmd_time;
@@ -1464,15 +2071,15 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+				"interrupt handler\n");
+#endif /* IDETAPE_DEBUG_LOG */	
 
-	ata_status(drive, 0, 0);
-	status.all = drive->status;					/* Clear the interrupt */
+	status.all = GET_STAT();	/* Clear the interrupt */
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (udma_stop(drive)) {
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -1484,128 +2091,132 @@
 			 * actually transferred (we can't receive that
 			 * information from the DMA engine on most chipsets).
 			 */
-			set_bit (PC_DMA_ERROR, &pc->flags);
+			set_bit(PC_DMA_ERROR, &pc->flags);
 		} else if (!status.b.check) {
 			pc->actually_transferred = pc->request_transfer;
-			idetape_update_buffers (pc);
+			idetape_update_buffers(pc);
 		}
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk (KERN_INFO "ide-tape: DMA finished\n");
-#endif
+			printk(KERN_INFO "ide-tape: DMA finished\n");
+#endif /* IDETAPE_DEBUG_LOG */
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {		/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = max(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif
+			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+#endif /* IDETAPE_DEBUG_LOG */
 		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
 		local_irq_enable();
 
 #if SIMULATE_ERRORS
-		if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
-			printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
+		if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+		     pc->c[0] == IDETAPE_READ_CMD) &&
+		    (++error_sim_count % 100) == 0) {
+			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+				tape->name);
 			status.b.check = 1;
 		}
 #endif
 		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
 			status.b.check = 0;
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
-#endif
+				printk(KERN_INFO "ide-tape: %s: I/O error, ",
+					tape->name);
+#endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ATA_OP_FINISHED;
+				printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+				return ide_do_reset(drive);
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
 				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
 #endif
-			idetape_retry_pc(drive);				/* Retry operation */
-			return ATA_OP_FINISHED;
+			return idetape_retry_pc(drive);				/* Retry operation */
 		}
 		pc->error = 0;
-		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+		if (!tape->onstream &&
+		     test_bit(PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {
+			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-			idetape_postpone_request(drive, rq);		/* Allow ide.c to handle other requests */
-
-			return ATA_OP_FINISHED;
+			idetape_postpone_request(drive);		/* Allow ide.c to handle other requests */
+			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		pc->callback(drive, rq);	/* Command finished - Call the callback function */
-		return ATA_OP_FINISHED;
+		return pc->callback(drive);	/* Command finished - Call the callback function */
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
-		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		udma_enable(drive, 0, 1);
-
-		return ATA_OP_FINISHED;
-	}
-#endif
-
-	bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all   = IN_BYTE (IDE_IREASON_REG);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-tape: The tape wants to issue more "
+				"interrupts in DMA mode\n");
+		printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		return ide_do_reset(drive);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	bcount.b.high = IN_BYTE(IDE_BCOUNTH_REG);	/* Get the number of bytes to transfer */
+	bcount.b.low  = IN_BYTE(IDE_BCOUNTL_REG);	/* on this interrupt */
+	ireason.all   = IN_BYTE(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-
-		return ATA_OP_FINISHED;
+		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-
-		return ATA_OP_FINISHED;
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-tape: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				atapi_discard_data (drive, bcount.all);
-				ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
-
-				return ATA_OP_CONTINUES;
+				printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+				idetape_discard_data(drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+					BUG();
+				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
-#endif
+				printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+#endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bio != NULL)
-			idetape_output_buffers (drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_write(drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			atapi_output_bytes(drive, pc->current_position, bcount.all);	/* Write the current buffer */
 	} else {
 		if (pc->bio != NULL)
-			idetape_input_buffers (drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_read(drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			atapi_input_bytes(drive, pc->current_position, bcount.all);	/* Read the current buffer */
 	}
-	pc->actually_transferred += bcount.all;					/* Update the current position */
-	pc->current_position+=bcount.all;
+	pc->actually_transferred += bcount.all;	/* Update the current position */
+	pc->current_position += bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
-
-	return ATA_OP_CONTINUES;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	return ide_started;
 }
 
 /*
@@ -1628,11 +2239,11 @@
  *	3.	ATAPI Tape media access commands have immediate status with a
  *		delayed process. In case of a successful initiation of a
  *		media access packet command, the DSC bit will be set when the
- *		actual execution of the command is finished.
+ *		actual execution of the command is finished. 
  *		Since the tape drive will not issue an interrupt, we have to
  *		poll for this event. In this case, we define the request as
  *		"low priority request" by setting rq_status to
- *		IDETAPE_RQ_POSTPONED,	set a timer to poll for DSC and exit
+ *		IDETAPE_RQ_POSTPONED, 	set a timer to poll for DSC and exit
  *		the driver.
  *
  *		ide.c will then give higher priority to requests which
@@ -1650,163 +2261,173 @@
  *		we will handle the next request.
  *
  */
-static ide_startstop_t idetape_transfer_pc(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command *pc = tape->pc;
-	atapi_ireason_reg_t ireason;
+	idetape_pc_t *pc = tape->pc;
+	idetape_ireason_reg_t ireason;
 	int retries = 100;
-	int ret;
-
-	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
-	if (ret != ATA_OP_READY) {
-		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+	ide_startstop_t startstop;
 
-		return ret;
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return startstop;
 	}
-
-	ireason.all = IN_BYTE (IDE_IREASON_REG);
-
+	ireason.all = IN_BYTE(IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+				"a packet command, retrying\n");
 		udelay(100);
 		ireason.all = IN_BYTE(IDE_IREASON_REG);
 		if (retries == 0) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+					"issuing a packet command, ignoring\n");
 			ireason.b.cod = 1;
 			ireason.b.io = 0;
 		}
 	}
-
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ret = ATA_OP_FINISHED;
-	} else {
-		tape->cmd_start_time = jiffies;
-		ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-		atapi_write(drive,pc->c,12);	/* Send the actual packet */
-		ret = ATA_OP_CONTINUES;
+		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+				"a packet command\n");
+		return ide_do_reset(drive);
 	}
-
-	return ret;
+	tape->cmd_start_time = jiffies;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
+	atapi_output_bytes(drive, pc->c, 12);	/* Send the actual packet */
+	return ide_started;
 }
 
-static ide_startstop_t idetape_issue_packet_command(struct ata_device *drive,
-		struct request *rq, struct atapi_packet_command *pc)
+static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	atapi_bcount_reg_t bcount;
+	idetape_bcount_reg_t bcount;
 	int dma_ok = 0;
 
 #if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
 		tape->failed_pc = pc;
-	tape->pc = pc;							/* Set the current packet command */
+	tape->pc = pc;			/* Set the current packet command */
 
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit(PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
 		 *	filemark, or DMA error in the end of media, for
 		 *	example).
 		 */
-		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
-			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
-				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+		if (!test_bit(PC_ABORT, &pc->flags)) {
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+			      tape->sense_key == 2 && tape->asc == 4 &&
+			     (tape->ascq == 1 || tape->ascq == 8))) {
+				printk(KERN_ERR "ide-tape: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						tape->name, pc->c[0],
+						tape->sense_key, tape->asc,
+						tape->ascq);
+				if (tape->onstream &&
+				    pc->c[0] == IDETAPE_READ_CMD &&
+				    tape->sense_key == 3 &&
+				    tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
-			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+			pc->error = IDETAPE_ERROR_GENERAL;	/* Giving up */
 		}
 		tape->failed_pc = NULL;
-		pc->callback(drive, rq);
-		return ATA_OP_FINISHED;
+		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
-#endif
+		printk(KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+#endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	pc->actually_transferred = 0;		/* We haven't transferred any data yet */
+	pc->current_position = pc->buffer;
+	bcount.all = pc->request_transfer;	/* Request to transfer the entire buffer at once */
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		udma_enable(drive, 0, 1);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = udma_init(drive, rq);
-#endif
-
-	ata_irq_enable(drive, 1);
-	OUT_BYTE (dma_ok ? 1 : 0,    IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,     IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		printk(KERN_WARNING "ide-tape: DMA disabled, "
+				"reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok = !HWIF(drive)->dmaproc(test_bit(PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+	OUT_BYTE(dma_ok ? 1 : 0,    IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE(bcount.b.high,     IDE_BCOUNTH_REG);
+	OUT_BYTE(bcount.b.low,      IDE_BCOUNTL_REG);
+	OUT_BYTE(drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {						/* Begin DMA, if necessary */
+	if (dma_ok) {			/* Begin DMA, if necessary */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		udma_start(drive, rq);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ata_set_handler(drive, idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-
-		return ATA_OP_CONTINUES;
+		return ide_started;
 	} else {
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idetape_transfer_pc(drive, rq);
+		return idetape_transfer_pc(drive);
 	}
 }
 
 /*
  *	General packet command callback function.
  */
-static void idetape_pc_callback(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-
+	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request(drive, rq, tape->pc->error ? 0 : 1);
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
+	return ide_stopped;
 }
 
 /*
  *	A mode sense command is used to "sense" tape parameters.
  */
-static void idetape_create_mode_sense_cmd(struct atapi_packet_command *pc, u8 page_code)
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
+		pc->c[1] = 8;	/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
-	pc->c[3] = 255;				/* Don't limit the returned information */
-	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	pc->c[3] = 255;		/* Don't limit the returned information */
+	pc->c[4] = 255;		/* (We will just discard data in that case) */
 	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
 		pc->request_transfer = 12;
 	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
 		pc->request_transfer = 24;
 	else
 		pc->request_transfer = 50;
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_onstream_buffer_fill_callback (struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_onstream_buffer_fill_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -1824,52 +2445,55 @@
 	}
 	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
 #if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
+			tape->tape_head, tape->minor);
 #endif
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
+			tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request(drive, rq, tape->pc->error ? 0 : 1);
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
+	return ide_stopped;
 }
 
-static void idetape_queue_onstream_buffer_fill(struct ata_device *drive)
+static void idetape_queue_onstream_buffer_fill (ide_drive_t *drive)
 {
-	struct atapi_packet_command *pc;
+	idetape_pc_t *pc;
 	struct request *rq;
 
-	pc = idetape_next_pc_storage (drive);
-	rq = idetape_next_rq_storage (drive);
-	idetape_create_mode_sense_cmd (pc, IDETAPE_BUFFER_FILLING_PAGE);
+	pc = idetape_next_pc_storage(drive);
+	rq = idetape_next_rq_storage(drive);
+	idetape_create_mode_sense_cmd(pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc->callback = idetape_onstream_buffer_fill_callback;
-	idetape_queue_pc_head (drive, pc, rq);
+	idetape_queue_pc_head(drive, pc, rq);
 }
 
-static void calculate_speeds(struct ata_device *drive)
+static void calculate_speeds(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int full = 125, empty = 75;
 
-	if (jiffies > tape->controlled_pipeline_head_time + 120 * HZ) {
+	if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
 		tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
 		tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
 		tape->controlled_last_pipeline_head = tape->pipeline_head;
 		tape->controlled_pipeline_head_time = jiffies;
 	}
-	if (jiffies > tape->controlled_pipeline_head_time + 60 * HZ)
+	if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
-	else if (jiffies > tape->controlled_previous_head_time)
+	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
 	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
-		if (jiffies > tape->uncontrolled_previous_head_time + 10 * HZ) {
+		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
 		}
 	} else {
 		tape->uncontrolled_previous_head_time = jiffies;
 		tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
-		if (jiffies > tape->uncontrolled_pipeline_head_time + 30 * HZ) {
+		if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 		}
 	}
@@ -1893,21 +2517,19 @@
 	tape->max_insert_speed = max(tape->max_insert_speed, 500);
 }
 
-static void idetape_media_access_finished(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command *pc = tape->pc;
-	atapi_status_reg_t status;
+	idetape_pc_t *pc = tape->pc;
+	idetape_status_reg_t status;
 
 	if (tape->onstream)
 		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
-	ata_status(drive, 0, 0);
-	status.all = drive->status;
+	status.all = GET_STAT();
 	if (status.b.dsc) {
-		if (status.b.check) {					/* Error detected */
-			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			idetape_retry_pc(drive);			/* Retry operation */
-			return;
+		if (status.b.check) {		/* Error detected */
+			printk(KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
+			return idetape_retry_pc(drive);	/* Retry operation */
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -1916,12 +2538,13 @@
 		pc->error = IDETAPE_ERROR_GENERAL;
 		tape->failed_pc = NULL;
 	}
-	pc->callback(drive, rq);
+	return pc->callback(drive);
 }
 
-static void idetape_rw_callback(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
 	int blocks = tape->pc->actually_transferred / tape->tape_block_size;
 
 	tape->avg_size += blocks * tape->tape_block_size;
@@ -1933,7 +2556,7 @@
 		tape->insert_time = jiffies;
 		tape->insert_size = 0;
 	}
-	if (jiffies > tape->insert_time)
+	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	if (jiffies - tape->avg_time >= HZ) {
 		tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
@@ -1941,31 +2564,30 @@
 		tape->avg_time = jiffies;
 	}
 
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
 	tape->first_frame_position += blocks;
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request(drive, rq, 1);
+		idetape_end_request(drive, 1);
 	else
-		idetape_end_request(drive, rq, tape->pc->error);
+		idetape_end_request(drive, tape->pc->error);
+	return ide_stopped;
 }
 
-static void idetape_create_read_cmd(idetape_tape_t *tape,
-		struct atapi_packet_command *pc,
-		unsigned int length, struct bio *bio)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	struct bio *p = bio;
-	struct bio_vec *bv = bio_iovec(p);
-	atapi_init_pc(pc);
+	struct bio_vec *bv = bio_iovec(p);	/* effective page bh */
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
-	pc->callback = idetape_rw_callback;
+	pc->callback = &idetape_rw_callback;
 	pc->bio = bio;
 	bv->bv_len = 0;
 	pc->buffer = NULL;
@@ -1988,19 +2610,17 @@
 	}
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape,
-		struct atapi_packet_command *pc,
-		unsigned int length, struct bio *bio)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	int size = 32768;
-
 	struct bio *p = bio;
-	atapi_init_pc(pc);
+
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
 	pc->c[8] = size & 0xff;
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 	pc->bio = bio;
 	atomic_set(&bio->bi_cnt, 0);
 	pc->buffer = NULL;
@@ -2011,18 +2631,17 @@
 	pc->request_transfer = pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd(idetape_tape_t *tape,
-		struct atapi_packet_command *pc,
-		unsigned int length, struct bio *bio)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	struct bio *p = bio;
 	struct bio_vec *bv= bio_iovec(p);
-	atapi_init_pc(pc);
+
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
-	pc->callback = idetape_rw_callback;
-	set_bit (PC_WRITING, &pc->flags);
+	pc->callback = &idetape_rw_callback;
+	set_bit(PC_WRITING, &pc->flags);
 	if (tape->onstream) {
 		while (p) {
 			bv->bv_len = p->bi_size;
@@ -2040,55 +2659,95 @@
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
 }
 
 /*
- * This is our request handling function.
+ * This is our end_request replacement function.
+ */
+static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	BUG_ON(!(rq->flags & REQ_STARTED));
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+		add_blkdev_randomness(major(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
+
+/*
+ * idetape_do_request is our request handling function.	
  */
-static ide_startstop_t idetape_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command *pc;
+	idetape_pc_t *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	atapi_status_reg_t status;
+	idetape_status_reg_t status;
 
 #if IDETAPE_DEBUG_LOG
-/*	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
-	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+#if 0
+	if (tape->debug_level >= 5)
+		printk(KERN_INFO "ide-tape: rq_status: %d, "
+			"rq_dev: %u, cmd: %ld, errors: %d\n", rq->rq_status,
+			(unsigned int) rq->rq_dev, rq->flags, rq->errors);
 #endif
+	if (tape->debug_level >= 2)
+		printk(KERN_INFO "ide-tape: sector: %ld, "
+			"nr_sectors: %ld, current_nr_sectors: %d\n",
+			rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+#endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->flags)) {
+	if (!IDETAPE_RQ_CMD(rq->flags)) {
 		/*
-		 *	We do not support buffer cache originated requests.
+		 * We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
-		ata_end_request(drive, rq, 0, 0);			/* Let the common code handle it */
-		return ATA_OP_FINISHED;
+		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
+			"request queue (%ld)\n", drive->name, rq->flags);
+		idetape_do_end_request(drive, 0);
+		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
-	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-
-		return idetape_issue_packet_command(drive, rq, tape->failed_pc);
+	if (tape->failed_pc != NULL &&
+	    tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		return idetape_issue_packet_command(drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
-			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-
-			idetape_end_request(drive, rq, 0);
-
-			return ATA_OP_FINISHED;
+			printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+					"Two DSC requests were queued\n");
+			idetape_end_request(drive, 0);
+			return ide_stopped;
 		}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 
 	tape->postponed_rq = NULL;
 
@@ -2096,8 +2755,7 @@
 	 * If the tape is still busy, postpone our request and service
 	 * the other device meanwhile.
 	 */
-	ata_status(drive, 0, 0);
-	status.all = drive->status;
+	status.all = GET_STAT();
 
 	/*
 	 * The OnStream tape drive doesn't support DSC. Assume
@@ -2118,17 +2776,18 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill &&
+	    (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
 		tape->last_buffer_fill = jiffies;
 		idetape_queue_onstream_buffer_fill(drive);
-		if (jiffies > tape->insert_time)
+		if (time_after(jiffies, tape->insert_time))
 			tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-		return ATA_OP_FINISHED;
+		return ide_stopped;
 	}
-	if (jiffies > tape->insert_time)
+	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
@@ -2143,7 +2802,8 @@
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+			printk(KERN_INFO "ide-tape: postponing request, "
+					"cmd %ld, cur %d, max %d\n",
 				rq->flags, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
@@ -2151,27 +2811,29 @@
 			tape->req_buffer_fill = 1;
 		}
 #if ONSTREAM_DEBUG
-		else if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+		else if (tape->debug_level >= 4) 
+			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
+				tape->name, tape->postpone_cnt);
 #endif
 	}
-	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
-			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-
-			if (rq->flags == IDETAPE_PC_RQ2)
-				idetape_media_access_finished(drive, rq);
-
-			return ATA_OP_FINISHED;
+			printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+				tape->name);
+			if (rq->flags == IDETAPE_PC_RQ2) {
+				idetape_media_access_finished(drive);
+				return ide_stopped;
+			} else {
+				return ide_do_reset(drive);
+			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request(drive, rq);
-
-		return ATA_OP_FINISHED;
+		idetape_postpone_request(drive);
+		return ide_stopped;
 	}
 	switch (rq->flags) {
 		case IDETAPE_READ_RQ:
@@ -2184,7 +2846,7 @@
 			if (tape->onstream) {
 				if (tape->cur_frames - tape->reads_since_buffer_fill <= 0)
 					tape->req_buffer_fill = 1;
-				if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
+				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
 			pc = idetape_next_pc_storage(drive);
@@ -2200,48 +2862,43 @@
 			if (tape->onstream) {
 				if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames)
 					tape->req_buffer_fill = 1;
-				if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
+				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc = idetape_next_pc_storage (drive);
+			pc = idetape_next_pc_storage(drive);
 			idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
-			pc = idetape_next_pc_storage (drive);
+			pc = idetape_next_pc_storage(drive);
 			idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->flags = IDETAPE_WRITE_RQ;
-			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
-			return ATA_OP_FINISHED;
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
+			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
 				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
 			rq->flags = IDETAPE_READ_RQ;
-			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
-			return ATA_OP_FINISHED;
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
+			return ide_stopped;
 		case IDETAPE_PC_RQ1:
-			/* FIXME: --mdcki */
-			pc = (struct atapi_packet_command *) rq->buffer;
+			pc = (idetape_pc_t *) rq->buffer;
 			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished(drive, rq);
-
-			return ATA_OP_FINISHED;
+			idetape_media_access_finished(drive);
+			return ide_stopped;
 		default:
-			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-
-			idetape_end_request(drive, rq, 0);
-
-			return ATA_OP_FINISHED;
+			printk(KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
+			idetape_end_request(drive, 0);
+			return ide_stopped;
 	}
-
-	return idetape_issue_packet_command(drive, rq, pc);
+	return idetape_issue_packet_command(drive, pc);
 }
 
 /*
@@ -2291,14 +2948,11 @@
 	if (clear)
 		memset(bio_data(bio), 0, PAGE_SIZE);
 	bio->bi_size = PAGE_SIZE;
-	if(bv->bv_len == full)
-	    bv->bv_len = bio->bi_size;
-#if 0
+	if (bv->bv_len == full)
+		bv->bv_len = bio->bi_size;
 
-	/* FIXME: What what this supposed to achieve? */
+//	set_bit(BH_Lock, &bio->bi_flags);
 
-	set_bit (BH_Lock, &bio->bi_flags);
-#endif
 	while (--pages) {
 		if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 			goto abort;
@@ -2320,18 +2974,14 @@
 		}
 		prev_bio = bio;
 		if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
-			free_page ((unsigned long) bio_data(bio));
+			free_page((unsigned long) bio_data(bio));
 			goto abort;
 		}
 		bio->bi_next = NULL;
 		//bio->bi_io_vec[0].bv_offset = b_data;
 		bio->bi_size = PAGE_SIZE;
 		atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
-#if 0
-		/* FIXME: What what this supposed to achieve? */
-
-		set_bit (BH_Lock, &bio->bi_flags);
-#endif
+//		set_bit(BH_Lock, &bio->bi_flags);
 		prev_bio->bi_next = bio;
 	}
 	bio->bi_size -= tape->excess_bh_size;
@@ -2341,7 +2991,7 @@
 		stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
 	return stage;
 abort:
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return NULL;
 }
 
@@ -2351,7 +3001,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->nr_stages >= tape->max_stages)
@@ -2360,11 +3010,10 @@
 		tape->cache_stage = NULL;
 		return cache_stage;
 	}
-	return __idetape_kmalloc_stage (tape, 0, 0);
+	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static void idetape_copy_stage_from_user(idetape_tape_t *tape, idetape_stage_t *stage,
-		const char *buf, unsigned int n)
+static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
 	struct bio *bio = tape->bio;
 	int count;
@@ -2372,12 +3021,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bio == NULL) {
-			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
+			printk(KERN_ERR "ide-tape: bio == NULL in "
+				"idetape_copy_stage_from_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = min(bio->bi_size - tape->b_count, n);
-		copy_from_user (bio_data(bio) + tape->b_count, buf, count);
+		count = min((unsigned long) (bio->bi_size - tape->b_count), (unsigned long) n);
+		copy_from_user(bio_data(bio) + tape->b_count, buf, count);
 		n -= count;
 		bio->bi_size += count;
 		buf += count;
@@ -2398,12 +3048,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bio == NULL) {
-			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
+			printk(KERN_ERR "ide-tape: bio == NULL in "
+				"idetape_copy_stage_to_user\n");
 			return;
 		}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 		count = min(tape->b_count, n);
-		copy_to_user (buf, tape->b_data, count);
+		copy_to_user(buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2421,7 +3072,7 @@
 static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
 	struct bio *bio = tape->merge_stage->bio;
-
+	
 	tape->bio = bio;
 	if (tape->chrdev_direction == idetape_direction_write)
 		atomic_set(&bio->bi_cnt, 0);
@@ -2437,23 +3088,25 @@
 	os_aux_t *tmp_aux;
 
 	tmp = stage->bio; tmp_aux = stage->aux;
-	stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
-	idetape_init_merge_stage (tape);
+	stage->bio = tape->merge_stage->bio;
+	stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bio = tmp;
+	tape->merge_stage->aux = tmp_aux;
+	idetape_init_merge_stage(tape);
 }
 
 /*
  *	idetape_add_stage_tail adds a new stage at the end of the pipeline.
  */
-static void idetape_add_stage_tail(struct ata_device *drive, idetape_stage_t *stage)
+static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
-
+	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
 		printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
-#endif
+#endif /* IDETAPE_DEBUG_LOG */
 	spin_lock_irqsave(&tape->spinlock, flags);
 	stage->next=NULL;
 	if (tape->last_stage != NULL)
@@ -2471,7 +3124,7 @@
 /*
  * Initialize the OnStream AUX
  */
-static void idetape_init_stage(struct ata_device *drive, idetape_stage_t *stage, int frame_type, int logical_blk_num)
+static void idetape_init_stage (ide_drive_t *drive, idetape_stage_t *stage, int frame_type, int logical_blk_num)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	os_aux_t *aux = stage->aux;
@@ -2521,7 +3174,7 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	}
+	} 
 	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
 	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
 	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
@@ -2534,7 +3187,7 @@
  *	The caller should ensure that the request will not be serviced
  *	before we install the completion (usually by disabling interrupts).
  */
-static void idetape_wait_for_request(struct ata_device *drive, struct request *rq)
+static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
 {
 	DECLARE_COMPLETION(wait);
 	idetape_tape_t *tape = drive->driver_data;
@@ -2554,43 +3207,44 @@
 	spin_lock_irq(&tape->spinlock);
 }
 
-static void idetape_read_position_callback(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
-
+	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
-#endif
+			printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+#endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
-			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request(drive, rq, 0);
+			printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+			clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_INFO "ide-tape: Block Location - %u\n", ntohl (result->first_block));
-#endif
+				printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block));
+#endif /* IDETAPE_DEBUG_LOG */
 			tape->partition = result->partition;
-			tape->first_frame_position = ntohl (result->first_block);
-			tape->last_frame_position = ntohl (result->last_block);
+			tape->first_frame_position = ntohl(result->first_block);
+			tape->last_frame_position = ntohl(result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
-			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request(drive, rq, 1);
+			set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 1);
 		}
 	} else {
-		idetape_end_request(drive, rq, 0);
+		idetape_end_request(drive, 0);
 	}
+	return ide_stopped;
 }
 
 /*
@@ -2601,25 +3255,24 @@
  *			if write_filemark=0.
  *
  */
-static void idetape_create_write_filemark_cmd(struct ata_device *drive,
-		struct atapi_packet_command *pc,int write_filemark)
+static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_test_unit_ready_cmd(struct atapi_packet_command *pc)
+static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD;
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
 /*
@@ -2642,23 +3295,21 @@
  *	the request to the request list without waiting for it to be serviced !
  *	In that case, we usually use idetape_queue_pc_head.
  */
-static int __idetape_queue_pc_tail(struct ata_device *drive, struct atapi_packet_command *pc)
+static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	struct request rq;
 
-	memset(&rq, 0, sizeof(rq));
-	/* FIXME: --mdcki */
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.flags = IDETAPE_PC_RQ1;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-static void idetape_create_load_unload_cmd(struct ata_device *drive,
-		struct atapi_packet_command *pc, int cmd)
+static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
 	if (tape->onstream) {
@@ -2666,39 +3317,40 @@
 		if (cmd == !IDETAPE_LU_LOAD_MASK)
 			pc->c[4] = 4;
 	}
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = idetape_pc_callback;
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
 }
 
-static int idetape_wait_ready(struct ata_device *drive, unsigned long long timeout)
+static int idetape_wait_ready (ide_drive_t *drive, unsigned long long timeout)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 
 	/*
 	 * Wait for the tape to become ready
 	 */
 	timeout += jiffies;
-	while (jiffies < timeout) {
+	while (time_before(jiffies, timeout)) {
 		idetape_create_test_unit_ready_cmd(&pc);
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
 			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
 		}
-		if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
+		if (!(tape->sense_key == 2 && tape->asc == 4 &&
+		      (tape->ascq == 1 || tape->ascq == 8)))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ / 10);
+  		schedule_timeout(HZ / 10);
 	}
 	return -EIO;
 }
 
-static int idetape_queue_pc_tail(struct ata_device *drive, struct atapi_packet_command *pc)
+static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int rc;
@@ -2706,48 +3358,52 @@
 	rc = __idetape_queue_pc_tail(drive, pc);
 	if (rc)
 		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
-                          because retension takes approx. 8:20 with Onstream 30GB tape */
+	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
+		/* AJN-4: Changed from 5 to 10 minutes;
+		 * because retension takes approx.
+		 * 8:20 with Onstream 30GB tape
+		 */
+		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
+	}
 	return rc;
 }
 
-static int idetape_flush_tape_buffers(struct ata_device *drive)
+static int idetape_flush_tape_buffers (ide_drive_t *drive)
 {
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	int rc;
 
 	idetape_create_write_filemark_cmd(drive, &pc, 0);
-	if ((rc = idetape_queue_pc_tail (drive, &pc)))
+	if ((rc = idetape_queue_pc_tail(drive, &pc)))
 		return rc;
 	idetape_wait_ready(drive, 60 * 5 * HZ);
 	return 0;
 }
 
-static void idetape_create_read_position_cmd(struct atapi_packet_command *pc)
+static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
-	pc->callback = idetape_read_position_callback;
+	pc->callback = &idetape_read_position_callback;
 }
 
-static int idetape_read_position(struct ata_device *drive)
+static int idetape_read_position (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	int position;
 
 #if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
-	    printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
-#endif
+        if (tape->debug_level >= 4)
+		printk(KERN_INFO "ide-tape: Reached idetape_read_position\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
 #endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc))
+	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
 #ifdef NO_LONGER_REQUIRED
@@ -2765,19 +3421,17 @@
 	return position;
 }
 
-static void idetape_create_locate_cmd(struct ata_device *drive,
-		struct atapi_packet_command *pc,
-		unsigned int block, u8 partition, int skip)
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
                 /*
@@ -2786,27 +3440,25 @@
                  * data in the drive to this new position!
                  */
 		pc->c[9] = skip << 7;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = idetape_pc_callback;
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
 }
 
-static int idetape_create_prevent_cmd(struct ata_device *drive,
-		struct atapi_packet_command *pc, int prevent)
+static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 	if (!tape->capabilities.lock)
 		return 0;
 
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_PREVENT_CMD;
 	pc->c[4] = prevent;
-	pc->callback = idetape_pc_callback;
-
+	pc->callback = &idetape_pc_callback;
 	return 1;
 }
 
-static int __idetape_discard_read_pipeline(struct ata_device *drive)
+static int __idetape_discard_read_pipeline (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
@@ -2816,23 +3468,23 @@
 		return 0;
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	tape->chrdev_direction = idetape_direction_none;
-
+	
 	if (tape->first_stage == NULL)
 		return 0;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
-	if (idetape_pipeline_active (tape))
+	if (idetape_pipeline_active(tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
 	cnt = tape->nr_stages - tape->nr_pending_stages;
 	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -2845,27 +3497,27 @@
  *
  *	Like all higher level operations, we queue the commands at the tail
  *	of the request queue and wait for their completion.
- *
+ *	
  */
-static int idetape_position_tape(struct ata_device *drive, unsigned int block, u8 partition, int skip)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int retval;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 
 	if (tape->chrdev_direction == idetape_direction_read)
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return (retval);
 
-	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive, &pc));
+	idetape_create_read_position_cmd(&pc);
+	return (idetape_queue_pc_tail(drive, &pc));
 }
 
-static void idetape_discard_read_pipeline(struct ata_device *drive, int restore_position)
+static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int cnt;
@@ -2886,49 +3538,49 @@
 	}
 }
 
-static void idetape_update_stats(struct ata_device *drive)
+static void idetape_update_stats (ide_drive_t *drive)
 {
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
 
 /*
- *	idetape_queue_rw_tail generates a read/write request for the block
- *	device interface and wait for it to be serviced.
+ * idetape_queue_rw_tail generates a read/write request for the block
+ * device interface and wait for it to be serviced.
  */
-static int idetape_queue_rw_tail(struct ata_device *drive, int cmd, int blocks, struct bio *bio)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request rq;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
-#endif
+		printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+#endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
-	if (idetape_pipeline_active (tape)) {
-		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+	if (idetape_pipeline_active(tape)) {
+		printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
 		return (0);
 	}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */	
 
-	memset(&rq, 0, sizeof(rq));
-	rq.flags = cmd;
+	ide_init_drive_cmd(&rq);
 	rq.bio = bio;
+	rq.flags = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
 		tape->postpone_cnt = 600;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
 		return 0;
 
 	if (tape->merge_stage)
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 	if (rq.errors == IDETAPE_ERROR_GENERAL)
 		return -EIO;
 	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
@@ -2939,7 +3591,7 @@
  * of the write error recovery mechanism for old OnStream
  * firmware revisions.
  */
-static void idetape_onstream_read_back_buffer(struct ata_device *drive)
+static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int frames, i, logical_blk_num;
@@ -2965,7 +3617,7 @@
 			printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
 #endif
 		rq = &stage->rq;
-		memset(rq, 0, sizeof(*rq));
+		ide_init_drive_cmd(rq);
 		rq->flags = IDETAPE_WRITE_RQ;
 		rq->sector = tape->first_frame_position;
 		rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
@@ -2993,7 +3645,7 @@
 /*
  * Error recovery algorithm for the OnStream tape.
  */
-static void idetape_onstream_write_error_recovery(struct ata_device *drive)
+static void idetape_onstream_write_error_recovery (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned int block;
@@ -3003,7 +3655,7 @@
 			tape->name, ntohl(tape->sense.information), tape->logical_blk_num,
 			tape->first_frame_position, tape->last_frame_position,
 			tape->blocks_in_buffer, tape->nr_stages,
-			(ntohl(tape->sense.command_specific) >> 16) & 0xff );
+ 			(ntohl(tape->sense.command_specific) >> 16) & 0xff );
 		block = ntohl(tape->sense.information) + ((ntohl(tape->sense.command_specific) >> 16) & 0xff);
 		idetape_update_stats(drive);
 		printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %u\n", tape->name, tape->cur_frames, block);
@@ -3030,7 +3682,7 @@
 #endif
 		idetape_flush_tape_buffers(drive);
 		block = idetape_read_position(drive);
-		if (block != OS_DATA_ENDFRAME1)
+		if (block != OS_DATA_ENDFRAME1)  
 			printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, OS_DATA_ENDFRAME1);
 		idetape_position_tape(drive, 0xbb8, 0, 0); /* 3000 */
 	}
@@ -3041,67 +3693,66 @@
  *	idetape_insert_pipeline_into_queue is used to start servicing the
  *	pipeline stages, starting from tape->next_stage.
  */
-static void idetape_insert_pipeline_into_queue(struct ata_device *drive)
+static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 	if (tape->next_stage == NULL)
 		return;
-	if (!idetape_pipeline_active (tape)) {
+	if (!idetape_pipeline_active(tape)) {
 		if (tape->onstream_write_error)
 			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-		idetape_active_next_stage (drive);
-		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+		idetape_active_next_stage(drive);
+		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 	}
 }
 
-static void idetape_create_inquiry_cmd(struct atapi_packet_command *pc)
+static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_INQUIRY_CMD;
 	pc->c[4] = pc->request_transfer = 254;
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_rewind_cmd(struct ata_device *drive,
-		struct atapi_packet_command *pc)
+static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	atapi_init_pc(pc);
+	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_mode_select_cmd(struct atapi_packet_command *pc, int length)
+static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	set_bit(PC_WRITING, &pc->flags);
 	pc->c[0] = IDETAPE_MODE_SELECT_CMD;
 	pc->c[1] = 0x10;
-	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
+	put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_erase_cmd(struct atapi_packet_command *pc)
+static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = idetape_pc_callback;
+	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd(struct atapi_packet_command *pc, int count, u8 cmd)
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
 {
-	atapi_init_pc(pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_SPACE_CMD;
-	put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
@@ -3110,7 +3761,7 @@
 /*
  * Verify that we have the correct tape frame
  */
-static int idetape_verify_stage(struct ata_device *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
+static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	os_aux_t *aux = stage->aux;
@@ -3183,7 +3834,7 @@
 	return 1;
 }
 
-static void idetape_wait_first_stage(struct ata_device *drive)
+static void idetape_wait_first_stage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
@@ -3207,7 +3858,7 @@
  *	3.	If we still can't allocate a stage, fallback to
  *		non-pipelined operation mode for this request.
  */
-static int idetape_add_chrdev_write_request(struct ata_device *drive, int blocks)
+static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *new_stage;
@@ -3216,40 +3867,40 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
-	/*
-	 *	Attempt to allocate a new stage.
+     	/*
+     	 *	Attempt to allocate a new stage.
 	 *	Pay special attention to possible race conditions.
 	 */
-	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
+	while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		if (idetape_pipeline_active (tape)) {
+		if (idetape_pipeline_active(tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
 			spin_unlock_irqrestore(&tape->spinlock, flags);
-			idetape_insert_pipeline_into_queue (drive);
-			if (idetape_pipeline_active (tape))
+			idetape_insert_pipeline_into_queue(drive);
+			if (idetape_pipeline_active(tape))
 				continue;
 			/*
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
+			return idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 		}
 	}
 	rq = &new_stage->rq;
-	memset(rq, 0, sizeof(*rq));
+	ide_init_drive_cmd(rq);
 	rq->flags = IDETAPE_WRITE_RQ;
 	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
-	idetape_switch_buffers (tape, new_stage);
+	idetape_switch_buffers(tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive, new_stage);
+	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3279,14 +3930,14 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
-	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3295,13 +3946,13 @@
  *	idetape_wait_for_pipeline will wait until all pending pipeline
  *	requests are serviced. Typically called on device close.
  */
-static void idetape_wait_for_pipeline(struct ata_device *drive)
+static void idetape_wait_for_pipeline (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 
 	while (tape->next_stage || idetape_pipeline_active(tape)) {
-		idetape_insert_pipeline_into_queue (drive);
+		idetape_insert_pipeline_into_queue(drive);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active(tape))
 			idetape_wait_for_request(drive, tape->active_data_request);
@@ -3309,22 +3960,22 @@
 	}
 }
 
-static void idetape_empty_write_pipeline(struct ata_device *drive)
+static void idetape_empty_write_pipeline (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int blocks, min;
 	struct bio *bio;
-
+	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
 		return;
 	}
 	if (tape->merge_stage_size > tape->stage_size) {
-		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
 		tape->merge_stage_size = tape->stage_size;
 	}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 	if (tape->merge_stage_size) {
 		blocks = tape->merge_stage_size / tape->tape_block_size;
 		if (tape->merge_stage_size % tape->tape_block_size) {
@@ -3350,15 +4001,15 @@
 				bio = bio->bi_next;
 			}
 		}
-		(void) idetape_add_chrdev_write_request (drive, blocks);
+		(void) idetape_add_chrdev_write_request(drive, blocks);
 		tape->merge_stage_size = 0;
 	}
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 
 	/*
@@ -3369,15 +4020,20 @@
 	 */
 	tape->max_stages = tape->min_pipeline;
 #if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
-		printk (KERN_ERR "ide-tape: ide-tape pipeline bug, "
-		"first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n",
-		tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
+	if (tape->first_stage != NULL ||
+	    tape->next_stage != NULL ||
+	    tape->last_stage != NULL ||
+	    tape->nr_stages != 0) {
+		printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+			"first_stage %p, next_stage %p, "
+			"last_stage %p, nr_stages %d\n",
+			tape->first_stage, tape->next_stage,
+			tape->last_stage, tape->nr_stages);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 }
 
-static void idetape_restart_speed_control(struct ata_device *drive)
+static void idetape_restart_speed_control (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -3392,7 +4048,7 @@
 	tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
 }
 
-static int idetape_initiate_read(struct ata_device *drive, int max_stages)
+static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *new_stage;
@@ -3411,7 +4067,7 @@
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_read;
 		tape->logical_blk_num = 0;
@@ -3421,9 +4077,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
+		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			kfree(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3431,19 +4087,19 @@
 	}
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
-
-	memset(&rq, 0, sizeof(rq));
+	ide_init_drive_cmd(&rq);
 	rq.flags = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
-		new_stage = idetape_kmalloc_stage (tape);
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+	    tape->nr_stages <= max_stages) {
+		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
-			idetape_add_stage_tail (drive, new_stage);
+			idetape_add_stage_tail(drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage = idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage(tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3452,17 +4108,17 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
 }
 
-static int idetape_get_logical_blk(struct ata_device *drive, int logical_blk_num, int max_stages, int quiet)
+static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
@@ -3533,7 +4189,7 @@
  *	to service a character device read request and add read-ahead
  *	requests to our pipeline.
  */
-static int idetape_add_chrdev_read_request(struct ata_device *drive,int blocks)
+static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
@@ -3542,7 +4198,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+		printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
@@ -3556,40 +4212,42 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
+		return idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
+	if (tape->onstream && !tape->raw &&
+	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
+				tape->name);
 #endif
 		return 0;
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
 	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit (IDETAPE_FILEMARK, &tape->flags);
+		idetape_switch_buffers(tape, tape->first_stage);
+		set_bit(IDETAPE_FILEMARK, &tape->flags);
 #if USE_IOTRACE
 		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
 #endif
 		calculate_speeds(drive);
 	} else {
-		idetape_switch_buffers (tape, tape->first_stage);
+		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 1)
 				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		clear_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 		tape->logical_blk_num++;
 		tape->pipeline_head++;
@@ -3600,19 +4258,19 @@
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (bytes_read > blocks*tape->tape_block_size) {
-		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-		bytes_read=blocks*tape->tape_block_size;
+		printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
+		bytes_read = blocks*tape->tape_block_size;
 	}
-#endif
+#endif /* IDETAPE_DEBUG_BUGS */
 	return (bytes_read);
 }
 
-static void idetape_pad_zeros(struct ata_device *drive, int bcount)
+static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct bio *bio;
 	int blocks;
-
+	
 	while (bcount) {
 		unsigned int count;
 
@@ -3622,22 +4280,22 @@
 		blocks = count / tape->tape_block_size;
 		while (count) {
 			atomic_set(&bio->bi_cnt, min(count, bio->bi_size));
-			memset (bio_data(bio), 0, bio->bi_size);
+			memset(bio_data(bio), 0, bio->bi_size);
 			count -= atomic_read(&bio->bi_cnt);
 			bio = bio->bi_next;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
+		idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 	}
 }
 
-static int idetape_pipeline_size(struct ata_device *drive)
+static int idetape_pipeline_size (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
 	struct request *rq;
 	int size = 0;
 
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	stage = tape->first_stage;
 	while (stage != NULL) {
 		rq = &stage->rq;
@@ -3654,24 +4312,24 @@
  *	Rewinds the tape to the Beginning Of the current Partition (BOP).
  *
  *	We currently support only one partition.
- */
-static int idetape_rewind_tape(struct ata_device *drive)
+ */ 
+static int idetape_rewind_tape (ide_drive_t *drive)
 {
 	int retval;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
-#endif
-
-	idetape_create_rewind_cmd (drive, &pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+		printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+#endif /* IDETAPE_DEBUG_LOG */	
+	
+	idetape_create_rewind_cmd(drive, &pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 
-	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_read_position_cmd(&pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 	tape->logical_blk_num = 0;
@@ -3685,16 +4343,15 @@
  *	mtio.h compatible commands should be issued to the character device
  *	interface.
  */
-static int idetape_blkdev_ioctl(struct ata_device *drive, struct inode *inode, struct file *file,
-				 unsigned int cmd, unsigned long arg)
+static int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_config_t config;
 
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+#endif /* IDETAPE_DEBUG_LOG */
 	switch (cmd) {
 		case 0x0340:
 			if (copy_from_user ((char *) &config, (char *) arg, sizeof (idetape_config_t)))
@@ -3704,8 +4361,8 @@
 			break;
 		case 0x0350:
 			config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
-			config.nr_stages = tape->max_stages;
-			if (copy_to_user ((char *) arg, (char *) &config, sizeof (idetape_config_t)))
+			config.nr_stages = tape->max_stages; 
+			if (copy_to_user((char *) arg, (char *) &config, sizeof (idetape_config_t)))
 				return -EFAULT;
 			break;
 		default:
@@ -3719,7 +4376,7 @@
  *	However, we still allow opening it so that we can issue general
  *	ide driver configuration ioctl's, such as the interrupt unmask feature.
  */
-static int idetape_blkdev_open(struct inode *inode, struct file *filp, struct ata_device *drive)
+static int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
@@ -3728,7 +4385,7 @@
 	return 0;
 }
 
-static void idetape_blkdev_release(struct inode *inode, struct file *filp, struct ata_device *drive)
+static void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
@@ -3737,9 +4394,19 @@
 }
 
 /*
+ *	idetape_pre_reset is called before an ATAPI/ATA software reset.
+ */
+static void idetape_pre_reset (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	if (tape != NULL)
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+}
+
+/*
  *	Character device interface functions
  */
-static struct ata_device *get_drive_ptr (kdev_t i_rdev)
+static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
 	unsigned int i = minor(i_rdev) & ~0xc0;
 
@@ -3748,7 +4415,7 @@
 	return (idetape_chrdevs[i].drive);
 }
 
-static int idetape_onstream_space_over_filemarks_backward(struct ata_device *drive,short mt_op,int mt_count)
+static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int cnt = 0;
@@ -3780,7 +4447,7 @@
 	}
 	if (mt_op == MTBSFM) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -3792,7 +4459,7 @@
  *
  * Just scans for the filemark sequentially.
  */
-static int idetape_onstream_space_over_filemarks_forward_slow(struct ata_device *drive,short mt_op,int mt_count)
+static int idetape_onstream_space_over_filemarks_forward_slow (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int cnt = 0;
@@ -3819,12 +4486,12 @@
 		if (cnt == mt_count)
 			break;
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -3835,7 +4502,7 @@
 /*
  * Fast linux specific version of OnStream FSF
  */
-static int idetape_onstream_space_over_filemarks_forward_fast(struct ata_device *drive,short mt_op,int mt_count)
+static int idetape_onstream_space_over_filemarks_forward_fast (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int cnt = 0, next_mark_addr;
@@ -3903,7 +4570,7 @@
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -3919,10 +4586,10 @@
  *	the filemark is in our internal pipeline even if the tape doesn't
  *	support spacing over filemarks in the reverse direction.
  */
-static int idetape_space_over_filemarks(struct ata_device *drive,short mt_op,int mt_count)
+static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	unsigned long flags;
 	int retval,count=0;
 	int speed_control;
@@ -3950,7 +4617,7 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		clear_bit(IDETAPE_FILEMARK, &tape->flags);
 		while (tape->first_stage != NULL) {
 			idetape_wait_first_stage(drive);
 			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
@@ -3959,7 +4626,7 @@
 				switch (mt_op) {
 					case MTFSF:
 						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
+						idetape_remove_stage_head(drive);
 						spin_unlock_irqrestore(&tape->spinlock, flags);
 					case MTFSFM:
 						return (0);
@@ -3968,10 +4635,10 @@
 				}
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
-			idetape_remove_stage_head (drive);
+			idetape_remove_stage_head(drive);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 1);
 	}
 
 	/*
@@ -3980,27 +4647,27 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
-			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTFSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTBSF, 1));
+			return (idetape_space_over_filemarks(drive, MTBSF, 1));
 		case MTBSF:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTBSF, mt_count+count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			return (idetape_space_over_filemarks(drive, MTFSF, 1));
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
@@ -4027,7 +4694,7 @@
 				    size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct ata_device *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
@@ -4041,11 +4708,11 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction != idetape_direction_read) {
-		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
+		if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
 			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
 				tape->user_bs_factor = count / tape->tape_block_size;
 	}
@@ -4054,49 +4721,51 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = min(tape->merge_stage_size, count);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		actually_read = min((unsigned long) (tape->merge_stage_size), (unsigned long) count);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
 	}
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = min(count, bytes_read);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
+		temp = min((unsigned long) count, (unsigned long) bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
-	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
+	if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
 #endif
-		idetape_space_over_filemarks (drive, MTFSF, 1);
+		idetape_space_over_filemarks(drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
-					tape->name, tape->logical_blk_num);
+	if (tape->onstream && !actually_read &&
+	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
+			"logical block number %d, skipping\n",
+			tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
 	return actually_read;
 }
 
-static void idetape_update_last_marker(struct ata_device *drive, int last_mark_addr, int next_mark_addr)
+static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr, int next_mark_addr)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
@@ -4114,21 +4783,25 @@
 	position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+		printk(KERN_INFO "ide-tape: current position (2) %d, "
+			"lblk %d\n", position, tape->logical_blk_num);
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
+		printk(KERN_INFO "ide-tape: current position (2) "
+			"tape block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bio)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
 	aux = stage->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+		printk(KERN_INFO "ide-tape: %s: expected to find marker "
+			"at addr %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
@@ -4138,19 +4811,20 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't write back marker "
+			"frame at %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 	idetape_position_tape(drive, position, 0, 0);
 	return;
 }
 
-static void idetape_write_filler(struct ata_device *drive, int block, int cnt)
+static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
@@ -4167,21 +4841,23 @@
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
 #endif
-	if (rc != 0) 
-		return;	/* don't write fillers if we cannot position the tape. */
+	if (rc != 0)
+		/* don't write fillers if we cannot position the tape. */
+		return;
 
 	strcpy(bio_data(stage->bio), "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: "
+				"couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
-static void __idetape_write_header(struct ata_device *drive, int block, int cnt)
+static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
@@ -4206,23 +4882,25 @@
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(bio_data(stage->bio), &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
+			printk(KERN_INFO "ide-tape: %s: couldn't write "
+				"header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 }
 
-static void idetape_write_header(struct ata_device *drive, int locate_eod)
+static void idetape_write_header (ide_drive_t *drive, int locate_eod)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: writing tape header\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: writing tape header\n",
+			tape->name);
 #endif
 	if (!tape->onstream || tape->raw)
 		return;
@@ -4232,17 +4910,19 @@
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+			printk(KERN_INFO "ide-tape: %s: locating back to eod "
+				"frame addr %d\n", tape->name,
+				tape->eod_frame_addr);
 #endif
 		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 	}
 }
 
-static ssize_t idetape_chrdev_write(struct file *file, const char *buf,
-		size_t count, loff_t *ppos)
+static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
+				     size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct ata_device *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t retval, actually_written = 0;
 	int position;
@@ -4254,22 +4934,25 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %Zd\n", count);
-#endif
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
+			"count %Zd\n", count);
+#endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->onstream) {
 		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
-					tape->name, tape->tape_block_size, count);
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d "
+				"bytes as block size (%Zd used)\n",
+				tape->name, tape->tape_block_size, count);
 			return -EINVAL;
 		}
 		/*
-		 * Check if we reach the end of the tape. Just assume the whole pipeline
-		 * is filled with write requests!
+		 * Check if we reach the end of the tape. Just assume the
+		 * whole pipeline is filled with write requests!
 		 */
 		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
 #if ONSTREAM_DEBUG
-			printk(KERN_INFO, "chrdev_write: Write truncated at EOM early warning");
+			printk(KERN_INFO, "chrdev_write: Write truncated at "
+				"EOM early warning");
 #endif
 			if (tape->chrdev_direction == idetape_direction_write)
 				idetape_write_release(inode);
@@ -4277,19 +4960,21 @@
 		}
 	}
 
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+	if (tape->chrdev_direction != idetape_direction_write) {
+		/* Initialize write operation */
 		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size "
+				"should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
-#endif
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+#endif /* IDETAPE_DEBUG_BUGS */
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_write;
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
@@ -4309,14 +4994,18 @@
 			}
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
+				printk(KERN_INFO "ide-tape: %s: positioning "
+					"tape to eod at %d\n",
+					tape->name, tape->eod_frame_addr);
 #endif
 			position = idetape_read_position(drive);
 			if (position != tape->eod_frame_addr)
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: first_frame_position %d\n", tape->name, tape->first_frame_position);
+				printk(KERN_INFO "ide-tape: %s: "
+					"first_frame_position %d\n",
+					tape->name, tape->first_frame_position);
 #endif
 		}
 
@@ -4325,16 +5014,17 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
+		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			kfree(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
 		}
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk("ide-tape: first_frame_position %d\n", tape->first_frame_position);
+			printk("ide-tape: first_frame_position %d\n",
+				tape->first_frame_position);
 #endif
 	}
 	if (count == 0)
@@ -4344,60 +5034,60 @@
 	if (tape->merge_stage_size) {
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
-			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = min(tape->stage_size - tape->merge_stage_size, count);
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		actually_written = min((unsigned long) (tape->stage_size - tape->merge_stage_size), (unsigned long) count);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
-				return (retval);
+				return(retval);
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
 		buf += tape->stage_size;
 		count -= tape->stage_size;
-		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 		actually_written += tape->stage_size;
 		if (retval <= 0)
-			return (retval);
+			return(retval);
 	}
 	if (count) {
-		actually_written+=count;
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		actually_written += count;
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
 		tape->merge_stage_size += count;
 	}
 	return (actually_written);
 }
 
-static int idetape_write_filemark(struct ata_device *drive)
+static int idetape_write_filemark (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int last_mark_addr;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 
 	if (!tape->onstream) {
 		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive, &pc)) {
-			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		if (idetape_queue_pc_tail(drive, &pc)) {
+			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
 	} else if (!tape->raw) {
 		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 		if (tape->merge_stage != NULL) {
 			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros (drive, tape->stage_size);
+			idetape_pad_zeros(drive, tape->stage_size);
 			tape->logical_blk_num++;
-			__idetape_kfree_stage (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 		}
 		if (tape->filemark_cnt)
@@ -4409,24 +5099,24 @@
 	return 0;
 }
 
-static void idetape_write_eod(struct ata_device *drive)
+static void idetape_write_eod (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 	if (!tape->onstream || tape->raw)
 		return;
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
 		tape->eod_frame_addr = idetape_read_position(drive);
 		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros (drive, tape->stage_size);
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->stage_size);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	return;
 }
 
-int idetape_seek_logical_blk(struct ata_device *drive, int logical_blk_num)
+int idetape_seek_logical_blk (ide_drive_t *drive, int logical_blk_num)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int estimated_address = logical_blk_num + 20;
@@ -4454,7 +5144,9 @@
 error:
 	tape->speed_control = speed_control;
 	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries);
+	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
+		"(at %d), %d retries\n", tape->name, logical_blk_num,
+		tape->logical_blk_num, retries);
 	return -EIO;
 ok:
 	tape->speed_control = speed_control;
@@ -4486,7 +5178,7 @@
  *		In this case, MTFSFM is also usually not supported (it is
  *		supported in the rare case in which we crossed the filemark
  *		during our read-ahead pipelined operation mode).
- *
+ *		
  *	MTWEOF	-	Writes mt_count filemarks. Tape is positioned after
  *			the last written filemark.
  *
@@ -4506,7 +5198,7 @@
  *
  *	MTERASE	-	Erases tape.
  *
- *	MTSETBLK -	Sets the user block size to mt_count bytes. If
+ *	MTSETBLK - 	Sets the user block size to mt_count bytes. If
  *			mt_count is 0, we will attempt to autodetect
  *			the block size.
  *
@@ -4514,26 +5206,27 @@
  *			each block is assumed to contain which user_block_size
  *			bytes.
  *
- *	MTSETPART -	Switches to another tape partition.
+ *	MTSETPART - 	Switches to another tape partition.
  *
- *	MTLOCK -	Locks the tape door.
+ *	MTLOCK - 	Locks the tape door.
  *
- *	MTUNLOCK -	Unlocks the tape door.
+ *	MTUNLOCK - 	Unlocks the tape door.
  *
  *	The following commands are currently not supported:
  *
  *	MTFSS, MTBSS, MTWSM, MTSETDENSITY,
  *	MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD.
  */
-static int idetape_mtioctop(struct ata_device *drive,short mt_op,int mt_count)
+static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	int i,retval;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+		printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: "
+			"mt_op=%d, mt_count=%d\n", mt_op, mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
@@ -4545,41 +5238,42 @@
 		case MTBSFM:
 			if (!mt_count)
 				return (0);
-			return (idetape_space_over_filemarks (drive,mt_op,mt_count));
+			return (idetape_space_over_filemarks(drive,mt_op,mt_count));
 		default:
 			break;
 	}
 	switch (mt_op) {
 		case MTWEOF:
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 			for (i = 0; i < mt_count; i++) {
 				retval = idetape_write_filemark(drive);
-				if (retval) return retval;
+				if (retval)
+					return retval;
 			}
 			return (0);
 		case MTREW:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
 				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTNOP:
-			idetape_discard_read_pipeline (drive, 0);
-			return (idetape_flush_tape_buffers (drive));
+			idetape_discard_read_pipeline(drive, 0);
+			return (idetape_flush_tape_buffers(drive));
 		case MTRETEN:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -4593,8 +5287,8 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
 				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
@@ -4602,7 +5296,7 @@
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
-				idetape_flush_tape_buffers (drive);
+				idetape_flush_tape_buffers(drive);
 				idetape_write_header(drive, 0);
 				/*
 				 * write filler frames to the unused frames...
@@ -4610,13 +5304,13 @@
 				 */
 				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
 				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers (drive);
-				(void) idetape_rewind_tape (drive);
+				idetape_flush_tape_buffers(drive);
+				(void) idetape_rewind_tape(drive);
 				return 0;
 			}
-			(void) idetape_rewind_tape (drive);
-			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive, &pc));
+			(void) idetape_rewind_tape(drive);
+			idetape_create_erase_cmd(&pc);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -4629,21 +5323,21 @@
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
 				tape->user_bs_factor = mt_count / tape->tape_block_size;
-				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+				clear_bit(IDETAPE_DETECT_BS, &tape->flags);
 			} else
-				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
 			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline (drive, 0);
-				return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+				idetape_discard_read_pipeline(drive, 0);
+				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 			}
 			return idetape_seek_logical_blk(drive, mt_count);
 		case MTSETPART:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (tape->onstream)
 				return -EIO;
-			return (idetape_position_tape (drive, 0, mt_count, 0));
+			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
 			if (tape->onstream) {
@@ -4652,26 +5346,27 @@
 				if (mt_op == MTFSR)
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
 				else {
-					idetape_discard_read_pipeline (drive, 0);
+					idetape_discard_read_pipeline(drive, 0);
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
 				}
 			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not "
+				"supported\n", mt_op);
 			return (-EIO);
 	}
 }
@@ -4701,7 +5396,7 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct ata_device *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -4710,26 +5405,27 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, "
+			"cmd=%u\n", cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->restart_speed_control_req = 1;
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
+		idetape_empty_write_pipeline(drive);
+		idetape_flush_tape_buffers(drive);
 	}
 	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
 		if ((position = idetape_read_position(drive)) < 0)
 			return -EIO;
 	}
 	switch (cmd) {
 		case MTIOCTOP:
-			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+			if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
 				return -EFAULT;
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+			return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
 		case MTIOCGET:
-			memset (&mtget, 0, sizeof (struct mtget));
+			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
 			if (!tape->onstream || tape->raw)
 				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
@@ -4747,7 +5443,7 @@
 				if (position <= OS_DATA_STARTFRAME1)
 					mtget.mt_gstat |= GMT_BOT(0xffffffff);
 			}
-			if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget)))
+			if (copy_to_user((char *) arg,(char *) &mtget, sizeof(struct mtget)))
 				return -EFAULT;
 			return 0;
 		case MTIOCPOS:
@@ -4757,17 +5453,17 @@
 				mtpos.mt_blkno = tape->logical_blk_num;
 			} else
 				mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
-			if (copy_to_user ((char *) arg,(char *) &mtpos, sizeof (struct mtpos)))
+			if (copy_to_user((char *) arg,(char *) &mtpos, sizeof(struct mtpos)))
 				return -EFAULT;
 			return 0;
 		default:
 			if (tape->chrdev_direction == idetape_direction_read)
-				idetape_discard_read_pipeline (drive, 1);
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+				idetape_discard_read_pipeline(drive, 1);
+			return (idetape_blkdev_ioctl(drive,inode,file,cmd,arg));
 	}
 }
 
-static int __idetape_analyze_headers(struct ata_device *drive, int block)
+static int __idetape_analyze_headers (ide_drive_t *drive, int block)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_stage_t *stage;
@@ -4783,7 +5479,7 @@
 	tape->wrt_pass_cntr = 0;
 	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage (tape, 0, 0);
+	stage = __idetape_kmalloc_stage(tape, 0, 0);
 	if (stage == NULL)
 		return 0;
 #if ONSTREAM_DEBUG
@@ -4791,20 +5487,23 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bio)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	header = (os_header_t *) bio_data(stage->bio);
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
-		__idetape_kfree_stage (stage);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
-		printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (up to 1.%d supported)\n", header->major_rev, header->minor_rev, OS_ADR_MINREV);
+		printk(KERN_INFO "ide-tape: warning: revision %d.%d "
+			"detected (up to 1.%d supported)\n",
+			header->major_rev, header->minor_rev, OS_ADR_MINREV);
 	if (header->par_num != 1)
 		printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num);
 	tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr);
@@ -4819,21 +5518,25 @@
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
-					 tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version "
+				"%d detected (current 3)\n",
+				 tape->name, tape->linux_media_version);
 	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
+		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
+			"(%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
 	}
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+		printk(KERN_INFO "ide-tape: %s: detected write pass counter "
+			"%d, eod frame addr %d\n", tape->name,
+			tape->wrt_pass_cntr, tape->eod_frame_addr);
 #endif
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return 1;
 }
 
-static int idetape_analyze_headers(struct ata_device *drive)
+static int idetape_analyze_headers (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int position, block;
@@ -4865,26 +5568,26 @@
  */
 static int idetape_chrdev_open (struct inode *inode, struct file *filp)
 {
-	struct ata_device *drive;
+	ide_drive_t *drive;
 	idetape_tape_t *tape;
-	struct atapi_packet_command pc;
-	unsigned int minor=minor(inode->i_rdev);
-
+	idetape_pc_t pc;
+	unsigned int minor = minor(inode->i_rdev);
+			
 #if IDETAPE_DEBUG_LOG
-	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
-#endif
-
-	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+	printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
+#endif /* IDETAPE_DEBUG_LOG */
+	
+	if ((drive = get_drive_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	if (!tape->onstream) {	
 		idetape_read_position(drive);
-		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
-			(void) idetape_rewind_tape (drive);
+		if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+			(void) idetape_rewind_tape(drive);
 	} else {
 		if (minor & 64) {
 			tape->tape_block_size = tape->stage_size = 32768 + 512;
@@ -4903,12 +5606,12 @@
 	}
 	idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive, &pc)) {
+			if (!idetape_queue_pc_tail(drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -4923,22 +5626,22 @@
 
 static void idetape_write_release (struct inode *inode)
 {
-	struct ata_device *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=minor(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 
-	idetape_empty_write_pipeline (drive);
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	idetape_empty_write_pipeline(drive);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
-		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
 	idetape_write_eod(drive);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 	idetape_write_header(drive, minor >= 128);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 
 	return;
 }
@@ -4948,15 +5651,16 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	struct ata_device *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape;
-	struct atapi_packet_command pc;
-	unsigned int minor=minor(inode->i_rdev);
+	idetape_pc_t pc;
+	unsigned int minor = minor(inode->i_rdev);
 
+	lock_kernel();
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
@@ -4964,25 +5668,26 @@
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 		else
-			idetape_wait_for_pipeline (drive);
+			idetape_wait_for_pipeline(drive);
 	}
 	if (tape->cache_stage != NULL) {
-		__idetape_kfree_stage (tape->cache_stage);
+		__idetape_kfree_stage(tape->cache_stage);
 		tape->cache_stage = NULL;
 	}
 	if (minor < 128)
-		(void) idetape_rewind_tape (drive);
+		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
 			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive, &pc))
+				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
 		}
 		MOD_DEC_USE_COUNT;
 	}
-	clear_bit (IDETAPE_BUSY, &tape->flags);
+	clear_bit(IDETAPE_BUSY, &tape->flags);
+	unlock_kernel();
 	return 0;
 }
 
@@ -4993,11 +5698,11 @@
  *	1	If the tape can be supported by us, based on the information
  *		we have so far.
  *
- *	0	If this tape driver is not currently supported by us.
+ *	0 	If this tape driver is not currently supported by us.
  */
-static int idetape_identify_device(struct ata_device *drive,struct hd_driveid *id)
+static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
 {
-	struct atapi_id_gcw gcw;
+	struct idetape_id_gcw gcw;
 #if IDETAPE_DEBUG_INFO
 	unsigned short mask,i;
 #endif /* IDETAPE_DEBUG_INFO */
@@ -5008,107 +5713,108 @@
 	*((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-	printk (KERN_INFO "ide-tape: Protocol Type: ");
+	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk(KERN_INFO "ATA\n");break;
+		case 2:	printk(KERN_INFO "ATAPI\n");break;
+		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
+	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk(KERN_INFO "Direct-access Device\n");break;
+		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
+		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
+		case 6: printk(KERN_INFO "Reserved\n");
+		case 7: printk(KERN_INFO "Optical memory Device\n");break;
+		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
+		default: printk(KERN_INFO "Reserved\n");
 	}
-	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
+		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
+		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
+		case 3: printk(KERN_INFO "Reserved\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Command Packet Size: ");
+	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
-	}
-	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+		case 0: printk(KERN_INFO "12 bytes\n");break;
+		case 1: printk(KERN_INFO "16 bytes\n");break;
+		default: printk(KERN_INFO "Reserved\n");break;
+	}
+	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk(KERN_INFO "%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk(KERN_INFO "(active) ");
 	}
-	printk (KERN_INFO "\n");
-	printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+	printk(KERN_INFO "\n");
+	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk(KERN_INFO "%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk(KERN_INFO "(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk(KERN_INFO "\n");
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
+			id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk(KERN_INFO "%d ns\n",id->eide_dma_min);
 
-		printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk(KERN_INFO "%d ns\n",id->eide_dma_time);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio);
+			printk(KERN_INFO "%d ns\n",id->eide_pio);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
 		
 	} else
-		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_INFO */
 
 	/* Check that we can support this device */
 
 	if (gcw.protocol !=2 )
-		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 1)
-		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+		printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
 	else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
 		if (gcw.packet_size == 1)
-			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+			printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
 	} else
 		return 1;
 	return 0;
@@ -5117,9 +5823,9 @@
 /*
  * Notify vendor ID to the OnStream tape drive
  */
-static void idetape_onstream_set_vendor(struct ata_device *drive, char *vendor)
+static void idetape_onstream_set_vendor (ide_drive_t *drive, char *vendor)
 {
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_mode_parameter_header_t *header;
 
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + 8);
@@ -5135,8 +5841,8 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
 
@@ -5144,9 +5850,9 @@
  * Various unused OnStream commands
  */
 #if ONSTREAM_DEBUG
-static void idetape_onstream_set_retries(struct ata_device *drive, int retries)
+static void idetape_onstream_set_retries (ide_drive_t *drive, int retries)
 {
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 
 	idetape_create_mode_select_cmd(&pc, sizeof(idetape_mode_parameter_header_t) + 4);
 	pc.buffer[0] = 3 + 4;
@@ -5157,26 +5863,26 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
 
 /*
  * Configure 32.5KB block size.
  */
-static void idetape_onstream_configure_block_size(struct ata_device *drive)
+static void idetape_onstream_configure_block_size (ide_drive_t *drive)
 {
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_mode_parameter_header_t *header;
 	idetape_block_size_page_t *bs;
 
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
@@ -5196,8 +5902,8 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
 	/*
@@ -5211,19 +5917,19 @@
 /*
  * Use INQUIRY to get the firmware revision
  */
-static void idetape_get_inquiry_results(struct ata_device *drive)
+static void idetape_get_inquiry_results (ide_drive_t *drive)
 {
 	char *r;
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
-	atapi_inquiry_result_t *inquiry;
-
+	idetape_pc_t pc;
+	idetape_inquiry_result_t *inquiry;
+	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
-	inquiry = (atapi_inquiry_result_t *) pc.buffer;
+	inquiry = (idetape_inquiry_result_t *) pc.buffer;
 	memcpy(tape->vendor_id, inquiry->vendor_id, 8);
 	memcpy(tape->product_id, inquiry->product_id, 16);
 	memcpy(tape->firmware_revision, inquiry->revision_level, 4);
@@ -5241,7 +5947,7 @@
 /*
  * Configure the OnStream ATAPI tape drive for default operation
  */
-static void idetape_configure_onstream(struct ata_device *drive)
+static void idetape_configure_onstream (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -5265,16 +5971,16 @@
  *	idetape_get_mode_sense_parameters asks the tape about its various
  *	parameters. This may work for other drives to???
  */
-static void idetape_onstream_mode_sense_tape_parameter_page(struct ata_device *drive, int debug)
+static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_mode_parameter_header_t *header;
 	onstream_tape_paramtr_page_t *prm;
-
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+	
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -5282,7 +5988,7 @@
 
         tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
         if (debug) {
-	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
                drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
         }
 
@@ -5294,16 +6000,16 @@
  *	parameters. In particular, we will adjust our data transfer buffer
  *	size to the recommended value as returned by the tape.
  */
-static void idetape_get_mode_sense_results(struct ata_device *drive)
+static void idetape_get_mode_sense_results (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
-
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+	
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
 		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
 		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
 		return;
@@ -5334,33 +6040,33 @@
 		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
-	printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-	printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
-
-	printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-	printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);
-	printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+	printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+	printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+	printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+	printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+	printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+	
+	printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+	printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+	printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+	printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
+	printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
@@ -5368,17 +6074,17 @@
  *	ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
  *	and if it succeeds sets the tape block size with the reported value
  */
-static void idetape_get_blocksize_from_block_descriptor(struct ata_device *drive)
+static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
 {
 
 	idetape_tape_t *tape = drive->driver_data;
-	struct atapi_packet_command pc;
+	idetape_pc_t pc;
 	idetape_mode_parameter_header_t *header;
 	idetape_parameter_block_descriptor_t *block_descrp;
-
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
+	
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		if (tape->tape_block_size == 0) {
 			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
 			tape->tape_block_size =  32768;
@@ -5389,8 +6095,42 @@
 	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
 	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
-#endif
+	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+#endif /* IDETAPE_DEBUG_INFO */
+}
+static void idetape_add_settings (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+
+/*
+ *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
+ */
+	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
+	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
+	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
+	ide_add_setting(drive,	"stage",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1024,				&tape->stage_size,			NULL);
+	ide_add_setting(drive,	"tdsc",		SETTING_RW,	-1,	-1,		TYPE_INT,	IDETAPE_DSC_RW_MIN,	IDETAPE_DSC_RW_MAX,	1000,				HZ,				&tape->best_dsc_rw_frequency,		NULL);
+	ide_add_setting(drive,	"dsc_overlap",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,			1,			1,				1,				&drive->dsc_overlap,			NULL);
+	ide_add_setting(drive,	"pipeline_head_speed_c",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->controlled_pipeline_head_speed,	NULL);
+	ide_add_setting(drive,	"pipeline_head_speed_u",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->uncontrolled_pipeline_head_speed,	NULL);
+	ide_add_setting(drive,	"avg_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->avg_speed,		NULL);
+	ide_add_setting(drive,	"debug_level",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->debug_level,		NULL);
+	if (tape->onstream) {
+		ide_add_setting(drive,	"cur_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->cur_frames,		NULL);
+		ide_add_setting(drive,	"max_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->max_frames,		NULL);
+		ide_add_setting(drive,	"insert_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_speed,		NULL);
+		ide_add_setting(drive,	"speed_control",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->speed_control,		NULL);
+		ide_add_setting(drive,	"tape_still_time",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->tape_still_time,		NULL);
+		ide_add_setting(drive,	"max_insert_speed",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->max_insert_speed,	NULL);
+		ide_add_setting(drive,	"insert_size",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_size,		NULL);
+		ide_add_setting(drive,	"capacity",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->capacity,		NULL);
+		ide_add_setting(drive,	"first_frame",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->first_frame_position,		NULL);
+		ide_add_setting(drive,	"logical_blk",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->logical_blk_num,		NULL);
+	}
 }
 
 /*
@@ -5405,35 +6145,34 @@
  *	Note that at this point ide.c already assigned us an irq, so that
  *	we can queue requests here and wait for their completion.
  */
-static void idetape_setup(struct ata_device *drive, idetape_tape_t *tape, int minor)
+static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
 {
-	unsigned long t1, tmid, tn;
-	unsigned long t;
+	unsigned long t1, tmid, tn, t;
 	int speed;
-	struct atapi_id_gcw gcw;
+	struct idetape_id_gcw gcw;
 	int stage_size;
 	struct sysinfo si;
 
-	memset (tape, 0, sizeof (idetape_tape_t));
+	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
 	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
 	drive->dsc_overlap = 1;
-#ifdef CONFIG_PCI
-	if (!tape->onstream && drive->channel->pci_dev != NULL) {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
 		/*
 		 * These two ide-pci host adapters appear to need DSC overlap disabled.
 		 * This probably needs further analysis.
 		 */
-		if ((drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (drive->channel->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
 			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-			drive->dsc_overlap = 0;
+		    	drive->dsc_overlap = 0;
 		}
 	}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 	tape->drive = drive;
 	tape->minor = minor;
 	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
@@ -5446,7 +6185,7 @@
 		set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
 
 	tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
-
+	
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
 	idetape_get_blocksize_from_block_descriptor(drive);
@@ -5457,7 +6196,7 @@
 	tape->user_bs_factor = 1;
 	tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	while (tape->stage_size > 0xffff) {
-		printk (KERN_NOTICE "ide-tape: decreasing stage size\n");
+		printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
 		tape->capabilities.ctl /= 2;
 		tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	}
@@ -5482,7 +6221,7 @@
 	 * 	Limit memory use for pipeline to 10% of physical memory
 	 */
 	si_meminfo(&si);
-	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
 	tape->min_pipeline = tape->max_stages;
 	tape->max_pipeline = tape->max_stages * 2;
@@ -5500,151 +6239,319 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = max(min(t, (unsigned long) IDETAPE_DSC_RW_MAX),
-			(unsigned long) IDETAPE_DSC_RW_MIN);
-	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
-		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
+	tape->best_dsc_rw_frequency = max((unsigned long) min(t, (unsigned long) IDETAPE_DSC_RW_MAX), (unsigned long) IDETAPE_DSC_RW_MIN);
+	printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+		"%dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed,
+		(tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024,
+		tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ,
+		drive->using_dma ? ", DMA":"");
+
+	idetape_add_settings(drive);
 }
 
-static int idetape_cleanup(struct ata_device *drive)
+static int idetape_cleanup (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int minor = tape->minor;
 	unsigned long flags;
 
-	spin_lock_irqsave (&tape->spinlock, flags);	/* overkill? */
-	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
-		spin_unlock_irqrestore(&tape->spinlock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
+	if (test_bit (IDETAPE_BUSY, &tape->flags) || drive->usage ||
+	    tape->first_stage != NULL || tape->merge_stage_size) {
+		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
 	idetape_chrdevs[minor].drive = NULL;
-	spin_unlock_irqrestore(&tape->spinlock, flags);
-
-	MOD_DEC_USE_COUNT;
-
-	ata_unregister_device(drive);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	DRIVER(drive)->busy = 0;
+	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister (tape->de_r);
-	devfs_unregister (tape->de_n);
+	devfs_unregister(tape->de_r);
+	devfs_unregister(tape->de_n);
 	kfree (tape);
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
 		if (idetape_chrdevs[minor].drive != NULL)
 			return 0;
-	unregister_chrdev (IDETAPE_MAJOR, "ht");
+	unregister_chrdev(IDETAPE_MAJOR, "ht");
 	idetape_chrdev_present = 0;
 	return 0;
 }
 
-static void idetape_attach(struct ata_device *);
+#ifdef CONFIG_PROC_FS
+
+static int proc_idetape_read_name
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	idetape_tape_t	*tape = drive->driver_data;
+	char		*out = page;
+	int		len;
+
+	len = sprintf(out, "%s\n", tape->name);
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
 
-static struct ata_operations idetape_driver = {
-	.owner =		THIS_MODULE,
-	.attach =		idetape_attach,
-	.cleanup =		idetape_cleanup,
-	.standby =		NULL,
-	.do_request =		idetape_do_request,
-	.end_request =		idetape_end_request,
-	.ioctl =		idetape_blkdev_ioctl,
-	.open =			idetape_blkdev_open,
-	.release =		idetape_blkdev_release,
+static ide_proc_entry_t idetape_proc[] = {
+	{ "name",	S_IFREG|S_IRUGO,	proc_idetape_read_name,	NULL },
+	{ NULL, 0, NULL, NULL }
 };
 
+#else
+
+#define	idetape_proc	NULL
+
+#endif
+
+int idetape_init (void);
+int idetape_reinit(ide_drive_t *drive);
+
+/*
+ *	IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idetape_driver = {
+	name:			"ide-tape",
+	version:		IDETAPE_VERSION,
+	media:			ide_tape,
+	busy:			1,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
+	supports_dma:		1,
+#endif
+	supports_dsc_overlap: 	1,
+	cleanup:		idetape_cleanup,
+	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
+	flushcache:		NULL,
+	do_request:		idetape_do_request,
+	end_request:		idetape_end_request,
+	sense:			NULL,
+	error:			NULL,
+	ioctl:			idetape_blkdev_ioctl,
+	open:			idetape_blkdev_open,
+	release:		idetape_blkdev_release,
+	media_change:		NULL,
+	revalidate:		NULL,
+	pre_reset:		idetape_pre_reset,
+	capacity:		NULL,
+	special:		NULL,
+	proc:			idetape_proc,
+	init:			idetape_init,
+	reinit:			idetape_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
+};
 
+static ide_module_t idetape_module = {
+	IDE_DRIVER_MODULE,
+	idetape_init,
+	&idetape_driver,
+	NULL
+};
 
 /*
  *	Our character device supporting functions, passed to register_chrdev.
  */
 static struct file_operations idetape_fops = {
-	.owner =	THIS_MODULE,
-	.read =		idetape_chrdev_read,
-	.write =	idetape_chrdev_write,
-	.ioctl =	idetape_chrdev_ioctl,
-	.open =		idetape_chrdev_open,
-	.release =	idetape_chrdev_release,
+	owner:		THIS_MODULE,
+	read:		idetape_chrdev_read,
+	write:		idetape_chrdev_write,
+	ioctl:		idetape_chrdev_ioctl,
+	open:		idetape_chrdev_open,
+	release:	idetape_chrdev_release,
 };
 
-static void idetape_attach(struct ata_device *drive)
+int idetape_reinit (ide_drive_t *drive)
 {
+#if 0
 	idetape_tape_t *tape;
-	int minor, supported = 0;
-	char *req;
-	struct ata_channel *channel;
-	int unit;
-
-	if (drive->type != ATA_TAPE)
-		return;
-
-	req = drive->driver_req;
-	if (req[0] != '\0' && strcmp(req, "ide-tape"))
-		return;
-
+	int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+	MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
 	if (!idetape_chrdev_present)
 		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
 			idetape_chrdevs[minor].drive = NULL;
 
+	if ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+		ide_register_module(&idetape_module);
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return 0;
+	}
 	if (!idetape_chrdev_present &&
-	    register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+	    register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
 		printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
-		return;
-	}
-
-	if (!idetape_identify_device (drive, drive->id)) {
-		printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
-		return;
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return -EBUSY;
 	}
-	if (drive->scsi) {
-		if (strstr(drive->id->model, "OnStream DI-")) {
-			printk(KERN_INFO "ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
-		} else {
-			printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
-			return;
+	do {
+		if (!idetape_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
 		}
-	}
-	tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
-	if (!tape) {
-		printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
-		return;
-	}
-	if (ata_register_device(drive, &idetape_driver)) {
-		printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (tape);
-		return;
-	}
-	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-	idetape_setup (drive, tape, minor);
-	idetape_chrdevs[minor].drive = drive;
-	tape->de_r =
-		devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
-				drive->channel->major, minor,
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				&idetape_fops, NULL);
-	tape->de_n =
-		devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
-				drive->channel->major, minor + 128,
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				&idetape_fops, NULL);
-	devfs_register_tape (tape->de_r);
-	supported++;
-
+		if (drive->scsi) {
+			if (strstr(drive->id->model, "OnStream DI-30")) {
+				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+			} else {
+				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				continue;
+			}
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree(tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup(drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		tape->de_r =
+		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		tape->de_n =
+		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor + 128,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		devfs_register_tape(tape->de_r);
+		supported++;
+		failed--;
+	} while ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
 	if (!idetape_chrdev_present && !supported) {
-		unregister_chrdev (IDETAPE_MAJOR, "ht");
+		devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
+	ide_register_module(&idetape_module);
+	MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+
+	return 0;
+#else
+	return 1;
+#endif
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
 MODULE_LICENSE("GPL");
 
-static void __exit idetape_exit(void)
+static void __exit idetape_exit (void)
 {
-	unregister_ata_driver(&idetape_driver);
+	ide_drive_t *drive;
+	int minor;
+
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
+		drive = idetape_chrdevs[minor].drive;
+		if (drive != NULL && idetape_cleanup (drive))
+		printk(KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+	}
+	ide_unregister_module(&idetape_module);
 }
 
-int __init idetape_init(void)
+/*
+ *	idetape_init will register the driver for each tape.
+ */
+int idetape_init (void)
 {
-	return ata_driver_module(&idetape_driver);
+	ide_drive_t *drive;
+	idetape_tape_t *tape;
+	int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+	MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
+	if (!idetape_chrdev_present)
+		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+			idetape_chrdevs[minor].drive = NULL;
+
+	if ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+		ide_register_module(&idetape_module);
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return 0;
+	}
+	if (!idetape_chrdev_present &&
+	    register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return -EBUSY;
+	}
+	do {
+		if (!idetape_identify_device (drive, drive->id)) {
+			printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			if (strstr(drive->id->model, "OnStream DI-")) {
+				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+			} else {
+				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				continue;
+			}
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree(tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup(drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		tape->de_r =
+		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		tape->de_n =
+		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor + 128,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		devfs_register_tape(tape->de_r);
+		supported++;
+		failed--;
+	} while ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+	if (!idetape_chrdev_present && !supported) {
+		unregister_chrdev(IDETAPE_MAJOR, "ht");
+	} else
+		idetape_chrdev_present = 1;
+	ide_register_module(&idetape_module);
+	MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+	return 0;
 }
 
 module_init(idetape_init);
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/ide/ide-taskfile.c	Tue Aug 27 12:28:08 2002
@@ -1,10 +1,29 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ * linux/drivers/ide/ide-taskfile.c	Version 0.33	April 11, 2002
+ *
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002	Klaus Smolin
+ *					IBM Storage Technology Division
+ *
+ *  The big the bad and the ugly.
  *
- *  Copyright (C) 2002		Marcin Dalecki <martin@dalecki.de>
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *  Problems to be fixed because of BH interface or the lack therefore.
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -20,7 +39,6 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
-#include <linux/completion.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -33,201 +51,2734 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
+#define DEBUG_TASKFILE	0	/* unset when fixed */
+
+#if DEBUG_TASKFILE
+#define DTF(x...) printk(x)
+#else
+#define DTF(x...)
+#endif
+
+#define task_map_rq(rq, flags)		ide_map_buffer((rq), (flags))
+#define task_unmap_rq(rq, buf, flags)	ide_unmap_buffer((buf), (flags))
+
+inline u32 task_read_24 (ide_drive_t *drive)
+{
+	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+	u16 *p = buffer;
+
+	while (wcount--) {
+		*p = *p << 8 | *p >> 8; p++;
+		*p = *p << 8 | *p >> 8; p++;
+	}
+}
+
+#if SUPPORT_VLB_SYNC
 /*
- * Data transfer functions for polled IO.
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
  */
-static void ata_read_32(struct ata_device *drive, void *buffer, unsigned int wcount)
+static inline void task_vlb_sync (ide_ioreg_t port)
 {
-	insl(IDE_DATA_REG, buffer, wcount);
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
 }
+#endif /* SUPPORT_VLB_SYNC */
 
-static void ata_write_32(struct ata_device *drive, void *buffer, unsigned int wcount)
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
-	outsl(IDE_DATA_REG, buffer, wcount);
+	byte io_32bit;
+
+	/*
+	 * first check if this controller has defined a special function
+	 * for handling polled ide transfers
+	 */
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			task_vlb_sync(IDE_NSECTOR_REG);
+			insl(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			insl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				*ptr++ = inw_p(IDE_DATA_REG);
+				*ptr++ = inw_p(IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			insw(IDE_DATA_REG, buffer, wcount<<1);
+	}
 }
 
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit;
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			task_vlb_sync(IDE_NSECTOR_REG);
+			outsl(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			outsl(IDE_DATA_REG, buffer, wcount);
+	} else {
 #if SUPPORT_SLOW_DATA_PORTS
-static void ata_read_slow(struct ata_device *drive, void *buffer, unsigned int wcount)
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				outw_p(*ptr++, IDE_DATA_REG);
+				outw_p(*ptr++, IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			outsw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
-	unsigned short *ptr = (unsigned short *) buffer;
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+		return;
+	}
 
-	while (wcount--) {
-		*ptr++ = inw_p(IDE_DATA_REG);
-		*ptr++ = inw_p(IDE_DATA_REG);
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
 	}
+#endif /* CONFIG_ATARI */
+	ata_input_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
 }
 
-static void ata_write_slow(struct ata_device *drive, void *buffer, unsigned int wcount)
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
-	unsigned short *ptr = (unsigned short *) buffer;
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+		return;
+	}
 
-	while (wcount--) {
-		outw_p(*ptr++, IDE_DATA_REG);
-		outw_p(*ptr++, IDE_DATA_REG);
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
 	}
+#endif /* CONFIG_ATARI */
+	ata_output_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
 }
-#endif
 
-static void ata_read_16(struct ata_device *drive, void *buffer, unsigned int wcount)
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
-	insw(IDE_DATA_REG, buffer, wcount<<1);
+	ata_input_data(drive, buffer, wcount);
+	if (drive->bswap)
+		ata_bswap_data(buffer, wcount);
 }
 
-static void ata_write_16(struct ata_device *drive, void *buffer, unsigned int wcount)
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
-	outsw(IDE_DATA_REG, buffer, wcount<<1);
+	if (drive->bswap) {
+		ata_bswap_data(buffer, wcount);
+		ata_output_data(drive, buffer, wcount);
+		ata_bswap_data(buffer, wcount);
+	} else {
+		ata_output_data(drive, buffer, wcount);
+	}
 }
 
 /*
- * This is used for most PIO data transfers *from* the device.
+ * Needed for PCI irq sharing
  */
-void ata_read(struct ata_device *drive, void *buffer, unsigned int wcount)
+int drive_is_ready (ide_drive_t *drive)
 {
-	int io_32bit;
+	byte stat = 0;
+	if (drive->waiting_for_dma)
+		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
 
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
 	/*
-	 * First check if this controller has defined a special function
-	 * for handling polled ide transfers.
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
 	 */
-	if (drive->channel->ata_read) {
-		drive->channel->ata_read(drive, buffer, wcount);
-		return;
+	if (IDE_CONTROL_REG)
+		stat = GET_ALTSTAT();
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
+
+	if (stat & BUSY_STAT)
+		return 0;	/* drive busy:  definitely not interrupting */
+	return 1;		/* drive ready: *might* be interrupting */
+}
+
+/*
+ * Global for All, and taken from ide-pmac.c
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+	byte stat = 0;
+
+	while(--timeout) {
+		stat = GET_STAT();
+		if(!(stat & BUSY_STAT)) {
+			if (drive->ready_stat == 0)
+				break;
+			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
+				break;
+		}
+		mdelay(1);
+	}
+	if((stat & ERR_STAT) || timeout <= 0) {
+		if (stat & ERR_STAT) {
+			printk(KERN_ERR "%s: wait_for_ready, error status: %x\n", drive->name, stat);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error() -- caller should just return.
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until timeout is achieved, before timing out.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
+{
+	byte stat;
+	int i;
+	unsigned long flags;
+ 
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		*startstop = ide_stopped;
+		return 1;
 	}
 
-	io_32bit = drive->channel->io_32bit;
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = GET_STAT()) & BUSY_STAT) {
+		local_irq_set(flags);
+		timeout += jiffies;
+		while ((stat = GET_STAT()) & BUSY_STAT) {
+			if (time_after(jiffies, timeout)) {
+				local_irq_restore(flags);
+				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
+				return 1;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = GET_STAT()), good, bad))
+			return 0;
+	}
+	*startstop = DRIVER(drive)->error(drive, "status error", stat);
+	return 1;
+}
 
-	if (io_32bit) {
-		ata_read_32(drive, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->channel->slow)
-			ata_read_slow(drive, buffer, wcount);
-		else
+void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
+{
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		if (task->prehandler != NULL)
+			return task->prehandler(drive, task->rq);
+		return ide_started;
+	}
+#if 0
+	switch(task->data_phase) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			HWIF(drive)->dmaproc(ide_dma_write, drive);
+			break;
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			HWIF(drive)->dmaproc(ide_dma_read, drive);
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		default:
+			if (task->handler == NULL)
+				return ide_stopped;
+			ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
+			/* Issue the command */
+			OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+#else
+	//	if ((rq->cmd == WRITE) && (drive->using_dma))
+	/* for dma commands we down set the handler */
+	if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+#endif
+	return ide_started;
+}
+
+#if 0
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
+
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif  /* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = task_read_24(drive);
+					OUT_BYTE(0x80, IDE_CONTROL_REG);
+					high = task_read_24(drive);
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld", sectors);
+				} else {
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						  (IN_BYTE(IDE_HCYL_REG)<<8) +
+						   IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive)->rq)
+					printk(", sector=%lu", (__u64) HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif  /* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return err;
+}
 #endif
-			ata_read_16(drive, buffer, wcount);
+
+/*
+ * Clean up after success/failure of an explicit taskfile operation.
+ */
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+{
+	unsigned long flags;
+	struct request *rq;
+	ide_task_t *args;
+	task_ioreg_t command;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	args = (ide_task_t *) rq->special;
+
+	command = args->tfRegister[IDE_COMMAND_OFFSET];
+
+	if (rq->errors == 0)
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+	if (args->tf_in_flags.b.data) {
+		unsigned short data = IN_WORD(IDE_DATA_REG);
+		args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
+		args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+	}
+	args->tfRegister[IDE_ERROR_OFFSET]   = err;
+	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+	if ((drive->id->command_set_2 & 0x0400) &&
+	    (drive->id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
 	}
+
+#if 0
+/*	taskfile_settings_update(drive, args, command); */
+
+	if (args->posthandler != NULL)
+		args->posthandler(drive, args);
+#endif
+
+	spin_lock_irqsave(&ide_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+#if 0
 /*
- * This is used for most PIO data transfers *to* the device interface.
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
  */
-void ata_write(struct ata_device *drive, void *buffer, unsigned int wcount)
+void task_try_to_flush_leftover_data (ide_drive_t *drive)
 {
-	int io_32bit;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
-	if (drive->channel->ata_write) {
-		drive->channel->ata_write(drive, buffer, wcount);
+	if (drive->media != ide_disk)
 		return;
+	while (i > 0) {
+		u32 buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		taskfile_input_data (drive, buffer, wcount);
 	}
+}
 
-	io_32bit = drive->channel->io_32bit;
+/*
+ * taskfile_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
 
-	if (io_32bit) {
-		ata_write_32(drive, buffer, wcount);
+        err = taskfile_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
 	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->channel->slow)
-			ata_write_slow(drive, buffer, wcount);
-		else
+		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			else if (err & TRK0_ERR)	/* help it find track zero */
+                                rq->errors |= ERROR_RECAL;
+                }
+                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+                        task_try_to_flush_leftover_data(drive);
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
+
+	if (rq->errors >= ERROR_MAX) {
+			DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
 #endif
-			ata_write_16(drive, buffer, wcount);
+
+/*
+ * Handler for special commands without a data phase from ide-disk
+ */
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+		drive->mult_count = drive->mult_req;
+	} else {
+		drive->mult_req = drive->mult_count = 0;
+		drive->special.b.recalibrate = 1;
+		(void) ide_dump_status(drive, "set_multmode", stat);
 	}
+	return ide_stopped;
 }
 
 /*
- * Invoked on completion of a special REQ_SPECIAL command.
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
-static ide_startstop_t special_intr(struct ata_device *drive, struct request *rq) {
-	unsigned long flags;
-	struct ata_channel *ch =drive->channel;
-	struct ata_taskfile *ar = rq->special;
-	ide_startstop_t ret = ATA_OP_FINISHED;
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+	int retries = 5;
+	byte stat;
+
+	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+		udelay(10);
+
+	if (OK_STAT(stat, READY_STAT,BAD_STAT))
+		return ide_stopped;
+
+	if (stat & (ERR_STAT|DRQ_STAT))
+		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+	byte stat = GET_STAT();
+
+	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+		return DRIVER(drive)->error(drive, "recal_intr", stat);
+	return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	byte stat		= GET_STAT();
 
 	local_irq_enable();
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+		DTF("%s: command opcode 0x%02x\n", drive->name,
+			args->tfRegister[IDE_COMMAND_OFFSET]);
+		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	}
+	if (args)
+		ide_end_drive_cmd (drive, stat, GET_ERR());
 
-	if (rq->buffer && ar->taskfile.sector_number) {
-		if (!ata_status(drive, 0, DRQ_STAT) && ar->taskfile.sector_number) {
-			int retries = 10;
+	return ide_stopped;
+}
 
-			ata_read(drive, rq->buffer, ar->taskfile.sector_number * SECTOR_WORDS);
+/*
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.4 enable ...
+ *	DATA integrity issue upon error. <andre@linux-ide.org>
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
 
-			while (!ata_status(drive, 0, BUSY_STAT) && retries--)
-				udelay(100);
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+#if 0
+			DTF("%s: attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+			/*
+			 * Expect a BUG BOMB if we attempt to rewind the
+			 * offset in the BH aka PAGE in the current BLOCK
+			 * segment.  This is different than the HOST segment.
+			 */
+#endif
+			if (!rq->bio)
+				rq->current_nr_sectors++;
+			return DRIVER(drive)->error(drive, "task_in_intr", stat);
+		}
+		if (!(stat & BUSY_STAT)) {
+			DTF("task_in_intr to Soon wait for next interrupt\n");
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			return ide_started;  
 		}
 	}
+#if 0
 
-	if (!ata_status(drive, READY_STAT, BAD_STAT)) {
-		/* Keep quiet for NOP because it is expected to fail. */
-		if (ar->cmd != WIN_NOP)
-			ret = ata_error(drive, rq, __FUNCTION__);
-		rq->errors = 1;
+	/*
+	 * Holding point for a brain dump of a thought :-/
+	 */
+
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: READ attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_in_intr", stat);
+        }
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+#endif
+
+	pBuf = task_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	task_unmap_rq(rq, pBuf, &flags);
+	/*
+	 * FIXME :: We really can not legally get a new page/bh
+	 * regardless, if this is the end of our segment.
+	 * BH walking or segment can only be updated after we have a good
+	 * GET_STAT(); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+	/*
+	 * ERM, it is techincally legal to leave/exit here but it makes
+	 * a mess of the code ...
+	 */
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+	return ide_started;
+}
+
+#undef ALTSTAT_SCREW_UP
+
+#ifdef ALTSTAT_SCREW_UP
+/*
+ * (ks/hs): Poll Alternate Status Register to ensure
+ * that drive is not busy.
+ */
+byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
+{
+	int i;
+
+	DTF("multi%s: ASR = %x\n", msg, stat);
+	if (stat & BUSY_STAT) {
+		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
+		for (i=0; i<100; i++) {
+			stat = GET_ALTSTAT();
+			if ((stat & BUSY_STAT) == 0)
+				break;
+		}
 	}
+	/*
+	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 */
+	return(GET_STAT());
+}
 
-	ar->taskfile.feature = IN_BYTE(IDE_ERROR_REG);
-	ata_in_regfile(drive, &ar->taskfile);
-	ar->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
-	if ((drive->id->command_set_2 & 0x0400) &&
-			(drive->id->cfs_enable_2 & 0x0400) &&
-			(drive->addressing == 1)) {
-		/* The following command goes to the hob file! */
-		OUT_BYTE(0x80, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-		ar->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
-		ata_in_regfile(drive, &ar->hobfile);
+/*
+ * (ks/hs): Poll Alternate status register to wait for drive
+ * to become ready for next transfer
+ */
+byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
+{
+
+	/* (ks/hs): FIXME: Error handling, time-out? */
+	while (stat & BUSY_STAT)
+		stat = GET_ALTSTAT();
+	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
+	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
+}
+#endif /* ALTSTAT_SCREW_UP */
+
+/*
+ * Handler for command with Read Multiple
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect	= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bio) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-READ assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
 	}
 
-	spin_lock_irqsave(ch->lock, flags);
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		/*
+		 * (ks/hs): Drive supports multi-sector transfer,
+		 * drive->mult_count was not set
+		 */
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = task_map_rq(rq, &flags);
+			DTF("Multiread: %p, nsect: %d, " \
+				"rq->current_nr_sectors: %ld\n",
+				pBuf, nsect, rq->current_nr_sectors);
+//			rq->current_nr_sectors -= nsect;
+			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+			task_unmap_rq(rq, pBuf, &flags);
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
+		}
+		DRIVER(drive)->end_request(drive, 1);
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
 
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+//		rq->current_nr_sectors -= nsect;
+//		msect -= nsect;
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		/*
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we have a
+		 * good GET_STAT(); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
 
-	spin_unlock_irqrestore(ch->lock, flags);
+/*
+ * VERIFY ME before 2.4 ... unexpected race is possible based on details
+ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
+ */
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	char *pBuf		= NULL;
+	unsigned long flags;
+	ide_startstop_t startstop;
 
-	return ret;
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "WRITE_EXT" : "WRITE");
+		return startstop;
+	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = task_map_rq(rq, &flags);
+//	rq->current_nr_sectors--;
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	rq->current_nr_sectors--;
+	/*
+	 * WARNING :: Interrupt could happen instantly :-/
+	 */
+	task_unmap_rq(rq, pBuf, &flags);
+	return ide_started;
 }
 
-int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *ar, char *buf)
+/*
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	struct request *rq;
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
 	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
-	request_queue_t *q = &drive->queue;
-	struct list_head *queue_head = &q->queue_head;
-	DECLARE_COMPLETION(wait);
-	struct request req;
-
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (ch->chipset == ide_pdc4030 && buf)
-		return -ENOSYS;  /* special drive cmds not supported */
+
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: WRITE attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_out_intr", stat);
+	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+		rq = HWGROUP(drive)->rq;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
+//		rq->current_nr_sectors--;
+		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors--;
+	}
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+#if 0
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
 #endif
 
-	memset(&req, 0, sizeof(req));
-	rq = &req;
-	
-	rq->flags = REQ_SPECIAL;
-	rq->buffer = buf;
-	rq->special = ar;
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
+		return startstop;
+	}
+#if 0
+	if (wait_for_ready(drive, 100))
+		IDE_DEBUG(__LINE__);		//BUG();
+#else
+	if (!(drive_is_ready(drive))) {
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+#endif
+	/*
+	 * WARNING :: if the drive as not acked good status we may not
+	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
+	 */
+	return args->handler(drive);
+}
+
+/*
+ * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
+ */
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	struct request *rq		= HWGROUP(drive)->rq;
+	char *pBuf			= NULL;
+	ide_startstop_t startstop	= ide_stopped;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+	if (rq->current_nr_sectors == 0) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bio) {
+                                rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		if (!rq->bio)
+			DRIVER(drive)->end_request(drive, 1);
+		return startstop;
+	}
+	/*
+	 * DON'T be lazy code the above and below togather !!!
+	 */
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bio) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&ide_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&ide_lock, lflags);
+	}
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = task_map_rq(rq, &flags);
+			DTF("Multiwrite: %p, nsect: %d, " \
+				"rq->current_nr_sectors: %d\n",
+				pBuf, nsect, rq->current_nr_sectors);
+//			rq->current_nr_sectors -= nsect;
+			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+			task_unmap_rq(pBuf, &flags);
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+		}
+		DRIVER(drive)->end_request(drive, 1);
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+//		rq->current_nr_sectors -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		/*
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we
+		 * have a good  GET_STAT(); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bio)
+					return ide_stopped;
+		}
+	} while (msect);
 	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->waiting = &wait;
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
 
-	ar->XXX_handler = special_intr;
-	ar->command_type = IDE_DRIVE_TASK_NO_DATA;
+/* Called by internal to feature out type of command being called */
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+				/* IDE_DRIVE_TASK_RAW_WRITE */
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &pre_task_mulout_intr;
+			
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return &pre_task_out_intr;
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_SMART:
+			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
+				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		default:
+			break;
+	}
+	return(NULL);
+}
 
-	spin_lock_irqsave(ch->lock, flags);
+/* Called by internal to feature out type of command being called */
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ_BUFFER:
+		case WIN_READ:
+		case WIN_READ_EXT:
+			return &task_in_intr;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+		case WIN_DOWNLOAD_MICROCODE:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_WRITE_BUFFER:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+			return &task_out_intr;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return &task_mulin_intr;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &task_mulout_intr;
+		case WIN_SMART:
+			switch(taskfile->feature) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return &task_in_intr;
+				case SMART_WRITE_LOG_SECTOR:
+					return &task_out_intr;
+				default:
+					return &task_no_data_intr;
+			}
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+			return &task_no_data_intr;
+		case WIN_SPECIFY:
+			return &set_geometry_intr;
+		case WIN_RECAL:
+	//	case WIN_RESTORE:
+			return &recal_intr;
+		case WIN_NOP:
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+			return &task_no_data_intr;
+		case WIN_SETMULT:
+			return &set_multmode_intr;
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+		case WIN_SETFEATURES:
+			return &task_no_data_intr;
+		case DISABLE_SEAGATE:
+		case EXABYTE_ENABLE_NEST:
+			return &task_no_data_intr;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+#endif
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return(NULL);
+	}	
+}
 
-	if (!blk_queue_empty(&drive->queue))
-		queue_head = queue_head->prev;
-	__elv_add_request(q, rq, queue_head);
+ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_SPECIFY:	/* set_geometry_intr */
+		case WIN_RESTORE:	/* recal_intr */
+		case WIN_SETMULT:	/* set_multmode_intr */
+		default:
+			return(NULL);
+	}
+}
+
+/* Called by ioctl to feature out type of command being called */
+int ide_cmd_type_parser (ide_task_t *args)
+{
+	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
+	args->handler		= ide_handler_parser(taskfile, hobfile);
+	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
+
+	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ:
+		case WIN_READ_EXT:
+		case WIN_READ_BUFFER:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+			return IDE_DRIVE_TASK_OUT;
+		case WIN_SMART:
+			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return IDE_DRIVE_TASK_IN;
+				case SMART_WRITE_LOG_SECTOR:
+					return IDE_DRIVE_TASK_OUT;
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+#endif
+		case WIN_SETFEATURES:
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_EN_8BIT:
+				case SETFEATURES_EN_WCACHE:
+					return IDE_DRIVE_TASK_NO_DATA;
+				case SETFEATURES_XFER:
+					return IDE_DRIVE_TASK_SET_XFER;
+				case SETFEATURES_DIS_DEFECT:
+				case SETFEATURES_EN_APM:
+				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_DIS_RETRY:
+				case SETFEATURES_EN_AAM:
+				case SETFEATURES_RW_LONG:
+				case SETFEATURES_SET_CACHE:
+				case SETFEATURES_DIS_RLA:
+				case SETFEATURES_EN_RI:
+				case SETFEATURES_EN_SI:
+				case SETFEATURES_DIS_RPOD:
+				case SETFEATURES_DIS_WCACHE:
+				case SETFEATURES_EN_DEFECT:
+				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_ECC:
+				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RETRY:
+				case SETFEATURES_EN_RLA:
+				case SETFEATURES_PREFETCH:
+				case SETFEATURES_4B_RW_LONG:
+				case SETFEATURES_DIS_AAM:
+				case SETFEATURES_EN_RPOD:
+				case SETFEATURES_DIS_RI:
+				case SETFEATURES_DIS_SI:
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+		case WIN_NOP:
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+		case WIN_SPECIFY:
+		case WIN_RESTORE:
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case DISABLE_SEAGATE:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+		case WIN_SETMULT:
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case EXABYTE_ENABLE_NEST:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+			return IDE_DRIVE_TASK_NO_DATA;
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return IDE_DRIVE_TASK_INVALID;
+	}
+}
+
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations.  Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+#if DEBUG_TASKFILE
+	byte status;
+#endif
 
-	q->request_fn(q);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	wait_for_completion(&wait);	/* wait for it to be serviced */
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+	/*
+	 * (ks) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
+		}
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+		}
+        }
+
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+#if DEBUG_TASKFILE
+	status = GET_STAT();
+	if (status & 0x80) {
+		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+		udelay(100);
+		status = GET_STAT();
+		printk("flagged_taskfile -> Status = %02x\n", status);
+	}
+#endif
+
+	if (task->tf_out_flags.b.data) {
+		unsigned short data =  taskfile->data + (hobfile->data << 8);
+		OUT_WORD(data, IDE_DATA_REG);
+	}
+
+	/* (ks) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+
+	/* (ks) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (ks) In the flagged taskfile approch, we will used all specified
+	 * registers and the register value will not be changed. Except the
+	 * select bit (master/slave) in the drive_head register. We must make
+	 * sure that the desired drive is selected.
+	 */
+	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	switch(task->data_phase) {
+
+   	        case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			HWIF(drive)->dmaproc(ide_dma_write, drive);
+			break;
+
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			HWIF(drive)->dmaproc(ide_dma_read, drive);
+			break;
+
+	        default:
+ 			if (task->handler == NULL)
+				return ide_stopped;
+
+			ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
+			/* Issue the command */
+			OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
+{
+	byte stat = GET_STAT();
+
+	local_irq_enable();
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+ 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
+	}
+
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
+
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
+
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+
+	if (--rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
+	}
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+	unsigned int msect, nsect;
+
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
+
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
+
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
+	}
+
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+/*
+ * Pre handler for command with PIO data-out phase
+ */
+ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	byte stat		= GET_STAT();
+	ide_startstop_t startstop;
+
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
+	}
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
+
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, GET_ERR());
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
+		(int) rq->current_nr_sectors, stat);
+
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	--rq->current_nr_sectors;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	byte stat		= GET_STAT();
+	char *pBuf		= NULL;
+	ide_startstop_t startstop;
+	unsigned int msect, nsect;
+
+	if (!rq->current_nr_sectors) 
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect, nsect;
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, GET_ERR());
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	rq->current_nr_sectors -= nsect;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_taskfile (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->flags = REQ_DRIVE_TASKFILE;
+}
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, byte *buf)
+{
+	struct request rq;
+
+	ide_init_drive_taskfile(&rq);
+	rq.flags = REQ_DRIVE_TASKFILE;
+	rq.buffer = buf;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0)
+			rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		/*	rq.hard_cur_sectors	*/
+		else
+			rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
+		/*	rq.hard_cur_sectors	*/
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+
+	}
+	rq.special = args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+{
+	return ide_diag_taskfile(drive, args, 0, buf);
+}
+	
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+char * ide_ioctl_verbose (unsigned int cmd)
+{
+	return("unknown");
+}
+
+char * ide_task_cmd_verbose (byte task)
+{
+	return("unknown");
 }
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+#define MAX_DMA		(256*SECTOR_WORDS)
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	ide_task_request_t	*req_task;
+	ide_task_t		args;
+	byte *outbuf		= NULL;
+	byte *inbuf		= NULL;
+	task_ioreg_t *argsptr	= args.tfRegister;
+	task_ioreg_t *hobsptr	= args.hobRegister;
+	int err			= 0;
+	int tasksize		= sizeof(struct ide_task_request_s);
+	int taskin		= 0;
+	int taskout		= 0;
+	byte io_32bit		= drive->io_32bit;
+
+//	printk("IDE Taskfile ...\n");
+
+	req_task = kmalloc(tasksize, GFP_KERNEL);
+	if (req_task == NULL) return -ENOMEM;
+	memset(req_task, 0, tasksize);
+	if (copy_from_user(req_task, (void *) arg, tasksize)) {
+		kfree(req_task);
+		return -EFAULT;
+	}
+
+	taskout = (int) req_task->out_size;
+	taskin  = (int) req_task->in_size;
+
+	if (taskout) {
+		int outtotal = tasksize;
+		outbuf = kmalloc(taskout, GFP_KERNEL);
+		if (outbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(outbuf, 0, taskout);
+		if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		inbuf = kmalloc(taskin, GFP_KERNEL);
+		if (inbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(inbuf, 0, taskin);
+		if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	memset (&args, 0, sizeof (ide_task_t) );
+	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+	args.tf_in_flags  = req_task->in_flags;
+	args.tf_out_flags = req_task->out_flags;
+	args.data_phase   = req_task->data_phase;
+	args.command_type = req_task->req_cmd;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
+		drive->name,
+		ide_ioctl_verbose(cmd),
+		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	drive->io_32bit = 0;
+	switch(req_task->data_phase) {
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+			break;
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+			break;
+		case TASKFILE_IN_OUT:
+#if 0
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+			break;
+#else
+			err = -EFAULT;
+			goto abort;
+#endif
+		case TASKFILE_MULTI_OUT:
+			if (!drive->mult_count) {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Write " \
+					"multcount is not set\n",
+					drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_mulout_intr;
+				args.handler = &flagged_task_mulout_intr;
+			} else {
+				args.prehandler = &pre_task_mulout_intr;
+				args.handler = &task_mulout_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+			break;
+		case TASKFILE_OUT:
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_out_intr;
+				args.handler    = &flagged_task_out_intr;
+			} else {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_out_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+			break;
+		case TASKFILE_MULTI_IN:
+			if (!drive->mult_count) {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Read failure " \
+					"multcount is not set\n",
+					drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_mulin_intr;
+			} else {
+				args.handler = &task_mulin_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+			break;
+		case TASKFILE_IN:
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_in_intr;
+			} else {
+				args.handler = &task_in_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+			break;
+		case TASKFILE_NO_DATA:
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_no_data_intr;
+			} else {
+				args.handler = &task_no_data_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, 0, NULL);
+			break;
+		default:
+			err = -EFAULT;
+			goto abort;
+	}
+
+	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+	req_task->in_flags  = args.tf_in_flags;
+	req_task->out_flags = args.tf_out_flags;
+
+	if (copy_to_user((void *)arg, req_task, tasksize)) {
+		err = -EFAULT;
+		goto abort;
+	}
+	if (taskout) {
+		int outtotal = tasksize;
+		if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+abort:
+	kfree(req_task);
+	if (outbuf != NULL)
+		kfree(outbuf);
+	if (inbuf != NULL)
+		kfree(inbuf);
+
+//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+	drive->io_32bit = io_32bit;
+
+	return err;
+}
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
+int set_transfer(ide_drive_t *drive, ide_task_t *args);
 
-EXPORT_SYMBOL(ata_read);
-EXPORT_SYMBOL(ata_write);
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 1
+	int err = 0;
+	byte args[4], *argbuf = args;
+	byte xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+
+#else
+
+	int err = 0;
+	byte args[4], *argbuf = args;
+	byte xfer_rate = 0;
+	int argsize = 0;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+	}
+
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	tfargs.command_type = ide_cmd_type_parser(&tfargs);
+	err = ide_raw_taskfile(drive, &tfargs, argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+
+	args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
+	args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
+	args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
+	args[3] = 0;
+
+	if (copy_to_user((void *)arg, argbuf, 4))
+		err = -EFAULT;
+	if (argbuf != NULL) {
+		if (copy_to_user((void *)arg, argbuf + 4, argsize))
+			err = -EFAULT;
+		kfree(argbuf);
+	}
+	return err;
+
+#endif
+
+}
+
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	byte args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+EXPORT_SYMBOL(wait_for_ready);
+
+EXPORT_SYMBOL(task_read_24);
+EXPORT_SYMBOL(ata_input_data);
+EXPORT_SYMBOL(ata_output_data);
+EXPORT_SYMBOL(atapi_input_bytes);
+EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(taskfile_input_data);
+EXPORT_SYMBOL(taskfile_output_data);
+
+EXPORT_SYMBOL(ide_wait_stat);
+EXPORT_SYMBOL(do_rw_taskfile);
+EXPORT_SYMBOL(flagged_taskfile);
+EXPORT_SYMBOL(ide_end_taskfile);
+
+EXPORT_SYMBOL(set_multmode_intr);
+EXPORT_SYMBOL(set_geometry_intr);
+EXPORT_SYMBOL(recal_intr);
+
+EXPORT_SYMBOL(task_no_data_intr);
+EXPORT_SYMBOL(task_in_intr);
+EXPORT_SYMBOL(task_mulin_intr);
+EXPORT_SYMBOL(pre_task_out_intr);
+EXPORT_SYMBOL(task_out_intr);
+EXPORT_SYMBOL(pre_task_mulout_intr);
+EXPORT_SYMBOL(task_mulout_intr);
+
+EXPORT_SYMBOL(ide_init_drive_taskfile);
 EXPORT_SYMBOL(ide_raw_taskfile);
+EXPORT_SYMBOL(ide_pre_handler_parser);
+EXPORT_SYMBOL(ide_handler_parser);
+EXPORT_SYMBOL(ide_post_handler_parser);
+EXPORT_SYMBOL(ide_cmd_type_parser);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+EXPORT_SYMBOL(ide_cmd_ioctl);
+EXPORT_SYMBOL(ide_task_ioctl);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+
+/*
+ *  All hosts that use the 80c ribbon must use!
+ *  The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+byte eighty_ninty_three (ide_drive_t *drive)
+{
+#if 0
+	if (!HWIF(drive)->udma_four)
+		return 0;
+
+	if (drive->id->major_rev_num) {
+		int hssbd = 0;
+		int i;
+		/*
+		 * Determime highest Supported SPEC
+		 */
+		for (i=1; i<=15; i++)
+			if (drive->id->major_rev_num & (1<<i))
+				hssbd++;
+
+		switch (hssbd) {
+			case 7:
+
+			case 6:
+			case 5:
+		/* ATA-4 and older do not support above Ultra 33 */
+			default:
+				return 0;
+		}
+	}
+
+	return ((byte) (
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+	return ((byte) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+			(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+			(drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+	if (!HWIF(drive)->udma_four) {
+		printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n",
+			HWIF(drive)->name);
+		return 1;
+	}
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+		if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+		if (((drive->id->hw_config & 0x2000) == 0) ||
+		    ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	    (drive->id->dma_ultra ||
+	     drive->id->dma_mword ||
+	     drive->id->dma_1word))
+		return 1;
+
+	return 0;
+}
+
+byte ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+	if (!drive->crc_count)
+		return drive->current_speed;
+	drive->crc_count = 0;
+
+	switch(drive->current_speed) {
+		case XFER_UDMA_7:	return XFER_UDMA_6;
+		case XFER_UDMA_6:	return XFER_UDMA_5;
+		case XFER_UDMA_5:	return XFER_UDMA_4;
+		case XFER_UDMA_4:	return XFER_UDMA_3;
+		case XFER_UDMA_3:	return XFER_UDMA_2;
+		case XFER_UDMA_2:	return XFER_UDMA_1;
+		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
+		case XFER_UDMA_0:
+		default:		return XFER_PIO_4;
+	}
+}
+
+int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf)
+{
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	if (drive->media == ide_disk)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, buf);
+}
+
+/*
+ * Update the 
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+#if 0
+	struct hd_driveid *id;
+
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id)
+		return 0;
+
+	taskfile_lib_get_identify(drive, (char *)&id);
+
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+	return 1;
+#else
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	struct hd_driveid *id;
+	unsigned long timeout, flags;
+
+	SELECT_MASK(HWIF(drive), drive, 1);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			SELECT_MASK(HWIF(drive), drive, 0);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+		SELECT_MASK(HWIF(drive), drive, 0);
+		printk("%s: CHECK for good STATUS\n", drive->name);
+		return 0;
+	}
+	local_irq_save(flags);
+	SELECT_MASK(HWIF(drive), drive, 0);
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id) {
+		local_irq_restore(flags);
+		return 0;
+	}
+	ata_input_data(drive, id, SECTOR_WORDS);
+	(void) GET_STAT();	/* clear drive IRQ */
+	local_irq_enable();
+	local_irq_restore(flags);
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+
+	return 1;
+#endif
+}
+
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	int	i, error	= 1;
+	byte stat;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	hwif->dmaproc(ide_dma_host_off, drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_MASK(HWIF(drive), drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+	OUT_BYTE(speed, IDE_NSECTOR_REG);
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = GET_STAT()) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		local_irq_set(flags);
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = GET_STAT()) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (speed >= XFER_SW_DMA_0)
+		hwif->dmaproc(ide_dma_host_on, drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+	return error;
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
+EXPORT_SYMBOL(set_transfer);
+EXPORT_SYMBOL(taskfile_lib_get_identify);
+EXPORT_SYMBOL(ide_driveid_update);
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+
+#if 0
+{
+
+{ /* start cdrom */
+
+	struct cdrom_info *info = drive->driver_data;
+
+	if (info->dma) {
+		if (info->cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (info->cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
+			printk("ide-cd: DMA set, but not allowed\n");
+		}
+	}
+
+	/* Set up the controller registers. */
+	OUT_BYTE (info->dma, IDE_FEATURE_REG);
+	OUT_BYTE (0, IDE_NSECTOR_REG);
+	OUT_BYTE (0, IDE_SECTOR_REG);
+
+	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+
+	if (info->dma)
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
+	} else {
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return (*handler) (drive);
+	}
+
+} /* end cdrom */
+
+{ /* start floppy */
+
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	idefloppy_bcount_reg_t bcount;
+	int dma_ok = 0;
+
+	floppy->pc=pc;		/* Set the current packet command */
+
+	pc->retries++;
+	pc->actually_transferred=0; /* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+} /* end floppy */
+
+{ /* start tape */
+
+	idetape_tape_t *tape = drive->driver_data;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
+	} else {
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idetape_transfer_pc(drive);
+	}
+
+} /* end tape */
+
+}
+#endif
+
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+	switch(req_task->data_phase) {
+		case TASKFILE_P_OUT_DMAQ:
+		case TASKFILE_P_IN_DMAQ:
+		case TASKFILE_P_OUT_DMA:
+		case TASKFILE_P_IN_DMA:
+		case TASKFILE_P_OUT:
+		case TASKFILE_P_IN:
+	}
+#endif
+	return -ENOMSG;
+}
+
+EXPORT_SYMBOL(pkt_taskfile_ioctl);
+
+#endif /* CONFIG_PKT_TASK_IOCTL */
diff -Nru a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-timing.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,281 @@
+#ifndef _IDE_TIMING_H
+#define _IDE_TIMING_H
+
+/*
+ * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/hdreg.h>
+
+#define XFER_PIO_5		0x0d
+#define XFER_UDMA_SLOW		0x4f
+
+struct ide_timing {
+	short mode;
+	short setup;	/* t1 */
+	short act8b;	/* t2 for 8-bit io */
+	short rec8b;	/* t2i for 8-bit io */
+	short cyc8b;	/* t0 for 8-bit io */
+	short active;	/* t2 or tD */
+	short recover;	/* t2i or tK */
+	short cycle;	/* t0 */
+	short udma;	/* t2CYCTYP/2 */
+};
+
+/*
+ * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+ * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+ * for PIO 5, which is a nonstandard extension and UDMA6, which
+ * is currently supported only by Maxtor drives. 
+ */
+
+static struct ide_timing ide_timing[] = {
+
+	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
+	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
+	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
+	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+
+	{ XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
+	{ XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
+	{ XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
+
+	{ XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0,   0, 150 },
+                                          
+	{ XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
+	{ XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
+	{ XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
+                                          
+	{ XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
+	{ XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
+	{ XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
+
+	{ XFER_PIO_5,     20,  50,  30, 100,  50,  30, 100,   0 },
+	{ XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
+	{ XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
+
+	{ XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
+	{ XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
+	{ XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
+
+	{ XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 },
+
+	{ -1 }
+};
+
+#define IDE_TIMING_SETUP	0x01
+#define IDE_TIMING_ACT8B	0x02
+#define IDE_TIMING_REC8B	0x04
+#define IDE_TIMING_CYC8B	0x08
+#define IDE_TIMING_8BIT		0x0e
+#define IDE_TIMING_ACTIVE	0x10
+#define IDE_TIMING_RECOVER	0x20
+#define IDE_TIMING_CYCLE	0x40
+#define IDE_TIMING_UDMA		0x80
+#define IDE_TIMING_ALL		0xff
+
+#define MIN(a,b)	((a)<(b)?(a):(b))
+#define MAX(a,b)	((a)>(b)?(a):(b))
+#define FIT(v,min,max)	MAX(MIN(v,max),min)
+#define ENOUGH(v,unit)	(((v)-1)/(unit)+1)
+#define EZ(v,unit)	((v)?ENOUGH(v,unit):0)
+
+#define XFER_MODE	0xf0
+#define XFER_UDMA_133	0x48
+#define XFER_UDMA_100	0x44
+#define XFER_UDMA_66	0x42
+#define XFER_UDMA	0x40
+#define XFER_MWDMA	0x20
+#define XFER_SWDMA	0x10
+#define XFER_EPIO	0x01
+#define XFER_PIO	0x00
+
+static short ide_find_best_mode(ide_drive_t *drive, int map)
+{
+	struct hd_driveid *id = drive->id;
+	short best = 0;
+
+	if (!id)
+		return XFER_PIO_SLOW;
+
+	if ((map & XFER_UDMA) && (id->field_valid & 4)) {	/* Want UDMA and UDMA bitmap valid */
+
+		if ((map & XFER_UDMA_133) == XFER_UDMA_133)
+			if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
+
+		if ((map & XFER_UDMA_100) == XFER_UDMA_100)
+			if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
+
+		if ((map & XFER_UDMA_66) == XFER_UDMA_66)
+			if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 :
+                	    	    (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
+
+                if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
+                	    (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
+                	    (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best;
+	}
+
+	if ((map & XFER_MWDMA) && (id->field_valid & 2)) {	/* Want MWDMA and drive has EIDE fields */
+
+		if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 :
+                	    (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 :
+                	    (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best;
+	}
+
+	if (map & XFER_SWDMA) {					/* Want SWDMA */
+
+ 		if (id->field_valid & 2) {			/* EIDE SWDMA */
+
+			if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 :
+      				    (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 :
+				    (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best;
+		}
+
+		if (id->capability & 1) {			/* Pre-EIDE style SWDMA */
+
+			if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 :
+				    (id->tDMA == 1) ? XFER_SW_DMA_1 :
+				    (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best;
+		}
+	}
+
+
+	if ((map & XFER_EPIO) && (id->field_valid & 2)) {	/* EIDE PIO modes */
+
+		if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
+			    (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
+			    (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
+	}
+	
+	return  (drive->id->tPIO == 2) ? XFER_PIO_2 :
+		(drive->id->tPIO == 1) ? XFER_PIO_1 :
+		(drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
+}
+
+static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
+{
+	q->setup   = EZ(t->setup   * 1000,  T);
+	q->act8b   = EZ(t->act8b   * 1000,  T);
+	q->rec8b   = EZ(t->rec8b   * 1000,  T);
+	q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
+	q->active  = EZ(t->active  * 1000,  T);
+	q->recover = EZ(t->recover * 1000,  T);
+	q->cycle   = EZ(t->cycle   * 1000,  T);
+	q->udma    = EZ(t->udma    * 1000, UT);
+}
+
+static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what)
+{
+	if (what & IDE_TIMING_SETUP  ) m->setup   = MAX(a->setup,   b->setup);
+	if (what & IDE_TIMING_ACT8B  ) m->act8b   = MAX(a->act8b,   b->act8b);
+	if (what & IDE_TIMING_REC8B  ) m->rec8b   = MAX(a->rec8b,   b->rec8b);
+	if (what & IDE_TIMING_CYC8B  ) m->cyc8b   = MAX(a->cyc8b,   b->cyc8b);
+	if (what & IDE_TIMING_ACTIVE ) m->active  = MAX(a->active,  b->active);
+	if (what & IDE_TIMING_RECOVER) m->recover = MAX(a->recover, b->recover);
+	if (what & IDE_TIMING_CYCLE  ) m->cycle   = MAX(a->cycle,   b->cycle);
+	if (what & IDE_TIMING_UDMA   ) m->udma    = MAX(a->udma,    b->udma);
+}
+
+static struct ide_timing* ide_timing_find_mode(short speed)
+{
+	struct ide_timing *t;
+
+	for (t = ide_timing; t->mode != speed; t++)
+		if (t->mode < 0)
+			return NULL;
+	return t; 
+}
+
+static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing *t, int T, int UT)
+{
+	struct hd_driveid *id = drive->id;
+	struct ide_timing *s, p;
+
+/*
+ * Find the mode.
+ */
+
+	if (!(s = ide_timing_find_mode(speed)))
+		return -EINVAL;
+
+/*
+ * If the drive is an EIDE drive, it can tell us it needs extended
+ * PIO/MWDMA cycle timing.
+ */
+
+	if (id && id->field_valid & 2) {	/* EIDE drive */
+
+		memset(&p, 0, sizeof(p));
+
+		switch (speed & XFER_MODE) {
+
+			case XFER_PIO:
+				if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio;
+						    else p.cycle = p.cyc8b = id->eide_pio_iordy;
+				break;
+
+			case XFER_MWDMA:
+				p.cycle = id->eide_dma_min;
+				break;
+		}
+
+		ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
+	}
+
+/*
+ * Convert the timing to bus clock counts.
+ */
+
+	ide_timing_quantize(s, t, T, UT);
+
+/*
+ * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
+ * and some other commands. We have to ensure that the DMA cycle timing is
+ * slower/equal than the fastest PIO timing.
+ */
+
+	if ((speed & XFER_MODE) != XFER_PIO) {
+		ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT);
+		ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
+	}
+
+/*
+ * Lenghten active & recovery time so that cycle time is correct.
+ */
+
+	if (t->act8b + t->rec8b < t->cyc8b) {
+		t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
+		t->rec8b = t->cyc8b - t->act8b;
+	}
+
+	if (t->active + t->recover < t->cycle) {
+		t->active += (t->cycle - (t->active + t->recover)) / 2;
+		t->recover = t->cycle - t->active;
+	}
+
+	return 0;
+}
+
+#endif
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/ide.c	Tue Aug 27 12:28:08 2002
@@ -1,19 +1,19 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
+/*
+ *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
  *
- *	Mark Lord	<mlord@pobox.com>
- *      Gadi Oxman	<gadio@netvision.net.il>
- *      Andre Hedrick	<andre@linux-ide.org>
- *	Jens Axboe	<axboe@suse.de>
- *      Marcin Dalecki	<martin@dalecki.de>
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Mostly written by Mark Lord  <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *                and Andre Hedrick <andre@linux-ide.org>
  *
  *  See linux/MAINTAINERS for address of current maintainer.
  *
- * This is the basic common code of the ATA interface drivers.
- *
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14
- * & 15).  There can be up to two drives per interface, as per the ATA-7 spec.
+ * This is the multiple IDE interface driver, as evolved from hd.c.
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * There can be up to two drives per interface, as per the ATA-2 spec.
  *
  * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
  * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
@@ -21,17 +21,113 @@
  * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
  * ...
  *
- *  Contributors:
+ *  From hd.c:
+ *  |
+ *  | It traverses the request-list, using interrupts to jump between functions.
+ *  | As nearly all functions can be called within interrupts, we may not sleep.
+ *  | Special care is recommended.  Have Fun!
+ *  |
+ *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *  |
+ *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  | in the early extended-partition checks and added DM partitions.
+ *  |
+ *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
+ *  |
+ *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ *  | and general streamlining by Mark Lord (mlord@pobox.com).
+ *
+ *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
+ *
+ *	Mark Lord	(mlord@pobox.com)		(IDE Perf.Pkg)
+ *	Delman Lee	(delman@ieee.org)		("Mr. atdisk2")
+ *	Scott Snyder	(snyder@fnald0.fnal.gov)	(ATAPI IDE cd-rom)
  *
- *	Drew Eckhardt
- *	Branko Lankester	<lankeste@fwi.uva.nl>
- *	Mika Liljeberg
- *	Delman Lee		<delman@ieee.org>
- *	Scott Snyder		<snyder@fnald0.fnal.gov>
+ *  This was a rewrite of just about everything from hd.c, though some original
+ *  code is still sprinkled about.  Think of it as a major evolution, with
+ *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
+ *
+ *  Version 1.0 ALPHA	initial code, primary i/f working okay
+ *  Version 1.3 BETA	dual i/f on shared irq tested & working!
+ *  Version 1.4 BETA	added auto probing for irq(s)
+ *  Version 1.5 BETA	added ALPHA (untested) support for IDE cd-roms,
+ *  ...
+ * Version 5.50		allow values as small as 20 for idebus=
+ * Version 5.51		force non io_32bit in drive_cmd_intr()
+ *			change delay_10ms() to delay_50ms() to fix problems
+ * Version 5.52		fix incorrect invalidation of removable devices
+ *			add "hdx=slow" command line option
+ * Version 5.60		start to modularize the driver; the disk and ATAPI
+ *			 drivers can be compiled as loadable modules.
+ *			move IDE probe code to ide-probe.c
+ *			move IDE disk code to ide-disk.c
+ *			add support for generic IDE device subdrivers
+ *			add m68k code from Geert Uytterhoeven
+ *			probe all interfaces by default
+ *			add ioctl to (re)probe an interface
+ * Version 6.00		use per device request queues
+ *			attempt to optimize shared hwgroup performance
+ *			add ioctl to manually adjust bandwidth algorithms
+ *			add kerneld support for the probe module
+ *			fix bug in ide_error()
+ *			fix bug in the first ide_get_lock() call for Atari
+ *			don't flush leftover data for ATAPI devices
+ * Version 6.01		clear hwgroup->active while the hwgroup sleeps
+ *			support HDIO_GETGEO for floppies
+ * Version 6.02		fix ide_ack_intr() call
+ *			check partition table on floppies
+ * Version 6.03		handle bad status bit sequencing in ide_wait_stat()
+ * Version 6.10		deleted old entries from this list of updates
+ *			replaced triton.c with ide-dma.c generic PCI DMA
+ *			added support for BIOS-enabled UltraDMA
+ *			rename all "promise" things to "pdc4030"
+ *			fix EZ-DRIVE handling on small disks
+ * Version 6.11		fix probe error in ide_scan_devices()
+ *			fix ancient "jiffies" polling bugs
+ *			mask all hwgroup interrupts on each irq entry
+ * Version 6.12		integrate ioctl and proc interfaces
+ *			fix parsing of "idex=" command line parameter
+ * Version 6.13		add support for ide4/ide5 courtesy rjones@orchestream.com
+ * Version 6.14		fixed IRQ sharing among PCI devices
+ * Version 6.15		added SMP awareness to IDE drivers
+ * Version 6.16		fixed various bugs; even more SMP friendly
+ * Version 6.17		fix for newest EZ-Drive problem
+ * Version 6.18		default unpartitioned-disk translation now "BIOS LBA"
+ * Version 6.19		Re-design for a UNIFORM driver for all platforms,
+ *			  model based on suggestions from Russell King and
+ *			  Geert Uytterhoeven
+ *			Promise DC4030VL now supported.
+ *			add support for ide6/ide7
+ *			delay_50ms() changed to ide_delay_50ms() and exported.
+ * Version 6.20		Added/Fixed Generic ATA-66 support and hwif detection.
+ *			Added hdx=flash to allow for second flash disk
+ *			  detection w/o the hang loop.
+ *			Added support for ide8/ide9
+ *			Added idex=ata66 for the quirky chipsets that are
+ *			  ATA-66 compliant, but have yet to determine a method
+ *			  of verification of the 80c cable presence.
+ *			  Specifically Promise's PDC20262 chipset.
+ * Version 6.21		Fixing/Fixed SMP spinlock issue with insight from an old
+ *			  hat that clarified original low level driver design.
+ * Version 6.30		Added SMP support; fixed multmode issues.  -ml
+ * Version 6.31		Debug Share INTR's and request queue streaming
+ *			Native ATA-100 support
+ *			Prep for Cascades Project
+ *
+ *  Some additional driver compile-time options are in ./include/linux/ide.h
+ *
+ *  To do, in likely order of completion:
+ *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
  *
- *  Some additional driver compile-time options are in <linux/ide.h>
  */
 
+#define	REVISION	"Revision: 6.31"
+#define	VERSION		"Id: ide.c 6.31 2000/06/09"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#define _IDE_C			/* Tell ide.h it's really us */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -40,22 +136,21 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
 #include <linux/slab.h>
 #ifndef MODULE
-# include <linux/init.h>
-#endif
+#include <linux/init.h>
+#endif /* MODULE */
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -63,87 +158,249 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#include "timing.h"
-#include "pcihost.h"
-#include "ioctl.h"
+#include "ide_modes.h"
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif /* CONFIG_KMOD */
+
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES 	1
+
+static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
+
+static int	idebus_parameter; /* holds the "idebus=" parameter */
+static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+static int	initializing;     /* set while initializing built-in drivers */
+
+spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_BLK_DEV_IDESCSI_24
+#define CONFIG_BLK_DEV_IDESCSI
+extern int idescsi_init(void);
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+/*
+ * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
+ * which is shared between several drivers.
+ */
+static int	ide_intr_lock;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+int noautodma = 0;
+
+/*
+ * ide_modules keeps track of the available IDE chipset/probe/driver modules.
+ */
+ide_module_t *ide_modules;
+ide_module_t *ide_probe;
+
+/*
+ * This is declared extern in ide.h, for access by other IDE modules:
+ */
+ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
 
+#if (DISK_RECOVERY_TIME > 0)
 /*
- * CompactFlash cards and their relatives pretend to be removable hard disks, except:
+ * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * we can enforce a minimum delay time between successive operations.
+ */
+static unsigned long read_timer (void)
+{
+	unsigned long t, flags;
+	int i;
+
+	local_irq_save(flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= IN_BYTE(0x40) << 8;
+	local_irq_restore(flags);
+	return (t - i);
+}
+#endif /* DISK_RECOVERY_TIME */
+
+static inline void set_recovery_timer (ide_hwif_t *hwif)
+{
+#if (DISK_RECOVERY_TIME > 0)
+	hwif->last_time = read_timer();
+#endif /* DISK_RECOVERY_TIME */
+}
+
+/*
+ * Do not even *think* about calling this!
+ */
+static void init_hwif_data (unsigned int index)
+{
+	unsigned int unit;
+	hw_regs_t hw;
+	ide_hwif_t *hwif = &ide_hwifs[index];
+
+	/* bulk initialize hwif & drive info with zeros */
+	memset(hwif, 0, sizeof(ide_hwif_t));
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+	/* fill in any non-zero initial values */
+	hwif->index     = index;
+	ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
+	memcpy(&hwif->hw, &hw, sizeof(hw));
+	memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
+	hwif->noprobe	= !hwif->io_ports[IDE_DATA_OFFSET];
+#ifdef CONFIG_BLK_DEV_HD
+	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
+		hwif->noprobe = 1; /* may be overridden by ide_setup() */
+#endif /* CONFIG_BLK_DEV_HD */
+	hwif->major	= ide_hwif_to_major[index];
+	hwif->name[0]	= 'i';
+	hwif->name[1]	= 'd';
+	hwif->name[2]	= 'e';
+	hwif->name[3]	= '0' + index;
+	hwif->bus_state = BUSSTATE_ON;
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		drive->media			= ide_disk;
+		drive->select.all		= (unit<<4)|0xa0;
+		drive->hwif			= hwif;
+		drive->ctl			= 0x08;
+		drive->ready_stat		= READY_STAT;
+		drive->bad_wstat		= BAD_W_STAT;
+		drive->special.b.recalibrate	= 1;
+		drive->special.b.set_geometry	= 1;
+		drive->name[0]			= 'h';
+		drive->name[1]			= 'd';
+		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
+		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		init_waitqueue_head(&drive->wqueue);
+	}
+}
+
+/*
+ * init_ide_data() sets reasonable default values into all fields
+ * of all instances of the hwifs and drives, but only on the first call.
+ * Subsequent calls have no effect (they don't wipe out anything).
+ *
+ * This routine is normally called at driver initialization time,
+ * but may also be called MUCH earlier during kernel "command-line"
+ * parameter processing.  As such, we cannot depend on any other parts
+ * of the kernel (such as memory allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the
+ * ide_drive_t structs as needed, rather than always consuming memory
+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
+ */
+#define MAGIC_COOKIE 0x12345678
+static void __init init_ide_data (void)
+{
+	unsigned int index;
+	static unsigned long magic_cookie = MAGIC_COOKIE;
+
+	if (magic_cookie != MAGIC_COOKIE)
+		return;		/* already initialized */
+	magic_cookie = 0;
+
+	/* Initialise all interface structures */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		init_hwif_data(index);
+
+	/* Add default hw interfaces */
+	ide_init_default_hwifs();
+
+	idebus_parameter = 0;
+	system_bus_speed = 0;
+}
+
+/*
+ * CompactFlash cards and their brethern pretend to be removable hard disks, except:
  *	(1) they never have a slave unit, and
- *	(2) they don't have a door lock mechanisms.
+ *	(2) they don't have doorlock mechanisms.
  * This test catches them, and is invoked elsewhere when setting appropriate config bits.
  *
- * FIXME FIXME: Yes this is for certain applicable for all of them as time has shown.
- *
  * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
  * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
  * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
  * At that time, we might also consider parameterizing the timeouts and retries,
  * since these are MUCH faster than mechanical drives.	-M.Lord
  */
-int drive_is_flashcard(struct ata_device *drive)
+int drive_is_flashcard (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
-	int i;
-
-	char *flashcards[] = {
-		"KODAK ATA_FLASH",
-		"Hitachi CV",
-		"SunDisk SDCFB",
-		"HAGIWARA HPC",
-		"LEXAR ATA_FLASH",
-		"ATA_FLASH"		/* Simple Tech */
-	};
 
 	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a)
-			return 1;	/* CompactFlash */
-		for (i = 0; i < ARRAY_SIZE(flashcards); i++)
-			if (!strncmp(id->model, flashcards[i],
-				     strlen(flashcards[i])))
-				return 1;
+		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
+		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
+		{
+			return 1;	/* yes, it is a flash memory card */
+		}
 	}
-	return 0;
+	return 0;	/* no, it is not a flash memory card */
 }
 
-int ata_end_request(struct ata_device *drive, struct request *rq, int uptodate, unsigned int nr_secs)
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
+ */
+int ide_system_bus_speed (void)
 {
+	if (!system_bus_speed) {
+		if (idebus_parameter)
+			system_bus_speed = idebus_parameter;	/* user supplied value */
+#ifdef CONFIG_PCI
+		else if (pci_present())
+			system_bus_speed = 33;	/* safe default value for PCI */
+#endif /* CONFIG_PCI */
+		else
+			system_bus_speed = 50;	/* safe default value for VESA and PCI */
+		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
+			idebus_parameter ? "" : "; override with idebus=xx");
+	}
+	return system_bus_speed;
+}
+
+/*
+ * This is our end_request replacement function.
+ */
+int ide_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
 	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ret = 1;
 
-	spin_lock_irqsave(ch->lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
 
-	/* FIXME: Make this "small" hack to eliminate locking from
-	 * ata_end_request to grab the first segment number of sectors go away.
-	 */
-	if (!nr_secs)
-		nr_secs = rq->hard_cur_sectors;
-
 	/*
-	 * Decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO.
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
 	 */
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		udma_enable(drive, 1, 1);
+		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
 	}
 
-	if (!end_that_request_first(rq, uptodate, nr_secs)) {
-		add_blkdev_randomness(ch->major);
-		if (!blk_rq_tagged(rq))
-			blkdev_dequeue_request(rq);
-		else
-			blk_queue_end_tag(&drive->queue, rq);
-		drive->rq = NULL;
+	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+		add_blkdev_randomness(major(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
 		end_that_request_last(rq);
 		ret = 0;
 	}
-
-	spin_unlock_irqrestore(ch->lock, flags);
-
+	spin_unlock_irqrestore(&ide_lock, flags);
 	return ret;
 }
 
@@ -154,155 +411,396 @@
  * timer is started to prevent us from waiting forever in case
  * something goes wrong (see the ide_timer_expiry() handler later on).
  */
-void ata_set_handler(struct ata_device *drive, ata_handler_t handler,
-		      unsigned long timeout, ata_expiry_t expiry)
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
 {
 	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-	spin_lock_irqsave(ch->lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
+	if (hwgroup->handler != NULL) {
+		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
+			drive->name, hwgroup->handler, handler);
+	}
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
 
-	/* FIXME: change it later to BUG_ON(ch->handler)  --bzolnier */
-	if (ch->handler)
-		printk("%s: %s: handler not null; old=%p, new=%p, from %p\n",
-			drive->name, __FUNCTION__, ch->handler, handler, __builtin_return_address(0));
+/*
+ * current_capacity() returns the capacity (in sectors) of a drive
+ * according to its current geometry/LBA settings.
+ */
+unsigned long current_capacity (ide_drive_t *drive)
+{
+	if (!drive->present)
+		return 0;
+	if (drive->driver != NULL)
+		return DRIVER(drive)->capacity(drive);
+	return 0;
+}
 
-	ch->handler = handler;
+extern struct block_device_operations ide_fops[];
+/*
+ * ide_geninit() is called exactly *once* for each interface.
+ */
+void ide_geninit (ide_hwif_t *hwif)
+{
+	unsigned int unit;
 
-	ch->expiry = expiry;
-	ch->timer.expires = jiffies + timeout;
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		struct gendisk *gd = hwif->gd[unit];
 
-	add_timer(&ch->timer);
+		if (!drive->present)
+			continue;
+		if (drive->media!=ide_disk && drive->media!=ide_floppy
+		    && drive->media != ide_cdrom)
+			continue;
+		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+			(drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+			1<<PARTN_BITS, ide_fops,
+			current_capacity(drive));
+	}
+}
 
-	spin_unlock_irqrestore(ch->lock, flags);
+static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	byte stat;
+
+	SELECT_DRIVE(HWIF(drive),drive);
+	udelay (10);
+
+	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
+		printk("%s: ATAPI reset complete\n", drive->name);
+	} else {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			return ide_started;	/* continue polling */
+		}
+		hwgroup->poll_timeout = 0;	/* end of polling */
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
+		return do_reset1 (drive, 1);	/* do it the old fashioned way */
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
 }
 
-static void check_crc_errors(struct ata_device *drive)
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
 {
-	if (!drive->using_dma)
-		return;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	ide_hwif_t *hwif = HWIF(drive);
+	byte tmp;
+
+	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+			return ide_started;	/* continue polling */
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+		drive->failures++;
+	} else  {
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = GET_ERR()) == 1) {
+			printk("success\n");
+			drive->failures = 0;
+		} else {
+			drive->failures++;
+#if FANCY_STATUS_DUMPS
+			printk("master: ");
+			switch (tmp & 0x7f) {
+				case 1: printk("passed");
+					break;
+				case 2: printk("formatter device error");
+					break;
+				case 3: printk("sector buffer error");
+					break;
+				case 4: printk("ECC circuitry error");
+					break;
+				case 5: printk("controlling MPU error");
+					break;
+				default:printk("error (0x%02x?)", tmp);
+			}
+			if (tmp & 0x80)
+				printk("; slave: failed");
+			printk("\n");
+#else
+			printk("failed\n");
+#endif /* FANCY_STATUS_DUMPS */
+		}
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
+}
 
-	/* check the DMA crc count */
+static void check_dma_crc (ide_drive_t *drive)
+{
 	if (drive->crc_count) {
-		udma_enable(drive, 0, 0);
-		if (drive->channel->speedproc) {
-			u8 mode = drive->current_speed;
-			drive->crc_count = 0;
-
-			if (mode > XFER_UDMA_0)
-				mode--;
-			else
-
-			/*
-			 * We do not do non Ultra DMA modes.  Without iCRC's
-			 * available, we force the system to PIO and make the
-			 * user select the ATA-1 ATA-2 DMA modes himself.
-			 */
+		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+		if (drive->current_speed >= XFER_SW_DMA_0)
+			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
+	} else {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+}
 
-				mode = XFER_PIO_4;
+static void pre_reset (ide_drive_t *drive)
+{
+	if (drive->driver != NULL)
+		DRIVER(drive)->pre_reset(drive);
 
-			drive->channel->speedproc(drive, mode);
+	if (!drive->keep_settings) {
+		if (drive->using_dma) {
+			check_dma_crc(drive);
+		} else {
+			drive->unmask = 0;
+			drive->io_32bit = 0;
 		}
-		if (drive->current_speed >= XFER_UDMA_0)
-			udma_enable(drive, 1, 1);
-	} else
-		udma_enable(drive, 0, 1);
+		return;
+	}
+	if (drive->using_dma)
+		check_dma_crc(drive);
 }
 
 /*
- * The capacity of a drive according to its current geometry/LBA settings in
- * sectors.
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
  */
-sector_t ata_capacity(struct ata_device *drive)
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 {
-	if (!drive->present || !drive->driver)
-		return 0;
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-	if (ata_ops(drive) && ata_ops(drive)->capacity)
-		return ata_ops(drive)->capacity(drive);
+	local_irq_save(flags);
 
-	return ~0UL;
-}
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media != ide_disk && !do_not_try_atapi) {
+		pre_reset(drive);
+		SELECT_DRIVE(hwif,drive);
+		udelay (20);
+		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
+		local_irq_restore(flags);
+		return ide_started;
+	}
 
-static inline u32 read_24(struct ata_device *drive)
-{
-	return  (IN_BYTE(IDE_HCYL_REG) << 16) |
-		(IN_BYTE(IDE_LCYL_REG) << 8) |
-		 IN_BYTE(IDE_SECTOR_REG);
-}
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		pre_reset(&hwif->drives[unit]);
 
-#if FANCY_STATUS_DUMPS
-struct ata_bit_messages {
-	u8 mask;
-	u8 match;
-	const char *msg;
-};
+#if OK_TO_RESET_CONTROLLER
+	if (!IDE_CONTROL_REG) {
+		local_irq_restore(flags);
+		return ide_stopped;
+	}
+	/*
+	 * Note that we also set nIEN while resetting the device,
+	 * to mask unwanted interrupts from the interface during the reset.
+	 * However, due to the design of PC hardware, this will cause an
+	 * immediate interrupt due to the edge transition it produces.
+	 * This single interrupt gives us a "fast poll" for drives that
+	 * recover from reset very quickly, saving us the first 50ms wait time.
+	 */
+	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
+	udelay(10);			/* more than enough time */
+	if (drive->quirk_list == 2) {
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
+	} else {
+		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	}
+	udelay(10);			/* more than enough time */
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
 
-static struct ata_bit_messages ata_status_msgs[] = {
-	{ BUSY_STAT,  BUSY_STAT,  "busy"            },
-	{ READY_STAT, READY_STAT, "drive ready"     },
-	{ WRERR_STAT, WRERR_STAT, "device fault"    },
-	{ SEEK_STAT,  SEEK_STAT,  "seek complete"   },
-	{ DRQ_STAT,   DRQ_STAT,   "data request"    },
-	{ ECC_STAT,   ECC_STAT,   "corrected error" },
-	{ INDEX_STAT, INDEX_STAT, "index"           },
-	{ ERR_STAT,   ERR_STAT,   "error"           }
-};
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL)
+		hwif->resetproc(drive);
 
-static struct ata_bit_messages ata_error_msgs[] = {
-	{ ICRC_ERR|ABRT_ERR,	ABRT_ERR,		"drive status error"	},
-	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR,		"bad sector"		},
-	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR|ABRT_ERR,	"invalid checksum"	},
-	{ ECC_ERR,		ECC_ERR,		"uncorrectable error"	},
-	{ ID_ERR,		ID_ERR,			"sector id not found"   },
-	{ TRK0_ERR,		TRK0_ERR,		"track zero not found"	},
-	{ MARK_ERR,		MARK_ERR,		"addr mark not found"   }
-};
+#endif	/* OK_TO_RESET_CONTROLLER */
+
+	local_irq_restore(flags);
+	return ide_started;
+}
 
-static void dump_bits(struct ata_bit_messages *msgs, int nr, u8 bits)
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
 {
-	int i;
-	int first = 1;
+	return do_reset1 (drive, 0);
+}
+
+static inline u32 read_24 (ide_drive_t *drive)
+{
+	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
 
-	printk(" [ ");
+/*
+ * Clean up after success/failure of an explicit drive cmd
+ */
+void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
+{
+	unsigned long flags;
+	struct request *rq;
 
-	for (i = 0; i < nr; i++, msgs++)
-		if ((bits & msgs->mask) == msgs->match) {
-			if (!first)
-				printk(",");
-			printk("%s", msgs->msg);
-			first = 0;
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	if (rq->flags & REQ_DRIVE_CMD) {
+		byte *args = (byte *) rq->buffer;
+		if (rq->errors == 0)
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+		if (args) {
+			args[0] = stat;
+			args[1] = err;
+			args[2] = IN_BYTE(IDE_NSECTOR_REG);
+		}
+	} else if (rq->flags & REQ_DRIVE_TASK) {
+		byte *args = (byte *) rq->buffer;
+		if (rq->errors == 0)
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+		if (args) {
+			args[0] = stat;
+			args[1] = err;
+			args[2] = IN_BYTE(IDE_NSECTOR_REG);
+			args[3] = IN_BYTE(IDE_SECTOR_REG);
+			args[4] = IN_BYTE(IDE_LCYL_REG);
+			args[5] = IN_BYTE(IDE_HCYL_REG);
+			args[6] = IN_BYTE(IDE_SELECT_REG);
+		}
+	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = (ide_task_t *) rq->special;
+		if (rq->errors == 0)
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			
+		if (args) {
+			if (args->tf_in_flags.b.data) {
+				unsigned short data			= IN_WORD(IDE_DATA_REG);
+				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+			}
+			args->tfRegister[IDE_ERROR_OFFSET]   = err;
+			args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+			args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+			args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+			args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+			args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+
+			if ((drive->id->command_set_2 & 0x0400) &&
+			    (drive->id->cfs_enable_2 & 0x0400) &&
+			    (drive->addressing == 1)) {
+				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+			}
 		}
+	}
 
-	printk("] ");
+	spin_lock_irqsave(&ide_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
-#else
-# define dump_bits(msgs,nr,bits) do { } while (0)
-#endif
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-u8 ata_dump(struct ata_device *drive, struct request * rq, const char *msg)
+byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
 {
 	unsigned long flags;
-	u8 err = 0;
-
-	/* FIXME:  --bzolnier */
-	local_save_flags(flags);
-	local_irq_enable();
+	byte err = 0;
 
-	printk("%s: %s: status=0x%02x", drive->name, msg, drive->status);
-	dump_bits(ata_status_msgs, ARRAY_SIZE(ata_status_msgs), drive->status);
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
 	printk("\n");
-
-	if ((drive->status & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
 		err = GET_ERR();
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (drive->type == ATA_DISK) {
-			dump_bits(ata_error_msgs, ARRAY_SIZE(ata_error_msgs), err);
-
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
 			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
 				if ((drive->id->command_set_2 & 0x0400) &&
 				    (drive->id->cfs_enable_2 & 0x0400) &&
@@ -310,13 +808,15 @@
 					__u64 sectors = 0;
 					u32 low = 0, high = 0;
 					low = read_24(drive);
-					OUT_BYTE(0x80, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
+					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
 					high = read_24(drive);
 
 					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld, high=%d, low=%d", (long long) sectors, high, low);
+					printk(", LBAsect=%llu, high=%d, low=%d",
+					       (unsigned long long) sectors,
+					       high, low);
 				} else {
-					u8 cur = IN_BYTE(IDE_SELECT_REG);
+					byte cur = IN_BYTE(IDE_SELECT_REG);
 					if (cur & 0x40) {	/* using LBA? */
 						printk(", LBAsect=%ld", (unsigned long)
 						 ((cur&0xf)<<24)
@@ -331,487 +831,684 @@
 						  IN_BYTE(IDE_SECTOR_REG));
 					}
 				}
-				if (rq)
-					printk(", sector=%ld", rq->sector);
+				if (HWGROUP(drive) && HWGROUP(drive)->rq)
+					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
 			}
 		}
-#endif
+#endif	/* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	local_irq_restore (flags);
-
+	local_irq_restore(flags);
 	return err;
 }
 
 /*
- * Take action based on the error returned by the drive.
- *
- * FIXME: Separate the error handling code out and call it only in cases where
- * we really wan't to try to recover from the error and not just reporting.
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
  */
-ide_startstop_t ata_error(struct ata_device *drive, struct request *rq,	const char *msg)
+static void try_to_flush_leftover_data (ide_drive_t *drive)
 {
-	u8 err;
-	u8 stat = drive->status;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
-	err = ata_dump(drive, rq, msg);
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		ata_input_data (drive, buffer, wcount);
+	}
+}
 
-	/* Only try to recover from block I/O operations.
-	 */
-	if (!rq || !(rq->flags & REQ_CMD)) {
-		rq->errors = 1;
+/*
+ * FIXME Add an ATAPI error
+ */
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
 
-		return ATA_OP_FINISHED;
+	err = ide_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+//		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
 	}
 
-	/* other bits are useless when BUSY */
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr))
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
-	else if (drive->type == ATA_DISK) {
-		/* The error bit has different meaning on cdrom and tape.
-		 */
-		if (stat & ERR_STAT) {
+	} else {
+
+/* ide_disk */
+		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
 				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ATA_OP_FINISHED; /* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
+					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
 				drive->crc_count++; /* UDMA crc error -- just retry the operation */
-			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
 				rq->errors = ERROR_MAX;
+			else if (err & TRK0_ERR)	/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
 		}
-
-		/* As an alternative to resetting the drive, we try to clear
-		 * the condition by reading a sector's worth of data from the
-		 * drive.  Of course, this can not help if the drive is
-		 * *waiting* for data from *us*.
-		 */
-
-		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
-			int i;
-
-			for (i = (drive->mult_count ? drive->mult_count : 1); i > 0; --i) {
-				u32 buffer[SECTOR_WORDS];
-
-				ata_read(drive, buffer, SECTOR_WORDS);
-			}
-		}
+/* !ide_disk */
+		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+			try_to_flush_leftover_data(drive);
+/* !ide_disk */
 	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
 
-	/* Force an abort if not even the status data is available.  This will
-	 * clear all pending IRQs on the drive as well.
-	 */
-	if (!ata_status(drive, 0, BUSY_STAT | DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
-
-	/* Bail out immediately. */
 	if (rq->errors >= ERROR_MAX) {
-		printk(KERN_ERR "%s: max number of retries exceeded!\n", drive->name);
-		if (ata_ops(drive) && ata_ops(drive)->end_request)
-			ata_ops(drive)->end_request(drive, rq, 0);
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(drive, 0);
 		else
-			ata_end_request(drive, rq, 0, 0);
-
-		return ATA_OP_FINISHED;
+	 		ide_end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
 	}
+	return ide_stopped;
+}
 
-	++rq->errors;
-	printk(KERN_INFO "%s: request error, nr. %d\n", drive->name, rq->errors);
-
-	/*
-	 * Attempt to recover a confused drive by resetting it.  Unfortunately,
-	 * resetting a disk drive actually resets all devices on the same
-	 * interface, so it can really be thought of as resetting the interface
-	 * rather than resetting the drive.
-	 *
-	 * ATAPI devices have their own reset mechanism which allows them to be
-	 * individually reset without clobbering other devices on the same
-	 * interface.
-	 *
-	 * The IDE interface does not generate an interrupt to let us know when
-	 * the reset operation has finished, so we must poll for this.  This
-	 * may take a very long time to complete.
-	 *
-	 * Maybe we can check if we are in IRQ context and schedule the CPU
-	 * during this time. But for certain we should block all data transfers
-	 * on the channel in question during those operations.
-	 */
-
-	if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-		unsigned int unit;
-		struct ata_channel *ch = drive->channel;
-		int ret;
-
-		/* For an ATAPI device, first try an ATAPI SRST.
-		 */
-
-		if (drive->type != ATA_DISK) {
-			check_crc_errors(drive);
-			ata_select(drive, 20);
-			udelay(1);
-			ata_irq_enable(drive, 0);
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
-			if (drive->quirk_list == 2)
-				ata_irq_enable(drive, 1);
-			udelay(1);
-			ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_WORSTCASE, NULL);
-			ata_mask(drive);
-
-			if (ret == ATA_OP_READY) {
-				printk("%s: ATAPI reset complete\n", drive->name);
+/*
+ * Issue a simple drive command
+ * The drive must be selected beforehand.
+ */
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+{
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler (drive, handler, WAIT_CMD, NULL);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive),drive,0);
+	OUT_BYTE(nsect,IDE_NSECTOR_REG);
+	OUT_BYTE(cmd,IDE_COMMAND_REG);
+}
 
-				return ATA_OP_CONTINUES;
-			} else
-				printk(KERN_ERR "%s: ATAPI reset timed out, status=0x%02x\n",
-						drive->name, drive->status);
-		}
+/*
+ * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ */
+static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	byte *args = (byte *) rq->buffer;
+	byte stat = GET_STAT();
+	int retries = 10;
 
-		/* Reset all devices on channel.
-		 */
+	local_irq_enable();
+	if ((stat & DRQ_STAT) && args && args[3]) {
+		byte io_32bit = drive->io_32bit;
+		drive->io_32bit = 0;
+		ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		drive->io_32bit = io_32bit;
+		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+			udelay(100);
+	}
 
-		/* First, reset any device state data we were maintaining for
-		 * any of the drives on this interface.
-		 */
-		for (unit = 0; unit < MAX_DRIVES; ++unit)
-			check_crc_errors(&ch->drives[unit]);
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+	return ide_stopped;
+}
 
-		/* And now actually perform the reset operation.
-		 */
-		printk("%s: ATA reset...\n", ch->name);
-		ata_select(drive, 20);
-		udelay(1);
-		ata_irq_enable(drive, 0);
-
-		OUT_BYTE(0x04, ch->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		OUT_BYTE(0x00, ch->io_ports[IDE_CONTROL_OFFSET]);
-		ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_WORSTCASE, NULL);
-		ata_mask(drive);
+/*
+ * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ * commands to a drive.  It used to do much more, but has been scaled back.
+ */
+static ide_startstop_t do_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
 
-		if (ret == ATA_OP_READY)
-			printk("%s: ATA reset complete\n", drive->name);
-		else
-			printk(KERN_ERR "%s: ATA reset timed out, status=0x%02x\n",
-					drive->name, drive->status);
-		mdelay(100);
+#ifdef DEBUG
+	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+#endif
+	if (s->b.set_tune) {
+		s->b.set_tune = 0;
+		if (HWIF(drive)->tuneproc != NULL)
+			HWIF(drive)->tuneproc(drive, drive->tune_req);
+	} else if (drive->driver != NULL) {
+		return DRIVER(drive)->special(drive);
+	} else if (s->all) {
+		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
+		s->all = 0;
 	}
+	return ide_stopped;
+}
 
-	/* signal that we should retry this request */
-	return ATA_OP_CONTINUES;
+/*
+ * execute_drive_cmd() issues a special drive command,
+ * usually initiated by ioctl() from the external hdparm program.
+ */
+static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+{
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+ 		ide_task_t *args = rq->special;
+ 
+		if (!args)
+			goto done;
+ 
+		if (args->tf_out_flags.all != 0) 
+			return flagged_taskfile(drive, args);
+		return do_rw_taskfile(drive, args);
+	} else if (rq->flags & REQ_DRIVE_TASK) {
+ 		byte *args = rq->buffer;
+ 		byte sel;
+ 
+		if (!args)
+			goto done;
+#ifdef DEBUG
+ 		printk("%s: DRIVE_TASK_CMD ", drive->name);
+ 		printk("cmd=0x%02x ", args[0]);
+ 		printk("fr=0x%02x ", args[1]);
+ 		printk("ns=0x%02x ", args[2]);
+ 		printk("sc=0x%02x ", args[3]);
+ 		printk("lcyl=0x%02x ", args[4]);
+ 		printk("hcyl=0x%02x ", args[5]);
+ 		printk("sel=0x%02x\n", args[6]);
+#endif
+ 		OUT_BYTE(args[1], IDE_FEATURE_REG);
+ 		OUT_BYTE(args[3], IDE_SECTOR_REG);
+ 		OUT_BYTE(args[4], IDE_LCYL_REG);
+ 		OUT_BYTE(args[5], IDE_HCYL_REG);
+ 		sel = (args[6] & ~0x10);
+ 		if (drive->select.b.unit)
+ 			sel |= 0x10;
+ 		OUT_BYTE(sel, IDE_SELECT_REG);
+ 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ 		return ide_started;
+ 	} else if (rq->flags & REQ_DRIVE_CMD) {
+ 		byte *args = rq->buffer;
+
+		if (!args)
+			goto done;
+#ifdef DEBUG
+ 		printk("%s: DRIVE_CMD ", drive->name);
+ 		printk("cmd=0x%02x ", args[0]);
+ 		printk("sc=0x%02x ", args[1]);
+ 		printk("fr=0x%02x ", args[2]);
+ 		printk("xx=0x%02x\n", args[3]);
+#endif
+ 		if (args[0] == WIN_SMART) {
+ 			OUT_BYTE(0x4f, IDE_LCYL_REG);
+ 			OUT_BYTE(0xc2, IDE_HCYL_REG);
+ 			OUT_BYTE(args[2],IDE_FEATURE_REG);
+ 			OUT_BYTE(args[1],IDE_SECTOR_REG);
+ 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		OUT_BYTE(args[2],IDE_FEATURE_REG);
+ 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ 		return ide_started;
+ 	}
+
+done:
+ 	/*
+ 	 * NULL is actually a valid way of waiting for
+ 	 * all current requests to be flushed from the queue.
+ 	 */
+#ifdef DEBUG
+ 	printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ 	return ide_stopped;
 }
 
 /*
- * Issue a new request.
- * Caller must have already done spin_lock_irqsave(channel->lock, ...)
+ * start_request() initiates handling of a new I/O request
+ * needed to reverse the perverted changes anonymously made back
+ * 2.3.99-pre6
  */
-void do_ide_request(request_queue_t *q)
+static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
-	struct ata_device *drive = q->queuedata;
-	struct ata_channel *ch = drive->channel;
+	ide_startstop_t startstop;
+	unsigned long block;
+	unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
+	ide_hwif_t *hwif = HWIF(drive);
 
-	while (!test_and_set_bit(IDE_BUSY, ch->active)) {
-		unsigned int unit;
-		ide_startstop_t ret;
-
-		if (drive) {
-			/* No request pending?! */
-			if (blk_queue_empty(&drive->queue))
-				drive = NULL;
-			/* Still resorting requests?! */
-			else if (blk_queue_plugged(&drive->queue))
-				drive = NULL;
-		}
+	BUG_ON(!(rq->flags & REQ_STARTED));
 
-		if (!drive) {
-			/* We should never get here! */
-			/* Unless someone called us from IRQ context after
-			 * finishing the actual request already. (Shrug!)
-			 */
-			// printk(KERN_INFO "no device found!\n");
-			for (unit = 0; unit < MAX_DRIVES; ++unit) {
-				struct ata_device *tmp = &ch->drives[unit];
-
-				if (!tmp->present)
-					continue;
-
-				/* There are no requests pending for this
-				 * device.
-				 */
-				if (blk_queue_empty(&tmp->queue))
-					continue;
-
-				/* Take this device, if there is no device
-				 * choosen thus far and the queue is ready for
-				 * processing.
-				 */
-				if (!drive && !blk_queue_plugged(&tmp->queue))
-					drive = tmp;
-			}
-		}
+#ifdef DEBUG
+	printk("%s: start_request: current=0x%08lx\n",
+		hwif->name, (unsigned long) rq);
+#endif
 
-		if (!drive) {
-			/* Ugly, but how can we sleep for the lock otherwise?
-			 */
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		goto kill_rq;
+	}
 
-			ide_release_lock(&ide_irq_lock);/* for atari only */
-			clear_bit(IDE_BUSY, ch->active);
+	/*
+	 * bail early if we've sent a device to sleep, however how to wake
+	 * this needs to be a masked flag.  FIXME for proper operations.
+	 */
+	if (drive->suspend_reset) {
+		goto kill_rq;
+	}
 
-			/* All requests are done.
-			 *
-			 * Disable IRQs from the last drive on this channel, to
-			 * make sure that it wan't throw stones at us when we
-			 * are not prepared to take them.
-			 */
+	if (unit >= MAX_DRIVES) {
+		printk("%s: bad device number: %s\n",
+			hwif->name, kdevname(rq->rq_dev));
+		goto kill_rq;
+	}
+#ifdef DEBUG
+	if (rq->bh && !buffer_locked(rq->bh)) {
+		printk("%s: block not locked\n", drive->name);
+		goto kill_rq;
+	}
+#endif
+	block    = rq->sector;
 
-			if (ch->drive && !ch->drive->using_tcq)
-				ata_irq_enable(ch->drive, 0);
+	if ((rq->flags & REQ_CMD) &&
+	    (drive->media == ide_disk || drive->media == ide_floppy)) {
+		block += drive->sect0;
+	}
+	/* Yecch - this will shift the entire interval,
+	   possibly killing some innocent following sector */
+	if (block == 0 && drive->remap_0_to_1 == 1)
+		block = 1;  /* redirect MBR access to EZ-Drive partn table */
 
-			return;
-		}
+#if (DISK_RECOVERY_TIME > 0)
+	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
+#endif
 
-		/* Remember the last drive we where acting on.
-		 */
-		ch->drive = drive;
+	SELECT_DRIVE(hwif, drive);
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+		printk("%s: drive not ready for command\n", drive->name);
+		return startstop;
+	}
+	if (!drive->special.all) {
+		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+			return execute_drive_cmd(drive, rq);
+		else if (rq->flags & REQ_DRIVE_TASKFILE)
+			return execute_drive_cmd(drive, rq);
 
-		/* Feed commands to a drive until it barfs.
-		 */
-		do {
-			struct request *rq = NULL;
+		if (drive->driver != NULL) {
+			return (DRIVER(drive)->do_request(drive, rq, block));
+		}
+		printk("%s: media type %d not supported\n", drive->name, drive->media);
+		goto kill_rq;
+	}
+	return do_special(drive);
+kill_rq:
+	if (drive->driver != NULL)
+		DRIVER(drive)->end_request(drive, 0);
+	else
+		ide_end_request(drive, 0);
+	return ide_stopped;
+}
 
-			/* Abort early if we can't queue another command. for
-			 * non tcq, ata_can_queue is always 1 since we never
-			 * get here unless the drive is idle.
-			 */
+int restart_request (ide_drive_t *drive, struct request *rq)
+{
+	(void) start_request(drive, rq);
+	return 0;
+}
 
-			if (!ata_can_queue(drive)) {
-				if (!ata_pending_commands(drive)) {
-					clear_bit(IDE_BUSY, ch->active);
-					if (drive->using_tcq)
-						ata_irq_enable(drive, 0);
-				}
-				break;
-			}
+/*
+ * ide_stall_queue() can be used by a drive to give excess bandwidth back
+ * to the hwgroup by sleeping for timeout jiffies.
+ */
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+	if (timeout > WAIT_WORSTCASE)
+		timeout = WAIT_WORSTCASE;
+	drive->sleep = timeout + jiffies;
+}
 
-			if (test_bit(IDE_DMA, ch->active)) {
-				printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
-				break;
-			}
+#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
 
-			/* There's a small window between where the queue could
-			 * be replugged while we are in here when using tcq (in
-			 * which case the queue is probably empty anyways...),
-			 * so check and leave if appropriate. When not using
-			 * tcq, this is still a severe BUG!
-			 */
+/*
+ * choose_drive() selects the next drive which will be serviced.
+ */
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+	ide_drive_t *drive, *best;
 
-			if (blk_queue_plugged(&drive->queue)) {
-				BUG_ON(!drive->using_tcq);
-				break;
+repeat:	
+	best = NULL;
+	drive = hwgroup->drive;
+	do {
+		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
+			if (!best
+			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
+			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+			{
+				if (!blk_queue_plugged(&drive->queue))
+					best = drive;
 			}
-
-			if (!(rq = elv_next_request(&drive->queue))) {
-				if (!ata_pending_commands(drive)) {
-					clear_bit(IDE_BUSY, ch->active);
-					if (drive->using_tcq)
-						ata_irq_enable(drive, 0);
+		}
+	} while ((drive = drive->next) != hwgroup->drive);
+	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+		long t = (signed long)(WAKEUP(best) - jiffies);
+		if (t >= WAIT_MIN_SLEEP) {
+		/*
+		 * We *may* have some time to spare, but first let's see if
+		 * someone can potentially benefit from our nice mood today..
+		 */
+			drive = best->next;
+			do {
+				if (!drive->sleep
+				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
+				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
+				{
+					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+					goto repeat;
 				}
-				drive->rq = NULL;
+			} while ((drive = drive->next) != best);
+		}
+	}
+	return best;
+}
 
-				break;
+/*
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&ide_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global ide_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The ide_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
+ */
+/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
+ *         into life on wakeup from machine sleep.
+ */ 
+void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+{
+	ide_drive_t	*drive;
+	ide_hwif_t	*hwif;
+	struct request	*rq;
+	ide_startstop_t	startstop;
+
+	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */
+
+	local_irq_disable();
+		/* necessary paranoia: ensure IRQs are masked on local CPU */
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
+		drive = choose_drive(hwgroup);
+		if (drive == NULL) {
+			unsigned long sleep = 0;
+			hwgroup->rq = NULL;
+			drive = hwgroup->drive;
+			do {
+				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
+					sleep = drive->sleep;
+			} while ((drive = drive->next) != hwgroup->drive);
+			if (sleep) {
+		/*
+		 * Take a short snooze, and then wake up this hwgroup again.
+		 * This gives other hwgroups on the same a chance to
+		 * play fairly with us, just in case there are big differences
+		 * in relative throughputs.. don't want to hog the cpu too much.
+		 */
+				if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+					sleep = jiffies + WAIT_MIN_SLEEP;
+#if 1
+				if (timer_pending(&hwgroup->timer))
+					printk("ide_set_handler: timer already active\n");
+#endif
+				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
+				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1 while sleeping */
+			} else {
+				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
+				ide_release_lock(&ide_lock);	/* for atari only */
+				hwgroup->busy = 0;
 			}
+			return;		/* no more work for this hwgroup (for now) */
+		}
+		hwif = HWIF(drive);
+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
+			/* set nIEN for previous hwif */
+			SELECT_INTERRUPT(hwif, drive);
+		}
+		hwgroup->hwif = hwif;
+		hwgroup->drive = drive;
+		drive->sleep = 0;
+		drive->service_start = jiffies;
 
-			/* If there are queued commands, we can't start a
-			 * non-fs request (really, a non-queuable command)
-			 * until the queue is empty.
-			 */
-			if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
-				break;
+		BUG_ON(blk_queue_plugged(&drive->queue));
 
-			drive->rq = rq;
+		rq = hwgroup->rq = elv_next_request(&drive->queue);
 
-			spin_unlock(ch->lock);
+		/*
+		 * Some systems have trouble with IDE IRQs arriving while
+		 * the driver is still setting things up.  So, here we disable
+		 * the IRQ used by this interface while the request is being started.
+		 * This may look bad at first, but pretty much the same thing
+		 * happens anyway when any interrupt comes in, IDE or otherwise
+		 *  -- the kernel masks the IRQ while it is being handled.
+		 */
+		if (masked_irq && hwif->irq != masked_irq)
+			disable_irq_nosync(hwif->irq);
+		spin_unlock(&ide_lock);
+		local_irq_enable();
 			/* allow other IRQs while we start this request */
-			local_irq_enable();
+		startstop = start_request(drive, rq);
+		spin_lock_irq(&ide_lock);
+		if (masked_irq && hwif->irq != masked_irq)
+			enable_irq(hwif->irq);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
+	}
+}
 
-			/*
-			 * This initiates handling of a new I/O request.
-			 */
-			BUG_ON(!(rq->flags & REQ_STARTED));
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
 
-			/* bail early if we've exceeded max_failures */
-			if (drive->max_failures && (drive->failures > drive->max_failures))
-				goto kill_rq;
+	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
 
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(request_queue_t *q)
+{
+	ide_do_request(q->queuedata, 0);
+}
 
-			ata_select(drive, 0);
-			ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
-					WAIT_READY, rq);
+#ifndef __IDEDMA_TIMEOUT
+/*
+ * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+void ide_dma_timeout_retry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct request *rq;
 
-			if (ret != ATA_OP_READY) {
-				printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+	/*
+	 * end current dma transaction
+	 */
+	(void) hwif->dmaproc(ide_dma_end, drive);
 
-				goto kill_rq;
-			}
+	/*
+	 * complain a little, later we might remove some of this verbosity
+	 */
+	printk("%s: timeout waiting for DMA\n", drive->name);
+	(void) hwif->dmaproc(ide_dma_timeout, drive);
 
-			if (!ata_ops(drive)) {
-				printk(KERN_WARNING "%s: device type %d not supported\n",
-						drive->name, drive->type);
-				goto kill_rq;
-			}
+	/*
+	 * disable dma for now, but remember that we did so because of
+	 * a timeout -- we'll reenable after we finish this next request
+	 * (or rather the first chunk of it) in pio.
+	 */
+	drive->retry_pio++;
+	drive->state = DMA_PIO_RETRY;
+	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
 
-			/* The normal way of execution is to pass and execute the request
-			 * handler down to the device type driver.
-			 */
+	/*
+	 * un-busy drive etc (hwgroup->busy is cleared on return) and
+	 * make sure request is sane
+	 */
+	rq = HWGROUP(drive)->rq;
+	HWGROUP(drive)->rq = NULL;
 
-			if (ata_ops(drive)->do_request)
-				ret = ata_ops(drive)->do_request(drive, rq, rq->sector);
-			else {
-kill_rq:
-				if (ata_ops(drive) && ata_ops(drive)->end_request)
-					ata_ops(drive)->end_request(drive, rq, 0);
-				else
-					ata_end_request(drive, rq, 0, 0);
-				ret = ATA_OP_FINISHED;
+	rq->errors = 0;
+	rq->sector = rq->bio->bi_sector;
+	rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+	if (rq->bio)
+		rq->buffer = NULL;
 
-			}
-			spin_lock_irq(ch->lock);
-			/* continue if command started, so we are busy */
-		} while (ret != ATA_OP_CONTINUES);
-	}
+	/*
+	 * FIXME or DELETE ME
+	 *
+	 * so what do we do if the device is left in an invalid state
+	 * and will not accept commands. SOFT RESET is the only chance.
+	 */
 }
+#endif
 
 /*
- * This is our timeout function for all drive operations.  But note that it can
- * also be invoked as a result of a "sleep" operation triggered by the
- * mod_timer() call in do_ide_request.
- *
- * FIXME: This should take a drive context instead of a channel.
- * FIXME: This should not explicitly reenter the request handling engine.
+ * ide_timer_expiry() is our timeout function for all drive operations.
+ * But note that it can also be invoked as a result of a "sleep" operation
+ * triggered by the mod_timer() call in ide_do_request.
  */
-void ide_timer_expiry(unsigned long data)
+void ide_timer_expiry (unsigned long data)
 {
-	unsigned long flags;
-	struct ata_channel *ch = (struct ata_channel *) data;
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	ide_expiry_t	*expiry;
+ 	unsigned long	flags;
+	unsigned long	wait;
 
-	spin_lock_irqsave(ch->lock, flags);
-	del_timer(&ch->timer);
-
-	if (!ch->drive) {
-		printk(KERN_ERR "%s: channel->drive was NULL\n", __FUNCTION__);
-		ch->handler = NULL;
-	} else if (!ch->handler) {
+	spin_lock_irqsave(&ide_lock, flags);
+	del_timer(&hwgroup->timer);
 
+	if ((handler = hwgroup->handler) == NULL) {
 		/*
-		 * Either a marginal timeout occurred (got the interrupt just
-		 * as timer expired), or we were "sleeping" to give other
-		 * devices a chance.  Either way, we don't really want to
-		 * complain about anything.
-		 *
-		 * FIXME: Do we really still have to clear IDE_BUSY here?
+		 * Either a marginal timeout occurred
+		 * (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.
+		 * Either way, we don't really want to complain about anything.
 		 */
-
-		if (test_and_clear_bit(IDE_SLEEP, ch->active))
-			clear_bit(IDE_BUSY, ch->active);
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+		}
 	} else {
-		struct ata_device *drive = ch->drive;
-		ide_startstop_t ret;
-		ata_handler_t *handler;
-
-		/* paranoia */
-		if (!test_and_set_bit(IDE_BUSY, ch->active))
-			printk(KERN_ERR "%s: %s: channel was not busy?!\n",
-					drive->name, __FUNCTION__);
-
-		if (ch->expiry) {
-			unsigned long wait;
-
-			/* continue */
-			ret = ch->expiry(drive, drive->rq, &wait);
-			if (ret == ATA_OP_CONTINUES) {
-				/* reengage timer */
-				if (wait) {
-					ch->timer.expires  = jiffies + wait;
-					add_timer(&ch->timer);
+		ide_drive_t *drive = hwgroup->drive;
+		if (!drive) {
+			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+			hwgroup->handler = NULL;
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop = ide_stopped;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			if ((expiry = hwgroup->expiry) != NULL) {
+				/* continue */
+				if ((wait = expiry(drive)) != 0) {
+					/* reset timer */
+					hwgroup->timer.expires  = jiffies + wait;
+					add_timer(&hwgroup->timer);
+					spin_unlock_irqrestore(&ide_lock, flags);
+					return;
 				}
-
-				spin_unlock_irqrestore(ch->lock, flags);
-
-				return;
 			}
-		}
-
-		/*
-		 * We need to simulate a real interrupt when invoking the
-		 * handler() function, which means we need to globally mask the
-		 * specific IRQ:
-		 */
-
-		handler = ch->handler;
-		ch->handler = NULL;
-
-		spin_unlock(ch->lock);
-#if DISABLE_IRQ_NOSYNC
-		disable_irq_nosync(ch->irq);
-#else
-		disable_irq(ch->irq);	/* disable_irq_nosync ?? */
-#endif
-
-		local_irq_disable();
-		if (ch->poll_timeout) {
-			ret = handler(drive, drive->rq);
-		} else if (ata_status_irq(drive)) {
-			if (test_bit(IDE_DMA, ch->active))
-				udma_irq_lost(drive);
-			(void) ide_ack_intr(ch);
-			printk("%s: lost interrupt\n", drive->name);
-			ret = handler(drive, drive->rq);
-		} else if (test_bit(IDE_DMA, ch->active)) {
-			struct request *rq = drive->rq;
-
+			hwgroup->handler = NULL;
 			/*
-			 * Un-busy the hwgroup etc, and clear any pending DMA
-			 * status. we want to retry the current request in PIO
-			 * mode instead of risking tossing it all away.
-			 */
-
-			udma_stop(drive);
-			udma_timeout(drive);
-
-			/* Disable dma for now, but remember that we did so
-			 * because of a timeout -- we'll reenable after we
-			 * finish this next request (or rather the first chunk
-			 * of it) in pio.
-			 */
-
-			drive->retry_pio++;
-			drive->state = DMA_PIO_RETRY;
-			udma_enable(drive, 0, 0);
-
-			/* Un-busy drive etc (hwgroup->busy is cleared on
-			 * return) and make sure request is sane.
+			 * We need to simulate a real interrupt when invoking
+			 * the handler() function, which means we need to globally
+			 * mask the specific IRQ:
 			 */
-
-			drive->rq = NULL;
-
-			rq->errors = 0;
-			if (rq->bio) {
-				rq->sector = rq->bio->bi_sector;
-				rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-				rq->buffer = NULL;
+			spin_unlock(&ide_lock);
+			hwif  = HWIF(drive);
+#if DISABLE_IRQ_NOSYNC
+			disable_irq_nosync(hwif->irq);
+#else
+			disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+#endif /* DISABLE_IRQ_NOSYNC */
+			local_irq_disable();
+				/* local CPU only, as if we were handling an interrupt */
+			if (hwgroup->poll_timeout != 0) {
+				startstop = handler(drive);
+			} else if (drive_is_ready(drive)) {
+				if (drive->waiting_for_dma)
+					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
+				(void)ide_ack_intr(hwif);
+				printk("%s: lost interrupt\n", drive->name);
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+#ifndef __IDEDMA_TIMEOUT
+					startstop = ide_stopped;
+					ide_dma_timeout_retry(drive);
+#else /* __IDEDMA_TIMEOUT */
+					(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
+					printk("%s: timeout waiting for DMA\n", drive->name);
+					(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
+#endif /* __IDEDMA_TIMEOUT */
+				} else
+					startstop = DRIVER(drive)->error(drive, "irq timeout", GET_STAT());
 			}
-			ret = ATA_OP_FINISHED;
-		} else
-			ret = ata_error(drive, drive->rq, "irq timeout");
-
-		enable_irq(ch->irq);
-		spin_lock_irq(ch->lock);
-
-		if (ret == ATA_OP_FINISHED) {
-			/* Reenter the request handling engine. */
-			clear_bit(IDE_BUSY, ch->active);
-			do_ide_request(&drive->queue);
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&ide_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
 		}
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
@@ -824,7 +1521,7 @@
  * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  * "good", we just ignore the interrupt completely.
  *
- * This routine assumes IRQ are disabled on entry.
+ * This routine assumes __cli() is in effect when called.
  *
  * If an unexpected interrupt happens on irq15 while we are handling irq14
  * and if the two interfaces are "serialized" (CMD640), then it looks like
@@ -832,294 +1529,2309 @@
  *
  * In reality, this is a non-issue.  The new command is not sent unless the
  * drive is ready to accept one, in which case we know the drive is not
- * trying to interrupt us.  And ata_set_handler() is always invoked before
+ * trying to interrupt us.  And ide_set_handler() is always invoked before
  * completing the issuance of any new drive command, so we will not be
  * accidentally invoked as a result of any valid command completion interrupt.
  *
  */
-static void unexpected_irq(int irq)
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
-	/* Try to not flood the console with msgs */
-	static unsigned long last_msgtime; /* = 0 */
-	static int count;		   /* = 0 */
-	int i;
+	byte stat;
+	ide_hwif_t *hwif = hwgroup->hwif;
 
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		struct ata_channel *ch = &ide_hwifs[i];
-		int j;
-		struct ata_device *drive;
+	/*
+	 * handle the unexpected interrupt
+	 */
+	do {
+		if (hwif->irq == irq) {
+			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+				/* Try to not flood the console with msgs */
+				static unsigned long last_msgtime, count;
+				++count;
+				if (time_after(jiffies, last_msgtime + HZ)) {
+					last_msgtime = jiffies;
+					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
+					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
+				}
+			}
+		}
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+}
 
-		if (!ch->present || ch->irq != irq)
-			continue;
+/*
+ * entry point for all interrupts, caller does __cli() for us
+ */
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	ide_handler_t *handler;
+	ide_startstop_t startstop;
 
-		for (j = 0; j < MAX_DRIVES; ++j) {
-			drive = &ch->drives[j];
+	spin_lock_irqsave(&ide_lock, flags);
+	hwif = hwgroup->hwif;
 
-			/* this drive is idle */
-			if (ata_status(drive, READY_STAT, BAD_STAT))
-				continue;
+	if (!ide_ack_intr(hwif)) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return;
+	}
 
-			++count;
+	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
+		/*
+		 * Not expecting an interrupt from this drive.
+		 * That means this could be:
+		 *	(1) an interrupt from another PCI device
+		 *	sharing the same PCI INT# as us.
+		 * or	(2) a drive just entered sleep or standby mode,
+		 *	and is interrupting to let us know.
+		 * or	(3) a spurious interrupt of unknown origin.
+		 *
+		 * For PCI, we cannot tell the difference,
+		 * so in that case we just ignore it and hope it goes away.
+		 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		{
+			/*
+			 * Probably not a shared PCI interrupt,
+			 * so we can safely try to do something about it:
+			 */
+			unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		} else {
+			/*
+			 * Whack the status register, just in case
+			 * we have a leftover pending IRQ.
+			 */
+			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+		}
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return;
+	}
+	drive = hwgroup->drive;
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much
+		 * we could do about it here.
+		 */
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return;
+	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with
+		 * another device.  Unfortunately, it can also happen
+		 * with some buggy drives that trigger the IRQ before
+		 * their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return;
+	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
+	hwgroup->handler = NULL;
+	del_timer(&hwgroup->timer);
+	spin_unlock(&ide_lock);
 
-			/* don't report too frequently */
-			if (!time_after(jiffies, last_msgtime + HZ))
-				continue;
+	if (drive->unmask)
+		local_irq_enable();
+	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
+	spin_lock_irq(&ide_lock);
 
-			last_msgtime = jiffies;
-			printk("%s: unexpected interrupt, status=0x%02x, count=%d\n",
-					ch->name, drive->status, count);
+	/*
+	 * Note that handler() may have set things up for another
+	 * interrupt to occur soon, but it cannot happen until
+	 * we exit from this routine, because it will be the
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
+	 */
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup, hwif->irq);
+		} else {
+			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
 		}
 	}
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
- * Entry point for all interrupts. Aussumes disabled IRQs.
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
  */
-void ata_irq_request(int irq, void *data, struct pt_regs *regs)
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
-	struct ata_channel *ch = data;
-	unsigned long flags;
-	struct ata_device *drive;
-	ata_handler_t *handler;
-	ide_startstop_t ret;
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	if (!ide_ack_intr(ch))
-		goto out_lock;
-
-	handler = ch->handler;
-	drive = ch->drive;
-	if (!handler || ch->poll_timeout) {
+	int		major = major(i_rdev);
 #if 0
-		printk(KERN_INFO "ide: unexpected interrupt %d %d\n", ch->unit, irq);
+	int		minor = minor(i_rdev) & PARTN_MASK;
 #endif
+	unsigned int	h;
 
-		/*
-		 * Not expecting an interrupt from this drive.  That means this
-		 * could be:
-		 *
-		 * - an interrupt from another PCI device sharing the same PCI
-		 * INT# as us.
-		 *
-		 * - a drive just entered sleep or standby mode, and is
-		 * interrupting to let us know.
-		 *
-		 * - a spurious interrupt of unknown origin.
-		 *
-		 * For PCI, we cannot tell the difference, so in that case we
-		 * just clear it and hope it goes away.
-		 */
-
-#ifdef CONFIG_PCI
-		if (ch->pci_dev && !ch->pci_dev->vendor)
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t  *hwif = &ide_hwifs[h];
+		if (hwif->present && major == hwif->major) {
+			unsigned unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				ide_drive_t *drive = &hwif->drives[unit];
+#if 0
+				if ((drive->present) && (drive->part[minor].nr_sects))
+#else
+				if (drive->present)
 #endif
-			unexpected_irq(irq);
-#ifdef CONFIG_PCI
-		else
-			ata_status(drive, READY_STAT, BAD_STAT);
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_cmd (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->flags = REQ_DRIVE_CMD;
+}
+
+/*
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * If action is ide_wait, then the rq is queued at the end of the
+ * request queue, and the function sleeps until it has been processed.
+ * This is for use when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then the rq is queued at the head of
+ * the request queue, displacing the currently-being-processed
+ * request and this function returns immediately without waiting
+ * for the new rq to be completed.  This is VERY DANGEROUS, and is
+ * intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_next, then the rq is queued immediately after
+ * the currently-being-processed-request (if any), and the function
+ * returns without waiting for the new rq to be completed.  As above,
+ * This is VERY DANGEROUS, and is intended for careful use by the
+ * ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code.
+ */
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	request_queue_t *q = &drive->queue;
+	struct list_head *queue_head = &q->queue_head;
+	DECLARE_COMPLETION(wait);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+		return -ENOSYS;  /* special drive cmds not supported */
 #endif
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS);
+	if (action == ide_wait)
+		rq->waiting = &wait;
+	spin_lock_irqsave(&ide_lock, flags);
+	if (blk_queue_empty(q) || action == ide_preempt) {
+		if (action == ide_preempt)
+			hwgroup->rq = NULL;
+	} else {
+		if (action == ide_wait || action == ide_end) {
+			queue_head = queue_head->prev;
+		} else
+			queue_head = queue_head->next;
+	}
+	q->elevator.elevator_add_req_fn(q, rq, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	if (action == ide_wait) {
+		wait_for_completion(&wait);	/* wait for it to be serviced */
+		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+	}
+	return 0;
+
+}
+
+void ide_revalidate_drive (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int unit = drive - hwif->drives;
+	struct gendisk *g = hwif->gd[unit];
+	int minor = (drive->select.b.unit << g->minor_shift);
+
+	grok_partitions(mk_kdev(g->major, minor), current_capacity(drive));
+}
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+int ide_revalidate_disk (kdev_t i_rdev)
+{
+	ide_drive_t *drive;
+	ide_hwgroup_t *hwgroup;
+	unsigned long flags;
+	int res;
+
+	if ((drive = get_info_ptr(i_rdev)) == NULL)
+		return -ENODEV;
+	hwgroup = HWGROUP(drive);
+	spin_lock_irqsave(&ide_lock, flags);
+	if (drive->busy || (drive->usage > 1)) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return -EBUSY;
+	};
+	drive->busy = 1;
+	MOD_INC_USE_COUNT;
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	res = wipe_partitions(i_rdev);
+
+	if (!res && DRIVER(drive)->revalidate)
+		DRIVER(drive)->revalidate(drive);
+
+	drive->busy = 0;
+	wake_up(&drive->wqueue);
+	MOD_DEC_USE_COUNT;
+	return res;
+}
 
-		goto out_lock;
+static void revalidate_drives (void)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int index, unit;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &ide_hwifs[index].drives[unit];
+			if (drive->revalidate) {
+				drive->revalidate = 0;
+				if (!initializing)
+					(void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
+			}
+		}
 	}
-	if (!ata_status_irq(drive)) {
-		/* This happens regularly when we share a PCI IRQ with another device.
-		 * Unfortunately, it can also happen with some buggy drives that trigger
-		 * the IRQ before their status register is up to date.  Hopefully we have
-		 * enough advance overhead that the latter isn't a problem.
-		 */
+}
+
+static void ide_probe_module (void)
+{
+	if (!ide_probe) {
+#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
+		(void) request_module("ide-probe-mod");
+#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
+	} else {
+		(void) ide_probe->init();
+	}
+	revalidate_drives();
+}
 
-		goto out_lock;
+static void ide_driver_module (void)
+{
+	int index;
+	ide_module_t *module = ide_modules;
+
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (ide_hwifs[index].present)
+			goto search;
+	ide_probe_module();
+search:
+	while (module) {
+		(void) module->init();
+		module = module->next;
 	}
+	revalidate_drives();
+}
 
-	/* paranoia */
-	if (!test_and_set_bit(IDE_BUSY, ch->active))
-		printk(KERN_ERR "%s: %s: channel was not busy!?\n", drive->name, __FUNCTION__);
+static int ide_open (struct inode * inode, struct file * filp)
+{
+	ide_drive_t *drive;
 
-	ch->handler = NULL;
-	del_timer(&ch->timer);
+	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
+		return -ENXIO;
+	if (drive->driver == NULL)
+		ide_driver_module();
+#ifdef CONFIG_KMOD
+	if (drive->driver == NULL) {
+		if (drive->media == ide_disk)
+			(void) request_module("ide-disk");
+		if (drive->media == ide_cdrom)
+			(void) request_module("ide-cd");
+		if (drive->media == ide_tape)
+			(void) request_module("ide-tape");
+		if (drive->media == ide_floppy)
+			(void) request_module("ide-floppy");
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+		if (drive->media == ide_scsi)
+			(void) request_module("ide-scsi");
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+	}
+#endif /* CONFIG_KMOD */
+	while (drive->busy)
+		sleep_on(&drive->wqueue);
+	drive->usage++;
+	if (drive->driver != NULL)
+		return DRIVER(drive)->open(inode, filp, drive);
+	printk ("%s: driver not present\n", drive->name);
+	drive->usage--;
+	return -ENXIO;
+}
 
-	spin_unlock(ch->lock);
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static int ide_release (struct inode * inode, struct file * file)
+{
+	ide_drive_t *drive;
 
-	if (ch->unmask)
-		local_irq_enable();
+	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
+		drive->usage--;
+		if (drive->driver != NULL)
+			DRIVER(drive)->release(inode, file, drive);
+	}
+	return 0;
+}
+
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->busy || drive->usage)
+		goto abort;
+	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	ide_driver_module();
+	drive->driver_req[0] = 0;
+	ide_driver_module();
+	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+#ifdef CONFIG_PROC_FS
+ide_proc_entry_t generic_subdriver_entries[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#endif
+
+/*
+ * Note that we only release the standard ports,
+ * and do not even try to handle any extra ports
+ * allocated for weird IDE interface chipsets.
+ */
+void hwif_unregister (ide_hwif_t *hwif)
+{
+	if (hwif->straight8) {
+		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		goto jump_eight;
+	}
+	if (hwif->io_ports[IDE_DATA_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	if (hwif->io_ports[IDE_ERROR_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+	if (hwif->io_ports[IDE_SECTOR_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+	if (hwif->io_ports[IDE_LCYL_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+	if (hwif->io_ports[IDE_HCYL_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+	if (hwif->io_ports[IDE_SELECT_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+	if (hwif->io_ports[IDE_STATUS_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+jump_eight:
+	if (hwif->io_ports[IDE_CONTROL_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (hwif->io_ports[IDE_IRQ_OFFSET])
+		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+}
 
+void ide_unregister (unsigned int index)
+{
+	struct gendisk *gd;
+	ide_drive_t *drive, *d;
+	ide_hwif_t *hwif, *g;
+	ide_hwgroup_t *hwgroup;
+	int irq_count = 0, unit, i;
+	unsigned long flags;
+	unsigned int p, minor;
+	ide_hwif_t old_hwif;
+
+	if (index >= MAX_HWIFS)
+		return;
+	spin_lock_irqsave(&ide_lock, flags);
+	hwif = &ide_hwifs[index];
+	if (!hwif->present)
+		goto abort;
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
+		if (drive->busy || drive->usage)
+			goto abort;
+		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+			goto abort;
+	}
+	hwif->present = 0;
+	
 	/*
-	 * Service this interrupt, this may setup handler for next interrupt.
+	 * All clear?  Then blow away the buffer cache
 	 */
-	ret = handler(drive, drive->rq);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
+		minor = drive->select.b.unit << PARTN_BITS;
+		for (p = 0; p < (1<<PARTN_BITS); ++p) {
+			if (drive->part[p].nr_sects > 0) {
+				kdev_t devp = mk_kdev(hwif->major, minor+p);
+				invalidate_device(devp, 0);
+			}
+		}
+#ifdef CONFIG_PROC_FS
+		destroy_proc_ide_drives(hwif);
+#endif
+	}
+	spin_lock_irqsave(&ide_lock, flags);
+	hwgroup = hwif->hwgroup;
 
-	spin_lock_irq(ch->lock);
+	/*
+	 * free the irq if we were the only hwif using it
+	 */
+	g = hwgroup->hwif;
+	do {
+		if (g->irq == hwif->irq)
+			++irq_count;
+		g = g->next;
+	} while (g != hwgroup->hwif);
+	if (irq_count == 1)
+		ide_free_irq(hwif->irq, hwgroup);
 
 	/*
-	 * Note that handler() may have set things up for another interrupt to
-	 * occur soon, but it cannot happen until we exit from this routine,
-	 * because it will be the same irq as is currently being serviced here,
-	 * and Linux won't allow another of the same (on any CPU) until we
-	 * return.
+	 * Note that we only release the standard ports,
+	 * and do not even try to handle any extra ports
+	 * allocated for weird IDE interface chipsets.
 	 */
+	hwif_unregister(hwif);
 
-	if (ret == ATA_OP_FINISHED) {
+	/*
+	 * Remove us from the hwgroup, and free
+	 * the hwgroup if we were the only member
+	 */
+	d = hwgroup->drive;
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		drive = &hwif->drives[i];
+		if (drive->de) {
+			devfs_unregister (drive->de);
+			drive->de = NULL;
+		}
+		if (!drive->present)
+			continue;
+		while (hwgroup->drive->next != drive)
+			hwgroup->drive = hwgroup->drive->next;
+		hwgroup->drive->next = drive->next;
+		if (hwgroup->drive == drive)
+			hwgroup->drive = NULL;
+		if (drive->id != NULL) {
+			kfree(drive->id);
+			drive->id = NULL;
+		}
+		drive->present = 0;
+		blk_cleanup_queue(&drive->queue);
+	}
+	if (d->present)
+		hwgroup->drive = d;
+	while (hwgroup->hwif->next != hwif)
+		hwgroup->hwif = hwgroup->hwif->next;
+	hwgroup->hwif->next = hwif->next;
+	if (hwgroup->hwif == hwif)
+		kfree(hwgroup);
+	else
+		hwgroup->hwif = HWIF(hwgroup->drive);
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (hwif->dma_base) {
+		(void) ide_release_dma(hwif);
+		hwif->dma_base = 0;
+	}
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
 
-		/* Reenter the request handling engine if we are not expecting
-		 * another interrupt.
-		 */
+	/*
+	 * Remove us from the kernel's knowledge
+	 */
+	unregister_blkdev(hwif->major, hwif->name);
+	blk_dev[hwif->major].data = NULL;
+	blk_dev[hwif->major].queue = NULL;
+	blk_clear(hwif->major);
+	gd = hwif->gd[0];
+	if (gd) {
+		int i;
+		for (i = 0; i < MAX_DRIVES; i++)
+			del_gendisk(gd + i);
+		kfree(gd->part);
+		if (gd->de_arr)
+			kfree (gd->de_arr);
+		if (gd->flags)
+			kfree (gd->flags);
+		kfree(gd);
+		for (i = 0; i < MAX_DRIVES; i++)
+			hwif->gd[i] = NULL;
+	}
+	old_hwif		= *hwif;
+	init_hwif_data (index);	/* restore hwif data to pristine status */
+	hwif->hwgroup		= old_hwif.hwgroup;
+	hwif->tuneproc		= old_hwif.tuneproc;
+	hwif->speedproc		= old_hwif.speedproc;
+	hwif->selectproc	= old_hwif.selectproc;
+	hwif->resetproc		= old_hwif.resetproc;
+	hwif->intrproc		= old_hwif.intrproc;
+	hwif->maskproc		= old_hwif.maskproc;
+	hwif->quirkproc		= old_hwif.quirkproc;
+	hwif->rwproc		= old_hwif.rwproc;
+	hwif->ideproc		= old_hwif.ideproc;
+	hwif->dmaproc		= old_hwif.dmaproc;
+	hwif->busproc		= old_hwif.busproc;
+	hwif->bus_state		= old_hwif.bus_state;
+	hwif->dma_base		= old_hwif.dma_base;
+	hwif->dma_extra		= old_hwif.dma_extra;
+	hwif->config_data	= old_hwif.config_data;
+	hwif->select_data	= old_hwif.select_data;
+	hwif->proc		= old_hwif.proc;
+#ifndef CONFIG_BLK_DEV_IDECS
+	hwif->irq		= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
+	hwif->major		= old_hwif.major;
+	hwif->chipset		= old_hwif.chipset;
+	hwif->autodma		= old_hwif.autodma;
+	hwif->udma_four		= old_hwif.udma_four;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	hwif->pci_dev		= old_hwif.pci_dev;
+	hwif->pci_devid		= old_hwif.pci_devid;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	hwif->straight8		= old_hwif.straight8;
+	hwif->hwif_data		= old_hwif.hwif_data;
+abort:
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
 
-		if (!ch->handler) {
-			clear_bit(IDE_BUSY, ch->active);
-			do_ide_request(&drive->queue);
-		} else
-			printk("%s: %s: huh? expected NULL handler on exit\n",
-					drive->name, __FUNCTION__);
+/*
+ * Setup hw_regs_t structure described by parameters.  You
+ * may set up the hw structure yourself OR use this routine to
+ * do it for you.
+ */
+void ide_setup_ports (	hw_regs_t *hw,
+			ide_ioreg_t base, int *offsets,
+			ide_ioreg_t ctrl, ide_ioreg_t intr,
+			ide_ack_intr_t *ack_intr, int irq)
+{
+	int i;
+
+	for (i = 0; i < IDE_NR_PORTS; i++) {
+		if (offsets[i] == -1) {
+			switch(i) {
+				case IDE_CONTROL_OFFSET:
+					hw->io_ports[i] = ctrl;
+					break;
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+				case IDE_IRQ_OFFSET:
+					hw->io_ports[i] = intr;
+					break;
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+				default:
+					hw->io_ports[i] = 0;
+					break;
+			}
+		} else {
+			hw->io_ports[i] = base + offsets[i];
+		}
 	}
+	hw->irq = irq;
+	hw->dma = NO_DMA;
+	hw->ack_intr = ack_intr;
+}
+
+/*
+ * Register an IDE interface, specifing exactly the registers etc
+ * Set init=1 iff calling before probes have taken place.
+ */
+int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
+{
+	int index, retry = 1;
+	ide_hwif_t *hwif;
 
-out_lock:
-	spin_unlock_irqrestore(ch->lock, flags);
+	do {
+		for (index = 0; index < MAX_HWIFS; ++index) {
+			hwif = &ide_hwifs[index];
+			if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
+				goto found;
+		}
+		for (index = 0; index < MAX_HWIFS; ++index) {
+			hwif = &ide_hwifs[index];
+			if ((!hwif->present && !hwif->mate && !initializing) ||
+			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
+				goto found;
+		}
+		for (index = 0; index < MAX_HWIFS; index++)
+			ide_unregister(index);
+	} while (retry--);
+	return -1;
+found:
+	if (hwif->present)
+		ide_unregister(index);
+	if (hwif->present)
+		return -1;
+	memcpy(&hwif->hw, hw, sizeof(*hw));
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+	hwif->irq = hw->irq;
+	hwif->noprobe = 0;
+	hwif->chipset = hw->chipset;
+
+	if (!initializing) {
+		ide_probe_module();
+#ifdef CONFIG_PROC_FS
+		create_proc_ide_interfaces();
+#endif
+		ide_driver_module();
+	}
+
+	if (hwifp)
+		*hwifp = hwif;
+
+	return (initializing || hwif->present) ? index : -1;
 }
 
-static int ide_open(struct inode * inode, struct file * filp)
+/*
+ * Compatability function with existing drivers.  If you want
+ * something different, use the function above.
+ */
+int ide_register (int arg1, int arg2, int irq)
 {
-	struct ata_device *drive;
+	hw_regs_t hw;
+	ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+	hw.irq = irq;
+	return ide_register_hw(&hw, NULL);
+}
 
-	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
-		return -ENXIO;
+void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
-	/* Request a particular device type module.
-	 *
-	 * FIXME: The function which should rather requests the drivers is
-	 * ide_driver_module(), since it seems illogical and even a bit
-	 * dangerous to postpone this until open time!
-	 */
+	while ((*p) && strcmp((*p)->name, name) < 0)
+		p = &((*p)->next);
+	if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+		goto abort;
+	memset(setting, 0, sizeof(*setting));
+	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
+		goto abort;
+	strcpy(setting->name, name);		setting->rw = rw;
+	setting->read_ioctl = read_ioctl;	setting->write_ioctl = write_ioctl;
+	setting->data_type = data_type;		setting->min = min;
+	setting->max = max;			setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;	setting->data = data;
+	setting->set = set;			setting->next = *p;
+	if (drive->driver)
+		setting->auto_remove = 1;
+	*p = setting;
+	return;
+abort:
+	if (setting)
+		kfree(setting);
+}
 
-#ifdef CONFIG_KMOD
-	if (!drive->driver) {
-		char *module = NULL;
+void ide_remove_setting (ide_drive_t *drive, char *name)
+{
+	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
 
-		switch (drive->type) {
-			case ATA_DISK:
-				module = "ide-disk";
-				break;
-			case ATA_ROM:
-				module = "ide-cd";
-				break;
-			case ATA_TAPE:
-				module = "ide-tape";
+	while ((*p) && strcmp((*p)->name, name))
+		p = &((*p)->next);
+	if ((setting = (*p)) == NULL)
+		return;
+	(*p) = setting->next;
+	kfree(setting->name);
+	kfree(setting);
+}
+
+static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
+{
+	ide_settings_t *setting = drive->settings;
+
+	while (setting) {
+		if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
+			break;
+		setting = setting->next;
+	}
+	return setting;
+}
+
+ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
+{
+	ide_settings_t *setting = drive->settings;
+
+	while (setting) {
+		if (strcmp(setting->name, name) == 0)
+			break;
+		setting = setting->next;
+	}
+	return setting;
+}
+
+static void auto_remove_settings (ide_drive_t *drive)
+{
+	ide_settings_t *setting;
+repeat:
+	setting = drive->settings;
+	while (setting) {
+		if (setting->auto_remove) {
+			ide_remove_setting(drive, setting->name);
+			goto repeat;
+		}
+		setting = setting->next;
+	}
+}
+
+int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
+{
+	int		val = -EINVAL;
+	unsigned long	flags;
+
+	if ((setting->rw & SETTING_READ)) {
+		spin_lock_irqsave(&ide_lock, flags);
+		switch(setting->data_type) {
+			case TYPE_BYTE:
+				val = *((u8 *) setting->data);
 				break;
-			case ATA_FLOPPY:
-				module = "ide-floppy";
+			case TYPE_SHORT:
+				val = *((u16 *) setting->data);
 				break;
-			case ATA_SCSI:
-				module = "ide-scsi";
+			case TYPE_INT:
+			case TYPE_INTA:
+				val = *((u32 *) setting->data);
 				break;
-			default:
-				/* nothing we can do about it */ ;
 		}
-		if (module)
-			request_module(module);
+		spin_unlock_irqrestore(&ide_lock, flags);
+	}
+	return val;
+}
+
+int ide_spin_wait_hwgroup (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned long timeout = jiffies + (3 * HZ);
+
+	spin_lock_irq(&ide_lock);
+
+	while (hwgroup->busy) {
+		unsigned long lflags;
+		spin_unlock_irq(&ide_lock);
+		local_irq_set(lflags);
+		if (time_after(jiffies, timeout)) {
+			local_irq_restore(lflags);
+			printk("%s: channel busy\n", drive->name);
+			return -EBUSY;
+		}
+		local_irq_restore(lflags);
+		spin_lock_irq(&ide_lock);
+	}
+	return 0;
+}
+
+/*
+ * FIXME:  This should be changed to enqueue a special request
+ * to the driver to change settings, and then wait on a sema for completion.
+ * The current scheme of polling is kludgey, though safe enough.
+ */
+int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
+{
+	int i;
+	u32 *p;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (!(setting->rw & SETTING_WRITE))
+		return -EPERM;
+	if (val < setting->min || val > setting->max)
+		return -EINVAL;
+	if (setting->set)
+		return setting->set(drive, val);
+	if (ide_spin_wait_hwgroup(drive))
+		return -EBUSY;
+	switch (setting->data_type) {
+		case TYPE_BYTE:
+			*((u8 *) setting->data) = val;
+			break;
+		case TYPE_SHORT:
+			*((u16 *) setting->data) = val;
+			break;
+		case TYPE_INT:
+			*((u32 *) setting->data) = val;
+			break;
+		case TYPE_INTA:
+			p = (u32 *) setting->data;
+			for (i = 0; i < 1 << PARTN_BITS; i++, p++)
+				*p = val;
+			break;
 	}
+	spin_unlock_irq(&ide_lock);
+	return 0;
+}
+
+static int set_io_32bit(ide_drive_t *drive, int arg)
+{
+	drive->io_32bit = arg;
+#ifdef CONFIG_BLK_DEV_DTC2278
+	if (HWIF(drive)->chipset == ide_dtc2278)
+		HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+#endif /* CONFIG_BLK_DEV_DTC2278 */
+	return 0;
+}
+
+static int set_using_dma (ide_drive_t *drive, int arg)
+{
+	if (!drive->driver || !DRIVER(drive)->supports_dma)
+		return -EPERM;
+	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+		return -EPERM;
+	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+		return -EIO;
+	return 0;
+}
+
+static int set_pio_mode (ide_drive_t *drive, int arg)
+{
+	struct request rq;
+
+	if (!HWIF(drive)->tuneproc)
+		return -ENOSYS;
+	if (drive->special.b.set_tune)
+		return -EBUSY;
+	ide_init_drive_cmd(&rq);
+	drive->tune_req = (byte) arg;
+	drive->special.b.set_tune = 1;
+	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	return 0;
+}
+
+void ide_add_generic_settings (ide_drive_t *drive)
+{
+/*
+ *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
+ */
+	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
+	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
+	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
+	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
+	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
+	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
+	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
+	ide_add_setting(drive,	"ide_scsi",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			NULL);
+	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
+	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		NULL);
+	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
+}
+
+int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
+{
+	struct request rq;
+	byte buffer[4];
+
+	if (!buf)
+		buf = buffer;
+	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = cmd;
+	*buf++ = nsect;
+	*buf++ = feature;
+	*buf++ = sectors;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
+{
+	struct request rq;
+
+	ide_init_drive_cmd(&rq);
+	rq.flags = REQ_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+/*
+ * Delay for *at least* 50ms.  As we don't know how much time is left
+ * until the next tick occurs, we wait an extra tick to be safe.
+ * This is used only during the probing/polling for drives at boot time.
+ *
+ * However, its usefullness may be needed in other places, thus we export it now.
+ * The future may change this to a millisecond setable delay.
+ */
+void ide_delay_50ms (void)
+{
+#ifndef CONFIG_BLK_DEV_IDECS
+	mdelay(50);
+#else
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/20);
+#endif /* CONFIG_BLK_DEV_IDECS */
+}
+
+int system_bus_clock (void)
+{
+	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
+}
+
+int ide_reinit_drive (ide_drive_t *drive)
+{
+	switch (drive->media) {
+#ifdef CONFIG_BLK_DEV_IDECD
+		case ide_cdrom:
+		{
+			extern int ide_cdrom_reinit(ide_drive_t *drive);
+			if (ide_cdrom_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+		case ide_disk:
+		{
+			extern int idedisk_reinit(ide_drive_t *drive);
+			if (idedisk_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+		case ide_floppy:
+		{
+			extern int idefloppy_reinit(ide_drive_t *drive);
+			if (idefloppy_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+		case ide_tape:
+		{
+			extern int idetape_reinit(ide_drive_t *drive);
+			if (idetape_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+/*
+ *              {
+ *                      extern int idescsi_reinit(ide_drive_t *drive);
+ *                      if (idescsi_reinit(drive))
+ *                              return 1;
+ *                      break;
+ * }
+ */
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+		default:
+			return 1;
+	}
+	return 0;
+}
+
+static int ide_ioctl (struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int err = 0, major, minor;
+	ide_drive_t *drive;
+	struct request rq;
+	kdev_t dev;
+	ide_settings_t *setting;
+
+	major = major(dev); minor = minor(dev);
+	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
+		return -ENODEV;
+
+	if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
+		if (cmd == setting->read_ioctl) {
+			err = ide_read_setting(drive, setting);
+			return err >= 0 ? put_user(err, (long *) arg) : err;
+		} else {
+			if ((minor(inode->i_rdev) & PARTN_MASK))
+				return -EINVAL;
+			return ide_write_setting(drive, setting, arg);
+		}
+	}
+
+	ide_init_drive_cmd (&rq);
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG_RAW:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			return ide_revalidate_disk(inode->i_rdev);
+
+		case HDIO_OBSOLETE_IDENTITY:
+		case HDIO_GET_IDENTITY:
+			if (minor(inode->i_rdev) & PARTN_MASK)
+				return -EINVAL;
+			if (drive->id == NULL)
+				return -ENOMSG;
+			if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+				return -EFAULT;
+			return 0;
+
+		case HDIO_GET_NICE:
+			return put_user(drive->dsc_overlap	<<	IDE_NICE_DSC_OVERLAP	|
+					drive->atapi_overlap	<<	IDE_NICE_ATAPI_OVERLAP	|
+					drive->nice0		<< 	IDE_NICE_0		|
+					drive->nice1		<<	IDE_NICE_1		|
+					drive->nice2		<<	IDE_NICE_2,
+					(long *) arg);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+		case HDIO_DRIVE_TASKFILE:
+		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			switch(drive->media) {
+				case ide_disk:
+					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
+#ifdef CONFIG_PKT_TASK_IOCTL
+				case ide_cdrom:
+				case ide_tape:
+				case ide_floppy:
+					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
+				default:
+					return -ENOMSG;
+			}
+#endif /* CONFIG_IDE_TASK_IOCTL */
+
+		case HDIO_DRIVE_CMD:
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
+
+		case HDIO_DRIVE_TASK:
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
+		case HDIO_SCAN_HWIF:
+		{
+			int args[3];
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (copy_from_user(args, (void *)arg, 3 * sizeof(int)))
+				return -EFAULT;
+			if (ide_register(args[0], args[1], args[2]) == -1)
+				return -EIO;
+			return 0;
+		}
+	        case HDIO_UNREGISTER_HWIF:
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			/* (arg > MAX_HWIFS) checked in function */
+			ide_unregister(arg);
+			return 0;
+		case HDIO_SET_NICE:
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (drive->driver == NULL)
+				return -EPERM;
+			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+				return -EPERM;
+			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
+			if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+				drive->dsc_overlap = 0;
+				return -EPERM;
+			}
+			drive->nice1 = (arg >> IDE_NICE_1) & 1;
+			return 0;
+		case HDIO_DRIVE_RESET:
+		{
+			unsigned long flags;
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#if 1
+			spin_lock_irqsave(&ide_lock, flags);
+			if ( HWGROUP(drive)->handler != NULL) {
+				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
+				(void) HWGROUP(drive)->handler(drive);
+//				HWGROUP(drive)->handler = NULL;
+				HWGROUP(drive)->expiry	= NULL;
+				del_timer(&HWGROUP(drive)->timer);
+			}
+			spin_unlock_irqrestore(&ide_lock, flags);
+
 #endif
+			(void) ide_do_reset(drive);
+			if (drive->suspend_reset) {
+/*
+ *				APM WAKE UP todo !!
+ *				int nogoodpower = 1;
+ *				while(nogoodpower) {
+ *					check_power1() or check_power2()
+ *					nogoodpower = 0;
+ *				} 
+ *				HWIF(drive)->multiproc(drive);
+ */
+				return ide_revalidate_disk(inode->i_rdev);
+			}
+			return 0;
+		}
+		case BLKGETSIZE:
+		case BLKGETSIZE64:
+		case BLKROSET:
+		case BLKROGET:
+		case BLKFLSBUF:
+		case BLKSSZGET:
+		case BLKPG:
+		case BLKELVGET:
+		case BLKELVSET:
+		case BLKBSZGET:
+		case BLKBSZSET:
+			return blk_ioctl(inode->i_bdev, cmd, arg);
+
+		case CDROMEJECT:
+		case CDROMCLOSETRAY:
+			return block_ioctl(inode->i_bdev, cmd, arg);
+
+		case HDIO_GET_BUSSTATE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (put_user(HWIF(drive)->bus_state, (long *)arg))
+				return -EFAULT;
+			return 0;
+
+		case HDIO_SET_BUSSTATE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (HWIF(drive)->busproc)
+				HWIF(drive)->busproc(drive, (int)arg);
+			return 0;
+
+		default:
+			if (drive->driver != NULL)
+				return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
+			return -EPERM;
+	}
+}
 
-	if (drive->driver == NULL)
-		ide_driver_module();
+static int ide_check_media_change (kdev_t i_rdev)
+{
+	ide_drive_t *drive;
 
-	++drive->usage;
-	if (ata_ops(drive) && ata_ops(drive)->open)
-		return ata_ops(drive)->open(inode, filp, drive);
-	else {
-		--drive->usage;
+	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
+	if (drive->driver != NULL)
+		return DRIVER(drive)->media_change(drive);
+	return 0;
+}
+
+void ide_fixstring (byte *s, const int bytecount, const int byteswap)
+{
+	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+	if (byteswap) {
+		/* convert from big-endian to host byte order */
+		for (p = end ; p != s;) {
+			unsigned short *pp = (unsigned short *) (p -= 2);
+			*pp = ntohs(*pp);
+		}
 	}
 
-	printk(KERN_INFO "%s: driver not present\n", drive->name);
-	--drive->usage;
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
+	}
 
-	return -ENXIO;
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
 }
 
 /*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
+ * stridx() returns the offset of c within s,
+ * or -1 if c is '\0' or not found within s.
+ */
+static int __init stridx (const char *s, char c)
+{
+	char *i = strchr(s, c);
+	return (i && c) ? i - s : -1;
+}
+
+/*
+ * match_parm() does parsing for ide_setup():
+ *
+ * 1. the first char of s must be '='.
+ * 2. if the remainder matches one of the supplied keywords,
+ *     the index (1 based) of the keyword is negated and returned.
+ * 3. if the remainder is a series of no more than max_vals numbers
+ *     separated by commas, the numbers are saved in vals[] and a
+ *     count of how many were saved is returned.  Base10 is assumed,
+ *     and base16 is allowed when prefixed with "0x".
+ * 4. otherwise, zero is returned.
  */
-static int ide_release(struct inode * inode, struct file * file)
+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
 {
-	struct ata_device *drive;
+	static const char *decimal = "0123456789";
+	static const char *hex = "0123456789abcdef";
+	int i, n;
 
-	if (!(drive = get_info_ptr(inode->i_rdev)))
+	if (*s++ == '=') {
+		/*
+		 * Try matching against the supplied keywords,
+		 * and return -(index+1) if we match one
+		 */
+		if (keywords != NULL) {
+			for (i = 0; *keywords != NULL; ++i) {
+				if (!strcmp(s, *keywords++))
+					return -(i+1);
+			}
+		}
+		/*
+		 * Look for a series of no more than "max_vals"
+		 * numeric values separated by commas, in base10,
+		 * or base16 when prefixed with "0x".
+		 * Return a count of how many were found.
+		 */
+		for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
+			vals[n] = i;
+			while ((i = stridx(decimal, *++s)) >= 0)
+				vals[n] = (vals[n] * 10) + i;
+			if (*s == 'x' && !vals[n]) {
+				while ((i = stridx(hex, *++s)) >= 0)
+					vals[n] = (vals[n] * 0x10) + i;
+			}
+			if (++n == max_vals)
+				break;
+			if (*s == ',' || *s == ';')
+				++s;
+		}
+		if (!*s)
+			return n;
+	}
+	return 0;	/* zero = nothing matched */
+}
+
+/*
+ * ide_setup() gets called VERY EARLY during initialization,
+ * to handle kernel "command line" strings beginning with "hdx="
+ * or "ide".  Here is the complete set currently supported:
+ *
+ * "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
+ * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
+ *
+ * "hdx=noprobe"	: drive may be present, but do not probe for it
+ * "hdx=none"		: drive is NOT present, ignore cmos and do not probe
+ * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
+ * "hdx=cdrom"		: drive is present, and is a cdrom drive
+ * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+ * "hdx=noremap"	: do not remap 0->1 even though EZD was detected
+ * "hdx=autotune"	: driver will attempt to tune interface speed
+ *				to the fastest PIO mode supported,
+ *				if possible for this drive only.
+ *				Not fully supported by all chipset types,
+ *				and quite likely to cause trouble with
+ *				older/odd IDE drives.
+ *
+ * "hdx=slow"		: insert a huge pause after each access to the data
+ *				port. Should be used only as a last resort.
+ *
+ * "hdx=swapdata"	: when the drive is a disk, byte swap all data
+ * "hdx=bswap"		: same as above..........
+ * "hdxlun=xx"          : set the drive last logical unit.
+ * "hdx=flash"		: allows for more than one ata_flash disk to be
+ *				registered. In most cases, only one device
+ *				will be present.
+ * "hdx=scsi"		: the return of the ide-scsi flag, this is useful for
+ *				allowwing ide-floppy, ide-tape, and ide-cdrom|writers
+ *				to use ide-scsi emulation on a device specific option.
+ * "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in MHz,
+ *				where "xx" is between 20 and 66 inclusive,
+ *				used when tuning chipset PIO modes.
+ *				For PCI bus, 25 is correct for a P75 system,
+ *				30 is correct for P90,P120,P180 systems,
+ *				and 33 is used for P100,P133,P166 systems.
+ *				If in doubt, use idebus=33 for PCI.
+ *				As for VLB, it is safest to not specify it.
+ *
+ * "idex=noprobe"	: do not attempt to access/use this interface
+ * "idex=base"		: probe for an interface at the addr specified,
+ *				where "base" is usually 0x1f0 or 0x170
+ *				and "ctl" is assumed to be "base"+0x206
+ * "idex=base,ctl"	: specify both base and ctl
+ * "idex=base,ctl,irq"	: specify base, ctl, and irq number
+ * "idex=autotune"	: driver will attempt to tune interface speed
+ *				to the fastest PIO mode supported,
+ *				for all drives on this interface.
+ *				Not fully supported by all chipset types,
+ *				and quite likely to cause trouble with
+ *				older/odd IDE drives.
+ * "idex=noautotune"	: driver will NOT attempt to tune interface speed
+ *				This is the default for most chipsets,
+ *				except the cmd640.
+ * "idex=serialize"	: do not overlap operations on idex and ide(x^1)
+ * "idex=four"		: four drives on idex and ide(x^1) share same ports
+ * "idex=reset"		: reset interface before first use
+ * "idex=dma"		: enable DMA by default on both drives if possible
+ * "idex=ata66"		: informs the interface that it has an 80c cable
+ *				for chipsets that are ATA-66 capable, but
+ *				the ablity to bit test for detection is
+ *				currently unknown.
+ * "ide=reverse"	: Formerly called to pci sub-system, but now local.
+ *
+ * The following are valid ONLY on ide0, (except dc4030)
+ * and the defaults for the base,ctl ports must not be altered.
+ *
+ * "ide0=dtc2278"	: probe/support DTC2278 interface
+ * "ide0=ht6560b"	: probe/support HT6560B interface
+ * "ide0=cmd640_vlb"	: *REQUIRED* for VLB cards with the CMD640 chip
+ *			  (not for PCI -- automatically detected)
+ * "ide0=qd65xx"	: probe/support qd65xx interface
+ * "ide0=ali14xx"	: probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
+ * "ide0=umc8672"	: probe/support umc8672 chipsets
+ * "idex=dc4030"	: probe/support Promise DC4030VL interface
+ * "ide=doubler"	: probe/support IDE doublers on Amiga
+ */
+int __init ide_setup (char *s)
+{
+	int i, vals[3];
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	unsigned int hw, unit;
+	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
+	const char max_hwif  = '0' + (MAX_HWIFS - 1);
+
+	
+	if (strncmp(s,"hd",2) == 0 && s[2] == '=')	/* hd= is for hd.c   */
+		return 0;				/* driver and not us */
+
+	if (strncmp(s,"ide",3) &&
+	    strncmp(s,"idebus",6) &&
+	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
 		return 0;
 
+	printk("ide_setup: %s", s);
+	init_ide_data ();
+
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+	if (!strcmp(s, "ide=doubler")) {
+		extern int ide_doubler;
+
+		printk(" : Enabled support for IDE doublers\n");
+		ide_doubler = 1;
+		return 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+	if (!strcmp(s, "ide=nodma")) {
+		printk("IDE: Prevented DMA\n");
+		noautodma = 1;
+		return 1;
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	if (!strcmp(s, "ide=reverse")) {
+		ide_scan_direction = 1;
+		printk(" : Enabled support for IDE inverse scan order.\n");
+		return 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+	/*
+	 * Look for drive options:  "hdx="
+	 */
+	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
+		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
+				"serialize", "autotune", "noautotune",
+				"slow", "swapdata", "bswap", "flash",
+				"remap", "noremap", "scsi", NULL};
+		unit = s[2] - 'a';
+		hw   = unit / MAX_DRIVES;
+		unit = unit % MAX_DRIVES;
+		hwif = &ide_hwifs[hw];
+		drive = &hwif->drives[unit];
+		if (strncmp(s + 4, "ide-", 4) == 0) {
+			strncpy(drive->driver_req, s + 4, 9);
+			goto done;
+		}
+		/*
+		 * Look for last lun option:  "hdxlun="
+		 */
+		if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') {
+			if (match_parm(&s[6], NULL, vals, 1) != 1)
+				goto bad_option;
+			if (vals[0] >= 0 && vals[0] <= 7) {
+				drive->last_lun = vals[0];
+				drive->forced_lun = 1;
+			} else
+				printk(" -- BAD LAST LUN! Expected value from 0 to 7");
+			goto done;
+		}
+		switch (match_parm(&s[3], hd_words, vals, 3)) {
+			case -1: /* "none" */
+				drive->nobios = 1;  /* drop into "noprobe" */
+			case -2: /* "noprobe" */
+				drive->noprobe = 1;
+				goto done;
+			case -3: /* "nowerr" */
+				drive->bad_wstat = BAD_R_STAT;
+				hwif->noprobe = 0;
+				goto done;
+			case -4: /* "cdrom" */
+				drive->present = 1;
+				drive->media = ide_cdrom;
+				hwif->noprobe = 0;
+				goto done;
+			case -5: /* "serialize" */
+				printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
+				goto do_serialize;
+			case -6: /* "autotune" */
+				drive->autotune = 1;
+				goto done;
+			case -7: /* "noautotune" */
+				drive->autotune = 2;
+				goto done;
+			case -8: /* "slow" */
+				drive->slow = 1;
+				goto done;
+			case -9: /* "swapdata" or "bswap" */
+			case -10:
+				drive->bswap = 1;
+				goto done;
+			case -11: /* "flash" */
+				drive->ata_flash = 1;
+				goto done;
+			case -12: /* "remap" */
+				drive->remap_0_to_1 = 1;
+				goto done;
+			case -13: /* "noremap" */
+				drive->remap_0_to_1 = 2;
+				goto done;
+			case -14: /* "scsi" */
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+				drive->scsi = 1;
+				goto done;
+#else
+				drive->scsi = 0;
+				goto bad_option;
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+			case 3: /* cyl,head,sect */
+				drive->media	= ide_disk;
+				drive->cyl	= drive->bios_cyl  = vals[0];
+				drive->head	= drive->bios_head = vals[1];
+				drive->sect	= drive->bios_sect = vals[2];
+				drive->present	= 1;
+				drive->forced_geom = 1;
+				hwif->noprobe = 0;
+				goto done;
+			default:
+				goto bad_option;
+		}
+	}
+
+	if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
+		goto bad_option;
+	/*
+	 * Look for bus speed option:  "idebus="
+	 */
+	if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
+		if (match_parm(&s[6], NULL, vals, 1) != 1)
+			goto bad_option;
+		if (vals[0] >= 20 && vals[0] <= 66) {
+			idebus_parameter = vals[0];
+		} else
+			printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
+		goto done;
+	}
+	/*
+	 * Look for interface options:  "idex="
+	 */
+	if (s[3] >= '0' && s[3] <= max_hwif) {
+		/*
+		 * Be VERY CAREFUL changing this: note hardcoded indexes below
+		 * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding.
+		 */
+		const char *ide_words[] = {
+			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
+			"minus8", "minus9", "minus10",
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+		hw = s[3] - '0';
+		hwif = &ide_hwifs[hw];
+		i = match_parm(&s[4], ide_words, vals, 3);
+
+		/*
+		 * Cryptic check to ensure chipset not already set for hwif:
+		 */
+		if (i > 0 || i <= -11) {			/* is parameter a chipset name? */
+			if (hwif->chipset != ide_unknown)
+				goto bad_option;	/* chipset already specified */
+			if (i <= -11 && i != -18 && hw != 0)
+				goto bad_hwif;		/* chipset drivers are for "ide0=" only */
+			if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown)
+				goto bad_option;	/* chipset for 2nd port already specified */
+			printk("\n");
+		}
+
+		switch (i) {
+#ifdef CONFIG_BLK_DEV_PDC4030
+			case -18: /* "dc4030" */
+			{
+				extern void init_pdc4030(void);
+				init_pdc4030();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+#ifdef CONFIG_BLK_DEV_ALI14XX
+			case -17: /* "ali14xx" */
+			{
+				extern void init_ali14xx (void);
+				init_ali14xx();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_ALI14XX */
+#ifdef CONFIG_BLK_DEV_UMC8672
+			case -16: /* "umc8672" */
+			{
+				extern void init_umc8672 (void);
+				init_umc8672();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_UMC8672 */
+#ifdef CONFIG_BLK_DEV_DTC2278
+			case -15: /* "dtc2278" */
+			{
+				extern void init_dtc2278 (void);
+				init_dtc2278();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_DTC2278 */
+#ifdef CONFIG_BLK_DEV_CMD640
+			case -14: /* "cmd640_vlb" */
+			{
+				extern int cmd640_vlb; /* flag for cmd640.c */
+				cmd640_vlb = 1;
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_CMD640 */
+#ifdef CONFIG_BLK_DEV_HT6560B
+			case -13: /* "ht6560b" */
+			{
+				extern void init_ht6560b (void);
+				init_ht6560b();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_HT6560B */
+#if CONFIG_BLK_DEV_QD65XX
+			case -12: /* "qd65xx" */
+			{
+				extern void init_qd65xx (void);
+				init_qd65xx();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_QD65XX */
+#ifdef CONFIG_BLK_DEV_4DRIVES
+			case -11: /* "four" drives on one set of ports */
+			{
+				ide_hwif_t *mate = &ide_hwifs[hw^1];
+				mate->drives[0].select.all ^= 0x20;
+				mate->drives[1].select.all ^= 0x20;
+				hwif->chipset = mate->chipset = ide_4drives;
+				mate->irq = hwif->irq;
+				memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
+				goto do_serialize;
+			}
+#endif /* CONFIG_BLK_DEV_4DRIVES */
+			case -10: /* minus10 */
+			case -9: /* minus9 */
+			case -8: /* minus8 */
+				goto bad_option;
+			case -7: /* ata66 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+				hwif->udma_four = 1;
+				goto done;
+#else /* !CONFIG_BLK_DEV_IDEPCI */
+				hwif->udma_four = 0;
+				goto bad_hwif;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+			case -6: /* dma */
+				hwif->autodma = 1;
+				goto done;
+			case -5: /* "reset" */
+				hwif->reset = 1;
+				goto done;
+			case -4: /* "noautotune" */
+				hwif->drives[0].autotune = 2;
+				hwif->drives[1].autotune = 2;
+				goto done;
+			case -3: /* "autotune" */
+				hwif->drives[0].autotune = 1;
+				hwif->drives[1].autotune = 1;
+				goto done;
+			case -2: /* "serialize" */
+			do_serialize:
+				hwif->mate = &ide_hwifs[hw^1];
+				hwif->mate->mate = hwif;
+				hwif->serialized = hwif->mate->serialized = 1;
+				goto done;
+
+			case -1: /* "noprobe" */
+				hwif->noprobe = 1;
+				goto done;
+
+			case 1:	/* base */
+				vals[1] = vals[0] + 0x206; /* default ctl */
+			case 2: /* base,ctl */
+				vals[2] = 0;	/* default irq = probe for it */
+			case 3: /* base,ctl,irq */
+				hwif->hw.irq = vals[2];
+				ide_init_hwif_ports(&hwif->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &hwif->irq);
+				memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+				hwif->irq      = vals[2];
+				hwif->noprobe  = 0;
+				hwif->chipset  = ide_generic;
+				goto done;
+
+			case 0: goto bad_option;
+			default:
+				printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
+				return 1;
+		}
+	}
+bad_option:
+	printk(" -- BAD OPTION\n");
+	return 1;
+bad_hwif:
+	printk("-- NOT SUPPORTED ON ide%d", hw);
+done:
+	printk("\n");
+	return 1;
+}
+
+/*
+ * probe_for_hwifs() finds/initializes "known" IDE interfaces
+ */
+static void __init probe_for_hwifs (void)
+{
+#ifdef CONFIG_PCI
+	if (pci_present())
+	{
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		ide_scan_pcibus(ide_scan_direction);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_ETRAX_IDE
+	{
+		extern void init_e100_ide(void);
+		init_e100_ide();
+	}
+#endif /* CONFIG_ETRAX_IDE */
+#ifdef CONFIG_BLK_DEV_CMD640
+	{
+		extern void ide_probe_for_cmd640x(void);
+		ide_probe_for_cmd640x();
+	}
+#endif /* CONFIG_BLK_DEV_CMD640 */
+#ifdef CONFIG_BLK_DEV_PDC4030
+	{
+		extern int ide_probe_for_pdc4030(void);
+		(void) ide_probe_for_pdc4030();
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	{
+		extern void pmac_ide_probe(void);
+		pmac_ide_probe();
+	}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#ifdef CONFIG_BLK_DEV_IDE_SWARM
+	{
+		extern void swarm_ide_probe(void);
+		swarm_ide_probe();
+	}
+#endif /* CONFIG_BLK_DEV_IDE_SWARM */
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+	{
+		extern void icside_init(void);
+		icside_init();
+	}
+#endif /* CONFIG_BLK_DEV_IDE_ICSIDE */
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+	{
+		extern void rapide_init(void);
+		rapide_init();
+	}
+#endif /* CONFIG_BLK_DEV_IDE_RAPIDE */
+#ifdef CONFIG_BLK_DEV_GAYLE
+	{
+		extern void gayle_init(void);
+		gayle_init();
+	}
+#endif /* CONFIG_BLK_DEV_GAYLE */
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+	{
+		extern void falconide_init(void);
+		falconide_init();
+	}
+#endif /* CONFIG_BLK_DEV_FALCON_IDE */
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+	{
+		extern void macide_init(void);
+		macide_init();
+	}
+#endif /* CONFIG_BLK_DEV_MAC_IDE */
+#ifdef CONFIG_BLK_DEV_Q40IDE
+	{
+		extern void q40ide_init(void);
+		q40ide_init();
+	}
+#endif /* CONFIG_BLK_DEV_Q40IDE */
+#ifdef CONFIG_BLK_DEV_BUDDHA
+	{
+		extern void buddha_init(void);
+		buddha_init();
+	}
+#endif /* CONFIG_BLK_DEV_BUDDHA */
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+	{
+		extern void pnpide_init(int enable);
+		pnpide_init(1);
+	}
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+}
+
+void __init ide_init_builtin_drivers (void)
+{
+	/*
+	 * Probe for special PCI and other "known" interface chipsets
+	 */
+	probe_for_hwifs ();
+
+#ifdef CONFIG_BLK_DEV_IDE
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		ide_get_lock(&ide_intr_lock, NULL, NULL);/* for atari only */
+		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
+//		disable_irq_nosync(ide_hwifs[0].irq);
+	}
+#endif /* __mc68000__ || CONFIG_APUS */
+
+	(void) ideprobe_init();
+
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		enable_irq(ide_hwifs[0].irq);
+		ide_release_lock(&ide_lock);	/* for atari only */
+	}
+#endif /* __mc68000__ || CONFIG_APUS */
+#endif /* CONFIG_BLK_DEV_IDE */
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_create();
+#endif
+
+	/*
+	 * Attempt to match drivers for the available drives
+	 */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+	(void) idedisk_init();
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDECD
+	(void) ide_cdrom_init();
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+	(void) idetape_init();
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+	(void) idefloppy_init();
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+ #ifdef CONFIG_SCSI
+	(void) idescsi_init();
+ #else
+    #warning ide scsi-emulation selected but no SCSI-subsystem in kernel
+ #endif
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+}
+
+static int default_cleanup (ide_drive_t *drive)
+{
+	return ide_unregister_subdriver(drive);
+}
+
+static int default_standby (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_suspend (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_resume (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_flushcache (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_end_request(drive, 0);
+	return ide_stopped;
+}
+
+static int default_end_request (ide_drive_t *drive, int uptodate)
+{
+	return ide_end_request(drive, uptodate);
+}
+
+static byte default_sense (ide_drive_t *drive, const char *msg, byte stat)
+{
+	return ide_dump_status(drive, msg, stat);
+}
+
+static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	return ide_error(drive, msg, stat);
+}
+
+static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	return -EIO;
+}
+
+static int default_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
 	drive->usage--;
-	if (ata_ops(drive) && ata_ops(drive)->release)
-		ata_ops(drive)->release(inode, file, drive);
+	return -EIO;
+}
 
+static void default_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+}
+
+static int default_check_media_change (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void default_pre_reset (ide_drive_t *drive)
+{
+}
+
+static unsigned long default_capacity (ide_drive_t *drive)
+{
+	return 0x7fffffff;
+}
+
+static ide_startstop_t default_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+	s->all = 0;
+	drive->mult_req = 0;
+	return ide_stopped;
+}
+
+static int default_init (void)
+{
 	return 0;
 }
 
-int ide_spin_wait_hwgroup(struct ata_device *drive)
+static int default_reinit (ide_drive_t *drive)
 {
-	/* FIXME: Wait on a proper timer. Instead of playing games on the
-	 * spin_lock().
-	 */
+	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
 
-	unsigned long timeout = jiffies + (10 * HZ);
+	return 0;
+}
 
-	spin_lock_irq(drive->channel->lock);
+static void setup_driver_defaults (ide_drive_t *drive)
+{
+	ide_driver_t *d = drive->driver;
 
-	while (test_bit(IDE_BUSY, drive->channel->active)) {
+	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->suspend == NULL)		d->suspend = default_suspend;
+	if (d->resume == NULL)		d->resume = default_resume;
+	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
+	if (d->do_request == NULL)	d->do_request = default_do_request;
+	if (d->end_request == NULL)	d->end_request = default_end_request;
+	if (d->sense == NULL)		d->sense = default_sense;
+	if (d->error == NULL)		d->error = default_error;
+	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
+	if (d->open == NULL)		d->open = default_open;
+	if (d->release == NULL)		d->release = default_release;
+	if (d->media_change == NULL)	d->media_change = default_check_media_change;
+	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
+	if (d->capacity == NULL)	d->capacity = default_capacity;
+	if (d->special == NULL)		d->special = default_special;
+	if (d->init == NULL)		d->init = default_init;
+	if (d->reinit == NULL)		d->reinit = default_reinit;
+}
 
-		spin_unlock_irq(drive->channel->lock);
+ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+{
+	unsigned int unit, index, i;
 
-		if (time_after(jiffies, timeout)) {
-			printk("%s: channel busy\n", drive->name);
-			return -EBUSY;
+	for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
+		ide_hwif_t *hwif = &ide_hwifs[index];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			char *req = drive->driver_req;
+			if (*req && !strstr(name, req))
+				continue;
+			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+				return drive;
 		}
-
-		spin_lock_irq(drive->channel->lock);
 	}
+	return NULL;
+}
 
+int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
+	    drive->driver != NULL || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	drive->driver = driver;
+	setup_driver_defaults(drive);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	if (drive->autotune != 2) {
+		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
+			/*
+			 * Force DMAing for the beginning of the check.
+			 * Some chipsets appear to do interesting things,
+			 * if not checked and cleared.
+			 *   PARANOIA!!!
+			 */
+			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
+			(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+		}
+		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
+		drive->nice1 = 1;
+	}
+	drive->revalidate = 1;
+	drive->suspend_reset = 0;
+#ifdef CONFIG_PROC_FS
+	ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+	ide_add_proc_entries(drive->proc, driver->proc, drive);
+#endif
 	return 0;
 }
 
-static int ide_check_media_change(kdev_t i_rdev)
+int ide_unregister_subdriver (ide_drive_t *drive)
 {
-	struct ata_device *drive;
-	int res = 0; /* not changed */
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
+	pnpide_init(0);
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+#ifdef CONFIG_PROC_FS
+	ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
+#endif
+	auto_remove_settings(drive);
+	drive->driver = NULL;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
 
-	drive = get_info_ptr(i_rdev);
-	if (!drive)
-		return -ENODEV;
+int ide_register_module (ide_module_t *module)
+{
+	ide_module_t *p = ide_modules;
 
-	if (ata_ops(drive)) {
-		ata_get(ata_ops(drive));
-		if (ata_ops(drive)->check_media_change)
-			res = ata_ops(drive)->check_media_change(drive);
-		else
-			res = 1; /* assume it was changed */
-		ata_put(ata_ops(drive));
+	while (p) {
+		if (p == module)
+			return 1;
+		p = p->next;
 	}
+	module->next = ide_modules;
+	ide_modules = module;
+	revalidate_drives();
+	return 0;
+}
 
-	return res;
+void ide_unregister_module (ide_module_t *module)
+{
+	ide_module_t **p;
+
+	for (p = &ide_modules; (*p) && (*p) != module; p = &((*p)->next));
+	if (*p)
+		*p = (*p)->next;
 }
 
 struct block_device_operations ide_fops[] = {{
-	.owner =		THIS_MODULE,
-	.open =			ide_open,
-	.release =		ide_release,
-	.ioctl =		ata_ioctl,
-	.check_media_change =	ide_check_media_change,
-	.revalidate =		ide_revalidate
+	owner:			THIS_MODULE,
+	open:			ide_open,
+	release:		ide_release,
+	ioctl:			ide_ioctl,
+	check_media_change:	ide_check_media_change,
+	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_fops);
+EXPORT_SYMBOL(ide_hwifs);
+EXPORT_SYMBOL(ide_register_module);
+EXPORT_SYMBOL(ide_unregister_module);
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
+/*
+ * Probe module
+ */
+devfs_handle_t ide_devfs_handle;
+
+EXPORT_SYMBOL(ide_lock);
+EXPORT_SYMBOL(ide_probe);
 EXPORT_SYMBOL(drive_is_flashcard);
 EXPORT_SYMBOL(ide_timer_expiry);
+EXPORT_SYMBOL(ide_intr);
+EXPORT_SYMBOL(ide_fops);
+EXPORT_SYMBOL(ide_get_queue);
+EXPORT_SYMBOL(ide_add_generic_settings);
+EXPORT_SYMBOL(ide_devfs_handle);
 EXPORT_SYMBOL(do_ide_request);
+/*
+ * Driver module
+ */
+EXPORT_SYMBOL(ide_scan_devices);
+EXPORT_SYMBOL(ide_register_subdriver);
+EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ide_replace_subdriver);
+EXPORT_SYMBOL(ide_set_handler);
+EXPORT_SYMBOL(ide_dump_status);
+EXPORT_SYMBOL(ide_error);
+EXPORT_SYMBOL(ide_fixstring);
+EXPORT_SYMBOL(ide_do_reset);
+EXPORT_SYMBOL(restart_request);
+EXPORT_SYMBOL(ide_init_drive_cmd);
+EXPORT_SYMBOL(ide_do_drive_cmd);
+EXPORT_SYMBOL(ide_end_drive_cmd);
+EXPORT_SYMBOL(ide_end_request);
+EXPORT_SYMBOL(ide_revalidate_drive);
+EXPORT_SYMBOL(ide_revalidate_disk);
+EXPORT_SYMBOL(ide_cmd);
+EXPORT_SYMBOL(ide_wait_cmd);
+EXPORT_SYMBOL(ide_wait_cmd_task);
+EXPORT_SYMBOL(ide_delay_50ms);
+EXPORT_SYMBOL(ide_stall_queue);
+#ifdef CONFIG_PROC_FS
+EXPORT_SYMBOL(ide_add_proc_entries);
+EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(proc_ide_read_geometry);
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL(recreate_proc_ide_device);
+EXPORT_SYMBOL(destroy_proc_ide_device);
+#endif
+EXPORT_SYMBOL(ide_add_setting);
+EXPORT_SYMBOL(ide_remove_setting);
 
-EXPORT_SYMBOL(ata_set_handler);
-EXPORT_SYMBOL(ata_dump);
-EXPORT_SYMBOL(ata_error);
+EXPORT_SYMBOL(ide_register_hw);
+EXPORT_SYMBOL(ide_register);
+EXPORT_SYMBOL(ide_unregister);
+EXPORT_SYMBOL(ide_setup_ports);
+EXPORT_SYMBOL(hwif_unregister);
+EXPORT_SYMBOL(get_info_ptr);
+EXPORT_SYMBOL(current_capacity);
 
-EXPORT_SYMBOL(ata_end_request);
+EXPORT_SYMBOL(system_bus_clock);
 
-EXPORT_SYMBOL(ide_setup_ports);
+EXPORT_SYMBOL(ide_reinit_drive);
+
+static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	switch (event) {
+		case SYS_HALT:
+		case SYS_POWER_OFF:
+		case SYS_RESTART:
+			break;
+		default:
+			return NOTIFY_DONE;
+	}
+
+	printk("flushing ide devices: ");
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (!drive->present)
+				continue;
+
+			/* set the drive to standby */
+			printk("%s ", drive->name);
+			if (event != SYS_RESTART)
+				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
+				continue;
+
+			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+				continue;
+		}
+	}
+	printk("\n");
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ide_notifier = {
+	ide_notify_reboot,
+	NULL,
+	5
+};
+
+/*
+ * This is gets invoked once during initialization, to set *everything* up
+ */
+int __init ide_init (void)
+{
+	static char banner_printed;
+	int i;
+
+	if (!banner_printed) {
+		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+		system_bus_speed = ide_system_bus_speed();
+		banner_printed = 1;
+	}
+
+	init_ide_data ();
+
+	initializing = 1;
+	ide_init_builtin_drivers();
+	initializing = 0;
+
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		ide_hwif_t  *hwif = &ide_hwifs[i];
+		if (hwif->present)
+			ide_geninit(hwif);
+	}
+
+	register_reboot_notifier(&ide_notifier);
+	return 0;
+}
+
+module_init(ide_init);
+
+#ifdef MODULE
+char *options = NULL;
+MODULE_PARM(options,"s");
+MODULE_LICENSE("GPL");
+
+static void __init parse_options (char *line)
+{
+	char *next = line;
+
+	if (line == NULL || !*line)
+		return;
+	while ((line = next) != NULL) {
+ 		if ((next = strchr(line,' ')) != NULL)
+			*next++ = 0;
+		if (!ide_setup(line))
+			printk ("Unknown option '%s'\n", line);
+	}
+}
+
+int init_module (void)
+{
+	parse_options(options);
+	return ide_init();
+}
+
+void cleanup_module (void)
+{
+	int index;
+
+	unregister_reboot_notifier(&ide_notifier);
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		ide_unregister(index);
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+		if (ide_hwifs[index].dma_base)
+			(void) ide_release_dma(&ide_hwifs[index]);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+	}
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_destroy();
+#endif
+	devfs_unregister (ide_devfs_handle);
+}
+
+#else /* !MODULE */
+
+__setup("", ide_setup);
+
+#endif /* MODULE */
diff -Nru a/drivers/ide/ide_modes.h b/drivers/ide/ide_modes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide_modes.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,236 @@
+/*
+ *  linux/drivers/ide/ide_modes.h
+ *
+ *  Copyright (C) 1996  Linus Torvalds, Igor Abramov, and Mark Lord
+ */
+
+#ifndef _IDE_MODES_H
+#define _IDE_MODES_H
+
+#include <linux/config.h>
+
+/*
+ * Shared data/functions for determining best PIO mode for an IDE drive.
+ * Most of this stuff originally lived in cmd640.c, and changes to the
+ * ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid
+ * breaking the fragile cmd640.c support.
+ */
+
+#ifdef CONFIG_BLK_DEV_IDE_MODES
+
+/*
+ * Standard (generic) timings for PIO modes, from ATA2 specification.
+ * These timings are for access to the IDE data port register *only*.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+typedef struct ide_pio_timings_s {
+	int	setup_time;	/* Address setup (ns) minimum */
+	int	active_time;	/* Active pulse (ns) minimum */
+	int	cycle_time;	/* Cycle time (ns) minimum = (setup + active + recovery) */
+} ide_pio_timings_t;
+
+typedef struct ide_pio_data_s {
+	byte pio_mode;
+	byte use_iordy;
+	byte overridden;
+	byte blacklisted;
+	unsigned int cycle_time;
+} ide_pio_data_t;
+	
+#ifndef _IDE_C
+
+int ide_scan_pio_blacklist (char *model);
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+extern const ide_pio_timings_t ide_pio_timings[6];
+
+#else /* _IDE_C */
+
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/*
+ * This routine searches the ide_pio_blacklist for an entry
+ * matching the start/whole of the supplied model name.
+ *
+ * Returns -1 if no match found.
+ * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/*
+ * This routine returns the recommended PIO settings for a given drive,
+ * based on the drive->id information and the ide_pio_blacklist[].
+ * This is used by most chipset support modules when "auto-tuning".
+ */
+
+/*
+ * Drive PIO mode auto selection
+ */
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
+
+#endif /* _IDE_C */
+#endif /* CONFIG_BLK_DEV_IDE_MODES */
+#endif /* _IDE_MODES_H */
diff -Nru a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c
--- a/drivers/ide/ioctl.c	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,361 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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.
- */
-
-/*
- * Generic ioctl handling for all ATA/ATAPI device drivers.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/blkpg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/cdrom.h>
-#include <linux/device.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/uaccess.h>
-
-#include "ioctl.h"
-
-
-/* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */
-struct hd_big_geometry {
-	u8 heads;
-	u8 sectors;
-	u32 cylinders;
-	unsigned long start;
-};
-
-/*
- * Implement generic ioctls invoked from userspace to imlpement specific
- * functionality.
- *
- * Unfortunately every single low level programm out there is using this
- * interface.
- */
-static int do_cmd_ioctl(struct ata_device *drive, unsigned long arg)
-{
-	int err = 0;
-	u8 vals[4];
-	u8 *argbuf = vals;
-	int argsize = 4;
-	struct ata_taskfile args;
-
-	/* Second phase.
-	 */
-	if (copy_from_user(vals, (void *)arg, 4))
-		return -EFAULT;
-
-	memset(&args, 0, sizeof(args));
-
-	args.taskfile.feature = vals[2];
-	args.taskfile.sector_count = vals[1];
-	args.taskfile.sector_number = vals[3];
-	if (vals[0] == WIN_SMART) {
-		args.taskfile.low_cylinder = 0x4f;
-		args.taskfile.high_cylinder = 0xc2;
-	} else {
-		args.taskfile.low_cylinder = 0x00;
-		args.taskfile.high_cylinder = 0x00;
-	}
-	args.taskfile.device_head = 0x00;
-	args.cmd = vals[0];
-
-	if (vals[3]) {
-		argsize = 4 + (SECTOR_WORDS * 4 * vals[3]);
-		argbuf = kmalloc(argsize, GFP_KERNEL);
-		if (argbuf == NULL)
-			return -ENOMEM;
-		memcpy(argbuf, vals, 4);
-		memset(argbuf + 4, 0, argsize - 4);
-	}
-
-	/* Issue ATA command and wait for completion.
-	 */
-	err = ide_raw_taskfile(drive, &args, argbuf + 4);
-
-	argbuf[0] = drive->status;
-	argbuf[1] = args.taskfile.feature;
-	argbuf[2] = args.taskfile.sector_count;
-
-	if (copy_to_user((void *)arg, argbuf, argsize))
-		err = -EFAULT;
-
-	if (argsize > 4)
-		kfree(argbuf);
-
-	return err;
-}
-
-/*
- * NOTE: Due to ridiculous coding habbits in the hdparm utility we have to
- * always return unsigned long in case we are returning simple values.
- */
-int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int major, minor;
-	struct ata_device *drive;
-	kdev_t dev;
-
-	dev = inode->i_rdev;
-	major = major(dev);
-	minor = minor(dev);
-
-	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
-		return -ENODEV;
-
-	/* Contrary to popular beleve we disallow even the reading of the ioctl
-	 * values for users which don't have permission too. We do this becouse
-	 * such information could be used by an attacker to deply a simple-user
-	 * attack, which triggers bugs present only on a particular
-	 * configuration.
-	 */
-
-	switch (cmd) {
-		case HDIO_GET_32BIT: {
-			unsigned long val = drive->channel->io_32bit;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_SET_32BIT:
-		        if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (drive->channel->no_io_32bit)
-				return -EIO;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			drive->channel->io_32bit = arg;
-			spin_unlock_irq(drive->channel->lock);
-
-			return 0;
-
-		case HDIO_SET_PIO_MODE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (arg < 0 || arg > 255)
-				return -EINVAL;
-
-			if (!drive->channel->tuneproc)
-				return -ENOSYS;
-
-			/* FIXME: we can see that tuneproc whould do the
-			 * locking!.
-			 */
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			drive->channel->tuneproc(drive, (u8) arg);
-			spin_unlock_irq(drive->channel->lock);
-
-			return 0;
-
-		case HDIO_GET_UNMASKINTR: {
-			unsigned long val = drive->channel->unmask;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_SET_UNMASKINTR:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (drive->channel->no_unmask)
-				return -EIO;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			drive->channel->unmask = arg;
-			spin_unlock_irq(drive->channel->lock);
-
-			return 0;
-
-		case HDIO_GET_DMA: {
-			unsigned long val = drive->using_dma;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_SET_DMA:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (!drive->driver)
-				return -EPERM;
-
-			if (!drive->id || !(drive->id->capability & 1) || !drive->channel->udma_setup)
-				return -EPERM;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			udma_enable(drive, arg, 1);
-			spin_unlock_irq(drive->channel->lock);
-
-			return 0;
-
-		case HDIO_GETGEO: {
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
-
-			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
-				return -EINVAL;
-
-			if (put_user(drive->bios_head, (u8 *) &loc->heads))
-				return -EFAULT;
-
-			if (put_user(drive->bios_sect, (u8 *) &loc->sectors))
-				return -EFAULT;
-
-			if (put_user(bios_cyl, (u16 *) &loc->cylinders))
-				return -EFAULT;
-
-			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
-				(unsigned long *) &loc->start))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG_RAW: {
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-
-			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
-				return -EINVAL;
-
-			if (put_user(drive->head, (u8 *) &loc->heads))
-				return -EFAULT;
-
-			if (put_user(drive->sect, (u8 *) &loc->sectors))
-				return -EFAULT;
-
-			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders))
-				return -EFAULT;
-
-			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
-				(unsigned long *) &loc->start))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_GET_IDENTITY:
-
-			if (minor(inode->i_rdev) & PARTN_MASK)
-				return -EINVAL;
-
-			if (drive->id == NULL)
-				return -ENOMSG;
-
-			if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id)))
-				return -EFAULT;
-
-			return 0;
-
-		case HDIO_GET_NICE:
-
-			return put_user(drive->dsc_overlap | drive->atapi_overlap << 1,
-					(long *) arg);
-
-		case HDIO_SET_NICE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (arg != (arg & 1))
-				return -EPERM;
-
-			drive->dsc_overlap = arg & 1;
-
-			/* Only CD-ROM's and tapes support DSC overlap. */
-			if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) {
-				drive->dsc_overlap = 0;
-				return -EPERM;
-			}
-
-			return 0;
-
-		case HDIO_GET_BUSSTATE:
-
-			if (put_user(drive->channel->bus_state, (long *)arg))
-				return -EFAULT;
-
-			return 0;
-
-		case HDIO_SET_BUSSTATE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (drive->channel->busproc)
-				drive->channel->busproc(drive, (int)arg);
-
-			return 0;
-
-		case HDIO_DRIVE_CMD:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			if (!arg) {
-				if (ide_spin_wait_hwgroup(drive))
-					return -EBUSY;
-				/* Do nothing, just unlock */
-				spin_unlock_irq(drive->channel->lock);
-				return 0;
-			}
-
-			return do_cmd_ioctl(drive, arg);
-
-		/*
-		 * uniform packet command handling
-		 */
-		case CDROMEJECT:
-		case CDROMCLOSETRAY:
-			return block_ioctl(inode->i_bdev, cmd, arg);
-
-		/* Now check whatever this particular ioctl has a device type
-		 * specific implementation.
-		 */
-		default:
-			if (ata_ops(drive) && ata_ops(drive)->ioctl)
-				return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg);
-
-			return -EINVAL;
-	}
-}
diff -Nru a/drivers/ide/ioctl.h b/drivers/ide/ioctl.h
--- a/drivers/ide/ioctl.h	Tue Aug 27 12:27:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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.
- */
-
-extern int ata_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/ide/it8172.c	Tue Aug 27 12:28:08 2002
@@ -33,110 +33,147 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/it8172/it8172_int.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
+/*
+ * Prototypes
+ */
+static byte it8172_ratemask (ide_drive_t *drive);
+static byte it8172_ratefilter (ide_drive_t *drive, byte speed);
+static void it8172_tune_drive (ide_drive_t *drive, byte pio);
+static byte it8172_dma_2_pio (byte xfer_rate);
+static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma (ide_drive_t *drive);
+static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
+#endif
+unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
+void __init ide_init_it8172 (ide_hwif_t *hwif);
 
-/* FIXME: fix locking  --bkz */
-static void it8172_tune_drive (struct ata_device *drive, u8 pio)
+static byte it8172_ratemask (ide_drive_t *drive)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-    unsigned long flags;
-    u16 drive_enables;
-    u32 drive_timing;
-    int is_slave	= (&drive->channel->drives[1] == drive);
-    
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
-	else
-		pio = min_t(byte, pio, 4);
+	byte mode	= 0x00;
+#if 1
+	mode |= 0x01;
+#endif
+	return (mode &= ~0xF8);
+}
 
-	pci_read_config_word(dev, master_port, &master_data);
-	pci_read_config_dword(dev, slave_port, &slave_data);
+static byte it8172_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = it8172_ratemask(drive);
 
-    /*
-     * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
-     * are being left at the default values of 8 PCI clocks (242 nsec
-     * for a 33 MHz clock). These can be safely shortened at higher
-     * PIO modes. The DIOR/DIOW pulse width and recovery times only
-     * apply to PIO modes, not to the DMA modes.
-     */
-    
-    /*
-     * Enable port 0x44. The IT8172G spec is confused; it calls
-     * this register the "Slave IDE Timing Register", but in fact,
-     * it controls timing for both master and slave drives.
-     */
-    drive_enables |= 0x4000;
+	switch(mode) {
+		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
 
-    if (is_slave) {
-	drive_enables &= 0xc006;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0060;
-    } else {
-	drive_enables &= 0xc060;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0006;
-    }
+static void it8172_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (hwif->drives[1] == drive);
+	unsigned long flags;
+	u16 drive_enables;
+	u32 drive_timing;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, 0x40, &drive_enables);
+	pci_read_config_dword(dev, 0x44, &drive_timing);
+
+	/*
+	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+	 * are being left at the default values of 8 PCI clocks (242 nsec
+	 * for a 33 MHz clock). These can be safely shortened at higher
+	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
+	 * apply to PIO modes, not to the DMA modes.
+	 */
+
+	/*
+	 * Enable port 0x44. The IT8172G spec is confused; it calls
+	 * this register the "Slave IDE Timing Register", but in fact,
+	 * it controls timing for both master and slave drives.
+	 */
+	drive_enables |= 0x4000;
+
+	if (is_slave) {
+		drive_enables &= 0xc006;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0060;
+	} else {
+		drive_enables &= 0xc060;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0006;
+	}
 
-	pci_write_config_word(dev, master_port, master_data);
+	pci_write_config_word(dev, 0x40, drive_enables);
+	spin_unlock_irqrestore(&ide_lock, flags)
 }
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-/*
- *
- */
-static u8 it8172_dma_2_pio(u8 xfer_rate)
+static byte it8172_dma_2_pio (byte xfer_rate)
 {
-    switch(xfer_rate) {
-    case XFER_UDMA_5:
-    case XFER_UDMA_4:
-    case XFER_UDMA_3:
-    case XFER_UDMA_2:
-    case XFER_UDMA_1:
-    case XFER_UDMA_0:
-    case XFER_MW_DMA_2:
-    case XFER_PIO_4:
-	return 4;
-    case XFER_MW_DMA_1:
-    case XFER_PIO_3:
-	return 3;
-    case XFER_SW_DMA_2:
-    case XFER_PIO_2:
-	return 2;
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_1:
-    case XFER_SW_DMA_0:
-    case XFER_PIO_1:
-    case XFER_PIO_0:
-    case XFER_PIO_SLOW:
-    default:
-	return 0;
-    }
-}
-
-static int it8172_tune_chipset(struct ata_device *drive, u8 speed)
-{
-    struct ata_channel *hwif = drive->channel;
-    struct pci_dev *dev	= hwif->pci_dev;
-    int a_speed		= 3 << (drive->dn * 4);
-    int u_flag		= 1 << drive->dn;
-    int u_speed		= 0;
-    int err		= 0;
-	u8 reg48, reg4a;
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
 
-    pci_read_config_byte(dev, 0x48, &reg48);
-    pci_read_config_byte(dev, 0x4a, &reg4a);
+static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte speed		= it8172_ratefilter(drive, xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	byte reg48, reg4a;
+
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x4a, &reg4a);
 
     /*
      * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
@@ -148,90 +185,205 @@
      * performance.
      */
     
-    switch(speed) {
-    case XFER_UDMA_4:
-    case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
-    case XFER_UDMA_5:
-    case XFER_UDMA_3:
-    case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
-    case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-    case XFER_MW_DMA_2:
-    case XFER_MW_DMA_1:
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_2:	break;
-    default:		return -1;
-    }
-
-    if (speed >= XFER_UDMA_0) {
-	pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-	reg4a &= ~a_speed;
-	pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-    } else {
-	pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-	pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-    }
-
-    it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		reg4a &= ~a_speed;
+		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+	} else {
+		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+	}
 
-	return ide_config_drive_speed(drive, speed);
+	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
 }
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte mode		= it8172_ratemask(drive);
+	byte speed, tspeed, dma = 1;
+
+	switch(mode) {
+		case 0x01:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+		default:
+			tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+			speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+			dma = 0;
+			break;
+	}
+
+	(void) it8172_tune_chipset(drive, speed);
+
+//	return ((int)(dma) ? ide_dma_on : ide_dma_off_quietly);
+	return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+		    ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+		    ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+		    ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+		    ide_dma_off_quietly);
+}
 
-static unsigned int __init pci_init_it8172(struct pci_dev *dev)
+static int config_drive_xfer_rate (ide_drive_t *drive)
 {
-	u8 progif;
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
 
-    /*
-     * Place both IDE interfaces into PCI "native" mode
-     */
-	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);
+	drive->init_speed = 0;
 
-    return IT8172_IDE_IRQ;
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = it8172_config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = it8172_config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = it8172_config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		it8172_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
-
-static void __init ide_init_it8172(struct ata_channel *hwif)
+static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-    struct pci_dev* dev = hwif->pci_dev;
-    unsigned long cmdBase, ctrlBase;
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default :
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-    hwif->tuneproc = &it8172_tune_drive;
-    hwif->drives[0].autotune = 1;
-    hwif->drives[1].autotune = 1;
 
-    if (!hwif->dma_base)
-	return;
+unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
+{
+	unsigned char progif;
+    
+	/*
+	 * Place both IDE interfaces into PCI "native" mode
+	 */
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
 
-# ifdef CONFIG_IT8172_TUNING
-	hwif->modes_map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
-	hwif->udma_setup = udma_generic_setup;
-    hwif->speedproc = &it8172_tune_chipset;
-# endif
+	return IT8172_IDE_IRQ;
+}
 
-    cmdBase = dev->resource[0].start;
-    ctrlBase = dev->resource[1].start;
 
-    ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
-    memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-    hwif->noprobe = 0;
-}
+void __init ide_init_it8172 (ide_hwif_t *hwif)
+{
+	struct pci_dev* dev = hwif->pci_dev;
+	unsigned long cmdBase, ctrlBase;
+    
+	hwif->autodma = 0;
+	hwif->tuneproc = &it8172_tune_drive;
+	hwif->speedproc = &it8172_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
 
+	cmdBase = dev->resource[0].start;
+	ctrlBase = dev->resource[1].start;
+    
+	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->noprobe = 0;
+
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc = &it8172_dmaproc;
+# ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+# endif /* CONFIG_IDEDMA_AUTO */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
 
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-        .vendor = PCI_VENDOR_ID_ITE,
-	.device = PCI_DEVICE_ID_ITE_IT8172G,
-	.init_chipset = pci_init_it8172,
-	.init_channel = ide_init_it8172,
-	.exnablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01} },
-	.bootable = ON_BOARD
-};
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-int __init init_it8172(void)
+void __init fixup_device_it8172 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	ata_register_chipset(&chipset);
-
-        return 0;
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return; /* IT8172 is more than only a IDE controller */
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+
diff -Nru a/drivers/ide/macide.c b/drivers/ide/macide.c
--- a/drivers/ide/macide.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/ide/macide.c	Tue Aug 27 12:28:08 2002
@@ -69,7 +69,7 @@
     IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
 };
 
-int macide_ack_intr(struct ata_channel *hwif)
+int macide_ack_intr(ide_hwif_t* hwif)
 {
 	if (*ide_ifr & 0x20) {
 		*ide_ifr &= ~0x20;
@@ -100,17 +100,17 @@
 	case MAC_IDE_QUADRA:
 		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw);
+		index = ide_register_hw(&hw, NULL);
 		break;
 	case MAC_IDE_PB:
 		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw);
+		index = ide_register_hw(&hw, NULL);
 		break;
 	case MAC_IDE_BABOON:
 		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
 				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw);
+		index = ide_register_hw(&hw, NULL);
 		if (index == -1) break;
 		if (macintosh_config->ident == MAC_MODEL_PB190) {
 
@@ -119,7 +119,7 @@
 			/* hardware ID, and we cna't get that without	*/
 			/* probing the drive which freezes a 190.	*/
 
-			struct ata_device *drive = &ide_hwifs[index].drives[0];
+			ide_drive_t *drive = &ide_hwifs[index].drives[0];
         		drive->capacity = drive->cyl*drive->head*drive->sect;
 
 #ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
diff -Nru a/drivers/ide/main.c b/drivers/ide/main.c
--- a/drivers/ide/main.c	Tue Aug 27 12:27:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1441 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
- *
- *	Mark Lord	<mlord@pobox.com>
- *      Gadi Oxman	<gadio@netvision.net.il>
- *      Andre Hedrick	<andre@linux-ide.org>
- *	Jens Axboe	<axboe@suse.de>
- *      Marcin Dalecki	<martin@dalecki.de>
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- */
-
-/*
- * Handle overall infrastructure of the driver
- */
-
-#define	VERSION	"7.0.0"
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#ifndef MODULE
-# include <linux/init.h>
-#endif
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/reboot.h>
-#include <linux/cdrom.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-#include "timing.h"
-#include "pcihost.h"
-#include "ioctl.h"
-
-
-MODULE_DESCRIPTION("ATA/ATAPI driver infrastructure");
-MODULE_PARM(options,"s");
-MODULE_LICENSE("GPL");
-
-/*
- * Those will be moved into separate header files eventually.
- */
-#ifdef CONFIG_ETRAX_IDE
-extern void init_e100_ide(void);
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-extern void ide_probe_for_cmd640x(void);
-#endif
-#ifdef CONFIG_BLK_DEV_PDC4030
-extern int ide_probe_for_pdc4030(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-extern void pmac_ide_probe(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
-extern void icside_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
-extern void rapide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_GAYLE
-extern void gayle_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-extern void falconide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-extern void macide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_Q40IDE
-extern void q40ide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_BUDDHA
-extern void buddha_init(void);
-#endif
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
-extern void pnpide_init(int);
-#endif
-
-/* default maximum number of failures */
-#define IDE_DEFAULT_MAX_FAILURES	1
-
-int system_bus_speed;		/* holds what we think is VESA/PCI bus speed */
-
-static int initializing;	/* set while initializing built-in drivers */
-static int idebus_parameter;	/* the "idebus=" parameter */
-
-/*
- * Protects access to global structures etc.
- */
-spinlock_t ide_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
-
-#ifdef CONFIG_PCI
-static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif
-
-#ifdef ATA_ARCH_LOCK
-/*
- * This is used by the Atari code to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-int ide_irq_lock;
-#endif
-
-int noautodma = 0;
-
-/* Single linked list of sub device type drivers */
-static struct ata_operations *ata_drivers; /* = NULL */
-static spinlock_t ata_drivers_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * This is declared extern in ide.h, for access by other IDE modules:
- */
-struct ata_channel ide_hwifs[MAX_HWIFS];	/* master data repository */
-
-/*
- * FIXME: This function should be unrolled in the palces where it get's used,
- * since in reality it's simple architecture specific initialization.
- *
- * Setup hw_regs_t structure described by parameters.  You may set up the hw
- * structure yourself OR use this routine to do it for you.
- */
-void ide_setup_ports(hw_regs_t *hw, ide_ioreg_t base, int *offsets,
-		ide_ioreg_t ctrl, ide_ioreg_t intr,
-		int (*ack_intr)(struct ata_channel *),
-		int irq)
-{
-	int i;
-
-	for (i = 0; i < IDE_NR_PORTS; i++) {
-		if (offsets[i] != -1)
-			hw->io_ports[i] = base + offsets[i];
-		else
-			hw->io_ports[i] = 0;
-	}
-	if (offsets[IDE_CONTROL_OFFSET] == -1)
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl;
-
-	/* FIMXE: check if we can remove this ifdef */
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (offsets[IDE_IRQ_OFFSET] == -1)
-		hw->io_ports[IDE_IRQ_OFFSET] = intr;
-#endif
-
-	hw->irq = irq;
-	hw->dma = NO_DMA;
-	hw->ack_intr = ack_intr;
-}
-
-static void init_hwif_data(struct ata_channel *ch, unsigned int index)
-{
-	static const unsigned int majors[] = {
-		IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
-		IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR
-	};
-
-	unsigned int unit;
-
-	/* bulk initialize channel & drive info with zeros */
-	memset(ch, 0, sizeof(struct ata_channel));
-
-	/* fill in any non-zero initial values */
-	ch->index = index;
-	ide_init_hwif_ports(&ch->hw, ide_default_io_base(index), 0, &ch->irq);
-
-	memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->hw.io_ports));
-
-	/* Most controllers cannot do transfers across 64kB boundaries.
-	   trm290 can do transfers within a 4GB boundary, so it changes
-	   this mask accordingly. */
-	ch->seg_boundary_mask = 0xffff;
-
-	/* Some chipsets (cs5530, any others?) think a 64kB transfer
-	   is 0 byte transfer, so set the limit one sector smaller.
-	   In the future, we may default to 64kB transfers and let
-	   invidual chipsets with this problem change ch->max_segment_size. */
-	ch->max_segment_size = (1<<16) - 512;
-
-	ch->noprobe	= !ch->io_ports[IDE_DATA_OFFSET];
-#ifdef CONFIG_BLK_DEV_HD
-
-	/* Ignore disks for which handling by the legacy driver was requested
-	 * by the used.
-	 */
-	if (ch->io_ports[IDE_DATA_OFFSET] == 0x1f0)
-		ch->noprobe = 1; /* may be overridden by ide_setup() */
-#endif
-
-	ch->major = majors[index];
-	sprintf(ch->name, "ide%d", index);
-	ch->bus_state = BUSSTATE_ON;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device *drive = &ch->drives[unit];
-
-		drive->type		= ATA_DISK;
-		drive->select.all	= (unit << 4) | 0xa0;
-		drive->channel		= ch;
-		drive->ready_stat	= READY_STAT;
-		drive->bad_wstat	= BAD_W_STAT;
-		sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit);
-		drive->max_failures	= IDE_DEFAULT_MAX_FAILURES;
-
-		init_waitqueue_head(&drive->wqueue);
-	}
-}
-
-extern struct block_device_operations ide_fops[];
-
-/*
- * Returns the (struct ata_device *) for a given device number.  Return
- * NULL if the given device number does not match any present drives.
- */
-struct ata_device *get_info_ptr(kdev_t i_rdev)
-{
-	unsigned int major = major(i_rdev);
-	int h;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		struct ata_channel *ch = &ide_hwifs[h];
-		if (ch->present && major == ch->major) {
-			int unit = DEVICE_NR(i_rdev);
-			if (unit < MAX_DRIVES) {
-				struct ata_device *drive = &ch->drives[unit];
-				if (drive->present)
-					return drive;
-			}
-			break;
-		}
-	}
-	return NULL;
-}
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-int ide_revalidate(kdev_t dev)
-{
-	struct ata_device *drive;
-	struct ata_channel *channel;
-	struct gendisk *disk;
-	int unit;
-
-	if ((drive = get_info_ptr(dev)) == NULL)
-		return -ENODEV;
-	if (ata_ops(drive) && ata_ops(drive)->revalidate) {
-		ata_get(ata_ops(drive));
-		ata_ops(drive)->revalidate(drive);
-		ata_put(ata_ops(drive));
-	}
-	channel = drive->channel;
-	unit = drive - channel->drives;
-	disk = channel->gd[unit];
-	disk->part[0].nr_sects = ata_capacity(drive);
-	return 0;
-}
-
-void ide_driver_module(void)
-{
-	int i;
-
-	/* Don't reinit the probe if there is already one channel detected. */
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		if (ide_hwifs[i].present)
-			return;
-	}
-
-	ideprobe_init();
-}
-
-/*
- * Release the data associated with a channel.
- */
-void ide_unregister(struct ata_channel *ch)
-{
-	struct gendisk *gd;
-	struct ata_device *d;
-	spinlock_t *lock;
-	int unit;
-	int i;
-	unsigned long flags;
-	unsigned int p, minor;
-	struct ata_channel old;
-	int n_irq;
-	int n_ch;
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	if (!ch->present)
-		goto abort;
-
-	put_device(&ch->dev);
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device * drive = &ch->drives[unit];
-
-		if (!drive->present)
-			continue;
-
-		if (drive->busy || drive->usage)
-			goto abort;
-
-		if (ata_ops(drive)) {
-			if (ata_ops(drive)->cleanup) {
-				if (ata_ops(drive)->cleanup(drive))
-					goto abort;
-			} else
-				ata_unregister_device(drive);
-		}
-	}
-	ch->present = 0;
-
-	/*
-	 * All clear?  Then blow away the buffer cache
-	 */
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device * drive = &ch->drives[unit];
-
-		if (!drive->present)
-			continue;
-
-		minor = drive->select.b.unit << PARTN_BITS;
-		for (p = 0; p < (1<<PARTN_BITS); ++p) {
-			if (drive->part[p].nr_sects > 0) {
-				kdev_t devp = mk_kdev(ch->major, minor+p);
-				invalidate_device(devp, 0);
-			}
-		}
-	}
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	/*
-	 * Note that we only release the standard ports, and do not even try to
-	 * handle any extra ports allocated for weird IDE interface chipsets.
-	 */
-
-	if (ch->straight8) {
-		release_region(ch->io_ports[IDE_DATA_OFFSET], 8);
-	} else {
-		for (i = 0; i < 8; i++)
-			if (ch->io_ports[i])
-				release_region(ch->io_ports[i], 1);
-	}
-	if (ch->io_ports[IDE_CONTROL_OFFSET])
-		release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1);
-/* FIXME: check if we can remove this ifdef */
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (ch->io_ports[IDE_IRQ_OFFSET])
-		release_region(ch->io_ports[IDE_IRQ_OFFSET], 1);
-#endif
-
-	/*
-	 * Remove us from the lock group.
-	 */
-
-	lock = ch->lock;
-	d = ch->drive;
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		if (drive->de) {
-			devfs_unregister(drive->de);
-			drive->de = NULL;
-		}
-		if (!drive->present)
-			continue;
-
-		/* FIXME: possibly unneccessary */
-		if (ch->drive == drive)
-			ch->drive = NULL;
-
-		if (drive->id != NULL) {
-			kfree(drive->id);
-			drive->id = NULL;
-		}
-		drive->present = 0;
-		blk_cleanup_queue(&drive->queue);
-	}
-	if (d->present)
-		ch->drive = d;
-
-
-	/*
-	 * Free the irq if we were the only channel using it.
-	 *
-	 * Free the lock group if we were the only member.
-	 */
-	n_irq = n_ch = 0;
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		struct ata_channel *tmp = &ide_hwifs[i];
-
-		if (!tmp->present)
-			continue;
-
-		if (tmp->irq == ch->irq)
-			++n_irq;
-		if (tmp->lock == ch->lock)
-			++n_ch;
-	}
-	if (n_irq == 1)
-		free_irq(ch->irq, ch);
-	if (n_ch == 1) {
-		kfree(ch->lock);
-		kfree(ch->active);
-		ch->lock = NULL;
-		ch->active = NULL;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_release_dma(ch);
-#endif
-
-	/*
-	 * Remove us from the kernel's knowledge.
-	 */
-	unregister_blkdev(ch->major, ch->name);
-	blk_dev[ch->major].data = NULL;
-	blk_dev[ch->major].queue = NULL;
-	blk_clear(ch->major);
-	gd = ch->gd[0];
-	if (gd) {
-		int i;
-		for (i = 0; i < MAX_DRIVES; i++)
-			del_gendisk(gd + i);
-		kfree(gd->major_name);
-		kfree(gd->part);
-		if (gd->de_arr)
-			kfree (gd->de_arr);
-		if (gd->flags)
-			kfree (gd->flags);
-		kfree(gd);
-		for (i = 0; i < MAX_DRIVES; i++)
-			ch->gd[i] = NULL;
-	}
-
-	/*
-	 * Reinitialize the channel handler, but preserve any special methods for
-	 * it.
-	 */
-
-	old = *ch;
-	init_hwif_data(ch, ch->index);
-	ch->lock = old.lock;
-	ch->tuneproc = old.tuneproc;
-	ch->speedproc = old.speedproc;
-	ch->selectproc = old.selectproc;
-	ch->resetproc = old.resetproc;
-	ch->intrproc = old.intrproc;
-	ch->maskproc = old.maskproc;
-	ch->quirkproc = old.quirkproc;
-	ch->ata_read = old.ata_read;
-	ch->ata_write = old.ata_write;
-	ch->atapi_read = old.atapi_read;
-	ch->atapi_write = old.atapi_write;
-	ch->udma_setup = old.udma_setup;
-	ch->udma_enable = old.udma_enable;
-	ch->udma_start = old.udma_start;
-	ch->udma_stop = old.udma_stop;
-	ch->udma_init = old.udma_init;
-	ch->udma_irq_status = old.udma_irq_status;
-	ch->udma_timeout = old.udma_timeout;
-	ch->udma_irq_lost = old.udma_irq_lost;
-	ch->busproc = old.busproc;
-	ch->bus_state = old.bus_state;
-	ch->dma_base = old.dma_base;
-	ch->dma_extra = old.dma_extra;
-	ch->config_data = old.config_data;
-	ch->select_data = old.select_data;
-	ch->proc = old.proc;
-	/* FIXME: most propably this is always right:! */
-#ifndef CONFIG_BLK_DEV_IDECS
-	ch->irq = old.irq;
-#endif
-	ch->major = old.major;
-	ch->chipset = old.chipset;
-	ch->autodma = old.autodma;
-	ch->udma_four = old.udma_four;
-#ifdef CONFIG_PCI
-	ch->pci_dev = old.pci_dev;
-#endif
-	ch->straight8 = old.straight8;
-
-abort:
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static int subdriver_match(struct ata_channel *channel, struct ata_operations *ops)
-{
-	int count, unit;
-
-	if (!channel->present)
-		return 0;
-
-	count = 0;
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device *drive = &channel->drives[unit];
-		if (drive->present && !drive->driver) {
-			(*ops->attach)(drive);
-			if (drive->driver != NULL)
-				++count;
-		}
-	}
-	return count;
-}
-
-/*
- * Register an IDE interface, specifing exactly the registers etc
- * Set initializing=1 iff calling before probes have taken place.
- */
-int ide_register_hw(hw_regs_t *hw)
-{
-	int h;
-	int retry = 1;
-	struct ata_channel *ch;
-
-	do {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if (ch->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
-				goto found;
-		}
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if ((!ch->present && (ch->unit == ATA_PRIMARY) && !initializing) ||
-			    (!ch->hw.io_ports[IDE_DATA_OFFSET] && initializing))
-				goto found;
-		}
-		for (h = 0; h < MAX_HWIFS; ++h)
-			ide_unregister(&ide_hwifs[h]);
-	} while (retry--);
-
-	return -1;
-
-found:
-	ide_unregister(ch);
-	if (ch->present)
-		return -1;
-	memcpy(&ch->hw, hw, sizeof(*hw));
-	memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->hw.io_ports));
-	ch->irq = hw->irq;
-	ch->noprobe = 0;
-	ch->chipset = hw->chipset;
-
-	if (!initializing) {
-		ideprobe_init();
-		/* FIXME: Do we really have to call it second time here?! */
-		ide_driver_module();
-	}
-
-	/* Look up whatever there is a subdriver, which will serve this
-	 * device and execute the attach method it is providing.
-	 */
-	{
-		struct ata_operations *tmp;
-		unsigned long flags;
-
-		spin_lock_irqsave(&ata_drivers_lock, flags);
-		for(tmp = ata_drivers; tmp; tmp = tmp->next) {
-			if (subdriver_match(ch, tmp) > 0)
-				break;
-		}
-		spin_unlock_irqrestore(&ata_drivers_lock, flags);
-	}
-
-	return (initializing || ch->present) ? h : -1;
-}
-
-/****************************************************************************
- * FIXME: rewrite the following crap:
- */
-
-/*
- * Parsing for ide_setup():
- *
- * 1. the first char of s must be '='.
- * 2. if the remainder matches one of the supplied keywords,
- *     the index (1 based) of the keyword is negated and returned.
- * 3. if the remainder is a series of no more than max_vals numbers
- *     separated by commas, the numbers are saved in vals[] and a
- *     count of how many were saved is returned.  Base10 is assumed,
- *     and base16 is allowed when prefixed with "0x".  The number of 
- *     values read will be placed in vals[0], and the values read will
- *     placed in vals[1] to vals[max_vals].
- * 4. otherwise, zero is returned.
- */
-static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
-{
-	int i;
-
-	if (*s++ == '=') {
-		/*
-		 * Try matching against the supplied keywords,
-		 * and return -(index+1) if we match one
-		 */
-		if (keywords != NULL) {
-			for (i = 0; *keywords != NULL; ++i) {
-				if (!strcmp(s, *keywords++))
-					return -(i+1);
-			}
-		}
-		/*
-		 * Look for a series of no more than "max_vals"
-		 * numeric values separated by commas, in base10,
-		 * or base16 when prefixed with "0x".
-		 * Return a count of how many were found.
-		 */
-        	get_options(s, max_vals+1, vals);
-	        return vals[0];
-	}
-	return 0;
-}
-
-/*
- * This sets reasonable default values into all fields of all instances of the
- * channles and drives, but only on the first call.  Subsequent calls have no
- * effect (they don't wipe out anything).
- *
- * This routine is normally called at driver initialization time, but may also
- * be called MUCH earlier during kernel "command-line" parameter processing.
- * As such, we cannot depend on any other parts of the kernel (such as memory
- * allocation) to be functioning yet.
- *
- * This is too bad, as otherwise we could dynamically allocate the ata_device
- * structs as needed, rather than always consuming memory for the max possible
- * number (MAX_HWIFS * MAX_DRIVES) of them.
- */
-#define MAGIC_COOKIE 0x12345678
-static void __init init_global_data(void)
-{
-	unsigned int h;
-	static unsigned long magic_cookie = MAGIC_COOKIE;
-
-	if (magic_cookie != MAGIC_COOKIE)
-		return;		/* already initialized */
-	magic_cookie = 0;
-
-	/* Initialize all interface structures */
-	for (h = 0; h < MAX_HWIFS; ++h)
-		init_hwif_data(&ide_hwifs[h], h);
-
-	/* Add default hw interfaces */
-	ide_init_default_hwifs();
-}
-
-/*
- * This gets called VERY EARLY during initialization, to handle kernel "command
- * line" strings beginning with "hdx=".  It gets called even before the actual
- * module gets initialized.
- *
- * Please look at Documentation/ide.txt to see the complete list of supported
- * options.
- */
-static int __init ata_hd_setup(char *s)
-{
-	int vals[4];
-	struct ata_channel *ch;	/* FIXME:  Channel parms should not be accessed in ata_hd_setup */
-	struct ata_device *drive;
-	unsigned int hw, unit;
-	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
-
-	if (s[0] == '=')	/* hd= is for hd.c driver and not us */
-		return 0;
-
-	printk(KERN_INFO  "hd%s", s);
-	init_global_data();
-
-	if (s[0] >= 'a' && s[0] <= max_drive) {
-		static const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
-				"serialize", "autotune", "noautotune",
-				"slow", "flash", "scsi", NULL};
-		unit = s[0] - 'a';
-		hw   = unit / MAX_DRIVES;
-		unit = unit % MAX_DRIVES;
-		ch = &ide_hwifs[hw];
-		drive = &ch->drives[unit];
-
-		/* Look for hdx=ide-* */
-		if (!strncmp(s+1, "=ide-", 5)) {
-			strncpy(drive->driver_req, s+2, 9);
-			goto done;
-		}
-		/*
-		 * Look for last lun option:  "hdxlun="
-		 */
-		if (!strncmp(s+1, "lun=", 4)) {
-	                if (*get_options(s+5, 2, vals) || vals[0]!=1)
-				goto bad_option;
-			if (vals[1] >= 0 && vals[1] <= 7) {
-				drive->last_lun = vals[1];
-				drive->forced_lun = 1;
-			} else
-				printk(" -- BAD LAST LUN! Expected value from 0 to 7");
-			goto done;
-		}
-		switch (match_parm(s+1, hd_words, vals, 3)) {
-			case -1: /* "none" */
-				drive->nobios = 1;  /* drop into "noprobe" */
-			case -2: /* "noprobe" */
-				drive->noprobe = 1;
-				goto done;
-			case -3: /* "nowerr" */
-				drive->bad_wstat = BAD_R_STAT;
-				ch->noprobe = 0;	/* FIXME:  Channel parm */
-				goto done;
-			case -4: /* "cdrom" */
-				drive->present = 1;
-				drive->type = ATA_ROM;
-				ch->noprobe = 0;	/* FIXME:  Channel parm */
-				goto done;
-			case -5: /* "serialize" */
-				printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
-				goto bad_option;
-			case -6: /* "autotune" */
-				drive->autotune = 1;
-				goto done;
-			case -7: /* "noautotune" */
-				drive->autotune = 2;
-				goto done;
-			case -8: /* "slow" */
-				ch->slow = 1;		/* FIXME:  Channel parm */
-				goto done;
-			case -9: /* "flash" */
-				drive->ata_flash = 1;
-				goto done;
-			case -10: /* "scsi" */
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-				drive->scsi = 1;
-				goto done;
-#else
-				drive->scsi = 0;
-				goto bad_option;
-#endif
-			case 3: /* cyl,head,sect */
-				drive->type	= ATA_DISK;
-				drive->cyl	= drive->bios_cyl  = vals[1];
-				drive->head	= drive->bios_head = vals[2];
-				drive->sect	= drive->bios_sect = vals[3];
-				drive->present	= 1;
-				drive->forced_geom = 1;
-				ch->noprobe = 0;
-				goto done;
-			default:
-				goto bad_option;
-		}
-	}
-
-bad_option:
-	printk(" -- BAD OPTION\n");
-	return 1;
-
-done:
-	printk("\n");
-
-	return 1;
-}
-
-/*
- * This gets called VERY EARLY during initialization, to handle kernel "command
- * line" strings beginning with "ide".  It gets called even before the actual
- * module gets initialized.
- *
- * Please look at Documentation/ide.txt to see the complete list of supported
- * options.
- */
-int __init ide_setup(char *s)
-{
-	int i, vals[4];
-	struct ata_channel *ch;
-	unsigned int hw;
-	const char max_ch  = '0' + (MAX_HWIFS - 1);
-
-	printk(KERN_INFO  "ide%s", s);
-	init_global_data();
-
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-	if (!strcmp(s, "=doubler")) {
-		extern int ide_doubler;
-
-		printk(KERN_INFO" : Enabled support for ATA doublers\n");
-		ide_doubler = 1;
-		return 1;
-	}
-#endif
-
-	if (!strcmp(s, "=nodma")) {
-		printk(KERN_INFO "ATA: Prevented DMA\n");
-		noautodma = 1;
-		return 1;
-	}
-
-#ifdef CONFIG_PCI
-	if (!strcmp(s, "=reverse")) {
-		ide_scan_direction = 1;
-		printk(" : Enabled support for IDE inverse scan order.\n");
-		return 1;
-	}
-#endif
-
-	/*
-	 * Look for bus speed option:  "idebus="
-	 */
-	if (!strncmp(s, "bus=", 4)) {
-		if (*get_options(s+4, 2, vals) || vals[0] != 1)
-			goto bad_option;
-		idebus_parameter = vals[1];
-		goto done;
-	}
-
-	/*
-	 * Look for interface options:  "idex="
-	 */
-	if (s[0] >= '0' && s[0] <= max_ch) {
-		/*
-		 * Be VERY CAREFUL changing this: note hardcoded indexes below
-		 */
-		const char *ide_options[] = {
-			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", NULL };
-		const char *ide_words[] = {
-			"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
-		hw = s[0] - '0';
-		ch = &ide_hwifs[hw];
-
-
-		switch (match_parm(s + 1, ide_options, vals, 1)) {
-			case -7: /* ata66 */
-#ifdef CONFIG_PCI
-				ch->udma_four = 1;
-				goto done;
-#else
-				ch->udma_four = 0;
-				goto bad_channel;
-#endif
-			case -6: /* dma */
-				ch->autodma = 1;
-				goto done;
-			case -5: /* reset */
-				ch->reset = 1;
-				goto done;
-			case -4: /* noautotune */
-				ch->drives[0].autotune = 2;
-				ch->drives[1].autotune = 2;
-				goto done;
-			case -3: /* autotune */
-				ch->drives[0].autotune = 1;
-				ch->drives[1].autotune = 1;
-				goto done;
-			case -2: /* "serialize" */
-				{
-					struct ata_channel *mate;
-
-					mate = &ide_hwifs[hw ^ 1];
-					ch->serialized = 1;
-					mate->serialized = 1;
-				}
-				goto done;
-
-			case -1: /* "noprobe" */
-				ch->noprobe = 1;
-				goto done;
-		}
-
-		/*
-		 * Check for specific chipset name
-		 */
-		i = match_parm(s + 1, ide_words, vals, 3);
-
-		/*
-		 * Cryptic check to ensure chipset not already set for a channel:
-		 */
-		if (i) {			/* is parameter a chipset name? */
-			if (ide_hwifs[hw].chipset != ide_unknown)
-				goto bad_option;	/* chipset already specified */
-			if (i != -7 && hw != 0)
-				goto bad_channel;	/* chipset drivers are for "ide0=" only */
-			if (i != -7 && ide_hwifs[1].chipset != ide_unknown)
-				goto bad_option;	/* chipset for 2nd port already specified */
-			printk("\n");
-		}
-
-		switch (i) {
-#ifdef CONFIG_BLK_DEV_PDC4030
-			case -7:  /* "dc4030" */
-			{
-				extern void init_pdc4030(void);
-				init_pdc4030();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_ALI14XX
-			case -6:  /* "ali14xx" */
-			{
-				extern void init_ali14xx(void);
-				init_ali14xx();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
-			case -5:  /* "umc8672" */
-			{
-				extern void init_umc8672(void);
-				init_umc8672();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
-			case -4:  /* "dtc2278" */
-			{
-				extern void init_dtc2278(void);
-				init_dtc2278();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-			case -3:  /* "cmd640_vlb" */
-			{
-				extern int cmd640_vlb; /* flag for cmd640.c */
-				cmd640_vlb = 1;
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
-			case -2:  /* "ht6560b" */
-			{
-				extern void init_ht6560b(void);
-				init_ht6560b();
-				goto done;
-			}
-#endif
-#if CONFIG_BLK_DEV_QD65XX
-			case -1:  /* "qd65xx" */
-			{
-				extern void init_qd65xx(void);
-				init_qd65xx();
-				goto done;
-			}
-#endif
-			case 1:	/* base */
-				vals[2] = vals[1] + 0x206; /* default ctl */
-			case 2: /* base,ctl */
-				vals[3] = 0;	/* default irq = probe for it */
-			case 3: /* base,ctl,irq */
-				ch->hw.irq = vals[3];
-				ide_init_hwif_ports(&ch->hw, (ide_ioreg_t) vals[1], (ide_ioreg_t) vals[2], &ch->irq);
-				memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports));
-				ch->irq = vals[3];
-				ch->noprobe  = 0;
-				ch->chipset  = ide_generic;
-				goto done;
-
-			case 0:
-				goto bad_option;
-			default:
-				printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
-				return 1;
-		}
-	}
-
-bad_option:
-	printk(" -- BAD OPTION\n");
-	return 1;
-
-bad_channel:
-	printk("-- NOT SUPPORTED ON ide%d", hw);
-
-done:
-	printk("\n");
-
-	return 1;
-}
-
-/****************************************************************************/
-
-int ata_register_device(struct ata_device *drive, struct ata_operations *driver)
-{
-	unsigned long flags;
-
-	/* FIXME: The locking here doesn't make the slightest sense! */
-	spin_lock_irqsave(&ide_lock, flags);
-
-	if (!drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		spin_unlock_irqrestore(&ide_lock, flags);
-		return 1;
-	}
-
-	drive->driver = driver;
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	/* Default autotune or requested autotune */
-	if (drive->autotune != 2) {
-		struct ata_channel *ch = drive->channel;
-		if (ch->udma_setup) {
-
-			/*
-			 * Force DMAing for the beginning of the check.  Some
-			 * chipsets appear to do interesting things, if not
-			 * checked and cleared.
-			 *
-			 *   PARANOIA!!!
-			 */
-
-			spin_lock_irqsave(ch->lock, flags);
-			udma_enable(drive, 0, 0);
-			ch->udma_setup(drive, ch->modes_map);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
-			udma_tcq_enable(drive, 1);
-#endif
-			spin_unlock_irqrestore(ch->lock, flags);
-		}
-
-		/* Only CD-ROMs and tape drives support DSC overlap.  But only
-		 * if they are alone on a channel. */
-		if (drive->type == ATA_ROM || drive->type == ATA_TAPE) {
-			int single = 0;
-			int unit;
-
-			for (unit = 0; unit < MAX_DRIVES; ++unit)
-				if (drive->channel->drives[unit].present)
-					++single;
-
-			drive->dsc_overlap = (single == 1);
-		} else
-			drive->dsc_overlap = 0;
-
-	}
-	return 0;
-}
-
-/*
- * This is in fact the default cleanup routine.
- *
- * FIXME: Check whatever we maybe don't call it twice!.
- */
-int ata_unregister_device(struct ata_device *drive)
-{
-	if (drive->usage || drive->busy || !ata_ops(drive))
-		return 1;
-
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
-	pnpide_init(0);
-#endif
-	drive->driver = NULL;
-
-	return 0;
-}
-
-
-/*
- * Register an ATA subdriver for a particular device type.
- */
-int register_ata_driver(struct ata_operations *driver)
-{
-	unsigned long flags;
-	int index;
-	int count = 0;
-
-	spin_lock_irqsave(&ata_drivers_lock, flags);
-	driver->next = ata_drivers;
-	ata_drivers = driver;
-	spin_unlock_irqrestore(&ata_drivers_lock, flags);
-
-	for (index = 0; index < MAX_HWIFS; ++index)
-		count += subdriver_match(&ide_hwifs[index], driver);
-
-	return count;
-}
-
-EXPORT_SYMBOL(register_ata_driver);
-
-/*
- * Unregister an ATA sub-driver for a particular device type.
- */
-void unregister_ata_driver(struct ata_operations *driver)
-{
-	struct ata_operations **tmp;
-	unsigned long flags;
-	int index;
-	int unit;
-
-	spin_lock_irqsave(&ata_drivers_lock, flags);
-	for (tmp = &ata_drivers; *tmp != NULL; tmp = &(*tmp)->next) {
-		if (*tmp == driver) {
-			*tmp = driver->next;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&ata_drivers_lock, flags);
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		struct ata_channel *ch = &ide_hwifs[index];
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (drive->driver == driver)
-				(*ata_ops(drive)->cleanup)(drive);
-		}
-	}
-}
-
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_lock);
-
-devfs_handle_t ide_devfs_handle;
-
-EXPORT_SYMBOL(ata_register_device);
-EXPORT_SYMBOL(ata_unregister_device);
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_unregister);
-EXPORT_SYMBOL(get_info_ptr);
-
-/*
- * Handle power handling related events ths system informs us about.
- */
-static int ata_sys_notify(struct notifier_block *this, unsigned long event, void *x)
-{
-	int i;
-
-	switch (event) {
-		case SYS_HALT:
-		case SYS_POWER_OFF:
-		case SYS_RESTART:
-			break;
-		default:
-			return NOTIFY_DONE;
-	}
-
-	printk(KERN_INFO "flushing ATA/ATAPI devices: ");
-
-	for (i = 0; i < MAX_HWIFS; i++) {
-		int unit;
-		struct ata_channel *ch = &ide_hwifs[i];
-
-		if (!ch->present)
-			continue;
-
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (!drive->present)
-				continue;
-
-			/* set the drive to standby */
-			printk("%s ", drive->name);
-			if (ata_ops(drive)) {
-				if (event != SYS_RESTART) {
-					if (ata_ops(drive)->standby && ata_ops(drive)->standby(drive))
-						continue;
-				}
-
-				if (ata_ops(drive)->cleanup)
-					ata_ops(drive)->cleanup(drive);
-			}
-		}
-	}
-	printk("\n");
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block ata_notifier = {
-	ata_sys_notify,
-	NULL,
-	5
-};
-
-/*
- * This is the global initialization entry point.
- */
-static int __init ata_module_init(void)
-{
-	printk(KERN_INFO "ATA/ATAPI device driver v" VERSION "\n");
-
-	ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
-
-	/*
-	 * Because most of the ATA adapters represent the timings in unit of
-	 * bus clocks, and there is no known reliable way to detect the bus
-	 * clock frequency, we assume 50 MHz for non-PCI (VLB, EISA) and 33 MHz
-	 * for PCI based systems. Since assuming only hurts performance and not
-	 * stability, this is OK. The user can change this on the command line
-	 * by using the "idebus=XX" parameter. While the system_bus_speed
-	 * variable is in kHz units, we accept both MHz and kHz entry on the
-	 * command line for backward compatibility.
-	 */
-
-	system_bus_speed = 50000;
-
-	if (pci_present())
-	    system_bus_speed = 33333;
-
-	if (idebus_parameter >= 20 && idebus_parameter <= 80) {
-
-		system_bus_speed = idebus_parameter * 1000;
-
-		switch (system_bus_speed) {
-			case 33000: system_bus_speed = 33333; break;
-			case 37000: system_bus_speed = 37500; break;
-			case 41000: system_bus_speed = 41666; break;
-			case 66000: system_bus_speed = 66666; break;
-		}
-	}
-
-	if (idebus_parameter >= 20000 && idebus_parameter <= 80000)
-	    system_bus_speed = idebus_parameter;
-
-	printk(KERN_INFO "ATA: %s bus speed %d.%dMHz\n",
-		pci_present() ? "PCI" : "System", system_bus_speed / 1000, system_bus_speed / 100 % 10);
-
-	init_global_data();
-
-	initializing = 1;
-
-#ifdef CONFIG_PCI
-	/*
-	 * Register the host chip drivers.
-	 */
-# ifdef CONFIG_BLK_DEV_PIIX
-	init_piix();
-# endif
-# ifdef CONFIG_BLK_DEV_VIA82CXXX
-	init_via82cxxx();
-# endif
-# ifdef CONFIG_BLK_DEV_PDC202XX
-	init_pdc202xx();
-# endif
-# ifdef CONFIG_BLK_DEV_RZ1000
-	init_rz1000();
-# endif
-# ifdef CONFIG_BLK_DEV_SIS5513
-	init_sis5513();
-# endif
-# ifdef CONFIG_BLK_DEV_CMD64X
-	init_cmd64x();
-# endif
-# ifdef CONFIG_BLK_DEV_OPTI621
-	init_opti621();
-# endif
-# ifdef CONFIG_BLK_DEV_TRM290
-	init_trm290();
-# endif
-# ifdef CONFIG_BLK_DEV_NS87415
-	init_ns87415();
-# endif
-# ifdef CONFIG_BLK_DEV_AEC62XX
-	init_aec62xx();
-# endif
-# ifdef CONFIG_BLK_DEV_SL82C105
-	init_sl82c105();
-# endif
-# ifdef CONFIG_BLK_DEV_HPT34X
-	init_hpt34x();
-# endif
-# ifdef CONFIG_BLK_DEV_HPT366
-	init_hpt366();
-# endif
-# ifdef CONFIG_BLK_DEV_ALI15X3
-	init_ali15x3();
-# endif
-# ifdef CONFIG_BLK_DEV_CY82C693
-	init_cy82c693();
-# endif
-# ifdef CONFIG_BLK_DEV_CS5530
-	init_cs5530();
-# endif
-# ifdef CONFIG_BLK_DEV_AMD74XX
-	init_amd74xx();
-# endif
-# ifdef CONFIG_BLK_DEV_SVWKS
-	init_svwks();
-# endif
-# ifdef CONFIG_BLK_DEV_IT8172
-	init_it8172();
-# endif
-
-	init_ata_pci_misc();
-
-	/*
-	 * Detect and initialize "known" IDE host chip types.
-	 */
-	if (pci_present()) {
-# ifdef CONFIG_PCI
-		ide_scan_pcibus(ide_scan_direction);
-# else
-#  ifdef CONFIG_BLK_DEV_RZ1000
-		ide_probe_for_rz100x();
-#  endif
-# endif
-	}
-#endif
-
-#ifdef CONFIG_ETRAX_IDE
-	init_e100_ide();
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-	ide_probe_for_cmd640x();
-#endif
-#ifdef CONFIG_BLK_DEV_PDC4030
-	ide_probe_for_pdc4030();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	pmac_ide_probe();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
-	icside_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
-	rapide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_GAYLE
-	gayle_init();
-#endif
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-	falconide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	macide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_Q40IDE
-	q40ide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_BUDDHA
-	buddha_init();
-#endif
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
-	pnpide_init(1);
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-# if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_irq_lock, NULL, NULL);/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-# endif
-
-	ideprobe_init();
-
-# if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_irq_lock);/* for atari only */
-	}
-# endif
-#endif
-
-	/*
-	 * Initialize all device type driver modules.
-	 */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-	idedisk_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDECD
-	ide_cdrom_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDETAPE
-	idetape_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-	idefloppy_init();
-#endif
-
-	initializing = 0;
-
-	register_reboot_notifier(&ata_notifier);
-
-	return 0;
-}
-
-static char *options = NULL;
-
-static int __init init_ata(void)
-{
-
-	if (options != NULL && *options) {
-		char *next = options;
-
-		while ((options = next) != NULL) {
-			if ((next = strchr(options,' ')) != NULL)
-				*next++ = 0;
-			if (!strncmp(options,"hd",2)) {
-				if (!ata_hd_setup(options+2))
-					printk(KERN_ERR "Unknown option '%s'\n", options);
-			}
-			else if (!strncmp(options,"ide",3)) {
-				if (!ide_setup(options+3))
-					printk(KERN_ERR "Unknown option '%s'\n", options);
-			}
-		}
-	}
-	return ata_module_init();
-}
-
-static void __exit cleanup_ata(void)
-{
-	int h;
-
-	unregister_reboot_notifier(&ata_notifier);
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_unregister(&ide_hwifs[h]);
-	}
-
-	devfs_unregister(ide_devfs_handle);
-}
-
-module_init(init_ata);
-module_exit(cleanup_ata);
-
-#ifndef MODULE
-
-/* command line option parser */
-__setup("ide", ide_setup);
-__setup("hd", ata_hd_setup);
-
-#endif
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/ns87415.c	Tue Aug 27 12:28:08 2002
@@ -19,23 +19,21 @@
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "pcihost.h"
-
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
 /*
  * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (drive->channel),
+ * the IRQ associated with the port (HWIF(drive)),
  * and selects either PIO or DMA handshaking for the next I/O operation.
  */
-static void ns87415_prepare_drive(struct ata_device *drive, unsigned int use_dma)
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned long flags;
@@ -44,12 +42,12 @@
 	new = *old;
 
 	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->unit);
+	bit = 1 << (8 + hwif->channel);
 	new = drive->present ? (new & ~bit) : (new | bit);
 
 	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->unit << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->unit << 1));
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
 	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
 	if (new != *old) {
@@ -77,56 +75,61 @@
 	local_irq_restore(flags);
 }
 
-static void ns87415_selectproc(struct ata_device *drive)
+static void ns87415_selectproc (ide_drive_t *drive)
 {
 	ns87415_prepare_drive (drive, drive->using_dma);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-
-static int ns87415_udma_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
-
-	dma_stat = inb(ch->dma_base+2);
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	outb(inb(dma_base)|6, dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
-	udma_destroy_table(ch);				/* and free any DMA resources */
-
-	return (dma_stat & 7) != 4;	/* verify good DMA status */
-
-}
-
-static int ns87415_udma_init(struct ata_device *drive, struct request *rq)
+static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-
-	if (udma_pci_init(drive, rq))		/* use standard DMA stuff */
-		return ATA_OP_CONTINUES;
+	ide_hwif_t	*hwif = HWIF(drive);
+	byte		dma_stat;
 
-	ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
-
-	return ATA_OP_FINISHED;
-}
-
-static int ns87415_udma_setup(struct ata_device *drive, int map)
-{
-	if (drive->type != ATA_DISK) {
-		udma_enable(drive, 0, 0);
-
-		return 0;
+	switch (func) {
+		case ide_dma_end: /* returns 1 on error, 0 otherwise */
+			drive->waiting_for_dma = 0;
+			dma_stat = IN_BYTE(hwif->dma_base+2);
+			/* stop DMA */
+			OUT_BYTE(IN_BYTE(hwif->dma_base)&~1, hwif->dma_base);
+			/* from ERRATA: clear the INTR & ERROR bits */
+			OUT_BYTE(IN_BYTE(hwif->dma_base)|6, hwif->dma_base);
+			/* and free any DMA resources */
+			ide_destroy_dmatable(drive);
+			/* verify good DMA status */
+			return (dma_stat & 7) != 4;
+		case ide_dma_write:
+		case ide_dma_read:
+			/* select DMA xfer */
+			ns87415_prepare_drive(drive, 1);
+			/* use standard DMA stuff */
+			if (!ide_dmaproc(func, drive))
+				return 0;
+			/* DMA failed: select PIO xfer */
+			ns87415_prepare_drive(drive, 0);
+			return 1;
+		case ide_dma_check:
+			if (drive->media != ide_disk)
+				return ide_dmaproc(ide_dma_off_quietly, drive);
+			/* Fallthrough... */
+		default:
+			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
 	}
-	return udma_pci_setup(drive, map);
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-static void __init ide_init_ns87415(struct ata_channel *hwif)
+void __init ide_init_ns87415 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned int ctrl, using_inta;
-	u8 progif;
+	byte progif;
+#ifdef __sparc_v9__
+	int timeout;
+	byte stat;
+#endif
+
+	hwif->autodma = 0;
+	hwif->selectproc = &ns87415_selectproc;
 
 	/* Set a good latency timer and cache line size value. */
 	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
@@ -144,24 +147,14 @@
 	(void) pci_read_config_dword(dev, 0x40, &ctrl);
 	(void) pci_read_config_byte(dev, 0x09, &progif);
 	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->unit << 1));
+	using_inta = progif & (1 << (hwif->channel << 1));
 	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->unit));
-	if (hwif->unit == ATA_SECONDARY) {
-
-		/* FIXME: If we are initializing the secondary channel, let us
-		 * assume that the primary channel got initialized just a tad
-		 * bit before now.  It would be much cleaner if the data in
-		 * ns87415_control just got duplicated.
-		 */
-
-		if (!hwif->select_data)
-		    hwif->select_data = (unsigned long)
-			&ns87415_control[ns87415_count - 1];
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
 	} else {
-		if (!hwif->select_data)
-		    hwif->select_data = (unsigned long)
-			&ns87415_control[ns87415_count++];
+		hwif->select_data = (unsigned long)
+					&ns87415_control[ns87415_count++];
 		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
 		if (using_inta)
 			ctrl &= ~(1 << 6);	/* unmask INTA */
@@ -177,52 +170,35 @@
 #ifdef __sparc_v9__
 		/*
 		 * XXX: Reset the device, if we don't it will not respond
-		 *      to select properly during first probe.
+		 *      to SELECT_DRIVE() properly during first probe_hwif().
 		 */
-		ata_reset(hwif);
+		timeout = 10000;
+		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			udelay(50);
+			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+                	if (stat == 0xff)
+                        	break;
+        	} while ((stat & BUSY_STAT) && --timeout);
 #endif
 	}
 
-	if (hwif->dma_base)
-		outb(0x60, hwif->dma_base + 2);
-
 	if (!using_inta)
-		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
-	else {
-		static int primary_irq = 0;
-
-		/* Ugly way to let the primary and secondary channel on the
-		 * chip use the same IRQ line.
-		 */
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
 
-		if (hwif->unit == ATA_PRIMARY)
-			primary_irq = hwif->irq;
-		else if (!hwif->irq)
-			hwif->irq = primary_irq;
-	}
+	if (!hwif->dma_base)
+		return;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->udma_stop = ns87415_udma_stop;
-		hwif->udma_init = ns87415_udma_init;
-		hwif->udma_setup = ns87415_udma_setup;
-	}
-#endif
-
-	hwif->selectproc = &ns87415_selectproc;
-}
-
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_NS,
-	.device = PCI_DEVICE_ID_NS_87415,
-	.init_channel = ide_init_ns87415,
-	.bootable = ON_BOARD,
-};
-
-int __init init_ns87415(void)
-{
-	ata_register_chipset(&chipset);
-
-        return 0;
+	OUT_BYTE(0x60, hwif->dma_base + 2);
+	hwif->dmaproc = &ns87415_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
diff -Nru a/drivers/ide/opti621.c b/drivers/ide/opti621.c
--- a/drivers/ide/opti621.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/opti621.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,10 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
  *
  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- *
+ */
+
+/*
  * Authors:
  * Jaromir Koutek <miri@punknet.cz>,
  * Jan Harkes <jaharkes@cwi.nl>,
@@ -59,9 +62,9 @@
  * by hdparm.
  *
  * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8.
+ * by Jaromir Koutek, for 2.1.8. 
  * Initial version of driver.
- *
+ * 
  * Version 0.2
  * Number 0.2 skipped.
  *
@@ -77,13 +80,14 @@
  * by Jaromir Koutek
  * Updates for use with (again) new IDE block driver.
  * Update of documentation.
- *
+ * 
  * Version 0.6, Jan 2, 1999
  * by Jaromir Koutek
  * Reversed to version 0.3 of the driver, because
  * 0.5 doesn't work.
  */
 
+#undef REALLY_SLOW_IO	/* most systems can safely undef this */
 #define OPTI621_DEBUG		/* define for debug messages */
 
 #include <linux/types.h>
@@ -99,8 +103,7 @@
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
 #define OPTI621_MAX_PIO 3
 /* In fact, I do not have any PIO 4 drive
@@ -137,7 +140,7 @@
 
 /* there are stored pio numbers from other calls of opti621_tune_drive */
 
-static void compute_pios(struct ata_device *drive, u8 pio)
+static void compute_pios(ide_drive_t *drive, byte pio)
 /* Store values into drive->drive_data
  *	second_contr - 0 for primary controller, 1 for secondary
  *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
@@ -145,18 +148,14 @@
  */
 {
 	int d;
-	struct ata_channel *hwif = drive->channel;
-
-	if (pio == PIO_DONT_KNOW)
-		drive->drive_data = min(ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0, OPTI621_MAX_PIO);
-	else
-		drive->drive_data = pio;
+	ide_hwif_t *hwif = HWIF(drive);
 
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
 	for (d = 0; d < 2; ++d) {
 		drive = &hwif->drives[d];
 		if (drive->present) {
 			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = min(ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0, OPTI621_MAX_PIO);
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
 #ifdef OPTI621_DEBUG
 			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
 #endif
@@ -166,7 +165,7 @@
 	}
 }
 
-static int cmpt_clk(int time, int bus_speed)
+int cmpt_clk(int time, int bus_speed)
 /* Returns (rounded up) time in clocks for time in ns,
  * with bus_speed in MHz.
  * Example: bus_speed = 40 MHz, time = 80 ns
@@ -175,36 +174,36 @@
  * Use idebus=xx to select right frequency.
  */
 {
-	return ((time*bus_speed+999999)/1000000);
+	return ((time*bus_speed+999)/1000);
 }
 
-static void write_reg(u8 value, int reg)
+static void write_reg(byte value, int reg)
 /* Write value to register reg, base of register
  * is at reg_base (0x1f0 primary, 0x170 secondary,
  * if not changed by PCI configuration).
  * This is from setupvic.exe program.
  */
 {
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	outb(value, reg_base+reg);
-	outb(0x83, reg_base+2);
+	IN_WORD(reg_base+1);
+	IN_WORD(reg_base+1);
+	OUT_BYTE(3, reg_base+2);
+	OUT_BYTE(value, reg_base+reg);
+	OUT_BYTE(0x83, reg_base+2);
 }
 
-static u8 read_reg(int reg)
+static byte read_reg(int reg)
 /* Read value from register reg, base of register
  * is at reg_base (0x1f0 primary, 0x170 secondary,
  * if not changed by PCI configuration).
  * This is from setupvic.exe program.
  */
 {
-	u8 ret;
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	ret=inb(reg_base+reg);
-	outb(0x83, reg_base+2);
+	byte ret;
+	IN_WORD(reg_base+1);
+	IN_WORD(reg_base+1);
+	OUT_BYTE(3, reg_base+2);
+	ret=IN_BYTE(reg_base+reg);
+	OUT_BYTE(0x83, reg_base+2);
 	return ret;
 }
 
@@ -217,52 +216,47 @@
 static void compute_clocks(int pio, pio_clocks_t *clks)
 {
         if (pio != PIO_NOT_EXIST) {
-		int adr_setup;
-		int data_pls;
-		struct ata_timing *t;
-
-		t = ata_timing_data(pio);
-
-		adr_setup = t->setup;
-		data_pls = t->active;
-		clks->address_time = cmpt_clk(adr_setup, system_bus_speed);
-		clks->data_time = cmpt_clk(data_pls, system_bus_speed);
-		clks->recovery_time = cmpt_clk(t->cycle
-			- adr_setup-data_pls, system_bus_speed);
-		if (clks->address_time<1) clks->address_time = 1;
-		if (clks->address_time>4) clks->address_time = 4;
-		if (clks->data_time<1) clks->data_time = 1;
-		if (clks->data_time>16) clks->data_time = 16;
-		if (clks->recovery_time<2) clks->recovery_time = 2;
-		if (clks->recovery_time>17) clks->recovery_time = 17;
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
+ 	       	adr_setup = ide_pio_timings[pio].setup_time;
+  	      	data_pls = ide_pio_timings[pio].active_time;
+	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+     			- adr_setup-data_pls, bus_speed);
+     		if (clks->address_time<1) clks->address_time = 1;
+     		if (clks->address_time>4) clks->address_time = 4;
+     		if (clks->data_time<1) clks->data_time = 1;
+     		if (clks->data_time>16) clks->data_time = 16;
+     		if (clks->recovery_time<2) clks->recovery_time = 2;
+     		if (clks->recovery_time>17) clks->recovery_time = 17;
 	} else {
 		clks->address_time = 1;
 		clks->data_time = 1;
 		clks->recovery_time = 2;
 		/* minimal values */
 	}
-
+ 
 }
 
-/* Main tune procedure, called from tuneproc.
-   Assumes IRQ's are disabled or at least that no other process will
-   attempt to access the IDE registers concurrently.
-*/
-static void opti621_tune_drive(struct ata_device *drive, u8 pio)
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, byte pio)
 {
 	/* primary and secondary drives share some registers,
 	 * so we have to program both drives
 	 */
-	u8 pio1, pio2;
+	unsigned long flags;
+	byte pio1, pio2;
 	pio_clocks_t first, second;
 	int ax, drdy;
-	u8 cycle1, cycle2, misc;
-	struct ata_channel *hwif = drive->channel;
+	byte cycle1, cycle2, misc;
+	ide_hwif_t *hwif = HWIF(drive);
 
 	/* sets drive->drive_data for both drives */
 	compute_pios(drive, pio);
-	pio1 = hwif->drives[0].drive_data;
-	pio2 = hwif->drives[1].drive_data;
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
 
 	compute_clocks(pio1, &first);
 	compute_clocks(pio2, &second);
@@ -283,10 +277,12 @@
 		hwif->name, ax, second.data_time, second.recovery_time, drdy);
 #endif
 
-	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	outb(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	outb(0xff, reg_base+5);		/* hmm, setupvic.exe does this ;-) */
-	inb(reg_base+CNTRL_REG);	/* if reads 0xff, adapter not exist? */
+	spin_lock_irqsave(&ide_lock, flags);
+
+     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+	OUT_BYTE(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
+	OUT_BYTE(0xff, reg_base+5);	/* hmm, setupvic.exe does this ;-) */
+	IN_BYTE(reg_base+CNTRL_REG); 	/* if reads 0xff, adapter not exist? */
 	read_reg(CNTRL_REG);		/* if reads 0xc0, no interface exist? */
 	read_reg(STRAP_REG);		/* read version, probably 0 */
 
@@ -303,44 +299,41 @@
 	write_reg(0x85, CNTRL_REG);	/* use Register-A for drive 0 */
 					/* use Register-B for drive 1 */
 
-	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
-					/*  and read prefetch for both drives */
+ 	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
+ 					/*  and read prefetch for both drives */
+
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /*
  * ide_init_opti621() is called once for each hwif found at boot.
  */
-static void __init ide_init_opti621(struct ata_channel *hwif)
+void __init ide_init_opti621 (ide_hwif_t *hwif)
 {
+	hwif->autodma = 0;
 	hwif->drives[0].drive_data = PIO_DONT_KNOW;
 	hwif->drives[1].drive_data = PIO_DONT_KNOW;
 	hwif->tuneproc = &opti621_tune_drive;
+
+	/* safety call for Anton A */
+	hwif->dma_base = 0;
 }
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_OPTI,
-		.device = PCI_DEVICE_ID_OPTI_82C621,
-		.init_channel = ide_init_opti621,
-		.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_OPTI,
-		.device = PCI_DEVICE_ID_OPTI_82C825,
-		.init_channel = ide_init_opti621,
-		.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
-		.bootable = ON_BOARD
-	},
-};
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-int __init init_opti621(void)
+void __init fixup_device_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+#if 0
+	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) &&
+	    !(PCI_FUNC(dev->devfn) & 1))
+#else
+	if ((dev->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+#endif
+		return; /* OPTI621 is more than only a IDE controller */
 
-        return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+
diff -Nru a/drivers/ide/pcidma.c b/drivers/ide/pcidma.c
--- a/drivers/ide/pcidma.c	Tue Aug 27 12:28:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,576 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 2002	     Marcin Dalecki <martin@dalecki.de>
- *
- *  Based on previous work by:
- *
- *  Copyright (c) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- *  Copyright (c) 1995-1998  Mark Lord
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- * Those are the generic BM DMA support functions for PCI bus based systems.
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include "timing.h"
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
-/*
- * This is the handler for disk read/write DMA interrupts.
- */
-ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq)
-{
-	u8 dma_stat;
-	dma_stat = udma_stop(drive);
-
-	if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
-		if (!dma_stat) {
-			ata_end_request(drive, rq, 1, rq->nr_sectors);
-
-			return ATA_OP_FINISHED;
-		}
-		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n",
-		       drive->name, dma_stat);
-	}
-
-	return ata_error(drive, rq, __FUNCTION__);
-}
-
-/*
- * FIXME: taskfiles should be a map of pages, not a long virt address... /jens
- * FIXME: I agree with Jens --mdcki!
- */
-static int build_sglist(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	struct scatterlist *sg = ch->sg_table;
-	int nents = 0;
-
-	if ((rq->flags & REQ_SPECIAL) && (drive->type == ATA_DISK)) {
-		struct ata_taskfile *args = rq->special;
-#if 1
-		unsigned char *virt_addr = rq->buffer;
-		int sector_count = rq->nr_sectors;
-#else
-		nents = blk_rq_map_sg(&drive->queue, rq, ch->sg_table);
-
-		if (nents > rq->nr_segments)
-			printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
-#endif
-
-		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-
-		/*
-		 * FIXME: This depends upon a hard coded page size!
-		 */
-		if (sector_count > 128) {
-			memset(&sg[nents], 0, sizeof(*sg));
-
-			sg[nents].page = virt_to_page(virt_addr);
-			sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
-			sg[nents].length = 128  * SECTOR_SIZE;
-			++nents;
-			virt_addr = virt_addr + (128 * SECTOR_SIZE);
-			sector_count -= 128;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].page = virt_to_page(virt_addr);
-		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
-		sg[nents].length =  sector_count  * SECTOR_SIZE;
-		++nents;
-	} else {
-		nents = blk_rq_map_sg(&drive->queue, rq, ch->sg_table);
-
-		if (rq->q && nents > rq->nr_phys_segments)
-			printk("ide-dma: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
-
-		if (rq_data_dir(rq) == READ)
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-
-	}
-
-	return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction);
-}
-
-/*
- * 1 dma-ing, 2 error, 4 intr
- */
-static ide_startstop_t dma_timer_expiry(struct ata_device *drive, struct request *rq, unsigned long *wait)
-{
-	/* FIXME: What's that? */
-	u8 dma_stat = inb(drive->channel->dma_base + 2);
-
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif
-
-#if 0
-	drive->expiry = NULL;	/* one free ride for now */
-#endif
-	*wait = 0;
-	if (dma_stat & 2) {	/* ERROR */
-		ata_status(drive, 0, 0);
-		return ata_error(drive, rq, __FUNCTION__);
-	}
-	if (dma_stat & 1) {	/* DMAing */
-		*wait = WAIT_CMD;
-		return ATA_OP_CONTINUES;
-	}
-
-	return ATA_OP_FINISHED;
-}
-
-int ata_start_dma(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	unsigned int reading = 0;
-
-	if (rq_data_dir(rq) == READ)
-		reading = 1 << 3;
-
-	/* try PIO instead of DMA */
-	if (!udma_new_table(drive, rq))
-		return 1;
-
-	outl(ch->dmatable_dma, dma_base + 4); /* PRD table */
-	outb(reading, dma_base);		/* specify r/w */
-	outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-
-	return 0;
-}
-
-/* generic udma_setup() function for drivers having ->speedproc/tuneproc */
-int udma_generic_setup(struct ata_device *drive, int map)
-{
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *ch = drive->channel;
-	int on = 0;
-	u8 mode;
-
-	if (!id || (drive->type != ATA_DISK && ch->no_atapi_autodma))
-		return 0;
-
-	if ((map & XFER_UDMA_80W) && !eighty_ninty_three(drive))
-		map &= ~XFER_UDMA_80W;
-
-	if ((id->capability & 1) && ch->autodma && ch->speedproc) {
-
-		/* Consult the list of known "bad" devices. */
-		if (udma_black_list(drive))
-			goto set_dma;
-
-		mode = ata_timing_mode(drive, map);
-
-		/* Device is UltraDMA capable. */
-		if (mode & XFER_UDMA) {
-			if((on = !ch->speedproc(drive, mode)))
-				goto set_dma;
-
-			printk(KERN_WARNING "%s: UDMA auto-tune failed.\n", drive->name);
-
-			map &= ~XFER_UDMA_ALL;
-			mode = ata_timing_mode(drive, map);
-		}
-
-		/* Device is regular DMA capable. */
-		if (mode & (XFER_SWDMA | XFER_MWDMA)) {
-			if((on = !ch->speedproc(drive, mode)))
-				goto set_dma;
-
-			printk(KERN_WARNING "%s: DMA auto-tune failed.\n", drive->name);
-		}
-
-		/* FIXME: this seems non-functional  --bkz */
-		/* Consult the list of known "good" devices. */
-		if (udma_white_list(drive)) {
-
-			if (id->eide_dma_time > 150)
-				goto set_dma;
-
-			printk(KERN_INFO "%s: device is on DMA whitelist.\n", drive->name);
-//			on = 1;
-		}
-
-		/* Revert to PIO. */
-		if (!on && ch->tuneproc)
-			ch->tuneproc(drive, 255);
-	}
-
-set_dma:
-	udma_enable(drive, on, !on);
-
-	return 0;
-}
-
-/*
- * Configure a device for DMA operation.
- */
-int udma_pci_setup(struct ata_device *drive, int map)
-{
-	int config_allows_dma = 1;
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *ch = drive->channel;
-
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->type != ATA_DISK)
-		config_allows_dma = 0;
-#endif
-
-	if (id && (id->capability & 1) && ch->autodma && config_allows_dma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			udma_enable(drive, 0, 1);
-
-			return 0;
-		}
-
-		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Consult the list of known "good" drives */
-		if (udma_white_list(drive)) {
-			udma_enable(drive, 1, 1);
-
-			return 0;
-		}
-	}
-	udma_enable(drive, 0, 0);
-
-	return 0;
-}
-
-/*
- * Needed for allowing full modular support of ide-driver
- */
-void ide_release_dma(struct ata_channel *ch)
-{
-	if (!ch->dma_base)
-		return;
-
-	if (ch->dmatable_cpu) {
-		pci_free_consistent(ch->pci_dev,
-				    PRD_ENTRIES * PRD_BYTES,
-				    ch->dmatable_cpu,
-				    ch->dmatable_dma);
-		ch->dmatable_cpu = NULL;
-	}
-	if (ch->sg_table) {
-		kfree(ch->sg_table);
-		ch->sg_table = NULL;
-	}
-	if ((ch->dma_extra) && (ch->unit == 0))
-		release_region((ch->dma_base + 16), ch->dma_extra);
-	release_region(ch->dma_base, 8);
-	ch->dma_base = 0;
-}
-
-/****************************************************************************
- * PCI specific UDMA channel method implementations.
- */
-
-/*
- * This is the generic part of the DMA setup used by the host chipset drivers
- * in the corresponding DMA setup method.
- *
- * FIXME: there are some places where this gets used driectly for "error
- * recovery" in the ATAPI drivers. This was just plain wrong before, in esp.
- * not portable, and just got uncovered now.
- */
-void udma_pci_enable(struct ata_device *drive, int on, int verbose)
-{
-	struct ata_channel *ch = drive->channel;
-	int set_high = 1;
-	u8 unit;
-	u64 addr;
-
-	/* Fall back to the default implementation. */
-	unit = (drive->select.b.unit & 0x01);
-	addr = BLK_BOUNCE_HIGH;
-
-	if (!on) {
-		if (verbose)
-			printk("%s: DMA disabled\n", drive->name);
-		set_high = 0;
-		outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-		udma_tcq_enable(drive, 0);
-#endif
-	}
-
-	/* toggle bounce buffers */
-
-	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = drive->channel->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-
-	drive->using_dma = on;
-
-	if (on) {
-		outb(inb(ch->dma_base + 2) | (1 << (5 + unit)), ch->dma_base + 2);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
-		udma_tcq_enable(drive, 1);
-#endif
-	}
-}
-
-/*
- * This prepares a dma request.  Returns 0 if all went okay, returns 1
- * otherwise.  May also be invoked from trm290.c
- */
-int udma_new_table(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned int *table = ch->dmatable_cpu;
-	int i;
-	struct scatterlist *sg;
-
-	ch->sg_nents = i = build_sglist(drive, rq);
-	if (!i)
-		return 0;
-
-	BUG_ON(i > PRD_ENTRIES);
-
-	sg = ch->sg_table;
-	while (i--) {
-		u32 cur_addr = sg_dma_address(sg);
-		u32 cur_len = sg_dma_len(sg) & 0xffff;
-
-		/* Delete this test after linux ~2.5.35, as we care
-		   about performance in this loop. */
-		BUG_ON(cur_len > ch->max_segment_size);
-
-		*table++ = cpu_to_le32(cur_addr);
-		*table++ = cpu_to_le32(cur_len);
-
-		sg++;
-	}
-
-#ifdef CONFIG_BLK_DEV_TRM290
-	if (ch->chipset == ide_trm290)
-		*--table |= cpu_to_le32(0x80000000);
-#endif
-
-	return ch->sg_nents;
-}
-
-/*
- * Teardown mappings after DMA has completed.
- */
-void udma_destroy_table(struct ata_channel *ch)
-{
-	pci_unmap_sg(ch->pci_dev, ch->sg_table, ch->sg_nents, ch->sg_dma_direction);
-}
-
-/*
- * Prepare the channel for a DMA startfer. Please note that only the broken
- * Pacific Digital host chip needs the reques to be passed there to decide
- * about addressing modes.
- */
-void udma_pci_start(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-
-	/* Note that this is done *after* the cmd has been issued to the drive,
-	 * as per the BM-IDE spec.  The Promise Ultra33 doesn't work correctly
-	 * when we do this part before issuing the drive cmd.
-	 */
-	outb(inb(dma_base) | 1, dma_base);	/* start DMA */
-}
-
-int udma_pci_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
-
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-}
-
-/*
- * FIXME: This should be attached to a channel as we can see now!
- */
-int udma_pci_irq_status(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	u8 dma_stat;
-
-	/* default action */
-	dma_stat = inb(ch->dma_base + 2);
-
-	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-}
-
-void udma_pci_timeout(struct ata_device *drive)
-{
-	printk(KERN_ERR "%s: UDMA timeout!\n", drive->name);
-}
-
-void udma_pci_irq_lost(struct ata_device *drive)
-{
-}
-
-/*
- * This can be called for a dynamically installed interface. Don't __init it
- */
-void ata_init_dma(struct ata_channel *ch, unsigned long dma_base)
-{
-	if (!request_region(dma_base, 8, ch->name)) {
-		printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n");
-
-		return;
-	}
-	printk(KERN_INFO"    %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7);
-	ch->dma_base = dma_base;
-	ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev,
-						  PRD_ENTRIES * PRD_BYTES,
-						  &ch->dmatable_dma);
-	if (ch->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
-
-	ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (ch->sg_table == NULL) {
-		pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    ch->dmatable_cpu, ch->dmatable_dma);
-		goto dma_alloc_failure;
-	}
-
-	/*
-	 * We could just assign them, and then leave it up to the chipset
-	 * specific code to override these after they've called this function.
-	 */
-	if (!ch->udma_setup)
-		ch->udma_setup = udma_pci_setup;
-	if (!ch->udma_enable)
-		ch->udma_enable = udma_pci_enable;
-	if (!ch->udma_start)
-		ch->udma_start = udma_pci_start;
-	if (!ch->udma_stop)
-		ch->udma_stop = udma_pci_stop;
-	if (!ch->udma_init)
-		ch->udma_init = udma_pci_init;
-	if (!ch->udma_irq_status)
-		ch->udma_irq_status = udma_pci_irq_status;
-	if (!ch->udma_timeout)
-		ch->udma_timeout = udma_pci_timeout;
-	if (!ch->udma_irq_lost)
-		ch->udma_irq_lost = udma_pci_irq_lost;
-
-	if (ch->chipset != ide_trm290) {
-		u8 dma_stat = inb(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
-	}
-	printk("\n");
-	return;
-
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
-}
-
-/*
- * This is the default read write function.
- *
- * It's exported only for host chips which use it for fallback or (too) late
- * capability checking.
- */
-int udma_pci_init(struct ata_device *drive, struct request *rq)
-{
-	u8 cmd;
-
-	if (ata_start_dma(drive, rq))
-		return ATA_OP_FINISHED;
-
-	/* No DMA transfers on ATAPI devices. */
-	if (drive->type != ATA_DISK)
-		return ATA_OP_CONTINUES;
-
-	if (rq_data_dir(rq) == READ)
-		cmd = 0x08;
-	else
-		cmd = 0x00;
-
-	ata_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);
-	if (drive->addressing)
-		outb(cmd ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-	else
-		outb(cmd ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-
-	udma_start(drive, rq);
-
-	return ATA_OP_CONTINUES;
-}
-
-EXPORT_SYMBOL(ide_dma_intr);
-EXPORT_SYMBOL(udma_pci_enable);
-EXPORT_SYMBOL(udma_pci_start);
-EXPORT_SYMBOL(udma_pci_stop);
-EXPORT_SYMBOL(udma_pci_init);
-EXPORT_SYMBOL(udma_pci_irq_status);
-EXPORT_SYMBOL(udma_pci_timeout);
-EXPORT_SYMBOL(udma_pci_irq_lost);
diff -Nru a/drivers/ide/pcihost.h b/drivers/ide/pcihost.h
--- a/drivers/ide/pcihost.h	Tue Aug 27 12:27:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,129 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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.
- */
-
-/*
- * Declarations needed for the handling of PCI (mostly) based host chip set
- * interfaces.
- */
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern int init_piix(void);
-#endif
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern int init_via82cxxx(void);
-#endif
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern int init_pdc202xx(void);
-#endif
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern int init_rz1000(void);
-#endif
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern int init_sis5513(void);
-#endif
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern int init_cmd64x(void);
-#endif
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern int init_opti621(void);
-#endif
-#ifdef CONFIG_BLK_DEV_TRM290
-extern int init_trm290(void);
-#endif
-#ifdef CONFIG_BLK_DEV_NS87415
-extern int init_ns87415(void);
-#endif
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern int init_aec62xx(void);
-#endif
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern int init_sl82c105(void);
-#endif
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern int init_hpt34x(void);
-#endif
-#ifdef CONFIG_BLK_DEV_HPT366
-extern int init_hpt366(void);
-#endif
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern int init_ali15x3(void);
-#endif
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern int init_cy82c693(void);
-#endif
-#ifdef CONFIG_BLK_DEV_CS5530
-extern int init_cs5530(void);
-#endif
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern int init_amd74xx(void);
-#endif
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern int init_svwks(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IT8172
-extern int init_it8172(void);
-#endif
-extern int init_ata_pci_misc(void);
-
-/*
- * Some combi chips, which can be used on the PCI bus or the VL bus can be in
- * some systems acessed either through the PCI config space or through the
- * hosts IO bus.  If the corresponding initialization driver is using the host
- * IO space to deal with them please define the following.
- */
-
-#define	ATA_PCI_IGNORE	((void *)-1)
-
-/*
- * Just to prevent us from having too many tinny headers we have consolidated
- * all those declarations here.
- */
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_probe_for_rz100x(void);
-#endif
-
-typedef struct ide_pci_enablebit_s {
-	u8	reg;	/* pci configuration register holding the enable-bit */
-	u8	mask;	/* mask used to isolate the enable-bit */
-	u8	val;	/* expected value of masked register when "enabled" */
-} ide_pci_enablebit_t;
-
-/* Flags used to untangle quirk handling.
- */
-#define ATA_F_DMA	0x001
-#define ATA_F_NODMA	0x002	/* no DMA mode supported at all */
-#define ATA_F_NOADMA	0x004	/* DMA has to be enabled explicitely */
-#define ATA_F_FIXIRQ	0x008	/* fixed irq wiring */
-#define ATA_F_SER	0x010	/* serialize on first and second channel interrupts */
-#define ATA_F_IRQ	0x020	/* trust IRQ information from config */
-#define ATA_F_PHACK	0x040	/* apply PROMISE hacks */
-#define ATA_F_HPTHACK	0x080	/* apply HPT366 hacks */
-#define ATA_F_SIMPLEX	0x100	/* force treatment as simple device */
-
-
-struct ata_pci_device {
-	unsigned short		vendor;
-	unsigned short		device;
-	unsigned int		(*init_chipset)(struct pci_dev *);
-	void			(*init_channel)(struct ata_channel *);
-	void			(*init_dma)(struct ata_channel *, unsigned long);
-	ide_pci_enablebit_t	enablebits[2];
-	unsigned int		bootable;
-	unsigned int		extra;
-	unsigned int		flags;
-	struct ata_pci_device *next;	/* beware we link the netries in pleace */
-};
-
-extern void ata_register_chipset(struct ata_pci_device *d);
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/pdc202xx.c	Tue Aug 27 12:28:08 2002
@@ -1,15 +1,7 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  linux/drivers/ide/pdc202xx.c	Version 0.30	May. 28, 2002
- *
- *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2002		BartÅ^Âomiej Å»oÅ^Ânierkiewicz
- *
- *  Portions Copyright (C) 1999-2002 Promise Technology, Inc.
- *  Author:	Frank Tiernan <frankt@promise.com>
- *		Hank Yang <support@promise.com.tw>
+/*
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
  *
  *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
  *  compiled into the kernel if you have more than one card installed.
@@ -23,21 +15,17 @@
  *
  *  The latest chipset code will support the following ::
  *  Three Ultra33 controllers and 12 drives.
- *
  *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
  *  The 8/4 ratio is a BIOS code limit by promise.
  *
  *  UNLESS you enable "CONFIG_PDC202XX_BURST"
  *
- *  History:
- *  Sync 2.5 driver with Promise 2.4 driver v1.20.0.7 (07/11/02):
- *		- Add PDC20271 support
- *		- Disable LBA48 support on PDC20262
- *		- Fix ATAPI UDMA port value
- *		- Add new quirk drive
- *		- Adjust timings for all drives when using ATA133
- *		- Update pdc202xx_reset() waiting time
- *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
  */
 
 #include <linux/config.h>
@@ -48,21 +36,260 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
 
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+byte pdc202xx_proc = 0;
+
+#define PDC202_MAX_DEVS		5
+
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+const char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+char *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+char *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	u32 bibma  = pci_resource_start(dev, 4);
+	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+	u8 hi = 0, lo = 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((unsigned short)bibma + 0x02);
+	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
+
+	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
+	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
+	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
+	u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
+	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
+	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
+	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "PDC20267"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "PDC20265"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "PDC20263"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "PDC20262"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "PDC20246");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "PDC202XX"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+		(c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
+		(c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
+	p += sprintf(p, "DMA Mode:       %s           %s "
+			"         %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s "
+			"          %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
+#if 0
+	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+#endif
+	return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+//	u32 bibma = pci_resource_start(dev, 4);
+
+//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+//	u16 reg50h = 0, word88 = 0;
+//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "PDC20277");
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "PDC20276"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "PDC20275"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "PDC20271"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "PDC20269 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "PDC20268 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p += sprintf(p, "PDC20270 TX2/4"); break;
+		default:
+			p += sprintf(p, "PDC202XX"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_PROMISE_20277:
+			case PCI_DEVICE_ID_PROMISE_20276:
+			case PCI_DEVICE_ID_PROMISE_20275:
+			case PCI_DEVICE_ID_PROMISE_20271:
+			case PCI_DEVICE_ID_PROMISE_20269:
+			case PCI_DEVICE_ID_PROMISE_20268:
+			case PCI_DEVICE_ID_PROMISE_20268R:
+				p = pdc202xx_info_new(buffer, dev);
+				break;
+			default:
+				p = pdc202xx_info(buffer, dev);
+				break;
+		}
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
 /* A Register */
 #define	SYNC_ERRDY_EN	0xC0
 
@@ -71,372 +298,453 @@
 #define	IORDY_EN	0x20	/* PIO: IOREADY */
 #define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
 
-#define PDC_CLK		0x11
-#define PDC_PRIMARY	0x1a
-#define PDC_SECONDARY	0x1b
-#define PDC_UDMA	0x1f
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
 
 #if PDC202XX_DECODE_REGISTER_INFO
 
-struct pdc_bit_messages {
-	u8 mask;
-	const char *msg;
-};
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
 
-static struct pdc_bit_messages pdc_reg_A[] = {
-	{0x80, "SYNC_IN"},
-	{0x40, "ERRDY_EN"},
-	{0x20, "IORDY_EN"},
-	{0x10, "PREFETCH_EN"},
-	/* PA3-PA0 - PIO "A" timing */
-};
+static void decode_registers (byte registers, byte value)
+{
+	byte	bit = 0, bit1 = 0, bit2 = 0;
 
-static struct pdc_bit_messages pdc_reg_B[] = {
-	/* MB2-MB0 - DMA "B" timing */
-	{0x10, "PIO_FORCED/PB4"},	/* PIO_FORCE 1:0 */
-	/* PB3-PB0 - PIO "B" timing */
-};
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
 
-static struct pdc_bit_messages pdc_reg_C[] = {
-	{0x80, "DMARQp"},
-	{0x40, "IORDYp"},
-	{0x20, "DMAR_EN"},
-	{0x10, "DMAW_EN"},
-	/* MC3-MC0 - DMA "C" timing */
-};
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-static void pdc_dump_bits(struct pdc_bit_messages *msgs, u8 bits)
+#if 0
+static byte pdc202xx_ratemask (ide_drive_t *drive)
 {
-	int i;
-
-	printk(KERN_DEBUG " { ");
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	byte mode = 0x00;
 
-	for (i = 0; i < ARRAY_SIZE(msgs); i++, msgs++)
-		if (bits & msgs->mask)
-			printk(KERN_DEBUG "%s ", msgs->msg);
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			{ mode |= 0x04; break; }
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			{ mode |= 0x03; break; }
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			{ mode |= 0x03; break; }
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			{ mode |= 0x02; break; }
+		case PCI_DEVICE_ID_PROMISE_20246:
+			{ mode |= 0x01; break; }
+		default:
+			return (mode &= ~0xF8);
+	}
 
-	printk(KERN_DEBUG " }\n");
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
 }
-#endif				/* PDC202XX_DECODE_REGISTER_INFO */
-
-static struct ata_device *drives[4];
 
-int check_in_drive_lists(struct ata_device *drive)
+static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
 {
-	static const char *pdc_quirk_drives[] = {
-		"QUANTUM FIREBALLlct08 08",
-		"QUANTUM FIREBALLP KA6.4",
-		"QUANTUM FIREBALLP KA9.1",
-		"QUANTUM FIREBALLP LM20.4",
-		"QUANTUM FIREBALLP KX13.6",
-		"QUANTUM FIREBALLP KX20.5",
-		"QUANTUM FIREBALLP KX27.3",
-		"QUANTUM FIREBALLP LM20.5",
-		NULL
-	};
-
-	const char **list = pdc_quirk_drives;
-	struct hd_driveid *id = drive->id;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = pdc202xx_ratemask(drive);
 
-	while (*list)
-		if (strstr(id->model, *list++))
-			return 2;
-	return 0;
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
 }
 
-static int __init pdc202xx_modes_map(struct ata_channel *ch)
+#else
+static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
 {
-	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
+	return speed;
+}
+#endif
 
-	switch (ch->pci_dev->device) {
-	case PCI_DEVICE_ID_PROMISE_20276:
-	case PCI_DEVICE_ID_PROMISE_20275:
-	case PCI_DEVICE_ID_PROMISE_20271:
-	case PCI_DEVICE_ID_PROMISE_20269:
-		map |= XFER_UDMA_133;
-	case PCI_DEVICE_ID_PROMISE_20268R:
-	case PCI_DEVICE_ID_PROMISE_20268:
-		map &= ~XFER_SWDMA;
-	case PCI_DEVICE_ID_PROMISE_20267:
-	case PCI_DEVICE_ID_PROMISE_20265:
-		map |= XFER_UDMA_100;
-	case PCI_DEVICE_ID_PROMISE_20262:
-		map |= XFER_UDMA_66;
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
 
-		if (!ch->udma_four) {
-			printk(KERN_WARNING
-			       "%s: 40-pin cable, speed reduced to UDMA(33) mode.\n",
-			       ch->name);
-			map &= ~XFER_UDMA_80W;
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
 		}
 	}
-
-	return map;
+	return 0;
 }
 
-static int pdc202xx_tune_chipset(struct ata_device *drive, u8 speed)
+static int pdc202xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	u32 drive_conf;
-	u8 drive_pci, AP, BP, CP, TA = 0, TB, TC = 0;
-#if PDC202XX_DECODE_REGISTER_INFO
-	u8 DP;
-#endif
-
-	drive_pci = 0x60 + (drive->dn << 2);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte speed		= pdc202xx_ratefilter(drive, xferspeed);
+
+	unsigned int		drive_conf;
+	byte			drive_pci, AP, BP, CP, DP;
+	byte			TA = 0, TB = 0, TC = 0;
+
+	switch (drive->dn) {
+		case 0: drive_pci = 0x60; break;
+		case 1: drive_pci = 0x64; break;
+		case 2: drive_pci = 0x68; break;
+		case 3: drive_pci = 0x6c; break;
+		default: return -1;
+	}
 
-	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
 		return -1;
 
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	pci_read_config_byte(dev, drive_pci, &AP);
-	pci_read_config_byte(dev, drive_pci + 1, &BP);
-	pci_read_config_byte(dev, drive_pci + 2, &CP);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
 
-	switch (speed) {
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	case XFER_UDMA_5:
-	case XFER_UDMA_4:
-		TB = 0x20;
-		TC = 0x01;
-		break;
-	case XFER_UDMA_3:
-		TB = 0x40;
-		TC = 0x02;
-		break;
-	case XFER_UDMA_2:
-		TB = 0x20;
-		TC = 0x01;
-		break;
-	case XFER_UDMA_1:
-		TB = 0x40;
-		TC = 0x02;
-		break;
-	case XFER_UDMA_0:
-		TB = 0x60;
-		TC = 0x03;
-		break;
-	case XFER_MW_DMA_2:
-		TB = 0x60;
-		TC = 0x03;
-		break;
-	case XFER_MW_DMA_1:
-		TB = 0x60;
-		TC = 0x04;
-		break;
-	case XFER_MW_DMA_0:
-		TB = 0x60;
-		TC = 0x05;
-		break;
-	case XFER_SW_DMA_2:
-		TB = 0x60;
-		TC = 0x05;
-		break;
-	case XFER_SW_DMA_1:
-		TB = 0x80;
-		TC = 0x06;
-		break;
-	case XFER_SW_DMA_0:
-		TB = 0xC0;
-		TC = 0x0B;
-		break;
-#endif
-	case XFER_PIO_4:
-		TA = 0x01;
-		TB = 0x04;
-		break;
-	case XFER_PIO_3:
-		TA = 0x02;
-		TB = 0x06;
-		break;
-	case XFER_PIO_2:
-		TA = 0x03;
-		TB = 0x08;
-		break;
-	case XFER_PIO_1:
-		TA = 0x05;
-		TB = 0x0C;
-		break;
-	case XFER_PIO_0:
-	default:
-		TA = 0x09;
-		TB = 0x13;
-		break;
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	}
 
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, drive_pci + 1,
-				      (BP & ~0xf0) | TB);
-		pci_write_config_byte(dev, drive_pci + 2,
-				      (CP & ~0x0f) | TC);
-	} else
-#endif
-	{
-		pci_write_config_byte(dev, drive_pci, (AP & ~0x0f) | TA);
-		pci_write_config_byte(dev, drive_pci + 1,
-				      (BP & ~0x07) | TB);
+		/* case XFER_UDMA_6: */
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
 	}
 
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, drive_pci, &AP);
-	pci_read_config_byte(dev, drive_pci + 1, &BP);
-	pci_read_config_byte(dev, drive_pci + 2, &CP);
-	pci_read_config_byte(dev, drive_pci + 3, &DP);
-
-	printk(KERN_DEBUG "AP(%x): PIO(A) = %d\n", AP, AP & 0x0f);
-	pdc_dump_bits(pdc_reg_A, AP);
-
-	printk(KERN_DEBUG "BP(%x): DMA(B) = %d PIO(B) = %d\n",
-	       BP, (BP & 0xe0) >> 5, BP & 0x0f);
-	pdc_dump_bits(pdc_reg_B, BP);
-
-	printk(KERN_DEBUG "CP(%x): DMA(C) = %d\n", CP, CP & 0x0f);
-	pdc_dump_bits(pdc_reg_C, CP);
-
-	printk(KERN_DEBUG "DP(%x)\n", DP);
-#endif
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
 
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
 #if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %02x drive%d 0x%08x ",
-	       drive->name, speed, drive->dn, drive_conf);
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
 	printk("0x%08x\n", drive_conf);
-#endif
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
 
-	return ide_config_drive_speed(drive, speed);
+	return (ide_config_drive_speed(drive, speed));
 }
 
-#define set_2regs(a, b) \
-        OUT_BYTE((a + adj), indexreg); \
-	OUT_BYTE(b, datareg);
-
-#define set_reg_and_wait(value, reg, delay) \
-	OUT_BYTE(value, reg); \
-        mdelay(delay);
-
-static int pdc202xx_new_tune_chipset(struct ata_device *drive, u8 speed)
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	struct ata_channel *hwif = drive->channel;
-	u32 high_16 = pci_resource_start(hwif->pci_dev, 4);
-	u32 indexreg = high_16 + (hwif->unit ? 0x09 : 0x01);
-	u32 datareg = indexreg + 2;
-
-	u8 adj = (drive->dn % 2) ? 0x08 : 0x00;
-	u8 thold = 0x10;
-	int err, i, j = hwif->unit ? 2 : 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	unsigned long indexreg	= (hwif->dma_base + 1);
+	unsigned long datareg	= (hwif->dma_base + 3);
+#else
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
+	unsigned long datareg	= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	byte thold		= 0x10;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+	byte speed		= pdc202xx_ratefilter(drive, xferspeed);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	/* Setting tHOLD bit to 0 if using UDMA mode 2 */
 	if (speed == XFER_UDMA_2) {
 		OUT_BYTE((thold + adj), indexreg);
 		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
 	}
-#endif
-
-	for (i = 0; i < 2; i++)
-		if (hwif->drives[i].present)
-			drives[i + j] = &hwif->drives[i];
-
-	err = ide_config_drive_speed(drive, speed);
-
-	/* For modes < UDMA mode 6 we need only to SET_FEATURE */
-	if (speed < XFER_UDMA_6)
-		return err;
-
-	/* We need to adjust timings to ATA133 clock if ATA133 drives exist */
-	for (i = 0; i < 4; i++) {
-		if (!drives[i])
-			continue;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-		/* Primary = 0x01, Secondary = 0x09 */
-		indexreg = high_16 + ((i > 1) ? 0x09 : 0x01);
-		datareg = indexreg + 2;
-
-		/* Master = 0x00, Slave = 0x08 */
-		adj = (i % 2) ? 0x08 : 0x00;
-
-		switch (drives[i]->current_speed) {
+	switch (speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
 		case XFER_UDMA_6:
-			set_2regs(0x10, 0x1a);
-			set_2regs(0x11, 0x01);
-			set_2regs(0x12, 0xcb);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x01, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
 			break;
 		case XFER_UDMA_5:
-			set_2regs(0x10, 0x1a);
-			set_2regs(0x11, 0x02);
-			set_2regs(0x12, 0xcb);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x02, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
 			break;
 		case XFER_UDMA_4:
-			set_2regs(0x10, 0x1a);
-			set_2regs(0x11, 0x03);
-			set_2regs(0x12, 0xcd);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x03, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
 			break;
 		case XFER_UDMA_3:
-			set_2regs(0x10, 0x1a);
-			set_2regs(0x11, 0x05);
-			set_2regs(0x12, 0xcd);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x05, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
 			break;
 		case XFER_UDMA_2:
-			set_2regs(0x10, 0x2a);
-			set_2regs(0x11, 0x07);
-			set_2regs(0x12, 0xcd);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x2a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x07, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
 			break;
 		case XFER_UDMA_1:
-			set_2regs(0x10, 0x3a);
-			set_2regs(0x11, 0x0a);
-			set_2regs(0x12, 0xd0);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x3a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0a, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd0, datareg);
 			break;
 		case XFER_UDMA_0:
-			set_2regs(0x10, 0x4a);
-			set_2regs(0x11, 0x0f);
-			set_2regs(0x12, 0xd5);
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x4a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0f, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd5, datareg);
 			break;
 		case XFER_MW_DMA_2:
-			set_2regs(0x0e, 0x69);
-			set_2regs(0x0f, 0x25);
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x69, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
 			break;
 		case XFER_MW_DMA_1:
-			set_2regs(0x0e, 0x6b);
-			set_2regs(0x0f, 0x27);
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x6b, datareg);
+			OUT_BYTE((0x0f+ adj), indexreg);
+			OUT_BYTE(0x27, datareg);
 			break;
 		case XFER_MW_DMA_0:
-			set_2regs(0x0e, 0xdf);
-			set_2regs(0x0f, 0x5f);
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0xdf, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x5f, datareg);
 			break;
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 		case XFER_PIO_4:
-			set_2regs(0x0c, 0x23);
-			set_2regs(0x0d, 0x09);
-			set_2regs(0x13, 0x25);
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x09, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
 			break;
 		case XFER_PIO_3:
-			set_2regs(0x0c, 0x27);
-			set_2regs(0x0d, 0x0d);
-			set_2regs(0x13, 0x35);
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x0d, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x35, datareg);
 			break;
 		case XFER_PIO_2:
-			set_2regs(0x0c, 0x23);
-			set_2regs(0x0d, 0x26);
-			set_2regs(0x13, 0x64);
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x26, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x64, datareg);
 			break;
 		case XFER_PIO_1:
-			set_2regs(0x0c, 0x46);
-			set_2regs(0x0d, 0x29);
-			set_2regs(0x13, 0xa4);
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x46, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x29, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xa4, datareg);
 			break;
 		case XFER_PIO_0:
-			set_2regs(0x0c, 0xfb);
-			set_2regs(0x0d, 0x2b);
-			set_2regs(0x13, 0xac);
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0xfb, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x2b, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xac, datareg);
 			break;
 		default:
-			;
-		}
+			break;
 	}
 
-	return err;
+	return (ide_config_drive_speed(drive, speed));
 }
 
 /*   0    1    2    3    4    5    6   7   8
@@ -446,477 +754,677 @@
  * 180, 120,  90,  90,  90,  60,  30
  *  11,   5,   4,   3,   2,   1,   0
  */
-static void pdc202xx_tune_drive(struct ata_device *drive, u8 pio)
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
 {
-	u8 speed;
+	byte speed = 0x00;
 
-	if (pio == 255)
-		speed = ata_best_pio_mode(drive);
-	else
-		speed = XFER_PIO_0 + min_t(u8, pio, 4);
-
-	pdc202xx_tune_chipset(drive, speed);
+	pio = (pio == 5) ? 4 : pio;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdc202xx_tune_chipset(drive, speed));
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int pdc202xx_tx_udma_setup(struct ata_device *drive, int map)
+static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
 {
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *ch = drive->channel;
-	u32 indexreg = ch->dma_base + 1;
-	u32 datareg = indexreg + 2;
-	u8 adj = (drive->dn % 2) ? 0x08 : 0x00;
-
-	if (drive->type != ATA_DISK)
-		return 0;
-
-	/* IORDY_EN & PREFETCH_EN */
-	if (id->capability & 4)
-		set_2regs(0x13, (IN_BYTE(datareg) | 0x03));
-
-	return udma_generic_setup(drive, map);
+	(void) config_chipset_for_pio(drive, pio);
 }
 
-static int pdc202xx_udma_setup(struct ata_device *drive, int map)
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *hwif = drive->channel;
-	struct hd_driveid *mate_id = hwif->drives[!(drive->dn % 2)].id;
-	struct pci_dev *dev = hwif->pci_dev;
-	u32 high_16 = pci_resource_start(dev, 4);
-	u32 drive_conf;
-	u8 drive_pci = 0, AP, tmp, mode = -1;
-	u8 CLKSPD, mask = hwif->unit ? 0x08 : 0x02;
+	struct hd_driveid *id	= drive->id;
+//	byte mode               = pdc202xx_ratemask(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16   = pci_resource_start(dev, 4);
+	unsigned long dma_base  = hwif->dma_base;
+	unsigned long indexreg	= dma_base + 1;
+	unsigned long datareg	= dma_base + 3;
+	byte iordy		= 0x13;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+	byte cable		= 0;
+	byte jumpbit		= 0;
+	unsigned int		drive_conf;
+	byte			drive_pci = 0;
+	byte			test1, test2, speed = -1;
+	byte			AP;
+	unsigned short		EP;
+	byte CLKSPD		= 0;
+	byte udma_33		= 1;
+	byte udma_66		= (eighty_ninty_three(drive)) ? 1 : 0;
+	byte udma_100		= 0;
+	byte udma_133		= 0;
+	byte mask		= hwif->channel ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+
+	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			udma_133 = (udma_66) ? 1 : 0;
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			udma_100 = 1;
+			udma_66 = 1;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			udma_100 = (udma_66) ? 1 : 0;
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		default:
+			udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
+			break;
+	}
 
+	if (!jumpbit)
+		CLKSPD = IN_BYTE(high_16 + 0x11);
 	/*
 	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operations. If one drive on
+	 * clock for UDMA 3/4 mode operation. If one drive on
 	 * a channel is U66 capable but the other isn't we
 	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued.
-	 * We can do the same in device specific udma_start/stop()
-	 * routines or better try to readjust timings.
-	 *
-	 * FIXME: move this to pdc202xx_tuneproc()
-	 *        right now you can't downgrade from U66 to U33  --bkz
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
 	 */
-	if (id->dma_ultra & 0x0078) {	/* UDMA 3, 4, 5 and 6 */
-		CLKSPD = IN_BYTE(high_16 + PDC_CLK);
-		/* check cable and mate (must be at least udma3 capable) */
-		if (!hwif->udma_four ||
-		    !mate_id || !(mate_id->dma_ultra & 0x0078))
-			OUT_BYTE(CLKSPD & ~mask, high_16 + PDC_CLK);
-		else
-			/* cable ok, mate ok or single drive */
-			OUT_BYTE(CLKSPD | mask, high_16 + PDC_CLK);
-	}
 
-	if (drive->dn > 3)	/* FIXME: remove this --bkz */
-		return 0;
-
-	drive_pci = 0x60 + (drive->dn << 2);
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-		goto chipset_is_set;
-
-	/* FIXME: what if SYNC_ERRDY is enabled for slave
-	   and disabled for master? --bkz */
-	pci_read_config_byte(dev, drive_pci, &AP);
-	/* enable SYNC_ERRDY for master and slave (if enabled for master) */
-	if (!(AP & SYNC_ERRDY_EN)) {
-		if (!(drive->dn % 2)) {
-			pci_write_config_byte(dev, drive_pci,
-					      AP | SYNC_ERRDY_EN);
-		} else {
-			pci_read_config_byte(dev, drive_pci - 4, &tmp);
-			if (tmp & SYNC_ERRDY_EN)
-				pci_write_config_byte(dev, drive_pci,
-						      AP | SYNC_ERRDY_EN);
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		if (!jumpbit)
+			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+		udma_66 = 0;
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive->dn%2)].id) {
+				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+				} else {
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				if (!jumpbit)
+					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+			}
 		}
 	}
 
-      chipset_is_set:
-
-	if (drive->type != ATA_DISK)
-		return 0;
+	if (jumpbit) {
+		if (drive->media != ide_disk)	return ide_dma_off_quietly;
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			OUT_BYTE((iordy + adj), indexreg);
+			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+		}
+		goto jumpbit_is_set;
+	}
 
-	pci_read_config_byte(dev, drive_pci, &AP);
-	if (id->capability & 4)	/* IORDY_EN */
-		pci_write_config_byte(dev, drive_pci, AP | IORDY_EN);
-	pci_read_config_byte(dev, drive_pci, &AP);
-	if (drive->type == ATA_DISK)	/* PREFETCH_EN */
-		pci_write_config_byte(dev, drive_pci, AP | PREFETCH_EN);
+	switch(drive->dn) {
+		case 0:	drive_pci = 0x60;
+			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
+			pci_read_config_byte(dev, (drive_pci), &test1);
+			if (!(test1 & SYNC_ERRDY_EN))
+				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
+			break;
+		case 1:	drive_pci = 0x64;
+			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
+			pci_read_config_byte(dev, 0x60, &test1);
+			pci_read_config_byte(dev, (drive_pci), &test2);
+			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
+				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
+			break;
+		case 2:	drive_pci = 0x68;
+			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
+			pci_read_config_byte(dev, (drive_pci), &test1);
+			if (!(test1 & SYNC_ERRDY_EN))
+				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
+			break;
+		case 3:	drive_pci = 0x6c;
+			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
+			pci_read_config_byte(dev, 0x68, &test1);
+			pci_read_config_byte(dev, (drive_pci), &test2);
+			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
+				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
+			break;
+		default:
+			return ide_dma_off;
+	}
 
-	map = hwif->modes_map;
+chipset_is_set:
 
-	if (!eighty_ninty_three(drive))
-		map &= ~XFER_UDMA_80W;
+	if (drive->media != ide_disk) {
+		hwif->tuneproc(drive, 5);
+		return ide_dma_off_quietly;
+	}
 
-	mode = ata_timing_mode(drive, map);
-	if (mode < XFER_SW_DMA_0) {
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	if (id->capability & 4)	/* IORDY_EN */
+		pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	if (drive->media == ide_disk)	/* PREFETCH_EN */
+		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+
+jumpbit_is_set:
+
+	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
+	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
+	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
+	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
+	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
+	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
+	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
+	else if ((id->dma_1word & 0x0004)&&(!jumpbit))	speed = XFER_SW_DMA_2;
+	else if ((id->dma_1word & 0x0002)&&(!jumpbit))	speed = XFER_SW_DMA_1;
+	else if ((id->dma_1word & 0x0001)&&(!jumpbit))	speed = XFER_SW_DMA_0;
+	else {
 		/* restore original pci-config space */
-		pci_write_config_dword(dev, drive_pci, drive_conf);
-		return 0;
+		if (!jumpbit)
+			pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return ide_dma_off_quietly;
 	}
 
-	return udma_generic_setup(drive, map);
+	(void) hwif->speedproc(drive, speed);
+
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
 }
 
-static void pdc202xx_udma_start(struct ata_device *drive,
-				struct request *rq)
+static int config_drive_xfer_rate (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	u32 high_16 = pci_resource_start(ch->pci_dev, 4);
-	unsigned long atapi_port = high_16 + (ch->unit ? 0x24 : 0x20);
-
-	/* Enable ATAPI UDMA port for 48bit data on PDC20265/PDC20267 */
-	if (drive->addressing) {
-		unsigned long word_count = 0, hankval;
-		u32 clockreg = high_16 + PDC_CLK;
-		u8 clock = IN_BYTE(clockreg);
-
-		OUT_BYTE(clock | (ch->unit ? 0x08 : 0x02), clockreg);
-		word_count = (rq->nr_sectors << 8);
-		hankval =
-		    (rq_data_dir(rq) == READ) ? 0x05 << 24 : 0x06 << 24;
-		hankval |= word_count;
-		outl(hankval, atapi_port);
+	struct hd_driveid *id		= drive->id;
+	ide_hwif_t *hwif		= HWIF(drive);
+	ide_dma_action_t dma_func	= ide_dma_off_quietly;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		hwif->tuneproc(drive, 5);
 	}
 
-	/* Note that this is done *after* the cmd has been issued to the drive,
-	 * as per the BM-IDE spec.  The Promise Ultra33 doesn't work correctly
-	 * when we do this part before issuing the drive cmd.
-	 */
-
-	outb(inb(ch->dma_base) | 1, ch->dma_base);	/* start DMA */
+	return hwif->dmaproc(dma_func, drive);
 }
 
-static int pdc202xx_udma_stop(struct ata_device *drive)
+int pdc202xx_quirkproc (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	u32 high_16 = pci_resource_start(ch->pci_dev, 4);
-	unsigned long atapi_port = high_16 + (ch->unit ? 0x24 : 0x20);
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
 
-	/* Disable ATAPI UDMA port for 48bit data on PDC20265/PDC20267 */
-	if (drive->addressing) {
-		u32 clockreg = high_16 + PDC_CLK;
-		u8 clock;
+/*
+ * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	byte dma_stat		= 0;
+	byte sc1d		= 0;
+	byte newchip		= 0;
+	byte clock		= 0;
+	byte hardware48hack	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+	unsigned long dma_base	= hwif->dma_base;
 
-		outl(0, atapi_port);	/* zero out extra */
-		clock = IN_BYTE(clockreg);
-		OUT_BYTE(clock & ~(ch->unit ? 0x08 : 0x02), clockreg);
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hardware48hack = 1;
+			clock = IN_BYTE(high_16 + 0x11);
+		default:
+			break;
 	}
 
-	outb(inb(dma_base) & ~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base + 2);	/* get DMA status */
-	outb(dma_stat | 6, dma_base + 2);	/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);	/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_begin:
+			/* Note that this is done *after* the cmd has
+			 * been issued to the drive, as per the BM-IDE spec.
+			 * The Promise Ultra33 doesn't work correctly when
+			 * we do this part before issuing the drive cmd.
+			 */
+			if ((drive->addressing == 1) && (hardware48hack)) {
+				struct request *rq = HWGROUP(drive)->rq;
+				unsigned long word_count = 0;
+
+				OUT_BYTE(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+				word_count = (rq->nr_sectors << 8);
+				word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
+				outl(word_count, atapi_reg);
+			}
+			break;
+		case ide_dma_end:
+			if ((drive->addressing == 1) && (hardware48hack)) {
+				outl(0, atapi_reg);	/* zero out extra */
+				clock = IN_BYTE(high_16 + 0x11);
+				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+			}
+			break;
+		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = IN_BYTE(dma_base+2);
+			if (newchip)
+				return (dma_stat & 4) == 4;
+
+			sc1d = IN_BYTE(high_16 + 0x001d);
+			if (hwif->channel) {
+				if ((sc1d & 0x50) == 0x50) goto somebody_else;
+				else if ((sc1d & 0x40) == 0x40)
+					return (dma_stat & 4) == 4;
+			} else {
+				if ((sc1d & 0x05) == 0x05) goto somebody_else;
+				else if ((sc1d & 0x04) == 0x04)
+					return (dma_stat & 4) == 4;
+			}
+somebody_else:
+			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+		case ide_dma_lostirq:
+		case ide_dma_timeout:
+			if (hwif->resetproc != NULL)
+				hwif->resetproc(drive);
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
 }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-static void pdc202xx_bug(struct ata_device *drive)
+void pdc202xx_new_reset (ide_drive_t *drive)
 {
-	if (!drive->channel->resetproc)
-		return;
-	/* Assume naively that resetting the drive may help. */
-	drive->channel->resetproc(drive);
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
 }
 
-#endif
-
-/* FIXME: use generic ata_reset()  --bzolnier */
-static void pdc202xx_reset(struct ata_device *drive)
+void pdc202xx_reset_pci (struct pci_dev *dev)
 {
-	outb(0x04, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-	udelay(10);
-	outb(0x00, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-	printk(KERN_INFO "PDC202XX: %s channel reset.\n",
-	       drive->channel->unit ? "Secondary" : "Primary");
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+
+	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+	mdelay(100);
+	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+	mdelay(2000);		/* 2 seconds ?! */
 }
 
-/*
- * software host reset
- *
- * BIOS will set UDMA timing on if the drive supports it.
- * The user may then want to turn it off. A bug is
- * that device cannot handle a downgrade in timing from
- * UDMA to DMA. Disk accesses after issuing a set
- * feature command will result in errors.
- *
- * A software reset leaves the timing registers intact,
- * but resets the drives on both channels.
- */
-#if 0
-static void pdc202xx_reset_host(struct pci_dev *dev)
+void pdc202xx_reset_host (ide_hwif_t *hwif)
 {
-	u32 high_16 = pci_resource_start(dev, 4);
-	u8 burst = IN_BYTE(high_16 + PDC_UDMA);
-
-	set_reg_and_wait(burst | 0x10, high_16 + PDC_UDMA, 100);
-	/* FIXME: 2 seconds ?! */
-	set_reg_and_wait(burst & ~0x10, high_16 + PDC_UDMA, 2000);
-	printk(KERN_INFO "%s: device reseted.\n", dev->name);
+	pdc202xx_reset_pci(hwif->pci_dev);
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
 }
 
-void pdc202xx_reset(struct ata_device *drive)
+void pdc202xx_reset (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	printk(KERN_INFO "%s: channel needs reset.\n", ch->name);
-	pdc202xx_reset_host(ch->pci_dev);
+	pdc202xx_reset_host(HWIF(drive));
 }
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+	byte sc1f		= IN_BYTE(high_16 + 0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		OUT_BYTE(sc1f | 0x08, high_16 + 0x001f);
+	} else {
+		OUT_BYTE(sc1f & ~0x08, high_16 + 0x001f);
+	}
 #endif
+	return 0;
+}
 
-static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
 {
-	u32 high_16 = pci_resource_start(dev, 4);
-	u32 burstreg = high_16 + PDC_UDMA;
-	u8 burst = IN_BYTE(burstreg);
-
-	set_reg_and_wait(burst | 0x10, burstreg, 100);
-	/* FIXME: 2 seconds ?! */
-	set_reg_and_wait(burst & ~0x10, burstreg, 2000);
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
+	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
+	byte newchip		= 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-				       dev->resource[PCI_ROM_RESOURCE].
-				       start | PCI_ROM_ADDRESS_ENABLE);
-		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", dev->name,
-		       dev->resource[PCI_ROM_RESOURCE].start);
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
-#if 0
+
 	switch (dev->device) {
-	case PCI_DEVICE_ID_PROMISE_20267:
-	case PCI_DEVICE_ID_PROMISE_20265:
-	case PCI_DEVICE_ID_PROMISE_20262:
-		pdc202xx_reset_host(dev);
-		break;
-	default:
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-			u8 irq = 0, irq2 = 0;
-			pci_read_config_byte(dev, PCI_INTERRUPT_LINE,
-					     &irq);
-			pci_read_config_byte(dev, (PCI_INTERRUPT_LINE) | 0x80, &irq2);	/* 0xbc */
-			if (irq != irq2) {
-				pci_write_config_byte(dev, (PCI_INTERRUPT_LINE) | 0x80, irq);	/* 0xbc */
-				printk
-				    ("%s: pci-config space interrupt mirror fixed.\n",
-				     dev->name);
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			pdc202xx_reset_pci(dev);
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			/*
+			 * software reset -  this is required because the bios
+			 * will set UDMA timing on if the hdd supports it. The
+			 * user may want to turn udma off. A bug in the pdc20262
+			 * is that it cannot handle a downgrade in timing from
+			 * UDMA to DMA. Disk accesses after issuing a set
+			 * feature command will result in errors. A software
+			 * reset leaves the timing registers intact,
+			 * but resets the drives.
+			 */
+			pdc202xx_reset_pci(dev);
+		default:
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				byte irq = 0, irq2 = 0;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
+				if (irq != irq2) {
+					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
+					printk("%s: pci-config space interrupt mirror fixed.\n", name);
+				}
 			}
-		}
-		break;
+			break;
 	}
-#endif
+
+	if (newchip)
+		goto fttk_tx_series;
+
+	printk("%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n",
+		name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
 
 #ifdef CONFIG_PDC202XX_BURST
-	if (!(burst & 1)) {
-		printk(KERN_INFO "%s: forcing (U)DMA BURST.\n", dev->name);
-		OUT_BYTE(burst | 1, burstreg);
-		burst = IN_BYTE(burstreg);
+	if (!(udma_speed_flag & 1)) {
+		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
+		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
+		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
-#endif
-	printk(KERN_INFO "%s: (U)DMA BURST %sabled, "
-	       "primary %s mode, secondary %s mode.\n",
-	       dev->name, (burst & 1) ? "en" : "dis",
-	       (IN_BYTE(high_16 + PDC_PRIMARY) & 1) ? "MASTER" : "PCI",
-	       (IN_BYTE(high_16 + PDC_SECONDARY) & 1) ? "MASTER" : "PCI");
+#endif /* CONFIG_PDC202XX_BURST */
 
-	return dev->irq;
-}
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
+			name, primary_mode, (primary_mode|1));
+		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+	}
 
-#if 0
-/* chipsets newer then 20267 */
-static unsigned int __init pdc202xx_tx_init_chipset(struct pci_dev *dev)
-{
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-				       dev->resource[PCI_ROM_RESOURCE].
-				       start | PCI_ROM_ADDRESS_ENABLE);
-		printk(KERN_INFO "%s: ROM enabled at 0x%08lx.\n",
-		       dev->name, dev->resource[PCI_ROM_RESOURCE].start);
+	if (!(secondary_mode & 1)) {
+		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
+			name, secondary_mode, (secondary_mode|1));
+		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+fttk_tx_series:
+
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		pdc202xx_display_info = &pdc202xx_get_info;
 	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
 	return dev->irq;
 }
-#endif
 
-static unsigned int __init pdc202xx_ata66_check(struct ata_channel *ch)
+unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
 {
-	u16 CIS;
+	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+	unsigned short CIS;
 
-	pci_read_config_word(ch->pci_dev, 0x50, &CIS);
-	return !(CIS & (1 << (10 + ch->unit)));
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
+		case PCI_DEVICE_ID_PROMISE_20267:
+			hwif->addressing = (hwif->channel) ? 0 : 1;
+		default:
+			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+			return (!(CIS & mask));
+	}
 }
 
-/* chipsets newer then 20267 */
-static unsigned int __init pdc202xx_tx_ata66_check(struct ata_channel *ch)
+void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
-	OUT_BYTE(0x0b, ch->dma_base + 1);
-	return !(IN_BYTE(ch->dma_base + 3) & 0x04);
-}
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
 
-static void __init ide_init_pdc202xx(struct ata_channel *hwif)
-{
-	hwif->tuneproc = &pdc202xx_tune_drive;
-	hwif->quirkproc = &check_in_drive_lists;
-	hwif->resetproc = &pdc202xx_reset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+	hwif->autodma = 0;
+
+#undef CONFIG_PDC202XX_32_UNMASK
+#ifdef CONFIG_PDC202XX_32_UNMASK
+	hwif->drives[0].io_32bit = 1;
+	hwif->drives[1].io_32bit = 1;
+	hwif->drives[0].unmask = 1;
+	hwif->drives[1].unmask = 1;
+#endif /* CONFIG_PDC202XX_32_UNMASK */
+
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			hwif->speedproc = &pdc202xx_new_tune_chipset;
+			hwif->resetproc = &pdc202xx_new_reset;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hwif->busproc   = &pdc202xx_tristate;
+			hwif->resetproc	= &pdc202xx_reset;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			hwif->speedproc = &pdc202xx_tune_chipset;
+		default:
+			break;
+	}
 
-	switch (hwif->pci_dev->device) {
-	case PCI_DEVICE_ID_PROMISE_20276:
-	case PCI_DEVICE_ID_PROMISE_20275:
-	case PCI_DEVICE_ID_PROMISE_20271:
-	case PCI_DEVICE_ID_PROMISE_20269:
-	case PCI_DEVICE_ID_PROMISE_20268:
-	case PCI_DEVICE_ID_PROMISE_20268R:
-		hwif->udma_four = pdc202xx_tx_ata66_check(hwif);
+	if (!hwif->dma_base)
+		return;
 
-		hwif->speedproc = &pdc202xx_new_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (hwif->dma_base)
-			hwif->udma_setup = pdc202xx_tx_udma_setup;
-#endif
-		break;
-	case PCI_DEVICE_ID_PROMISE_20267:
-	case PCI_DEVICE_ID_PROMISE_20265:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		/* we need special functions for lba48 */
-		if (hwif->dma_base) {
-			hwif->udma_start = pdc202xx_udma_start;
-			hwif->udma_stop = pdc202xx_udma_stop;
-		}
-#endif
-		/* PDC20262 doesn't support LBA48 */
-	case PCI_DEVICE_ID_PROMISE_20262:
-		hwif->udma_four = pdc202xx_ata66_check(hwif);
+	hwif->dmaproc = &pdc202xx_dmaproc;
+# ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+# endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
 
-	case PCI_DEVICE_ID_PROMISE_20246:
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (hwif->dma_base)
-			hwif->udma_setup = pdc202xx_udma_setup;
-#endif
-		hwif->speedproc = &pdc202xx_tune_chipset;
-	default:
-		break;
-	}
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->modes_map = pdc202xx_modes_map(hwif);
-		hwif->udma_irq_lost = pdc202xx_bug;
-		hwif->udma_timeout = pdc202xx_bug;
-		hwif->highmem = 1;
-	} else
-#endif
-	{
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
+void __init fixup_device_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+				"attached to I2O RAID controller.\n");
+		return;
 	}
-}
 
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+}
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20246,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-#ifndef CONFIG_PDC202XX_FORCE
-	 .enablebits = {{0x50, 0x02, 0x02}, {0x50, 0x04, 0x04}},
-#endif
-	 .bootable = OFF_BOARD,
-	 .extra = 16,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20262,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-#ifndef CONFIG_PDC202XX_FORCE
-	 .enablebits = {{0x50, 0x02, 0x02}, {0x50, 0x04, 0x04}},
-#endif
-	 .bootable = OFF_BOARD,
-	 .extra = 48,
-	 .flags = ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20265,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-#ifndef CONFIG_PDC202XX_FORCE
-	 .enablebits = {{0x50, 0x02, 0x02}, {0x50, 0x04, 0x04}},
-	 .bootable = OFF_BOARD,
-#else
-	 .bootable = ON_BOARD,
-#endif
-	 .extra = 48,
-	 .flags = ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20267,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-#ifndef CONFIG_PDC202XX_FORCE
-	 .enablebits = {{0x50, 0x02, 0x02}, {0x50, 0x04, 0x04}},
-#endif
-	 .bootable = OFF_BOARD,
-	 .extra = 48,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20268,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	/* Promise used a different PCI identification for the raid card
-	 * apparently to try and prevent Linux detecting it and using our own
-	 * raid code. We want to detect it for the ataraid drivers, so we have
-	 * to list both here.. */
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20268R,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20269,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20271,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20275,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-	{
-	 .vendor = PCI_VENDOR_ID_PROMISE,
-	 .device = PCI_DEVICE_ID_PROMISE_20276,
-	 .init_chipset = pdc202xx_init_chipset,
-	 .init_channel = ide_init_pdc202xx,
-	 .bootable = OFF_BOARD,
-	 .flags = ATA_F_IRQ | ATA_F_DMA},
-};
-
-int __init init_pdc202xx(void)
+void __init fixup_device_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	unsigned int i;
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				byte irq = 0, irq2 = 0;
+				dev2 = findev;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					dev2->irq = dev->irq;
+					pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+				}
+			}
+		}
+	}
 
-	return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
 }
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/pdc4030.c	Tue Aug 27 12:28:08 2002
@@ -1,11 +1,14 @@
 /*  -*- linux-c -*-
+ *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
  *
- *  Copyright (C) 1995-2002  Linus Torvalds & authors (see below)
- *
+ *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
+ */
+
+/*
  *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
  *
  *  This file provides support for the second port and cache of Promise
- *  VLB based IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
  *
  *  Thanks are due to Mark Lord for advice and patiently answering stupid
  *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
@@ -34,21 +37,18 @@
  *			Autodetection code added.
  *
  *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
- *  Version 0.91	Bring in line with new bio code in 2.5.1
- *  Version 0.92	Update for IDE driver taskfile changes
- *  Version 0.93	Sync with 2.5.10, minor taskfile changes
  */
 
 /*
  * Once you've compiled it in, you'll have to also enable the interface
- * setup routine from the kernel command line, as in
+ * setup routine from the kernel command line, as in 
  *
  *	'linux ide0=dc4030' or 'linux ide1=dc4030'
  *
  * It should now work as a second controller also ('ide1=dc4030') but only
  * if you DON'T have BIOS V4.44, which has a bug. If you have this version
  * and EPROM programming facilities, you need to fix 4 bytes:
- *	2496:	81	81
+ * 	2496:	81	81
  *	2497:	3E	3E
  *	2498:	22	98	*
  *	2499:	06	05	*
@@ -64,16 +64,14 @@
  *
  * As of January 1999, Promise Technology Inc. have finally supplied me with
  * some technical information which has shed a glimmer of light on some of the
- * problems I was having, especially with writes.
+ * problems I was having, especially with writes. 
  *
- * There are still potential problems with the robustness and efficiency of
- * this driver because I still don't understand what the card is doing with
- * interrupts, however, it has been stable for a while with no reports of ill
- * effects.
+ * There are still problems with the robustness and efficiency of this driver
+ * because I still don't understand what the card is doing with interrupts.
  */
 
-#undef DEBUG_READ
-#undef DEBUG_WRITE
+#define DEBUG_READ
+#define DEBUG_WRITE
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -92,82 +90,15 @@
 #include "pdc4030.h"
 
 /*
- * Data transfer functions for polled IO.
- */
-
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static void read_vlb(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	inb(IDE_NSECTOR_REG);
-	inb(IDE_NSECTOR_REG);
-	inb(IDE_NSECTOR_REG);
-	insl(IDE_DATA_REG, buffer, wcount);
-	local_irq_restore(flags);
-}
-
-static void write_vlb(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	inb(IDE_NSECTOR_REG);
-	inb(IDE_NSECTOR_REG);
-	inb(IDE_NSECTOR_REG);
-	outsl(IDE_DATA_REG, buffer, wcount);
-	local_irq_restore(flags);
-}
-
-static void read_16(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	insw(IDE_DATA_REG, buffer, wcount<<1);
-}
-
-static void write_16(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	outsw(IDE_DATA_REG, buffer, wcount<<1);
-}
-
-/*
- * This is used for most PIO data transfers *from* the device.
- */
-static void promise_read(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	if (drive->channel->io_32bit)
-		read_vlb(drive, buffer, wcount);
-	else
-		read_16(drive, buffer, wcount);
-}
-
-/*
- * This is used for most PIO data transfers *to* the device interface.
- */
-static void promise_write(struct ata_device *drive, void *buffer, unsigned int wcount)
-{
-	if (drive->channel->io_32bit)
-		write_vlb(drive, buffer, wcount);
-	else
-		write_16(drive, buffer, wcount);
-}
-
-/*
  * promise_selectproc() is invoked by ide.c
  * in preparation for access to the specified drive.
  */
-static void promise_selectproc(struct ata_device *drive)
+static void promise_selectproc (ide_drive_t *drive)
 {
-	u8 number;
+	unsigned int number;
 
-	number = (drive->channel->unit << 1) + drive->select.b.unit;
-	outb(number, IDE_FEATURE_REG);
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	OUT_BYTE(number,IDE_FEATURE_REG);
 }
 
 /*
@@ -175,15 +106,15 @@
  * by command F0. They all have the same success/failure notification -
  * 'P' (=0x50) on success, 'p' (=0x70) on failure.
  */
-int pdc4030_cmd(struct ata_device *drive, u8 cmd)
+int pdc4030_cmd(ide_drive_t *drive, byte cmd)
 {
 	unsigned long timeout, timer;
-	u8 status_val;
+	byte status_val;
 
 	promise_selectproc(drive);	/* redundant? */
-	outb(0xF3, IDE_SECTOR_REG);
-	outb(cmd, IDE_SELECT_REG);
-	outb(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	OUT_BYTE(0xF3,IDE_SECTOR_REG);
+	OUT_BYTE(cmd,IDE_SELECT_REG);
+	OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
 	timeout = HZ * 10;
 	timeout += jiffies;
 	do {
@@ -194,7 +125,7 @@
 		/* Delays at least 10ms to give interface a chance */
 		timer = jiffies + (HZ + 99)/100 + 1;
 		while (time_after(timer, jiffies));
-		status_val = inb(IDE_SECTOR_REG);
+		status_val = IN_BYTE(IDE_SECTOR_REG);
 	} while (status_val != 0x50 && status_val != 0x70);
 
 	if(status_val == 0x50)
@@ -206,7 +137,7 @@
 /*
  * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
  */
-int pdc4030_identify(struct ata_device *drive)
+int pdc4030_identify(ide_drive_t *drive)
 {
 	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
 }
@@ -222,43 +153,36 @@
  * setup_pdc4030()
  * Completes the setup of a Promise DC4030 controller card, once found.
  */
-int __init setup_pdc4030(struct ata_channel *hwif)
+int __init setup_pdc4030 (ide_hwif_t *hwif)
 {
-        struct ata_device *drive;
-	struct ata_channel *hwif2;
+        ide_drive_t *drive;
+	ide_hwif_t *hwif2;
 	struct dc_ident ident;
 	int i;
-	ide_startstop_t ret;
-
-	if (!hwif)
-		return 0;
+	ide_startstop_t startstop;
+	
+	if (!hwif) return 0;
 
 	drive = &hwif->drives[0];
 	hwif2 = &ide_hwifs[hwif->index+1];
 	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
 		return 1;
 
-	if (inb(IDE_NSECTOR_REG) == 0xFF || inb(IDE_SECTOR_REG) == 0xFF) {
+	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF ||
+	    IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
 		return 0;
 	}
-	ata_irq_enable(drive, 1);
-	if (pdc4030_cmd(drive, PROMISE_GET_CONFIG)) {
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(0x08,IDE_CONTROL_REG);
+	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
 		return 0;
 	}
-
-	/* FIXME: Make this go away. */
-	spin_lock_irq(hwif->lock);
-	ret = ata_status_poll(drive, DATA_READY, BAD_W_STAT, WAIT_DRQ, NULL);
-	if (ret != ATA_OP_READY) {
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
 		printk(KERN_INFO
 			"%s: Failed Promise read config!\n",hwif->name);
-		spin_unlock_irq(hwif->lock);
-
 		return 0;
 	}
-	spin_unlock_irq(hwif->lock);
-
-	promise_read(drive, &ident, SECTOR_WORDS);
+	ata_input_data(drive, &ident, SECTOR_WORDS);
 	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
 		return 0;
 	}
@@ -299,20 +223,19 @@
 	 */
 
 	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->unit	= ATA_PRIMARY;
-	hwif2->unit	= ATA_SECONDARY;
-	hwif->ata_read  = hwif2->ata_read = promise_read;
-	hwif->ata_write = hwif2->ata_write = promise_write;
-	hwif->selectproc = hwif2->selectproc = promise_selectproc;
+	hwif->mate	= hwif2;
+	hwif2->mate	= hwif;
+	hwif2->channel	= 1;
+	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
 	hwif->serialized = hwif2->serialized = 1;
 
-/* Shift the remaining interfaces up by one */
+/* Shift the remaining interfaces down by one */
 	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		struct ata_channel *h = &ide_hwifs[i];
+		ide_hwif_t *h = &ide_hwifs[i];
 
 #ifdef DEBUG
-		printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
-#endif
+		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif /* DEBUG */
 		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
 		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
 		h->noprobe = (h-1)->noprobe;
@@ -321,8 +244,11 @@
 	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
 	hwif2->irq = hwif->irq;
 	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
-	hwif->io_32bit = hwif2->io_32bit = 1;
 	for (i=0; i<2 ; i++) {
+		hwif->drives[i].io_32bit = 3;
+		hwif2->drives[i].io_32bit = 3;
+		hwif->drives[i].keep_settings = 1;
+		hwif2->drives[i].keep_settings = 1;
 		if (!ident.current_tm[i].cyl)
 			hwif->drives[i].noprobe = 1;
 		if (!ident.current_tm[i+2].cyl)
@@ -336,22 +262,22 @@
  * Tests for the presence of a DC4030 Promise card on this interface
  * Returns: 1 if found, 0 if not found
  */
-int __init detect_pdc4030(struct ata_channel *hwif)
+int __init detect_pdc4030(ide_hwif_t *hwif)
 {
-	struct ata_device *drive = &hwif->drives[0];
+	ide_drive_t *drive = &hwif->drives[0];
 
 	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
 		return 0;
 	}
-	outb(0xF3, IDE_SECTOR_REG);
-	outb(0x14, IDE_SELECT_REG);
-	outb(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
-
-	mdelay(50);
-
-	if (inb(IDE_ERROR_REG) == 'P' &&
-	    inb(IDE_NSECTOR_REG) == 'T' &&
-	    inb(IDE_SECTOR_REG) == 'I') {
+	OUT_BYTE(0xF3, IDE_SECTOR_REG);
+	OUT_BYTE(0x14, IDE_SELECT_REG);
+	OUT_BYTE(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	
+	ide_delay_50ms();
+
+	if (IN_BYTE(IDE_ERROR_REG) == 'P' &&
+	    IN_BYTE(IDE_NSECTOR_REG) == 'T' &&
+	    IN_BYTE(IDE_SECTOR_REG) == 'I') {
 		return 1;
 	} else {
 		return 0;
@@ -361,7 +287,7 @@
 void __init ide_probe_for_pdc4030(void)
 {
 	unsigned int	index;
-	struct ata_channel *hwif;
+	ide_hwif_t	*hwif;
 
 	if (enable_promise_support == 0)
 		return;
@@ -376,75 +302,99 @@
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
-static ide_startstop_t promise_read_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
 {
+	byte stat;
 	int total_remaining;
 	unsigned int sectors_left, sectors_avail, nsect;
+	struct request *rq;
+#ifdef CONFIG_IDE_TASKFILE_IO
 	unsigned long flags;
 	char *to;
+#endif /* CONFIG_IDE_TASKFILE_IO */
 
-	if (!ata_status(drive, DATA_READY, BAD_R_STAT))
-		return ata_error(drive, rq, __FUNCTION__);
+	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT))
+		return DRIVER(drive)->error(drive, "promise_read_intr", stat);
 
 read_again:
 	do {
-		sectors_left = inb(IDE_NSECTOR_REG);
-		inb(IDE_SECTOR_REG);
-	} while (inb(IDE_NSECTOR_REG) != sectors_left);
+		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
+		IN_BYTE(IDE_SECTOR_REG);
+	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
+	rq = HWGROUP(drive)->rq;
 	sectors_avail = rq->nr_sectors - sectors_left;
 	if (!sectors_avail)
 		goto read_again;
 
 read_next:
+	rq = HWGROUP(drive)->rq;
 	nsect = rq->current_nr_sectors;
 	if (nsect > sectors_avail)
 		nsect = sectors_avail;
 	sectors_avail -= nsect;
-	to = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
-	promise_read(drive, to, nsect * SECTOR_WORDS);
+#ifdef CONFIG_IDE_TASKFILE_IO
+	to = ide_map_buffer(rq, &flags);
+	ata_input_data(drive, to, nsect * SECTOR_WORDS);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
 	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect);
-#endif
-	bio_kunmap_irq(to, &flags);
+	       rq->sector+nsect-1,
+#ifdef CONFIG_IDE_TASKFILE_IO
+		(unsigned long) to,
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		(unsigned long) rq->buffer,
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	       rq->nr_sectors-nsect);
+#endif /* DEBUG_READ */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	ide_unmap_buffer(to, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	rq->buffer += nsect<<9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
 	rq->sector += nsect;
 	rq->errors = 0;
 	rq->nr_sectors -= nsect;
 	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0)
-		ata_end_request(drive, rq, 1, 0);
-
-	/*
-	 * Now the data has been read in, do the following:
-	 *
-	 * if there are still sectors left in the request, if we know there are
-	 * still sectors available from the interface, go back and read the
-	 * next bit of the request.  else if DRQ is asserted, there are more
-	 * sectors available, so go back and find out how many, then read them
-	 * in.  else if BUSY is asserted, we are going to get an interrupt, so
-	 * set the handler for the interrupt and just return
-	 */
-
+	if ((rq->current_nr_sectors -= nsect) <= 0) {
+		DRIVER(drive)->end_request(drive, 1);
+	}
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
 	if (total_remaining > 0) {
 		if (sectors_avail)
 			goto read_next;
-		ata_status(drive, 0, 0);
-		if (drive->status & DRQ_STAT)
+		stat = GET_STAT();
+		if (stat & DRQ_STAT)
 			goto read_again;
-		if (drive->status & BUSY_STAT) {
-			ata_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
+		if (stat & BUSY_STAT) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
 #ifdef DEBUG_READ
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
-#endif
-			return ATA_OP_CONTINUES;
+#endif /* DEBUG_READ */
+			return ide_started;
 		}
 		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
 		       "!DRQ !BUSY\n", drive->name);
-		return ata_error(drive, rq, "promise read intr");
+		return DRIVER(drive)->error(drive, "promise read intr", stat);
 	}
-	return ATA_OP_FINISHED;
+	return ide_stopped;
 }
 
 /*
@@ -455,29 +405,34 @@
  *
  * Once not busy, the end request is called.
  */
-static ide_startstop_t promise_complete_pollfunc(struct ata_device *drive, struct request *rq)
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-
-	if (!ata_status(drive, 0, BUSY_STAT)) {
-		if (time_before(jiffies, ch->poll_timeout)) {
-			ata_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	int i;
 
-			return ATA_OP_CONTINUES; /* continue polling... */
+	if (GET_STAT() & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+			return ide_started; /* continue polling... */
 		}
-		ch->poll_timeout = 0;
+		hwgroup->poll_timeout = 0;
 		printk(KERN_ERR "%s: completion timeout - still busy!\n",
 		       drive->name);
-		return ata_error(drive, rq, "busy timeout");
+		return DRIVER(drive)->error(drive, "busy timeout", GET_STAT());
 	}
 
-	ch->poll_timeout = 0;
+	hwgroup->poll_timeout = 0;
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
-#endif
-	ata_end_request(drive, rq, 1, rq->nr_sectors);
-
-	return ATA_OP_FINISHED;
+#endif /* DEBUG_WRITE */
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		DRIVER(drive)->end_request(drive, 1);
+	}
+	return ide_stopped;
 }
 
 /*
@@ -491,32 +446,52 @@
  * full "mcount" number of sectors, so we must make sure we update the
  * state _before_ we output the final part of the data!
  */
-int promise_multwrite(struct ata_device *drive, struct request *rq, unsigned int mcount)
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	struct request *rq	= &hwgroup->wrq;
+
 	do {
 		char *buffer;
 		int nsect = rq->current_nr_sectors;
+#ifdef CONFIG_IDE_TASKFILE_IO
 		unsigned long flags;
+#endif /* CONFIG_IDE_TASKFILE_IO */
 
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		buffer = rq->buffer;
 
-		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
 		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
 
 		/* Do we move to the next bh after this? */
 		if (!rq->current_nr_sectors) {
-			struct bio *bio = rq->bio->bi_next;
+			struct bio *bio = rq->bio;
+
+			/*
+			 * only move to next bio, when we have processed
+			 * all bvecs in this one.
+			 */
+			if (++bio->bi_idx >= bio->bi_vcnt) {
+				bio->bi_idx = 0;
+				bio = bio->bi_next;
+			}
 
 			/* end early early we ran out of requests */
 			if (!bio) {
 				mcount = 0;
 			} else {
 				rq->bio = bio;
-				rq->current_nr_sectors = bio_sectors(bio);
+				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
 				rq->hard_cur_sectors = rq->current_nr_sectors;
 			}
 		}
@@ -525,8 +500,10 @@
 		 * Ok, we're all setup for the interrupt
 		 * re-entering us on the last transfer.
 		 */
-		promise_write(drive, buffer, nsect << 7);
-		bio_kunmap_irq(buffer, &flags);
+		taskfile_output_data(drive, buffer, nsect<<7);
+#ifdef CONFIG_IDE_TASKFILE_IO
+		ide_unmap_buffer(buffer, &flags);
+#endif /* CONFIG_IDE_TASKFILE_IO */
 	} while (mcount);
 
 	return 0;
@@ -535,203 +512,205 @@
 /*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
-static ide_startstop_t promise_write_pollfunc(struct ata_device *drive, struct request *rq)
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-
-	if (inb(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, ch->poll_timeout)) {
-			ata_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-			return ATA_OP_CONTINUES; /* continue polling... */
+	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+			return ide_started; /* continue polling... */
 		}
-		ch->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed out!\n", drive->name);
-		ata_status(drive, 0, 0);
-
-		return ata_error(drive, rq, "write timeout");
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+		return DRIVER(drive)->error(drive, "write timeout", GET_STAT());
 	}
 
 	/*
 	 * Now write out last 4 sectors and poll for not BUSY
 	 */
-	promise_multwrite(drive, rq, 4);
-	ch->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ata_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
+	promise_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
-		drive->name, drive->status);
-#endif
-
-	return ATA_OP_CONTINUES;
+		drive->name, GET_STAT());
+#endif /* DEBUG_WRITE */
+	return ide_started;
 }
 
 /*
- * This transfers a block of one or more sectors of data to a drive as part of
- * a disk write operation. All but 4 sectors are transferred in the first
- * attempt, then the interface is polled (nicely!) for completion before the
- * final 4 sectors are transferred. There is no interrupt generated on writes
- * (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
+ * promise_write() transfers a block of one or more sectors of data to a
+ * drive as part of a disk write operation. All but 4 sectors are transferred
+ * in the first attempt, then the interface is polled (nicely!) for completion
+ * before the final 4 sectors are transferred. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
  */
-static ide_startstop_t promise_do_write(struct ata_device *drive, struct request *rq)
+static ide_startstop_t promise_write (ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
 
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
 	       "buffer=%p\n", drive->name, rq->sector,
 	       rq->sector + rq->nr_sectors - 1, rq->buffer);
-#endif
+#endif /* DEBUG_WRITE */
+
 	/*
 	 * If there are more than 4 sectors to transfer, do n-4 then go into
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
-		if (promise_multwrite(drive, rq, rq->nr_sectors - 4)) {
-
-			return ATA_OP_FINISHED;
-		}
-		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ata_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
-
-		return ATA_OP_CONTINUES;
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
 	} else {
 	/*
 	 * There are 4 or fewer sectors to transfer, do them all in one go
 	 * and wait for NOT BUSY.
 	 */
-		if (promise_multwrite(drive, rq, rq->nr_sectors))
-			return ATA_OP_FINISHED;
-
-		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ata_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
-
+		if (promise_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
-			"status = %02x\n", drive->name, drive->status);
-#endif
-		return ATA_OP_CONTINUES;
+			"status = %02x\n", drive->name, GET_STAT());
+#endif /* DEBUG_WRITE */
+		return ide_started;
 	}
 }
 
 /*
- * do_pdc4030_io() is called from promise_do_request, having had the block
- * number already set up. It issues a READ or WRITE command to the Promise
+ * do_pdc4030_io() is called from do_rw_disk, having had the block number
+ * already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *args, struct request *rq)
+#ifndef CONFIG_IDE_TASKFILE_IO
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+{
+#else /* CONFIG_IDE_TASKFILE_IO */
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
 {
-	struct hd_drive_task_hdr *taskfile = &(args->taskfile);
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	ide_startstop_t startstop;
 	unsigned long timeout;
+	byte stat;
 
-	/* Check that it's a regular command. If not, bomb out early. */
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "pdc4030 bad flags");
-		ata_end_request(drive, rq, 0, 0);
-
-		return ATA_OP_FINISHED;
-	}
-
-	ata_irq_enable(drive, 1);
-	ata_mask(drive);
-
-	ata_out_regfile(drive, taskfile);
-
-	outb(taskfile->device_head, IDE_SELECT_REG);
-	outb(args->cmd, IDE_COMMAND_REG);
-
-	switch (rq_data_dir(rq)) {
-	case READ:
-
-		/*
-		 * The card's behaviour is odd at this point. If the data is
-		 * available, DRQ will be true, and no interrupt will be
-		 * generated by the card. If this is the case, we need to call
-		 * the "interrupt" handler (promise_read_intr) directly.
-		 * Otherwise, if an interrupt is going to occur, bit0 of the
-		 * SELECT register will be high, so we can set the handler the
-		 * just return and be interrupted.  If neither of these is the
-		 * case, we wait for up to 50ms (badly I'm afraid!) until one
-		 * of them is.
-		 */
+	BUG_ON(!(rq->flags & REQ_CMD));
 
+#ifdef CONFIG_IDE_TASKFILE_IO
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
+	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	if (rq_data_dir(rq) == READ) {
+#ifndef CONFIG_IDE_TASKFILE_IO
+		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
 		timeout = jiffies + HZ/20; /* 50ms wait */
 		do {
-			if (!ata_status(drive, 0, DRQ_STAT)) {
+			stat=GET_STAT();
+			if (stat & DRQ_STAT) {
 				udelay(1);
-				return promise_read_intr(drive, rq);
+				return promise_read_intr(drive);
 			}
-			if (inb(IDE_SELECT_REG) & 0x01) {
+			if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
 #ifdef DEBUG_READ
 				printk(KERN_DEBUG "%s: read: waiting for "
-				                  "interrupt\n", drive->name);
-#endif
-				ata_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
-
-				return ATA_OP_CONTINUES;
+						"interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
+				return ide_started;
 			}
 			udelay(1);
 		} while (time_before(jiffies, timeout));
 
-		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
-			drive->name);
-		return ATA_OP_FINISHED;
-
-	case WRITE: {
-		ide_startstop_t ret;
-
-		/*
-		 * Strategy on write is: look for the DRQ that should have been
-		 * immediately asserted copy the request into the hwgroup's
-		 * scratchpad call the promise_write function to deal with
-		 * writing the data out.
-		 *
-		 * NOTE: No interrupts are generated on writes. Write
-		 * completion must be polled
-		 */
-
-		ret = ata_status_poll(drive, DATA_READY, drive->bad_wstat,
-					WAIT_DRQ, rq);
-		if (ret != ATA_OP_READY) {
+		printk(KERN_ERR "%s: reading: No DRQ and not "
+				"waiting - Odd!\n", drive->name);
+		return ide_stopped;
+	} else if (rq_data_dir(rq) == WRITE) {
+#ifndef CONFIG_IDE_TASKFILE_IO
+		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing "
-			       "PROMISE_WRITE\n", drive->name);
-
-			return ret;
-		}
-		if (!drive->channel->unmask)
+				"PROMISE_WRITE\n", drive->name);
+			return startstop;
+	    	}
+		if (!drive->unmask)
 			local_irq_disable();
-
-		return promise_do_write(drive, rq);
-	}
-
-	default:
-		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
-
-		ata_end_request(drive, rq, 0, 0);
-		return ATA_OP_FINISHED;
+		HWGROUP(drive)->wrq = *rq; /* scratchpad */
+		return promise_write(drive);
+	} else {
+		blk_dump_rq_flags(rq, "do_pdc4030_io - bad command\n");
+		DRIVER(drive)->end_request(drive, 0);
+		return ide_stopped;
 	}
 }
 
-ide_startstop_t promise_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+#ifdef CONFIG_IDE_TASKFILE_IO
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	struct ata_taskfile args;
+	struct hd_drive_task_hdr	taskfile;
+	ide_task_t			args;
 
-	memset(&args, 0, sizeof(args));
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
 
-	/* The four drives on the two logical (one physical) interfaces
-	   are distinguished by writing the drive number (0-3) to the
-	   Feature register.
-	   FIXME: Is promise_selectproc now redundant??
-	*/
-	args.taskfile.feature		= (drive->channel->unit << 1) + drive->select.b.unit;
-	args.taskfile.sector_count	= rq->nr_sectors;
-	args.taskfile.sector_number	= block;
-	args.taskfile.low_cylinder	= (block>>=8);
-	args.taskfile.high_cylinder	= (block>>=8);
-	args.taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
-	args.cmd = (rq_data_dir(rq) == READ) ? PROMISE_READ : PROMISE_WRITE;
-	args.XXX_handler	= NULL;
-	rq->special	= &args;
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
 
-	return do_pdc4030_io(drive, &args, rq);
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= NULL;
+	args.handler		= NULL;
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
 }
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pdcadma.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,106 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.01	June 21, 2001
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+
+	p += sprintf(p, "\n                                PDC ADMA %04X Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte pdcadma_proc = 0;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+
+int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			func = ide_dma_off_quietly;
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		bmide_dev = dev;
+		pdcadma_display_info = &pdcadma_get_info;
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+{
+	return 1;
+}
+
+void __init ide_init_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->dmaproc = &pdcadma_dmaproc;
+//		hwif->autodma = 1;
+//	}
+}
+
+void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+//	ide_setup_dma(hwif, dmabase, 8);
+}
+
diff -Nru a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c
--- a/drivers/ide/pdcraid.c	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,681 +0,0 @@
-/*
-   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   Based on work done by SÃ¸ren Schmidt for FreeBSD  
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int pdcraid_open(struct inode *inode, struct file *filp);
-static int pdcraid_release(struct inode *inode, struct file *filp);
-static int pdcraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg);
-static int pdcraid0_make_request(request_queue_t * q, int rw,
-				 struct buffer_head *bh);
-static int pdcraid1_make_request(request_queue_t * q, int rw,
-				 struct buffer_head *bh);
-
-struct disk_dev {
-	int major;
-	int minor;
-	int device;
-};
-
-static struct disk_dev devlist[] = {
-	{IDE0_MAJOR, 0, -1},
-	{IDE0_MAJOR, 64, -1},
-	{IDE1_MAJOR, 0, -1},
-	{IDE1_MAJOR, 64, -1},
-	{IDE2_MAJOR, 0, -1},
-	{IDE2_MAJOR, 64, -1},
-	{IDE3_MAJOR, 0, -1},
-	{IDE3_MAJOR, 64, -1},
-	{IDE4_MAJOR, 0, -1},
-	{IDE4_MAJOR, 64, -1},
-	{IDE5_MAJOR, 0, -1},
-	{IDE5_MAJOR, 64, -1},
-	{IDE6_MAJOR, 0, -1},
-	{IDE6_MAJOR, 64, -1},
-};
-
-
-struct pdcdisk {
-	kdev_t device;
-	unsigned long sectors;
-	struct block_device *bdev;
-	unsigned long last_pos;
-};
-
-struct pdcraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-
-	struct pdcdisk disk[8];
-
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations pdcraid0_ops = {
-	.open = pdcraid_open,
-	.release = pdcraid_release,
-	.ioctl = pdcraid_ioctl,
-	.make_request = pdcraid0_make_request
-};
-
-static struct raid_device_operations pdcraid1_ops = {
-	.open = pdcraid_open,
-	.release = pdcraid_release,
-	.ioctl = pdcraid_ioctl,
-	.make_request = pdcraid1_make_request
-};
-
-static struct pdcraid raid[16];
-
-
-static int pdcraid_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned long sectors;
-
-	if (!inode || kdev_none(inode->i_rdev))
-		return -EINVAL;
-
-	minor = minor(inode->i_rdev) >> SHIFT;
-
-	switch (cmd) {
-
-	case BLKGETSIZE:	/* Return device size */
-		if (!arg)
-			return -EINVAL;
-		sectors =
-		    ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects;
-		if (minor(inode->i_rdev) & 15)
-			return put_user(sectors, (unsigned long *) arg);
-		return put_user(raid[minor].sectors,
-				(unsigned long *) arg);
-		break;
-
-
-	case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc =
-			    (struct hd_geometry *) arg;
-			unsigned short bios_cyl = raid[minor].geom.cylinders;	/* truncate */
-
-			if (!loc)
-				return -EINVAL;
-			if (put_user
-			    (raid[minor].geom.heads,
-			     (u8 *) & loc->heads))
-				return -EFAULT;
-			if (put_user
-			    (raid[minor].geom.sectors,
-			     (u8 *) & loc->sectors))
-				return -EFAULT;
-			if (put_user
-			    (bios_cyl, (unsigned short *) &loc->cylinders))
-				return -EFAULT;
-			if (put_user
-			    ((unsigned) ataraid_gendisk.
-			     part[minor(inode->i_rdev)].start_sect,
-			     (unsigned long *) &loc->start))
-				return -EFAULT;
-			return 0;
-		}
-
-	default:
-		printk("Invalid ioctl \n");
-		return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-unsigned long partition_map_normal(unsigned long block,
-				   unsigned long partition_off,
-				   unsigned long partition_size,
-				   int stride)
-{
-	return block + partition_off;
-}
-
-unsigned long partition_map_linux(unsigned long block,
-				  unsigned long partition_off,
-				  unsigned long partition_size, int stride)
-{
-	unsigned long newblock;
-
-	newblock = stride - (partition_off % stride);
-	if (newblock == stride)
-		newblock = 0;
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-
-	return newblock;
-}
-
-static int funky_remap[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-
-unsigned long partition_map_linux_raid0_4disk(unsigned long block,
-					      unsigned long partition_off,
-					      unsigned long partition_size,
-					      int stride)
-{
-	unsigned long newblock, temp, temp2;
-
-	newblock = stride - (partition_off % stride);
-	if (newblock == stride)
-		newblock = 0;
-
-	if (block < (partition_size / (8 * stride)) * 8 * stride) {
-		temp = block % stride;
-		temp2 = block / stride;
-		temp2 = ((temp2 >> 3) << 3) | (funky_remap[temp2 & 7]);
-		block = temp2 * stride + temp;
-	}
-
-
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-
-	return newblock;
-}
-
-
-
-static int pdcraid0_make_request(request_queue_t * q, int rw,
-				 struct buffer_head *bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left, rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk = 0, real_disk = 0;
-	int i;
-	int device;
-	struct pdcraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-
-	device = (bh->b_rdev >> SHIFT) & MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride == 0)
-		thisraid->stride = 1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-
-	rsect =
-	    partition_map_normal(rsect,
-				 ataraid_gendisk.part[MINOR(bh->b_rdev)].
-				 start_sect,
-				 ataraid_gendisk.part[MINOR(bh->b_rdev)].
-				 nr_sects, thisraid->stride);
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect / thisraid->stride) !=
-	    ((rsect + (bh->b_size / 512) - 1) / thisraid->stride)) {
-		return -1;
-	}
-
-	rsect_left = rsect;
-
-	for (i = 0; i < 8; i++) {
-		if (thisraid->cutoff_disks[i] == 0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum +=
-			    thisraid->cutoff[i] /
-			    thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block =
-			    (block / thisraid->cutoff_disks[i]) *
-			    thisraid->stride;
-			rsect =
-			    rsect_accum + (rsect_left % thisraid->stride) +
-			    block;
-			break;
-		}
-	}
-
-	for (i = 0; i < 8; i++) {
-		if ((disk == 0)
-		    && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk > 0)
-		    && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-
-	}
-	disk = real_disk;
-
-
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-static int pdcraid1_write_request(request_queue_t * q, int rw,
-				  struct buffer_head *bh)
-{
-	struct buffer_head *bh1;
-	struct ataraid_bh_private *private;
-	int device;
-	int i;
-
-	device = (bh->b_rdev >> SHIFT) & MAJOR_MASK;
-	private = ataraid_get_private();
-	if (private == NULL)
-		BUG();
-
-	private->parent = bh;
-
-	atomic_set(&private->count, raid[device].disks);
-
-
-	for (i = 0; i < raid[device].disks; i++) {
-		bh1 = ataraid_get_bhead();
-		/* If this ever fails we're doomed */
-		if (!bh1)
-			BUG();
-
-		/* dupe the bufferhead and update the parts that need to be different */
-		memcpy(bh1, bh, sizeof(*bh));
-
-		bh1->b_end_io = ataraid_end_request;
-		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;	/* partition offset */
-		bh1->b_rdev = raid[device].disk[i].device;
-
-		/* update the last known head position for the drive */
-		raid[device].disk[i].last_pos =
-		    bh1->b_rsector + (bh1->b_size >> 9);
-
-		generic_make_request(rw, bh1);
-	}
-	return 0;
-}
-
-static int pdcraid1_read_request(request_queue_t * q, int rw,
-				 struct buffer_head *bh)
-{
-	int device;
-	int dist;
-	int bestsofar, bestdist, i;
-	static int previous;
-
-	/* Reads are simple in principle. Pick a disk and go. 
-	   Initially I cheat by just picking the one which the last known
-	   head position is closest by.
-	   Later on, online/offline checking and performance needs adding */
-
-	device = (bh->b_rdev >> SHIFT) & MAJOR_MASK;
-	bh->b_rsector +=
-	    ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	bestsofar = 0;
-	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
-	if (bestdist < 0)
-		bestdist = -bestdist;
-	if (bestdist > 4095)
-		bestdist = 4095;
-
-	for (i = 1; i < raid[device].disks; i++) {
-		dist = raid[device].disk[i].last_pos - bh->b_rsector;
-		if (dist < 0)
-			dist = -dist;
-		if (dist > 4095)
-			dist = 4095;
-
-		if (bestdist == dist) {	/* it's a tie; try to do some read balancing */
-			if ((previous > bestsofar) && (previous <= i))
-				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
-		} else if (bestdist > dist) {
-			bestdist = dist;
-			bestsofar = i;
-		}
-
-	}
-
-	bh->b_rdev = raid[device].disk[bestsofar].device;
-	raid[device].disk[bestsofar].last_pos =
-	    bh->b_rsector + (bh->b_size >> 9);
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-
-	return 1;
-}
-
-
-static int pdcraid1_make_request(request_queue_t * q, int rw,
-				 struct buffer_head *bh)
-{
-	/* Read and Write are totally different cases; split them totally here */
-	if (rw == READA)
-		rw = READ;
-
-	if (rw == READ)
-		return pdcraid1_read_request(q, rw, bh);
-	else
-		return pdcraid1_write_request(q, rw, bh);
-}
-
-#include "pdcraid.h"
-
-static unsigned long calc_pdcblock_offset(struct block_device *bdev)
-{
-	unsigned long lba = 0;
-	struct ata_device *ideinfo = get_info_ptr(to_kdev_t(bdev->bd_dev));
-
-	if (ideinfo == NULL)
-		return 0;
-
-	/* first sector of the last cluster */
-	if (ideinfo->head == 0)
-		return 0;
-	if (ideinfo->sect == 0)
-		return 0;
-	lba = (ideinfo->capacity / (ideinfo->head * ideinfo->sect));
-	lba = lba * (ideinfo->head * ideinfo->sect);
-	lba = lba - ideinfo->sect;
-
-	return lba;
-}
-
-
-static int read_disk_sb(struct block_device *bdev,
-			struct promise_raid_conf *p)
-{
-	unsigned long sb_offset;
-	char *buffer;
-	int i;
-
-	/*
-	 * Calculate the position of the superblock,
-	 * it's at first sector of the last cylinder
-	 */
-	sb_offset = calc_pdcblock_offset(bdev);
-
-	if (sb_offset == 0)
-		return -1;
-
-	for (i = 0, buffer = (char *) p; i < 4; i++, buffer += 512) {
-		Sector sect;
-		char *q = read_dev_sector(bdev, sb_offset + i, &sect);
-		if (!p) {
-			printk(KERN_ERR
-			       "pdcraid: Error reading superblock.\n");
-			return -1;
-		}
-		memcpy(buffer, q, 512);
-		put_dev_sector(&sect);
-	}
-	return 0;
-}
-
-static unsigned int calc_sb_csum(unsigned int *ptr)
-{
-	unsigned int sum;
-	int count;
-
-	sum = 0;
-	for (count = 0; count < 511; count++)
-		sum += *ptr++;
-
-	return sum;
-}
-
-static int cookie = 0;
-
-static struct promise_raid_conf __initdata prom;
-static void __init probedisk(int devindex, int device, int raidlevel)
-{
-	int i;
-	int major, minor;
-	struct block_device *bdev;
-
-	if (devlist[devindex].device != -1)	/* already assigned to another array */
-		return;
-
-	major = devlist[devindex].major;
-	minor = devlist[devindex].minor;
-
-	bdev = bdget(mk_kdev(major, minor));
-	if (!bdev)
-		return;
-
-	if (blkdev_get(bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW) != 0)
-		return;
-
-	if (read_disk_sb(bdev, &prom))
-		goto out;
-
-	/* the checksums must match */
-	if (prom.checksum != calc_sb_csum((unsigned int *) &prom))
-		goto out;
-	if (prom.raid.type != raidlevel)	/* different raidlevel */
-		goto out;
-
-	if ((cookie != 0) && (cookie != prom.raid.magic_1))	/* different array */
-		goto out;
-
-	cookie = prom.raid.magic_1;
-
-	/* This looks evil. But basically, we have to search for our adapternumber
-	   in the arraydefinition, both of which are in the superblock */
-	for (i = 0; (i < prom.raid.total_disks) && (i < 8); i++) {
-		if ((prom.raid.disk[i].channel == prom.raid.channel) &&
-		    (prom.raid.disk[i].device == prom.raid.device)) {
-
-			raid[device].disk[i].bdev = bdev;
-			raid[device].disk[i].device =
-			    mk_kdev(major, minor);
-			raid[device].disk[i].sectors = prom.raid.disk_secs;
-			raid[device].stride = (1 << prom.raid.raid0_shift);
-			raid[device].disks = prom.raid.total_disks;
-			raid[device].sectors = prom.raid.total_secs;
-			raid[device].geom.heads = prom.raid.heads + 1;
-			raid[device].geom.sectors = prom.raid.sectors;
-			raid[device].geom.cylinders =
-			    prom.raid.cylinders + 1;
-			devlist[devindex].device = device;
-			return;
-		}
-	}
-      out:
-	blkdev_put(bdev, BDEV_RAW);
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i, j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-
-	bar = 0;
-	for (i = 0; i < 8; i++) {
-		smallest = ~0;
-		for (j = 0; j < 8; j++)
-			if ((raid[device].disk[j].sectors < smallest)
-			    && (raid[device].disk[j].sectors > bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j = 0; j < 8; j++)
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-	}
-}
-
-static __init int pdcraid_init_one(int device, int raidlevel)
-{
-	int i, count;
-
-	for (i = 0; i < 14; i++)
-		probedisk(i, device, raidlevel);
-
-	if (raidlevel == 0)
-		fill_cutoff(device);
-
-	/* Initialize the gendisk structure */
-
-	ataraid_register_disk(device, raid[device].sectors);
-
-	count = 0;
-
-	for (i = 0; i < 8; i++) {
-		if (raid[device].disk[i].device != 0) {
-			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
-			       i, raid[device].disk[i].sectors / 2048,
-			       major(raid[device].disk[i].device),
-			       minor(raid[device].disk[i].device));
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid%i array consists of %i drives. \n",
-		       raidlevel, count);
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-}
-
-static __init int pdcraid_init(void)
-{
-	int retval, device, count = 0;
-
-	do {
-		cookie = 0;
-		device = ataraid_get_device(&pdcraid0_ops);
-		if (device < 0)
-			break;
-		retval = pdcraid_init_one(device, 0);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	do {
-
-		cookie = 0;
-		device = ataraid_get_device(&pdcraid1_ops);
-		if (device < 0)
-			break;
-		retval = pdcraid_init_one(device, 1);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	if (count) {
-		printk(KERN_INFO
-		       "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
-		return 0;
-	}
-	printk(KERN_DEBUG
-	       "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
-	return -ENODEV;
-}
-
-static void __exit pdcraid_exit(void)
-{
-	int i, device;
-	for (device = 0; device < 16; device++) {
-		for (i = 0; i < 8; i++) {
-			struct block_device *bdev =
-			    raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int pdcraid_open(struct inode *inode, struct file *filp)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int pdcraid_release(struct inode *inode, struct file *filp)
-{
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(pdcraid_init);
-module_exit(pdcraid_exit);
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/pdcraid.h b/drivers/ide/pdcraid.h
--- a/drivers/ide/pdcraid.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-struct promise_raid_conf {
-    char                promise_id[24];
-
-    u32             dummy_0;
-    u32             magic_0;
-    u32             dummy_1;
-    u32             magic_1;
-    u16             dummy_2;
-    u8              filler1[470];
-    struct {
-        u32 flags;                          /* 0x200 */
-        u8          dummy_0;
-        u8          disk_number;
-        u8          channel;
-        u8          device;
-        u32         magic_0;
-        u32         dummy_1;
-        u32         dummy_2;                /* 0x210 */
-        u32         disk_secs;
-        u32         dummy_3;
-        u16         dummy_4;
-        u8          status;
-        u8          type;
-        u8        total_disks;            /* 0x220 */
-        u8        raid0_shift;
-        u8        raid0_disks;
-        u8        array_number;
-        u32       total_secs;
-        u16       cylinders;
-        u8        heads;
-        u8        sectors;
-        u32         magic_1;
-        u32         dummy_5;                /* 0x230 */
-        struct {
-            u16     dummy_0;
-            u8      channel;
-            u8      device;
-            u32     magic_0;
-            u32     disk_number;
-        } disk[8];
-    } raid;
-    u32             filler2[346];
-    u32            checksum;
-};
-
-#define PR_MAGIC        "Promise Technology, Inc."
-
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/piix.c	Tue Aug 27 12:28:08 2002
@@ -1,527 +1,617 @@
 /*
- *  piix.c, v1.5 2002/05/03
+ *  linux/drivers/ide/piix.c		Version 0.32	June 9, 2000
  *
- *  Copyright (c) 2000-2002 Vojtech Pavlik
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  May be copied or modified under the terms of the GNU General Public License
  *
- *  Based on the work of:
- *	Andrzej Krzysztofowicz
- *      Andre Hedrick
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
  *
- *  Thanks to Daniela Egbert for advice on PIIX bugs.
- *  Thanks to Ulf Axelsson for noticing that ICH4 only documents UDMA100.
- */
-
-/*
- * Intel PIIX/ICH and Efar Victory66 IDE driver for Linux.
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ *
+ *    ata-33/82371AB
+ *    ata-33/82371EB
+ *    ata-33/82801AB            ata-66/82801AA
+ *    00|00 udma 0              00|00 reserved
+ *    01|01 udma 1              01|01 udma 3
+ *    10|10 udma 2              10|10 udma 4
+ *    11|11 reserved            11|11 reserved
+ *
+ * 54 8421|8421    ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
  *
- * UDMA66 and higher modes are autoenabled only in case the BIOS has detected a
- * 80 wire cable. To ignore the BIOS data and assume the cable is present, use
- * 'ide0=ata66' or 'ide1=ata66' on the kernel command line.
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
-
-#define PIIX_IDETIM0		0x40
-#define PIIX_IDETIM1		0x42
-#define PIIX_SIDETIM		0x44
-#define PIIX_IDESTAT		0x47
-#define PIIX_UDMACTL		0x48
-#define PIIX_UDMATIM		0x4a
-#define PIIX_IDECFG		0x54
-
-#define PIIX_UDMA		0x07
-#define PIIX_UDMA_NONE		0x00
-#define PIIX_UDMA_33		0x01
-#define PIIX_UDMA_66		0x02
-#define PIIX_UDMA_100		0x03
-#define PIIX_UDMA_133		0x04
-#define PIIX_NO_SITRE		0x08	/* Chip doesn't have separate slave timing */
-#define PIIX_PINGPONG		0x10	/* Enable ping-pong buffers */
-#define PIIX_VICTORY		0x20	/* Efar Victory66 has a different UDMA setup */
-#define PIIX_CHECK_REV		0x40	/* May be a buggy revision of PIIX */
-#define PIIX_NODMA		0x80	/* Don't do DMA with this chip */
+#include "ide_modes.h"
 
-/*
- * Intel IDE chips
- */
+#define PIIX_DEBUG_DRIVE_INFO		0
 
-static struct piix_ide_chip {
-	unsigned short id;
-	unsigned char flags;
-} piix_ide_chips[] = {
-	{ PCI_DEVICE_ID_INTEL_82801DB_9,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801DB ICH4 */
-	{ PCI_DEVICE_ID_INTEL_82801CA_11,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801CA ICH3/ICH3-S */
-	{ PCI_DEVICE_ID_INTEL_82801CA_10,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801CAM ICH3-M */
-	{ PCI_DEVICE_ID_INTEL_82801E_9,		PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801E C-ICH */
-	{ PCI_DEVICE_ID_INTEL_82801BA_9,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801BA ICH2 */
-	{ PCI_DEVICE_ID_INTEL_82801BA_8,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801BAM ICH2-M */
-	{ PCI_DEVICE_ID_INTEL_82801AB_1,	PIIX_UDMA_33  | PIIX_PINGPONG},				/* Intel 82801AB ICH0 */
-	{ PCI_DEVICE_ID_INTEL_82801AA_1,	PIIX_UDMA_66  | PIIX_PINGPONG },			/* Intel 82801AA ICH */
-	{ PCI_DEVICE_ID_INTEL_82372FB_1,	PIIX_UDMA_66 },						/* Intel 82372FB PIIX5 */
-	{ PCI_DEVICE_ID_INTEL_82443MX_1,	PIIX_UDMA_33 },						/* Intel 82443MX MPIIX4 */
-	{ PCI_DEVICE_ID_INTEL_82371AB,		PIIX_UDMA_33 },						/* Intel 82371AB/EB PIIX4/PIIX4E */
-	{ PCI_DEVICE_ID_INTEL_82371SB_1,	PIIX_UDMA_NONE },					/* Intel 82371SB PIIX3 */
-	{ PCI_DEVICE_ID_INTEL_82371FB_1,	PIIX_UDMA_NONE | PIIX_NO_SITRE | PIIX_CHECK_REV },	/* Intel 82371FB PIIX */
-	{ PCI_DEVICE_ID_EFAR_SLC90E66_1,	PIIX_UDMA_66 | PIIX_VICTORY },				/* Efar Victory66 */
-	{ 0 }
-};
+#define DISPLAY_PIIX_TIMINGS
 
-static struct piix_ide_chip *piix_config;
-static unsigned char piix_enabled;
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
 
-static char *piix_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
-
-/*
- * piix_set_speed() writes timing values to the chipset registers
- */
+static int piix_get_info(char *, char **, off_t, int);
+extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
 
-static void piix_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing, int umul)
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	unsigned short t;
-	unsigned char u;
-	unsigned int c;
-
-	pci_read_config_word(dev, PIIX_IDETIM0 + (dn & 2), &t);
-
-	switch (dn & 1) {
-
-		case 1:
-			if (timing->cycle > 9) {
-				t &= ~0x30;
-				break;
-			}
-
-			if (~piix_config->flags & PIIX_NO_SITRE) {
-				pci_read_config_byte(dev, PIIX_SIDETIM, &u);
-				u &= ~(0xf << ((dn & 2) << 1));
-				t |= 0x30;
-				u |= (4 - FIT(timing->recover, 1, 4)) << ((dn & 2) << 1);
-				u |= (5 - FIT(timing->active, 2, 5)) << (((dn & 2) << 1) + 2);
-				pci_write_config_byte(dev, PIIX_SIDETIM, u);
-				break;
-			}
-
-		case 0:
-			if ((~dn & 1) && timing->cycle > 9) {
-				t &= ~0x03;
-				break;
-			}
-
-			t &= 0xccff;
-			t |= 0x03 << ((dn & 1) << 2);
-			t |= (4 - FIT(timing->recover, 1, 4)) << 8;
-			t |= (5 - FIT(timing->active, 2, 5)) << 12;
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
+
+	p += sprintf(p, "\n                                ");
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+			p += sprintf(p, "Intel PIIX4 Ultra 100 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+			p += sprintf(p, "Intel PIIX4 Ultra 66 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82371AB:
+			p += sprintf(p, "Intel PIIX4 Ultra 33 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+			p += sprintf(p, "Intel PIIX3 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_INTEL_82371MX:
+			p += sprintf(p, "Intel MPIIX Chipset.\n");
+			return p-buffer;	/* => must be less than 4k! */
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		default:
+			p += sprintf(p, "Intel PIIX Chipset.\n");
+			break;
 	}
 
-	pci_write_config_word(dev, PIIX_IDETIM0 + (dn & 2), t);
-
-	if (!(piix_config->flags & PIIX_UDMA)) return;
-
-	pci_read_config_byte(dev, PIIX_UDMACTL, &u);
-	u &= ~(1 << dn);
-
-	if (timing->udma) {
-
-		u |= 1 << dn;
-
-		pci_read_config_word(dev, PIIX_UDMATIM, &t);
-
-		if (piix_config->flags & PIIX_VICTORY) {
-			t &= ~(0x07 << (dn << 2));
-			t |= (8 - FIT(timing->udma, 2, 8)) << (dn << 2);
-		} else {
-			t &= ~(0x03 << (dn << 2));
-			t |= (4 - FIT(timing->udma, 2, 4)) << (dn << 2);
-		}
-
-		pci_write_config_word(dev, PIIX_UDMATIM, t);
-
-		if ((piix_config->flags & PIIX_UDMA) > PIIX_UDMA_33
-			&& ~piix_config->flags & PIIX_VICTORY) {
-
-			pci_read_config_dword(dev, PIIX_IDECFG, &c);
-
-			if ((piix_config->flags & PIIX_UDMA) > PIIX_UDMA_66)
-				c &= ~(1 << (dn + 12));
-			c &= ~(1 << dn);
-
-			switch (umul) {
-				case 2: c |= 1 << dn;		break;
-				case 4: c |= 1 << (dn + 12);	break;
-			}
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+	pci_read_config_byte(bmide_dev, 0x54, &reg54);
+	pci_read_config_byte(bmide_dev, 0x55, &reg55);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb_p((unsigned short)bibma + 0x02);
+	c1 = inb_p((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
+			((reg54&0x11) && (reg4a&0x02)) ? "4" :
+			((reg54&0x11) && (reg4a&0x01)) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" :
+			((reg54&0x22) && (reg4a&0x20)) ? "4" :
+			((reg54&0x22) && (reg4a&0x10)) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" :
+			((reg54&0x44) && (reg4b&0x02)) ? "4" :
+			((reg54&0x44) && (reg4b&0x01)) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" :
+			((reg54&0x88) && (reg4b&0x20)) ? "4" :
+			((reg54&0x88) && (reg4b&0x10)) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
 
-			pci_write_config_dword(dev, PIIX_IDECFG, c);
-		}
-	}
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
 
-	pci_write_config_byte(dev, PIIX_UDMACTL, u);
+	return p-buffer;	 /* => must be less than 4k! */
 }
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
 
 /*
- * piix_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ *  Used to set Fifo configuration via kernel command line:
  */
 
-static int piix_set_drive(struct ata_device *drive, unsigned char speed)
-{
-	struct ata_device *peer = drive->channel->drives + (~drive->dn & 1);
-	struct ata_timing t, p;
-	int err, T, UT, umul = 1;
+byte piix_proc = 0;
 
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if ((err = ide_config_drive_speed(drive, speed)))
-			return err;
 
-	if (speed > XFER_UDMA_2 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66)
-		umul = 2;
-	if (speed > XFER_UDMA_4 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100)
-		umul = 4;
+static byte piix_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= 0x00;
 
-	T = 1000000000 / system_bus_speed;
-	UT = T / umul;
+	switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+			mode |= 0x03;
+			break;
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+			mode |= 0x02;
+			break;
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			mode |= 0x01;
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		default:
+			return (mode &= ~0xF8);
+	}
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
 
-	ata_timing_compute(drive, speed, &t, T, UT);
+static byte piix_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = piix_ratemask(drive);
 
-	if ((piix_config->flags & PIIX_NO_SITRE) && peer->present) {
-			ata_timing_compute(peer, peer->current_speed, &p, T, UT);
-			if (t.cycle <= 9 && p.cycle <= 9)
-				ata_timing_merge(&p, &t, &t, IDE_TIMING_ALL);
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
 	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
 
-	piix_set_speed(drive->channel->pci_dev, drive->dn, &t, umul);
-
-	return 0;
+static byte piix_dma_2_pio (byte xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
 }
 
 /*
- * piix_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
  */
+static void piix_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	byte slave_data;
+				 /* ISP  RTC */
+	byte timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
 
-static void piix_tune_drive(struct ata_device *drive, unsigned char pio)
+static int piix_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	if (!((piix_enabled >> drive->channel->unit) & 1))
-		return;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte maslave		= hwif->channel ? 0x42 : 0x40;
+	byte speed		= piix_ratefilter(drive, xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	short			reg4042, reg44, reg48, reg4a, reg54;
+	byte			reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
 
-	if (pio == 255) {
-		piix_set_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
+		}
+		if (!(reg4a & u_speed)) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag)) {
+				pci_write_config_word(dev, 0x54, reg54|v_flag);
+			}
+		} else {
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
 	}
 
-	piix_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int __init piix_modes_map(struct ata_channel *ch)
+static int piix_config_drive_for_dma (ide_drive_t *drive)
 {
-	short w80 = ch->udma_four;
-	int map = XFER_EPIO |
-		  (piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA |
-		  (piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) |
-		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) |
-		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0) |
-		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_133 ? XFER_UDMA_133 : 0)));
+	struct hd_driveid *id	= drive->id;
+	byte mode		= piix_ratemask(drive);
+	byte speed, tspeed, dma = 1;
+
+	switch(mode) {
+		case 0x03:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_5; break; }
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+		default:
+			tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+			speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+			dma = 0;
+			break;
+	}
+
+	(void) piix_tune_chipset(drive, speed);
 
-	return map;
+//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
+	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
 }
-#endif
 
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-static unsigned int __init piix_init_chipset(struct pci_dev *dev)
+static int config_drive_xfer_rate (ide_drive_t *drive)
 {
-	struct pci_dev *orion = NULL;
-	unsigned int u;
-	unsigned short w;
-	unsigned char t;
-	int i;
-
-/*
- * Find out which Intel IDE this is.
- */
-
-	for (piix_config = piix_ide_chips; piix_config->id != 0; ++piix_config)
-		if (dev->device == piix_config->id)
-			break;
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
 
-/*
- * Check for possibly broken DMA configs.
- */
+	drive->init_speed = 0;
 
-	if (piix_config->flags & PIIX_CHECK_REV) {
-		pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-		if (t < 2) {
-			printk(KERN_INFO "PIIX: Found buggy old PIIX rev %#x, disabling DMA\n", t);
-			piix_config->flags |= PIIX_NODMA;
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
 		}
-	}
-
-	if ((orion = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, NULL))) {
-		pci_read_config_byte(orion, PCI_REVISION_ID, &t);
-		if (t < 4) {
-			printk(KERN_INFO "PIIX: Found buggy 82454GX Orion bridge rev %#x, disabling DMA\n", t);
-			piix_config->flags |= PIIX_NODMA;
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = piix_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = piix_config_drive_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = piix_config_drive_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
 		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		piix_tune_drive(drive, 255);
 	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
 
-/*
- * Enable ping-pong buffers where applicable.
- */
-
-	if (piix_config->flags & PIIX_PINGPONG) {
-		pci_read_config_dword(dev, PIIX_IDECFG, &u);
-		u |= 0x400;
-		pci_write_config_dword(dev, PIIX_IDECFG, u);
+static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default :
+			break;
 	}
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-/*
- * Detect enabled interfaces, enable slave separate timing if possible.
- */
-
-	for (i = 0; i < 2; i++) {
-		pci_read_config_word(dev, PIIX_IDETIM0 + (i << 1), &w);
-		piix_enabled |= (w & 0x8000) ? (1 << i) : 0;
-		w &= 0x8c00;
-		if (~piix_config->flags & PIIX_NO_SITRE) w |= 0x4000;
-		w |= 0x44;
-		pci_write_config_word(dev, PIIX_IDETIM0 + (i << 1), w);
+unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
+{
+        switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		{
+			unsigned int extra = 0;
+			pci_read_config_dword(dev, 0x54, &extra);
+			pci_write_config_dword(dev, 0x54, extra|0x400);
+		}
+		default:
+			break;
 	}
 
-/*
- * Print the boot message.
- */
-
-	printk(KERN_INFO "PIIX: %s %s controller on pci%s\n",
-		dev->name, piix_dma[piix_config->flags & PIIX_UDMA], dev->slot_name);
-
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!piix_proc) {
+		piix_proc = 1;
+		bmide_dev = dev;
+		piix_display_info = &piix_get_info;
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
 	return 0;
 }
 
-static unsigned int __init piix_ata66_check(struct ata_channel *ch)
+/*
+ * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards.
+ * It does not specify device detection, but channel!!!
+ * You determine later if bit 13 of word93 is set...
+ */
+unsigned int __init ata66_piix (ide_hwif_t *hwif)
 {
-	unsigned char t;
-	unsigned int u;
+	byte reg54h = 0, reg55h = 0, ata66 = 0;
+	byte mask = hwif->channel ? 0xc0 : 0x30;
 
-	if ((piix_config->flags & PIIX_UDMA) < PIIX_UDMA_66)
-		return 0;
+	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+	pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
 
-	if (piix_config->flags & PIIX_VICTORY) {
-		pci_read_config_byte(ch->pci_dev, PIIX_IDESTAT, &t);
-		return ch->unit ? (t & 1) : !!(t & 2);
-	}
+	ata66 = (reg54h & mask) ? 1 : 0;
 
-	pci_read_config_dword(ch->pci_dev, PIIX_IDECFG, &u);
-	return ch->unit ? !!(u & 0xc0) : !!(u & 0x30);
+	return ata66;
 }
 
-static void __init piix_init_channel(struct ata_channel *ch)
+void __init ide_init_piix (ide_hwif_t *hwif)
 {
-	int i;
+#ifndef CONFIG_IA64
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
 
-	ch->udma_four = piix_ata66_check(ch);
-
-	ch->tuneproc = &piix_tune_drive;
-	ch->speedproc = &piix_set_drive;
-	ch->io_32bit = 1;
-	ch->unmask = 1;
-	for (i = 0; i < 2; i++) {
-		ch->drives[i].autotune = 1;
-		ch->drives[i].dn = ch->unit * 2 + i;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+		/* This is a painful system best to let it self tune for now */
+		return;
 	}
 
+	hwif->autodma = 0;
+	hwif->tuneproc = &piix_tune_drive;
+	hwif->speedproc = &piix_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (ch->dma_base) {
-		ch->highmem = 1;
-		ch->modes_map = piix_modes_map(ch);
-		ch->udma_setup = udma_generic_setup;
-	}
-#endif
+	hwif->dmaproc = &piix_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
 }
 
-/*
- * We allow the BM-DMA driver only work on enabled interfaces,
- * and only if DMA is safe with the chip and bridge.
- */
-static void __init piix_init_dma(struct ata_channel *ch, unsigned long dmabase)
-{
-	if (((piix_enabled >> ch->unit) & 1)
-		&& !(piix_config->flags & PIIX_NODMA))
-			ata_init_dma(ch, dmabase);
-}
-
-
-
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82371FB_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82371SB_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82371AB,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82443MX_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82372FB_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801AA_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801AB_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801BA_9,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801BA_8,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801E_9,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801CA_10,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801CA_11,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_INTEL,
-		.device = PCI_DEVICE_ID_INTEL_82801DB_9,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_EFAR,
-		.device = PCI_DEVICE_ID_EFAR_SLC90E66_1,
-		.init_chipset = piix_init_chipset,
-		.init_channel = piix_init_channel,
-		.init_dma = piix_init_dma,
-		.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		.bootable = ON_BOARD
-	},
-};
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-int __init init_piix(void)
+void __init fixup_device_piix (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+	if (dev->resource[0].start != 0x01F1)
+		ide_register_xp_fix(dev);
 
-	return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c
--- a/drivers/ide/probe.c	Tue Aug 27 12:27:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1215 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- *
- *  Mostly written by Mark Lord <mlord@pobox.com>
- *                and Gadi Oxman <gadio@netvision.net.il>
- *                and Andre Hedrick <andre@linux-ide.org>
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- */
-
-/*
- * This is roughly the code related to device detection and
- * device id handling.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-extern struct ata_device * get_info_ptr(kdev_t);
-
-/*
- * This is called from the partition-table code in pt/msdos.c
- * to invent a translated geometry.
- *
- * This is suppressed if the user specifies an explicit geometry.
- *
- * The ptheads parameter is either 0 or tells about the number of
- * heads shown by the end of the first nonempty partition.
- * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
- *
- * The xparm parameter has the following meaning:
- *	 0 = convert to CHS with fewer than 1024 cyls
- *	     using the same method as Ontrack DiskManager.
- *	 1 = same as "0", plus offset everything by 63 sectors.
- *	-1 = similar to "0", plus redirect sector 0 to sector 1.
- *	 2 = convert to a CHS geometry with "ptheads" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
- */
-int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg)
-{
-	struct ata_device *drive;
-	const char *msg1 = "";
-	int heads = 0;
-	int c, h, s;
-	int transl = 1;		/* try translation */
-	int ret = 0;
-
-	drive = get_info_ptr(i_rdev);
-	if (!drive)
-		return 0;
-
-	/* There used to be code here that assigned drive->id->CHS to
-	 * drive->CHS and that to drive->bios_CHS. However, some disks have
-	 * id->C/H/S = 4092/16/63 but are larger than 2.1 GB.  In such cases
-	 * that code was wrong.  Moreover, there seems to be no reason to do
-	 * any of these things.
-	 *
-	 * Please note that recent RedHat changes to the disk utils are bogous
-	 * and will report spurious errors.
-	 */
-
-	/* translate? */
-	if (drive->forced_geom)
-		transl = 0;
-
-	/* does ptheads look reasonable? */
-	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
-	    ptheads == 240 || ptheads == 255)
-		heads = ptheads;
-
-	if (xparm == 2) {
-		if (!heads ||
-		   (drive->bios_head >= heads && drive->bios_sect == 63))
-			transl = 0;
-	}
-	if (xparm == -1) {
-		if (drive->bios_head > 16)
-			transl = 0;     /* we already have a translation */
-	}
-
-	if (transl) {
-		static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-		const u8 *headp = dm_head_vals;
-		unsigned long total;
-
-		/*
-		 * If heads is nonzero: find a translation with this many heads
-		 * and S=63.  Otherwise: find out how OnTrack Disk Manager
-		 * would translate the disk.
-		 *
-		 * The specs say: take geometry as obtained from Identify,
-		 * compute total capacity C*H*S from that, and truncate to
-		 * 1024*255*63. Now take S=63, H the first in the sequence 4,
-		 * 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
-		 * [Please tell aeb@cwi.nl in case this computes a geometry
-		 * different from what OnTrack uses.]
-		 */
-
-		total = ata_capacity(drive);
-
-		s = 63;
-
-		if (heads) {
-			h = heads;
-			c = total / (63 * heads);
-		} else {
-			while (63 * headp[0] * 1024 < total && headp[1] != 0)
-				headp++;
-			h = headp[0];
-			c = total / (63 * headp[0]);
-		}
-
-		drive->bios_cyl = c;
-		drive->bios_head = h;
-		drive->bios_sect = s;
-		ret = 1;
-	}
-
-	drive->part[0].nr_sects = ata_capacity(drive);
-
-	if (ret)
-		printk("%s%s [%d/%d/%d]", msg, msg1,
-		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
-	return ret;
-}
-
-/*
- * Drive ID data come as little endian, it needs to be converted on big endian
- * machines.
- */
-void ata_fix_driveid(struct hd_driveid *id)
-{
-#ifndef __LITTLE_ENDIAN
-# ifdef __BIG_ENDIAN
-	int i;
-	u16 *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; ++i)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-	for (i = 0; i < 4; ++i)
-		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; ++i)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-# else
-#  error "Please fix <asm/byteorder.h>"
-# endif
-#endif
-}
-
-void ide_fixstring(char *s, const int bytecount, const int byteswap)
-{
-	char *p = s;
-	char *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-	if (byteswap) {
-		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;) {
-			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = ntohs(*pp);
-		}
-	}
-
-	/* strip leading blanks */
-	while (s != end && *s == ' ')
-		++s;
-
-	/* compress internal blanks and strip trailing blanks */
-	while (s != end && *s) {
-		if (*s++ != ' ' || (s != end && *s && *s != ' '))
-			*p++ = *(s-1);
-	}
-
-	/* wipe out trailing garbage */
-	while (p != end)
-		*p++ = '\0';
-}
-
-/*
- *  All hosts that use the 80c ribbon must use this!
- */
-int eighty_ninty_three(struct ata_device *drive)
-{
-	return ((drive->channel->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-		(drive->id->hw_config & 0x4000) &&
-#endif
-		(drive->id->hw_config & 0x6000)) ? 1 : 0;
-}
-
-/* FIXME: Channel lock should be held.
- */
-int ide_config_drive_speed(struct ata_device *drive, u8 speed)
-{
-	struct ata_channel *ch = drive->channel;
-	int ret;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
-	u8 unit = (drive->select.b.unit & 0x01);
-	outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2);
-#endif
-
-	/*
-         * Select the drive, and issue the SETFEATURES command.
-         */
-	disable_irq(ch->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	ata_select(drive, 0);
-	ata_mask(drive);
-	udelay(1);
-	ata_irq_enable(drive, 0);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if (drive->quirk_list == 2)
-		ata_irq_enable(drive, 1);
-	udelay(1);
-	ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_CMD, NULL);
-	ata_mask(drive);
-	enable_irq(ch->irq);
-
-	if (ret != ATA_OP_READY) {
-		ata_dump(drive, NULL, "set drive speed");
-		return 1;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
-	if (speed > XFER_PIO_4) {
-		outb(inb(ch->dma_base + 2)|(1 << (5 + unit)), ch->dma_base + 2);
-	} else {
-		outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2);
-	}
-#endif
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-static inline void do_identify(struct ata_device *drive, u8 cmd)
-{
-	int bswap = 1;
-	struct hd_driveid *id;
-
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
-	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
-		goto err_kmalloc;
-	}
-
-	/* Read 512 bytes of id info.
-	 *
-	 * Please note that it is well known that some *very* old drives are
-	 * able to provide only 256 of them, since this was the amount read by
-	 * DOS.
-	 *
-	 * However let's try to get away with this...
-	 */
-
-	ata_read(drive, id, SECTOR_WORDS);
-	local_irq_enable();
-	ata_fix_driveid(id);
-
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
-	}
-
-	if (!drive->forced_lun)
-		drive->last_lun = id->last_lun & 0x7;
-#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
-	/*
-	 * EATA SCSI controllers do a hardware ATA emulation:
-	 * Ignore them if there is a driver for them available.
-	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
-		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-		goto err_misc;
-	}
-#endif
-
-	/*
-	 *  WIN_IDENTIFY returns little-endian info,
-	 *  WIN_PIDENTIFY *usually* returns little-endian info.
-	 */
-	if (cmd == WIN_PIDENTIFY) {
-		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
-		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
-		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
-	}
-	ide_fixstring(id->model,     sizeof(id->model),     bswap);
-	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
-
-	if (strstr(id->model, "E X A B Y T E N E S T"))
-		goto err_misc;
-
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
-	printk("%s: %s, ", drive->name, id->model);
-	drive->present = 1;
-
-	/*
-	 * Check for an ATAPI device:
-	 */
-	if (cmd == WIN_PIDENTIFY) {
-		u8 type = (id->config >> 8) & 0x1f;
-		printk("ATAPI ");
-#ifdef CONFIG_BLK_DEV_PDC4030
-		if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
-			printk(" -- not supported on 2nd Promise port\n");
-			goto err_misc;
-		}
-#endif
-		switch (type) {
-			case ATA_FLOPPY:
-				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
-						printk("cdrom or floppy?, assuming ");
-					if (drive->type != ATA_ROM) {
-						printk ("FLOPPY");
-						break;
-					}
-				}
-				type = ATA_ROM;	/* Early cdrom models used zero */
-			case ATA_ROM:
-				drive->removable = 1;
-#ifdef CONFIG_PPC
-				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
-					printk ("FLOPPY");
-					type = ATA_FLOPPY;
-					break;
-				}
-#endif
-				printk ("CD/DVD-ROM");
-				break;
-			case ATA_TAPE:
-				printk ("TAPE");
-				break;
-			case ATA_MOD:
-				printk ("OPTICAL");
-				drive->removable = 1;
-				break;
-			default:
-				printk("UNKNOWN (type %d)", type);
-				break;
-		}
-		printk (" drive\n");
-		drive->type = type;
-		return;
-	}
-
-	/*
-	 * Not an ATAPI device: looks like a "regular" hard disk:
-	 */
-	if (id->config & (1<<7))
-		drive->removable = 1;
-
-	/*
-	 * FIXME: This is just plain ugly or plain unnecessary.
-	 *
-	 * Prevent long system lockup probing later for non-existant slave
-	 * drive if the hwif is actually a flash memory card of some variety:
-	 */
-
-	if (drive_is_flashcard(drive)) {
-		struct ata_device *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
-		if (!mate->ata_flash) {
-			mate->present = 0;
-			mate->noprobe = 1;
-		}
-	}
-	drive->type = ATA_DISK;
-	printk("DISK drive\n");
-
-	/* Initialize our quirk list. */
-	if (drive->channel->quirkproc)
-		drive->quirk_list = drive->channel->quirkproc(drive);
-
-	/* Initialize queue depth settings */
-	drive->queue_depth = 1;
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
-	drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
-#else
-	drive->queue_depth = drive->id->queue_depth + 1;
-#endif
-	if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
-		drive->queue_depth = IDE_MAX_TAG;
-
-	return;
-
-err_misc:
-	kfree(id);
-err_kmalloc:
-	drive->present = 0;
-
-	return;
-}
-
-/*
- * Sends an ATA(PI) IDENTIFY request to a drive and wait for a response.  It
- * also monitor irqs while this is happening, in hope of automatically
- * determining which one is being used by the interface.
- *
- * Returns:	0  device was identified
- *		1  device timed-out (no response to identify request)
- *		2  device aborted the command (refused to identify itself)
- */
-static int identify(struct ata_device *drive, u8 cmd)
-{
-	struct ata_channel *ch = drive->channel;
-	int rc = 1;
-	int autoprobe = 0;
-	unsigned long cookie = 0;
-	ide_ioreg_t hd_status;
-	unsigned long timeout;
-
-
-	/* FIXME: perhaps we should be just using allways the status register,
-	 * since it should simplify the code significantly.
-	 */
-	if (ch->io_ports[IDE_CONTROL_OFFSET]) {
-		u8 s;
-		u8 a;
-
-		if (!drive->channel->irq) {
-			autoprobe = 1;
-			cookie = probe_irq_on();
-			ata_irq_enable(drive, 1);	/* enable device irq */
-		}
-
-		/* take a deep breath */
-		mdelay(50);
-		a = IN_BYTE(ch->io_ports[IDE_ALTSTATUS_OFFSET]);
-		s = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
-		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = ch->io_ports[IDE_STATUS_OFFSET];	/* ancient Seagate drives, broken interfaces */
-		} else {
-			hd_status = ch->io_ports[IDE_ALTSTATUS_OFFSET];	/* use non-intrusive polling */
-		}
-	} else {
-		mdelay(50);
-		hd_status = ch->io_ports[IDE_STATUS_OFFSET];
-	}
-
-	/* set features register for atapi identify command to be sure of reply */
-	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
-
-#if CONFIG_BLK_DEV_PDC4030
-	if (drive->channel->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(struct ata_device *);
-
-		if (pdc4030_identify(drive))
-			goto out;
-	} else
-#endif
-		OUT_BYTE(cmd, IDE_COMMAND_REG);		/* ask drive for ID */
-	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-	timeout += jiffies;
-	do {
-		if (time_after(jiffies, timeout))
-			goto out;	/* drive timed-out */
-		mdelay(50);		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
-
-	mdelay(50);		/* wait for IRQ and DRQ_STAT */
-
-	if (ata_status(drive, DRQ_STAT, BAD_R_STAT)) {
-		unsigned long flags;
-
-		local_irq_save(flags);		/* some systems need this */
-		do_identify(drive, cmd);	/* drive returned ID */
-		rc = 0;				/* drive responded with ID */
-		ata_status(drive, 0, 0);	/* clear drive IRQ */
-		local_irq_restore(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
-
-out:
-	if (autoprobe) {
-		int irq;
-
-		ata_irq_enable(drive, 0);	/* mask device irq */
-		ata_status(drive, 0, 0);	/* clear drive IRQ */
-		udelay(5);
-		irq = probe_irq_off(cookie);
-		if (!drive->channel->irq) {
-			if (irq > 0)
-				drive->channel->irq = irq;
-			else	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
-		}
-	}
-
-	return rc;
-}
-
-
-/*
- * This has the difficult job of finding a drive if it exists, without getting
- * hung up if it doesn't exist, without trampling on ethernet cards, and
- * without leaving any IRQs dangling to haunt us later.
- *
- * If a drive is "known" to exist (from CMOS or kernel parameters), but does
- * not respond right away, the probe will "hang in there" for the maximum wait
- * time (about 30 seconds), otherwise it will exit much more quickly.
- *
- * Returns:	0  device was identified
- *		1  device timed-out (no response to identify request)
- *		2  device aborted the command (refused to identify itself)
- *		3  bad status from device (possible for ATAPI drives)
- *		4  probe was not attempted because failure was obvious
- */
-static int do_probe(struct ata_device *drive, u8 cmd)
-{
-	int rc;
-	struct ata_channel *ch = drive->channel;
-	u8 select;
-
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
-		if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
-			return 4;
-	}
-#ifdef DEBUG
-	printk("probing for %s: present=%d, type=%02x, probetype=%s\n",
-		drive->name, drive->present, drive->type,
-		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
-#endif
-	mdelay(50);	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	ata_select(drive, 50000);
-	select = IN_BYTE(IDE_SELECT_REG);
-	if (select != drive->select.all && !drive->present) {
-		if (drive->select.b.unit != 0) {
-			ata_select(&ch->drives[0], 50000);	/* exit with drive0 selected */
-		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
-	}
-
-	if (ata_status(drive, READY_STAT, BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY)	{
-		if ((rc = identify(drive,cmd)))   /* send cmd and wait */
-			rc = identify(drive,cmd); /* failed: try again */
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
-			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n",
-					drive->name, drive->status);
-			mdelay(50);
-			OUT_BYTE(drive->select.all, IDE_SELECT_REG);
-			mdelay(50);
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
-			timeout = jiffies;
-			while (!ata_status(drive, 0, BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
-				mdelay(50);
-			rc = identify(drive, cmd);
-		}
-		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n",
-					drive->name, drive->status);
-		ata_status(drive, 0, 0);	/* ensure drive irq is clear */
-	} else
-		rc = 3;				/* not present or maybe ATAPI */
-
-	if (drive->select.b.unit != 0) {
-		ata_select(&ch->drives[0], 50000);	/* exit with drive0 selected */
-		ata_status(drive, 0, 0);		/* ensure drive irq is clear */
-	}
-
-	return rc;
-}
-
-/*
- * Probe for drivers on a channel.
- *
- * This routine only knows how to look for drive units 0 and 1 on an interface,
- * so any setting of MAX_DRIVES > 2 won't work here.
- */
-static void channel_probe(struct ata_channel *ch)
-{
-	unsigned int i;
-	unsigned long flags;
-	int error;
-
-	if (ch->noprobe)
-		return;
-
-	ch->straight8 = 0;
-
-	local_save_flags(flags);
-	local_irq_enable();	/* needed for jiffies and irq probing */
-
-	/*
-	 * Check for the presence of a channel by probing for drives on it.
-	 */
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		if (drive->noprobe)	/* don't look for this one */
-			continue;
-
-		if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-			do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
-		}
-
-		/* Special handling of EXABYTE controller cards. */
-		if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) {
-			unsigned long timeout;
-
-			printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
-			ata_select(drive, 50000);
-			OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
-			timeout = jiffies + WAIT_WORSTCASE;
-			do {
-				if (time_after(jiffies, timeout)) {
-					printk("failed (timeout)\n");
-					return;
-				}
-				mdelay(50);
-			} while (!ata_status(drive, 0, BUSY_STAT));
-			mdelay(50);
-			if (!ata_status(drive, 0, BAD_STAT))
-				printk("failed (status = 0x%02x)\n", drive->status);
-			else
-				printk("success\n");
-
-			if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-				do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
-		}
-		}
-
-		if (!drive->present)
-			continue;	/* drive not found */
-
-		if (!drive->id) {	/* identification failed? */
-			if (drive->type == ATA_DISK)
-				printk ("%s: pre-ATA drive, CHS=%d/%d/%d\n",
-						drive->name, drive->cyl, drive->head, drive->sect);
-			else if (drive->type == ATA_ROM)
-				printk("%s: ATAPI cdrom (?)\n", drive->name);
-			else
-				drive->present = 0;	/* nuke it */
-		}
-
-		/* drive found, there is a channel it is attached too. */
-		if (drive->present)
-			ch->present = 1;
-	}
-
-	if (!ch->present)
-		goto not_found;
-
-	error = 0;
-
-	if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
-			((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
-		error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
-		ch->straight8 = 1;
-	} else {
-		for (i = 0; i < 8; i++)
-			error += !request_region(ch->io_ports[i], 1, ch->name);
-	}
-	if (ch->io_ports[IDE_CONTROL_OFFSET])
-		error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (ch->io_ports[IDE_IRQ_OFFSET])
-		error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
-#endif
-
-	/* Some neccessary register area was already used. Skip this device.
-	 */
-
-	if (
-#if CONFIG_BLK_DEV_PDC4030
-			(ch->chipset != ide_pdc4030 || ch->unit == 0) &&
-#endif
-			error) {
-
-		/* FIXME: We should be dealing properly with partial IO region
-		 * allocations here.
-		 */
-
-		ch->present = 0;
-		printk("%s: error: ports already in use!\n", ch->name);
-	}
-
-	if (!ch->present)
-		goto not_found;
-
-	/* Register this hardware interface within the global device tree.
-	 *
-	 * FIXME: This should be handled as a pci subdevice in a generic way.
-	 */
-	sprintf(ch->dev.bus_id, "ata@%02x", ch->unit);
-	strcpy(ch->dev.name, "ATA/ATAPI Host-Channel");
-	ch->dev.driver_data = ch;
-#ifdef CONFIG_PCI
-	if (ch->pci_dev)
-		ch->dev.parent = &ch->pci_dev->dev;
-	else
-#endif
-		ch->dev.parent = NULL; /* Would like to do = &device_legacy */
-
-	device_register(&ch->dev);
-
-	if (ch->reset)
-		ata_reset(ch);
-
-	local_irq_restore(flags);
-
-	/*
-	 * Now setup the PIO transfer modes of the drives on this channel.
-	 */
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		if (drive->present && (drive->autotune == 1)) {
-			if (drive->channel->tuneproc)
-				drive->channel->tuneproc(drive, 255);	/* auto-tune PIO mode */
-		}
-	}
-
-	return;
-
-not_found:
-	local_irq_restore(flags);
-}
-
-/*
- * This routine sets up the irq for an ide interface, and creates a new hwgroup
- * for the irq/channel if none was previously assigned.
- *
- * Much of the code is for correctly detecting/handling irq sharing and irq
- * serialization situations.  This is somewhat complex because it handles
- * static as well as dynamic (PCMCIA) IDE interfaces.
- *
- * The SA_INTERRUPT in sa_flags means ata_irq_request() is always entered with
- * interrupts completely disabled.  This can be bad for interrupt latency, but
- * anything else has led to problems on some machines.  We re-enable interrupts
- * as much as we can safely do in most places.
- */
-static int init_irq(struct ata_channel *ch)
-{
-	unsigned long flags;
-	int i;
-	spinlock_t *lock;
-	spinlock_t *new_lock;
-	unsigned long *active;
-	unsigned long *new_active;
-	struct ata_channel *match = NULL;
-
-	/* Spare allocation before sleep. */
-	new_lock = kmalloc(sizeof(*lock), GFP_KERNEL);
-	new_active = kmalloc(sizeof(*active), GFP_KERNEL);
-	*new_active = 0L;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	ch->lock = NULL;
-
-#if MAX_HWIFS > 1
-	/*
-	 * Group up with any other channels that share our irq(s).
-	 */
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		struct ata_channel *h = &ide_hwifs[i];
-
-		/* scan only initialized channels */
-		if (!h->lock)
-			continue;
-
-		if (ch->irq != h->irq)
-		        continue;
-
-		ch->sharing_irq = h->sharing_irq = 1;
-
-		if (ch->chipset != ide_pci || h->chipset != ide_pci ||
-		     ch->serialized || h->serialized) {
-			if (match && match->lock && match->lock != h->lock)
-				printk("%s: potential irq problem with %s and %s\n", ch->name, h->name, match->name);
-			/* don't undo a prior perfect match */
-			if (!match || match->irq != ch->irq)
-				match = h;
-		}
-	}
-#endif
-	/*
-	 * If we are still without a lock group, then form a new one
-	 */
-	if (!match) {
-		lock = new_lock;
-		active = new_active;
-		if (!lock) {
-			spin_unlock_irqrestore(&ide_lock, flags);
-
-			return 1;
-		}
-		spin_lock_init(lock);
-	} else {
-		lock = match->lock;
-		active = match->active;
-		if(new_lock)
-			kfree(new_lock);
-	}
-
-	/*
-	 * Allocate the irq, if not already obtained for another channel
-	 */
-	if (!match || match->irq != ch->irq) {
-		struct ata_device tmp;
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else
-		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
-#endif
-
-		/* Enable interrupts triggered by the drive.  We use a shallow
-		 * device structure, just to use the generic function very
-		 * early.
-		 */
-		tmp.channel = ch;
-		ata_irq_enable(&tmp, 1);
-
-		if (request_irq(ch->irq, &ata_irq_request, sa, ch->name, ch)) {
-			if (!match) {
-				kfree(lock);
-				kfree(active);
-			}
-
-			spin_unlock_irqrestore(&ide_lock, flags);
-
-			return 1;
-		}
-	}
-
-	/*
-	 * Everything is okay. Tag us as member of this lock group.
-	 */
-	ch->lock = lock;
-	ch->active = active;
-
-	init_timer(&ch->timer);
-	ch->timer.function = &ide_timer_expiry;
-	ch->timer.data = (unsigned long) ch;
-
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-		request_queue_t *q;
-		int max_sectors = 255;
-
-		if (!drive->present)
-			continue;
-
-		if (!ch->drive)
-			ch->drive = drive;
-
-		/*
-		 * Init the per device request queue.
-		 */
-
-		q = &drive->queue;
-		q->queuedata = drive;
-		blk_init_queue(q, do_ide_request, drive->channel->lock);
-		blk_queue_segment_boundary(q, ch->seg_boundary_mask);
-		blk_queue_max_segment_size(q, ch->max_segment_size);
-
-		/* ATA can do up to 128K per request, pdc4030 needs smaller
-		 * limit. */
-#ifdef CONFIG_BLK_DEV_PDC4030
-		if (drive->channel->chipset == ide_pdc4030)
-			max_sectors = 127;
-#endif
-		blk_queue_max_sectors(q, max_sectors);
-
-		/* ATA DMA can do PRD_ENTRIES number of segments. */
-		blk_queue_max_hw_segments(q, PRD_ENTRIES);
-
-		/* FIXME: This is a driver limit and could be eliminated. */
-		blk_queue_max_phys_segments(q, PRD_ENTRIES);
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET],
-		ch->io_ports[IDE_DATA_OFFSET]+7,
-		ch->io_ports[IDE_CONTROL_OFFSET], ch->irq);
-#elif defined(__sparc__)
-	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET],
-		ch->io_ports[IDE_DATA_OFFSET]+7,
-		ch->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(ch->irq));
-#else
-	printk("%s at %p on irq 0x%08x", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET], ch->irq);
-#endif
-	if (match)
-		printk(" (%sed with %s)",
-			ch->sharing_irq ? "shar" : "serializ", match->name);
-	printk("\n");
-
-	return 0;
-}
-
-/*
- * Returns the queue which corresponds to a given device.
- *
- * FIXME: this should take struct block_device * as argument in future.
- */
-static request_queue_t *ata_get_queue(kdev_t dev)
-{
-	struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data;
-
-	/* FIXME: ALLERT: This discriminates between master and slave! */
-	return &ch->drives[DEVICE_NR(dev) & 1].queue;
-}
-
-/* Number of minor numbers we consume par channel. */
-#define ATA_MINORS	(MAX_DRIVES * (1 << PARTN_BITS))
-
-static void channel_init(struct ata_channel *ch)
-{
-	struct gendisk *gd;
-	struct hd_struct *part;
-	devfs_handle_t *de_arr;
-	char *flags;
-	unsigned int unit;
-	extern devfs_handle_t ide_devfs_handle;
-	char *names;
-
-	if (!ch->present)
-		return;
-
-	/* we set it back to 1 if all is ok below */
-	ch->present = 0;
-
-	if (!ch->irq) {
-		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: DISABLED, NO IRQ\n", ch->name);
-
-			return;
-		}
-	}
-#ifdef CONFIG_BLK_DEV_HD
-
-	/* The first "legacy"  HD gets distinguished by the IRQ it is attached
-	 * to and the IO port it takes.
-	 */
-
-	if (ch->irq == 14 && ch->io_ports[IDE_DATA_OFFSET] != 0x1f0) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
-
-		return;
-	}
-#endif
-
-	if (register_blkdev(ch->major, ch->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", ch->name, ch->major);
-
-		return;
-	}
-
-	if (init_irq(ch)) {
-		int irq = ch->irq;
-		/*
-		 * It failed to initialise. Find the default IRQ for
-		 * this port and try that.
-		 */
-		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
-			printk(KERN_INFO "%s: disabled; unable to get IRQ %d.\n", ch->name, irq);
-			(void) unregister_blkdev (ch->major, ch->name);
-
-			return;
-		}
-		if (init_irq(ch)) {
-			printk(KERN_INFO "%s: probed IRQ %d and default IRQ %d failed.\n",
-				ch->name, irq, ch->irq);
-			(void) unregister_blkdev(ch->major, ch->name);
-
-			return;
-		}
-		printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq);
-	}
-
-	/* Initialize partition and global device data.
-	 */
-
-	gd = kmalloc (MAX_DRIVES * sizeof(struct gendisk), GFP_KERNEL);
-	if (!gd)
-		goto err_kmalloc_gd;
-
-	memset(gd, 0, MAX_DRIVES * sizeof(struct gendisk));
-
-	part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL);
-	if (!part)
-		goto err_kmalloc_gd_part;
-	memset(part, 0, ATA_MINORS * sizeof(struct hd_struct));
-
-	de_arr = kmalloc (sizeof(devfs_handle_t) * MAX_DRIVES, GFP_KERNEL);
-	if (!de_arr)
-		goto err_kmalloc_gd_de_arr;
-	memset(de_arr, 0, sizeof(devfs_handle_t) * MAX_DRIVES);
-
-	flags = kmalloc (sizeof(char) * MAX_DRIVES, GFP_KERNEL);
-	if (!flags)
-		goto err_kmalloc_gd_flags;
-	memset(flags, 0, sizeof(char) * MAX_DRIVES);
-
-	names = kmalloc (4 * MAX_DRIVES, GFP_KERNEL);
-	if (!names)
-		goto err_kmalloc_gd_names;
-	memset(names, 0, 4 * MAX_DRIVES);
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		gd[unit].part = part + (unit << PARTN_BITS);
-		gd[unit].de_arr = de_arr + unit;
-		gd[unit].flags = flags + unit;
-		ch->drives[unit].part = gd[unit].part;
-		gd[unit].major	= ch->major;
-		gd[unit].first_minor = unit << PARTN_BITS;
-		sprintf(names + 4*unit, "hd%c", 'a'+ch->index*MAX_DRIVES+unit);
-		gd[unit].major_name = names + 4*unit;
-		gd[unit].minor_shift = PARTN_BITS;
-		gd[unit].nr_real = 1;
-		gd[unit].fops = ide_fops;
-		ch->gd[unit] = gd + unit;
-		add_gendisk(gd + unit);
-	}
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		char name[80];
-
-		ch->drives[unit].dn = ((ch->unit ? 2 : 0) + unit);
-		sprintf(name, "host%d/bus%d/target%d/lun%d",
-			ch->index, ch->unit, unit, ch->drives[unit].lun);
-		if (ch->drives[unit].present)
-			ch->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-	}
-
-	blk_dev[ch->major].data = ch;
-	blk_dev[ch->major].queue = ata_get_queue;
-
-	/* All went well, flag this channel entry as valid again. */
-	ch->present = 1;
-
-	return;
-
-err_kmalloc_gd_names:
-	kfree(names);
-err_kmalloc_gd_flags:
-	kfree(de_arr);
-err_kmalloc_gd_de_arr:
-	kfree(part);
-err_kmalloc_gd_part:
-	kfree(gd);
-err_kmalloc_gd:
-	printk(KERN_CRIT "(%s) Out of memory\n", __FUNCTION__);
-}
-
-/*
- * FIXME: consider moving this to main.c, since this is the only place where
- * it's used.
- *
- * Probe only for drives on channes which are not already present.
- */
-int ideprobe_init(void)
-{
-	unsigned int i;
-	int probe[MAX_HWIFS];
-
-	for (i = 0; i < MAX_HWIFS; ++i)
-		probe[i] = !ide_hwifs[i].present;
-
-	/*
-	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
-	 */
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		if (!probe[i])
-			continue;
-		channel_probe(&ide_hwifs[i]);
-	}
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		if (!probe[i])
-			continue;
-		channel_init(&ide_hwifs[i]);
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(ata_fix_driveid);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(eighty_ninty_three);
-EXPORT_SYMBOL(ide_config_drive_speed);
diff -Nru a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
--- a/drivers/ide/q40ide.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/ide/q40ide.c	Tue Aug 27 12:28:08 2002
@@ -57,7 +57,7 @@
 
 static int q40ide_default_irq(q40ide_ioreg_t base)
 {
-           switch (base) {
+           switch (base) { 
 	            case 0x1f0: return 14;
 		    case 0x170: return 15;
 		    case 0x1e8: return 11;
@@ -66,9 +66,12 @@
 	   }
 }
 
-/*
- *  Probe for Q40 IDE interfaces
- */
+
+
+    /*
+     *  Probe for Q40 IDE interfaces
+     */
+
 void q40ide_init(void)
 {
     int i;
@@ -79,10 +82,10 @@
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
 
-	ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets,
-			(ide_ioreg_t)pcide_bases[i]+0x206,
+	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
+			pcide_bases[i]+0x206, 
 			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw);
+	ide_register_hw(&hw, NULL);
     }
 }
 
diff -Nru a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
--- a/drivers/ide/qd65xx.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/qd65xx.c	Tue Aug 27 12:28:08 2002
@@ -1,25 +1,32 @@
 /*
- *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
  *
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+ */
+
+/*
  *  Version 0.03	Cleaned auto-tune, added probe
  *  Version 0.04	Added second channel tuning
  *  Version 0.05	Enhanced tuning ; added qd6500 support
  *  Version 0.06	Added dos driver's list
- *  Version 0.07	Second channel bug fix
+ *  Version 0.07	Second channel bug fix 
  *
  * QDI QD6500/QD6580 EIDE controller fast support
  *
  * Please set local bus speed using kernel parameter idebus
- *	for example, "idebus=33" stands for 33Mhz VLbus
+ * 	for example, "idebus=33" stands for 33Mhz VLbus
  * To activate controller support, use "ide0=qd65xx"
  * To enable tuning, use "ide0=autotune"
  * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- *
+ */
+
+/*
  * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
  * Samuel Thibault <samuel.thibault@fnac.net>
  */
 
-#include <linux/module.h>
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -27,13 +34,12 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-
+#include <linux/init.h>
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 #include "qd65xx.h"
 
 /*
@@ -79,62 +85,90 @@
  * bit 5 : status, but of what ?
  * bit 6 : always set 1 by dos driver
  * bit 7 : set 1 for non-ATAPI devices on primary port
- *	(maybe read-ahead and post-write buffer ?)
+ * 	(maybe read-ahead and post-write buffer ?)
  */
 
 static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
 
+static void qd_write_reg (byte content, byte reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	OUT_BYTE(content,reg);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+byte __init qd_read_reg (byte reg)
+{
+	unsigned long flags;
+	byte read;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	read = IN_BYTE(reg);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return read;
+}
+
 /*
+ * qd_select:
+ *
  * This routine is invoked from ide.c to prepare for access to a given drive.
  */
 
-static void qd_select(struct ata_device *drive)
+static void qd_select (ide_drive_t *drive)
 {
-	u8 index = (((QD_TIMREG(drive)) & 0x80 ) >> 7) |
-		(QD_TIMREG(drive) & 0x02);
+	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
+			(QD_TIMREG(drive) & 0x02);
 
 	if (timings[index] != QD_TIMING(drive))
-		outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
 }
 
 /*
+ * qd6500_compute_timing
+ *
  * computes the timing value where
- *	lower nibble represents active time,   in count of VLB clocks
- *	upper nibble represents recovery time, in count of VLB clocks
+ * 	lower nibble represents active time,   in count of VLB clocks
+ * 	upper nibble represents recovery time, in count of VLB clocks
  */
 
-static u8 qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time)
+static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
 {
-	u8 active_cycle,recovery_cycle;
+	byte active_cycle,recovery_cycle;
 
-	if (system_bus_speed <= 33333) {
-		active_cycle =   9  - IDE_IN(active_time   * system_bus_speed / 1000000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 0, 15);
+	if (ide_system_bus_speed()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
 	} else {
-		active_cycle =   8  - IDE_IN(active_time   * system_bus_speed / 1000000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 3, 18);
+		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
 	}
 
 	return((recovery_cycle<<4) | 0x08 | active_cycle);
 }
 
 /*
+ * qd6580_compute_timing
+ *
  * idem for qd6580
  */
 
-static u8 qd6580_compute_timing(int active_time, int recovery_time)
+static byte qd6580_compute_timing (int active_time, int recovery_time)
 {
-	u8 active_cycle   = 17 - IDE_IN(active_time   * system_bus_speed / 1000000 + 1, 2, 17);
-	u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 2, 15);
+	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
+	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
 
-	return (recovery_cycle<<4) | active_cycle;
+	return((recovery_cycle<<4) | active_cycle);
 }
 
 /*
+ * qd_find_disk_type
+ *
  * tries to find timing from dos driver's table
  */
 
-static int qd_find_disk_type(struct ata_device *drive,
+static int qd_find_disk_type (ide_drive_t *drive,
 		int *active_time, int *recovery_time)
 {
 	struct qd65xx_timing_s *p;
@@ -142,10 +176,12 @@
 
 	if (!*drive->id->model) return 0;
 
-	strncpy(model,drive->id->model, 40);
+	strncpy(model,drive->id->model,40);
+	ide_fixstring(model,40,1); /* byte-swap */
+
 	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset, 4)) {
-			printk(KERN_DEBUG "%s: listed !\n", drive->name);
+		if (!strncmp(p->model, model+p->offset,4)) {
+			printk(KERN_DEBUG "%s: listed !\n",drive->name);
 			*active_time = p->active;
 			*recovery_time = p->recovery;
 			return 1;
@@ -155,10 +191,12 @@
 }
 
 /*
+ * qd_timing_ok:
+ *
  * check whether timings don't conflict
  */
 
-static int qd_timing_ok(struct ata_device drives[])
+static int qd_timing_ok (ide_drive_t drives[])
 {
 	return (IDE_IMPLY(drives[0].present && drives[1].present,
 			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
@@ -167,12 +205,14 @@
 }
 
 /*
+ * qd_set_timing:
+ *
  * records the timing, and enables selectproc as needed
  */
 
-static void qd_set_timing(struct ata_device *drive, u8 timing)
+static void qd_set_timing (ide_drive_t *drive, byte timing)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 
 	drive->drive_data &= 0xff00;
 	drive->drive_data |= timing;
@@ -182,91 +222,101 @@
 	} else
 		hwif->selectproc = &qd_select;
 
-	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
 }
 
-static void qd6500_tune_drive(struct ata_device *drive, u8 pio)
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
 {
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
-	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
 		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
 		&& drive->id->eide_pio >= 240) {
 
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name, drive->id->tPIO);
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+				drive->id->tPIO);
 		active_time = 110;
 		recovery_time = drive->id->eide_pio - 120;
 	}
 
-	qd_set_timing(drive, qd6500_compute_timing(drive->channel, active_time, recovery_time));
+	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
 }
 
-static void qd6580_tune_drive(struct ata_device *drive, u8 pio)
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
 {
-	struct ata_timing *t;
-	int base = drive->channel->select_data;
+	ide_pio_data_t d;
+	int base = HWIF(drive)->select_data;
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
-	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
-
-		if (pio == 255)
-			pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-		else
-			pio = XFER_PIO_0 + min_t(u8, pio, 4);
-
-		t = ata_timing_data(pio);
+	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
+		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+		pio = IDE_MIN(pio,4);
 
 		switch (pio) {
 			case 0: break;
 			case 3:
-				if (t->cycle >= 110) {
+				if (d.cycle_time >= 110) {
 					active_time = 86;
-					recovery_time = t->cycle - 102;
+					recovery_time = d.cycle_time-102;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
 			case 4:
-				if (t->cycle >= 69) {
+				if (d.cycle_time >= 69) {
 					active_time = 70;
-					recovery_time = t->cycle - 61;
+					recovery_time = d.cycle_time-61;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
 			default:
-				if (t->cycle >= 180) {
+				if (d.cycle_time >= 180) {
 					active_time = 110;
-					recovery_time = t->cycle - 120;
+					recovery_time = d.cycle_time - 120;
 				} else {
-					active_time = t->active;
-					recovery_time = t->cycle - active_time;
+					active_time = ide_pio_timings[pio].active_time;
+					recovery_time = d.cycle_time
+							-active_time;
 				}
 		}
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name, pio - XFER_PIO_0);
+		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
 	}
 
-	if (!drive->channel->unit && drive->type != ATA_DISK) {
-		outb(0x5f, QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n", drive->name, drive->channel->name);
+	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+		qd_write_reg(0x5f,QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
 	}
 
-	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
 }
 
 /*
+ * qd_testreg
+ *
  * tests if the given port is a register
  */
 
 static int __init qd_testreg(int port)
 {
-	u8 savereg;
-	u8 readreg;
+	byte savereg;
+	byte readreg;
+	unsigned long flags;
 
+	spin_lock_irqsave(&ide_lock, flags);
 	savereg = inb_p(port);
-	outb_p(QD_TESTVAL, port);	/* safe value */
+	outb_p(QD_TESTVAL,port);	/* safe value */
 	readreg = inb_p(port);
-	outb(savereg, port);
+	OUT_BYTE(savereg,port);
+	spin_unlock_irqrestore(&ide_lock, flags);
 
 	if (savereg == QD_TESTVAL) {
 		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
@@ -279,115 +329,110 @@
 }
 
 /*
- * called to setup an ata channel : adjusts attributes & links for tuning
- */
-
-void __init qd_setup(int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (struct ata_device *, u8 pio))
-{
-	struct ata_channel *hwif = &ide_hwifs[unit];
-
-	hwif->chipset = ide_qd65xx;
-	hwif->unit = unit;
-	hwif->select_data = base;
-	hwif->config_data = config;
-	hwif->drives[0].drive_data = data0;
-	hwif->drives[1].drive_data = data1;
-	hwif->io_32bit = 1;
-	hwif->tuneproc = tuneproc;
-}
-
-/*
- * called to unsetup an ata channel : back to default values, unlinks tuning
- */
-void __init qd_unsetup(int unit) {
-	struct ata_channel *hwif = &ide_hwifs[unit];
-	u8 config = hwif->config_data;
-	int base = hwif->select_data;
-	void *tuneproc = (void *) hwif->tuneproc;
-
-	if (!(hwif->chipset == ide_qd65xx)) return;
-
-	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
-
-	hwif->selectproc = NULL;
-	hwif->tuneproc = NULL;
-
-	if (tuneproc == (void *) qd6500_tune_drive) {
-		// will do it for both
-		outb(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-	} else if (tuneproc == (void *) qd6580_tune_drive) {
-		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
-			outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-			outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
-		} else {
-			outb(unit ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-		}
-	} else {
-		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
-		printk(KERN_WARNING "keeping settings !\n");
-	}
-}
-
-/*
+ * probe:
+ *
  * looks at the specified baseport, and if qd found, registers & initialises it
  * return 1 if another qd may be probed
  */
 
-int __init qd_probe(int base)
+int __init probe (int base)
 {
-	u8 config;
-	int unit;
+	byte config;
+	byte index;
 
-	config = inb(QD_CONFIG_PORT);
+	config = qd_read_reg(QD_CONFIG_PORT);
 
 	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
 
-	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+	index = ! (config & QD_CONFIG_IDE_BASEPORT);
 
 	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		if (qd_testreg(base)) return 1;		/* bad register */
+		ide_hwif_t *hwif = &ide_hwifs[index];
 
-		/* qd6500 found */
+		if (qd_testreg(base)) return 1;		/* bad register */
 
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n", ide_hwifs[unit].name, base);
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", config, QD_ID3);
+			/* qd6500 found */
 
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+			ide_hwifs[index].name, base);
+		
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+			config, QD_ID3);
+		
 		if (config & QD_CONFIG_DISABLED) {
 			printk(KERN_WARNING "qd6500 is disabled !\n");
 			return 1;
 		}
 
-		qd_setup(unit, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA, &qd6500_tune_drive);
+		hwif->chipset = ide_qd65xx;
+		hwif->select_data = base;
+		hwif->config_data = config;
+		hwif->drives[0].drive_data =
+		hwif->drives[1].drive_data = QD6500_DEF_DATA;
+		hwif->drives[0].io_32bit =
+		hwif->drives[1].io_32bit = 1;
+		hwif->tuneproc = &qd6500_tune_drive;
 		return 1;
 	}
 
 	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-		u8 control;
+
+		byte control;
 
 		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
 			/* bad registers */
 
-		/* qd6580 found */
+			/* qd6580 found */
 
-		control = inb(QD_CONTROL_PORT);
+		control = qd_read_reg(QD_CONTROL_PORT);
 
 		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", config, control, QD_ID3);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+			config, control, QD_ID3);
 
 		if (control & QD_CONTR_SEC_DISABLED) {
+			ide_hwif_t *hwif = &ide_hwifs[index];
+
 			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n", ide_hwifs[unit].name);
-			qd_setup(unit, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA2, &qd6580_tune_drive);
-			outb(QD_DEF_CONTR, QD_CONTROL_PORT);
+			printk(KERN_INFO "%s: qd6580: single IDE board\n",
+					ide_hwifs[index].name);
+
+			hwif->chipset = ide_qd65xx;
+			hwif->select_data = base;
+			hwif->config_data = config | (control <<8);
+			hwif->drives[0].drive_data =
+			hwif->drives[1].drive_data = QD6580_DEF_DATA;
+			hwif->drives[0].io_32bit =
+			hwif->drives[1].io_32bit = 1;
+			hwif->tuneproc = &qd6580_tune_drive;
+
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
 			return 1;
 		} else {
+			int i,j;
 			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n", ide_hwifs[0].name, ide_hwifs[1].name);
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+					ide_hwifs[0].name,ide_hwifs[1].name);
+
+			for (i=0;i<2;i++) {
 
-			qd_setup(ATA_PRIMARY, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA, &qd6580_tune_drive);
-			qd_setup(ATA_SECONDARY, base, config | (control << 8), QD6580_DEF_DATA2, QD6580_DEF_DATA2, &qd6580_tune_drive);
-			outb(QD_DEF_CONTR, QD_CONTROL_PORT);
+				ide_hwifs[i].chipset = ide_qd65xx;
+				ide_hwifs[i].mate = &ide_hwifs[i^1];
+				ide_hwifs[i].channel = i;
+
+				ide_hwifs[i].select_data = base;
+				ide_hwifs[i].config_data = config | (control <<8);
+				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
+
+				for (j=0;j<2;j++) {
+					ide_hwifs[i].drives[j].drive_data =
+					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
+					ide_hwifs[i].drives[j].io_32bit = 1;
+				}
+			}
+
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
 			return 0; /* no other qd65xx possible */
 		}
@@ -396,34 +441,13 @@
 	return 1;
 }
 
-#ifndef MODULE
 /*
- * called by ide.c when parsing command line
+ * init_qd65xx:
+ *
+ * called at the very beginning of initialization ; should just probe and link
  */
 
-void __init init_qd65xx(void)
-{
-	if (qd_probe(0x30)) qd_probe(0xb0);
-}
-
-#else
-
-MODULE_AUTHOR("Samuel Thibault");
-MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
-MODULE_LICENSE("GPL");
-
-int __init qd65xx_mod_init(void)
-{
-	if (qd_probe(0x30)) qd_probe(0xb0);
-	if (ide_hwifs[0].chipset != ide_qd65xx && ide_hwifs[1].chipset != ide_qd65xx) return -ENODEV;
-	return 0;
-}
-module_init(qd65xx_mod_init);
-
-void __init qd65xx_mod_exit(void)
+void __init init_qd65xx (void)
 {
-	qd_unsetup(ATA_PRIMARY);
-	qd_unsetup(ATA_SECONDARY);
+	if (probe(0x30)) probe(0xb0);
 }
-module_exit(qd65xx_mod_exit);
-#endif
diff -Nru a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
--- a/drivers/ide/qd65xx.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/qd65xx.h	Tue Aug 27 12:28:08 2002
@@ -34,8 +34,8 @@
 #define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
 #define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
 
-#define QD_TIMING(drive)	(u8)(((drive)->drive_data) & 0x00ff)
-#define QD_TIMREG(drive)	(u8)((((drive)->drive_data) & 0xff00) >> 8)
+#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
 
 #define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
 #define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
diff -Nru a/drivers/ide/quirks.c b/drivers/ide/quirks.c
--- a/drivers/ide/quirks.c	Tue Aug 27 12:27:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,232 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
- *
- *  Copyright (c) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- *  Copyright (c) 1995-1998  Mark Lord
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-/*
- *  Just the black and white list handling for BM-DMA operation.
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-struct drive_list_entry drive_whitelist[] = {
-	{ "Micropolis 2112A", NULL },
-	{ "CONNER CTMA 4000", NULL },
-	{ "CONNER CTT8000-A", NULL },
-	{ "ST34342A", NULL },
-	{ NULL, NULL }
-};
-
-struct drive_list_entry drive_blacklist[] = {
-
-	{ "WDC AC11000H", NULL },
-	{ "WDC AC22100H", NULL },
-	{ "WDC AC32500H", NULL },
-	{ "WDC AC33100H", NULL },
-	{ "WDC AC31600H", NULL },
-	{ "WDC AC32100H", "24.09P07" },
-	{ "WDC AC23200L", "21.10N21" },
-	{ "Compaq CRD-8241B", NULL },
-	{ "CRD-8400B", NULL },
-	{ "CRD-8480B", NULL },
-	{ "CRD-8480C", NULL },
-	{ "CRD-8482B", NULL },
-	{ "CRD-84", NULL },
-	{ "SanDisk SDP3B", NULL },
-	{ "SanDisk SDP3B-64", NULL },
-	{ "SANYO CD-ROM CRD", NULL },
-	{ "HITACHI CDR-8", NULL },
-	{ "HITACHI CDR-8335", NULL },
-	{ "HITACHI CDR-8435", NULL },
-	{ "Toshiba CD-ROM XM-6202B", NULL },
-	{ "CD-532E-A", NULL },
-	{ "E-IDE CD-ROM CR-840", NULL },
-	{ "CD-ROM Drive/F5A", NULL },
-	{ "RICOH CD-R/RW MP7083A", NULL },
-	{ "WPI CDD-820", NULL },
-	{ "SAMSUNG CD-ROM SC-148C", NULL },
-	{ "SAMSUNG CD-ROM SC-148F", NULL },
-	{ "SAMSUNG CD-ROM SC", NULL },
-	{ "SanDisk SDP3B-64", NULL },
-	{ "SAMSUNG CD-ROM SN-124", NULL },
-	{ "PLEXTOR CD-R PX-W8432T", NULL },
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL },
-	{ "_NEC DV5800A", NULL },
-	{ NULL,	NULL }
-
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((drive_table->id_firmware && !strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!drive_table->id_firmware)))
-			return 1;
-	return 0;
-}
-
-#else
-
-/*
- * good_dma_drives() lists the model names (from "hdparm -i")
- * of drives which do not support mode2 DMA but which are
- * known to work fine with this interface under Linux.
- */
-const char *good_dma_drives[] = {"Micropolis 2112A",
-				 "CONNER CTMA 4000",
-				 "CONNER CTT8000-A",
-				 "ST34342A",	/* for Sun Ultra */
-				 NULL};
-
-/*
- * bad_dma_drives() lists the model names (from "hdparm -i")
- * of drives which supposedly support (U)DMA but which are
- * known to corrupt data with this interface under Linux.
- *
- * This is an empirical list. Its generated from bug reports. That means
- * while it reflects actual problem distributions it doesn't answer whether
- * the drive or the controller, or cabling, or software, or some combination
- * thereof is the fault. If you don't happen to agree with the kernel's
- * opinion of your drive - use hdparm to turn DMA on.
- */
-const char *bad_dma_drives[] = {"WDC AC11000H",
-				"WDC AC22100H",
-				"WDC AC32100H",
-				"WDC AC32500H",
-				"WDC AC33100H",
-				"WDC AC31600H",
-				NULL};
-
-#endif
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-int check_drive_lists(struct ata_device *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else
-	const char **list;
-
-	if (good_bad) {
-		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++, id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++, id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
-	}
-#endif
-	return 0;
-}
-
-void udma_print(struct ata_device *drive)
-{
-#ifdef CONFIG_ARCH_ACORN
-	printk(", DMA");
-#else
-	struct hd_driveid *id = drive->id;
-	char *str = NULL;
-
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
-		if ((id->dma_ultra >> 15) & 1)
-			str = ", UDMA(mode 7)";	/* UDMA BIOS-enabled! */
-		else
-			str = ", UDMA(133)";	/* UDMA BIOS-enabled! */
-	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-		  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-		if ((id->dma_ultra >> 13) & 1) {
-			str = ", UDMA(100)";	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			str = ", UDMA(66)";	/* UDMA BIOS-enabled! */
-		} else {
-			str = ", UDMA(44)";	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			str = ", UDMA(33)";	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			str = ", UDMA(25)";	/* UDMA BIOS-enabled! */
-		} else {
-			str = ", UDMA(16)";	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4)
-		str = ", (U)DMA";	/* Can be BIOS-enabled! */
-	else
-		str = ", DMA";
-
-	printk(str);
-#endif
-}
-
-/*
- * Drive back/white list handling for UDMA capability:
- */
-
-int udma_black_list(struct ata_device *drive)
-{
-	return check_drive_lists(drive, 0);
-}
-
-int udma_white_list(struct ata_device *drive)
-{
-	return check_drive_lists(drive, 1);
-}
-
-EXPORT_SYMBOL(udma_print);
-EXPORT_SYMBOL(udma_black_list);
-EXPORT_SYMBOL(udma_white_list);
diff -Nru a/drivers/ide/rapide.c b/drivers/ide/rapide.c
--- a/drivers/ide/rapide.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/rapide.c	Tue Aug 27 12:28:08 2002
@@ -41,7 +41,7 @@
 	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
 	hw.irq = ec->irq;
 
-	return ide_register_hw(&hw);
+	return ide_register_hw(&hw, NULL);
 }
 
 int __init rapide_init(void)
diff -Nru a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
--- a/drivers/ide/rz1000.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/ide/rz1000.c	Tue Aug 27 12:28:08 2002
@@ -1,7 +1,10 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
  *
  *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- *
+ */
+
+/*
  *  Principal Author:  mlord@pobox.com (Mark Lord)
  *
  *  See linux/MAINTAINERS for address of current maintainer.
@@ -12,7 +15,9 @@
  *  Dunno if this fixes both ports, or only the primary port (?).
  */
 
-#include <linux/config.h> /* for CONFIG_PCI */
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -22,85 +27,61 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#ifdef CONFIG_PCI
-
-#include "pcihost.h"
+#ifdef CONFIG_BLK_DEV_IDEPCI
 
-static void __init rz1000_init_channel(struct ata_channel *hwif)
+void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
 {
 	unsigned short reg;
 	struct pci_dev *dev = hwif->pci_dev;
 
 	hwif->chipset = ide_rz1000;
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+		printk("%s: disabled chipset read-ahead "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
 	} else {
 		hwif->serialized = 1;
-		hwif->no_unmask = 1;
-		printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk("%s: serialized, disabled unmasking "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
 	}
 }
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_PCTECH,
-		.device = PCI_DEVICE_ID_PCTECH_RZ1000,
-		.init_channel = rz1000_init_channel,
-		.bootable = ON_BOARD
-	},
-	{
-		.vendor = PCI_VENDOR_ID_PCTECH,
-		.device = PCI_DEVICE_ID_PCTECH_RZ1001,
-		.init_channel = rz1000_init_channel,
-		.bootable = ON_BOARD
-	},
-};
-
-int __init init_rz1000(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
-
-        return 0;
-}
-
 #else
 
 static void __init init_rz1000 (struct pci_dev *dev, const char *name)
 {
 	unsigned short reg, h;
 
-	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) && !(reg & PCI_COMMAND_IO)) {
+	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) &&
+	    !(reg & PCI_COMMAND_IO)) {
 		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
 		return;
 	}
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
 		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
 	} else {
 		for (h = 0; h < MAX_HWIFS; ++h) {
-			struct ata_channel *hwif = &ide_hwifs[h];
-			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-			 && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
-			{
+			ide_hwif_t *hwif = &ide_hwifs[h];
+			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 ||
+			     hwif->io_ports[IDE_DATA_OFFSET] == 0x170)  &&
+			    (hwif->chipset == ide_unknown ||
+			     hwif->chipset == ide_generic)) {
 				hwif->chipset = ide_rz1000;
 				hwif->serialized = 1;
 				hwif->drives[0].no_unmask = 1;
 				hwif->drives[1].no_unmask = 1;
 				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->unit = 1;
-				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
+					hwif->channel = 1;
+				printk("%s: serialized, disabled unmasking "
+					"(buggy %s)\n", hwif->name, name);
 			}
 		}
 	}
@@ -111,9 +92,9 @@
 	struct pci_dev *dev = NULL;
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		rz1000_init (dev, "RZ1000");
+		init_rz1000 (dev, "RZ1000");
 	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		rz1000_init (dev, "RZ1001");
+		init_rz1000 (dev, "RZ1001");
 }
 
-#endif
+#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/ide/serverworks.c	Tue Aug 27 12:28:08 2002
@@ -1,8 +1,5 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
- *
- * May be copied or modified under the terms of the GNU General Public License
+/*
+ * linux/drivers/ide/serverworks.c		Version 0.6	05 April 2002
  *
  * Copyright (C) 1998-2000 Michel Aubry
  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -22,61 +19,7 @@
  *         *** The CSB5 does not provide ANY register ***
  *         *** to detect 80-conductor cable presence. ***
  *
- *
- * here's the default lspci:
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP])
- *	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
- *	Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *	Latency: 255
- *	Region 4: I/O ports at c200
- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 01 c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
- *         Subsystem: ServerWorks: Unknown device 0212
- *         Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
- *         Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *         Latency: 64, cache line size 08
- *         Region 0: I/O ports at 01f0
- *         Region 1: I/O ports at 03f4
- *         Region 2: I/O ports at 0170
- *         Region 3: I/O ports at 0374
- *         Region 4: I/O ports at 08b0
- *         Region 5: I/O ports at 1000
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
- * 50: 00 00 00 00 07 00 44 02 0f 04 03 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
+ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
  *
  */
 
@@ -85,66 +28,280 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
+#define DISPLAY_SVWKS_TIMINGS	1
 #undef SVWKS_DEBUG_DRIVE_INFO
 
-static u8 svwks_revision;
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
 
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_MAX_DEVS		2
+static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
+static int n_svwks_devs;
 
-static struct pci_dev *isa_dev;
+static byte svwks_revision = 0;
 
-static int __init svwks_modes_map(struct ata_channel *ch)
+static int svwks_get_info(char *, char **, off_t, int);
+extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	int map = XFER_EPIO | XFER_MWDMA;
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"ServerWorks OSB4/CSB5/CSB6\n");
+
+	for (i = 0; i < n_svwks_devs; i++) {
+		struct pci_dev *dev = svwks_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+		u32 reg40, reg44;
+		u16 reg48, reg56;
+		u8  reg54, c0=0, c1=0;
+
+		pci_read_config_dword(dev, 0x40, &reg40);
+		pci_read_config_dword(dev, 0x44, &reg44);
+		pci_read_config_word(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_word(dev, 0x56, &reg56);
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((unsigned short)bibma + 0x02);
+		c1 = inb_p((unsigned short)bibma + 0x0a);
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+				p += sprintf(p, "\n                            "
+					"ServerWorks CSB6 Chipset (rev %02x)\n",
+					svwks_revision);
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				p += sprintf(p, "\n                            "
+					"ServerWorks CSB5 Chipset (rev %02x)\n",
+					svwks_revision);
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+				p += sprintf(p, "\n                            "
+					"ServerWorks OSB4 Chipset (rev %02x)\n",
+					svwks_revision);
+				break;
+			default:
+				p += sprintf(p, "\n                            "
+					"ServerWorks %04x Chipset (rev %02x)\n",
+					dev->device, svwks_revision);
+				break;
+		}
+
+		p += sprintf(p, "------------------------------- "
+				"General Status "
+				"---------------------------------\n");
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled                         %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s              %s"
+				"             %s               %s\n",
+			(reg54 & 0x01) ? "yes" : "no ",
+			(reg54 & 0x02) ? "yes" : "no ",
+			(reg54 & 0x04) ? "yes" : "no ",
+			(reg54 & 0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg56&0x0005)==0x0005)?"5":
+				((reg56&0x0004)==0x0004)?"4":
+				((reg56&0x0003)==0x0003)?"3":
+				((reg56&0x0002)==0x0002)?"2":
+				((reg56&0x0001)==0x0001)?"1":
+				((reg56&0x000F))?"?":"0",
+			((reg56&0x0050)==0x0050)?"5":
+				((reg56&0x0040)==0x0040)?"4":
+				((reg56&0x0030)==0x0030)?"3":
+				((reg56&0x0020)==0x0020)?"2":
+				((reg56&0x0010)==0x0010)?"1":
+				((reg56&0x00F0))?"?":"0",
+			((reg56&0x0500)==0x0500)?"5":
+				((reg56&0x0400)==0x0400)?"4":
+				((reg56&0x0300)==0x0300)?"3":
+				((reg56&0x0200)==0x0200)?"2":
+				((reg56&0x0100)==0x0100)?"1":
+				((reg56&0x0F00))?"?":"0",
+			((reg56&0x5000)==0x5000)?"5":
+				((reg56&0x4000)==0x4000)?"4":
+				((reg56&0x3000)==0x3000)?"3":
+				((reg56&0x2000)==0x2000)?"2":
+				((reg56&0x1000)==0x1000)?"1":
+				((reg56&0xF000))?"?":"0");
+		p += sprintf(p, "DMA enabled:    %s                %s"
+				"               %s                 %s\n",
+			((reg44&0x00002000)==0x00002000)?"2":
+				((reg44&0x00002100)==0x00002100)?"1":
+				((reg44&0x00007700)==0x00007700)?"0":
+				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
+			((reg44&0x00000020)==0x00000020)?"2":
+				((reg44&0x00000021)==0x00000021)?"1":
+				((reg44&0x00000077)==0x00000077)?"0":
+				((reg44&0x000000FF)==0x000000FF)?"X":"?",
+			((reg44&0x20000000)==0x20000000)?"2":
+				((reg44&0x21000000)==0x21000000)?"1":
+				((reg44&0x77000000)==0x77000000)?"0":
+				((reg44&0xFF000000)==0xFF000000)?"X":"?",
+			((reg44&0x00200000)==0x00200000)?"2":
+				((reg44&0x00210000)==0x00210000)?"1":
+				((reg44&0x00770000)==0x00770000)?"0":
+				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+
+		p += sprintf(p, "PIO  enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg40&0x00002000)==0x00002000)?"4":
+				((reg40&0x00002200)==0x00002200)?"3":
+				((reg40&0x00003400)==0x00003400)?"2":
+				((reg40&0x00004700)==0x00004700)?"1":
+				((reg40&0x00005D00)==0x00005D00)?"0":"?",
+			((reg40&0x00000020)==0x00000020)?"4":
+				((reg40&0x00000022)==0x00000022)?"3":
+				((reg40&0x00000034)==0x00000034)?"2":
+				((reg40&0x00000047)==0x00000047)?"1":
+				((reg40&0x0000005D)==0x0000005D)?"0":"?",
+			((reg40&0x20000000)==0x20000000)?"4":
+				((reg40&0x22000000)==0x22000000)?"3":
+				((reg40&0x34000000)==0x34000000)?"2":
+				((reg40&0x47000000)==0x47000000)?"1":
+				((reg40&0x5D000000)==0x5D000000)?"0":"?",
+			((reg40&0x00200000)==0x00200000)?"4":
+				((reg40&0x00220000)==0x00220000)?"3":
+				((reg40&0x00340000)==0x00340000)?"2":
+				((reg40&0x00470000)==0x00470000)?"1":
+				((reg40&0x005D0000)==0x005D0000)?"0":"?");
 
-	switch(ch->pci_dev->device) {
-		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			if (svwks_revision >= SVWKS_CSB5_REVISION_NEW)
-				map |= XFER_UDMA_100;
-			map |= XFER_UDMA_66;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
-			map |= XFER_UDMA;
-			break;
 	}
+	p += sprintf(p, "\n");
 
-	return map;
+	return p-buffer;	 /* => must be less than 4k! */
 }
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+
+#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+byte svwks_proc = 0;
+
+static struct pci_dev *isa_dev;
 
-static int svwks_tune_chipset(struct ata_device *drive, u8 speed)
+static byte svwks_ratemask (ide_drive_t *drive)
 {
-	static u8 dma_modes[]	= { 0x77, 0x21, 0x20 };
-	static u8 pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	struct pci_dev *dev     = HWIF(drive)->pci_dev;
+	byte mode		= 0;
 
-	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev = ch->pci_dev;
-	u8 unit = drive->select.b.unit & 0x01;
-	u8 drive_pci, drive_pci2;
-	u8 drive_pci3 = ch->unit ? 0x57 : 0x56;
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		u32 reg = 0;
+		mode &= ~0x01;
+		if (isa_dev)
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+		if ((reg & 0x00004000) == 0x00004000)
+			mode |= 0x01;
+	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+		mode |= 0x01;
+	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+		u8 btr =0;
+		pci_read_config_byte(dev, 0x5A, &btr);
+		mode |= btr;
+		if (!eighty_ninty_three(drive))
+			mode &= ~0x02;
+	}
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		mode = 0x02;
+	mode &= ~0xFC;
+	return (mode);
+}
+
+static byte svwks_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = svwks_ratemask(drive);
+	
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
 
-	u8 ultra_enable, ultra_timing, dma_timing, pio_timing;
-	u16 csb5_pio;
+static byte svwks_csb_check (struct pci_dev *dev)
+{
+	switch (dev->device) {
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
+	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte unit		= (drive->select.b.unit & 0x01);
+	byte csb5		= svwks_csb_check(dev);
+
+	byte drive_pci		= 0x00;
+	byte drive_pci2		= 0x00;
+	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
+
+	byte ultra_enable	= 0x00;
+	byte ultra_timing	= 0x00;
+	byte dma_timing		= 0x00;
+	byte pio_timing		= 0x00;
+	unsigned short csb5_pio	= 0x00;
 
-	u8 pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+	byte pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
+	byte speed	= svwks_ratefilter(drive, xferspeed);
 
         switch (drive->dn) {
-		case 0: drive_pci = 0x41; break;
-		case 1: drive_pci = 0x40; break;
-		case 2: drive_pci = 0x43; break;
-		case 3: drive_pci = 0x42; break;
+		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
+		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
+		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
+		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
 		default:
 			return -1;
 	}
-	drive_pci2 = drive_pci + 4;
 
 	pci_read_config_byte(dev, drive_pci, &pio_timing);
 	pci_read_config_byte(dev, drive_pci2, &dma_timing);
@@ -152,11 +309,6 @@
 	pci_read_config_word(dev, 0x4A, &csb5_pio);
 	pci_read_config_byte(dev, 0x54, &ultra_enable);
 
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
 	pio_timing	&= ~0xFF;
 	dma_timing	&= ~0xFF;
 	ultra_timing	&= ~(0x0F << (4*unit));
@@ -173,7 +325,6 @@
 			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
 			break;
 
-		/* FIXME: check SWDMA modes  --bkz */
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
@@ -192,90 +343,239 @@
 			pio_timing   |= pio_modes[pio];
 			csb5_pio     |= (pio << (4*drive->dn));
 			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((speed - XFER_UDMA_0) << (4*unit));
+			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
 #endif
 		default:
 			break;
 	}
 
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-#if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %02x drive%d\n", drive->name, speed, drive->dn);
-#endif
-
 	pci_write_config_byte(dev, drive_pci, pio_timing);
-
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+	if (csb5)
 		pci_write_config_word(dev, 0x4A, csb5_pio);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	pci_write_config_byte(dev, drive_pci2, dma_timing);
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	return ide_config_drive_speed(drive, speed);
+	return (ide_config_drive_speed(drive, speed));
 }
 
-/* FIXME: pio == 255 -> ata_best_pio_mode(drive)  --bkz */
-static void svwks_tune_drive(struct ata_device *drive, u8 pio)
+static void config_chipset_for_pio (ide_drive_t *drive)
 {
-	(void) svwks_tune_chipset(drive, XFER_PIO_0 + min_t(u8, pio, 4));
+	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+	unsigned short xfer_pio = drive->id->eide_pio_modes;
+	byte timing, speed, pio;
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0)
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	else
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 :
+			   (drive->id->tPIO & 2) ? 0x02 :
+			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+	drive->current_speed = speed;
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int svwks_udma_stop(struct ata_device *drive)
+static void svwks_tune_drive (ide_drive_t *drive, byte pio)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
+	byte speed;
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4;break;
+		case 3:		speed = XFER_PIO_3;break;
+		case 2:		speed = XFER_PIO_2;break;
+		case 1:		speed = XFER_PIO_1;break;
+		default:	speed = XFER_PIO_0;break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+}
 
-	if(inb(dma_base+0x02)&1)
-	{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte mode		= svwks_ratemask(drive);
+	byte speed, dma		= 1;
+
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		mode = 0;
+
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
 #if 0
-		int i;
-		printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
-		for(i=0;i<10;i++)
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+#endif
+		default:
+			speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+			dma = 0;
+			break;
+	}
+
+	(void) svwks_tune_chipset(drive, speed);
+
+//	return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
+	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x003F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		config_chipset_for_pio(drive);
+		//	HWIF(drive)->tuneproc(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_end:
 		{
-			if(!(inb(dma_base+0x02)&1))
+			ide_hwif_t *hwif		= HWIF(drive);
+			unsigned long dma_base		= hwif->dma_base;
+	
+			if(IN_BYTE(dma_base+0x02)&1)
 			{
-				printk(KERN_ERR "OSB4 now finished.\n");
-				break;
+#if 0		
+				int i;
+				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
+				for(i=0;i<10;i++)
+				{
+					if(!(IN_BYTE(dma_base+0x02)&1))
+					{
+						printk(KERN_ERR "OSB4 now finished.\n");
+						break;
+					}
+					udelay(5);
+				}
+#endif		
+				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+#if 0		
+				/* Panic might sys_sync -> death by corrupt disk */
+				panic("OSB4: continuing might cause disk corruption.\n");
+#else
+				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+				while(1)
+					cpu_relax();
+#endif				
 			}
-			udelay(5);
+			/* and drop through */
 		}
-#endif
-		printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
-		printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
-		printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
-#if 0
-		/* Panic might sys_sync -> death by corrupt disk */
-		panic("OSB4: continuing might cause disk corruption.\n");
-#else
-		printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
-		while(1)
-			cpu_relax();
-#endif
+		default:
+			break;
 	}
-
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-	udma_destroy_table(ch);			/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
 }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-static unsigned int __init svwks_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
 {
 	unsigned int reg;
-	u8 btr;
+	byte btr;
 
 	/* save revision id to determine DMA capability */
 	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
@@ -295,24 +595,79 @@
 		}
 	}
 
-	/* setup CSB5 : South Bridge and IDE */
-	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) {
+		/* Third Channel Test */
+		if (!(PCI_FUNC(dev->devfn) & 1)) {
+#if 1
+			struct pci_dev * findev = NULL;
+			unsigned int reg4c = 0;
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+			if (findev) {
+				pci_read_config_dword(findev, 0x4C, &reg4c);
+				reg4c &= ~0x000007FF;
+				reg4c |=  0x00000040;
+				reg4c |=  0x00000020;
+				pci_write_config_dword(findev, 0x4C, reg4c);
+			}
+#endif
+			outb_p(0x06, 0x0c00);
+			dev->irq = inb_p(0x0c01);
+#if 1
+			/* WE need to figure out how to get the correct one */
+			printk("%s: interrupt %d\n", name, dev->irq);
+			if (dev->irq != 0x0B)
+				dev->irq = 0x0B;
+#endif
+		} else {
+			/*
+			 * This is a device pin issue on CSB6.
+			 * Since there will be a future raid mode,
+			 * early versions of the chipset require the
+			 * interrupt pin to be set, and it is a compatablity
+			 * mode issue.
+			 */
+			dev->irq = 0;
+		}
+		pci_write_config_dword(dev, 0x40, 0x99999999);
+		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
 		/* setup the UDMA Control register
 		 *
 		 * 1. clear bit 6 to enable DMA
 		 * 2. enable DMA modes with bits 0-1
-		 *      00 : legacy
-		 *      01 : udma2
-		 *      10 : udma2/udma4
-		 *      11 : udma2/udma4/udma5
+		 * 	00 : legacy
+		 * 	01 : udma2
+		 * 	10 : udma2/udma4
+		 * 	11 : udma2/udma4/udma5
 		 */
 		pci_read_config_byte(dev, 0x5A, &btr);
 		btr &= ~0x40;
-		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		if (!(PCI_FUNC(dev->devfn) & 1))
+			btr |= 0x2;
+		else
+			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
 		pci_write_config_byte(dev, 0x5A, btr);
 	}
 
-	return 0;
+	svwks_devs[n_svwks_devs++] = dev;
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!svwks_proc) {
+		svwks_proc = 1;
+		svwks_display_info = &svwks_get_info;
+	}
+#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+
+	return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+//	struct pci_dev *dev = hwif->pci_dev;
+//	return 0;
+	return 1;
 }
 
 /* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
@@ -322,13 +677,14 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-static unsigned int __init ata66_svwks_dell(struct ata_channel *hwif)
+static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
 	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
 	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
-		return ((1 << (hwif->unit + 14)) &
+		return ((1 << (hwif->channel + 14)) &
 			dev->subsystem_device) ? 1 : 0;
 	return 0;
 }
@@ -339,20 +695,25 @@
  *
  * WARNING: this only works on Alpine hardware!
  */
-static unsigned int __init ata66_svwks_cobalt(struct ata_channel *hwif)
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
 	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->unit + 14)) &
+		return ((1 << (hwif->channel + 14)) &
 			dev->subsystem_device) ? 1 : 0;
 	return 0;
 }
 
-static unsigned int __init svwks_ata66_check(struct ata_channel *hwif)
+unsigned int __init ata66_svwks (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 
+	/* Server Works */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+		return ata66_svwks_svwks (hwif);
+	
 	/* Dell PowerEdge */
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 		return ata66_svwks_dell (hwif);
@@ -364,59 +725,65 @@
 	return 0;
 }
 
-static void __init ide_init_svwks(struct ata_channel *hwif)
+void __init ide_init_svwks (ide_hwif_t *hwif)
 {
 	if (!hwif->irq)
-		hwif->irq = hwif->unit ? 15 : 14;
-
-	hwif->udma_four = svwks_ata66_check(hwif);
+		hwif->irq = hwif->channel ? 15 : 14;
 
 	hwif->tuneproc = &svwks_tune_drive;
 	hwif->speedproc = &svwks_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-#else
-	if (hwif->dma_base) {
-		hwif->modes_map = svwks_modes_map(hwif);
-		hwif->udma_setup = udma_generic_setup;
-		hwif->udma_stop = svwks_udma_stop;
-		hwif->highmem = 1;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->dmaproc = &svwks_dmaproc;
+# ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+# endif /* CONFIG_IDEDMA_AUTO */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+void __init ide_dmacapable_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+		return;
+#if 0
+	if (svwks_revision == (SVWKS_CSB5_REVISION_NEW + 1)) {
+		if (hwif->mate && hwif->mate->dma_base) {
+	                dmabase = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+		} else {
+			dmabase = pci_resource_start(dev, 4);
+			if (!dmabase) {
+				printk("%s: dma_base is invalid (0x%04lx)\n",
+					hwif->name, dmabase);
+				dmabase = 0;
+			}
+		}
 	}
 #endif
+	ide_setup_dma(hwif, dmabase, 8);
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-        {
-		.vendor = PCI_VENDOR_ID_SERVERWORKS,
-		.device = PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
-		.init_chipset = svwks_init_chipset,
-		.init_channel = ide_init_svwks,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_DMA
-	},
-	{
-		.vendor = PCI_VENDOR_ID_SERVERWORKS,
-		.device = PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
-		.init_chipset = svwks_init_chipset,
-		.init_channel = ide_init_svwks,
-		.bootable = ON_BOARD,
-		.flags = ATA_F_SIMPLEX
-	},
-};
-
-int __init init_svwks(void)
+void __init fixup_device_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
+	if (!(PCI_FUNC(dev->devfn) & 1)) {
+		d->bootable = NEVER_BOARD;
+	}
 
-        return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
+ 
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/sis5513.c	Tue Aug 27 12:28:08 2002
@@ -12,9 +12,8 @@
  * Daniela Engert	: for initial ATA100 advices and numerous others.
  * John Fremlin, Manfred Spraul :
  *			  for checking code correctness, providing patches.
- */
-
-/*
+ *
+ *
  * Original tests and design on the SiS620/5513 chipset.
  * ATA100 tests and design on the SiS735/5513 chipset.
  * ATA16/33 design from specs
@@ -24,7 +23,8 @@
  * TODO:
  *	- Get ridden of SisHostChipInfo[] completness dependancy.
  *	- Get ATA-133 datasheets, implement ATA-133 init code.
- *	- Are there pre-ATA_16 SiS chips ? -> tune init code for them
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
  *	  or remove ATA_00 define
  *	- More checks in the config registers (force values instead of
  *	  relying on the BIOS setting them correctly).
@@ -40,25 +40,25 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide_modes.h"
 
 /* When DEBUG is defined it outputs initial PCI config register
-   values and changes made to them by the driver */
+   values and changes made to them by the driver */   
 // #define DEBUG
 /* When BROKEN_LEVEL is defined it limits the DMA mode
    at boot time to its value */
 // #define BROKEN_LEVEL XFER_SW_DMA_0
+#define DISPLAY_SIS_TIMINGS
 
 /* Miscellaneaous flags */
 #define SIS5513_LATENCY		0x01
@@ -69,13 +69,13 @@
 #define ATA_16		0x01
 #define ATA_33		0x02
 #define ATA_66		0x03
-#define ATA_100a	0x04	// SiS730 is ATA100 with ATA66 layout
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
 #define ATA_100		0x05
 #define ATA_133		0x06
-
 /* 2/ variable holding the controller chipset family value */
 static unsigned char chipset_family;
 
+
 /*
  * Debug code: following IDE config registers' changes
  */
@@ -84,7 +84,7 @@
    Fewer might be used depending on the actual chipset */
 static unsigned char ide_regs_copy[0x58];
 
-static u8 sis5513_max_config_register(void) {
+static byte sis5513_max_config_register(void) {
 	switch(chipset_family) {
 		case ATA_00:
 		case ATA_16:	return 0x4f;
@@ -100,9 +100,9 @@
 /* Read config registers, print differences from previous read */
 static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
 	int i;
-	u8 reg_val;
-	u8 changed = 0;
-	u8 max = sis5513_max_config_register();
+	byte reg_val;
+	byte changed=0;
+	byte max = sis5513_max_config_register();
 
 	printk("SIS5513: %s, changed registers:\n", info);
 	for(i=0; i<=max; i++) {
@@ -121,10 +121,9 @@
 }
 
 /* Load config registers, no printing */
-static void sis5513_load_registers(struct pci_dev* dev)
-{
+static void sis5513_load_registers(struct pci_dev* dev) {
 	int i;
-	u8 max = sis5513_max_config_register();
+	byte max = sis5513_max_config_register();
 
 	for(i=0; i<=max; i++) {
 		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
@@ -132,15 +131,14 @@
 }
 
 /* Print a register */
-static void sis5513_print_register(int reg)
-{
+static void sis5513_print_register(int reg) {
 	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
 }
 
 /* Print valuable registers */
 static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
 	int i;
-	u8 max = sis5513_max_config_register();
+	byte max = sis5513_max_config_register();
 
 	sis5513_load_registers(dev);
 	printk("SIS5513 %s\n", marker);
@@ -195,9 +193,9 @@
 /* Cycle time bits and values vary accross chip dma capabilities
    These three arrays hold the register layout and the values to set.
    Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
-static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
-static u8 cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
+static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
+static byte cycle_time_range[] = {0,0,2,3,3,4,4};
+static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
 	{0,0,0,0,0,0}, /* no udma */
 	{0,0,0,0,0,0}, /* no udma */
 	{3,2,1,0,0,0},
@@ -209,43 +207,270 @@
 
 static struct pci_dev *host_dev = NULL;
 
-static int __init sis5513_modes_map(struct ata_channel *ch)
+
+/*
+ * Printing configuration
+ */
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sis_get_info(char *, char **, off_t, int);
+extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char* recovery_time[] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"Reserved", "Reserved",
+	"Reserved", "Reserved"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, byte pos)
 {
-	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
+	byte reg00, reg01, reg10, reg11; /* timing registers */
+	char* p = buffer;
 
+/* Postwrite/Prefetch */
+	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+
+	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+
+/* UDMA */
+	if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
 	switch(chipset_family) {
-		case ATA_133:	/* map |= XFER_UDMA_133; */
-		case ATA_100:
-		case ATA_100a:
-			map |= XFER_UDMA_100;
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
 		case ATA_66:
-			map |= XFER_UDMA_66;
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
 		case ATA_33:
-			map |= XFER_UDMA;
-			break;
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	byte reg;
+	u16 reg2, reg3;
+
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133:
+		default: p+= sprintf(p, "Ultra 133+"); break;
+	}
+	p += sprintf(p, " chipset\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
 	}
 
-	return map;
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+	if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
+
+/* Prefetch Count */
+	pci_read_config_word(bmide_dev, 0x4c, &reg2);
+	pci_read_config_word(bmide_dev, 0x4e, &reg3);
+	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+		     reg2, reg3);
+
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
+
+	return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+byte sis_proc = 0;
+
+static byte sis5513_ratemask (ide_drive_t *drive)
+{
+//	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mode		= 0x00;
+
+	switch(chipset_family) {
+		case ATA_133:	//	{ mode |= 0x04; break; }
+		case ATA_100:
+		case ATA_100a:	{ mode |= 0x03; break; }
+		case ATA_66:	{ mode |= 0x02; break; }
+		case ATA_33:	{ mode |= 0x01; break; }
+		case ATA_16:
+                case ATA_00:	
+		default:
+			return (mode &= ~0xF8);
+	}
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
+
+static byte sis5513_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = sis5513_ratemask(drive);
+
+	switch(mode) {
+		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
 }
 
 /*
  * Configuration functions
  */
 /* Enables per-drive prefetch and postwrite */
-static void config_drive_art_rwp(struct ata_device *drive)
+static void config_drive_art_rwp (ide_drive_t *drive)
 {
-	struct ata_channel *hwif = drive->channel;
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 
-	u8 reg4bh = 0;
-	u8 rw_prefetch = (0x11 << drive->dn);
+	byte reg4bh		= 0;
+	byte rw_prefetch	= (0x11 << drive->dn);
 
 #ifdef DEBUG
 	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
 	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
 #endif
 
-	if (drive->type != ATA_DISK)
+	if (drive->media != ide_disk)
 		return;
 	pci_read_config_byte(dev, 0x4b, &reg4bh);
 
@@ -258,24 +483,51 @@
 
 
 /* Set per-drive active and recovery time */
-static int config_art_rwp_pio(struct ata_device *drive, u8 pio)
+static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
 {
-	struct ata_channel *hwif = drive->channel;
-	struct pci_dev *dev = hwif->pci_dev;
-	u8 drive_pci, test1, test2;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	byte			timing, drive_pci, test1, test2;
+
+	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	unsigned short xfer_pio = drive->id->eide_pio_modes;
 
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
 #endif
 
 	config_drive_art_rwp(drive);
+	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
 #ifdef DEBUG
 	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
 	       drive->dn, pio, timing);
 #endif
 
-	drive_pci = 0x40 + (drive->dn << 1);
+	switch(drive->dn) {
+		case 0:		drive_pci = 0x40; break;
+		case 1:		drive_pci = 0x42; break;
+		case 2:		drive_pci = 0x44; break;
+		case 3:		drive_pci = 0x46; break;
+		default:	return;
+	}
 
 	/* register layout changed with newer ATA100 chips */
 	if (chipset_family < ATA_100) {
@@ -286,7 +538,7 @@
 		test1 &= ~0x0F;
 		test2 &= ~0x07;
 
-		switch(pio) {
+		switch(timing) {
 			case 4:		test1 |= 0x01; test2 |= 0x03; break;
 			case 3:		test1 |= 0x03; test2 |= 0x03; break;
 			case 2:		test1 |= 0x04; test2 |= 0x04; break;
@@ -296,7 +548,7 @@
 		pci_write_config_byte(dev, drive_pci, test1);
 		pci_write_config_byte(dev, drive_pci+1, test2);
 	} else {
-		switch(pio) { /*   active  recovery
+		switch(timing) { /*   active  recovery
 					  v     v */
 			case 4:		test1 = 0x30|0x01; break;
 			case 3:		test1 = 0x30|0x03; break;
@@ -310,27 +562,49 @@
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
 #endif
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+	byte speed;
+
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
 
-	return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4));
+	config_art_rwp_pio(drive, pio);
+	return (ide_config_drive_speed(drive, speed));
 }
 
-static int sis5513_tune_chipset(struct ata_device *drive, u8 speed)
+static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-
-	u8 drive_pci, reg;
+	byte speed		= sis5513_ratefilter(drive, xferspeed);
+	byte			drive_pci, reg;
 
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
 	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
 	       drive->dn, speed);
 #endif
-
-	if (drive->dn > 3)	/* FIXME: remove this  --bkz */
-		return 1;
-
-	drive_pci = 0x40 + (drive->dn << 1);
+#if 1
+	switch(drive->dn) {
+		case 0:		drive_pci = 0x40; break;
+		case 1:		drive_pci = 0x42; break;
+		case 2:		drive_pci = 0x44; break;
+		case 3:		drive_pci = 0x46; break;
+		default:	return ide_dma_off;
+	}
+#else
+//	drive_pci = (0x40 + ((drive->dn) *2));
+//	drive_pci = 0x40;
+//	drive_pci |= ((drive->dn) << 1);
+#endif
 
 #ifdef BROKEN_LEVEL
 #ifdef DEBUG
@@ -373,31 +647,151 @@
 		case XFER_SW_DMA_0:
 			break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
+		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
 		case XFER_PIO_0:
-			return config_art_rwp_pio(drive, speed - XFER_PIO_0);
-		default:
-			return config_art_rwp_pio(drive, 0);
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
 	}
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
 #endif
-	return ide_config_drive_speed(drive, speed);
+	return ((int) ide_config_drive_speed(drive, speed));
 }
 
-static void sis5513_tune_drive(struct ata_device *drive, u8 pio)
+static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
 {
-	if (pio == 255)
-		pio = ata_best_pio_mode(drive) - XFER_PIO_0;
+	(void) config_chipset_for_pio(drive, pio);
+}
 
-	(void)config_art_rwp_pio(drive, min_t(u8, pio, 4));
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte mode		= sis5513_ratemask(drive);
+	byte speed		= 0;
+
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d ultra %d\n",
+	       drive->dn, mode);
+#endif
+
+	switch(mode) {
+		case 0x04:
+			if (id->dma_ultra & 0x0040)
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if (id->dma_ultra & 0x0020)
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_mword & 0x0001)
+				{ speed = XFER_MW_DMA_0; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+			if (id->dma_1word & 0x0002)
+				{ speed = XFER_SW_DMA_1; break; }
+			if (id->dma_1word & 0x0001)
+				{ speed = XFER_SW_DMA_0; break; }
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
+	sis5513_tune_chipset(drive, speed);
+//	return ((int) ide_dma_on);
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id		= drive->id;
+	ide_dma_action_t dma_func	= ide_dma_off_quietly;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x003F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
+			   (id->eide_dma_time > 150)) {
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		sis5513_tune_drive(drive, 5);
+	}
+
+	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			config_drive_art_rwp(drive);
+			config_art_rwp_pio(drive, 5);
+			return config_drive_xfer_rate(drive);
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
 /* Chip detection and general config */
-static unsigned int __init pci_init_sis5513(struct pci_dev *dev)
+unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
 	int i = 0;
@@ -420,7 +814,7 @@
 #endif
 
 		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
 			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
 		}
 	}
@@ -429,7 +823,7 @@
 	   1/ tell IDE channels to operate in Compabitility mode only
 	   2/ tell old chips to allow per drive IDE timings */
 	if (host_dev) {
-		u8 reg;
+		byte reg;
 		switch(chipset_family) {
 			case ATA_133:
 			case ATA_100:
@@ -464,6 +858,14 @@
 			case ATA_00:
 			default: break;
 		}
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		if (!sis_proc) {
+			sis_proc = 1;
+			bmide_dev = dev;
+			sis_display_info = &sis_get_info;
+		}
+#endif
 	}
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
@@ -471,10 +873,10 @@
 	return 0;
 }
 
-static unsigned int __init ata66_sis5513(struct ata_channel *hwif)
+unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
 {
-	u8 reg48h, ata66 = 0;
-	u8 mask = hwif->unit ? 0x20 : 0x10;
+	byte reg48h = 0, ata66 = 0;
+	byte mask = hwif->channel ? 0x20 : 0x10;
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
 
 	if (chipset_family >= ATA_66) {
@@ -483,41 +885,43 @@
         return ata66;
 }
 
-static void __init ide_init_sis5513(struct ata_channel *hwif)
+void __init ide_init_sis5513 (ide_hwif_t *hwif)
 {
 
-	hwif->irq = hwif->unit ? 15 : 14;
-
-	hwif->udma_four = ata66_sis5513(hwif);
+	hwif->irq = hwif->channel ? 15 : 14;
 
 	hwif->tuneproc = &sis5513_tune_drive;
 	hwif->speedproc = &sis5513_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+	hwif->autodma = 0;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base && host_dev && chipset_family > ATA_16) {
-		hwif->highmem = 1;
-		hwif->modes_map = sis5513_modes_map(hwif);
-		hwif->udma_setup = udma_generic_setup;
-	}
-#endif
+	if (!(hwif->dma_base))
+		return;
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (host_dev) {
+		if (chipset_family > ATA_16)
+			hwif->dmaproc = &sis5513_dmaproc;
+		else
+			hwif->autodma = 0;
+	}
+# ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+# endif /* CONFIG_IDEDMA_AUTO */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	return;
 }
 
+extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
 
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_SI,
-	.device = PCI_DEVICE_ID_SI_5513,
-	.init_chipset = pci_init_sis5513,
-	.init_channel = ide_init_sis5513,
-	.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04} },
-	.bootable = ON_BOARD,
-};
-
-int __init init_sis5513(void)
+void __init fixup_device_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	ata_register_chipset(&chipset);
+	if (dev->resource[0].start != 0x01F1)
+		ide_register_xp_fix(dev);
 
-        return 0;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
 }
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/sl82c105.c	Tue Aug 27 12:28:08 2002
@@ -5,13 +5,11 @@
  *
  * Maintainer unknown.
  *
- * Changelog:
- *
- * 15/11/1998	RMK	Drive tuning added from Rebel.com's kernel
- *			sources
- * 30/03/2002	RMK	Add fixes specified in W83C553F errata.
- *			(with special thanks to Todd Inglett)
+ * Drive tuning added from Rebel.com's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
  */
+
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -19,39 +17,27 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/pci.h>
 #include <linux/hdreg.h>
+#include <linux/pci.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include "timing.h"
-#include "pcihost.h"
-
-/*
- * SL82C105 PCI config register 0x40 bits.
- */
-#define CTRL_IDE_IRQB	(1 << 30)
-#define CTRL_IDE_IRQA	(1 << 28)
-#define CTRL_LEGIRQ	(1 << 11)
-#define CTRL_P1F16	(1 << 5)
-#define CTRL_P1EN	(1 << 4)
-#define CTRL_P0F16	(1 << 1)
-#define	CTRL_P0EN	(1 << 0)
+#include "ide_modes.h"
 
 /*
  * Convert a PIO mode and cycle time to the required on/off
  * times for the interface.  This has protection against run-away
  * timings.
  */
-static unsigned int get_timing_sl82c105(struct ata_timing *t)
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
 {
 	unsigned int cmd_on;
 	unsigned int cmd_off;
 
-	cmd_on = (t->active + 29) / 30;
-	cmd_off = (t->cycle - 30 * cmd_on + 29) / 30;
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
 
 	if (cmd_on > 32)
 		cmd_on = 32;
@@ -63,33 +49,37 @@
 	if (cmd_off == 0)
 		cmd_off = 1;
 
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | ((t->mode > XFER_PIO_2) ? 0x40 : 0x00);
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
 }
 
 /*
  * Configure the drive and chipset for PIO
  */
-static void config_for_pio(struct ata_device *drive, int pio, int report)
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
-	struct ata_timing *t;
+	ide_pio_data_t p;
 	unsigned short drv_ctrl = 0x909;
 	unsigned int xfer_mode, reg;
 
-	reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
 
-	if (pio == 255)
-		xfer_mode = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		xfer_mode = XFER_PIO_0 + min_t(u8, pio, 4);
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
 
-	t = ata_timing_data(xfer_mode);
+	switch (pio) {
+	default:
+	case 0:		xfer_mode = XFER_PIO_0;		break;
+	case 1:		xfer_mode = XFER_PIO_1;		break;
+	case 2:		xfer_mode = XFER_PIO_2;		break;
+	case 3:		xfer_mode = XFER_PIO_3;		break;
+	case 4:		xfer_mode = XFER_PIO_4;		break;
+	}
 
 	if (ide_config_drive_speed(drive, xfer_mode) == 0)
-		drv_ctrl = get_timing_sl82c105(t);
+		drv_ctrl = get_timing_sl82c105(&p);
 
-	if (!drive->using_dma) {
+	if (drive->using_dma == 0) {
 		/*
 		 * If we are actually using MW DMA, then we can not
 		 * reprogram the interface drive control register.
@@ -98,9 +88,8 @@
 		pci_read_config_word(dev, reg, &drv_ctrl);
 
 		if (report) {
-			printk("%s: selected %02x (%dns) (%04X)\n",
-					drive->name, xfer_mode,
-					t->cycle, drv_ctrl);
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
 		}
 	}
 }
@@ -108,14 +97,14 @@
 /*
  * Configure the drive and the chipset for DMA
  */
-static int config_for_dma(struct ata_device *drive)
+static int config_for_dma(ide_drive_t *drive)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned short drv_ctrl = 0x909;
 	unsigned int reg;
 
-	reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
 
 	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
 		drv_ctrl = 0x0240;
@@ -125,18 +114,17 @@
 	return 0;
 }
 
-
 /*
  * Check to see if the drive and
  * chipset is capable of DMA mode
  */
-static int sl82c105_dma_setup(struct ata_device *drive, int map)
+static int sl82c105_check_drive(ide_drive_t *drive)
 {
-	int on = 0;
+	ide_dma_action_t dma_func = ide_dma_off_quietly;
 
 	do {
 		struct hd_driveid *id = drive->id;
-		struct ata_channel *hwif = drive->channel;
+		ide_hwif_t *hwif = HWIF(drive);
 
 		if (!hwif->autodma)
 			break;
@@ -145,120 +133,53 @@
 			break;
 
 		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
 			break;
 		}
 
 		if (id->field_valid & 2) {
 			if  (id->dma_mword & 7 || id->dma_1word & 7)
-				on = 1;
+				dma_func = ide_dma_on;
 			break;
 		}
 
-		if (udma_white_list(drive)) {
-			on = 1;
+		if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			dma_func = ide_dma_on;
 			break;
 		}
 	} while (0);
 
-	if (on)
-		config_for_dma(drive);
-	else
-		config_for_pio(drive, 4, 0);
-
-	udma_enable(drive, on, 0);
-
-	return 0;
+	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
 /*
- * The SL82C105 holds off all IDE interrupts while in DMA mode until
- * all DMA activity is completed.  Sometimes this causes problems (eg,
- * when the drive wants to report an error condition).
- *
- * 0x7e is a "chip testing" register.  Bit 2 resets the DMA controller
- * state machine.  We need to kick this to work around various bugs.
+ * Our own dmaproc, only to intercept ide_dma_check
  */
-static inline void sl82c105_reset_host(struct pci_dev *dev)
-{
-	u16 val;
-
-	pci_read_config_word(dev, 0x7e, &val);
-	pci_write_config_word(dev, 0x7e, val | (1 << 2));
-	pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
-}
-
-static void sl82c105_dma_enable(struct ata_device *drive, int on, int verbose)
+static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	if (!on || config_for_dma(drive)) {
+	switch (func) {
+	case ide_dma_check:
+		return sl82c105_check_drive(drive);
+	case ide_dma_on:
+		if (config_for_dma(drive))
+			func = ide_dma_off;
+		/* fall through */
+	case ide_dma_off_quietly:
+	case ide_dma_off:
 		config_for_pio(drive, 4, 0);
-		on = 0;
-	}
-	udma_pci_enable(drive, on, verbose);
-}
-
-/*
- * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
- * Winbond recommend that the DMA state machine is reset prior to
- * setting the bus master DMA enable bit.
- *
- * The generic IDE core will have disabled the BMEN bit before this
- * function is called.
- */
-static int sl82c105_dma_init(struct ata_device *drive, struct request *rq)
-{
-	sl82c105_reset_host(drive->channel->pci_dev);
-
-	return udma_pci_init(drive, rq);
-}
-
-static void sl82c105_timeout(struct ata_device *drive)
-{
-	sl82c105_reset_host(drive->channel->pci_dev);
-}
-
-/*
- * If we get an IRQ timeout, it might be that the DMA state machine
- * got confused.  Fix from Todd Inglett.  Details from Winbond.
- *
- * This function is called when the IDE timer expires, the drive
- * indicates that it is READY, and we were waiting for DMA to complete.
- */
-static void sl82c105_lostirq(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev = ch->pci_dev;
-	u32 val, mask = ch->unit ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
-	unsigned long dma_base = ch->dma_base;
-
-	printk("sl82c105: lost IRQ: resetting host\n");
-
-	/*
-	 * Check the raw interrupt from the drive.
-	 */
-	pci_read_config_dword(dev, 0x40, &val);
-	if (val & mask)
-		printk("sl82c105: drive was requesting IRQ, but host lost it\n");
-
-	/*
-	 * Was DMA enabled?  If so, disable it - we're resetting the
-	 * host.  The IDE layer will be handling the drive for us.
-	 */
-	val = inb(dma_base);
-	if (val & 1) {
-		outb(val & ~1, dma_base);
-		printk("sl82c105: DMA was enabled\n");
+		break;
+	default:
+		break;
 	}
-
-	sl82c105_reset_host(dev);
+	return ide_dmaproc(func, drive);
 }
 
 /*
  * We only deal with PIO mode here - DMA mode 'using_dma' is not
  * initialised at the point that this function is called.
  */
-static void tune_sl82c105(struct ata_device *drive, u8 pio)
+static void tune_sl82c105(ide_drive_t *drive, byte pio)
 {
 	config_for_pio(drive, pio, 1);
 
@@ -266,33 +187,29 @@
 	 * We support 32-bit I/O on this interface, and it
 	 * doesn't have problems with interrupts.
 	 */
-	drive->channel->io_32bit = 1;
-	drive->channel->unmask = 1;
+	drive->io_32bit = 1;
+	drive->unmask = 1;
 }
 
 /*
  * Return the revision of the Winbond bridge
  * which this function is part of.
  */
-static __init unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
 {
 	struct pci_dev *bridge;
 	unsigned char rev;
 
+	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
+
 	/*
-	 * The bridge should be part of the same device, but function 0.
+	 * If we are part of a Winbond 553
 	 */
-	bridge = pci_find_slot(dev->bus->number,
-			       PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-	if (!bridge)
+	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
 		return -1;
 
-	/*
-	 * Make sure it is a Winbond 553 and is an ISA bridge.
-	 */
-	if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
-	    bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
-	    bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+	if (bridge->bus != dev->bus ||
+	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
 		return -1;
 
 	/*
@@ -306,72 +223,50 @@
 /*
  * Enable the PCI device
  */
-static unsigned int __init sl82c105_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
 {
-	u32 val;
+	unsigned char ctrl_stat;
 
-	pci_read_config_dword(dev, 0x40, &val);
-	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1EN | CTRL_P1F16;
-	pci_write_config_dword(dev, 0x40, val);
+	/*
+	 * Enable the ports
+	 */
+	pci_read_config_byte(dev, 0x40, &ctrl_stat);
+	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
 
 	return dev->irq;
 }
 
-static void __init sl82c105_init_dma(struct ata_channel *ch, unsigned long dma_base)
+void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
 {
-	unsigned int bridge_rev;
-	u8 dma_state;
+	unsigned int rev;
+	byte dma_state;
 
-	dma_state = inb(dma_base + 2);
-	bridge_rev = sl82c105_bridge_revision(ch->pci_dev);
-	if (bridge_rev <= 5) {
-		ch->autodma = 0;
-		ch->drives[0].autotune = 1;
-		ch->drives[1].autotune = 1;
+	dma_state = IN_BYTE(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		hwif->autodma = 0;
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
 		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       ch->name, bridge_rev);
+		       hwif->name, rev);
 		dma_state &= ~0x60;
 	} else {
 		dma_state |= 0x60;
+		hwif->autodma = 1;
 	}
-	outb(dma_state, dma_base + 2);
-
-	ata_init_dma(ch, dma_base);
+	OUT_BYTE(dma_state, dma_base + 2);
 
-	if (bridge_rev <= 5)
-		ch->udma_setup = NULL;
-	else {
-		ch->udma_setup    = sl82c105_dma_setup;
-		ch->udma_enable   = sl82c105_dma_enable;
-		ch->udma_init	  = sl82c105_dma_init;
-		ch->udma_timeout  = sl82c105_timeout;
-		ch->udma_irq_lost = sl82c105_lostirq;
-	}
+	hwif->dmaproc = NULL;
+	ide_setup_dma(hwif, dma_base, 8);
+	if (hwif->dmaproc)
+		hwif->dmaproc = sl82c105_dmaproc;
 }
 
 /*
  * Initialise the chip
  */
-static void __init sl82c105_init_channel(struct ata_channel *ch)
+void __init ide_init_sl82c105(ide_hwif_t *hwif)
 {
-	ch->tuneproc = tune_sl82c105;
+	hwif->tuneproc = tune_sl82c105;
 }
 
-
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_WINBOND,
-	.device = PCI_DEVICE_ID_WINBOND_82C105,
-	.init_chipset = sl82c105_init_chipset,
-	.init_channel = sl82c105_init_channel,
-	.init_dma = sl82c105_init_dma,
-	.enablebits = { {0x40,0x01,0x01}, {0x40,0x10,0x10} },
-	.bootable = ON_BOARD
-};
-
-int __init init_sl82c105(void)
-{
-	ata_register_chipset(&chipset);
-
-	return 0;
-}
diff -Nru a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/slc90e66.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,470 @@
+/*
+ *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
+ *
+ *  Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ * 00:07.1 IDE interface: EFAR Microsystems:
+ * 		Unknown device 9130 (prog-if 8a [Master SecP PriP])
+ * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV-
+ * 		VGASnoop- ParErr- Stepping- SERR- FastB2B-
+ * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium
+ * 		>TAbort- <TAbort- <MAbort- >SERR- <PERR-
+ * Latency: 64
+ * Interrupt: pin A routed to IRQ 255
+ * Region 4: I/O ports at 1050
+ *
+ * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00
+ * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00
+ * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00
+ * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00
+ * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+#define SLC90E66_DEBUG_DRIVE_INFO		0
+
+#define DISPLAY_SLC90E66_TIMINGS
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int slc90e66_get_info(char *, char **, off_t, int);
+extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x47, &reg47);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+#ifdef __mips__	/* only for mips? */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+#else
+	c0 = inb_p((unsigned short)bibma + 0x02);
+	c1 = inb_p((unsigned short)bibma + 0x0a);
+#endif
+
+	p += sprintf(p, "                                SLC90E66 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg4a&0x04)==0x04) ? "4" :
+			((reg4a&0x03)==0x03) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4a&0x40)==0x40) ? "4" :
+			((reg4a&0x30)==0x30) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4b&0x04)==0x04) ? "4" :
+			((reg4b&0x03)==0x03) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg4b&0x40)==0x40) ? "4" :
+			((reg4b&0x30)==0x30) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ *  Used to set Fifo configuration via kernel command line:
+ */
+
+byte slc90e66_proc = 0;
+
+static byte slc90e66_ratemask (ide_drive_t *drive)
+{
+	byte mode	= 0x00;
+
+	mode |= 0x02;
+
+	if (!eighty_ninty_three(drive)) {
+		mode &= ~0xFE;
+		mode |= 0x01;
+	}
+	return (mode &= ~0xF8);
+}
+
+static byte slc90e66_ratefilter (ide_drive_t *drive, byte speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	byte mode = slc90e66_ratemask(drive);
+
+	switch(mode) {
+		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
+		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
+		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
+		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
+		case 0x00:
+		default:	while (speed > XFER_MW_DMA_2) speed--; break;
+			break;
+	}
+#else
+	while (speed > XFER_PIO_4) speed--;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
+	return speed;
+}
+
+static byte slc90e66_dma_2_pio (byte xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	byte slave_data;
+				 /* ISP  RTC */
+	byte timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte maslave		= hwif->channel ? 0x42 : 0x40;
+	byte speed		= slc90e66_ratefilter(drive, xferspeed);
+	int a_speed		= 7 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	short			reg4042, reg44, reg48, reg4a;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:        break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if ((reg4a & u_speed) != u_speed) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_read_config_word(dev, 0x4a, &reg4a);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte mode		= slc90e66_ratemask(drive);
+	byte speed, tspeed, dma = 1;
+
+	switch(mode) {
+		case 0x02:
+			if (id->dma_ultra & 0x0010)
+				{ speed = XFER_UDMA_4; break; }
+			if (id->dma_ultra & 0x0008)
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if (id->dma_ultra & 0x0004)
+				{ speed = XFER_UDMA_2; break; }
+			if (id->dma_ultra & 0x0002)
+				{ speed = XFER_UDMA_1; break; }
+			if (id->dma_ultra & 0x0001)
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if (id->dma_mword & 0x0004)
+				{ speed = XFER_MW_DMA_2; break; }
+			if (id->dma_mword & 0x0002)
+				{ speed = XFER_MW_DMA_1; break; }
+			if (id->dma_1word & 0x0004)
+				{ speed = XFER_SW_DMA_2; break; }
+		default:
+			tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+			speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+			dma = 0;
+			break;
+	}
+
+	(void) slc90e66_tune_chipset(drive, speed);
+//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
+	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x007F) {
+				/* Force if Capable UltraDMA */
+				dma_func = slc90e66_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = slc90e66_config_drive_for_dma(drive);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = slc90e66_config_drive_for_dma(drive);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		slc90e66_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default :
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+	return ide_dmaproc(func, drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!slc90e66_proc) {
+		slc90e66_proc = 1;
+		bmide_dev = dev;
+		slc90e66_display_info = &slc90e66_get_info;
+	}
+#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
+{
+	byte reg47 = 0, ata66 = 0;
+	byte mask = hwif->channel ? 0x01 : 0x02;	/* bit0:Primary */
+
+	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+	ata66 = (reg47 & mask) ? 0 : 1;	/* bit[0(1)]: 0:80, 1:40 */
+	return ata66;
+}
+
+void __init ide_init_slc90e66 (ide_hwif_t *hwif)
+{
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->autodma = 0;
+	hwif->speedproc = &slc90e66_tune_chipset;
+	hwif->tuneproc = &slc90e66_tune_drive;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	hwif->dmaproc = &slc90e66_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+	if (!noautodma)
+		hwif->autodma = 1;
+#endif /* CONFIG_IDEDMA_AUTO */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c
--- a/drivers/ide/tcq.c	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,649 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 Jens Axboe <axboe@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- * Support for the DMA queued protocol, which enables ATA disk drives to
- * use tagged command queueing.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/delay.h>
-
-/*
- * warning: it will be _very_ verbose if defined
- */
-#undef IDE_TCQ_DEBUG
-
-#ifdef IDE_TCQ_DEBUG
-#define TCQ_PRINTK printk
-#else
-#define TCQ_PRINTK(x...)
-#endif
-
-/*
- * use nIEN or not
- */
-#undef IDE_TCQ_NIEN
-
-/*
- * We are leaving the SERVICE interrupt alone, IBM drives have it
- * on per default and it can't be turned off. Doesn't matter, this
- * is the sane config.
- */
-#undef IDE_TCQ_FIDDLE_SI
-
-static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq);
-static ide_startstop_t service(struct ata_device *drive, struct request *rq);
-
-static ide_startstop_t tcq_nop_handler(struct ata_device *drive, struct request *rq)
-{
-	unsigned long flags;
-	struct ata_taskfile *args = rq->special;
-	struct ata_channel *ch = drive->channel;
-
-	local_irq_enable();
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
-
-	spin_unlock_irqrestore(ch->lock, flags);
-
-	kfree(args);
-
-	return ATA_OP_FINISHED;
-}
-
-/*
- * If we encounter _any_ error doing I/O to one of the tags, we must
- * invalidate the pending queue. Clear the software busy queue and requeue
- * on the request queue for restart. Issue a WIN_NOP to clear hardware queue.
- */
-static void tcq_invalidate_queue(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	request_queue_t *q = &drive->queue;
-	struct ata_taskfile *ar;
-	struct request *rq;
-	unsigned long flags;
-
-	printk(KERN_INFO "ATA: %s: invalidating pending queue (%d)\n", drive->name, ata_pending_commands(drive));
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	del_timer(&ch->timer);
-
-	if (test_bit(IDE_DMA, ch->active))
-		udma_stop(drive);
-
-	blk_queue_invalidate_tags(q);
-
-	drive->using_tcq = 0;
-	drive->queue_depth = 1;
-	clear_bit(IDE_BUSY, ch->active);
-	clear_bit(IDE_DMA, ch->active);
-	ch->handler = NULL;
-
-	/*
-	 * Do some internal stuff -- we really need this command to be
-	 * executed before any new commands are started. issue a NOP
-	 * to clear internal queue on drive.
-	 */
-	ar = kmalloc(sizeof(*ar), GFP_ATOMIC);
-	if (!ar) {
-		printk(KERN_ERR "ATA: %s: failed to issue NOP\n", drive->name);
-		goto out;
-	}
-
-	rq = __blk_get_request(&drive->queue, READ);
-	if (!rq)
-		rq = __blk_get_request(&drive->queue, WRITE);
-
-	/*
-	 * blk_queue_invalidate_tags() just added back at least one command
-	 * to the free list, so there _must_ be at least one free.
-	 */
-	BUG_ON(!rq);
-
-	/* WIN_NOP is a special request so set it's flags ?? */
-	rq->flags = REQ_SPECIAL;
-	rq->special = ar;
-	ar->cmd = WIN_NOP;
-	ar->XXX_handler = tcq_nop_handler;
-	ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-
-	_elv_add_request(q, rq, 0, 0);
-
-out:
-#ifdef IDE_TCQ_NIEN
-	ata_irq_enable(drive, 1);
-#endif
-
-	/*
-	 * start doing stuff again
-	 */
-	q->request_fn(q);
-	spin_unlock_irqrestore(ch->lock, flags);
-	printk(KERN_DEBUG "ATA: tcq_invalidate_queue: done\n");
-}
-
-static void ata_tcq_irq_timeout(unsigned long data)
-{
-	struct ata_device *drive = (struct ata_device *) data;
-	struct ata_channel *ch = drive->channel;
-	unsigned long flags;
-
-	printk(KERN_ERR "ATA: %s: timeout waiting for interrupt...\n", __FUNCTION__);
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	if (test_and_set_bit(IDE_BUSY, ch->active))
-		printk(KERN_ERR "ATA: %s: IRQ handler not busy\n", __FUNCTION__);
-	if (!ch->handler)
-		printk(KERN_ERR "ATA: %s: missing ISR!\n", __FUNCTION__);
-
-	spin_unlock_irqrestore(ch->lock, flags);
-
-	/*
-	 * if pending commands, try service before giving up
-	 */
-	if (ata_pending_commands(drive) && !ata_status(drive, 0, SERVICE_STAT))
-		if (service(drive, drive->rq) == ATA_OP_CONTINUES)
-			return;
-
-	if (drive)
-		tcq_invalidate_queue(drive);
-}
-
-static void __set_irq(struct ata_channel *ch, ata_handler_t *handler)
-{
-	/*
-	 * always just bump the timer for now, the timeout handling will
-	 * have to be changed to be per-command
-	 *
-	 * FIXME: Jens - this is broken it will interfere with
-	 * the normal timer function on serialized drives!
-	 */
-
-	ch->timer.function = ata_tcq_irq_timeout;
-	ch->timer.data = (unsigned long) ch->drive;
-	mod_timer(&ch->timer, jiffies + 5 * HZ);
-	ch->handler = handler;
-}
-
-static void set_irq(struct ata_device *drive, ata_handler_t *handler)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long flags;
-
-	spin_lock_irqsave(ch->lock, flags);
-	__set_irq(ch, handler);
-	spin_unlock_irqrestore(ch->lock, flags);
-}
-
-/*
- * wait 400ns, then poll for busy_mask to clear from alt status
- */
-#define IDE_TCQ_WAIT	(10000)
-static int wait_altstat(struct ata_device *drive, u8 *stat, u8 busy_mask)
-{
-	int i = 0;
-
-	udelay(1);
-
-	while ((*stat = GET_ALTSTAT()) & busy_mask) {
-		if (unlikely(i++ > IDE_TCQ_WAIT))
-			return 1;
-
-		udelay(10);
-	}
-
-	return 0;
-}
-
-static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *rq);
-
-/*
- * issue SERVICE command to drive -- drive must have been selected first,
- * and it must have reported a need for service (status has SERVICE_STAT set)
- *
- * Also, nIEN must be set as not to need protection against ide_dmaq_intr
- */
-static ide_startstop_t service(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long flags;
-	u8 feat, stat;
-	int tag;
-
-	TCQ_PRINTK("%s: started service\n", drive->name);
-
-	/*
-	 * Could be called with IDE_DMA in-progress from invalidate
-	 * handler, refuse to do anything.
-	 */
-	if (test_bit(IDE_DMA, drive->channel->active))
-		return ATA_OP_FINISHED;
-
-	/*
-	 * need to select the right drive first...
-	 */
-	if (drive != drive->channel->drive)
-		ata_select(drive, 10);
-
-#ifdef IDE_TCQ_NIEN
-	ata_irq_enable(drive, 0);
-#endif
-	/*
-	 * send SERVICE, wait 400ns, wait for BUSY_STAT to clear
-	 */
-	OUT_BYTE(WIN_QUEUED_SERVICE, IDE_COMMAND_REG);
-
-	if (wait_altstat(drive, &stat, BUSY_STAT)) {
-		ata_dump(drive, rq, "BUSY clear took too long");
-		tcq_invalidate_queue(drive);
-
-		return ATA_OP_FINISHED;
-	}
-
-#ifdef IDE_TCQ_NIEN
-	ata_irq_enable(drive, 1);
-#endif
-
-	/*
-	 * FIXME, invalidate queue
-	 */
-	if (stat & ERR_STAT) {
-		ata_dump(drive, rq, "ERR condition");
-		tcq_invalidate_queue(drive);
-
-		return ATA_OP_FINISHED;
-	}
-
-	/*
-	 * should not happen, a buggy device could introduce loop
-	 */
-	if ((feat = GET_FEAT()) & NSEC_REL) {
-		drive->rq = NULL;
-		printk("%s: release in service\n", drive->name);
-		return ATA_OP_FINISHED;
-	}
-
-	tag = feat >> 3;
-
-	TCQ_PRINTK("%s: stat %x, feat %x\n", __FUNCTION__, stat, feat);
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	rq = blk_queue_find_tag(&drive->queue, tag);
-	if (!rq) {
-		printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag);
-		spin_unlock_irqrestore(ch->lock, flags);
-		return ATA_OP_FINISHED;
-	}
-
-	drive->rq = rq;
-
-	spin_unlock_irqrestore(ch->lock, flags);
-	/*
-	 * we'll start a dma read or write, device will trigger
-	 * interrupt to indicate end of transfer, release is not allowed
-	 */
-	TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat);
-
-	return udma_tcq_start(drive, rq);
-}
-
-static ide_startstop_t check_service(struct ata_device *drive, struct request *rq)
-{
-	TCQ_PRINTK("%s: %s\n", drive->name, __FUNCTION__);
-
-	if (!ata_pending_commands(drive))
-		return ATA_OP_FINISHED;
-
-	if (!ata_status(drive, 0, SERVICE_STAT))
-		return service(drive, rq);
-
-	/*
-	 * we have pending commands, wait for interrupt
-	 */
-	set_irq(drive, ide_dmaq_intr);
-
-	return ATA_OP_CONTINUES;
-}
-
-static ide_startstop_t dmaq_complete(struct ata_device *drive, struct request *rq)
-{
-	u8 dma_stat;
-
-	/*
-	 * transfer was in progress, stop DMA engine
-	 */
-	dma_stat = udma_stop(drive);
-
-	/*
-	 * must be end of I/O, check status and complete as necessary
-	 */
-	if (!ata_status(drive, READY_STAT, drive->bad_wstat | DRQ_STAT)) {
-		ata_dump(drive, rq, __FUNCTION__);
-		tcq_invalidate_queue(drive);
-
-		return ATA_OP_FINISHED;
-	}
-
-	if (dma_stat)
-		printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat);
-
-	TCQ_PRINTK("%s: ending %p, tag %d\n", __FUNCTION__, rq, rq->tag);
-
-	ata_end_request(drive, rq, !dma_stat, rq->nr_sectors);
-
-	/*
-	 * we completed this command, check if we can service a new command
-	 */
-	return check_service(drive, rq);
-}
-
-/*
- * Interrupt handler for queued dma operations. this can be entered for two
- * reasons:
- *
- * 1) device has completed dma transfer
- * 2) service request to start a command
- *
- * if the drive has an active tag, we first complete that request before
- * processing any pending SERVICE.
- */
-static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq)
-{
-	int ok;
-
-	ok = !ata_status(drive, 0, SERVICE_STAT);
-	TCQ_PRINTK("%s: stat=%x\n", __FUNCTION__, drive->status);
-
-	/*
-	 * If a command completion interrupt is pending, do that first and
-	 * check service afterwards.
-	 */
-	if (rq)
-		return dmaq_complete(drive, rq);
-
-	/*
-	 * service interrupt
-	 */
-	if (ok) {
-		TCQ_PRINTK("%s: SERV (stat=%x)\n", __FUNCTION__, drive->status);
-		return service(drive, rq);
-	}
-
-	printk("%s: stat=%x, not expected\n", __FUNCTION__, drive->status);
-
-	return check_service(drive, rq);
-}
-
-/*
- * Check if the ata adapter this drive is attached to supports the
- * NOP auto-poll for multiple tcq enabled drives on one channel.
- */
-static int check_autopoll(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	struct ata_taskfile args;
-	int drives = 0, i;
-
-	/*
-	 * only need to probe if both drives on a channel support tcq
-	 */
-	for (i = 0; i < MAX_DRIVES; i++)
-		if (drive->channel->drives[i].present &&drive->type == ATA_DISK)
-			drives++;
-
-	if (drives <= 1)
-		return 0;
-
-	/*
-	 * do taskfile and check ABRT bit -- intelligent adapters will not
-	 * pass NOP with sub-code 0x01 to device, so the command will not
-	 * fail there
-	 */
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = 0x01;
-	args.cmd = WIN_NOP;
-	ide_raw_taskfile(drive, &args, NULL);
-	if (args.taskfile.feature & ABRT_ERR)
-		return 1;
-
-	ch->auto_poll = 1;
-	printk("%s: NOP Auto-poll enabled\n", ch->name);
-	return 0;
-}
-
-/*
- * configure the drive for tcq
- */
-static int configure_tcq(struct ata_device *drive)
-{
-	int tcq_mask = 1 << 1 | 1 << 14;
-	int tcq_bits = tcq_mask | 1 << 15;
-	struct ata_taskfile args;
-
-	/*
-	 * bit 14 and 1 must be set in word 83 of the device id to indicate
-	 * support for dma queued protocol, and bit 15 must be cleared
-	 */
-	if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask)
-		return -EIO;
-
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SETFEATURES_EN_WCACHE;
-	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args, NULL)) {
-		printk("%s: failed to enable write cache\n", drive->name);
-		return 1;
-	}
-
-	/*
-	 * disable RELease interrupt, it's quicker to poll this after
-	 * having sent the command opcode
-	 */
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SETFEATURES_DIS_RI;
-	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args, NULL)) {
-		printk("%s: disabling release interrupt fail\n", drive->name);
-		return 1;
-	}
-
-#ifdef IDE_TCQ_FIDDLE_SI
-	/*
-	 * enable SERVICE interrupt
-	 */
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SETFEATURES_EN_SI;
-	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args, NULL)) {
-		printk("%s: enabling service interrupt fail\n", drive->name);
-		return 1;
-	}
-#endif
-
-	return 0;
-}
-
-static int tcq_wait_dataphase(struct ata_device *drive)
-{
-	int i;
-
-	while (!ata_status(drive, 0, BUSY_STAT))
-		udelay(10);
-
-	if (ata_status(drive, READY_STAT | DRQ_STAT, drive->bad_wstat))
-		return 0;
-
-	i = 0;
-	udelay(1);
-	while (!ata_status(drive, READY_STAT | DRQ_STAT, drive->bad_wstat)) {
-		++i;
-		if (i > IDE_TCQ_WAIT)
-			return 1;
-
-		udelay(10);
-	}
-
-	return 0;
-}
-
-/****************************************************************************
- * UDMA transfer handling functions.
- */
-
-/*
- * Invoked from a SERVICE interrupt, command etc already known.  Just need to
- * start the dma engine for this tag.
- */
-static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-
-	TCQ_PRINTK("%s: setting up queued %d\n", __FUNCTION__, rq->tag);
-	if (!test_bit(IDE_BUSY, ch->active))
-		printk("queued_rw: IDE_BUSY not set\n");
-
-	if (tcq_wait_dataphase(drive))
-		return ATA_OP_FINISHED;
-
-	if (ata_start_dma(drive, rq))
-		return ATA_OP_FINISHED;
-
-	__set_irq(ch, ide_dmaq_intr);
-	udma_start(drive, rq);
-
-	return ATA_OP_CONTINUES;
-}
-
-/*
- * Start a queued command from scratch.
- */
-ide_startstop_t udma_tcq_init(struct ata_device *drive, struct request *rq)
-{
-	u8 stat;
-	u8 feat;
-
-	struct ata_taskfile *args = rq->special;
-
-	TCQ_PRINTK("%s: start tag %d\n", drive->name, rq->tag);
-
-	/*
-	 * set nIEN, tag start operation will enable again when
-	 * it is safe
-	 */
-#ifdef IDE_TCQ_NIEN
-	ata_irq_enable(drive, 0);
-#endif
-
-	OUT_BYTE(args->cmd, IDE_COMMAND_REG);
-
-	if (wait_altstat(drive, &stat, BUSY_STAT)) {
-		ata_dump(drive, rq, "queued start");
-		tcq_invalidate_queue(drive);
-		return ATA_OP_FINISHED;
-	}
-
-#ifdef IDE_TCQ_NIEN
-	ata_irq_enable(drive, 1);
-#endif
-
-	if (stat & ERR_STAT) {
-		ata_dump(drive, rq, "tcq_start");
-		return ATA_OP_FINISHED;
-	}
-
-	/*
-	 * drive released the bus, clear active tag and
-	 * check for service
-	 */
-	if ((feat = GET_FEAT()) & NSEC_REL) {
-		drive->immed_rel++;
-		drive->rq = NULL;
-		set_irq(drive, ide_dmaq_intr);
-
-		TCQ_PRINTK("REL in queued_start\n");
-
-		if (!ata_status(drive, 0, SERVICE_STAT))
-			return service(drive, rq);
-
-		return ATA_OP_RELEASED;
-	}
-
-	TCQ_PRINTK("IMMED in queued_start\n");
-	drive->immed_comp++;
-
-	return udma_tcq_start(drive, rq);
-}
-
-/*
- * For now assume that command list is always as big as we need and don't
- * attempt to shrink it on tcq disable.
- */
-int udma_tcq_enable(struct ata_device *drive, int on)
-{
-	int depth = drive->using_tcq ? drive->queue_depth : 0;
-
-	/*
-	 * disable or adjust queue depth
-	 */
-	if (!on) {
-		if (drive->using_tcq)
-			printk("%s: TCQ disabled\n", drive->name);
-		drive->using_tcq = 0;
-		return 0;
-	}
-
-	if (configure_tcq(drive)) {
-		drive->using_tcq = 0;
-		return 1;
-	}
-
-	/*
-	 * enable block tagging
-	 */
-	if (!blk_queue_tagged(&drive->queue))
-		blk_queue_init_tags(&drive->queue, IDE_MAX_TAG);
-
-	/*
-	 * check auto-poll support
-	 */
-	check_autopoll(drive);
-
-	if (depth != drive->queue_depth)
-		printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
-
-	drive->using_tcq = 1;
-	return 0;
-}
-
-/* FIXME: This should go away! */
-EXPORT_SYMBOL(udma_tcq_enable);
diff -Nru a/drivers/ide/timing.h b/drivers/ide/timing.h
--- a/drivers/ide/timing.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-/*
- *  Copyright (C) 1996  Linus Torvalds, Igor Abramov, and Mark Lord
- *  Copyright (C) 1999-2001 Vojtech Pavlik
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define XFER_PIO_5		0x0d
-#define XFER_UDMA_SLOW		0x4f
-
-struct ata_timing {
-	short mode;
-	short setup;	/* t1 */
-	short act8b;	/* t2 for 8-bit io */
-	short rec8b;	/* t2i for 8-bit io */
-	short cyc8b;	/* t0 for 8-bit io */
-	short active;	/* t2 or tD */
-	short recover;	/* t2i or tK */
-	short cycle;	/* t0 */
-	short udma;	/* t2CYCTYP/2 */
-};
-
-extern struct ata_timing ata_timing[];
-
-#define IDE_TIMING_SETUP	0x01
-#define IDE_TIMING_ACT8B	0x02
-#define IDE_TIMING_REC8B	0x04
-#define IDE_TIMING_CYC8B	0x08
-#define IDE_TIMING_8BIT		0x0e
-#define IDE_TIMING_ACTIVE	0x10
-#define IDE_TIMING_RECOVER	0x20
-#define IDE_TIMING_CYCLE	0x40
-#define IDE_TIMING_UDMA		0x80
-#define IDE_TIMING_ALL		0xff
-
-#define FIT(v,x,y)	max_t(int,min_t(int,v,y),x)
-#define ENOUGH(v,unit)	(((v)-1)/(unit)+1)
-#define EZ(v,unit)	((v)?ENOUGH(v,unit):0)
-
-/* see hpt366.c for details */
-#define XFER_UDMA_66_3	0x100
-#define XFER_UDMA_66_4	0x200
-
-#define XFER_MODE	0xff0
-#define XFER_UDMA_133	0x800
-#define XFER_UDMA_100	0x400
-#define XFER_UDMA_66	0x300
-#define XFER_UDMA	0x040
-#define XFER_MWDMA	0x020
-#define XFER_SWDMA	0x010
-#define XFER_EPIO	0x001
-#define XFER_PIO	0x000
-
-#define XFER_UDMA_ALL	0xf40
-#define XFER_UDMA_80W	0xf00
-
-/* External interface to host chips channel timing setup.
- *
- * It's a bit elaborate due to the legacy we have to bear.
- */
-
-extern short ata_timing_mode(struct ata_device *drive, int map);
-extern void ata_timing_quantize(struct ata_timing *t, struct ata_timing *q,
-		int T, int UT);
-extern void ata_timing_merge(struct ata_timing *a, struct ata_timing *b,
-		struct ata_timing *m, unsigned int what);
-void ata_timing_merge_8bit(struct ata_timing *t);
-extern struct ata_timing* ata_timing_data(short speed);
-extern int ata_timing_compute(struct ata_device *drive,
-		short speed, struct ata_timing *t, int T, int UT);
-extern u8 ata_best_pio_mode(struct ata_device *drive);
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/ide/trm290.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,4 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*
  *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
  *
  *  Copyright (c) 1997-1998  Mark Lord
@@ -140,11 +139,9 @@
 
 #include <asm/io.h>
 
-#include "pcihost.h"
-
-static void trm290_prepare_drive(struct ata_device *drive, unsigned int use_dma)
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
-	struct ata_channel *hwif = drive->channel;
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned int reg;
 	unsigned long flags;
 
@@ -155,186 +152,164 @@
 
 	if (reg != hwif->select_data) {
 		hwif->select_data = reg;
-		outb(0x51|(hwif->unit<<3), hwif->config_data+1);	/* set PIO/DMA */
-		outw(reg & 0xff, hwif->config_data);
+		/* set PIO/DMA */
+		OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
+		OUT_WORD(reg & 0xff, hwif->config_data);
 	}
 
 	/* enable IRQ if not probing */
 	if (drive->present) {
-		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->unit);
-		outw(reg, hwif->config_data+3);
+		reg = IN_WORD(hwif->config_data+3) & 0x13;
+		reg &= ~(1 << hwif->channel);
+		OUT_WORD(reg, hwif->config_data+3);
 	}
 
 	local_irq_restore(flags);
 }
 
-static void trm290_selectproc(struct ata_device *drive)
+static void trm290_selectproc (ide_drive_t *drive)
 {
 	trm290_prepare_drive(drive, drive->using_dma);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static void trm290_udma_start(struct ata_device *drive, struct request *__rq)
-{
-	/* Nothing to be done here. */
-}
-
-static int trm290_udma_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-
-	udma_destroy_table(ch);	/* purge DMA mappings */
-
-	return (inw(ch->dma_base + 2) != 0x00ff);
-}
-
-static int trm290_udma_init(struct ata_device *drive, struct request *rq)
+static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	struct ata_channel *ch = drive->channel;
-	unsigned int count;
-	int writing;
-	int reading;
-
-
-	if (rq_data_dir(rq) == READ)
-		reading = 1;
-	else
-		reading = 0;
-
-	if (!reading) {
-		reading = 0;
-		writing = 1;
+	ide_hwif_t *hwif = HWIF(drive);
+//	ide_task_t *args = HWGROUP(drive)->rq->special;
+	unsigned int count, reading = 2, writing = 0;
+
+	switch (func) {
+		case ide_dma_write:
+			reading = 0;
+			writing = 1;
 #ifdef TRM290_NO_DMA_WRITES
-		trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-
-		return ATA_OP_FINISHED;
+			break;	/* always use PIO for writes */
 #endif
-	} else {
-		reading = 2;
-		writing = 0;
-	}
-
-	if (!(count = udma_new_table(drive, rq))) {
-		trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
-	}
-
-	trm290_prepare_drive(drive, 1);	/* select DMA xfer */
-
-	outl(ch->dmatable_dma|reading|writing, ch->dma_base);
-	outw((count * 2) - 1, ch->dma_base+2); /* start DMA */
-
-	if (drive->type == ATA_DISK) {
-		ata_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
-		outb(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		case ide_dma_read:
+			if (!(count = ide_build_dmatable(drive, func)))
+				/* try PIO instead of DMA */
+				break;
+			/* select DMA xfer */
+			trm290_prepare_drive(drive, 1);
+			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
+			drive->waiting_for_dma = 1;
+			/* start DMA */
+			OUT_WORD((count * 2) - 1, hwif->dma_base+2);
+			if (drive->media != ide_disk)
+				return 0;
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
+			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+/*
+ * FIX ME to use only ACB ide_task_t args Struct
+ */
+#if 0
+		{
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		}
+#else
+			if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing == 1)
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			else
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+#endif
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+		case ide_dma_begin:
+			return 0;
+		case ide_dma_end:
+			drive->waiting_for_dma = 0;
+			/* purge DMA mappings */
+			ide_destroy_dmatable(drive);
+			return (IN_WORD(hwif->dma_base+2) != 0x00ff);
+		case ide_dma_test_irq:
+			return (IN_WORD(hwif->dma_base+2) == 0x00ff);
+		default:
+			return ide_dmaproc(func, drive);
 	}
-
-	return ATA_OP_CONTINUES;
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
+	return 1;
 }
-
-static int trm290_udma_irq_status(struct ata_device *drive)
-{
-	return (inw(drive->channel->dma_base + 2) == 0x00ff);
-}
-
-static int trm290_udma_setup(struct ata_device *drive, int map)
-{
-	return udma_pci_setup(drive, map);
-}
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * Invoked from ide-dma.c at boot time.
  */
-static void __init trm290_init_channel(struct ata_channel *hwif)
+void __init ide_init_trm290 (ide_hwif_t *hwif)
 {
 	unsigned int cfgbase = 0;
 	unsigned long flags;
-	u8 reg;
+	byte reg;
 	struct pci_dev *dev = hwif->pci_dev;
 
 	hwif->chipset = ide_trm290;
-	hwif->seg_boundary_mask = 0xffffffff;
 	cfgbase = pci_resource_start(dev, 4);
-	if ((dev->class & 5) && cfgbase)
-	{
+	if ((dev->class & 5) && cfgbase) {
 		hwif->config_data = cfgbase;
-		printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
+		printk("TRM290: chip config base at 0x%04lx\n",
+			hwif->config_data);
 	} else {
 		hwif->config_data = 0x3df0;
-		printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
+		printk("TRM290: using default config base at 0x%04lx\n",
+			hwif->config_data);
 	}
 
 	local_irq_save(flags);
 	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->unit<<3), hwif->config_data+1);
-	hwif->select_data = 0x21;			/* select PIO as default */
-	outb(hwif->select_data, hwif->config_data);
-	reg = inb(hwif->config_data+3);			/* get IRQ info */
-	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
-	outb(reg, hwif->config_data+3);
+	OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
+	/* select PIO as default */
+	hwif->select_data = 0x21;
+	OUT_BYTE(hwif->select_data, hwif->config_data);
+	/* get IRQ info */
+	reg = IN_BYTE(hwif->config_data+3);
+	/* mask IRQs for both ports */
+	reg = (reg & 0x10) | 0x03;
+	OUT_BYTE(reg, hwif->config_data+3);
 	local_irq_restore(flags);
 
 	if ((reg & 0x10))
-		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
-	else {
-		static int primary_irq = 0;
-
-		/* Ugly way to let the primary and secondary channel on the
-		 * chip use the same IRQ line.
-		 */
-
-		if (hwif->unit == ATA_PRIMARY)
-			primary_irq = hwif->irq;
-		else if (!hwif->irq)
-			hwif->irq = primary_irq;
-	}
-
-	ata_init_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000));
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->udma_start = trm290_udma_start;
-	hwif->udma_stop = trm290_udma_stop;
-	hwif->udma_init = trm290_udma_init;
-	hwif->udma_irq_status = trm290_udma_irq_status;
-	hwif->udma_setup = trm290_udma_setup;
-#endif
+	hwif->dmaproc = &trm290_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	hwif->selectproc = &trm290_selectproc;
+	hwif->autodma = 0;			/* play it safe for now */
 #if 1
 	{
-		/*
-		 * My trm290-based card doesn't seem to work with all possible values
-		 * for the control basereg, so this kludge ensures that we use only
-		 * values that are known to work.  Ugh.		-ml
-		 */
-		unsigned short old, compat = hwif->unit ? 0x374 : 0x3f4;
+	/*
+	 * My trm290-based card doesn't seem to work with all possible values
+	 * for the control basereg, so this kludge ensures that we use only
+	 * values that are known to work.  Ugh.		-ml
+	 */
+		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
 		static unsigned short next_offset = 0;
 
-		outb(0x54|(hwif->unit<<3), hwif->config_data+1);
-		old = inw(hwif->config_data) & ~1;
-		if (old != compat && inb(old+2) == 0xff) {
+		OUT_BYTE(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = IN_WORD(hwif->config_data) & ~1;
+		if (old != compat && IN_BYTE(old+2) == 0xff) {
 			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
+#if 1
+			if (ide_check_region(compat + 2, 1))
+				printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2));
+			/*
+			 * The region check is not needed; however.........
+			 * Since this is the checked in ide-probe.c,
+			 * this is only an assignment.
+			 */
+#endif
 			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
-			outw(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
+			OUT_WORD(compat|1, hwif->config_data);
+			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, IN_WORD(hwif->config_data) & ~1);
 		}
 	}
 #endif
-}
-
-/* module data table */
-static struct ata_pci_device chipset __initdata = {
-	.vendor = PCI_VENDOR_ID_TEKRAM,
-	.device = PCI_DEVICE_ID_TEKRAM_DC290,
-	.init_channel = trm290_init_channel,
-	.bootable = ON_BOARD
-};
-
-int __init init_trm290(void)
-{
-        ata_register_chipset(&chipset);
-
-        return 0;
 }
diff -Nru a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
--- a/drivers/ide/umc8672.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ide/umc8672.c	Tue Aug 27 12:28:08 2002
@@ -21,7 +21,7 @@
  */
 
 /*
- * VLB Controller Support from
+ * VLB Controller Support from 
  * Wolfram Podien
  * Rohoefe 3
  * D28832 Achim
@@ -34,7 +34,7 @@
  * #define UMC_DRIVE0 11
  * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
  * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the
+ * the results from the DOS speed test program supplied from UMC. 11 is the 
  * highest speed (about PIO mode 3)
  */
 #define REALLY_SLOW_IO		/* some systems can safely undef this */
@@ -46,13 +46,13 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
-#include "timing.h"
+#include "ide_modes.h"
 
 /*
  * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
@@ -62,32 +62,32 @@
 #define UMC_DRIVE2      1              /* 11 = Fastest Speed */
 #define UMC_DRIVE3      1              /* In case of crash reduce speed */
 
-static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const u8 pio_to_umc[5] = {0,3,7,10,11};	/* rough guesses */
+static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const byte pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
 
 /*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const u8 speedtab[3][12] = {
+static const byte speedtab [3][12] = {
 	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
 	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
 	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
 
 static void out_umc (char port,char wert)
 {
-	outb_p (port,0x108);
-	outb_p (wert,0x109);
+	outb_p(port,0x108);
+	outb_p(wert,0x109);
 }
 
-static inline u8 in_umc (char port)
+static inline byte in_umc (char port)
 {
-	outb_p (port,0x108);
-	return inb_p (0x109);
+	outb_p(port,0x108);
+	return inb_p(0x109);
 }
 
-static void umc_set_speeds(u8 speeds[])
+static void umc_set_speeds (byte speeds[])
 {
 	int i, tmp;
 
-	outb_p (0x5A,0x108); /* enable umc */
+	outb_p(0x5A,0x108); /* enable umc */
 
 	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
 	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
@@ -100,51 +100,57 @@
 		out_umc (0xd0+i,speedtab[2][speeds[i]]);
 		out_umc (0xd8+i,speedtab[2][speeds[i]]);
 	}
-	outb_p (0xa5,0x108); /* disable umc */
+	outb_p(0xa5,0x108); /* disable umc */
 
 	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
 		speeds[0], speeds[1], speeds[2], speeds[3]);
 }
 
-static void tune_umc(struct ata_device *drive, u8 pio)
+static void tune_umc (ide_drive_t *drive, byte pio)
 {
-	if (pio == 255)
-		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
-	else
-		pio = min_t(u8, pio, 4);
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
 
-	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
-	current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-	umc_set_speeds (current_speeds);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+		drive->name, pio, pio_to_umc[pio]);
+	spin_lock_irqsave(&ide_lock, flags);
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk("umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-void __init init_umc8672(void)	/* called from ide.c */
+void __init init_umc8672 (void)	/* called from ide.c */
 {
 	unsigned long flags;
 
 	local_irq_save(flags);
-	if (!request_region(0x108, 2, "umc8672")) {
+	if (check_region(0x108, 2)) {
 		local_irq_restore(flags);
 		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
 		return;
 	}
-	outb_p (0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0)
-	{
+	outb_p(0x5A,0x108); /* enable umc */
+	if (in_umc (0xd5) != 0xa0) {
 		local_irq_restore(flags);
-		release_region(0x108, 2);
 		printk ("umc8672: not found\n");
-		return;
+		return;  
 	}
-	outb_p (0xa5,0x108); /* disable umc */
+	outb_p(0xa5,0x108); /* disable umc */
 
-	umc_set_speeds(current_speeds);
+	umc_set_speeds (current_speeds);
 	local_irq_restore(flags);
 
+	request_region(0x108, 2, "umc8672");
 	ide_hwifs[0].chipset = ide_umc8672;
 	ide_hwifs[1].chipset = ide_umc8672;
-	ide_hwifs[0].tuneproc = tune_umc;
-	ide_hwifs[1].tuneproc = tune_umc;
-	ide_hwifs[0].unit = ATA_PRIMARY;
-	ide_hwifs[1].unit = ATA_SECONDARY;
+	ide_hwifs[0].tuneproc = &tune_umc;
+	ide_hwifs[1].tuneproc = &tune_umc;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 }
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/ide/via82cxxx.c	Tue Aug 27 12:28:08 2002
@@ -1,5 +1,4 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
+/*
  * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
@@ -65,13 +64,10 @@
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
-
 #include <asm/io.h>
 
-#include "timing.h"
-#include "pcihost.h"
+#include "ide-timing.h"
 
 #define VIA_IDE_ENABLE		0x40
 #define VIA_IDE_CONFIG		0x41
@@ -106,7 +102,7 @@
 	unsigned char rev_min;
 	unsigned char rev_max;
 	unsigned short flags;
-} via_isa_bridges [] __initdata = {
+} via_isa_bridges[] = {
 #ifdef FUTURE_BRIDGES
 	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
 	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
@@ -133,13 +129,147 @@
 static struct via_isa_bridge *via_config;
 static unsigned char via_enabled;
 static unsigned int via_80w;
+static unsigned int via_clock;
 static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
 
 /*
+ * VIA /proc entry.
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+int via_proc, via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	unsigned short c, w;
+	unsigned char t, x;
+	char *p = buffer;
+
+	via_print("----------VIA BusMastering IDE Configuration----------------");
+
+	via_print("Driver Version:                     3.34");
+	via_print("South Bridge:                       VIA %s", via_config->name);
+
+	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+	via_print("Revision:                           ISA %#x IDE %#x", t, x);
+	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
+
+	via_print("BM-DMA base:                        %#x", via_base);
+	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
+
+	pci_read_config_byte(dev, VIA_MISC_1, &t);
+	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
+	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
+	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_MISC_3, &t);
+	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+	via_print("-----------------------Primary IDE-------Secondary IDE------");
+	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = IN_BYTE(via_base + 0x02) | (IN_BYTE(via_base + 0x0a) << 8);
+	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+	via_print("-------------------drive0----drive1----drive2----drive3-----");
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+	if (via_config->flags & VIA_UDMA)
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+	else u = 0;
+
+	for (i = 0; i < 4; i++) {
+
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+		if (!uen[i] || !den[i])
+			continue;
+
+		switch (via_config->flags & VIA_UDMA) {
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_66:
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+				break;
+
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
+				break;
+		}
+	}
+
+	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
+	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
+
+	return p - buffer;	/* hoping it is less than 4K... */
+}
+
+#endif
+
+/*
  * via_set_speed() writes timing values to the chipset registers
  */
 
-static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing)
+static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
 {
 	unsigned char t;
 
@@ -170,10 +300,10 @@
  * by upper layers.
  */
 
-static int via_set_drive(struct ata_device *drive, unsigned char speed)
+static int via_set_drive(ide_drive_t *drive, unsigned char speed)
 {
-	struct ata_device *peer = drive->channel->drives + (~drive->dn & 1);
-	struct ata_timing t, p;
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
 	unsigned int T, UT;
 
 	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
@@ -181,7 +311,7 @@
 			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
 				drive->dn >> 1, drive->dn & 1);
 
-	T = 1000000000 / system_bus_speed;
+	T = 1000000000 / via_clock;
 
 	switch (via_config->flags & VIA_UDMA) {
 		case VIA_UDMA_33:   UT = T;   break;
@@ -191,14 +321,18 @@
 		default: UT = T;
 	}
 
-	ata_timing_compute(drive, speed, &t, T, UT);
+	ide_timing_compute(drive, speed, &t, T, UT);
 
 	if (peer->present) {
-		ata_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ata_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
 	}
 
-	via_set_speed(drive->channel->pci_dev, drive->dn, &t);
+	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
 
 	return 0;
 }
@@ -208,39 +342,58 @@
  * PIO-only tuning.
  */
 
-static void via82cxxx_tune_drive(struct ata_device *drive, unsigned char pio)
+static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
 {
-	if (!((via_enabled >> drive->channel->unit) & 1))
+	if (!((via_enabled >> HWIF(drive)->channel) & 1))
 		return;
 
 	if (pio == 255) {
-		via_set_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO));
+		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
 		return;
 	}
 
-	via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int __init via_modes_map(struct ata_channel *ch)
+
+/*
+ * via82cxxx_dmaproc() is a callback from upper layers that can do
+ * a lot, but we use it for DMA/PIO tuning only, delegating everything
+ * else to the default ide_dmaproc().
+ */
+
+int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	short w80 = ch->udma_four;
-	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-		  (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0);
 
-	return map;
+	if (func == ide_dma_check) {
+
+		short w80 = HWIF(drive)->udma_four;
+
+		short speed = ide_find_best_mode(drive,
+			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+		via_set_drive(drive, speed);
+
+		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+			? ide_dma_on : ide_dma_off_quietly;
+	}
+
+	return ide_dmaproc(func, drive);
 }
-#endif
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
  * The initialization callback. Here we determine the IDE chip type
  * and initialize its drive independent registers.
  */
 
-static unsigned int __init via82cxxx_init_chipset(struct pci_dev *dev)
+unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *isa = NULL;
 	unsigned char t, v;
@@ -328,84 +481,85 @@
 	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
 
 /*
+ * Determine system bus clock.
+ */
+
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
+		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
+		via_clock = 33333;
+	}
+
+/*
  * Print the boot message.
  */
 
 	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) ATA %s controller on PCI %s\n",
+	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
 		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
 
+/*
+ * Setup /proc/ide/via entry.
+ */
+
+#ifdef CONFIG_PROC_FS
+	if (!via_proc) {
+		via_base = pci_resource_start(dev, 4);
+		bmide_dev = dev;
+		isa_dev = isa;
+		via_display_info = &via_get_info;
+		via_proc = 1;
+	}
+#endif
+
 	return 0;
 }
 
-static unsigned int __init via82cxxx_ata66_check(struct ata_channel *hwif)
+unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
 {
-	return ((via_enabled & via_80w) >> hwif->unit) & 1;
+	return ((via_enabled & via_80w) >> hwif->channel) & 1;
 }
 
-static void __init via82cxxx_init_channel(struct ata_channel *hwif)
+void __init ide_init_via82cxxx(ide_hwif_t *hwif)
 {
 	int i;
 
-	hwif->udma_four = via82cxxx_ata66_check(hwif);
-
 	hwif->tuneproc = &via82cxxx_tune_drive;
 	hwif->speedproc = &via_set_drive;
-	hwif->io_32bit = 1;
+	hwif->autodma = 0;
 
-	hwif->unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
 	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
 		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->unit * 2 + i;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		hwif->highmem = 1;
-		hwif->modes_map = via_modes_map(hwif);
-		hwif->udma_setup = udma_generic_setup;
-	}
+		hwif->dmaproc = &via82cxxx_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
+		if (!noautodma)
+			hwif->autodma = 1;
 #endif
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
 /*
  * We allow the BM-DMA driver to only work on enabled interfaces.
  */
 
-static void __init via82cxxx_init_dma(struct ata_channel *hwif, unsigned long dmabase)
-{
-	if ((via_enabled >> hwif->unit) & 1)
-		ata_init_dma(hwif, dmabase);
-}
-
-/* module data table */
-static struct ata_pci_device chipsets[] __initdata = {
-	{
-		.vendor = PCI_VENDOR_ID_VIA,
-		.device = PCI_DEVICE_ID_VIA_82C576_1,
-		.init_chipset = via82cxxx_init_chipset,
-		.init_channel = via82cxxx_init_channel,
-		.init_dma = via82cxxx_init_dma,
-		.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-		.bootable = ON_BOARD,
-	},
-	{
-		.vendor = PCI_VENDOR_ID_VIA,
-		.device = PCI_DEVICE_ID_VIA_82C586_1,
-		.init_chipset = via82cxxx_init_chipset,
-		.init_channel = via82cxxx_init_channel,
-		.init_dma = via82cxxx_init_dma,
-		.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-		.bootable = ON_BOARD,
-	},
-};
-
-int __init init_via82cxxx(void)
+void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
-		ata_register_chipset(&chipsets[i]);
-
-	return 0;
+	if ((via_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
 }
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/ieee1394/ieee1394_core.c	Tue Aug 27 12:28:02 2002
@@ -22,7 +22,6 @@
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
-#include <asm/smplock.h>
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
diff -Nru a/drivers/input/Config.help b/drivers/input/Config.help
--- a/drivers/input/Config.help	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/Config.help	Tue Aug 27 12:28:02 2002
@@ -15,16 +15,6 @@
   The module will be called input.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_INPUT_KEYBDEV
-  Say Y here if you want your keyboard to be able to serve as a system
-  keyboard. This is needed in most cases. The only exceptions are
-  headless and embedded systems.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called keybdev.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
 CONFIG_INPUT_MOUSEDEV
   Say Y here if you want your mouse to be accessible as char devices
   13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
@@ -98,12 +88,3 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called joydev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_UINPUT
-  Say Y here if you want to support user level drivers for input
-  subsystem accessible under char device 10:223 - /dev/input/uinput.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called uinput.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.	    
diff -Nru a/drivers/input/Config.in b/drivers/input/Config.in
--- a/drivers/input/Config.in	Tue Aug 27 12:28:05 2002
+++ b/drivers/input/Config.in	Tue Aug 27 12:28:05 2002
@@ -5,10 +5,9 @@
 mainmenu_option next_comment
 comment 'Input device support'
 
-tristate 'Input core support' CONFIG_INPUT
+define_tristate CONFIG_INPUT y
 
 comment 'Userland interfaces'
-dep_tristate '  Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
 dep_tristate '  Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
 dep_mbool '    Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT
 if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
@@ -23,7 +22,7 @@
 fi
 dep_tristate '  Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
 dep_tristate '  Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
-dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_EXPERIMENTAL
+
 
 comment 'Input I/O drivers'
 source drivers/input/gameport/Config.in
@@ -35,6 +34,7 @@
    source drivers/input/mouse/Config.in
    source drivers/input/joystick/Config.in
    source drivers/input/touchscreen/Config.in
+   source drivers/input/misc/Config.in
 fi
 
 endmenu
diff -Nru a/drivers/input/Makefile b/drivers/input/Makefile
--- a/drivers/input/Makefile	Tue Aug 27 12:28:08 2002
+++ b/drivers/input/Makefile	Tue Aug 27 12:28:08 2002
@@ -9,19 +9,18 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT)		+= input.o
-obj-$(CONFIG_INPUT_KEYBDEV)	+= keybdev.o
 obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
 obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
 obj-$(CONFIG_INPUT_TSDEV)	+= tsdev.o
 obj-$(CONFIG_INPUT_POWER)	+= power.o
 obj-$(CONFIG_INPUT_EVBUG)	+= evbug.o
-obj-$(CONFIG_INPUT_UINPUT)	+= uinput.o
 
 obj-$(CONFIG_INPUT_KEYBOARD)	+= keyboard/
 obj-$(CONFIG_INPUT_MOUSE)	+= mouse/
 obj-$(CONFIG_INPUT_JOYSTICK)	+= joystick/
 obj-$(CONFIG_INPUT_TOUCHSCREEN)	+= touchscreen/
+obj-$(CONFIG_INPUT_MISC)	+= misc/
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c
--- a/drivers/input/evbug.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/evbug.c	Tue Aug 27 12:28:02 2002
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/init.h>
+#include <linux/device.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Input driver event debug module"); 
@@ -87,8 +88,14 @@
 	.id_table =	evbug_ids,
 };
 
+static struct device_interface evbug_intf = {
+	.name		= "debug",
+	.devclass	= &input_devclass,
+};
+
 int __init evbug_init(void)
 {
+	interface_register(&evbug_intf);
 	input_register_handler(&evbug_handler);
 	return 0;
 }
@@ -96,6 +103,7 @@
 void __exit evbug_exit(void)
 {
 	input_unregister_handler(&evbug_handler);
+	interface_register(&evbug_intf);
 }
 
 module_init(evbug_init);
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/input/evdev.c	Tue Aug 27 12:28:08 2002
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/smp_lock.h>
+#include <linux/device.h>
 
 struct evdev {
 	int exist;
@@ -234,7 +235,7 @@
 	struct evdev *evdev = list->evdev;
 	struct input_dev *dev = evdev->handle.dev;
 	struct input_absinfo abs;
-	int t, u;
+	int i, t, u;
 
 	if (!evdev->exist) return -ENODEV;
 
@@ -258,26 +259,21 @@
 
 		case EVIOCGKEYCODE:
 			if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax) return -EINVAL;
-			switch (dev->keycodesize) {
-				case 1: u = *(u8*)(dev->keycode + t); break;
-				case 2: u = *(u16*)(dev->keycode + t * 2); break;
-				case 4: u = *(u32*)(dev->keycode + t * 4); break;
-				default: return -EINVAL;
-			}
-			if (put_user(u, ((int *) arg) + 1)) return -EFAULT;
+			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			if (put_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
 			return 0;
 
 		case EVIOCSKEYCODE:
 			if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax) return -EINVAL;
-			if (get_user(u, ((int *) arg) + 1)) return -EFAULT;
-			switch (dev->keycodesize) {
-				case 1: *(u8*)(dev->keycode + t) = u; break;
-				case 2: *(u16*)(dev->keycode + t * 2) = u; break;
-				case 4: *(u32*)(dev->keycode + t * 4) = u; break;
-				default: return -EINVAL;
-			}
+			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			u = INPUT_KEYCODE(dev, t);
+			if (get_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
+
+			for (i = 0; i < dev->keycodemax; i++)
+				if(INPUT_KEYCODE(dev, t) == u) break;
+			if (i == dev->keycodemax) clear_bit(u, dev->keybit);
+			set_bit(INPUT_KEYCODE(dev, t), dev->keybit);
+
 			return 0;
 
 		case EVIOCSFF:
@@ -489,8 +485,14 @@
 	.id_table =	evdev_ids,
 };
 
+static struct device_interface evdev_intf = {
+	.name		= "event",
+	.devclass	= &input_devclass,
+};
+
 static int __init evdev_init(void)
 {
+	interface_register(&evdev_intf);
 	input_register_handler(&evdev_handler);
 	return 0;
 }
@@ -498,6 +500,7 @@
 static void __exit evdev_exit(void)
 {
 	input_unregister_handler(&evdev_handler);
+	interface_register(&evdev_intf);
 }
 
 module_init(evdev_init);
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/input/input.c	Tue Aug 27 12:28:07 2002
@@ -37,6 +37,7 @@
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/device.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -57,8 +58,9 @@
 #define INPUT_MAJOR	13
 #define INPUT_DEVICES	256
 
-static struct input_dev *input_dev;
-static struct input_handler *input_handler;
+static LIST_HEAD(input_dev_list);
+static LIST_HEAD(input_handler_list);
+
 static struct input_handler *input_table[8];
 static devfs_handle_t input_devfs_handle;
 
@@ -68,9 +70,10 @@
 static int input_devices_state;
 #endif
 
+
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct input_handle *handle = dev->handle;
+	struct list_head * node;
 
 	if (dev->pm_dev)
 		pm_access(dev->pm_dev);
@@ -105,7 +108,7 @@
 
 			change_bit(code, dev->key);
 
-			if (test_bit(EV_REP, dev->evbit) && value) {
+			if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && value) {
 				dev->repeat_key = code;
 				mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
 			}
@@ -165,10 +168,9 @@
 
 		case EV_SND:
 	
-			if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
+			if (code > SND_MAX || !test_bit(code, dev->sndbit))
 				return;
 
-			change_bit(code, dev->snd);
 			if (dev->event) dev->event(dev, type, code, value);	
 	
 			break;
@@ -190,10 +192,10 @@
 	if (type != EV_SYN) 
 		dev->sync = 0;
 
-	while (handle) {
+	list_for_each(node,&dev->h_list) {
+		struct input_handle *handle = to_handle(node);
 		if (handle->open)
 			handle->handler->event(handle, type, code, value);
-		handle = handle->dnext;
 	}
 }
 
@@ -247,41 +249,8 @@
 
 static void input_link_handle(struct input_handle *handle)
 {
-	handle->dnext = handle->dev->handle;
-	handle->hnext = handle->handler->handle;
-	handle->dev->handle = handle;
-	handle->handler->handle = handle;
-}
-
-/**
- *     input_find_and_remove - Find and remove node
- *
- *     @type:          data type
- *     @initval:       initial value
- *     @targ:          node to find
- *     @next:          next node in the list
- *
- *     Searches the linked list for the target node @targ. If the node
- *     is found, it is removed from the list.
- *
- *     If the node is not found, the end of the list will be hit,
- *     indicating that it wasn't in the list to begin with.
- *
- *     Returns nothing.
- */
-
-#define input_find_and_remove(type, initval, targ, next)		\
-	do {								\
-		type **ptr;						\
-		for (ptr = &initval; *ptr; ptr = &((*ptr)->next))	\
-			if (*ptr == targ) break;			\
-		if (*ptr) *ptr = (*ptr)->next;				\
-	} while (0)
-
-static void input_unlink_handle(struct input_handle *handle)
-{
-	input_find_and_remove(struct input_handle, handle->dev->handle, handle, dnext);
-        input_find_and_remove(struct input_handle, handle->handler->handle, handle, hnext);
+	list_add_tail(&handle->d_node,&handle->dev->h_list);
+	list_add_tail(&handle->h_node,&handle->handler->h_list);
 }
 
 #define MATCH_BIT(bit, max) \
@@ -442,7 +411,7 @@
 
 void input_register_device(struct input_dev *dev)
 {
-	struct input_handler *handler = input_handler;
+	struct list_head * node;
 	struct input_handle *handle;
 	struct input_device_id *id;
 
@@ -465,19 +434,17 @@
 /*
  * Add the device.
  */
-
-	dev->next = input_dev;	
-	input_dev = dev;
+	INIT_LIST_HEAD(&dev->h_list);
+	list_add_tail(&dev->node,&input_dev_list);
 
 /*
  * Notify handlers.
  */
-
-	while (handler) {
+	list_for_each(node,&input_handler_list) {
+		struct input_handler *handler = to_handler(node);
 		if ((id = input_match_device(handler->id_table, dev)))
 			if ((handle = handler->connect(handler, dev, id)))
 				input_link_handle(handle);
-		handler = handler->next;
 	}
 
 /*
@@ -500,8 +467,7 @@
 
 void input_unregister_device(struct input_dev *dev)
 {
-	struct input_handle *handle = dev->handle;
-	struct input_handle *dnext;
+	struct list_head * node, * next;
 
 	if (!dev) return;
 
@@ -521,11 +487,11 @@
  * Notify handlers.
  */
 
-	while (handle) {
-		dnext = handle->dnext;
-		input_unlink_handle(handle);
+	list_for_each_safe(node,next,&dev->h_list) {
+		struct input_handle * handle = to_handle(node);
+		list_del_init(&handle->d_node);
+		list_del_init(&handle->h_node);
 		handle->handler->disconnect(handle);
-		handle = dnext;
 	}
 
 /*
@@ -539,7 +505,7 @@
 /*
  * Remove the device.
  */
-	input_find_and_remove(struct input_dev, input_dev, dev, next);
+	list_del_init(&dev->node);
 
 /*
  * Notify /proc.
@@ -553,12 +519,13 @@
 
 void input_register_handler(struct input_handler *handler)
 {
-	struct input_dev *dev = input_dev;
+	struct list_head * node;
 	struct input_handle *handle;
 	struct input_device_id *id;
 
 	if (!handler) return;
 
+	INIT_LIST_HEAD(&handler->h_list);
 /*
  * Add minors if needed.
  */
@@ -569,19 +536,17 @@
 /*
  * Add the handler.
  */
-
-	handler->next = input_handler;	
-	input_handler = handler;
+	list_add_tail(&handler->node,&input_handler_list);
 	
 /*
  * Notify it about all existing devices.
  */
 
-	while (dev) {
+	list_for_each(node,&input_dev_list) {
+		struct input_dev *dev = to_dev(node);
 		if ((id = input_match_device(handler->id_table, dev)))
 			if ((handle = handler->connect(handler, dev, id)))
 				input_link_handle(handle);
-		dev = dev->next;
 	}
 
 /*
@@ -596,25 +561,23 @@
 
 void input_unregister_handler(struct input_handler *handler)
 {
-	struct input_handle *handle = handler->handle;
-	struct input_handle *hnext;
+	struct list_head * node, * next;
+
 
 /*
  * Tell the handler to disconnect from all devices it keeps open.
  */
-
-	while (handle) {
-		hnext = handle->hnext;
-		input_unlink_handle(handle);
+	list_for_each_safe(node,next,&handler->h_list) {
+		struct input_handle * handle = to_handle_h(node);
+		list_del_init(&handle->h_node);
+		list_del_init(&handle->d_node);
 		handler->disconnect(handle);
-		handle = hnext;
 	}
 
 /*
  * Remove it.
  */
-	input_find_and_remove(struct input_handler, input_handler, handler,
-				next);
+	list_del_init(&handler->node);
 
 /*
  * Remove minors.
@@ -715,13 +678,14 @@
 
 static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
 {
-	struct input_dev *dev = input_dev;
-	struct input_handle *handle;
+	struct list_head * node;
 
 	off_t at = 0;
 	int i, len, cnt = 0;
 
-	while (dev) {
+	list_for_each(node,&input_dev_list) {
+		struct input_dev * dev = to_dev(node);
+		struct list_head * hnode;
 
 		len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
 			dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
@@ -730,11 +694,9 @@
 		len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
 		len += sprintf(buf + len, "D: Drivers=");
 
-		handle = dev->handle;
-
-		while (handle) {
+		list_for_each(hnode,&dev->h_list) {
+			struct input_handle * handle = to_handle(hnode);
 			len += sprintf(buf + len, "%s ", handle->name);
-			handle = handle->dnext;
 		}
 
 		len += sprintf(buf + len, "\n");
@@ -761,24 +723,24 @@
 			if (cnt >= count)
 				break;
 		}
-
-		dev = dev->next;
 	}
 
-	if (!dev) *eof = 1;
+	if (node == &input_dev_list)
+		*eof = 1;
 
 	return (count > cnt) ? cnt : count;
 }
 
 static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
 {
-	struct input_handler *handler = input_handler;
+	struct list_head * node;
 
 	off_t at = 0;
 	int len = 0, cnt = 0;
 	int i = 0;
 
-	while (handler) {
+	list_for_each(node,&input_handler_list) {
+		struct input_handler *handler = to_handler(node);
 
 		if (handler->fops)
 			len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n",
@@ -798,21 +760,25 @@
 			if (cnt >= count)
 				break;
 		}
-
-		handler = handler->next;
 	}
-
-	if (!handler) *eof = 1;
+	if (node == &input_handler_list)
+		*eof = 1;
 
 	return (count > cnt) ? cnt : count;
 }
 
 #endif
 
+struct device_class input_devclass = {
+	.name		= "input",
+};
+
 static int __init input_init(void)
 {
 	struct proc_dir_entry *entry;
 
+	devclass_register(&input_devclass);
+
 #ifdef CONFIG_PROC_FS
 	proc_bus_input_dir = proc_mkdir("input", proc_bus);
 	proc_bus_input_dir->owner = THIS_MODULE;
@@ -842,6 +808,7 @@
 	devfs_unregister(input_devfs_handle);
         if (unregister_chrdev(INPUT_MAJOR, "input"))
                 printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
+	devclass_unregister(&input_devclass);
 }
 
 module_init(input_init);
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/input/joydev.c	Tue Aug 27 12:28:06 2002
@@ -42,6 +42,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/device.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Joystick device interfaces");
@@ -534,8 +535,14 @@
 	.id_table =	joydev_ids,
 };
 
+static struct device_interface joydev_intf = {
+	.name		= "joystick",
+	.devclass	= &input_devclass,
+};
+
 static int __init joydev_init(void)
 {
+	interface_register(&joydev_intf);
 	input_register_handler(&joydev_handler);
 	return 0;
 }
@@ -543,6 +550,7 @@
 static void __exit joydev_exit(void)
 {
 	input_unregister_handler(&joydev_handler);
+	interface_unregister(&joydev_intf);
 }
 
 module_init(joydev_init);
diff -Nru a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
--- a/drivers/input/joystick/Config.help	Tue Aug 27 12:27:59 2002
+++ b/drivers/input/joystick/Config.help	Tue Aug 27 12:27:59 2002
@@ -203,13 +203,13 @@
   The module will be called turbografx.o. If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_JOYSTICK_AMIJOY
+CONFIG_JOYSTICK_AMIGA
   Say Y here if you have an Amiga with a digital joystick connected
   to it.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called joy-amiga.o. If you want to compile it as
+  The module will be called amijoy.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_INPUT_JOYDUMP
diff -Nru a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
--- a/drivers/input/joystick/Config.in	Tue Aug 27 12:28:08 2002
+++ b/drivers/input/joystick/Config.in	Tue Aug 27 12:28:08 2002
@@ -28,7 +28,7 @@
 dep_tristate '  Multisystem joysticks via TurboGraFX device' CONFIG_JOYSTICK_TURBOGRAFX $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
-   dep_tristate '  Amiga joysticks' CONFIG_JOYSTICK_AMIJOY $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
+   dep_tristate '  Amiga joysticks' CONFIG_JOYSTICK_AMIGA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
 fi
 
 dep_tristate '  Gameport data dumper' CONFIG_INPUT_JOYDUMP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
diff -Nru a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
--- a/drivers/input/joystick/amijoy.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/input/joystick/amijoy.c	Tue Aug 27 12:28:07 2002
@@ -37,6 +37,7 @@
 
 #include <asm/system.h>
 #include <asm/amigahw.h>
+#include <asm/amigaints.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Driver for Amiga joysticks");
@@ -78,13 +79,13 @@
 
 	if ((*used)++)
 		return 0;
-	
-	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
+
+	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 		(*used)--;
-		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
+		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 		return -EBUSY;
 	}
-		
+
 	return 0;
 }
 
@@ -99,8 +100,9 @@
 static int __init amijoy_setup(char *str)
 {
 	int i;
-	int ints[4]
-        str = get_options(str, ARRAY_SIZE(ints), ints);
+	int ints[4];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
 	for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
 	return 1;
 }
@@ -110,9 +112,6 @@
 {
 	int i, j;
 
-	init_timer(amijoy_timer);
-	port->timer.function = amijoy_timer;
-
 	for (i = 0; i < 2; i++)
 		if (amijoy[i]) {
 			if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
@@ -134,12 +133,12 @@
 				amijoy_dev[i].absmax[ABS_X + j] = 1;
 			}
 
-			amijoy->dev[i].name = amijoy_name;
-			amijoy->dev[i].phys = amijoy_phys[i];
-			amijoy->dev[i].id.bustype = BUS_AMIGA;
-			amijoy->dev[i].id.vendor = 0x0001;
-			amijoy->dev[i].id.product = 0x0003;
-			amijoy->dev[i].id.version = 0x0100;
+			amijoy_dev[i].name = amijoy_name;
+			amijoy_dev[i].phys = amijoy_phys[i];
+			amijoy_dev[i].id.bustype = BUS_AMIGA;
+			amijoy_dev[i].id.vendor = 0x0001;
+			amijoy_dev[i].id.product = 0x0003;
+			amijoy_dev[i].id.version = 0x0100;
 
 			amijoy_dev[i].private = amijoy_used + i;
 
@@ -149,7 +148,7 @@
 	return 0;
 }
 
-static void _exit amijoy_exit(void)
+static void __exit amijoy_exit(void)
 {
 	int i;
 
diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
--- a/drivers/input/joystick/iforce/iforce-usb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/input/joystick/iforce/iforce-usb.c	Tue Aug 27 12:28:08 2002
@@ -179,7 +179,7 @@
 static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct iforce *iforce = ptr;
-	int open = iforce->dev.handle->open;
+	int open = 0; /* FIXME! iforce->dev.handle->open; */
 
 	iforce->usbdev = NULL;
 	input_unregister_device(&iforce->dev);
diff -Nru a/drivers/input/keybdev.c b/drivers/input/keybdev.c
--- a/drivers/input/keybdev.c	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,229 +0,0 @@
-/*
- * $Id: keybdev.c,v 1.19 2002/03/13 10:09:20 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  Input core to console keyboard binding.
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/config.h>
-#include <linux/kbd_ll.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/kbd_kern.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Input core to console keyboard binding");
-MODULE_LICENSE("GPL");
-
-char keybdev_name[] = "keyboard";
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
-    defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
-    defined(CONFIG_PPC) || defined(__mc68000__) || defined(__hppa__) || \
-    defined(__arm__) || defined(__x86_64__)
-
-static int x86_sysrq_alt = 0;
-#ifdef CONFIG_SPARC64
-static int sparc_l1_a_state = 0;
-#endif
-
-static unsigned short x86_keycodes[256] =
-	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-	 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
-	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
-	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
-	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
-	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
-	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
-	118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269,
-	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
-	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
-	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
-
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-extern int mac_hid_mouse_emulate_buttons(int, int, int);
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
- 
-static int emulate_raw(unsigned int keycode, int down)
-{
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-	if (mac_hid_mouse_emulate_buttons(1, keycode, down))
-		return 0;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
-	if (keycode > 255 || !x86_keycodes[keycode])
-		return -1; 
-
-	if (keycode == KEY_PAUSE) {
-		handle_scancode(0xe1, 1);
-		handle_scancode(0x1d, down);
-		handle_scancode(0x45, down);
-		return 0;
-	} 
-
-	if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
-		handle_scancode(0x54, down);
-
-		return 0;
-	}
-
-#ifdef CONFIG_SPARC64
-	if (keycode == KEY_A && sparc_l1_a_state) {
-		sparc_l1_a_state = 0;
-		sun_do_break();
-	}
-#endif
-
-	if (x86_keycodes[keycode] & 0x100)
-		handle_scancode(0xe0, 1);
-
-	handle_scancode(x86_keycodes[keycode] & 0x7f, down);
-
-	if (keycode == KEY_SYSRQ) {
-		handle_scancode(0xe0, 1);
-		handle_scancode(0x37, down);
-	}
-
-	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
-		x86_sysrq_alt = down;
-#ifdef CONFIG_SPARC64
-	if (keycode == KEY_STOP)
-		sparc_l1_a_state = down;
-#endif
-
-	return 0;
-}
-
-#endif /* CONFIG_X86 || CONFIG_IA64 || __alpha__ || __mips__ || CONFIG_PPC */
-
-static struct input_handler keybdev_handler;
-
-void keybdev_ledfunc(unsigned int led)
-{
-	struct input_handle *handle;	
-
-	for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-		input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
-		input_event(handle->dev, EV_LED, LED_NUML,    !!(led & 0x02));
-		input_event(handle->dev, EV_LED, LED_CAPSL,   !!(led & 0x04));
-		input_sync(handle->dev);
-	}
-}
-
-/* Tell the user who may be running in X and not see the console that we have 
-   panic'ed. This is to distingush panics from "real" lockups. 
-   Could in theory send the panic message as morse, but that is left as an
-   exercise for the reader.  */ 
-
-void panic_blink(void)
-{ 
-	static unsigned long last_jiffie;
-	static char led;
-	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
-	if (time_after(jiffies, last_jiffie + HZ/2)) {
-		led ^= 0x01 | 0x04;
-		keybdev_ledfunc(led);
-		last_jiffie = jiffies;
-	}
-}  
-
-void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
-{
-	if (type != EV_KEY) return;
-	emulate_raw(code, down);
-	tasklet_schedule(&keyboard_tasklet);
-}
-
-static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
-{
-	struct input_handle *handle;
-	int i;
-
-	for (i = KEY_ESC; i < BTN_MISC; i++)
-		if (test_bit(i, dev->keybit))
-			break;
-
-	if (i == BTN_MISC)
- 		return NULL;
-
-	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
-		return NULL;
-	memset(handle, 0, sizeof(struct input_handle));
-
-	handle->dev = dev;
-	handle->name = keybdev_name;
-	handle->handler = handler;
-
-	input_open_device(handle);
-
-	return handle;
-}
-
-static void keybdev_disconnect(struct input_handle *handle)
-{
-	input_close_device(handle);
-	kfree(handle);
-}
-
-static struct input_device_id keybdev_ids[] = {
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-		.evbit = { BIT(EV_KEY) },
-	},	
-	{ }, 	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, keybdev_ids);
-	
-static struct input_handler keybdev_handler = {
-	.event =	keybdev_event,
-	.connect =	keybdev_connect,
-	.disconnect =	keybdev_disconnect,
-	.name =		"keybdev",
-	.id_table =	keybdev_ids,
-};
-
-static int __init keybdev_init(void)
-{
-	input_register_handler(&keybdev_handler);
-	kbd_ledfunc = keybdev_ledfunc;
-	return 0;
-}
-
-static void __exit keybdev_exit(void)
-{
-	kbd_ledfunc = NULL;
-	input_unregister_handler(&keybdev_handler);
-}
-
-module_init(keybdev_init);
-module_exit(keybdev_exit);
-
diff -Nru a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
--- a/drivers/input/keyboard/amikbd.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/keyboard/amikbd.c	Tue Aug 27 12:28:02 2002
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
+#include <linux/delay.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
@@ -51,9 +52,9 @@
 	 57, 14, 15, 96, 28,  1,111,  0,  0,  0, 74,  0,103,108,106,105,
 	 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87,
 	 42, 54, 58, 29, 56,100
-}
+};
 
-static char *amikbd_messages[] = {
+static const char *amikbd_messages[8] = {
 	KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
 	KERN_WARNING "amikbd: keyboard lost sync\n",
 	KERN_WARNING "amikbd: keyboard buffer overflow\n",
@@ -79,19 +80,19 @@
 	ciaa.cra &= ~0x40;		/* switch CIA serial port to input mode */
 
 	down = scancode & 1;		/* lowest bit is release bit */
-	scancode = scancode >> 1;
+	scancode >>= 1;
 
 	if (scancode < 0x78) {		/* scancodes < 0x78 are keys */
 
 		scancode = amikbd_keycode[scancode];
-	
-		if (scancode == KEY_CAPS) {	/* CapsLock is a toggle switch key on Amiga */
+
+		if (scancode == KEY_CAPSLOCK) {	/* CapsLock is a toggle switch key on Amiga */
 			input_report_key(&amikbd_dev, scancode, 1);
 			input_report_key(&amikbd_dev, scancode, 0);
 			input_sync(&amikbd_dev);
 			return;
 		}
-		
+
 		input_report_key(&amikbd_dev, scancode, down);
 		input_sync(&amikbd_dev);
 
@@ -106,20 +107,22 @@
 	int i;
 
 	if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-	 	return -EIO;
+		return -EIO;
 
-	if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))   
+	if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
 		return -EBUSY;
 
-	amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);	
+	amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	amikbd_dev.keycode = amikbd_keycode;
-	
- 	for (i = 0; i < 0x78; i++)
+	amikbd_dev.keycodesize = sizeof(unsigned char);
+	amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode);
+
+	for (i = 0; i < 0x78; i++)
 		if (amikbd_keycode[i])
 			set_bit(amikbd_keycode[i], amikbd_dev.keybit);
 
 	ciaa.cra &= ~0x41;	 /* serial data in, turn off TA */
-	request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL);
+	request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt);
 
 	amikbd_dev.name = amikbd_name;
 	amikbd_dev.phys = amikbd_phys;
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/input/keyboard/atkbd.c	Tue Aug 27 12:28:08 2002
@@ -366,7 +366,7 @@
  */
 
 	if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS))
-		return -1;
+		printk(KERN_WARNING "atkbd.c: keyboard reset failed\n");
 
 /*
  * Next, we check if it's a keyboard. It should send 0xab83
@@ -470,6 +470,8 @@
 	atkbd->serio = serio;
 
 	atkbd->dev.keycode = atkbd->keycode;
+	atkbd->dev.keycodesize = sizeof(unsigned char);
+	atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
 	atkbd->dev.event = atkbd_event;
 	atkbd->dev.private = atkbd;
 
diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- a/drivers/input/keyboard/newtonkbd.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/input/keyboard/newtonkbd.c	Tue Aug 27 12:27:42 2002
@@ -94,6 +94,8 @@
 	nkbd->serio = serio;
 
 	nkbd->dev.keycode = nkbd->keycode;
+	nkbd->dev.keycodesize = sizeof(unsigned char);
+	nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode);
 	nkbd->dev.private = nkbd;
 
 	serio->private = nkbd;
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/input/keyboard/sunkbd.c	Tue Aug 27 12:27:42 2002
@@ -245,6 +245,9 @@
 	sunkbd->tq.data = sunkbd;
 
 	sunkbd->dev.keycode = sunkbd->keycode;
+	sunkbd->dev.keycodesize = sizeof(unsigned char);
+	sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode);
+
 	sunkbd->dev.event = sunkbd_event;
 	sunkbd->dev.private = sunkbd;
 
diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- a/drivers/input/keyboard/xtkbd.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/input/keyboard/xtkbd.c	Tue Aug 27 12:27:42 2002
@@ -101,6 +101,8 @@
 	xtkbd->serio = serio;
 
 	xtkbd->dev.keycode = xtkbd->keycode;
+	xtkbd->dev.keycodesize = sizeof(unsigned char);
+	xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode);
 	xtkbd->dev.private = xtkbd;
 
 	serio->private = xtkbd;
diff -Nru a/drivers/input/misc/Config.help b/drivers/input/misc/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/Config.help	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,28 @@
+CONFIG_INPUT_MISC
+
+  Say Y here, and a list of miscellaneous input drivers will be displayed.
+  Everything that didn't fit into the other categories is here. This option
+  doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_INPUT_PCSPKR
+  Say Y here if you want the standard PC Speaker to be used for
+  bells and whistles.
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pcspkr.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+
+CONFIG_INPUT_UINPUT
+  Say Y here if you want to support user level drivers for input
+  subsystem accessible under char device 10:223 - /dev/input/uinput.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uinput.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.	    
diff -Nru a/drivers/input/misc/Config.in b/drivers/input/misc/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/Config.in	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,8 @@
+#
+# Input misc drivers configuration
+#
+
+bool 'Misc' CONFIG_INPUT_MISC
+
+dep_tristate '  PC Speaker support' CONFIG_INPUT_PCSPKR $CONFIG_INPUT $CONFIG_INPUT_MISC
+dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_INPUT_MISC
diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/Makefile	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,12 @@
+#
+# Makefile for the input misc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
+obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/pcspkr.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,94 @@
+/*
+ *  PC Speaker beeper driver for Linux
+ *
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 1992 Orest Zborowski
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PC Speaker beeper driver");
+MODULE_LICENSE("GPL");
+
+static char *pcspkr_name = "PC Speaker";
+static char *pcspkr_phys = "isa0061/input0";
+static struct input_dev pcspkr_dev;
+
+spinlock_t i8253_beep_lock = SPIN_LOCK_UNLOCKED;
+
+static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	unsigned int count = 0;
+	unsigned long flags;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	} 
+
+	if (value > 20 && value < 32767)
+		count = 1193182 / value;
+	
+	spin_lock_irqsave(&i8253_beep_lock, flags);
+
+	if (count) {
+		/* enable counter 2 */
+		outb_p(inb_p(0x61) | 3, 0x61);
+		/* set command for counter 2, 2 byte write */
+		outb_p(0xB6, 0x43);
+		/* select desired HZ */
+		outb_p(count & 0xff, 0x42);
+		outb((count >> 8) & 0xff, 0x42);
+	} else {
+		/* disable counter 2 */
+		outb(inb_p(0x61) & 0xFC, 0x61);
+	}
+
+	spin_unlock_irqrestore(&i8253_beep_lock, flags);
+
+	return 0;
+}
+
+static int __init pcspkr_init(void)
+{
+	pcspkr_dev.evbit[0] = BIT(EV_SND);
+	pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+	pcspkr_dev.event = pcspkr_event;
+
+	pcspkr_dev.name = pcspkr_name;
+	pcspkr_dev.phys = pcspkr_phys;
+	pcspkr_dev.id.bustype = BUS_ISA;
+	pcspkr_dev.id.vendor = 0x001f;
+	pcspkr_dev.id.product = 0x0001;
+	pcspkr_dev.id.version = 0x0100;
+
+	input_register_device(&pcspkr_dev);
+
+        printk(KERN_INFO "input: %s\n", pcspkr_name);
+
+	return 0;
+}
+
+static void __exit pcspkr_exit(void)
+{
+        input_unregister_device(&pcspkr_dev);
+}
+
+module_init(pcspkr_init);
+module_exit(pcspkr_exit);
diff -Nru a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/uinput.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,385 @@
+/*
+ *  User level driver support for input subsystem
+ *
+ * Heavily based on evdev.c by Vojtech Pavlik
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
+ * 
+ * Changes/Revisions:
+ *	0.1	20/06/2002
+ *		- first public version
+ */
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uinput.h>
+
+static int uinput_dev_open(struct input_dev *dev)
+{
+	return 0;
+}
+
+static void uinput_dev_close(struct input_dev *dev)
+{
+
+}
+
+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct uinput_device	*udev;
+
+	udev = (struct uinput_device *)dev->private;
+
+	udev->head = (udev->head + 1) & 0xF;
+	udev->buff[udev->head].type = type;
+	udev->buff[udev->head].code = code;
+	udev->buff[udev->head].value = value;
+	do_gettimeofday(&udev->buff[udev->head].time);
+
+	wake_up_interruptible(&udev->waitq);
+
+	return 0;
+}
+
+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+{
+	return 0;
+}
+
+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
+{
+	return 0;
+}					
+
+static int uinput_create_device(struct uinput_device *udev)
+{
+	if (!udev->dev->name) {
+		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
+		return -EINVAL;
+	}
+
+	udev->dev->open = uinput_dev_open;
+	udev->dev->close = uinput_dev_close;
+	udev->dev->event = uinput_dev_event;
+	udev->dev->upload_effect = uinput_dev_upload_effect;
+	udev->dev->erase_effect = uinput_dev_erase_effect;
+
+	init_waitqueue_head(&(udev->waitq));
+
+	input_register_device(udev->dev);
+
+	udev->state |= UIST_CREATED;
+
+	return 0;
+}
+
+static int uinput_destroy_device(struct uinput_device *udev)
+{
+	if (!(udev->state & UIST_CREATED)) {
+		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
+		return -EINVAL;
+	}
+
+	input_unregister_device(udev->dev);
+
+	clear_bit(UIST_CREATED, &(udev->state));
+
+	return 0;
+}
+
+static int uinput_open(struct inode *inode, struct file *file)
+{
+	struct uinput_device	*newdev;
+	struct input_dev	*newinput;
+
+	MOD_INC_USE_COUNT;
+
+	newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
+	if (!newdev)
+		goto error;
+	memset(newdev, 0, sizeof(struct uinput_device));
+
+	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
+	if (!newinput)
+		goto cleanup;
+	memset(newinput, 0, sizeof(struct input_dev));
+
+	newdev->dev = newinput;
+	
+	file->private_data = newdev;
+
+	return 0;
+cleanup:
+	kfree(newdev);
+error:
+	MOD_DEC_USE_COUNT;
+	return -ENOMEM;
+}
+
+static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
+{
+	struct uinput_user_dev	user_dev;
+	struct input_dev	*dev;
+	struct uinput_device	*udev;
+	int			size,
+				retval;
+
+	retval = count;
+
+	if (copy_from_user(&user_dev, buffer, sizeof(struct uinput_user_dev))) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	udev = (struct uinput_device *)file->private_data;
+	dev = udev->dev;
+
+	size = strnlen(user_dev.name, UINPUT_MAX_NAME_SIZE);
+	dev->name = kmalloc(size + 1, GFP_KERNEL);
+	if (!dev->name) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	strncpy(dev->name, user_dev.name, size);
+	dev->name[size] = '\0';
+	dev->id.bustype	= user_dev.id.bustype;
+	dev->id.vendor	= user_dev.id.vendor;
+	dev->id.product	= user_dev.id.product;
+	dev->id.version	= user_dev.id.version;
+	dev->ff_effects_max = user_dev.ff_effects_max;
+
+	size = sizeof(unsigned long) * NBITS(ABS_MAX + 1);
+	memcpy(dev->absmax, user_dev.absmax, size);
+	memcpy(dev->absmin, user_dev.absmin, size);
+	memcpy(dev->absfuzz, user_dev.absfuzz, size);
+	memcpy(dev->absflat, user_dev.absflat, size);
+
+	/* check if absmin/absmax/absfuzz/absflat are filled as
+	 * told in Documentation/input/input-programming.txt */
+	if (test_bit(EV_ABS, dev->evbit)) {
+		unsigned int cnt;
+		for (cnt = 1; cnt < ABS_MAX; cnt++)
+			if (test_bit(cnt, dev->absbit) &&
+					(!dev->absmin[cnt] ||
+					 !dev->absmax[cnt] ||
+					 !dev->absfuzz[cnt] ||
+					 !dev->absflat[cnt])) {
+				printk(KERN_DEBUG "%s: set abs fields "
+					"first\n", UINPUT_NAME);
+				retval = -EINVAL;
+				goto free_name;
+			}
+	}
+
+exit:
+	return retval;
+free_name:
+	kfree(dev->name);
+	goto exit;
+}
+
+static int uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device	*udev = file->private_data;
+	
+
+	if (udev->state & UIST_CREATED) {
+		struct input_event	ev;
+
+		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
+			return -EFAULT;
+		input_event(udev->dev, ev.type, ev.code, ev.value);
+	}
+	else
+		count = uinput_alloc_device(file, buffer, count);
+
+	return count;
+}
+
+static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device	*udev;
+	int retval = 0;
+	DECLARE_WAITQUEUE(waitq, current);
+
+	udev = (struct uinput_device *)file->private_data;
+
+	if (udev->head == udev->tail) {
+		add_wait_queue(&udev->waitq, &waitq);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (udev->head == udev->tail) {
+			if (!(udev->state & UIST_CREATED)) {
+				retval = -ENODEV;
+				break;
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&udev->waitq, &waitq);
+	}
+
+	if (retval)
+		return retval;
+
+	while (udev->head != udev->tail && retval + sizeof(struct uinput_device) <= count) {
+		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
+		    sizeof(struct input_event)))
+			return -EFAULT;
+		udev->tail = (udev->tail + 1)%(UINPUT_BUFFER_SIZE - 1);
+		retval += sizeof(struct input_event);
+	}
+
+	return retval;
+}
+
+static unsigned int uinput_poll(struct file *file, poll_table *wait)
+{
+        struct uinput_device *udev = file->private_data;
+
+	poll_wait(file, &udev->waitq, wait);
+
+	if (udev->head != udev->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;			
+}
+
+static int uinput_burn_device(struct uinput_device *udev)
+{
+	if (udev->state & UIST_CREATED)
+		uinput_destroy_device(udev);
+
+	kfree(udev->dev);
+	kfree(udev);
+
+	return 0;
+}
+
+static int uinput_close(struct inode *inode, struct file *file)
+{
+	int	retval;
+
+	retval = uinput_burn_device((struct uinput_device *)file->private_data);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int			retval = 0;
+	struct uinput_device	*udev;
+
+	udev = (struct uinput_device *)file->private_data;
+
+	if (cmd >= UI_SET_EVBIT && (udev->state & UIST_CREATED))
+		return -EINVAL;
+
+	switch (cmd) {
+		case UI_DEV_CREATE:
+			retval = uinput_create_device(udev);
+
+			break;
+		case UI_DEV_DESTROY:
+			retval = uinput_destroy_device(udev);
+
+			break;
+		case UI_SET_EVBIT:
+			set_bit(arg, udev->dev->evbit);
+
+		break;
+		case UI_SET_KEYBIT:
+			set_bit(arg, udev->dev->keybit);
+
+		break;
+		case UI_SET_RELBIT:
+			set_bit(arg, udev->dev->relbit);
+
+		break;
+		case UI_SET_ABSBIT:
+			set_bit(arg, udev->dev->absbit);
+
+		break;
+		case UI_SET_MSCBIT:
+			set_bit(arg, udev->dev->mscbit);
+
+		break;
+		case UI_SET_LEDBIT:
+			set_bit(arg, udev->dev->ledbit);
+
+		break;
+		case UI_SET_SNDBIT:
+			set_bit(arg, udev->dev->sndbit);
+
+		break;
+		case UI_SET_FFBIT:
+			set_bit(arg, udev->dev->ffbit);
+
+		break;
+		default:
+			retval = -EFAULT;
+	}
+	return retval;
+}
+
+struct file_operations uinput_fops = {
+	.owner =	THIS_MODULE,
+	.open =		uinput_open,
+	.release =	uinput_close,
+	.read =		uinput_read,
+	.write =	uinput_write,
+	.poll =		uinput_poll,
+	.ioctl =	uinput_ioctl,
+};
+
+static struct miscdevice uinput_misc = {
+	.fops =		&uinput_fops,
+	.minor =	UINPUT_MINOR,
+	.name =		UINPUT_NAME,
+};
+
+static int __init uinput_init(void)
+{
+	return misc_register(&uinput_misc);
+}
+
+static void __exit uinput_exit(void)
+{
+	misc_deregister(&uinput_misc);
+}
+
+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
+MODULE_DESCRIPTION("User level driver support for input subsystem");
+MODULE_LICENSE("GPL");
+
+module_init(uinput_init);
+module_exit(uinput_exit);
+
diff -Nru a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
--- a/drivers/input/mouse/amimouse.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/input/mouse/amimouse.c	Tue Aug 27 12:28:01 2002
@@ -64,7 +64,7 @@
 
 	input_report_rel(&amimouse_dev, REL_X, dx);
 	input_report_rel(&amimouse_dev, REL_Y, dy);
-	
+
 	input_report_key(&amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
 	input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
 	input_report_key(&amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
@@ -84,9 +84,9 @@
 	amimouse_lastx = joy0dat & 0xff;
 	amimouse_lasty = joy0dat >> 8;
 
-	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", NULL)) {
+	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
                 amimouse_used--;
-                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq);
+                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
                 return -EBUSY;
         }
 
@@ -116,10 +116,11 @@
 	amimouse_dev.id.vendor = 0x0001;
 	amimouse_dev.id.product = 0x0002;
 	amimouse_dev.id.version = 0x0100;
-        
+
 	input_register_device(&amimouse_dev);
 
         printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
+	return 0;
 }
 
 static void __exit amimouse_exit(void)
diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
--- a/drivers/input/mouse/psmouse.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/mouse/psmouse.c	Tue Aug 27 12:28:02 2002
@@ -62,6 +62,7 @@
 	unsigned char cmdcnt;
 	unsigned char pktcnt;
 	unsigned char type;
+	unsigned char model;
 	unsigned long last;
 	char acking;
 	char ack;
@@ -312,6 +313,7 @@
 	param[0] = 0;
 	psmouse->vendor = "Generic";
 	psmouse->name = "Mouse";
+	psmouse->model = 2;
 
 /*
  * Try Genius NetMouse magic init.
@@ -353,11 +355,9 @@
 		static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 };
 		static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
 							76, 80, 81, 83, 88, 96, 97, -1 };
-
-		int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
-
 		psmouse->vendor = "Logitech";
 		psmouse->name = "Mouse";
+		psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
 
 		if (param[1] < 3)
 			clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
@@ -367,21 +367,21 @@
 		psmouse->type = PSMOUSE_PS2;
 
 		for (i = 0; logitech_ps2pp[i] != -1; i++)
-			if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP;
+			if (logitech_ps2pp[i] == psmouse->model) psmouse->type = PSMOUSE_PS2PP;
 
 		if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2;
 
 		for (i = 0; logitech_4btn[i] != -1; i++)
-			if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit);
+			if (logitech_4btn[i] == psmouse->model) set_bit(BTN_SIDE, psmouse->dev.keybit);
 
 		for (i = 0; logitech_wheel[i] != -1; i++)
-			if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit);
+			if (logitech_wheel[i] == psmouse->model) set_bit(REL_WHEEL, psmouse->dev.relbit);
 
 /*
  * Do Logitech PS2++ / PS2T++ magic init.
  */
 
-		if (devicetype == 97) { /* TouchPad 3 */
+		if (psmouse->model == 97) { /* TouchPad 3 */
 
 			set_bit(REL_WHEEL, psmouse->dev.relbit);
 			set_bit(REL_HWHEEL, psmouse->dev.relbit);
@@ -603,7 +603,7 @@
 	psmouse->dev.phys = psmouse->phys;
 	psmouse->dev.id.bustype = BUS_I8042;
 	psmouse->dev.id.vendor = psmouse->type;
-	psmouse->dev.id.product = 0x0002;
+	psmouse->dev.id.product = psmouse->model;
 	psmouse->dev.id.version = 0x0100;
 
 	input_register_device(&psmouse->dev);
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/mousedev.c	Tue Aug 27 12:28:02 2002
@@ -39,6 +39,7 @@
 #include <linux/smp_lock.h>
 #include <linux/random.h>
 #include <linux/major.h>
+#include <linux/device.h>
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
 #include <linux/miscdevice.h>
 #endif
@@ -199,8 +200,9 @@
 
 	if (!--list->mousedev->open) {
 		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			struct input_handle *handle = mousedev_handler.handle;
-			while (handle) {
+			struct list_head * node;
+			list_for_each(node,&mousedev_handler.h_list) {
+				struct input_handle *handle = to_handle_h(node);
 				struct mousedev *mousedev = handle->private;
 				if (!mousedev->open) {
 					if (mousedev->exist) {
@@ -211,7 +213,6 @@
 						kfree(mousedev);
 					}
 				}
-				handle = handle->hnext;
 			}
 		} else {
 			if (!mousedev_mix.open) {
@@ -257,13 +258,13 @@
 
 	if (!list->mousedev->open++) {
 		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			struct input_handle *handle = mousedev_handler.handle;
-			while (handle) {
+			struct list_head * node;
+			list_for_each(node,&mousedev_handler.h_list) {
+				struct input_handle *handle = to_handle_h(node);
 				struct mousedev *mousedev = handle->private;
 				if (!mousedev->open)
 					if (mousedev->exist)	
 						input_open_device(handle);
-				handle = handle->hnext;
 			}
 		} else {
 			if (!mousedev_mix.open)
@@ -516,8 +517,14 @@
 };
 #endif
 
+static struct device_interface mousedev_intf = {
+	.name		= "mouse",
+	.devclass	= &input_devclass,
+};
+
 static int __init mousedev_init(void)
 {
+	interface_register(&mousedev_intf);
 	input_register_handler(&mousedev_handler);
 
 	memset(&mousedev_mix, 0, sizeof(struct mousedev));
@@ -542,6 +549,7 @@
 #endif
 	input_unregister_minor(mousedev_mix.devfs);
 	input_unregister_handler(&mousedev_handler);
+	interface_unregister(&mousedev_intf);
 }
 
 module_init(mousedev_init);
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/input/serio/i8042.c	Tue Aug 27 12:27:59 2002
@@ -54,12 +54,15 @@
 static struct serio i8042_aux_port;
 static unsigned char i8042_initial_ctr;
 static unsigned char i8042_ctr;
+static unsigned char i8042_last_e0;
 struct timer_list i8042_timer;
 
 #ifdef I8042_DEBUG_IO
 static unsigned long i8042_start;
 #endif
 
+extern struct pt_regs *kbd_pt_regs;
+
 static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG];
 static unsigned char i8042_unxlate_table[128] = {
 	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
@@ -345,6 +348,10 @@
 	unsigned char str, data;
 	unsigned int dfl;
 
+#ifdef CONFIG_VT
+	kbd_pt_regs = regs;
+#endif
+
 	spin_lock_irqsave(&i8042_lock, flags);
 
 	while ((str = i8042_read_status()) & I8042_STR_OBF) {
@@ -366,12 +373,15 @@
 					if (data > 0x7f) {
 						if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
 							serio_interrupt(&i8042_kbd_port, 0xf0, dfl);
+							if (i8042_last_e0 && (data == 0xaa || data == 0xb6))
+								set_bit(data & 0x7f, i8042_unxlate_seen);
 							data = i8042_unxlate_table[data & 0x7f];
 						}
 					} else {
 						set_bit(data, i8042_unxlate_seen);
 						data = i8042_unxlate_table[data];
 					}
+					i8042_last_e0 = (data == 0xe0);
 				}
 				serio_interrupt(&i8042_kbd_port, data, dfl);
 			}
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/input/tsdev.c	Tue Aug 27 12:28:02 2002
@@ -40,6 +40,7 @@
 #include <linux/smp_lock.h>
 #include <linux/random.h>
 #include <linux/time.h>
+#include <linux/device.h>
 
 #ifndef CONFIG_INPUT_TSDEV_SCREEN_X
 #define CONFIG_INPUT_TSDEV_SCREEN_X	240
@@ -420,8 +421,14 @@
 	.id_table =	tsdev_ids,
 };
 
+static struct device_interface tsdev_intf = {
+	.name		= "touchscreen",
+	.devclass	= &input_devclass,
+};
+
 static int __init tsdev_init(void)
 {
+	interface_register(&tsdev_intf);
 	input_register_handler(&tsdev_handler);
 	printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
 	return 0;
@@ -430,6 +437,7 @@
 static void __exit tsdev_exit(void)
 {
 	input_unregister_handler(&tsdev_handler);
+	interface_unregister(&tsdev_intf);
 }
 
 module_init(tsdev_init);
diff -Nru a/drivers/input/uinput.c b/drivers/input/uinput.c
--- a/drivers/input/uinput.c	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,385 +0,0 @@
-/*
- *  User level driver support for input subsystem
- *
- * Heavily based on evdev.c by Vojtech Pavlik
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
- * 
- * Changes/Revisions:
- *	0.1	20/06/2002
- *		- first public version
- */
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/smp_lock.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/uinput.h>
-
-static int uinput_dev_open(struct input_dev *dev)
-{
-	return 0;
-}
-
-static void uinput_dev_close(struct input_dev *dev)
-{
-
-}
-
-static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	struct uinput_device	*udev;
-
-	udev = (struct uinput_device *)dev->private;
-
-	udev->head = (udev->head + 1) & 0xF;
-	udev->buff[udev->head].type = type;
-	udev->buff[udev->head].code = code;
-	udev->buff[udev->head].value = value;
-	do_gettimeofday(&udev->buff[udev->head].time);
-
-	wake_up_interruptible(&udev->waitq);
-
-	return 0;
-}
-
-static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-{
-	return 0;
-}
-
-static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
-{
-	return 0;
-}					
-
-static int uinput_create_device(struct uinput_device *udev)
-{
-	if (!udev->dev->name) {
-		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
-		return -EINVAL;
-	}
-
-	udev->dev->open = uinput_dev_open;
-	udev->dev->close = uinput_dev_close;
-	udev->dev->event = uinput_dev_event;
-	udev->dev->upload_effect = uinput_dev_upload_effect;
-	udev->dev->erase_effect = uinput_dev_erase_effect;
-
-	init_waitqueue_head(&(udev->waitq));
-
-	input_register_device(udev->dev);
-
-	udev->state |= UIST_CREATED;
-
-	return 0;
-}
-
-static int uinput_destroy_device(struct uinput_device *udev)
-{
-	if (!(udev->state & UIST_CREATED)) {
-		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
-		return -EINVAL;
-	}
-
-	input_unregister_device(udev->dev);
-
-	clear_bit(UIST_CREATED, &(udev->state));
-
-	return 0;
-}
-
-static int uinput_open(struct inode *inode, struct file *file)
-{
-	struct uinput_device	*newdev;
-	struct input_dev	*newinput;
-
-	MOD_INC_USE_COUNT;
-
-	newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
-	if (!newdev)
-		goto error;
-	memset(newdev, 0, sizeof(struct uinput_device));
-
-	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
-	if (!newinput)
-		goto cleanup;
-	memset(newinput, 0, sizeof(struct input_dev));
-
-	newdev->dev = newinput;
-	
-	file->private_data = newdev;
-
-	return 0;
-cleanup:
-	kfree(newdev);
-error:
-	MOD_DEC_USE_COUNT;
-	return -ENOMEM;
-}
-
-static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
-{
-	struct uinput_user_dev	user_dev;
-	struct input_dev	*dev;
-	struct uinput_device	*udev;
-	int			size,
-				retval;
-
-	retval = count;
-
-	if (copy_from_user(&user_dev, buffer, sizeof(struct uinput_user_dev))) {
-		retval = -EFAULT;
-		goto exit;
-	}
-
-	udev = (struct uinput_device *)file->private_data;
-	dev = udev->dev;
-
-	size = strnlen(user_dev.name, UINPUT_MAX_NAME_SIZE);
-	dev->name = kmalloc(size + 1, GFP_KERNEL);
-	if (!dev->name) {
-		retval = -ENOMEM;
-		goto exit;
-	}
-
-	strncpy(dev->name, user_dev.name, size);
-	dev->name[size] = '\0';
-	dev->id.bustype	= user_dev.id.bustype;
-	dev->id.vendor	= user_dev.id.vendor;
-	dev->id.product	= user_dev.id.product;
-	dev->id.version	= user_dev.id.version;
-	dev->ff_effects_max = user_dev.ff_effects_max;
-
-	size = sizeof(unsigned long) * NBITS(ABS_MAX + 1);
-	memcpy(dev->absmax, user_dev.absmax, size);
-	memcpy(dev->absmin, user_dev.absmin, size);
-	memcpy(dev->absfuzz, user_dev.absfuzz, size);
-	memcpy(dev->absflat, user_dev.absflat, size);
-
-	/* check if absmin/absmax/absfuzz/absflat are filled as
-	 * told in Documentation/input/input-programming.txt */
-	if (test_bit(EV_ABS, dev->evbit)) {
-		unsigned int cnt;
-		for (cnt = 1; cnt < ABS_MAX; cnt++)
-			if (test_bit(cnt, dev->absbit) &&
-					(!dev->absmin[cnt] ||
-					 !dev->absmax[cnt] ||
-					 !dev->absfuzz[cnt] ||
-					 !dev->absflat[cnt])) {
-				printk(KERN_DEBUG "%s: set abs fields "
-					"first\n", UINPUT_NAME);
-				retval = -EINVAL;
-				goto free_name;
-			}
-	}
-
-exit:
-	return retval;
-free_name:
-	kfree(dev->name);
-	goto exit;
-}
-
-static int uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
-{
-	struct uinput_device	*udev = file->private_data;
-	
-
-	if (udev->state & UIST_CREATED) {
-		struct input_event	ev;
-
-		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
-			return -EFAULT;
-		input_event(udev->dev, ev.type, ev.code, ev.value);
-	}
-	else
-		count = uinput_alloc_device(file, buffer, count);
-
-	return count;
-}
-
-static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
-	struct uinput_device	*udev;
-	int retval = 0;
-	DECLARE_WAITQUEUE(waitq, current);
-
-	udev = (struct uinput_device *)file->private_data;
-
-	if (udev->head == udev->tail) {
-		add_wait_queue(&udev->waitq, &waitq);
-		current->state = TASK_INTERRUPTIBLE;
-
-		while (udev->head == udev->tail) {
-			if (!(udev->state & UIST_CREATED)) {
-				retval = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
-			schedule();
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(&udev->waitq, &waitq);
-	}
-
-	if (retval)
-		return retval;
-
-	while (udev->head != udev->tail && retval + sizeof(struct uinput_device) <= count) {
-		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-		    sizeof(struct input_event)))
-			return -EFAULT;
-		udev->tail = (udev->tail + 1)%(UINPUT_BUFFER_SIZE - 1);
-		retval += sizeof(struct input_event);
-	}
-
-	return retval;
-}
-
-static unsigned int uinput_poll(struct file *file, poll_table *wait)
-{
-        struct uinput_device *udev = file->private_data;
-
-	poll_wait(file, &udev->waitq, wait);
-
-	if (udev->head != udev->tail)
-		return POLLIN | POLLRDNORM;
-
-	return 0;			
-}
-
-static int uinput_burn_device(struct uinput_device *udev)
-{
-	if (udev->state & UIST_CREATED)
-		uinput_destroy_device(udev);
-
-	kfree(udev->dev);
-	kfree(udev);
-
-	return 0;
-}
-
-static int uinput_close(struct inode *inode, struct file *file)
-{
-	int	retval;
-
-	retval = uinput_burn_device((struct uinput_device *)file->private_data);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int			retval = 0;
-	struct uinput_device	*udev;
-
-	udev = (struct uinput_device *)file->private_data;
-
-	if (cmd >= UI_SET_EVBIT && (udev->state & UIST_CREATED))
-		return -EINVAL;
-
-	switch (cmd) {
-		case UI_DEV_CREATE:
-			retval = uinput_create_device(udev);
-
-			break;
-		case UI_DEV_DESTROY:
-			retval = uinput_destroy_device(udev);
-
-			break;
-		case UI_SET_EVBIT:
-			set_bit(arg, udev->dev->evbit);
-
-		break;
-		case UI_SET_KEYBIT:
-			set_bit(arg, udev->dev->keybit);
-
-		break;
-		case UI_SET_RELBIT:
-			set_bit(arg, udev->dev->relbit);
-
-		break;
-		case UI_SET_ABSBIT:
-			set_bit(arg, udev->dev->absbit);
-
-		break;
-		case UI_SET_MSCBIT:
-			set_bit(arg, udev->dev->mscbit);
-
-		break;
-		case UI_SET_LEDBIT:
-			set_bit(arg, udev->dev->ledbit);
-
-		break;
-		case UI_SET_SNDBIT:
-			set_bit(arg, udev->dev->sndbit);
-
-		break;
-		case UI_SET_FFBIT:
-			set_bit(arg, udev->dev->ffbit);
-
-		break;
-		default:
-			retval = -EFAULT;
-	}
-	return retval;
-}
-
-struct file_operations uinput_fops = {
-	.owner =	THIS_MODULE,
-	.open =		uinput_open,
-	.release =	uinput_close,
-	.read =		uinput_read,
-	.write =	uinput_write,
-	.poll =		uinput_poll,
-	.ioctl =	uinput_ioctl,
-};
-
-static struct miscdevice uinput_misc = {
-	.fops =		&uinput_fops,
-	.minor =	UINPUT_MINOR,
-	.name =		UINPUT_NAME,
-};
-
-static int __init uinput_init(void)
-{
-	return misc_register(&uinput_misc);
-}
-
-static void __exit uinput_exit(void)
-{
-	misc_deregister(&uinput_misc);
-}
-
-MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
-MODULE_DESCRIPTION("User level driver support for input subsystem");
-MODULE_LICENSE("GPL");
-
-module_init(uinput_init);
-module_exit(uinput_exit);
-
diff -Nru a/drivers/isdn/Config.in b/drivers/isdn/Config.in
--- a/drivers/isdn/Config.in	Tue Aug 27 12:28:07 2002
+++ b/drivers/isdn/Config.in	Tue Aug 27 12:28:07 2002
@@ -22,8 +22,9 @@
       tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI
       if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
          source drivers/isdn/capi/Config.in
-         source drivers/isdn/hardware/Config.in
       fi
+
+      source drivers/isdn/hardware/Config.in
    fi
 fi
 endmenu
diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/capi/capi.c	Tue Aug 27 12:28:08 2002
@@ -957,14 +957,14 @@
 
 static struct file_operations capi_fops =
 {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		capi_read,
-	write:		capi_write,
-	poll:		capi_poll,
-	ioctl:		capi_ioctl,
-	open:		capi_open,
-	release:	capi_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= capi_read,
+	.write		= capi_write,
+	.poll		= capi_poll,
+	.ioctl		= capi_ioctl,
+	.open		= capi_open,
+	.release	= capi_release,
 };
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
diff -Nru a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
--- a/drivers/isdn/capi/capifs.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/isdn/capi/capifs.c	Tue Aug 27 12:28:02 2002
@@ -72,16 +72,16 @@
 static struct inode *capifs_new_inode(struct super_block *sb);
 
 static struct file_operations capifs_root_operations = {
-	read:		generic_read_dir,
-	readdir:	capifs_root_readdir,
+	.read		= generic_read_dir,
+	.readdir	= capifs_root_readdir,
 };
 
 struct inode_operations capifs_root_inode_operations = {
-	lookup: capifs_root_lookup,
+	.lookup = capifs_root_lookup,
 };
 
 static struct dentry_operations capifs_dentry_operations = {
-	d_revalidate: capifs_revalidate,
+	.d_revalidate = capifs_revalidate,
 };
 
 /*
@@ -222,8 +222,8 @@
 }
 
 static struct super_operations capifs_sops = {
-	put_super:	capifs_put_super,
-	statfs:		simple_statfs,
+	.put_super	= capifs_put_super,
+	.statfs		= simple_statfs,
 };
 
 static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
@@ -371,10 +371,10 @@
 }
 
 static struct file_system_type capifs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"capifs",
-	get_sb:		capifs_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "capifs",
+	.get_sb		= capifs_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 void capifs_new_ncci(char type, unsigned int num, kdev_t device)
diff -Nru a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c
--- a/drivers/isdn/capi/capilib.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/capi/capilib.c	Tue Aug 27 12:28:08 2002
@@ -4,7 +4,7 @@
 #include <linux/isdn/capilli.h>
 
 #define DBG(format, arg...) do { \
-printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
 
 struct capilib_msgidqueue {
diff -Nru a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
--- a/drivers/isdn/capi/kcapi.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/isdn/capi/kcapi.h	Tue Aug 27 12:28:02 2002
@@ -16,7 +16,7 @@
 #include <linux/isdn/capilli.h>
 
 #define DBG(format, arg...) do { \
-printk(KERN_INFO __FUNCTION__ ": " format "\n" , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
 
 
diff -Nru a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
--- a/drivers/isdn/capi/kcapi_proc.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/isdn/capi/kcapi_proc.c	Tue Aug 27 12:28:06 2002
@@ -90,17 +90,17 @@
 }
 
 struct seq_operations seq_controller_ops = {
-	start:	controller_start,
-	next:	controller_next,
-	stop:	controller_stop,
-	show:	controller_show,
+	.start	= controller_start,
+	.next	= controller_next,
+	.stop	= controller_stop,
+	.show	= controller_show,
 };
 
 struct seq_operations seq_contrstats_ops = {
-	start:	controller_start,
-	next:	controller_next,
-	stop:	controller_stop,
-	show:	contrstats_show,
+	.start	= controller_start,
+	.next	= controller_next,
+	.stop	= controller_stop,
+	.show	= contrstats_show,
 };
 
 static int seq_controller_open(struct inode *inode, struct file *file)
@@ -114,17 +114,17 @@
 }
 
 static struct file_operations proc_controller_ops = {
-	open:		seq_controller_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= seq_controller_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 static struct file_operations proc_contrstats_ops = {
-	open:		seq_contrstats_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= seq_contrstats_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 // /proc/capi/applications: 
@@ -193,17 +193,17 @@
 }
 
 struct seq_operations seq_applications_ops = {
-	start:	applications_start,
-	next:	applications_next,
-	stop:	applications_stop,
-	show:	applications_show,
+	.start	= applications_start,
+	.next	= applications_next,
+	.stop	= applications_stop,
+	.show	= applications_show,
 };
 
 struct seq_operations seq_applstats_ops = {
-	start:	applications_start,
-	next:	applications_next,
-	stop:	applications_stop,
-	show:	applstats_show,
+	.start	= applications_start,
+	.next	= applications_next,
+	.stop	= applications_stop,
+	.show	= applstats_show,
 };
 
 static int
@@ -219,17 +219,17 @@
 }
 
 static struct file_operations proc_applications_ops = {
-	open:		seq_applications_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= seq_applications_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 static struct file_operations proc_applstats_ops = {
-	open:		seq_applstats_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= seq_applstats_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 static void
diff -Nru a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
--- a/drivers/isdn/divert/divert_procfs.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/divert/divert_procfs.c	Tue Aug 27 12:28:08 2002
@@ -261,14 +261,14 @@
 #ifdef CONFIG_PROC_FS
 static struct file_operations isdn_fops =
 {
-	owner:          THIS_MODULE,
-	llseek:         no_llseek,
-	read:           isdn_divert_read,
-	write:          isdn_divert_write,
-	poll:           isdn_divert_poll,
-	ioctl:          isdn_divert_ioctl,
-	open:           isdn_divert_open,
-	release:        isdn_divert_close,                                      
+	.owner          = THIS_MODULE,
+	.llseek         = no_llseek,
+	.read           = isdn_divert_read,
+	.write          = isdn_divert_write,
+	.poll           = isdn_divert_poll,
+	.ioctl          = isdn_divert_ioctl,
+	.open           = isdn_divert_open,
+	.release        = isdn_divert_close,                                      
 };
 
 /****************************/
diff -Nru a/drivers/isdn/hardware/Config.in b/drivers/isdn/hardware/Config.in
--- a/drivers/isdn/hardware/Config.in	Tue Aug 27 12:28:05 2002
+++ b/drivers/isdn/hardware/Config.in	Tue Aug 27 12:28:05 2002
@@ -2,4 +2,26 @@
 # ISDN hardware drivers
 #
 
-source drivers/isdn/hardware/avm/Config.in
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+  comment 'CAPI hardware drivers'
+  source drivers/isdn/hardware/avm/Config.in
+fi
+
+if [ "$CONFIG_ISDN" != "n" ]; then
+  comment 'ISDN4Linux hardware drivers'
+
+  source drivers/isdn/hisax/Config.in
+
+  mainmenu_option next_comment
+  comment 'Active cards'
+
+  source drivers/isdn/icn/Config.in
+  source drivers/isdn/pcbit/Config.in
+  source drivers/isdn/sc/Config.in
+  source drivers/isdn/act2000/Config.in
+  source drivers/isdn/eicon/Config.in
+  source drivers/isdn/tpam/Config.in
+  source drivers/isdn/hysdn/Config.in
+  endmenu
+fi
+
diff -Nru a/drivers/isdn/hardware/avm/Config.in b/drivers/isdn/hardware/avm/Config.in
--- a/drivers/isdn/hardware/avm/Config.in	Tue Aug 27 12:27:57 2002
+++ b/drivers/isdn/hardware/avm/Config.in	Tue Aug 27 12:27:57 2002
@@ -3,7 +3,7 @@
 #
 
 mainmenu_option next_comment
-comment 'Drivers for active AVM cards'
+comment 'Active AVM cards'
 
 bool 'Support AVM cards' CONFIG_CAPI_AVM
 
diff -Nru a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
--- a/drivers/isdn/hardware/avm/b1pci.c	Tue Aug 27 12:27:54 2002
+++ b/drivers/isdn/hardware/avm/b1pci.c	Tue Aug 27 12:27:54 2002
@@ -352,10 +352,10 @@
 }
 
 static struct pci_driver b1pci_pci_driver = {
-	name:		"b1pci",
-	id_table:	b1pci_pci_tbl,
-	probe:		b1pci_pci_probe,
-	remove:		__devexit_p(b1pci_pci_remove),
+	.name		= "b1pci",
+	.id_table	= b1pci_pci_tbl,
+	.probe		= b1pci_pci_probe,
+	.remove		= __devexit_p(b1pci_pci_remove),
 };
 
 static int __init b1pci_init(void)
diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c	Tue Aug 27 12:27:45 2002
+++ b/drivers/isdn/hardware/avm/c4.c	Tue Aug 27 12:27:47 2002
@@ -1232,10 +1232,10 @@
 }
 
 static struct pci_driver c4_pci_driver = {
-       name:           "c4",
-       id_table:       c4_pci_tbl,
-       probe:          c4_probe,
-       remove:         c4_remove,
+       .name           = "c4",
+       .id_table       = c4_pci_tbl,
+       .probe          = c4_probe,
+       .remove         = c4_remove,
 };
 
 static int __init c4_init(void)
diff -Nru a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
--- a/drivers/isdn/hardware/avm/t1pci.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/hardware/avm/t1pci.c	Tue Aug 27 12:28:01 2002
@@ -215,10 +215,10 @@
 }
 
 static struct pci_driver t1pci_pci_driver = {
-       name:           "t1pci",
-       id_table:       t1pci_pci_tbl,
-       probe:          t1pci_probe,
-       remove:         t1pci_remove,
+       .name           = "t1pci",
+       .id_table       = t1pci_pci_tbl,
+       .probe          = t1pci_probe,
+       .remove         = t1pci_remove,
 };
 
 static int __init t1pci_init(void)
diff -Nru a/drivers/isdn/hisax/Config.in b/drivers/isdn/hisax/Config.in
--- a/drivers/isdn/hisax/Config.in	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/hisax/Config.in	Tue Aug 27 12:28:01 2002
@@ -1,5 +1,5 @@
 mainmenu_option next_comment
-comment 'Passive ISDN cards'
+comment 'Passive cards'
 dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
    comment '  D-channel protocol features'
diff -Nru a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
--- a/drivers/isdn/hisax/config.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/hisax/config.c	Tue Aug 27 12:28:08 2002
@@ -1919,6 +1919,8 @@
 		break;
 	case PH_DEACTIVATE | INDICATION:
 		L1L2(st, pr, NULL);
+		clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		skb_queue_purge(&bcs->squeue);
 		bcs->hw.b_if = NULL;
 		break;
 	case PH_DATA | INDICATION:
@@ -2006,6 +2008,9 @@
 		else
 			set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
+	case PH_DEACTIVATE | REQUEST:
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		skb_queue_purge(&bcs->squeue);
 	default:
 		B_L2L1(b_if, pr, arg);
 		break;
diff -Nru a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
--- a/drivers/isdn/hisax/hisax_debug.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/isdn/hisax/hisax_debug.h	Tue Aug 27 12:28:02 2002
@@ -28,7 +28,7 @@
 
 #define DBG(level, format, arg...) do { \
 if (level & __debug_variable) \
-printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
 
 #define DBG_PACKET(level,data,count) \
diff -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c	Tue Aug 27 12:28:01 2002
@@ -944,17 +944,17 @@
 }
 
 static struct pci_driver fcpci_driver = {
-	name:     "fcpci",
-	probe:    fcpci_probe,
-	remove:   __devexit_p(fcpci_remove),
-	id_table: fcpci_ids,
+	.name     = "fcpci",
+	.probe    = fcpci_probe,
+	.remove   = __devexit_p(fcpci_remove),
+	.id_table = fcpci_ids,
 };
 
 static struct isapnp_driver fcpnp_driver = {
-	name:     "fcpnp",
-	probe:    fcpnp_probe,
-	remove:   __devexit_p(fcpnp_remove),
-	id_table: fcpnp_ids,
+	.name     = "fcpnp",
+	.probe    = fcpnp_probe,
+	.remove   = __devexit_p(fcpnp_remove),
+	.id_table = fcpnp_ids,
 };
 
 static int __init hisax_fcpcipnp_init(void)
diff -Nru a/drivers/isdn/hisax/hisax_hfcpci.c b/drivers/isdn/hisax/hisax_hfcpci.c
--- a/drivers/isdn/hisax/hisax_hfcpci.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/isdn/hisax/hisax_hfcpci.c	Tue Aug 27 12:28:02 2002
@@ -40,12 +40,12 @@
 MODULE_DESCRIPTION("HFC PCI ISDN driver");
 
 #define ID(ven, dev, name)                     \
-        { vendor:      PCI_VENDOR_ID_##ven,    \
-	  device:      PCI_DEVICE_ID_##dev,    \
-	  subvendor:   PCI_ANY_ID,             \
-	  subdevice:   PCI_ANY_ID,             \
-	  class:       0,                      \
-          class_mask:  0,                      \
+        { .vendor      = PCI_VENDOR_ID_##ven,    \
+	  .device      = PCI_DEVICE_ID_##dev,    \
+	  .subvendor   = PCI_ANY_ID,             \
+	  .subdevice   = PCI_ANY_ID,             \
+	  .class       = 0,                      \
+          .class_mask  = 0,                      \
 	  driver_data: (unsigned long) name }
 
 static struct pci_device_id hfcpci_ids[] __devinitdata = {
@@ -1604,10 +1604,10 @@
 }
 
 static struct pci_driver hfcpci_driver = {
-	name:     "hfcpci",
-	probe:    hfcpci_probe,
-	remove:   hfcpci_remove,
-	id_table: hfcpci_ids,
+	.name     = "hfcpci",
+	.probe    = hfcpci_probe,
+	.remove   = hfcpci_remove,
+	.id_table = hfcpci_ids,
 };
 
 static int __init hisax_hfcpci_init(void)
diff -Nru a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
--- a/drivers/isdn/hisax/ipacx.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/isdn/hisax/ipacx.c	Tue Aug 27 12:28:06 2002
@@ -66,9 +66,6 @@
 	if (cs->debug &L1_DEB_ISAC)
 		debugl1(cs, "ph_command (%#x) in (%#x)", command,
 			cs->dc.isac.ph_state);
-//###################################  
-//	printk(KERN_INFO "ph_command (%#x)\n", command);
-//###################################  
 	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
 }
 
@@ -82,9 +79,6 @@
 
 	event = cs->readisac(cs, IPACX_CIR0) >> 4;
 	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
-//#########################################  
-//	printk(KERN_INFO "cic_int(%x)\n", event);
-//#########################################  
   cs->dc.isac.ph_state = event;
   dch_sched_event(cs, D_L1STATECHANGE);
 }
@@ -417,9 +411,6 @@
 	int count;
 
 	istad = cs->readisac(cs, IPACX_ISTAD);
-//##############################################  
-//	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
-//##############################################  
   
 	if (istad &0x80) {  // RME
 	  rstad = cs->readisac(cs, IPACX_RSTAD);
@@ -714,9 +705,6 @@
 
 	bcs = cs->bcs + hscx;
 	istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
-//##############################################  
-//	printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
-//##############################################  
 	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
 
 	if (istab &0x80) {	// RME
@@ -963,15 +951,11 @@
 	u_char ista;
   
 	while ((ista = cs->readisac(cs, IPACX_ISTA))) {
-//#################################################  
-//		printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
-//#################################################  
-    if (ista &0x80) bch_int(cs, 0); // B channel interrupts
-    if (ista &0x40) bch_int(cs, 1);
-    
-    if (ista &0x01) dch_int(cs);    // D channel
-    if (ista &0x10) cic_int(cs);    // Layer 1 state
-  }  
+		if (ista &0x80) bch_int(cs, 0); // B channel interrupts
+		if (ista &0x40) bch_int(cs, 1);
+		if (ista &0x01) dch_int(cs);    // D channel
+		if (ista &0x10) cic_int(cs);    // Layer 1 state
+	}  
 }
 
 //----------------------------------------------------------
@@ -1003,9 +987,6 @@
 init_ipacx(struct IsdnCardState *cs, int part)
 {
 	if (part &1) {  // initialise chip
-//##################################################  
-//	printk(KERN_INFO "init_ipacx(%x)\n", part);
-//##################################################  
 		clear_pending_ints(cs);
 		bch_init(cs, 0);
 		bch_init(cs, 1);
diff -Nru a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
--- a/drivers/isdn/hisax/st5481.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/hisax/st5481.h	Tue Aug 27 12:28:08 2002
@@ -219,13 +219,13 @@
 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
 
 #define ERR(format, arg...) \
-printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_ERR __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
 
 #define WARN(format, arg...) \
-printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_WARNING __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
 
 #define INFO(format, arg...) \
-printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_INFO __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
 
 #include "st5481_hdlc.h"
 #include "fsm.h"
diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
--- a/drivers/isdn/hisax/st5481_init.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/hisax/st5481_init.c	Tue Aug 27 12:28:08 2002
@@ -176,10 +176,10 @@
 MODULE_DEVICE_TABLE (usb, st5481_ids);
 
 static struct usb_driver st5481_usb_driver = {
-	name: "st5481_usb",
-	probe: probe_st5481,
-	disconnect: __devexit_p(disconnect_st5481),
-	id_table: st5481_ids,
+	.name = "st5481_usb",
+	.probe = probe_st5481,
+	.disconnect = __devexit_p(disconnect_st5481),
+	.id_table = st5481_ids,
 };
 
 static int __init st5481_usb_init(void)
diff -Nru a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
--- a/drivers/isdn/hysdn/hysdn_procconf.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/hysdn/hysdn_procconf.c	Tue Aug 27 12:28:01 2002
@@ -377,11 +377,11 @@
 /******************************************************/
 static struct file_operations conf_fops =
 {
-	llseek:         no_llseek,
-	read:           hysdn_conf_read,
-	write:          hysdn_conf_write,
-	open:           hysdn_conf_open,
-	release:        hysdn_conf_close,                                       
+	.llseek         = no_llseek,
+	.read           = hysdn_conf_read,
+	.write          = hysdn_conf_write,
+	.open           = hysdn_conf_open,
+	.release        = hysdn_conf_close,                                       
 };
 
 /*****************************/
diff -Nru a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
--- a/drivers/isdn/hysdn/hysdn_proclog.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/hysdn/hysdn_proclog.c	Tue Aug 27 12:28:01 2002
@@ -389,12 +389,12 @@
 /**************************************************/
 static struct file_operations log_fops =
 {
-	llseek:         no_llseek,
-	read:           hysdn_log_read,
-	write:          hysdn_log_write,
-	poll:           hysdn_log_poll,
-	open:           hysdn_log_open,
-	release:        hysdn_log_close,                                        
+	.llseek         = no_llseek,
+	.read           = hysdn_log_read,
+	.write          = hysdn_log_write,
+	.poll           = hysdn_log_poll,
+	.open           = hysdn_log_open,
+	.release        = hysdn_log_close,                                        
 };
 
 
diff -Nru a/drivers/isdn/i4l/Config.in b/drivers/isdn/i4l/Config.in
--- a/drivers/isdn/i4l/Config.in	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/i4l/Config.in	Tue Aug 27 12:28:01 2002
@@ -24,22 +24,3 @@
    dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
 endmenu
 
-comment 'low-level hardware drivers'
-
-source drivers/isdn/hisax/Config.in
-
-### Active ISDN cards
-
-mainmenu_option next_comment
-comment 'Active ISDN cards'
-
-source drivers/isdn/icn/Config.in
-source drivers/isdn/pcbit/Config.in
-source drivers/isdn/sc/Config.in
-source drivers/isdn/act2000/Config.in
-source drivers/isdn/eicon/Config.in
-source drivers/isdn/tpam/Config.in
-source drivers/isdn/hysdn/Config.in
-
-endmenu
-
diff -Nru a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
--- a/drivers/isdn/i4l/isdn_audio.c	Tue Aug 27 12:27:40 2002
+++ b/drivers/isdn/i4l/isdn_audio.c	Tue Aug 27 12:27:40 2002
@@ -1,9 +1,9 @@
-/* $Id: isdn_audio.c,v 1.21.6.2 2001/09/23 22:24:31 kai Exp $
+/* $Id: isdn_audio.c,v 1.21.6.3 2002/08/13 09:45:33 keil Exp $
  *
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
+ * DTMF code (c) 1996 by Christian Mock (cm@tahina.priv.at)
  * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
  *
  * This software may be used and distributed according to the terms
@@ -15,7 +15,7 @@
 #include "isdn_audio.h"
 #include "isdn_common.h"
 
-char *isdn_audio_revision = "$Revision: 1.21.6.2 $";
+char *isdn_audio_revision = "$Revision: 1.21.6.3 $";
 
 /*
  * Misc. lookup-tables.
diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
--- a/drivers/isdn/i4l/isdn_common.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/isdn/i4l/isdn_common.c	Tue Aug 27 12:28:02 2002
@@ -1090,14 +1090,14 @@
 
 static struct file_operations isdn_status_fops =
 {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		isdn_status_read,
-	write:		isdn_status_write,
-	poll:		isdn_status_poll,
-	ioctl:		isdn_status_ioctl,
-	open:		isdn_status_open,
-	release:	isdn_status_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= isdn_status_read,
+	.write		= isdn_status_write,
+	.poll		= isdn_status_poll,
+	.ioctl		= isdn_status_ioctl,
+	.open		= isdn_status_open,
+	.release	= isdn_status_release,
 };
 
 /*
@@ -1609,14 +1609,14 @@
 
 static struct file_operations isdn_ctrl_fops =
 {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		isdn_ctrl_read,
-	write:		isdn_ctrl_write,
-	poll:		isdn_ctrl_poll,
-	ioctl:		isdn_ctrl_ioctl,
-	open:		isdn_ctrl_open,
-	release:	isdn_ctrl_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= isdn_ctrl_read,
+	.write		= isdn_ctrl_write,
+	.poll		= isdn_ctrl_poll,
+	.ioctl		= isdn_ctrl_ioctl,
+	.open		= isdn_ctrl_open,
+	.release	= isdn_ctrl_release,
 };
 
 /*
@@ -1661,8 +1661,8 @@
 
 static struct file_operations isdn_fops =
 {
-	owner:		THIS_MODULE,
-	open:		isdn_open,
+	.owner		= THIS_MODULE,
+	.open		= isdn_open,
 };
 
 char *
diff -Nru a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
--- a/drivers/isdn/i4l/isdn_net.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/isdn/i4l/isdn_net.c	Tue Aug 27 12:28:06 2002
@@ -48,6 +48,12 @@
 	ST_WAIT_BEFORE_CB,
 };
 
+enum {
+	ST_CHARGE_NULL,
+	ST_CHARGE_GOT_CINF,  /* got a first charge info */
+	ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */
+};
+
 /* keep clear of ISDN_CMD_* and ISDN_STAT_* */
 enum {
 	EV_NET_DIAL            = 0x200,
@@ -349,12 +355,7 @@
  * outgoing packet), if counter exceeds configured limit either do a
  * hangup immediately or - if configured - wait until just before the next
  * charge-info.
- *
- * cps-calculation (needed for dynamic channel-bundling):
- * Since this function is called every second, simply reset the
- * byte-counter of the interface after copying it to the cps-variable.
  */
-unsigned long last_jiffies = -HZ;
 
 void
 isdn_net_autohup()
@@ -366,59 +367,54 @@
 	list_for_each(l, &isdn_net_devs) {
 		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
 		isdn_net_local *l = &p->local;
-		if (jiffies == last_jiffies)
-			l->cps = l->transcount;
-		else
-			l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
-		l->transcount = 0;
-		if (dev->net_verbose > 3)
-			printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
-		if ((l->flags & ISDN_NET_CONNECTED) && (l->dialstate == ST_ACTIVE)) {
+
+		if (!(l->flags & ISDN_NET_CONNECTED) || l->dialstate != ST_ACTIVE)
+			continue;
+
+		if(dev->global_flags & ISDN_GLOBAL_STOPPED || 
+		   ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF) {
+			isdn_net_hangup(&p->dev);
+			continue;
+		}
+		dbg_net_dial("%s: huptimer %d, onhtime %d, chargetime %ld, chargeint %d\n",
+			     l->name, l->huptimer, l->onhtime, l->chargetime, l->chargeint);
+
+		if (!(l->onhtime))
+			continue;
+
+		if (l->huptimer++ <= l->onhtime) {
 			anymore = 1;
-			l->huptimer++;
-			printk("huptimer %d, onhtime %d, chargetime %d, chargeint %d\n", l->huptimer, l->onhtime, l->chargetime, l->chargeint);
-			/*
-			 * if there is some dialmode where timeout-hangup
-			 * should _not_ be done, check for that here
-			 */
-			if ((l->onhtime) &&
-			    (l->huptimer > l->onhtime))
-			{
-				if (l->hupflags & ISDN_MANCHARGE &&
-				    l->hupflags & ISDN_CHARGEHUP) {
-					while (time_after(jiffies, l->chargetime + l->chargeint))
-						l->chargetime += l->chargeint;
-					if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
-						if (l->outgoing || l->hupflags & ISDN_INHUP) {
-							HERE;
-							isdn_net_hangup(&p->dev);
-						}
-				} else if (l->outgoing) {
-					if (l->hupflags & ISDN_CHARGEHUP) {
-						if (l->hupflags & ISDN_WAITCHARGE) {
-							printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
-							       l->name, l->hupflags);
-							isdn_net_hangup(&p->dev);
-						} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
-							printk(KERN_DEBUG
-							       "isdn_net: %s: chtime = %lu, chint = %d\n",
-							       l->name, l->chargetime, l->chargeint);
-							isdn_net_hangup(&p->dev);
-						}
-					}
-				} else if (l->hupflags & ISDN_INHUP) {
-					HERE;
+			continue;
+		}
+		if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) {
+			while (time_after(jiffies, l->chargetime + l->chargeint))
+				l->chargetime += l->chargeint;
+
+			if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) {
+				if (l->outgoing || l->hupflags & ISDN_INHUP) {
 					isdn_net_hangup(&p->dev);
+					continue;
 				}
 			}
-
-			if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
-				isdn_net_hangup(&p->dev);
-				break;
+		} else if (l->outgoing) {
+			if (l->hupflags & ISDN_CHARGEHUP) {
+				if (l->charge_state != ST_CHARGE_HAVE_CINT) {
+					dbg_net_dial("%s: did not get CINT\n", l->name);
+					isdn_net_hangup(&p->dev);
+					continue;
+				} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
+					dbg_net_dial("%s: chtime = %lu, chint = %d\n",
+						     l->name, l->chargetime, l->chargeint);
+					isdn_net_hangup(&p->dev);
+					continue;
+				}
 			}
+		} else if (l->hupflags & ISDN_INHUP) {
+			isdn_net_hangup(&p->dev);
+			continue;
 		}
+		anymore = 1;
 	}
-	last_jiffies = jiffies;
 	isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
 }
 
@@ -453,6 +449,10 @@
 	lp->dialstarted = 0;
 	lp->dialwait_timer = 0;
 	
+	lp->transcount = 0;
+	lp->cps = 0;
+	lp->last_jiffies = jiffies;
+
 #ifdef CONFIG_ISDN_PPP
 	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 		isdn_ppp_wakeup_daemon(lp);
@@ -499,7 +499,7 @@
 		isdn_BUG();
 		return;
 	}
-	printk("%s: %s %#x\n", __FUNCTION__, lp->name, lp->dial_event);
+	printk("%s: %s %#x\n", __FUNCTION__ , lp->name, lp->dial_event);
 	isdn_net_handle_event(lp, lp->dial_event, NULL);
 }
 
@@ -608,13 +608,11 @@
 	}
 	lp->huptimer = 0;
 	lp->outgoing = 1;
-	if (lp->chargeint) {
-		lp->hupflags |= ISDN_HAVECHARGE;
-		lp->hupflags &= ~ISDN_WAITCHARGE;
-	} else {
-		lp->hupflags |= ISDN_WAITCHARGE;
-		lp->hupflags &= ~ISDN_HAVECHARGE;
-	}
+	if (lp->chargeint)
+		lp->charge_state = ST_CHARGE_HAVE_CINT;
+	else
+		lp->charge_state = ST_CHARGE_NULL;
+
 	if (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) {
 		lp->dial_timer.expires = jiffies + lp->cbdelay;
 		lp->dial_event = EV_NET_TIMER_CB;
@@ -701,15 +699,19 @@
 			 * usage by isdn_net_autohup()
 			 */
 			lp->charge++;
-			if (lp->hupflags & ISDN_HAVECHARGE) {
-				lp->hupflags &= ~ISDN_WAITCHARGE;
-				lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
+			switch (lp->charge_state) {
+			case ST_CHARGE_NULL:
+				lp->charge_state = ST_CHARGE_GOT_CINF;
+				break;
+			case ST_CHARGE_GOT_CINF:
+				lp->charge_state = ST_CHARGE_HAVE_CINT;
+				/* fall through */
+			case ST_CHARGE_HAVE_CINT:
+				lp->chargeint = jiffies - lp->chargetime - 2 * HZ;
+				break;
 			}
-			if (lp->hupflags & ISDN_WAITCHARGE)
-				lp->hupflags |= ISDN_HAVECHARGE;
 			lp->chargetime = jiffies;
-			printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
-			       lp->name, lp->chargetime);
+			dbg_net_dial("%s: got CINF\n", lp->name);
 			return 1;
 		}
 		break;
@@ -1054,7 +1056,7 @@
 	int retv = 0;
 
 	if (((isdn_net_local *) (ndev->priv))->master) {
-		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		isdn_BUG();
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -1083,6 +1085,14 @@
 	 * should move to userspace and get based on an overall cps
 	 * calculation
 	 */
+	if (jiffies != lp->last_jiffies) {
+		lp->cps = lp->transcount * HZ / (jiffies - lp->last_jiffies);
+		lp->last_jiffies = jiffies;
+		lp->transcount = 0;
+	}
+	if (dev->net_verbose > 3)
+		printk(KERN_DEBUG "%s: %d bogocps\n", lp->name, lp->cps);
+
 	if (lp->cps > lp->triggercps) {
 		if (lp->slave) {
 			if (!lp->sqfull) {
@@ -2381,8 +2391,7 @@
 
 					lp->outgoing = 0;
 					lp->huptimer = 0;
-					lp->hupflags |= ISDN_WAITCHARGE;
-					lp->hupflags &= ~ISDN_HAVECHARGE;
+					lp->charge_state = ST_CHARGE_NULL;
 					/* Got incoming Call, setup L2 and L3 protocols,
 					 * then wait for D-Channel-connect
 					 */
@@ -2837,8 +2846,9 @@
 		else
 			lp->hupflags &= ~ISDN_INHUP;
 		if (cfg->chargeint > 10) {
-			lp->hupflags |= ISDN_HAVECHARGE | ISDN_MANCHARGE;
 			lp->chargeint = cfg->chargeint * HZ;
+			lp->charge_state = ST_CHARGE_HAVE_CINT;
+			lp->hupflags |= ISDN_MANCHARGE;
 		}
 		if (cfg->p_encap != lp->p_encap) {
 			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
diff -Nru a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
--- a/drivers/isdn/i4l/isdn_net.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/isdn/i4l/isdn_net.h	Tue Aug 27 12:28:08 2002
@@ -12,8 +12,6 @@
  */
 
 			      /* Definitions for hupflags:                */
-#define ISDN_WAITCHARGE  1      /* did not get a charge info yet            */
-#define ISDN_HAVECHARGE  2      /* We know a charge info                    */
 #define ISDN_CHARGEHUP   4      /* We want to use the charge mechanism      */
 #define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
 #define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
diff -Nru a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
--- a/drivers/isdn/i4l/isdn_ppp.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/isdn/i4l/isdn_ppp.c	Tue Aug 27 12:28:07 2002
@@ -852,14 +852,14 @@
 
 struct file_operations isdn_ppp_fops =
 {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		isdn_ppp_read,
-	write:		isdn_ppp_write,
-	poll:		isdn_ppp_poll,
-	ioctl:		isdn_ppp_ioctl,
-	open:		isdn_ppp_open,
-	release:	isdn_ppp_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= isdn_ppp_read,
+	.write		= isdn_ppp_write,
+	.poll		= isdn_ppp_poll,
+	.ioctl		= isdn_ppp_ioctl,
+	.open		= isdn_ppp_open,
+	.release	= isdn_ppp_release,
 };
 
 /*
diff -Nru a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c
--- a/drivers/isdn/tpam/tpam_main.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/isdn/tpam/tpam_main.c	Tue Aug 27 12:28:01 2002
@@ -251,10 +251,10 @@
 MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
 
 static struct pci_driver tpam_driver = {
-	name:		"tpam",
-	id_table:	tpam_pci_tbl,
-	probe:		tpam_probe,
-	remove:		__devexit_p(tpam_remove),
+	.name		= "tpam",
+	.id_table	= tpam_pci_tbl,
+	.probe		= tpam_probe,
+	.remove		= __devexit_p(tpam_remove),
 };
 
 static int __init tpam_init(void) {
diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
--- a/drivers/macintosh/Makefile	Tue Aug 27 12:28:02 2002
+++ b/drivers/macintosh/Makefile	Tue Aug 27 12:28:02 2002
@@ -20,7 +20,7 @@
 ifneq ($(CONFIG_MAC),y)
   obj-$(CONFIG_NVRAM)		+= nvram.o
 endif
-obj-$(CONFIG_MAC_HID)		+= mac_hid.o
+obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_PPC_RTC)		+= rtc.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/macintosh/adbhid.c	Tue Aug 27 12:28:06 2002
@@ -37,7 +37,6 @@
 #include <linux/init.h>
 #include <linux/notifier.h>
 #include <linux/input.h>
-#include <linux/kbd_ll.h>
 
 #include <linux/adb.h>
 #include <linux/cuda.h>
@@ -51,6 +50,8 @@
 #define KEYB_KEYREG	0	/* register # for key up/down data */
 #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
+
+extern struct pt_regs *kbd_pt_regs;
 
 static int adb_message_handler(struct notifier_block *, unsigned long, void *);
 static struct notifier_block adbhid_adb_notifier = {
diff -Nru a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
--- a/drivers/macintosh/mac_hid.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/macintosh/mac_hid.c	Tue Aug 27 12:28:08 2002
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2000 Franz Sirl.
  *
- * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
+ * This file will soon be removed in favor of an uinput userspace tool.
  */
 
 #include <linux/config.h>
@@ -16,36 +16,14 @@
 #include <linux/module.h>
 
 
-static unsigned char e0_keys[128] = {
-	0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0,		/* 0x00-0x07 */
-	0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0,			/* 0x08-0x0f */
-	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x10-0x17 */
-	0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, KEY_VOLUMEUP, 0,/* 0x18-0x1f */
-	0, 0, 0, 0, 0, KEY_VOLUMEDOWN, KEY_MUTE, 0,		/* 0x20-0x27 */
-	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x28-0x2f */
-	0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ,		/* 0x30-0x37 */
-	KEY_RIGHTALT, KEY_BRIGHTNESSUP, KEY_BRIGHTNESSDOWN, 
-		KEY_EJECTCD, 0, 0, 0, 0,			/* 0x38-0x3f */
-	0, 0, 0, 0, 0, 0, 0, KEY_HOME,				/* 0x40-0x47 */
-	KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */
-	KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */
-	0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, KEY_POWER, 0, /* 0x58-0x5f */
-	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x60-0x67 */
-	0, 0, 0, 0, 0, 0, 0, KEY_MACRO,				/* 0x68-0x6f */
-	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x70-0x77 */
-	0, 0, 0, 0, 0, 0, 0, 0					/* 0x78-0x7f */
-};
-
-#ifdef CONFIG_MAC_EMUMOUSEBTN
 static struct input_dev emumousebtn;
 static void emumousebtn_input_register(void);
 static int mouse_emulate_buttons = 0;
 static int mouse_button2_keycode = KEY_RIGHTCTRL;	/* right control key */
 static int mouse_button3_keycode = KEY_RIGHTALT;	/* right option key */
 static int mouse_last_keycode = 0;
-#endif
 
-#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
+#if defined(CONFIG_SYSCTL)
 /* file(s) in /proc/sys/dev/mac_hid */
 ctl_table mac_hid_files[] =
 {
@@ -85,76 +63,11 @@
 
 #endif /* endif CONFIG_SYSCTL */
 
-int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
-			  char raw_mode)
-{
-	/* This code was copied from char/pc_keyb.c and will be
-	 * superflous when the input layer is fully integrated.
-	 * We don't need the high_keys handling, so this part
-	 * has been removed.
-	 */
-	static int prev_scancode = 0;
-
-	/* special prefix scancodes.. */
-	if (scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
-		return 0;
-	}
-
-	scancode &= 0x7f;
-
-	if (prev_scancode) {
-		if (prev_scancode != 0xe0) {
-			if (prev_scancode == 0xe1 && scancode == 0x1d) {
-				prev_scancode = 0x100;
-				return 0;
-			} else if (prev_scancode == 0x100 && scancode == 0x45) {
-				*keycode = KEY_PAUSE;
-				prev_scancode = 0;
-			} else {
-				if (!raw_mode)
-					printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-				prev_scancode = 0;
-				return 0;
-			}
-		} else {
-			prev_scancode = 0;
-			if (scancode == 0x2a || scancode == 0x36)
-				return 0;
-		}
-		if (e0_keys[scancode])
-			*keycode = e0_keys[scancode];
-		else {
-			if (!raw_mode)
-				printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-				       scancode);
-			return 0;
-		}
-	} else {
-		switch (scancode) {
-		case  91: scancode = KEY_LINEFEED; break;
-		case  92: scancode = KEY_KPEQUAL; break;
-		case 125: scancode = KEY_INTL1; break;
-		}
-		*keycode = scancode;
-	}
-	return 1;
-}
-
-char mac_hid_kbd_unexpected_up(unsigned char keycode)
-{
-	if (keycode == KEY_F13)
-		return 0;
-	else
-		return 0x80;
-}
-
-#ifdef CONFIG_MAC_EMUMOUSEBTN
 int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
 {
 	switch (caller) {
 	case 1:
-		/* Called from keybdev.c */
+		/* Called from keyboard.c */
 		if (mouse_emulate_buttons
 		    && (keycode == mouse_button2_keycode
 			|| keycode == mouse_button3_keycode)) {
@@ -191,16 +104,13 @@
 
 	printk(KERN_INFO "input: Macintosh mouse button emulation\n");
 }
-#endif
 
 int __init mac_hid_init(void)
 {
 
-#ifdef CONFIG_MAC_EMUMOUSEBTN
 	emumousebtn_input_register();
-#endif
 
-#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
+#if defined(CONFIG_SYSCTL)
 	mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
 #endif /* CONFIG_SYSCTL */
 
diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/md/linear.c	Tue Aug 27 12:28:02 2002
@@ -55,12 +55,12 @@
 		int j = rdev->raid_disk;
 		dev_info_t *disk = conf->disks + j;
 
-		if (j < 0 || j > mddev->raid_disks || disk->bdev) {
+		if (j < 0 || j > mddev->raid_disks || disk->rdev) {
 			printk("linear: disk numbering problem. Aborting!\n");
 			goto out;
 		}
 
-		disk->bdev = rdev->bdev;
+		disk->rdev = rdev;
 		disk->size = rdev->size;
 
 		if (!conf->smallest || (disk->size < conf->smallest->size))
@@ -153,11 +153,11 @@
     
 	if (block >= (tmp_dev->size + tmp_dev->offset)
 				|| block < tmp_dev->offset) {
-		printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, bdevname(tmp_dev->bdev), tmp_dev->size, tmp_dev->offset);
+		printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, bdevname(tmp_dev->rdev->bdev), tmp_dev->size, tmp_dev->offset);
 		bio_io_error(bio);
 		return 0;
 	}
-	bio->bi_bdev = tmp_dev->bdev;
+	bio->bi_bdev = tmp_dev->rdev->bdev;
 	bio->bi_sector = bio->bi_sector - (tmp_dev->offset << 1);
 
 	return 1;
@@ -176,11 +176,11 @@
 	for (j = 0; j < conf->nr_zones; j++)
 	{
 		sz += sprintf(page+sz, "[%s",
-			bdev_partition_name(conf->hash_table[j].dev0->bdev));
+			bdev_partition_name(conf->hash_table[j].dev0->rdev->bdev));
 
 		if (conf->hash_table[j].dev1)
 			sz += sprintf(page+sz, "/%s] ",
-			  bdev_partition_name(conf->hash_table[j].dev1->bdev));
+			  bdev_partition_name(conf->hash_table[j].dev1->rdev->bdev));
 		else
 			sz += sprintf(page+sz, "] ");
 	}
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/md/md.c	Tue Aug 27 12:28:02 2002
@@ -116,16 +116,7 @@
 static struct block_device_operations md_fops;
 static devfs_handle_t devfs_handle;
 
-static struct gendisk md_gendisk=
-{
-	.major		= MD_MAJOR,
-	.major_name	= "md",
-	.minor_shift	= 0,
-	.part		= md_hd_struct,
-	.nr_real	= MAX_MD_DEVS,
-	.next		= NULL,
-	.fops		= &md_fops,
-};
+static struct gendisk *disks[MAX_MD_DEVS];
 
 /*
  * Enables to iterate over all existing md arrays
@@ -242,7 +233,7 @@
 	struct list_head *tmp;
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		if (rdev->raid_disk == nr)
+		if (rdev->desc_nr == nr)
 			return rdev;
 	}
 	return NULL;
@@ -260,18 +251,6 @@
 	return NULL;
 }
 
-static mdk_rdev_t * find_rdev_bdev(mddev_t * mddev, struct block_device *bdev)
-{
-	struct list_head *tmp;
-	mdk_rdev_t *rdev;
-
-	ITERATE_RDEV(mddev,rdev,tmp) {
-		if (rdev->bdev == bdev)
-			return rdev;
-	}
-	return NULL;
-}
-
 static LIST_HEAD(device_names);
 
 char * partition_name(kdev_t dev)
@@ -386,9 +365,6 @@
 		rdev->sb_page = NULL;
 		rdev->sb_offset = 0;
 		rdev->size = 0;
-	} else {
-		if (!rdev->faulty)
-			MD_BUG();
 	}
 }
 
@@ -603,11 +579,10 @@
 		MD_BUG();
 	free_disk_sb(rdev);
 	list_del_init(&rdev->same_set);
-	unlock_rdev(rdev);
 #ifndef MODULE
 	md_autodetect_dev(rdev->bdev->bd_dev);
 #endif
-	rdev->faulty = 0;
+	unlock_rdev(rdev);
 	kfree(rdev);
 }
 
@@ -692,9 +667,9 @@
 
 static void print_rdev(mdk_rdev_t *rdev)
 {
-	printk(KERN_INFO "md: rdev %s, SZ:%08ld F:%d DN:%d ",
+	printk(KERN_INFO "md: rdev %s, SZ:%08ld F:%d S:%d DN:%d ",
 		bdev_partition_name(rdev->bdev),
-		rdev->size, rdev->faulty, rdev->desc_nr);
+		rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr);
 	if (rdev->sb) {
 		printk(KERN_INFO "md: rdev superblock:\n");
 		print_sb(rdev->sb);
@@ -825,6 +800,7 @@
 	mdk_rdev_t *rdev;
 	mdp_super_t *sb;
 	struct list_head *tmp;
+	int next_spare = mddev->raid_disks;
 
 	/* make all rdev->sb match mddev data..
 	 * we setup the data in the first rdev and copy it
@@ -877,12 +853,20 @@
 
 	sb->disks[0].state = (1<<MD_DISK_REMOVED);
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		mdp_disk_t *d = &sb->disks[rdev->desc_nr];
+		mdp_disk_t *d;
+		if (rdev->raid_disk >= 0)
+			rdev->desc_nr = rdev->raid_disk;
+		else
+			rdev->desc_nr = next_spare++;
+		d = &sb->disks[rdev->desc_nr];
 		nr_disks++;
 		d->number = rdev->desc_nr;
 		d->major = MAJOR(rdev->bdev->bd_dev);
 		d->minor = MINOR(rdev->bdev->bd_dev);
-		d->raid_disk = rdev->raid_disk;
+		if (rdev->raid_disk >= 0)
+			d->raid_disk = rdev->raid_disk;
+		else
+			d->raid_disk = rdev->desc_nr; /* compatability */
 		if (rdev->faulty) {
 			d->state = (1<<MD_DISK_FAULTY);
 			failed++;
@@ -918,8 +902,6 @@
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		mdp_super_t *this_sb;
 		
-		if (rdev->faulty || rdev->alias_device)
-			continue;
 		this_sb = rdev->sb;
 		if (this_sb != sb)
 			*this_sb = *sb;
@@ -965,16 +947,17 @@
 		printk(KERN_INFO "md: ");
 		if (rdev->faulty)
 			printk("(skipping faulty ");
-		if (rdev->alias_device)
-			printk("(skipping alias ");
 
 		printk("%s ", bdev_partition_name(rdev->bdev));
-		if (!rdev->faulty && !rdev->alias_device) {
+		if (!rdev->faulty) {
 			printk("[events: %08lx]",
 				(unsigned long)rdev->sb->events_lo);
 			err += write_disk_sb(rdev);
 		} else
 			printk(")\n");
+		if (!err && mddev->level == LEVEL_MULTIPATH)
+			/* only need to write one superblock... */
+			break;
 	}
 	if (err) {
 		if (--count) {
@@ -1019,6 +1002,8 @@
 	}
 	rdev->desc_nr = -1;
 	rdev->faulty = 0;
+	rdev->in_sync = 0;
+	atomic_set(&rdev->nr_pending, 0);
 
 	size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	if (!size) {
@@ -1207,7 +1192,6 @@
 	i = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		if (mddev->level == LEVEL_MULTIPATH) {
-			rdev->alias_device = !!i;
 			rdev->desc_nr = i++;
 			rdev->raid_disk = rdev->desc_nr;
 			rdev->in_sync = 1;
@@ -1215,15 +1199,17 @@
 			mdp_disk_t *desc;
 			rdev->desc_nr = rdev->sb->this_disk.number;
 			desc = sb->disks + rdev->desc_nr;
-			rdev->raid_disk = desc->raid_disk;
+			rdev->raid_disk = -1;
 			rdev->in_sync = rdev->faulty = 0;
 
 			if (desc->state & (1<<MD_DISK_FAULTY)) {
 				rdev->faulty = 1;
 				kick_rdev_from_array(rdev);
 			} else if (desc->state & (1<<MD_DISK_SYNC) &&
-				 rdev->raid_disk < mddev->raid_disks)
+				   desc->raid_disk < mddev->raid_disks) {
 				rdev->in_sync = 1;
+				rdev->raid_disk = desc->raid_disk;
+			}
 		}
 	}
 
@@ -1353,6 +1339,8 @@
 	int chunk_size;
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
+	struct gendisk *disk;
+	char *major_name;
 
 
 	if (list_empty(&mddev->disks)) {
@@ -1406,10 +1394,7 @@
 			printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE);
 			return -EINVAL;
 		}
-	} else
-		if (chunk_size)
-			printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n",
-			       mddev->level);
+	}
 
 	if (pnum >= MAX_PERSONALITY) {
 		MD_BUG();
@@ -1458,6 +1443,25 @@
 			md_blocksizes[mdidx(mddev)] = bdev_hardsect_size(rdev->bdev);
 #endif
 	}
+
+	disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+	if (!disk)
+		return -ENOMEM;
+	memset(disk, 0, sizeof(struct gendisk));
+	major_name = kmalloc(6, GFP_KERNEL);
+	if (!major_name) {
+		kfree(disk);
+		return -ENOMEM;
+	}
+	disk->major = MD_MAJOR;
+	disk->first_minor = mdidx(mddev);
+	disk->minor_shift = 0;
+	sprintf(major_name, "md%d", mdidx(mddev));
+	disk->major_name = major_name;
+	disk->part = md_hd_struct + mdidx(mddev);
+	disk->nr_real = 1;
+	disk->fops = &md_fops;
+
 	mddev->pers = pers[pnum];
 
 	blk_queue_make_request(&mddev->queue, mddev->pers->make_request);
@@ -1467,6 +1471,8 @@
 	if (err) {
 		printk(KERN_ERR "md: pers->run() failed ...\n");
 		mddev->pers = NULL;
+		kfree(disk->major_name);
+		kfree(disk);
 		return -EINVAL;
 	}
 
@@ -1477,15 +1483,11 @@
 	if (mddev->pers->sync_request)
 		mddev->state &= ~(1 << MD_SB_CLEAN);
 	md_update_sb(mddev);
-
 	md_recover_arrays();
-	/*
-	 * md_size has units of 1K blocks, which are
-	 * twice as large as sectors.
-	 */
-	md_hd_struct[mdidx(mddev)].start_sect = 0;
-	register_disk(&md_gendisk, mk_kdev(MAJOR_NR,mdidx(mddev)),
+	add_gendisk(disk);
+	register_disk(disk, mk_kdev(disk->major,disk->first_minor),
 			1, &md_fops, md_size[mdidx(mddev)]<<1);
+	disks[mdidx(mddev)] = disk;
 
 	return (0);
 }
@@ -1538,6 +1540,7 @@
 {
 	int err = 0;
 	kdev_t dev = mddev_to_kdev(mddev);
+	struct gendisk *disk;
 
 	if (atomic_read(&mddev->active)>1) {
 		printk(STILL_IN_USE, mdidx(mddev));
@@ -1551,10 +1554,6 @@
 				mddev->recovery_running = -EINTR;
 			md_unregister_thread(mddev->sync_thread);
 			mddev->sync_thread = NULL;
-			if (mddev->spare) {
-				mddev->pers->spare_inactive(mddev);
-				mddev->spare = NULL;
-			}
 		}
 
 		invalidate_device(dev, 1);
@@ -1590,6 +1589,14 @@
 		if (ro)
 			set_device_ro(dev, 1);
 	}
+	disk = disks[mdidx(mddev)];
+	disks[mdidx(mddev)] = NULL;
+
+	if (disk) {
+		del_gendisk(disk);
+		kfree(disk->major_name);
+		kfree(disk);
+	}
 
 	/*
 	 * Free resources if final stop
@@ -1917,7 +1924,7 @@
 		}
 	} else {
 		info.major = info.minor = 0;
-		info.raid_disk = 0;
+		info.raid_disk = -1;
 		info.state = (1<<MD_DISK_REMOVED);
 	}
 
@@ -1967,7 +1974,11 @@
 			return PTR_ERR(rdev);
 		}
 		rdev->desc_nr = info->number;
-		rdev->raid_disk = info->raid_disk;
+		if (info->raid_disk < mddev->raid_disks)
+			rdev->raid_disk = info->raid_disk;
+		else
+			rdev->raid_disk = -1;
+
 		rdev->faulty = 0;
 		if (rdev->raid_disk < mddev->raid_disks)
 			rdev->in_sync = (info->state & (1<<MD_DISK_SYNC));
@@ -2026,7 +2037,6 @@
 
 static int hot_remove_disk(mddev_t * mddev, dev_t dev)
 {
-	int err;
 	mdk_rdev_t *rdev;
 
 	if (!mddev->pers)
@@ -2035,29 +2045,13 @@
 	printk(KERN_INFO "md: trying to remove %s from md%d ... \n",
 		partition_name(to_kdev_t(dev)), mdidx(mddev));
 
-	if (!mddev->pers->hot_remove_disk) {
-		printk(KERN_WARNING "md%d: personality does not support diskops!\n",
-		       mdidx(mddev));
-		return -EINVAL;
-	}
-
 	rdev = find_rdev(mddev, dev);
 	if (!rdev)
 		return -ENXIO;
 
-	if (rdev->in_sync && ! rdev->faulty)
+	if (rdev->raid_disk >= 0)
 		goto busy;
 
-	err = mddev->pers->hot_remove_disk(mddev, rdev->raid_disk);
-	if (err == -EBUSY) {
-		MD_BUG();
-		goto busy;
-	}
-	if (err) {
-		MD_BUG();
-		return -EINVAL;
-	}
-
 	kick_rdev_from_array(rdev);
 	md_update_sb(mddev);
 
@@ -2129,13 +2123,7 @@
 	}
 
 	rdev->desc_nr = i;
-	rdev->raid_disk = i;
-
-	if (mddev->pers->hot_add_disk(mddev, rdev)) {
-		MD_BUG();
-		err = -EINVAL;
-		goto abort_unbind_export;
-	}
+	rdev->raid_disk = -1;
 
 	md_update_sb(mddev);
 
@@ -2188,14 +2176,13 @@
 static int set_disk_faulty(mddev_t *mddev, dev_t dev)
 {
 	mdk_rdev_t *rdev;
-	int ret;
 
 	rdev = find_rdev(mddev, dev);
 	if (!rdev)
 		return 0;
 
-	ret = md_error(mddev, rdev->bdev);
-	return ret;
+	md_error(mddev, rdev);
+	return 1;
 }
 
 static int md_ioctl(struct inode *inode, struct file *file,
@@ -2418,9 +2405,10 @@
 		}
 
 		default:
-			printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, "
-			       "upgrade your software to use new ictls.\n",
-			       current->comm, current->pid);
+			if (_IOC_TYPE(cmd) == MD_MAJOR)
+				printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, "
+				       "upgrade your software to use new ictls.\n",
+				       current->comm, current->pid);
 			err = -EINVAL;
 			goto abort_unlock;
 	}
@@ -2610,10 +2598,8 @@
 }
 
 
-int md_error(mddev_t *mddev, struct block_device *bdev)
+void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
-	mdk_rdev_t * rrdev;
-
 	dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
 		MD_MAJOR,mdidx(mddev),MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev),
 		__builtin_return_address(0),__builtin_return_address(1),
@@ -2621,25 +2607,15 @@
 
 	if (!mddev) {
 		MD_BUG();
-		return 0;
+		return;
 	}
-	rrdev = find_rdev_bdev(mddev, bdev);
-	if (!rrdev || rrdev->faulty)
-		return 0;
-	if (!mddev->pers->error_handler
-			|| mddev->pers->error_handler(mddev,bdev) <= 0) {
-		rrdev->faulty = 1;
-		rrdev->in_sync = 0;
-	} else
-		return 1;
-	/*
-	 * if recovery was running, stop it now.
-	 */
-	if (mddev->recovery_running) 
-		mddev->recovery_running = -EIO;
-	md_recover_arrays();
 
-	return 0;
+	if (!rdev || rdev->faulty)
+		return;
+	if (!mddev->pers->error_handler)
+		return;
+	mddev->pers->error_handler(mddev,rdev);
+	md_recover_arrays();
 }
 
 static int status_unused(char * page)
@@ -2690,7 +2666,7 @@
 		sz += sprintf(page + sz, "] ");
 	}
 	sz += sprintf(page + sz, " %s =%3lu.%lu%% (%lu/%lu)",
-		      (mddev->spare ? "recovery" : "resync"),
+		      (mddev->spares ? "recovery" : "resync"),
 		      res/10, res % 10, resync, max_blocks);
 
 	/*
@@ -2808,26 +2784,10 @@
 	return 0;
 }
 
-static mdk_rdev_t *get_spare(mddev_t *mddev)
-{
-	mdk_rdev_t *rdev;
-	struct list_head *tmp;
-
-	ITERATE_RDEV(mddev,rdev,tmp) {
-		if (rdev->faulty)
-			continue;
-		if (rdev->in_sync)
-			continue;
-
-		return rdev;
-	}
-	return NULL;
-}
-
 static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK];
-void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors)
+void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors)
 {
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	kdev_t dev = to_kdev_t(rdev->bdev->bd_dev);
 	unsigned int major = major(dev);
 	unsigned int index;
 
@@ -3041,19 +3001,30 @@
 
 
 /*
- * This is the kernel thread that watches all md arrays for re-sync action
- * that might be needed.
+ * This is the kernel thread that watches all md arrays for re-sync and other
+ * action that might be needed.
  * It does not do any resync itself, but rather "forks" off other threads
  * to do that as needed.
  * When it is determined that resync is needed, we set "->recovery_running" and
  * create a thread at ->sync_thread.
- * When the thread finishes is clears recovery_running (or set and error)
+ * When the thread finishes it clears recovery_running (or sets an error)
  * and wakeup up this thread which will reap the thread and finish up.
+ * This thread also removes any faulty devices (with nr_pending == 0).
+ *
+ * The overall approach is:
+ *  1/ if the superblock needs updating, update it.
+ *  2/ If a recovery thread is running, don't do anything else.
+ *  3/ If recovery has finished, clean up, possibly marking spares active.
+ *  4/ If there are any faulty devices, remove them.
+ *  5/ If array is degraded, try to add spares devices
+ *  6/ If array has spares or is not in-sync, start a resync thread.
  */
 void md_do_recovery(void *data)
 {
 	mddev_t *mddev;
-	struct list_head *tmp;
+	mdk_rdev_t *rdev;
+	struct list_head *tmp, *rtmp;
+
 
 	dprintk(KERN_INFO "md: recovery thread got woken up ...\n");
 
@@ -3069,26 +3040,11 @@
 			/* resync has finished, collect result */
 			md_unregister_thread(mddev->sync_thread);
 			mddev->sync_thread = NULL;
-			if (mddev->recovery_running < 0) {
-				/* some sort of failure.
-				 * If we were doing a reconstruction,
-				 * we need to retrieve the spare
-				 */
-				if (!mddev->pers->spare_inactive)
-					goto unlock;
-				if (mddev->spare) {
-					mddev->pers->spare_inactive(mddev);
-					mddev->spare = NULL;
-				}
-			} else {
-				if (!mddev->pers->spare_active)
-					goto unlock;
+			if (mddev->recovery_running == 0) {
 				/* success...*/
-				if (mddev->spare) {
-					mddev->pers->spare_active(mddev);
-					mddev->spare->in_sync = 1;
-					mddev->spare = NULL;
-				}
+				/* activate any spares */
+				mddev->pers->spare_active(mddev);
+				mddev->spares = 0;
 			}
 			md_update_sb(mddev);
 			mddev->recovery_running = 0;
@@ -3101,16 +3057,33 @@
 			wake_up(&resync_wait);
 		}
 
+		/* no recovery is running.
+		 * remove any failed drives, then
+		 * add spares if possible
+		 */
+		mddev->spares = 0;
+		ITERATE_RDEV(mddev,rdev,rtmp) {
+			if (rdev->raid_disk >= 0 &&
+			    rdev->faulty &&
+			    atomic_read(&rdev->nr_pending)==0) {
+				mddev->pers->hot_remove_disk(mddev, rdev->raid_disk);
+				rdev->raid_disk = -1;
+			}
+			if (!rdev->faulty && rdev->raid_disk >= 0 && !rdev->in_sync)
+				mddev->spares++;
+		}
 		if (mddev->degraded) {
-			mddev->spare = get_spare(mddev);
-			if (!mddev->spare)
-				printk(KERN_ERR "md%d: no spare disk to reconstruct array! "
-				       "-- continuing in degraded mode\n", mdidx(mddev));
-			else
-				printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n",
-				       mdidx(mddev), bdev_partition_name(mddev->spare->bdev));
+			ITERATE_RDEV(mddev,rdev,rtmp)
+				if (rdev->raid_disk < 0
+				    && !rdev->faulty) {
+					if (mddev->pers->hot_add_disk(mddev,rdev))
+						mddev->spares++;
+					else
+						break;
+				}
 		}
-		if (!mddev->spare && mddev->in_sync) {
+
+		if (!mddev->spares && mddev->in_sync) {
 			/* nothing we can do ... */
 			goto unlock;
 		}
@@ -3120,13 +3093,9 @@
 								"md_resync");
 			if (!mddev->sync_thread) {
 				printk(KERN_ERR "md%d: could not start resync thread...\n", mdidx(mddev));
-				if (mddev->spare)
-					mddev->pers->spare_inactive(mddev);
-				mddev->spare = NULL;
+				/* leave the spares where they are, it shouldn't hurt */
 				mddev->recovery_running = 0;
 			} else {
-				if (mddev->spare)
-					mddev->pers->spare_write(mddev);
 				mddev->recovery_running = 1;
 				md_wakeup_thread(mddev->sync_thread);
 			}
@@ -3223,8 +3192,6 @@
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_fail_request);
 	blk_dev[MAJOR_NR].queue = md_queue_proc;
 
-	add_gendisk(&md_gendisk);
-
 	md_recovery_thread = md_register_thread(md_do_recovery, NULL, name);
 	if (!md_recovery_thread)
 		printk(KERN_ALERT
@@ -3526,7 +3493,7 @@
 	return 1;
 }
 
-int __init md_run_setup(void)
+static int __init md_run_setup(void)
 {
 	if (raid_setup_args.noautodetect)
 		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
@@ -3572,7 +3539,6 @@
 	remove_proc_entry("mdstat", NULL);
 #endif
 
-	del_gendisk(&md_gendisk);
 	blk_dev[MAJOR_NR].queue = NULL;
 	blk_clear(MAJOR_NR);
 	
@@ -3591,6 +3557,5 @@
 EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_print_devices);
-EXPORT_SYMBOL(find_rdev_nr);
 EXPORT_SYMBOL(md_interrupt_thread);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/md/multipath.c	Tue Aug 27 12:28:05 2002
@@ -70,7 +70,7 @@
 	kfree(mpb);
 }
 
-static int multipath_map (mddev_t *mddev, struct block_device **bdev)
+static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
 	int i, disks = MD_SB_DISKS;
@@ -80,12 +80,17 @@
 	 * now we use the first available disk.
 	 */
 
+	spin_lock_irq(&conf->device_lock);
 	for (i = 0; i < disks; i++) {
-		if (conf->multipaths[i].operational) {
-			*bdev = conf->multipaths[i].bdev;
-			return (0);
+		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
+		if (rdev && rdev->in_sync) {
+			*rdevp = rdev;
+			atomic_inc(&rdev->nr_pending);
+			spin_unlock_irq(&conf->device_lock);
+			return 0;
 		}
 	}
+	spin_unlock_irq(&conf->device_lock);
 
 	printk (KERN_ERR "multipath_map(): no more operational IO paths?\n");
 	return (-1);
@@ -126,21 +131,21 @@
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
-	multipath_conf_t *conf;
-	struct block_device *bdev;
-	if (uptodate) {
+	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
+	mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev;
+
+	if (uptodate)
 		multipath_end_bh_io(mp_bh, uptodate);
-		return;
+	else {
+		/*
+		 * oops, IO error:
+		 */
+		md_error (mp_bh->mddev, rdev);
+		printk(KERN_ERR "multipath: %s: rescheduling sector %lu\n", 
+		       bdev_partition_name(rdev->bdev), bio->bi_sector);
+		multipath_reschedule_retry(mp_bh);
 	}
-	/*
-	 * oops, IO error:
-	 */
-	conf = mddev_to_conf(mp_bh->mddev);
-	bdev = conf->multipaths[mp_bh->path].bdev;
-	md_error (mp_bh->mddev, bdev);
-	printk(KERN_ERR "multipath: %s: rescheduling sector %lu\n", 
-		 bdev_partition_name(bdev), bio->bi_sector);
-	multipath_reschedule_retry(mp_bh);
+	atomic_dec(&rdev->nr_pending);
 	return;
 }
 
@@ -153,9 +158,11 @@
 {
 	int disk;
 
-	for (disk = 0; disk < MD_SB_DISKS; disk++)	
-		if (conf->multipaths[disk].operational)
+	for (disk = 0; disk < MD_SB_DISKS; disk++) {
+		mdk_rdev_t *rdev = conf->multipaths[disk].rdev;
+		if (rdev && rdev->in_sync)
 			return disk;
+	}
 	BUG();
 	return 0;
 }
@@ -175,11 +182,14 @@
 	/*
 	 * read balancing logic:
 	 */
+	spin_lock_irq(&conf->device_lock);
 	mp_bh->path = multipath_read_balance(conf);
 	multipath = conf->multipaths + mp_bh->path;
+	atomic_inc(&multipath->rdev->nr_pending);
+	spin_unlock_irq(&conf->device_lock);
 
 	mp_bh->bio = *bio;
-	mp_bh->bio.bi_bdev = multipath->bdev;
+	mp_bh->bio.bi_bdev = multipath->rdev->bdev;
 	mp_bh->bio.bi_end_io = multipath_end_request;
 	mp_bh->bio.bi_private = mp_bh;
 	generic_make_request(&mp_bh->bio);
@@ -195,7 +205,8 @@
 						 conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
 		sz += sprintf (page+sz, "%s",
-			conf->multipaths[i].operational ? "U" : "_");
+			       conf->multipaths[i].rdev && 
+			       conf->multipaths[i].rdev->in_sync ? "U" : "_");
 	sz += sprintf (page+sz, "]");
 	return sz;
 }
@@ -210,28 +221,13 @@
 "multipath: IO failure on %s, disabling IO path. \n" \
 "	Operation continuing on %d IO paths.\n"
 
-static void mark_disk_bad (mddev_t *mddev, int failed)
-{
-	multipath_conf_t *conf = mddev_to_conf(mddev);
-	struct multipath_info *multipath = conf->multipaths+failed;
-
-	multipath->operational = 0;
-	mddev->sb_dirty = 1;
-	conf->working_disks--;
-	printk (DISK_FAILED, bdev_partition_name (multipath->bdev),
-				 conf->working_disks);
-}
 
 /*
  * Careful, this can execute in IRQ contexts as well!
  */
-static int multipath_error (mddev_t *mddev, struct block_device *bdev)
+static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
-	struct multipath_info * multipaths = conf->multipaths;
-	int disks = MD_SB_DISKS;
-	int i;
-
 
 	if (conf->working_disks <= 1) {
 		/*
@@ -239,24 +235,21 @@
 		 * first check if this is a queued request for a device
 		 * which has just failed.
 		 */
-		for (i = 0; i < disks; i++) {
-			if (multipaths[i].bdev == bdev && !multipaths[i].operational)
-				return 0;
-		}
 		printk (LAST_DISK);
-		return 1; /* leave it active... it's all we have */
+		/* leave it active... it's all we have */
 	} else {
 		/*
 		 * Mark disk as unusable
 		 */
-		for (i = 0; i < disks; i++) {
-			if (multipaths[i].bdev == bdev && multipaths[i].operational) {
-				mark_disk_bad(mddev, i);
-				break;
-			}
+		if (!rdev->faulty) {
+			rdev->in_sync = 0;
+			rdev->faulty = 1;
+			mddev->sb_dirty = 1;
+			conf->working_disks--;
+			printk (DISK_FAILED, bdev_partition_name (rdev->bdev),
+				conf->working_disks);
 		}
 	}
-	return 0;
 }
 
 #undef LAST_DISK
@@ -279,11 +272,10 @@
 
 	for (i = 0; i < MD_SB_DISKS; i++) {
 		tmp = conf->multipaths + i;
-		if (tmp->operational || tmp->used_slot)
-			printk(" disk%d, o:%d, us:%d dev:%s\n",
-				i,tmp->operational,
-				tmp->used_slot,
-				bdev_partition_name(tmp->bdev));
+		if (tmp->rdev)
+			printk(" disk%d, o:%d, dev:%s\n",
+				i,!tmp->rdev->faulty,
+			       bdev_partition_name(tmp->rdev->bdev));
 	}
 }
 
@@ -291,24 +283,23 @@
 static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	multipath_conf_t *conf = mddev->private;
-	int err = 1;
-	struct multipath_info *p = conf->multipaths + rdev->raid_disk;
+	int found = 0;
+	int path;
+	struct multipath_info *p;
 
 	print_multipath_conf(conf);
 	spin_lock_irq(&conf->device_lock);
-	if (!p->used_slot) {
-		p->bdev = rdev->bdev;
-		p->operational = 1;
-		p->used_slot = 1;
-		conf->working_disks++;
-		err = 0;
-	}
-	if (err)
-		MD_BUG();
+	for (path=0; path<mddev->raid_disks; path++) 
+		if ((p=conf->multipaths+path)->rdev == NULL) {
+			p->rdev = rdev;
+			conf->working_disks++;
+			rdev->raid_disk = path;
+			found = 1;
+		}
 	spin_unlock_irq(&conf->device_lock);
 
 	print_multipath_conf(conf);
-	return err;
+	return found;
 }
 
 static int multipath_remove_disk(mddev_t *mddev, int number)
@@ -320,14 +311,14 @@
 	print_multipath_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 
-	if (p->used_slot) {
-		if (p->operational) {
+	if (p->rdev) {
+		if (p->rdev->in_sync ||
+		    atomic_read(&p->rdev->nr_pending)) {
 			printk(KERN_ERR "hot-remove-disk, slot %d is identified but is still operational!\n", number);
 			err = -EBUSY;
 			goto abort;
 		}
-		p->bdev = NULL;
-		p->used_slot = 0;
+		p->rdev = NULL;
 		err = 0;
 	}
 	if (err)
@@ -359,7 +350,7 @@
 	struct bio *bio;
 	unsigned long flags;
 	mddev_t *mddev;
-	struct block_device *bdev;
+	mdk_rdev_t *rdev;
 
 	for (;;) {
 		spin_lock_irqsave(&retry_list_lock, flags);
@@ -372,16 +363,16 @@
 		mddev = mp_bh->mddev;
 		bio = &mp_bh->bio;
 		bio->bi_sector = mp_bh->master_bio->bi_sector;
-		bdev = bio->bi_bdev;
 		
-		multipath_map (mddev, &bio->bi_bdev);
-		if (bio->bi_bdev == bdev) {
+		rdev = NULL;
+		if (multipath_map (mddev, &rdev)<0) {
 			printk(IO_ERROR,
 				bdev_partition_name(bio->bi_bdev), bio->bi_sector);
 			multipath_end_bh_io(mp_bh, 0);
 		} else {
 			printk(REDIRECT_SECTOR,
 				bdev_partition_name(bio->bi_bdev), bio->bi_sector);
+			bio->bi_bdev = rdev->bdev;
 			generic_make_request(bio);
 		}
 	}
@@ -436,7 +427,6 @@
 	struct multipath_info *disk;
 	mdk_rdev_t *rdev;
 	struct list_head *tmp;
-	int num_rdevs = 0;
 
 	MOD_INC_USE_COUNT;
 
@@ -458,40 +448,20 @@
 	}
 	memset(conf, 0, sizeof(*conf));
 
+	conf->working_disks = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		if (rdev->faulty) {
-			/* this is a "should never happen" case and if it */
-			/* ever does happen, a continue; won't help */
-			printk(ERRORS, bdev_partition_name(rdev->bdev));
-			continue;
-		} else {
-			/* this is a "should never happen" case and if it */
-			/* ever does happen, a continue; won't help */
-			if (!rdev->sb) {
-				MD_BUG();
-				continue;
-			}
-		}
-		if (rdev->desc_nr == -1) {
-			MD_BUG();
+		disk_idx = rdev->raid_disk;
+		if (disk_idx < 0 ||
+		    disk_idx >= mddev->raid_disks)
 			continue;
-		}
 
-		disk_idx = rdev->raid_disk;
 		disk = conf->multipaths + disk_idx;
-
-		/*
-		 * Mark all disks as active to start with, there are no
-		 * spares.  multipath_read_balance deals with choose
-		 * the "best" operational device.
-		 */
-		disk->bdev = rdev->bdev;
-		disk->operational = 1;
-		disk->used_slot = 1;
-		num_rdevs++;
+		disk->rdev = rdev;
+		if (!rdev->faulty) 
+			conf->working_disks++;
 	}
 
-	conf->raid_disks = mddev->raid_disks = num_rdevs;
+	conf->raid_disks = mddev->raid_disks;
 	mddev->sb_dirty = 1;
 	conf->mddev = mddev;
 	conf->device_lock = SPIN_LOCK_UNLOCKED;
@@ -500,6 +470,7 @@
 		printk(NONE_OPERATIONAL, mdidx(mddev));
 		goto out_free_conf;
 	}
+	mddev->degraded = conf->raid_disks = conf->working_disks;
 
 	conf->pool = mempool_create(NR_RESERVED_BUFS,
 				    mp_pool_alloc, mp_pool_free,
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/md/raid0.c	Tue Aug 27 12:28:07 2002
@@ -87,7 +87,7 @@
 	cnt = 0;
 	smallest = NULL;
 	ITERATE_RDEV(mddev, rdev1, tmp1) {
-		int j = rdev1->sb->this_disk.raid_disk;
+		int j = rdev1->raid_disk;
 
 		if (j < 0 || j >= mddev->raid_disks) {
 			printk("raid0: bad disk number %d - aborting!\n", j);
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/md/raid1.c	Tue Aug 27 12:27:42 2002
@@ -135,7 +135,7 @@
 		bio_put(r1_bio->read_bio);
 		r1_bio->read_bio = NULL;
 	}
-	for (i = 0; i < MD_SB_DISKS; i++) {
+	for (i = 0; i < conf->raid_disks; i++) {
 		struct bio **bio = r1_bio->write_bios + i;
 		if (*bio) {
 			if (atomic_read(&(*bio)->bi_cnt) != 1)
@@ -188,22 +188,27 @@
 	mempool_free(r1_bio, conf->r1buf_pool);
 }
 
-static int map(mddev_t *mddev, struct block_device **bdev)
+static int map(mddev_t *mddev, mdk_rdev_t **rdevp)
 {
 	conf_t *conf = mddev_to_conf(mddev);
-	int i, disks = MD_SB_DISKS;
+	int i, disks = conf->raid_disks;
 
 	/*
 	 * Later we do read balancing on the read side
 	 * now we use the first available disk.
 	 */
 
+	spin_lock_irq(&conf->device_lock);
 	for (i = 0; i < disks; i++) {
-		if (conf->mirrors[i].operational) {
-			*bdev = conf->mirrors[i].bdev;
+		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+		if (rdev && rdev->in_sync) {
+			*rdevp = rdev;
+			atomic_inc(&rdev->nr_pending);
+			spin_unlock_irq(&conf->device_lock);
 			return 0;
 		}
 	}
+	spin_unlock_irq(&conf->device_lock);
 
 	printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n");
 	return -1;
@@ -244,7 +249,6 @@
 
 	conf->mirrors[disk].head_position =
 		r1_bio->sector + (r1_bio->master_bio->bi_size >> 9);
-	atomic_dec(&conf->mirrors[disk].nr_pending);
 }
 
 static void end_request(struct bio *bio)
@@ -257,7 +261,7 @@
 	if (r1_bio->cmd == READ || r1_bio->cmd == READA)
 		mirror = r1_bio->read_disk;
 	else {
-		for (mirror = 0; mirror < MD_SB_DISKS; mirror++)
+		for (mirror = 0; mirror < conf->raid_disks; mirror++)
 			if (r1_bio->write_bios[mirror] == bio)
 				break;
 	}
@@ -265,7 +269,7 @@
 	 * this branch is our 'one mirror IO has finished' event handler:
 	 */
 	if (!uptodate)
-		md_error(r1_bio->mddev, conf->mirrors[mirror].bdev);
+		md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
 	else
 		/*
 		 * Set R1BIO_Uptodate in our master bio, so that
@@ -285,29 +289,30 @@
 		/*
 		 * we have only one bio on the read side
 		 */
-		if (uptodate) {
+		if (uptodate)
 			raid_end_bio_io(r1_bio, uptodate);
-			return;
+		else {
+			/*
+			 * oops, read error:
+			 */
+			printk(KERN_ERR "raid1: %s: rescheduling sector %lu\n",
+			       bdev_partition_name(conf->mirrors[mirror].rdev->bdev), r1_bio->sector);
+			reschedule_retry(r1_bio);
 		}
+	} else {
+
+		if (r1_bio->read_bio)
+			BUG();
 		/*
-		 * oops, read error:
+		 * WRITE:
+		 *
+		 * Let's see if all mirrored write operations have finished
+		 * already.
 		 */
-		printk(KERN_ERR "raid1: %s: rescheduling sector %lu\n",
-			bdev_partition_name(conf->mirrors[mirror].bdev), r1_bio->sector);
-		reschedule_retry(r1_bio);
-		return;
+		if (atomic_dec_and_test(&r1_bio->remaining))
+			raid_end_bio_io(r1_bio, uptodate);
 	}
-
-	if (r1_bio->read_bio)
-		BUG();
-	/*
-	 * WRITE:
-	 *
-	 * Let's see if all mirrored write operations have finished
-	 * already.
-	 */
-	if (atomic_dec_and_test(&r1_bio->remaining))
-		raid_end_bio_io(r1_bio, uptodate);
+	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
 }
 
 /*
@@ -321,6 +326,8 @@
  *
  * If there are 2 mirrors in the same 2 devices, performance degrades
  * because position is mirror, not device based.
+ *
+ * The rdev for the device selected will have nr_pending incremented.
  */
 static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
 {
@@ -329,6 +336,7 @@
 	const int sectors = bio->bi_size >> 9;
 	sector_t new_distance, current_distance;
 
+	spin_lock_irq(&conf->device_lock);
 	/*
 	 * Check if it if we can balance. We can balance on the whole
 	 * device if no resync is going on, or below the resync window.
@@ -337,7 +345,9 @@
 	if (!conf->mddev->in_sync && (this_sector + sectors >= conf->next_resync)) {
 		/* make sure that disk is operational */
 		new_disk = 0;
-		while (!conf->mirrors[new_disk].operational || conf->mirrors[new_disk].write_only) {
+
+		while (!conf->mirrors[new_disk].rdev ||
+		       !conf->mirrors[new_disk].rdev->in_sync) {
 			new_disk++;
 			if (new_disk == conf->raid_disks) {
 				new_disk = 0;
@@ -349,7 +359,8 @@
 
 
 	/* make sure the disk is operational */
-	while (!conf->mirrors[new_disk].operational) {
+	while (!conf->mirrors[new_disk].rdev ||
+	       !conf->mirrors[new_disk].rdev->in_sync) {
 		if (new_disk <= 0)
 			new_disk = conf->raid_disks;
 		new_disk--;
@@ -378,11 +389,11 @@
 			disk = conf->raid_disks;
 		disk--;
 
-		if ((conf->mirrors[disk].write_only) ||
-				(!conf->mirrors[disk].operational))
+		if (!conf->mirrors[disk].rdev ||
+		    !conf->mirrors[disk].rdev->in_sync)
 			continue;
 
-		if (!atomic_read(&conf->mirrors[disk].nr_pending)) {
+		if (!atomic_read(&conf->mirrors[disk].rdev->nr_pending)) {
 			new_disk = disk;
 			break;
 		}
@@ -399,6 +410,10 @@
 
 	conf->last_used = new_disk;
 
+	if (conf->mirrors[new_disk].rdev)
+		atomic_inc(&conf->mirrors[new_disk].rdev->nr_pending);
+	spin_unlock_irq(&conf->device_lock);
+
 	return new_disk;
 }
 
@@ -441,7 +456,7 @@
 	mirror_info_t *mirror;
 	r1bio_t *r1_bio;
 	struct bio *read_bio;
-	int i, sum_bios = 0, disks = MD_SB_DISKS;
+	int i, sum_bios = 0, disks = conf->raid_disks;
 
 	/*
 	 * Register the new request and wait if the reconstruction
@@ -478,31 +493,42 @@
 		r1_bio->read_bio = read_bio;
 
 		read_bio->bi_sector = r1_bio->sector;
-		read_bio->bi_bdev = mirror->bdev;
+		read_bio->bi_bdev = mirror->rdev->bdev;
 		read_bio->bi_end_io = end_request;
 		read_bio->bi_rw = r1_bio->cmd;
 		read_bio->bi_private = r1_bio;
 
 		generic_make_request(read_bio);
-		atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending);
 		return 0;
 	}
 
 	/*
 	 * WRITE:
 	 */
+	/* first select target devices under spinlock and
+	 * inc refcount on their rdev.  Record them by setting
+	 * write_bios[x] to bio
+	 */
+	spin_lock_irq(&conf->device_lock);
+	for (i = 0;  i < disks; i++) {
+		if (conf->mirrors[i].rdev &&
+		    !conf->mirrors[i].rdev->faulty) {
+			atomic_inc(&conf->mirrors[i].rdev->nr_pending);
+			r1_bio->write_bios[i] = bio;
+		} else
+			r1_bio->write_bios[i] = NULL;
+	}
+	spin_unlock_irq(&conf->device_lock);
 	for (i = 0; i < disks; i++) {
 		struct bio *mbio;
-		if (!conf->mirrors[i].operational)
+		if (!r1_bio->write_bios[i])
 			continue;
 
 		mbio = bio_clone(bio, GFP_NOIO);
-		if (r1_bio->write_bios[i])
-			BUG();
 		r1_bio->write_bios[i] = mbio;
 
 		mbio->bi_sector	= r1_bio->sector;
-		mbio->bi_bdev = conf->mirrors[i].bdev;
+		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
 		mbio->bi_end_io	= end_request;
 		mbio->bi_rw = r1_bio->cmd;
 		mbio->bi_private = r1_bio;
@@ -529,14 +555,13 @@
 	 * do end_request by hand if all requests finish until we had a
 	 * chance to set up the semaphore correctly ... lots of races).
 	 */
-	for (i = 0; i < disks; i++) {
+	for (i=disks; i--; ) {
 		struct bio *mbio;
 		mbio = r1_bio->write_bios[i];
 		if (!mbio)
 			continue;
 
 		generic_make_request(mbio);
-		atomic_inc(&conf->mirrors[i].nr_pending);
 	}
 	return 0;
 }
@@ -550,7 +575,8 @@
 						conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
 		sz += sprintf(page+sz, "%s",
-			conf->mirrors[i].operational ? "U" : "_");
+			      conf->mirrors[i].rdev &&
+			      conf->mirrors[i].rdev->in_sync ? "U" : "_");
 	sz += sprintf (page+sz, "]");
 	return sz;
 }
@@ -571,48 +597,37 @@
 #define ALREADY_SYNCING KERN_INFO \
 "raid1: syncing already in progress.\n"
 
-static void mark_disk_bad(mddev_t *mddev, int failed)
-{
-	conf_t *conf = mddev_to_conf(mddev);
-	mirror_info_t *mirror = conf->mirrors+failed;
-
-	mirror->operational = 0;
-	if (!mirror->write_only) {
-		mddev->degraded++;
-		conf->working_disks--;
-	}
-	mddev->sb_dirty = 1;
-	printk(DISK_FAILED, bdev_partition_name(mirror->bdev), conf->working_disks);
-}
 
-static int error(mddev_t *mddev, struct block_device *bdev)
+static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	conf_t *conf = mddev_to_conf(mddev);
-	mirror_info_t * mirrors = conf->mirrors;
-	int disks = MD_SB_DISKS;
-	int i;
 
 	/*
-	 * Find the drive.
 	 * If it is not operational, then we have already marked it as dead
 	 * else if it is the last working disks, ignore the error, let the
 	 * next level up know.
 	 * else mark the drive as failed
 	 */
-	for (i = 0; i < disks; i++)
-		if (mirrors[i].bdev == bdev && mirrors[i].operational)
-			break;
-	if (i == disks)
-		return 0;
-
-	if (i < conf->raid_disks && conf->working_disks == 1)
+	if (rdev->in_sync
+	    && conf->working_disks == 1)
 		/*
 		 * Don't fail the drive, act as though we were just a
 		 * normal single drive
 		 */
-		return 1;
-	mark_disk_bad(mddev, i);
-	return 0;
+		return;
+	if (rdev->in_sync) {
+		mddev->degraded++;
+		conf->working_disks--;
+		/*
+		 * if recovery was running, stop it now.
+		 */
+		if (mddev->recovery_running) 
+			mddev->recovery_running = -EIO;
+	}
+	rdev->in_sync = 0;
+	rdev->faulty = 1;
+	mddev->sb_dirty = 1;
+	printk(DISK_FAILED, bdev_partition_name(rdev->bdev), conf->working_disks);
 }
 
 static void print_conf(conf_t *conf)
@@ -628,12 +643,12 @@
 	printk(" --- wd:%d rd:%d\n", conf->working_disks,
 			conf->raid_disks);
 
-	for (i = 0; i < MD_SB_DISKS; i++) {
+	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->mirrors + i;
-		printk(" disk %d, s:%d, o:%d, us:%d dev:%s\n",
-			i, tmp->spare, tmp->operational,
-			tmp->used_slot,
-			bdev_partition_name(tmp->bdev));
+		if (tmp->rdev)
+			printk(" disk %d, wo:%d, o:%d, dev:%s\n",
+			       i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+			       bdev_partition_name(tmp->rdev->bdev));
 	}
 }
 
@@ -653,160 +668,52 @@
 
 static int raid1_spare_active(mddev_t *mddev)
 {
-	int err = 0;
-	int i, failed_disk = -1, spare_disk = -1;
+	int i;
 	conf_t *conf = mddev->private;
-	mirror_info_t *tmp, *sdisk, *fdisk;
-	mdk_rdev_t *spare_rdev, *failed_rdev;
+	mirror_info_t *tmp;
 
-	print_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 	/*
-	 * Find the failed disk within the RAID1 configuration ...
-	 * (this can only be in the first conf->working_disks part)
+	 * Find all failed disks within the RAID1 configuration 
+	 * and mark them readable
 	 */
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->mirrors + i;
-		if ((!tmp->operational && !tmp->spare) ||
-				!tmp->used_slot) {
-			failed_disk = i;
-			break;
+		if (tmp->rdev 
+		    && !tmp->rdev->faulty
+		    && !tmp->rdev->in_sync) {
+			conf->working_disks++;
+			mddev->degraded--;
+			tmp->rdev->in_sync = 1;
 		}
 	}
-	/*
-	 * When we activate a spare disk we _must_ have a disk in
-	 * the lower (active) part of the array to replace.
-	 */
-	if (failed_disk == -1) {
-		MD_BUG();
-		err = 1;
-		goto abort;
-	}
-	/*
-	 * Find the spare disk ... (can only be in the 'high'
-	 * area of the array)
-	 */
-	spare_disk = mddev->spare->raid_disk;
-
-	sdisk = conf->mirrors + spare_disk;
-	fdisk = conf->mirrors + failed_disk;
-
-	/*
-	 * do the switch finally
-	 */
-	spare_rdev = find_rdev_nr(mddev, spare_disk);
-	failed_rdev = find_rdev_nr(mddev, failed_disk);
-
-	/*
-	 * There must be a spare_rdev, but there may not be a
-	 * failed_rdev. That slot might be empty...
-	 */
-	spare_rdev->desc_nr = failed_disk;
-	spare_rdev->raid_disk = failed_disk;
-	if (failed_rdev) {
-		failed_rdev->desc_nr = spare_disk;
-		failed_rdev->raid_disk = spare_disk;
-	}
-
-	xchg_values(*fdisk, *sdisk);
-
-	/*
-	 * (careful, 'failed' and 'spare' are switched from now on)
-	 *
-	 * we want to preserve linear numbering and we want to
-	 * give the proper raid_disk number to the now activated
-	 * disk. (this means we switch back these values)
-	 */
-
-	if (!sdisk->bdev)
-		sdisk->used_slot = 0;
-	/*
-	 * this really activates the spare.
-	 */
-	fdisk->spare = 0;
-	fdisk->write_only = 0;
-
-	/*
-	 * if we activate a spare, we definitely replace a
-	 * non-operational disk slot in the 'low' area of
-	 * the disk array.
-	 */
-
-	conf->working_disks++;
-	mddev->degraded--;
-abort:
 	spin_unlock_irq(&conf->device_lock);
 
 	print_conf(conf);
-	return err;
-}
-
-static int raid1_spare_inactive(mddev_t *mddev)
-{
-	conf_t *conf = mddev->private;
-	mirror_info_t *p;
-	int err = 0;
-
-	print_conf(conf);
-	spin_lock_irq(&conf->device_lock);
-	p = conf->mirrors + mddev->spare->raid_disk;
-	if (p) {
-		p->operational = 0;
-		p->write_only = 0;
-	} else {
-		MD_BUG();
-		err = 1;
-	}
-	spin_unlock_irq(&conf->device_lock);
-	print_conf(conf);
-	return err;
+	return 0;
 }
 
-static int raid1_spare_write(mddev_t *mddev)
-{
-	conf_t *conf = mddev->private;
-	mirror_info_t *p;
-	int err = 0;
-
-	print_conf(conf);
-	spin_lock_irq(&conf->device_lock);
-	p = conf->mirrors + mddev->spare->raid_disk;
-	if (p) {
-		p->operational = 1;
-		p->write_only = 1;
-	} else {
-		MD_BUG();
-		err = 1;
-	}
-	spin_unlock_irq(&conf->device_lock);
-	print_conf(conf);
-	return err;
-}
 
 static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	conf_t *conf = mddev->private;
-	int err = 1;
-	mirror_info_t *p = conf->mirrors + rdev->raid_disk;
+	int found = 0;
+	int mirror;
+	mirror_info_t *p;
 
-	print_conf(conf);
 	spin_lock_irq(&conf->device_lock);
-	if (!p->used_slot) {
-		/* it will be held open by rdev */
-		p->bdev = rdev->bdev;
-		p->operational = 0;
-		p->write_only = 0;
-		p->spare = 1;
-		p->used_slot = 1;
-		p->head_position = 0;
-		err = 0;
-	}
-	if (err)
-		MD_BUG();
+	for (mirror=0; mirror < mddev->raid_disks; mirror++)
+		if ( !(p=conf->mirrors+mirror)->rdev) {
+			p->rdev = rdev;
+			p->head_position = 0;
+			rdev->raid_disk = mirror;
+			found = 1;
+			break;
+		}
 	spin_unlock_irq(&conf->device_lock);
 
 	print_conf(conf);
-	return err;
+	return found;
 }
 
 static int raid1_remove_disk(mddev_t *mddev, int number)
@@ -817,13 +724,13 @@
 
 	print_conf(conf);
 	spin_lock_irq(&conf->device_lock);
-	if (p->used_slot) {
-		if (p->operational) {
+	if (p->rdev) {
+		if (p->rdev->in_sync ||
+		    atomic_read(&p->rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
 		}
-		p->bdev = NULL;
-		p->used_slot = 0;
+		p->rdev = NULL;
 		err = 0;
 	}
 	if (err)
@@ -857,9 +764,10 @@
 	 */
 	if (!uptodate)
 		md_error(r1_bio->mddev,
-			 conf->mirrors[r1_bio->read_disk].bdev);
+			 conf->mirrors[r1_bio->read_disk].rdev);
 	else
 		set_bit(R1BIO_Uptodate, &r1_bio->state);
+	atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending);
 	reschedule_retry(r1_bio);
 }
 
@@ -872,13 +780,13 @@
 	int i;
 	int mirror=0;
 
-	for (i = 0; i < MD_SB_DISKS; i++)
+	for (i = 0; i < conf->raid_disks; i++)
 		if (r1_bio->write_bios[i] == bio) {
 			mirror = i;
 			break;
 		}
 	if (!uptodate)
-		md_error(mddev, conf->mirrors[mirror].bdev);
+		md_error(mddev, conf->mirrors[mirror].rdev);
 	update_head_pos(mirror, r1_bio);
 
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
@@ -886,13 +794,14 @@
 		resume_device(conf);
 		put_buf(r1_bio);
 	}
+	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
 }
 
 static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
 {
 	conf_t *conf = mddev_to_conf(mddev);
 	int i, sum_bios = 0;
-	int disks = MD_SB_DISKS;
+	int disks = conf->raid_disks;
 	struct bio *bio, *mbio;
 
 	bio = r1_bio->master_bio;
@@ -913,25 +822,33 @@
 		return;
 	}
 
+	spin_lock_irq(&conf->device_lock);
 	for (i = 0; i < disks ; i++) {
-		if (!conf->mirrors[i].operational)
+		r1_bio->write_bios[i] = NULL;
+		if (!conf->mirrors[i].rdev || 
+		    conf->mirrors[i].rdev->faulty)
 			continue;
 		if (i == conf->last_used)
 			/*
 			 * we read from here, no need to write
 			 */
 			continue;
-		if (i < conf->raid_disks && mddev->in_sync)
+		if (conf->mirrors[i].rdev->in_sync && mddev->in_sync)
 			/*
 			 * don't need to write this we are just rebuilding
 			 */
 			continue;
+		atomic_inc(&conf->mirrors[i].rdev->nr_pending);
+		r1_bio->write_bios[i] = bio;
+	}
+	spin_unlock_irq(&conf->device_lock);
 
+	for (i = 0; i < disks ; i++) {
+		if (!r1_bio->write_bios[i])
+			continue;
 		mbio = bio_clone(bio, GFP_NOIO);
-		if (r1_bio->write_bios[i])
-			BUG();
 		r1_bio->write_bios[i] = mbio;
-		mbio->bi_bdev = conf->mirrors[i].bdev;
+		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
 		mbio->bi_sector = r1_bio->sector;
 		mbio->bi_end_io	= end_sync_write;
 		mbio->bi_rw = WRITE;
@@ -949,7 +866,7 @@
 		 * Nowhere to write this to... I guess we
 		 * must be done
 		 */
-		printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), r1_bio->sector);
+		printk(KERN_ALERT "raid1: sync aborting as there is nowhere to write sector %lu\n", r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
 		resume_device(conf);
 		put_buf(r1_bio);
@@ -960,9 +877,8 @@
 		if (!mbio)
 			continue;
 
-		md_sync_acct(mbio->bi_bdev, mbio->bi_size >> 9);
+		md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9);
 		generic_make_request(mbio);
-		atomic_inc(&conf->mirrors[i].nr_pending);
 	}
 }
 
@@ -982,7 +898,7 @@
 	unsigned long flags;
 	mddev_t *mddev;
 	conf_t *conf;
-	struct block_device *bdev;
+	mdk_rdev_t *rdev;
 
 
 	for (;;) {
@@ -1002,20 +918,18 @@
 			break;
 		case READ:
 		case READA:
-			bdev = bio->bi_bdev;
-			map(mddev, &bio->bi_bdev);
-			if (bio->bi_bdev == bdev) {
+			if (map(mddev, &rdev) == -1) {
 				printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), r1_bio->sector);
 				raid_end_bio_io(r1_bio, 0);
 				break;
 			}
 			printk(REDIRECT_SECTOR,
-				bdev_partition_name(bio->bi_bdev), r1_bio->sector);
+				bdev_partition_name(rdev->bdev), r1_bio->sector);
+			bio->bi_bdev = rdev->bdev;
 			bio->bi_sector = r1_bio->sector;
 			bio->bi_rw = r1_bio->cmd;
 
 			generic_make_request(bio);
-			atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending);
 			break;
 		}
 	}
@@ -1081,7 +995,9 @@
 	 */
 	disk = conf->last_used;
 	/* make sure disk is operational */
-	while (!conf->mirrors[disk].operational) {
+	spin_lock_irq(&conf->device_lock);
+	while (conf->mirrors[disk].rdev == NULL ||
+	       !conf->mirrors[disk].rdev->in_sync) {
 		if (disk <= 0)
 			disk = conf->raid_disks;
 		disk--;
@@ -1089,6 +1005,8 @@
 			break;
 	}
 	conf->last_used = disk;
+	atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+	spin_unlock_irq(&conf->device_lock);
 
 	mirror = conf->mirrors + conf->last_used;
 
@@ -1119,7 +1037,7 @@
 	read_bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
 
 	read_bio->bi_sector = sector_nr;
-	read_bio->bi_bdev = mirror->bdev;
+	read_bio->bi_bdev = mirror->rdev->bdev;
 	read_bio->bi_end_io = end_sync_read;
 	read_bio->bi_rw = READ;
 	read_bio->bi_private = r1_bio;
@@ -1128,10 +1046,9 @@
 		BUG();
 	r1_bio->read_bio = read_bio;
 
-	md_sync_acct(read_bio->bi_bdev, nr_sectors);
+	md_sync_acct(mirror->rdev, nr_sectors);
 
 	generic_make_request(read_bio);
-	atomic_inc(&conf->mirrors[conf->last_used].nr_pending);
 
 	return nr_sectors;
 }
@@ -1209,61 +1126,18 @@
 		goto out;
 	}
 
-//	for (tmp = (mddev)->disks.next; rdev = ((mdk_rdev_t *)((char *)(tmp)-(unsigned long)(&((mdk_rdev_t *)0)->same_set))), tmp = tmp->next, tmp->prev != &(mddev)->disks ; ) {
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
-		if (rdev->faulty) {
-			printk(ERRORS, bdev_partition_name(rdev->bdev));
-		} else {
-			if (!rdev->sb) {
-				MD_BUG();
-				continue;
-			}
-		}
-		if (rdev->desc_nr == -1) {
-			MD_BUG();
-			continue;
-		}
 		disk_idx = rdev->raid_disk;
+		if (disk_idx >= mddev->raid_disks
+		    || disk_idx < 0)
+			continue;
 		disk = conf->mirrors + disk_idx;
 
-		if (rdev->faulty) {
-			disk->bdev = rdev->bdev;
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 0;
-			disk->used_slot = 1;
-			disk->head_position = 0;
-			continue;
-		}
-		if (rdev->in_sync) {
-			if (disk->operational) {
-				printk(ALREADY_RUNNING,
-					bdev_partition_name(rdev->bdev),
-					disk_idx);
-				continue;
-			}
-			printk(OPERATIONAL, bdev_partition_name(rdev->bdev),
-					disk_idx);
-			disk->bdev = rdev->bdev;
-			disk->operational = 1;
-			disk->write_only = 0;
-			disk->spare = 0;
-			disk->used_slot = 1;
-			disk->head_position = 0;
+		disk->rdev = rdev;
+		disk->head_position = 0;
+		if (!rdev->faulty && rdev->in_sync)
 			conf->working_disks++;
-		} else {
-		/*
-		 * Must be a spare disk ..
-		 */
-			printk(SPARE, bdev_partition_name(rdev->bdev));
-			disk->bdev = rdev->bdev;
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 1;
-			disk->used_slot = 1;
-			disk->head_position = 0;
-		}
 	}
 	conf->raid_disks = mddev->raid_disks;
 	conf->mddev = mddev;
@@ -1283,23 +1157,19 @@
 
 		disk = conf->mirrors + i;
 
-		if (!disk->used_slot) {
-			disk->bdev = NULL;
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 0;
-			disk->used_slot = 1;
+		if (!disk->rdev) {
 			disk->head_position = 0;
-		}
-		if (!disk->used_slot)
 			mddev->degraded++;
+		}
 	}
 
 	/*
 	 * find the first working one and use it as a starting point
 	 * to read balancing.
 	 */
-	for (j = 0; !conf->mirrors[j].operational && j < MD_SB_DISKS; j++)
+	for (j = 0; j < conf->raid_disks &&
+		     (!conf->mirrors[j].rdev ||
+		      !conf->mirrors[j].rdev->in_sync) ; j++)
 		/* nothing */;
 	conf->last_used = j;
 
@@ -1354,8 +1224,6 @@
 	.error_handler	= error,
 	.hot_add_disk	= raid1_add_disk,
 	.hot_remove_disk= raid1_remove_disk,
-	.spare_write	= raid1_spare_write,
-	.spare_inactive	= raid1_spare_inactive,
 	.spare_active	= raid1_spare_active,
 	.sync_request	= sync_request,
 };
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/md/raid5.c	Tue Aug 27 12:28:01 2002
@@ -371,9 +371,10 @@
 		set_bit(R5_UPTODATE, &sh->dev[i].flags);
 #endif		
 	} else {
-		md_error(conf->mddev, conf->disks[i].bdev);
+		md_error(conf->mddev, conf->disks[i].rdev);
 		clear_bit(R5_UPTODATE, &sh->dev[i].flags);
 	}
+	atomic_dec(&conf->disks[i].rdev->nr_pending);
 #if 0
 	/* must restore b_page before unlocking buffer... */
 	if (sh->bh_page[i] != bh->b_page) {
@@ -407,7 +408,9 @@
 
 	spin_lock_irqsave(&conf->device_lock, flags);
 	if (!uptodate)
-		md_error(conf->mddev, conf->disks[i].bdev);
+		md_error(conf->mddev, conf->disks[i].rdev);
+
+	atomic_dec(&conf->disks[i].rdev->nr_pending);
 	
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
@@ -420,7 +423,6 @@
 	
 static void raid5_build_block (struct stripe_head *sh, int i)
 {
-	raid5_conf_t *conf = sh->raid_conf;
 	struct r5dev *dev = &sh->dev[i];
 
 	bio_init(&dev->req);
@@ -430,7 +432,6 @@
 	dev->vec.bv_len = STRIPE_SIZE;
 	dev->vec.bv_offset = 0;
 
-	dev->req.bi_bdev = conf->disks[i].bdev;
 	dev->req.bi_sector = sh->sector;
 	dev->req.bi_private = sh;
 
@@ -439,54 +440,30 @@
 		dev->sector = compute_blocknr(sh, i);
 }
 
-static int error(mddev_t *mddev, struct block_device *bdev)
+static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
-	struct disk_info *disk;
-	int i;
-
 	PRINTK("raid5: error called\n");
 
-	for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) {
-		if (disk->bdev != bdev)
-			continue;
-		if (disk->operational) {
-			disk->operational = 0;
-			mddev->sb_dirty = 1;
+	if (!rdev->faulty) {
+		mddev->sb_dirty = 1;
+		conf->working_disks--;
+		if (rdev->in_sync) {
 			mddev->degraded++;
-			conf->working_disks--;
 			conf->failed_disks++;
-			printk (KERN_ALERT
-				"raid5: Disk failure on %s, disabling device."
-				" Operation continuing on %d devices\n",
-				bdev_partition_name(bdev), conf->working_disks);
-		}
-		return 0;
-	}
-	/*
-	 * handle errors in spares (during reconstruction)
-	 */
-	if (conf->spare) {
-		disk = conf->spare;
-		if (disk->bdev == bdev) {
-			printk (KERN_ALERT
-				"raid5: Disk failure on spare %s\n",
-				bdev_partition_name (bdev));
-			if (!conf->spare->operational) {
-				/* probably a SET_DISK_FAULTY ioctl */
-				return -EIO;
-			}
-			disk->operational = 0;
-			disk->write_only = 0;
-			conf->spare = NULL;
-
-			mddev->sb_dirty = 1;
-
-			return 0;
+			rdev->in_sync = 0;
+			/*
+			 * if recovery was running, stop it now.
+			 */
+			if (mddev->recovery_running) 
+				mddev->recovery_running = -EIO;
 		}
+		rdev->faulty = 1;
+		printk (KERN_ALERT
+			"raid5: Disk failure on %s, disabling device."
+			" Operation continuing on %d devices\n",
+			bdev_partition_name(rdev->bdev), conf->working_disks);
 	}
-	MD_BUG();
-	return -EIO;
 }	
 
 /*
@@ -681,7 +658,7 @@
 	}
 	if (count != 1)
 		xor_block(count, STRIPE_SIZE, ptr);
-	set_bit(R5_UPTODATE, &sh->dev[i].flags);
+	set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
 }
 
 static void compute_parity(struct stripe_head *sh, int method)
@@ -840,7 +817,6 @@
 	int disks = conf->raid_disks;
 	struct bio *return_bi= NULL;
 	struct bio *bi;
-	int action[MD_SB_DISKS];
 	int i;
 	int syncing;
 	int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
@@ -848,7 +824,6 @@
 	struct r5dev *dev;
 
 	PRINTK("handling stripe %ld, cnt=%d, pd_idx=%d\n", sh->sector, atomic_read(&sh->count), sh->pd_idx);
-	memset(action, 0, sizeof(action));
 
 	spin_lock(&sh->lock);
 	clear_bit(STRIPE_HANDLE, &sh->state);
@@ -858,7 +833,13 @@
 	/* Now to look around and see what can be done */
 
 	for (i=disks; i--; ) {
+		mdk_rdev_t *rdev;
 		dev = &sh->dev[i];
+		clear_bit(R5_Wantread, &dev->flags);
+		clear_bit(R5_Wantwrite, &dev->flags);
+		clear_bit(R5_Insync, &dev->flags);
+		clear_bit(R5_Syncio, &dev->flags);
+
 		PRINTK("check %d: state 0x%lx read %p write %p written %p\n", i, 
 		       dev->flags, dev->toread, dev->towrite, dev->written);
 		/* maybe we can reply to a read */
@@ -890,10 +871,12 @@
 		if (dev->toread) to_read++;
 		if (dev->towrite) to_write++;
 		if (dev->written) written++;
-		if (!conf->disks[i].operational) {
+		rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
+		if (!rdev || !rdev->in_sync) {
 			failed++;
 			failed_num = i;
-		}
+		} else
+			set_bit(R5_Insync, &dev->flags);
 	}
 	PRINTK("locked=%d uptodate=%d to_read=%d to_write=%d failed=%d failed_num=%d\n",
 	       locked, uptodate, to_read, to_write, failed, failed_num);
@@ -918,7 +901,7 @@
 				bi = nextbi;
 			}
 			/* fail any reads if this device is non-operational */
-			if (!conf->disks[i].operational) {
+			if (!test_bit(R5_Insync, &sh->dev[i].flags)) {
 				bi = sh->dev[i].toread;
 				sh->dev[i].toread = NULL;
 				if (bi) to_read--;
@@ -946,7 +929,7 @@
 	 */
 	dev = &sh->dev[sh->pd_idx];
 	if ( written &&
-	     ( (conf->disks[sh->pd_idx].operational && !test_bit(R5_LOCKED, &dev->flags) &&
+	     ( (test_bit(R5_Insync, &dev->flags) && !test_bit(R5_LOCKED, &dev->flags) &&
 		test_bit(R5_UPTODATE, &dev->flags))
 	       || (failed == 1 && failed_num == sh->pd_idx))
 	    ) {
@@ -954,7 +937,7 @@
 	    for (i=disks; i--; )
 		if (sh->dev[i].written) {
 		    dev = &sh->dev[i];
-		    if (!conf->disks[sh->pd_idx].operational ||
+		    if (!test_bit(R5_Insync, &dev->flags) &&
 			(!test_bit(R5_LOCKED, &dev->flags) && test_bit(R5_UPTODATE, &dev->flags)) ) {
 			/* maybe we can return some write requests */
 			    struct bio *wbi, *wbi2;
@@ -988,9 +971,9 @@
 					PRINTK("Computing block %d\n", i);
 					compute_block(sh, i);
 					uptodate++;
-				} else if (conf->disks[i].operational) {
+				} else if (test_bit(R5_Insync, &dev->flags)) {
 					set_bit(R5_LOCKED, &dev->flags);
-					action[i] = READ+1;
+					set_bit(R5_Wantread, &dev->flags);
 #if 0
 					/* if I am just reading this block and we don't have
 					   a failed drive, or any pending writes then sidestep the cache */
@@ -1003,7 +986,7 @@
 					locked++;
 					PRINTK("Reading block %d (sync=%d)\n", i, syncing);
 					if (syncing)
-						md_sync_acct(conf->disks[i].bdev, STRIPE_SECTORS);
+						md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS);
 				}
 			}
 		}
@@ -1023,7 +1006,7 @@
 #endif
 				    ) &&
 			    !test_bit(R5_UPTODATE, &dev->flags)) {
-				if (conf->disks[i].operational 
+				if (test_bit(R5_Insync, &dev->flags)
 /*				    && !(!mddev->insync && i == sh->pd_idx) */
 					)
 					rmw++;
@@ -1037,7 +1020,7 @@
 #endif
 				    ) &&
 			    !test_bit(R5_UPTODATE, &dev->flags)) {
-				if (conf->disks[i].operational) rcw++;
+				if (test_bit(R5_Insync, &dev->flags)) rcw++;
 				else rcw += 2*disks;
 			}
 		}
@@ -1049,12 +1032,12 @@
 				dev = &sh->dev[i];
 				if ((dev->towrite || i == sh->pd_idx) &&
 				    !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
-				    conf->disks[i].operational) {
+				    test_bit(R5_Insync, &dev->flags)) {
 					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 					{
 						PRINTK("Read_old block %d for r-m-w\n", i);
 						set_bit(R5_LOCKED, &dev->flags);
-						action[i] = READ+1;
+						set_bit(R5_Wantread, &dev->flags);
 						locked++;
 					} else {
 						set_bit(STRIPE_DELAYED, &sh->state);
@@ -1068,12 +1051,12 @@
 				dev = &sh->dev[i];
 				if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
 				    !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
-				    conf->disks[i].operational) {
+				    test_bit(R5_Insync, &dev->flags)) {
 					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 					{
 						PRINTK("Read_old block %d for Reconstruct\n", i);
 						set_bit(R5_LOCKED, &dev->flags);
-						action[i] = READ+1;
+						set_bit(R5_Wantread, &dev->flags);
 						locked++;
 					} else {
 						set_bit(STRIPE_DELAYED, &sh->state);
@@ -1090,8 +1073,8 @@
 				if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
 					PRINTK("Writing block %d\n", i);
 					locked++;
-					action[i] = WRITE+1;
-					if (!conf->disks[i].operational
+					set_bit(R5_Wantwrite, &sh->dev[i].flags);
+					if (!test_bit(R5_Insync, &sh->dev[i].flags)
 					    || (i==sh->pd_idx && failed == 0))
 						set_bit(STRIPE_INSYNC, &sh->state);
 				}
@@ -1124,7 +1107,6 @@
 			}
 		}
 		if (!test_bit(STRIPE_INSYNC, &sh->state)) {
-			struct disk_info *spare;
 			if (failed==0)
 				failed_num = sh->pd_idx;
 			/* should be able to compute the missing block and write it to spare */
@@ -1138,14 +1120,10 @@
 				BUG();
 			dev = &sh->dev[failed_num];
 			set_bit(R5_LOCKED, &dev->flags);
-			action[failed_num] = WRITE+1;
+			set_bit(R5_Wantwrite, &dev->flags);
 			locked++;
 			set_bit(STRIPE_INSYNC, &sh->state);
-			if (conf->disks[failed_num].operational)
-				md_sync_acct(conf->disks[failed_num].bdev, STRIPE_SECTORS);
-			else if ((spare=conf->spare))
-				md_sync_acct(spare->bdev, STRIPE_SECTORS);
-
+			set_bit(R5_Syncio, &dev->flags);
 		}
 	}
 	if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
@@ -1161,27 +1139,34 @@
 		bi->bi_end_io(bi);
 	}
 	for (i=disks; i-- ;) 
-		if (action[i]) {
+		if (sh->dev[i].flags & ((1<<R5_Wantwrite)|(1<<R5_Wantread))) {
 			struct bio *bi = &sh->dev[i].req;
-			struct disk_info *spare = conf->spare;
-			int skip = 0;
-			if (action[i] == READ+1)
+			mdk_rdev_t *rdev ;
+
+			bi->bi_rw = 0;
+			if (test_bit(R5_Wantread, &sh->dev[i].flags))
 				bi->bi_end_io = raid5_end_read_request;
-			else
+			else {
 				bi->bi_end_io = raid5_end_write_request;
-			if (conf->disks[i].operational)
-				bi->bi_bdev = conf->disks[i].bdev;
-			else if (spare && action[i] == WRITE+1)
-				bi->bi_bdev = spare->bdev;
-			else skip=1;
-			if (!skip) {
-				PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, action[i]-1, i);
+				bi->bi_rw = 1;
+			}
+
+			spin_lock_irq(&conf->device_lock);
+			rdev = conf->disks[i].rdev;
+			if (rdev && rdev->faulty)
+				rdev = NULL;
+			if (rdev)
+				atomic_inc(&rdev->nr_pending);
+			spin_unlock_irq(&conf->device_lock);
+
+			if (rdev) {
+				if (test_bit(R5_Syncio, &sh->dev[i].flags))
+					md_sync_acct(rdev, STRIPE_SECTORS);
+
+				bi->bi_bdev = rdev->bdev;
+				PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, bi->bi_rw, i);
 				atomic_inc(&sh->count);
 				bi->bi_sector = sh->sector;
-				if (action[i] == READ+1) 
-					bi->bi_rw = 0;
-				else
-					bi->bi_rw = 1;
 				bi->bi_flags = 0;
 				bi->bi_vcnt = 1;	
 				bi->bi_idx = 0;
@@ -1190,7 +1175,7 @@
 				bi->bi_next = NULL;
 				generic_make_request(bi);
 			} else {
-				PRINTK("skip op %d on disc %d for sector %ld\n", action[i]-1, i, sh->sector);
+				PRINTK("skip op %d on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector);
 				clear_bit(R5_LOCKED, &dev->flags);
 				set_bit(STRIPE_HANDLE, &sh->state);
 			}
@@ -1363,7 +1348,7 @@
 static int run (mddev_t *mddev)
 {
 	raid5_conf_t *conf;
-	int i, raid_disk, memory;
+	int raid_disk, memory;
 	mdk_rdev_t *rdev;
 	struct disk_info *disk;
 	struct list_head *tmp;
@@ -1399,60 +1384,17 @@
 	PRINTK("raid5: run(md%d) called.\n", mdidx(mddev));
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		/*
-		 * This is important -- we are using the descriptor on
-		 * the disk only to get a pointer to the descriptor on
-		 * the main superblock, which might be more recent.
-		 */
 		raid_disk = rdev->raid_disk;
+		if (raid_disk > mddev->raid_disks
+		    || raid_disk < 0)
+			continue;
 		disk = conf->disks + raid_disk;
 
-		if (rdev->faulty) {
-			printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", bdev_partition_name(rdev->bdev));
-			disk->bdev = rdev->bdev;
-
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 0;
-			disk->used_slot = 1;
-			continue;
-		}
+		disk->rdev = rdev;
+
 		if (rdev->in_sync) {
-			if (disk->operational) {
-				printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", bdev_partition_name(rdev->bdev), raid_disk);
-				continue;
-			}
 			printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", bdev_partition_name(rdev->bdev), raid_disk);
-	
-			disk->bdev = rdev->bdev;
-			disk->operational = 1;
-			disk->used_slot = 1;
-
 			conf->working_disks++;
-		} else {
-			/*
-			 * Must be a spare disk ..
-			 */
-			printk(KERN_INFO "raid5: spare disk %s\n", bdev_partition_name(rdev->bdev));
-			disk->bdev = rdev->bdev;
-
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 1;
-			disk->used_slot = 1;
-		}
-	}
-
-	for (i = 0; i < conf->raid_disks; i++) {
-		disk = conf->disks + i;
-
-		if (!disk->used_slot) {
-			disk->bdev = NULL;
-
-			disk->operational = 0;
-			disk->write_only = 0;
-			disk->spare = 0;
-			disk->used_slot = 1;
 		}
 	}
 
@@ -1467,14 +1409,6 @@
 	conf->algorithm = mddev->layout;
 	conf->max_nr_stripes = NR_STRIPES;
 
-#if 0
-	for (i = 0; i < conf->raid_disks; i++) {
-		if (!conf->disks[i].used_slot) {
-			MD_BUG();
-			goto abort;
-		}
-	}
-#endif
 	if (!conf->chunk_size || conf->chunk_size % 4) {
 		printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", conf->chunk_size, mdidx(mddev));
 		goto abort;
@@ -1519,7 +1453,7 @@
 		       mddev->raid_disks-mddev->degraded, mddev->raid_disks, conf->algorithm);
 	else
 		printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev),
-		       mddev->raid_disks = mddev->degraded, mddev->raid_disks, conf->algorithm);
+		       mddev->raid_disks - mddev->degraded, mddev->raid_disks, conf->algorithm);
 
 	print_raid5_conf(conf);
 
@@ -1596,7 +1530,9 @@
 	sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
 	sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
-		sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_");
+		sz += sprintf (page+sz, "%s",
+			       conf->disks[i].rdev &&
+			       conf->disks[i].rdev->in_sync ? "U" : "_");
 	sz += sprintf (page+sz, "]");
 #if RAID5_DEBUG
 #define D(x) \
@@ -1619,149 +1555,36 @@
 	printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks,
 		 conf->working_disks, conf->failed_disks);
 
-#if RAID5_DEBUG
-	for (i = 0; i < MD_SB_DISKS; i++) {
-#else
-	for (i = 0; i < conf->working_disks+conf->failed_disks; i++) {
-#endif
+	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->disks + i;
-		printk(" disk %d, s:%d, o:%d, us:%d dev:%s\n",
-			i, tmp->spare,tmp->operational,
-			tmp->used_slot,
-			bdev_partition_name(tmp->bdev));
+		if (tmp->rdev)
+		printk(" disk %d, o:%d, dev:%s\n",
+			i, !tmp->rdev->faulty,
+			bdev_partition_name(tmp->rdev->bdev));
 	}
 }
 
 static int raid5_spare_active(mddev_t *mddev)
 {
-	int err = 0;
-	int i, failed_disk=-1, spare_disk=-1;
+	int i;
 	raid5_conf_t *conf = mddev->private;
-	struct disk_info *tmp, *sdisk, *fdisk;
-	mdk_rdev_t *spare_rdev, *failed_rdev;
+	struct disk_info *tmp;
 
-	print_raid5_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->disks + i;
-		if ((!tmp->operational && !tmp->spare) ||
-				!tmp->used_slot) {
-			failed_disk = i;
-			break;
+		if (tmp->rdev
+		    && !tmp->rdev->faulty
+		    && !tmp->rdev->in_sync) {
+			mddev->degraded--;
+			conf->failed_disks--;
+			conf->working_disks++;
+			tmp->rdev->in_sync = 1;
 		}
 	}
-	if (failed_disk == -1) {
-		MD_BUG();
-		err = 1;
-		goto abort;
-	}
-	/*
-	 * Find the spare disk ... (can only be in the 'high'
-	 * area of the array)
-	 */
-	spare_disk = mddev->spare->raid_disk;
-
-	if (!conf->spare) {
-		MD_BUG();
-		err = 1;
-		goto abort;
-	}
-	sdisk = conf->disks + spare_disk;
-	fdisk = conf->disks + failed_disk;
-
-	/*
-	 * do the switch finally
-	 */
-	spare_rdev = find_rdev_nr(mddev, spare_disk);
-	failed_rdev = find_rdev_nr(mddev, failed_disk);
-
-	/* There must be a spare_rdev, but there may not be a
-	 * failed_rdev.  That slot might be empty...
-	 */
-	spare_rdev->desc_nr = failed_disk;
-	spare_rdev->raid_disk = failed_disk;
-	if (failed_rdev) {
-		failed_rdev->desc_nr = spare_disk;
-		failed_rdev->raid_disk = spare_disk;
-	}
-	
-	xchg_values(*fdisk, *sdisk);
-
-	/*
-	 * (careful, 'failed' and 'spare' are switched from now on)
-	 *
-	 * we want to preserve linear numbering and we want to
-	 * give the proper raid_disk number to the now activated
-	 * disk. (this means we switch back these values)
-	 */
-
-	if (!sdisk->bdev)
-		sdisk->used_slot = 0;
-
-	/*
-	 * this really activates the spare.
-	 */
-	fdisk->spare = 0;
-	fdisk->write_only = 0;
-
-	/*
-	 * if we activate a spare, we definitely replace a
-	 * non-operational disk slot in the 'low' area of
-	 * the disk array.
-	 */
-	mddev->degraded--;
-	conf->failed_disks--;
-	conf->working_disks++;
-	conf->spare = NULL;
-abort:
 	spin_unlock_irq(&conf->device_lock);
 	print_raid5_conf(conf);
-	return err;
-}
-
-static int raid5_spare_inactive(mddev_t *mddev)
-{
-	raid5_conf_t *conf = mddev->private;
-	struct disk_info *p;
-	int err = 0;
-
-	print_raid5_conf(conf);
-	spin_lock_irq(&conf->device_lock);
-	p = conf->disks + mddev->spare->raid_disk;
-	if (p) {
-		p->operational = 0;
-		p->write_only = 0;
-		if (conf->spare == p)
-			conf->spare = NULL;
-	} else {
-		MD_BUG();
-		err = 1;
-	}
-	spin_unlock_irq(&conf->device_lock);
-	print_raid5_conf(conf);
-	return err;
-}
-
-static int raid5_spare_write(mddev_t *mddev)
-{
-	raid5_conf_t *conf = mddev->private;
-	struct disk_info *p;
-	int err = 0;
-
-	print_raid5_conf(conf);
-	spin_lock_irq(&conf->device_lock);
-	p = conf->disks + mddev->spare->raid_disk;
-	if (p && !conf->spare) {
-		p->operational = 1;
-		p->write_only = 1;
-		conf->spare = p;
-	} else {
-		MD_BUG();
-		err = 1;
-	}
-	spin_unlock_irq(&conf->device_lock);
-	print_raid5_conf(conf);
-	return err;
+	return 0;
 }
 
 static int raid5_remove_disk(mddev_t *mddev, int number)
@@ -1773,13 +1596,13 @@
 	print_raid5_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 
-	if (p->used_slot) {
-		if (p->operational) {
+	if (p->rdev) {
+		if (p->rdev->in_sync || 
+		    atomic_read(&p->rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
 		}
-		p->bdev = NULL;
-		p->used_slot = 0;
+		p->rdev = NULL;
 		err = 0;
 	}
 	if (err)
@@ -1793,29 +1616,25 @@
 static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	raid5_conf_t *conf = mddev->private;
-	int err = 1;
-	struct disk_info *p = conf->disks + rdev->raid_disk;
+	int found = 0;
+	int disk;
+	struct disk_info *p;
 
-	print_raid5_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 	/*
 	 * find the disk ...
 	 */
-
-	if (!p->used_slot) {
-		/* it will be held open by rdev */
-		p->bdev = rdev->bdev;
-		p->operational = 0;
-		p->write_only = 0;
-		p->spare = 1;
-		p->used_slot = 1;
-		err = 0;
-	}
-	if (err)
-		MD_BUG();
+	for (disk=0; disk < mddev->raid_disks; disk++)
+		if ((p=conf->disks + disk)->rdev == NULL) {
+			p->rdev = rdev;
+			rdev->in_sync = 0;
+			rdev->raid_disk = disk;
+			found = 1;
+			break;
+		}
 	spin_unlock_irq(&conf->device_lock);
 	print_raid5_conf(conf);
-	return err;
+	return found;
 }
 
 static mdk_personality_t raid5_personality=
@@ -1828,8 +1647,6 @@
 	.error_handler	= error,
 	.hot_add_disk	= raid5_add_disk,
 	.hot_remove_disk= raid5_remove_disk,
-	.spare_write	= raid5_spare_write,
-	.spare_inactive	= raid5_spare_inactive,
 	.spare_active	= raid5_spare_active,
 	.sync_request	= sync_request,
 };
diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/message/i2o/i2o_block.c	Tue Aug 27 12:28:08 2002
@@ -59,6 +59,7 @@
 #include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
+#include <linux/bio.h>
 
 #include <linux/notifier.h>
 #include <linux/reboot.h>
@@ -173,6 +174,7 @@
 	struct i2ob_request request_queue[MAX_I2OB_DEPTH];
 	struct i2ob_request *i2ob_qhead;
 	request_queue_t req_queue;
+	spinlock_t lock;
 };
 static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
 static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
@@ -185,7 +187,8 @@
 static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
 static int i2ob_dev_count = 0;
 static struct hd_struct i2ob[MAX_I2OB<<4];
-static struct gendisk i2ob_gendisk;	/* Declared later */
+static struct gendisk i2o_disk[MAX_I2OB];
+static char i2o_names[MAX_I2OB * 8];
 
 /*
  * Mutex and spin lock for event handling synchronization
@@ -211,7 +214,6 @@
 static int i2ob_init_iop(unsigned int);
 static request_queue_t* i2ob_get_queue(kdev_t);
 static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
-static int do_i2ob_revalidate(kdev_t, int);
 static int i2ob_evt(void *);
 
 static int evt_pid = 0;
@@ -477,10 +479,10 @@
 		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
 		ireq->req->errors++;
 
-		spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 		i2ob_unhook_request(ireq, c->unit);
 		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 	
 		/* Now flush the message by making it a NOP */
 		m[0]&=0x00FFFFFF;
@@ -501,12 +503,12 @@
 
 	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
 	{
-		spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 		dev->constipated=0;
 		DEBUG(("unconstipated\n"));
 		if(i2ob_backlog_request(c, dev)==0)
 			i2ob_request(dev->req_queue);
-		spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		return;
 	}
 
@@ -522,10 +524,10 @@
 		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
 		ireq->req->errors++;
 		printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n");
-		spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 		i2ob_unhook_request(ireq, c->unit);
 		i2ob_end_request(ireq->req);
-		spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		return;
 	}	
 
@@ -571,7 +573,7 @@
 		 */
 		 
 		
-		spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 		if(err==4)
 		{
 			/*
@@ -616,7 +618,7 @@
 			 */
 			 
 			i2ob_request(dev->req_queue);
-			spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+			spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 			
 			/*
 			 *	and out
@@ -624,7 +626,7 @@
 			 
 			return;	
 		}
-		spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
 			bsa_errors[m[4]&0XFFFF]);
 		if(m[4]&0x00FF0000)
@@ -640,7 +642,7 @@
 	 *	may be running polled controllers from a BH...
 	 */
 
-	spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+	spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 	i2ob_unhook_request(ireq, c->unit);
 	i2ob_end_request(ireq->req);
 	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
@@ -652,7 +654,7 @@
 	if(i2ob_backlog_request(c, dev)==0)
 		i2ob_request(dev->req_queue);
 
-	spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+	spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 }
 
 /* 
@@ -715,8 +717,14 @@
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_LOAD:
 			{
+				struct gendisk *p = &i2o_disk[unit>>4];
 				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
 					i2ob_dev[unit].i2odev, unit);
+				add_gendisk(p);
+				register_disk(p,
+					      mk_kdev(p->major, p->first_minor),
+					      1<<p->minor_shift, p->fops,
+					      i2ob[unit].nr_sects);
 				break;
 			}
 
@@ -728,12 +736,11 @@
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
 			{
+				struct gendisk *p = &i2o_disk[unit>>4];
+				wipe_partitions(mk_kdev(MAJOR_NR, unit));
+				del_gendisk(p);
 				for(i = unit; i <= unit+15; i++)
-				{
 					blk_queue_max_sectors(i2ob_dev[i].req_queue, 0);
-					i2ob[i].nr_sects = 0;
-					i2ob_gendisk.part[i].nr_sects = 0;
-				}
 				i2ob_media_change_flag[unit] = 1;
 				break;
 			}
@@ -758,16 +765,12 @@
 			{
 				u64 size;
 
-				if(do_i2ob_revalidate(mk_kdev(MAJOR_NR, unit),0) != -EBUSY)
-					continue;
-
 	  			if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 )
 					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
 
-				spin_lock_irqsave(&I2O_LOCK(unit), flags);	
-				i2ob_gendisk.part[unit].nr_sects = size>>9;
-				i2ob[unit].nr_sects = (int)(size>>9);
-				spin_unlock_irqrestore(&I2O_LOCK(unit), flags);	
+				spin_lock_irqsave(I2O_LOCK(unit), flags);	
+				i2ob[unit].nr_sects = size>>9;
+				spin_unlock_irqrestore(I2O_LOCK(unit), flags);	
 				break;
 			}
 
@@ -827,7 +830,7 @@
 	 * We cannot touch the request queue or the timer
          * flag without holding the queue_lock
 	 */
-	spin_lock_irqsave(&req_queue->queue_lock,flags);
+	spin_lock_irqsave(req_queue->queue_lock,flags);
 
 	/* 
 	 * Clear the timer started flag so that 
@@ -843,7 +846,7 @@
 	/* 
 	 * Free the lock.
 	 */
-	spin_unlock_irqrestore(&req_queue->queue_lock,flags);
+	spin_unlock_irqrestore(req_queue->queue_lock,flags);
 }
 
 static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
@@ -1028,37 +1031,6 @@
 	*hds  = (unsigned char) heads; 
 }
 
-
-/*
- *	Rescan the partition tables
- */
- 
-static int do_i2ob_revalidate(kdev_t dev, int maxu)
-{
-	int minor=minor(dev);
-	int i;
-	
-	minor&=0xF0;
-
-	i2ob_dev[minor].refcnt++;
-	if(i2ob_dev[minor].refcnt>maxu+1)
-	{
-		i2ob_dev[minor].refcnt--;
-		return -EBUSY;
-	}
-	
-	wipe_partitions(mk_kdev(MAJOR_NR, minor), 1);
-
-	/*
-	 *	Do a physical check and then reconfigure
-	 */
-	 
-	i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
-		minor);
-	i2ob_dev[minor].refcnt--;
-	return 0;
-}
-
 /*
  *	Issue device specific ioctl calls.
  */
@@ -1066,33 +1038,19 @@
 static int i2ob_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
+	struct hd_geometry g;
+	int u = minor(inode->i_rdev) & 0xF0;
 	/* Anyone capable of this syscall can do *real bad* things */
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	if (!inode || kdev_none(inode->i_rdev))
-		return -EINVAL;
 
-	switch (cmd) {
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g;
-			int u = minor(inode->i_rdev) & 0xF0;
-			i2o_block_biosparam(i2ob[u].nr_sects, 
+	if (cmd != HDIO_GETGEO)
+		return -EINVAL;
+	i2o_block_biosparam(i2ob[u].nr_sects, 
 				&g.cylinders, &g.heads, &g.sectors);
-			g.start = get_start_sect(inode->i_bdev);
-			return copy_to_user((void *)arg, &g, sizeof(g))
-				? -EFAULT : 0;
-		}
-	
-		case BLKRRPART:
-			if(!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return do_i2ob_revalidate(inode->i_rdev,1);
-			
-		default:
-			return -EINVAL;
-	}
+	g.start = get_start_sect(inode->i_bdev);
+	return copy_to_user((void *)arg, &g, sizeof(g)) ? -EFAULT : 0;
 }
 
 /*
@@ -1265,8 +1223,7 @@
 	
 	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
-	i2ob_gendisk.part[unit].nr_sects = size>>9;
-	i2ob[unit].nr_sects = (int)(size>>9);
+	i2ob[unit].nr_sects = size>>9;
 
 	/* Set limit based on inbound frame size */
 	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
@@ -1303,7 +1260,7 @@
 	}
 
 
-	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
+	strcpy(d->dev_name, i2o_disk[unit>>4].major_name);
 
 	printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n",
 		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, limit);
@@ -1363,8 +1320,6 @@
 	 */
 	dev->req_queue = &i2ob_queues[c->unit]->req_queue;
 
-	grok_partitions(mk_kdev(MAJOR_NR, unit), (long)(size>>9));
-
 	/*
 	 * Register for the events we're interested in and that the
 	 * device actually supports.
@@ -1372,6 +1327,7 @@
 	i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, 
 		(I2OB_EVENT_MASK & d->lct_data.event_capabilities));
 
+	i2ob[unit].nr_sects = size>>9;
 	return 0;
 }
 
@@ -1398,13 +1354,14 @@
 			&i2ob_queues[unit]->request_queue[i+1];
 		i2ob_queues[unit]->request_queue[i].num = i;
 	}
+	i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED;
 	
 	/* Queue is MAX_I2OB + 1... */
 	i2ob_queues[unit]->request_queue[i].next = NULL;
 	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
 	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
 
-	blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request);
+	blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request, &i2ob_queues[unit]->lock);
 	i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit];
 
 	return 0;
@@ -1510,6 +1467,12 @@
 					printk(KERN_WARNING "Could not install I2O block device\n");
 				else
 				{
+					struct gendisk *p = &i2o_disk[scan_unit>>4];
+					add_gendisk(p);
+					register_disk(p,
+						      mk_kdev(p->major, p->first_minor),
+						      1<<p->minor_shift, p->fops,
+						      i2ob[scan_unit].nr_sects);
 					scan_unit+=16;
 					i2ob_dev_count++;
 
@@ -1597,6 +1560,12 @@
 		printk(KERN_ERR "i2o_block: Could not install new device\n");
 	else	
 	{
+		struct gendisk *p = &i2o_disk[unit>>4];
+		add_gendisk(p);
+		register_disk(p,
+			      mk_kdev(p->major, p->first_minor),
+			      1<<p->minor_shift, p->fops,
+			      i2ob[unit].nr_sects);
 		i2ob_dev_count++;
 		i2o_device_notify_on(d, &i2o_block_handler);
 	}
@@ -1617,7 +1586,7 @@
 	int i = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&I2O_LOCK(c->unit), flags);
+	spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 
 	/*
 	 * Need to do this...we somtimes get two events from the IRTOS
@@ -1639,7 +1608,7 @@
 	if(unit >= MAX_I2OB<<4)
 	{
 		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
-		spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		return;
 	}
 
@@ -1647,15 +1616,15 @@
 	 * This will force errors when i2ob_get_queue() is called
 	 * by the kenrel.
 	 */
+	wipe_partitions(mk_kdev(MAJOR_NR, unit));
+	del_gendisk(&i2o_disk[unit>>4]);
 	i2ob_dev[unit].req_queue = NULL;
 	for(i = unit; i <= unit+15; i++)
 	{
 		i2ob_dev[i].i2odev = NULL;
 		blk_queue_max_sectors(i2ob_dev[i].req_queue, 0);
-		i2ob[i].nr_sects = 0;
-		i2ob_gendisk.part[i].nr_sects = 0;
 	}
-	spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags);
+	spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 
 	/*
 	 * Decrease usage count for module
@@ -1694,7 +1663,9 @@
 
 static int i2ob_revalidate(kdev_t dev)
 {
-	return do_i2ob_revalidate(dev, 0);
+	int minor = minor(dev) & ~15;
+	return i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
+		minor);
 }
 
 /*
@@ -1751,17 +1722,6 @@
 	revalidate:		i2ob_revalidate,
 };
 
-static struct gendisk i2ob_gendisk = 
-{
-	major:		MAJOR_NR,
-	major_name:	"i2o/hd",
-	minor_shift:	4,
-	part:		i2ob,
-	nr_real:	MAX_I2OB,
-	fops:		&i2ob_fops,
-};
-
-
 /*
  * And here should be modules and kernel interface 
  *  (Just smiley confuses emacs :-)
@@ -1797,8 +1757,6 @@
 	 
 	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
 	
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
-
 	for (i = 0; i < MAX_I2OB << 4; i++) {
 		i2ob_dev[i].refcnt = 0;
 		i2ob_dev[i].flags = 0;
@@ -1809,6 +1767,18 @@
 		i2ob_dev[i].tail = NULL;
 		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
 	}
+
+	for (i = 0; i < MAX_I2OB; i++) {
+		struct gendisk *disk = i2o_disk + i;
+		disk->major = MAJOR_NR;
+		disk->first_minor = i<<4;
+		disk->minor_shift = 4;
+		disk->part = i2ob + (i<<4);
+		disk->fops = &i2ob_fops;
+		disk->nr_real = 1;
+		disk->major_name = i2o_names + i*8;
+		sprintf(disk->major_name, "i2o/hd%c", 'a' + i);
+	}
 	
 	/*
 	 *	Set up the queue
@@ -1834,7 +1804,6 @@
 	if(i2o_install_handler(&i2o_block_handler)<0)
 	{
 		unregister_blkdev(MAJOR_NR, "i2o_block");
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 		printk(KERN_ERR "i2o_block: unable to register OSM.\n");
 		return -EINVAL;
 	}
@@ -1856,15 +1825,8 @@
 	/*
 	 *	Finally see what is actually plugged in to our controllers
 	 */
-	for (i = 0; i < MAX_I2OB; i++)
-		register_disk(&i2ob_gendisk, mk_kdev(MAJOR_NR,i<<4), 1<<4,
-			&i2ob_fops, 0);
-	i2ob_probe();
 
-	/*
-	 *	Adding i2ob_gendisk into the gendisk list.
-	 */
-	add_gendisk(&i2ob_gendisk);
+	i2ob_probe();
 
 	return 0;
 }
@@ -1927,12 +1889,5 @@
 	 */
 	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
 		printk("i2o_block: cleanup_module failed\n");
-
-	/*
-	 * free request queue
-	 */
-	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-
-	del_gendisk(&i2ob_gendisk);
 }
 #endif
diff -Nru a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in
--- a/drivers/mtd/maps/Config.in	Tue Aug 27 12:28:06 2002
+++ b/drivers/mtd/maps/Config.in	Tue Aug 27 12:28:06 2002
@@ -26,7 +26,7 @@
    dep_tristate '  JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
-   dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_X86 $CONFIG_MTD_JEDEC
+   dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDEC
 fi
 
 if [ "$CONFIG_PPC" = "y" ]; then
@@ -47,7 +47,7 @@
 fi
 
 if [ "$CONFIG_SUPERH" = "y" ]; then
-   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SUPERH $CONFIG_MTD_REDBOOT_PARTS
+   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_MTD_REDBOOT_PARTS
 fi
 
 if [ "$CONFIG_ARM" = "y" ]; then
diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c
--- a/drivers/net/3c501.c	Tue Aug 27 12:27:45 2002
+++ b/drivers/net/3c501.c	Tue Aug 27 12:27:45 2002
@@ -103,7 +103,6 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/ptrace.h>
 #include <linux/fcntl.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/net/3c505.c	Tue Aug 27 12:28:06 2002
@@ -102,7 +102,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c
--- a/drivers/net/3c507.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/3c507.c	Tue Aug 27 12:28:08 2002
@@ -51,7 +51,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/string.h>
diff -Nru a/drivers/net/3c515.c b/drivers/net/3c515.c
--- a/drivers/net/3c515.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/net/3c515.c	Tue Aug 27 12:28:01 2002
@@ -64,7 +64,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c
--- a/drivers/net/3c527.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/3c527.c	Tue Aug 27 12:28:07 2002
@@ -88,7 +88,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/mca.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
diff -Nru a/drivers/net/7990.c b/drivers/net/7990.c
--- a/drivers/net/7990.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/7990.c	Tue Aug 27 12:28:08 2002
@@ -18,7 +18,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/8139cp.c	Tue Aug 27 12:28:05 2002
@@ -188,8 +188,8 @@
 	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
 	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
 	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
-	RxProtoTCP	= 2,
-	RxProtoUDP	= 1,
+	RxProtoTCP	= 1,
+	RxProtoUDP	= 2,
 	RxProtoIP	= 3,
 	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
 	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
diff -Nru a/drivers/net/82596.c b/drivers/net/82596.c
--- a/drivers/net/82596.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/net/82596.c	Tue Aug 27 12:28:01 2002
@@ -46,7 +46,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c
--- a/drivers/net/8390.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/8390.c	Tue Aug 27 12:27:59 2002
@@ -55,7 +55,6 @@
 #include <linux/jiffies.h>
 #include <linux/fs.h>
 #include <linux/types.h>
-#include <linux/ptrace.h>
 #include <linux/string.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
diff -Nru a/drivers/net/a2065.c b/drivers/net/a2065.c
--- a/drivers/net/a2065.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/a2065.c	Tue Aug 27 12:28:07 2002
@@ -42,7 +42,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/string.h>
diff -Nru a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c
--- a/drivers/net/aironet4500_card.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/aironet4500_card.c	Tue Aug 27 12:28:07 2002
@@ -23,7 +23,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/tqueue.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
diff -Nru a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c
--- a/drivers/net/aironet4500_proc.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/aironet4500_proc.c	Tue Aug 27 12:27:59 2002
@@ -18,7 +18,6 @@
 
 #include <linux/sched.h>
 #include <linux/tqueue.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
diff -Nru a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
--- a/drivers/net/am79c961a.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/am79c961a.c	Tue Aug 27 12:28:08 2002
@@ -18,7 +18,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in
--- a/drivers/net/appletalk/Config.in	Tue Aug 27 12:27:45 2002
+++ b/drivers/net/appletalk/Config.in	Tue Aug 27 12:27:45 2002
@@ -2,8 +2,6 @@
 # Appletalk driver configuration
 #
 
-mainmenu_option next_comment
-comment 'Appletalk devices'
 dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK
 if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then
    tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
@@ -18,4 +16,4 @@
       bool '    Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
    fi
 fi
-endmenu
+
diff -Nru a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
--- a/drivers/net/appletalk/cops.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/net/appletalk/cops.c	Tue Aug 27 12:28:06 2002
@@ -181,7 +181,7 @@
         int board;			/* Holds what board type is. */
 	int nodeid;			/* Set to 1 once have nodeid. */
         unsigned char node_acquire;	/* Node ID when acquired. */
-        struct at_addr node_addr;	/* Full node address */
+        struct atalk_addr node_addr;	/* Full node address */
 };
 
 /* Index to functions, as function prototypes. */
@@ -955,8 +955,8 @@
 static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct cops_local *lp = (struct cops_local *)dev->priv;
-        struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr;
-        struct at_addr *aa=(struct at_addr *)&lp->node_addr;
+        struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
+        struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;
 
         switch(cmd)
         {
diff -Nru a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
--- a/drivers/net/appletalk/ipddp.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/appletalk/ipddp.c	Tue Aug 27 12:27:59 2002
@@ -116,7 +116,7 @@
 	u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
         struct ddpehdr *ddp;
         struct ipddp_route *rt;
-        struct at_addr *our_addr;
+        struct atalk_addr *our_addr;
 
 	/*
          * Find appropriate route to use, based only on IP number.
diff -Nru a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
--- a/drivers/net/appletalk/ipddp.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/appletalk/ipddp.h	Tue Aug 27 12:28:08 2002
@@ -15,7 +15,7 @@
 {
         struct net_device *dev;             /* Carrier device */
         __u32 ip;                       /* IP address */
-        struct at_addr at;              /* Gateway appletalk address */
+        struct atalk_addr at;              /* Gateway appletalk address */
         int flags;
         struct ipddp_route *next;
 };
diff -Nru a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
--- a/drivers/net/appletalk/ltpc.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/appletalk/ltpc.c	Tue Aug 27 12:28:02 2002
@@ -262,7 +262,7 @@
 struct ltpc_private
 {
 	struct net_device_stats stats;
-	struct at_addr my_addr;
+	struct atalk_addr my_addr;
 };
 
 /* transmit queue element struct */
@@ -826,7 +826,7 @@
 {
 	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
 	/* we'll keep the localtalk node address in dev->pa_addr */
-	struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr;
+	struct atalk_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr;
 	struct lt_init c;
 	int ltflags;
 
diff -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c
--- a/drivers/net/ariadne.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/ariadne.c	Tue Aug 27 12:28:07 2002
@@ -40,7 +40,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c
--- a/drivers/net/at1700.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/at1700.c	Tue Aug 27 12:28:02 2002
@@ -43,7 +43,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
--- a/drivers/net/atari_bionet.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/atari_bionet.c	Tue Aug 27 12:28:07 2002
@@ -90,7 +90,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
--- a/drivers/net/atari_pamsnet.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/atari_pamsnet.c	Tue Aug 27 12:28:02 2002
@@ -84,7 +84,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/atarilance.c b/drivers/net/atarilance.c
--- a/drivers/net/atarilance.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/atarilance.c	Tue Aug 27 12:28:02 2002
@@ -51,7 +51,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/net/atp.c b/drivers/net/atp.c
--- a/drivers/net/atp.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/atp.c	Tue Aug 27 12:28:05 2002
@@ -129,7 +129,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c
--- a/drivers/net/bagetlance.c	Tue Aug 27 12:27:56 2002
+++ b/drivers/net/bagetlance.c	Tue Aug 27 12:27:56 2002
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c
--- a/drivers/net/bonding.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/bonding.c	Tue Aug 27 12:28:02 2002
@@ -195,7 +195,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -399,7 +398,7 @@
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
-	struct mii_ioctl_data mii;
+	struct mii_ioctl_data *mii;
 	struct ethtool_value etool;
 
 	if ((ioctl = dev->do_ioctl) != NULL)  { /* ioctl to access MII */
@@ -425,21 +424,24 @@
 			} 
 		}
 
-		ifr.ifr_data = (char*)&mii;
-                /* try MIIPHY first then, if that doesn't work, try MIIREG */
-		if (ioctl(dev, &ifr, SIOCGMIIPHY) == 0) {
-			/* now, mii.phy_id contains info about link status :
-			- mii.phy_id & 0x04 means link up
-			- mii.phy_id & 0x20 means end of auto-negociation
-			*/
-			return mii.phy_id;
+		/*
+		 * We cannot assume that SIOCGMIIPHY will also read a
+		 * register; not all network drivers support that.
+		 */
+
+		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+		if (ioctl(dev, &ifr, SIOCGMIIPHY) != 0) {
+			return MII_LINK_READY;	 /* can't tell */
 		}
 
-		mii.reg_num = 1; /* the MII register we want to read */  
+		mii->reg_num = 1;
 		if (ioctl(dev, &ifr, SIOCGMIIREG) == 0) {
-			/* mii.val_out contians the same link info as phy_id */
-			/* above                                             */
-			return mii.val_out;
+			/*
+			 * mii->val_out contains MII reg 1, BMSR
+			 * 0x0004 means link established
+			 */
+			return mii->val_out;
 		}
 
 	}
@@ -641,12 +643,6 @@
 	 */
 	write_lock_irqsave(&bond->lock, flags);
 
-	/*
-	 * Lock the master device so that noone trys to transmit
-	 * while we're changing things
-	 */
-	spin_lock_bh(&master->xmit_lock);
-
 	/* set promiscuity flag to slaves */
 	if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
 		bond_set_promiscuity(bond, 1); 
@@ -680,7 +676,6 @@
 	bond_mc_list_destroy (bond);
 	bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
 
-	spin_unlock_bh(&master->xmit_lock);
 	write_unlock_irqrestore(&bond->lock, flags);
 }
 
diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
--- a/drivers/net/cs89x0.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/cs89x0.c	Tue Aug 27 12:28:08 2002
@@ -120,7 +120,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/de600.c b/drivers/net/de600.c
--- a/drivers/net/de600.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/de600.c	Tue Aug 27 12:28:05 2002
@@ -100,7 +100,6 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <linux/in.h>
-#include <linux/ptrace.h>
 #include <asm/system.h>
 #include <linux/errno.h>
 #include <linux/init.h>
diff -Nru a/drivers/net/de620.c b/drivers/net/de620.c
--- a/drivers/net/de620.c	Tue Aug 27 12:27:40 2002
+++ b/drivers/net/de620.c	Tue Aug 27 12:27:40 2002
@@ -127,7 +127,6 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <linux/in.h>
-#include <linux/ptrace.h>
 #include <asm/system.h>
 #include <linux/errno.h>
 #include <linux/init.h>
diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c
--- a/drivers/net/declance.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/net/declance.c	Tue Aug 27 12:27:57 2002
@@ -72,7 +72,6 @@
 #include <linux/stddef.h>
 #include <linux/string.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/utsname.h>
diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c
--- a/drivers/net/defxx.c	Tue Aug 27 12:27:40 2002
+++ b/drivers/net/defxx.c	Tue Aug 27 12:27:40 2002
@@ -208,7 +208,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/depca.c	Tue Aug 27 12:28:07 2002
@@ -240,7 +240,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
--- a/drivers/net/e100/e100.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/e100/e100.h	Tue Aug 27 12:28:02 2002
@@ -97,6 +97,7 @@
 #include <asm/processor.h>
 #include <linux/ethtool.h>
 #include <linux/inetdevice.h>
+#include <linux/bitops.h>
 
 #include <linux/if.h>
 #include <asm/uaccess.h>
diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c
--- a/drivers/net/eepro.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/eepro.c	Tue Aug 27 12:28:08 2002
@@ -135,7 +135,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/eexpress.c b/drivers/net/eexpress.c
--- a/drivers/net/eexpress.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/net/eexpress.c	Tue Aug 27 12:27:42 2002
@@ -105,7 +105,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/in.h>
@@ -341,7 +340,7 @@
 int __init express_probe(struct net_device *dev)
 {
 	unsigned short *port;
-	static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
+	static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
 	unsigned short ioaddr = dev->base_addr;
 
 	SET_MODULE_OWNER(dev);
diff -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c
--- a/drivers/net/eth16i.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/eth16i.c	Tue Aug 27 12:28:02 2002
@@ -152,7 +152,6 @@
 #include <linux/types.h>		  
 #include <linux/fcntl.h>		  
 #include <linux/interrupt.h>		  
-#include <linux/ptrace.h>		  
 #include <linux/ioport.h>		  
 #include <linux/in.h>		  
 #include <linux/slab.h>		  
diff -Nru a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
--- a/drivers/net/ewrk3.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/ewrk3.c	Tue Aug 27 12:28:05 2002
@@ -143,7 +143,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
--- a/drivers/net/fmv18x.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/fmv18x.c	Tue Aug 27 12:27:59 2002
@@ -42,7 +42,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c
--- a/drivers/net/hamachi.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/hamachi.c	Tue Aug 27 12:28:05 2002
@@ -158,7 +158,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/time.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in
--- a/drivers/net/hamradio/Config.in	Tue Aug 27 12:27:39 2002
+++ b/drivers/net/hamradio/Config.in	Tue Aug 27 12:27:39 2002
@@ -1,4 +1,3 @@
-comment 'AX.25 network device drivers'
 
 dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25
 dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25
diff -Nru a/drivers/net/hplance.c b/drivers/net/hplance.c
--- a/drivers/net/hplance.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/hplance.c	Tue Aug 27 12:28:05 2002
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/string.h>
diff -Nru a/drivers/net/hydra.c b/drivers/net/hydra.c
--- a/drivers/net/hydra.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/hydra.c	Tue Aug 27 12:28:05 2002
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
--- a/drivers/net/irda/ali-ircc.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/irda/ali-ircc.c	Tue Aug 27 12:28:02 2002
@@ -57,7 +57,6 @@
 static unsigned int irq[] = { 0, 0, 0, 0 };
 static unsigned int dma[] = { 0, 0, 0, 0 };
 
-static int  ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);
@@ -252,7 +251,6 @@
 	struct ali_ircc_cb *self;
 	struct pm_dev *pmdev;
 	int dongle_id;
-	int ret;
 	int err;
 			
 	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
@@ -448,16 +446,6 @@
 	 */
 	
 	return 0;
-}
-
-/*
- * Function ali_ircc_probe_43 (chip, info)
- *    	
- *	Probes for the ALi M1543
- */
-static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info)
-{
-	return 0;	
 }
 
 /*
diff -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
--- a/drivers/net/isa-skeleton.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/net/isa-skeleton.c	Tue Aug 27 12:28:05 2002
@@ -47,7 +47,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
--- a/drivers/net/jazzsonic.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/jazzsonic.c	Tue Aug 27 12:28:02 2002
@@ -18,7 +18,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
diff -Nru a/drivers/net/lance.c b/drivers/net/lance.c
--- a/drivers/net/lance.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/lance.c	Tue Aug 27 12:27:59 2002
@@ -45,7 +45,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
--- a/drivers/net/lasi_82596.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/net/lasi_82596.c	Tue Aug 27 12:28:01 2002
@@ -73,7 +73,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/lp486e.c b/drivers/net/lp486e.c
--- a/drivers/net/lp486e.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/lp486e.c	Tue Aug 27 12:28:02 2002
@@ -64,7 +64,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
--- a/drivers/net/mac89x0.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/net/mac89x0.c	Tue Aug 27 12:28:06 2002
@@ -88,7 +88,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/macsonic.c b/drivers/net/macsonic.c
--- a/drivers/net/macsonic.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/macsonic.c	Tue Aug 27 12:27:59 2002
@@ -31,7 +31,6 @@
 #include <linux/ctype.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
diff -Nru a/drivers/net/mvme147.c b/drivers/net/mvme147.c
--- a/drivers/net/mvme147.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/mvme147.c	Tue Aug 27 12:28:02 2002
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/string.h>
diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
--- a/drivers/net/myri_sbus.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/myri_sbus.c	Tue Aug 27 12:27:59 2002
@@ -14,7 +14,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/net/natsemi.c	Tue Aug 27 12:27:57 2002
@@ -1662,7 +1662,7 @@
 		if ((np->tx_config & TxDrthMask) < 62)
 			np->tx_config += 2;
 		if (debug > 2)
-			printk(KERN_NOTICE "%s: increasing Tx theshold, new tx cfg %8.8xh.\n",
+			printk(KERN_NOTICE "%s: increasing Tx threshold, new tx cfg %8.8xh.\n",
 					dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
 	}
diff -Nru a/drivers/net/ne2.c b/drivers/net/ne2.c
--- a/drivers/net/ne2.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/ne2.c	Tue Aug 27 12:28:08 2002
@@ -67,7 +67,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c
--- a/drivers/net/ni65.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/ni65.c	Tue Aug 27 12:28:02 2002
@@ -64,7 +64,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
--- a/drivers/net/pcmcia/xirc2ps_cs.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/pcmcia/xirc2ps_cs.c	Tue Aug 27 12:28:02 2002
@@ -2096,7 +2096,7 @@
 	MAYBE_SET(irq_list[1], 7);
 	MAYBE_SET(irq_list[2], 8);
 	MAYBE_SET(irq_list[3], 9);
-#undef  MAYBE_SET(X,Y)
+#undef  MAYBE_SET
 
 	return 0;
 }
diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/pcnet32.c	Tue Aug 27 12:28:02 2002
@@ -34,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c
--- a/drivers/net/plip.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/plip.c	Tue Aug 27 12:28:08 2002
@@ -95,7 +95,6 @@
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/if_ether.h>
 #include <asm/system.h>
 #include <linux/in.h>
diff -Nru a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c
--- a/drivers/net/rcpci45.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/rcpci45.c	Tue Aug 27 12:28:02 2002
@@ -50,7 +50,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/init.h>
@@ -93,8 +92,6 @@
 
 static void rc_timer (unsigned long);
 
-static int RCinit (struct net_device *);
-
 static int RCopen (struct net_device *);
 static int RC_xmit_packet (struct sk_buff *, struct net_device *);
 static void RCinterrupt (int, void *, struct pt_regs *);
@@ -224,7 +221,7 @@
 	}
 	pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff);
 
-	dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA);
+	dprintk ("pDpa->PLanApiPA = %p\n", pDpa->PLanApiPA);
 
 	/* The adapter is accessible through memory-access read/write, not
 	 * I/O read/write.  Thus, we need to map it to some virtual address
diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c
--- a/drivers/net/sb1000.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/sb1000.c	Tue Aug 27 12:27:59 2002
@@ -41,7 +41,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
--- a/drivers/net/seeq8005.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/net/seeq8005.c	Tue Aug 27 12:28:01 2002
@@ -36,7 +36,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
--- a/drivers/net/sgiseeq.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/sgiseeq.c	Tue Aug 27 12:28:08 2002
@@ -8,7 +8,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/shaper.c b/drivers/net/shaper.c
--- a/drivers/net/shaper.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/shaper.c	Tue Aug 27 12:28:08 2002
@@ -73,7 +73,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/ptrace.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
--- a/drivers/net/sk_g16.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/net/sk_g16.c	Tue Aug 27 12:28:06 2002
@@ -61,7 +61,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/ptrace.h>
 #include <linux/fcntl.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c
--- a/drivers/net/smc9194.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/smc9194.c	Tue Aug 27 12:28:08 2002
@@ -64,7 +64,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
--- a/drivers/net/sun3lance.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/sun3lance.c	Tue Aug 27 12:28:08 2002
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
--- a/drivers/net/sunbmac.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/net/sunbmac.c	Tue Aug 27 12:27:42 2002
@@ -11,7 +11,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/sungem.c	Tue Aug 27 12:28:08 2002
@@ -25,7 +25,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/sunhme.c	Tue Aug 27 12:28:02 2002
@@ -24,7 +24,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sunlance.c b/drivers/net/sunlance.c
--- a/drivers/net/sunlance.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/sunlance.c	Tue Aug 27 12:28:02 2002
@@ -82,7 +82,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/sunqe.c b/drivers/net/sunqe.c
--- a/drivers/net/sunqe.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/sunqe.c	Tue Aug 27 12:28:02 2002
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
diff -Nru a/drivers/net/tc35815.c b/drivers/net/tc35815.c
--- a/drivers/net/tc35815.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/net/tc35815.c	Tue Aug 27 12:27:42 2002
@@ -38,7 +38,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/malloc.h>
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/net/tg3.c	Tue Aug 27 12:28:07 2002
@@ -3337,8 +3337,10 @@
 	/* Clear statistics/status block in chip, and status block in ram. */
 	for (i = NIC_SRAM_STATS_BLK;
 	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
-	     i += sizeof(u32))
+	     i += sizeof(u32)) {
 		tg3_write_mem(tp, i, 0);
+		udelay(40);
+	}
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 
 	/* This value is determined during the probe time DMA
diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
--- a/drivers/net/tokenring/3c359.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/net/tokenring/3c359.c	Tue Aug 27 12:28:08 2002
@@ -51,7 +51,6 @@
 #include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/ptrace.h>
diff -Nru a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
--- a/drivers/net/wan/Config.in	Tue Aug 27 12:27:59 2002
+++ b/drivers/net/wan/Config.in	Tue Aug 27 12:27:59 2002
@@ -39,7 +39,7 @@
 # The Etinc driver has not been tested as non-modular yet.
 #
 
-   dep_tristate '  Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
+   dep_tristate '  Etinc PCISYNC serial board support' CONFIG_DSCC4 m
 
 
 #
diff -Nru a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
--- a/drivers/net/wan/sbni.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/net/wan/sbni.c	Tue Aug 27 12:28:02 2002
@@ -64,11 +64,6 @@
 #include <net/arp.h>
 #include <linux/pci.h>
 
-
-#ifndef MODULE
-#include <linux/string.h>
-#endif
-
 #include <linux/config.h>
 #include "sbni.h"
 
diff -Nru a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c
--- a/drivers/net/wan/sdla_ft1.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/net/wan/sdla_ft1.c	Tue Aug 27 12:28:01 2002
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
diff -Nru a/drivers/net/znet.c b/drivers/net/znet.c
--- a/drivers/net/znet.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/net/znet.c	Tue Aug 27 12:27:42 2002
@@ -65,7 +65,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Tue Aug 27 12:28:07 2002
+++ b/drivers/pci/pci.ids	Tue Aug 27 12:28:07 2002
@@ -7,7 +7,7 @@
 #	so if you have anything to contribute, please visit the home page or
 #	send a diff -u against the most recent pci.ids to pci-ids@ucw.cz.
 #
-#	$Id: pci.ids,v 1.24 2001/10/28 21:55:26 mares Exp $
+#	$Id: pci.ids,v 1.46 2002/08/14 17:38:51 mares Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -26,6 +26,10 @@
 0675  Dynalink
 	1700  IS64PH ISDN Adapter
 	1702  IS64PH ISDN Adapter
+# Wrong ID used in subsystem ID of VIA USB controllers.
+0925  VIA Technologies, Inc. (Wrong ID)
+09c1  Arris
+	0704  CM 200E Cable Modem
 0a89  BREA Technologies Inc
 0e11  Compaq Computer Corporation
 	0001  PCI to EISA Bridge
@@ -47,7 +51,7 @@
 	a0f7  PCI Hotplug Controller
 		8086 002a  PCI Hotplug Controller A
 		8086 002b  PCI Hotplug Controller B
-	a0f8  USB Open Host Controller
+	a0f8  ZFMicro Chipset USB
 	a0fc  Fibre Channel Host Controller
 	ae10  Smart-2/P RAID Controller
 		0e11 4030  Smart-2/P Array Controller
@@ -88,11 +92,12 @@
 	b13c  NC3162 Fast Ethernet NIC
 	b144  NC3123 Fast Ethernet NIC
 	b163  NC3134 Fast Ethernet NIC
-	b164  NC3135 Fast Ethernet Upgrade Module
+	b164  NC3165 Fast Ethernet Upgrade Module
 	b178  Smart Array 5i/532
 	b1a4  NC7131 Gigabit Server Adapter
 	f130  NetFlex-3/P ThunderLAN 1.0
 	f150  NetFlex-3/P ThunderLAN 2.3
+0e55  HaSoTec GmbH
 1000  LSI Logic / Symbios Logic (formerly NCR)
 	0001  53c810
 		1000 1000  8100S
@@ -104,15 +109,22 @@
 	000a  53c1510
 	000b  53c896
 	000c  53c895
+		1de1 3907  DC-390U2W
 	000d  53c885
 	000f  53c875
 		0e11 7004  Embedded Ultra Wide SCSI Controller
 		1092 8760  FirePort 40 Dual SCSI Controller
 		1de1 3904  DC390F Ultra Wide SCSI Controller
+	0010  53c895
+		0e11 4040  Integrated Array Controller
+		0e11 4048  Integrated Array Controller
 	0012  53c895a
+	0013  53c875a
 	0020  53c1010 Ultra3 SCSI Adapter
+		1de1 1020  DC-390U3W
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
 	0030  53c1030
+		1028 1010  LSI U320 SCSI Controller
 	0040  53c1035
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
@@ -122,12 +134,20 @@
 	0623  FC929 LAN
 	0624  FC919
 	0625  FC919 LAN
-	0701  83C885
+	0626  FC929X
+	0627  FC929X LAN
+	0628  FC919X
+	0629  FC919X LAN
+	0701  83C885 NT50 DigitalScape Fast Ethernet
 	0702  Yellowfin G-NIC gigabit ethernet
 		1318 0000  PEI100X
 	0901  61C102
 	1000  63C815
-1001  Initio
+	1960  PowerEdge Expandable RAID Controller 4
+		1028 0518  PowerEdge Expandable RAID Controller 4/DC
+		1028 0520  PowerEdge Expandable RAID Controller 4/SC
+		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+1001  Kolter Electronic
 	0010  PCI 1616 Measurement card with 32 digital I/O lines
 	0011  OPTO-PCI Opto-Isolated digital I/O board
 	0012  PCI-AD/DA Analogue I/O board
@@ -139,28 +159,65 @@
 	9100  INI-9100/9100W SCSI Host
 1002  ATI Technologies Inc
 	4158  68800AX [Mach32]
+	4242  Radeon 8500 DV
+		1002 02aa  Radeon 8500 AIW DV Edition
 	4354  215CT [Mach64 CT]
 	4358  210888CX [Mach64 CX]
 	4554  210888ET [Mach64 ET]
 	4654  Mach64 VT
 	4742  3D Rage Pro AGP 1X/2X
+		1002 0040  Rage Pro Turbo AGP 2X
+		1002 0044  Rage Pro Turbo AGP 2X
+		1002 0061  Rage Pro AIW AGP 2X
+		1002 0062  Rage Pro AIW AGP 2X
+		1002 0063  Rage Pro AIW AGP 2X
+		1002 0080  Rage Pro Turbo AGP 2X
+		1002 0084  Rage Pro Turbo AGP 2X
+		1002 4742  Rage Pro Turbo AGP 2X
+		1002 8001  Rage Pro Turbo AGP 2X
+		1028 0082  Rage Pro Turbo AGP 2X
 		1028 4082  Optiplex GX1 Onboard Display Adapter
-		8086 4152  Rage 3D Pro AGP
+		1028 8082  Rage Pro Turbo AGP 2X
+		1028 c082  Rage Pro Turbo AGP 2X
+		8086 4152  Xpert 98D AGP 2X
+		8086 464a  Rage Pro Turbo AGP 2X
 	4744  3D Rage Pro AGP 1X
+		1002 4744  Rage Pro Turbo AGP
 	4747  3D Rage Pro
 	4749  3D Rage Pro
+		1002 0061  Rage Pro AIW
+		1002 0062  Rage Pro AIW
 	474c  Rage XC
-	474d  Rage XL AGP
+	474d  Rage XL AGP 2X
+		1002 0004  Xpert 98 RXL AGP 2X
+		1002 0008  Xpert 98 RXL AGP 2X
+		1002 0080  Rage XL AGP 2X
+		1002 0084  Xpert 98 AGP 2X
+		1002 474d  Rage XL AGP
+		1033 806a  Rage XL AGP
 	474e  Rage XC AGP
+		1002 474e  Rage XC AGP
 	474f  Rage XL
+		1002 0008  Rage XL
+		1002 474f  Rage XL
 	4750  3D Rage Pro 215GP
+		1002 0040  Rage Pro Turbo
+		1002 0044  Rage Pro Turbo
+		1002 0080  Rage Pro Turbo
+		1002 0084  Rage Pro Turbo
+		1002 4750  Rage Pro Turbo
 	4751  3D Rage Pro 215GQ
 	4752  Rage XL
+		1002 0008  Rage XL
+		1002 4752  Rage XL
 	4753  Rage XC
+		1002 4753  Rage XC
 	4754  3D Rage I/II 215GT [Mach64 GT]
 	4755  3D Rage II+ 215GTB [Mach64 GTB]
 	4756  3D Rage IIC 215IIC [Mach64 GT IIC]
+		1002 4756  Rage IIC
 	4757  3D Rage IIC AGP
+		1002 4757  Rage IIC AGP
 		1028 0089  Rage 3D IIC
 		1028 4082  Rage 3D IIC
 		1028 8082  Rage 3D IIC
@@ -169,78 +226,166 @@
 	4759  3D Rage IIC
 	475a  3D Rage IIC AGP
 		1002 0087  Rage 3D IIC
+		1002 475a  Rage IIC AGP
 	4c42  3D Rage LT Pro AGP-133
 		0e11 b0e8  Rage 3D LT Pro
 		0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)
+		1002 0040  Rage LT Pro AGP 2X
+		1002 0044  Rage LT Pro AGP 2X
+		1002 4c42  Rage LT Pro AGP 2X
+		1002 8001  Rage LT Pro AGP 2X
 		1028 0085  Rage 3D LT Pro
 	4c44  3D Rage LT Pro AGP-66
 	4c45  Rage Mobility M3 AGP
 	4c46  Rage Mobility M3 AGP 2x
 	4c47  3D Rage LT-G 215LG
 	4c49  3D Rage LT Pro
+		1002 0004  Rage LT Pro
+		1002 0040  Rage LT Pro
+		1002 0044  Rage LT Pro
+		1002 4c49  Rage LT Pro
 	4c4d  Rage Mobility P/M AGP 2x
+		1002 0084  Xpert 98 AGP 2X (Mobility)
 	4c4e  Rage Mobility L AGP 2x
 	4c50  3D Rage LT Pro
+		1002 4c50  Rage LT Pro
 	4c51  3D Rage LT Pro
 	4c52  Rage Mobility P/M
 	4c53  Rage Mobility L
 	4c54  264LT [Mach64 LT]
-	4c57  Radeon Mobility M6 LW
+	4c57  Radeon Mobility M7 LW
+		1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)
+	4c58  Radeon Mobility M7 LX [Radeon Mobility FireGL 7800]
 	4c59  Radeon Mobility M6 LY
+		1014 0235  ThinkPad A30p (2653-64G)
+		1014 0239  ThinkPad X22/X23/X24
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	4c5a  Radeon Mobility M6 LZ
 	4d46  Rage Mobility M4 AGP
 	4d4c  Rage Mobility M4 AGP
-	5041  Rage 128 PA
-	5042  Rage 128 PB
-	5043  Rage 128 PC
-	5044  Rage 128 PD
-	5045  Rage 128 PE
-	5046  Rage 128 PF
+	5041  Rage 128 PA/PRO
+	5042  Rage 128 PB/PRO AGP 2x
+	5043  Rage 128 PC/PRO AGP 4x
+	5044  Rage 128 PD/PRO TMDS
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+	5045  Rage 128 PE/PRO AGP 2x TMDS
+	5046  Rage 128 PF/PRO AGP 4x TMDS
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0014  Rage Fury Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 Pro AIW AGP
+		1002 002a  Rage 128 Pro AIW AGP
+		1002 0048  Rage Fury Pro
 		1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)
 		1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)
-	5047  Rage 128 PG
-	5048  Rage 128 PH
-	5049  Rage 128 PI
-	504a  Rage 128 PJ
-	504b  Rage 128 PK
-	504c  Rage 128 PL
-	504d  Rage 128 PM
-	504e  Rage 128 PN
-	504f  Rage 128 PO
-	5050  Rage 128 PP
-	5051  Rage 128 PQ
-	5052  Rage 128 PR
-	5053  Rage 128 PS
-	5054  Rage 128 PT
-	5055  Rage 128 PU
-	5056  Rage 128 PV
-	5057  Rage 128 PW
-	5058  Rage 128 PX
+	5047  Rage 128 PG/PRO
+	5048  Rage 128 PH/PRO AGP 2x
+	5049  Rage 128 PI/PRO AGP 4x
+	504a  Rage 128 PJ/PRO TMDS
+	504b  Rage 128 PK/PRO AGP 2x TMDS
+	504c  Rage 128 PL/PRO AGP 4x TMDS
+	504d  Rage 128 PM/PRO
+	504e  Rage 128 PN/PRO AGP 2x
+	504f  Rage 128 PO/PRO AGP 4x
+	5050  Rage 128 PP/PRO TMDS
+		1002 0008  Xpert 128
+	5051  Rage 128 PQ/PRO AGP 2x TMDS
+	5052  Rage 128 PR/PRO AGP 4x TMDS
+	5053  Rage 128 PS/PRO
+	5054  Rage 128 PT/PRO AGP 2x
+	5055  Rage 128 PU/PRO AGP 4x
+	5056  Rage 128 PV/PRO TMDS
+	5057  Rage 128 PW/PRO AGP 2x TMDS
+	5058  Rage 128 PX/PRO AGP 4x TMDS
 	5144  Radeon QD
+		1002 0008  Radeon 7000/Radeon VE
+		1002 0009  Radeon 7000/Radeon
+		1002 000a  Radeon 7000/Radeon
+		1002 001a  Radeon 7000/Radeon
+		1002 0029  Radeon AIW
+		1002 0038  Radeon 7000/Radeon
+		1002 0039  Radeon 7000/Radeon
+		1002 008a  Radeon 7000/Radeon
+		1002 00ba  Radeon 7000/Radeon
+		1002 0139  Radeon 7000/Radeon
+		1002 028a  Radeon 7000/Radeon
+		1002 02aa  Radeon AIW
+		1002 053a  Radeon 7000/Radeon
 	5145  Radeon QE
 	5146  Radeon QF
 	5147  Radeon QG
-	514c  Radeon 8500 QL
+	5148  Radeon R200 QH [Radeon 8500]
+		1002 0152  FireGL 8800
+		1002 0172  FireGL 8700
+	5149  Radeon R200 QI
+	514a  Radeon R200 QJ
+	514b  Radeon R200 QK
+	514c  Radeon R200 QL [Radeon 8500 LE]
+		1002 003a  Radeon R200 QL [Radeon 8500 LE]
+		1002 013a  Radeon 8500
+	5157  Radeon 7500 QW
+		1002 013a  Radeon 7500
+		174b 7161  Radeon RV200 QW [Radeon 7500 LE]
+	5158  Radeon 7500 QX
 	5159  Radeon VE QY
+		1002 000a  Radeon 7000/Radeon VE
+		1002 0038  Radeon 7000/Radeon VE
+		1002 003a  Radeon 7000/Radeon VE
+		1002 00ba  Radeon 7000/Radeon VE
+		1002 013a  Radeon 7000/Radeon VE
+		174b 7112  Radeon 7000 64M TVO
 	515a  Radeon VE QZ
-	5245  Rage 128 RE
-	5246  Rage 128 RF
+	5168  Radeon R200 Qh
+	5169  Radeon R200 Qi
+	516a  Radeon R200 Qj
+	516b  Radeon R200 Qk
+	5245  Rage 128 RE/SG
+		1002 0008  Xpert 128
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+		1002 0068  Rage 128 AIW
+	5246  Rage 128 RF/SG AGP
+		1002 0004  Magnum/Xpert 128/Xpert 99
+		1002 0008  Magnum/Xpert128/X99/Xpert2000
+		1002 0028  Rage 128 AIW AGP
+		1002 0044  Rage Fury/Xpert 128/Xpert 2000
+		1002 0068  Rage 128 AIW AGP
+		1002 0448  Rage Fury
 	5247  Rage 128 RG
-	524b  Rage 128 RK
-	524c  Rage 128 RL
-	5345  Rage 128 SE
-	5346  Rage 128 SF
-	5347  Rage 128 SG
-	5348  Rage 128 4x
-	534b  Rage 128 SK
-	534c  Rage 128 SL
-	534d  Rage 128 SM
-	534e  Rage 128 SN
+	524b  Rage 128 RK/VR
+	524c  Rage 128 RL/VR AGP
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0088  Xpert 99
+	5345  Rage 128 SE/4x
+	5346  Rage 128 SF/4x AGP 2x
+	5347  Rage 128 SG/4x AGP 4x
+	5348  Rage 128 SH
+	534b  Rage 128 SK/4x
+	534c  Rage 128 SL/4x AGP 2x
+	534d  Rage 128 SM/4x AGP 4x
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0018  Xpert 2000
+	534e  Rage 128 4x
 	5354  Mach 64 VT
 		1002 5654  Mach 64 reference
-	5446  Rage 128 Pro TF
-	544c  Rage 128 Pro TL
-	5452  Rage 128 Pro TR
+	5446  Rage 128 Pro Ultra TF
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 AIW Pro AGP
+		1002 0029  Rage 128 AIW
+		1002 002a  Rage 128 AIW Pro AGP
+		1002 002b  Rage 128 AIW
+		1002 0048  Xpert 2000 Pro
+	544c  Rage 128 Pro Ultra TL
+	5452  Rage 128 Pro Ultra TR
+		1002 001c  Rage 128 Pro 4XL
+		103c 1279  Rage 128 Pro 4XL
+	5453  Rage 128 Pro Ultra TS
+	5454  Rage 128 Pro Ultra TT
+	5455  Rage 128 Pro Ultra TU
 	5654  264VT [Mach64 VT]
 		1002 5654  Mach64VT Reference
 	5655  264VT3 [Mach64 VT3]
@@ -256,7 +401,7 @@
 	000c  82C541 [Lynx]
 	000d  82C543 [Lynx]
 	0101  82C532
-	0102  82C534
+	0102  82C534 [Eagle]
 	0103  82C538
 	0104  82C535
 	0105  82C147
@@ -291,11 +436,17 @@
 	0001  DP83810
 	0002  87415/87560 IDE
 	000e  87560 Legacy I/O
-	000f  OHCI Compliant FireWire Controller
-	0011  National PCI System I/O
+	000f  FireWire Controller
+	0011  NS87560 National PCI System I/O
 	0012  USB Controller
 	0020  DP83815 (MacPhyter) Ethernet Controller
 	0022  DP83820 10/100/1000 Ethernet Controller
+	0500  SCx200 Bridge
+	0501  SCx200 SMI
+	0502  SCx200 IDE
+	0503  SCx200 Audio
+	0504  SCx200 Video
+	0505  SCx200 XBus
 	d001  87410 IDE
 100c  Tseng Labs Inc
 	3202  ET4000/W32p rev A
@@ -306,9 +457,10 @@
 	4702  ET6300
 100d  AST Research Inc
 100e  Weitek
-	9000  P9000
-	9001  P9000
-	9100  P9100
+	9000  P9000 Viper
+	9001  P9000 Viper
+	9002  P9000 Viper
+	9100  P9100 Viper Pro/SE
 1010  Video Logic, Ltd.
 1011  Digital Equipment Corporation
 	0001  DECchip 21050
@@ -317,6 +469,7 @@
 	0007  NVRAM [Zephyr NVRAM]
 	0008  KZPSA [KZPSA]
 	0009  DECchip 21140 [FasterNet]
+		1025 0310  21140 Fast Ethernet
 		10b8 2001  SMC9332BDT EtherPower 10/100
 		10b8 2002  SMC9332BVT EtherPower T4 10/100
 		10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)
@@ -329,6 +482,7 @@
 		1186 1112  DFE-570TX Fast Ethernet
 		1186 1140  DFE-660 Cardbus Ethernet 10/100
 		1186 1142  DFE-660 Cardbus Ethernet 10/100
+		11f6 0503  Freedomline Fast Ethernet
 		1282 9100  AEF-380TXD Fast Ethernet
 		1385 1100  FA310TX Fast Ethernet
 		2646 0001  KNE100TX Fast Ethernet
@@ -339,11 +493,16 @@
 		1186 0100  DE-530+
 	0016  DGLPB [OPPO]
 	0019  DECchip 21142/43
-		1011 500b  DE500 Fast Ethernet
+		1011 500a  DE500A Fast Ethernet
+		1011 500b  DE500B Fast Ethernet
 		1014 0001  10/100 EtherJet Cardbus
 		1025 0315  ALN315 Fast Ethernet
+		1033 800c  PC-9821-CS01
+		1033 800d  PC-9821NR-B06
 		108d 0016  Rapidfire 2327 10/100 Ethernet
+		108d 0017  GoCard 2250 Ethernet 10/100 Cardbus
 		10b8 2005  SMC8032DT Extreme Ethernet 10/100
+		10b8 8034  SMC8034 Extreme Ethernet 10/100
 		10ef 8169  Cardbus Fast Ethernet
 		1109 2a00  ANA-6911A/TX Fast Ethernet
 		1109 2b00  ANA-6911A/TXC Fast Ethernet
@@ -356,25 +515,38 @@
 		1186 1100  DFE-500TX Fast Ethernet
 		1186 1101  DFE-500TX Fast Ethernet
 		1186 1102  DFE-500TX Fast Ethernet
+		1259 2800  AT-2800Tx Fast Ethernet
 		1266 0004  Eagle Fast EtherMAX
 		12af 0019  NetFlyer Cardbus Fast Ethernet
 		1374 0001  Cardbus Ethernet Card 10/100
+		1374 0002  Cardbus Ethernet Card 10/100
+		1374 0007  Cardbus Ethernet Card 10/100
+		1374 0008  Cardbus Ethernet Card 10/100
 		1395 0001  10/100 Ethernet CardBus PC Card
+		13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
+	001a  Farallon PN9000SX
 	0021  DECchip 21052
 	0022  DECchip 21150
 	0023  DECchip 21150
 	0024  DECchip 21152
 	0025  DECchip 21153
 	0026  DECchip 21154
+	0034  56k Modem Cardbus
+		1374 0003  56k Modem Cardbus
 	0045  DECchip 21553
 	0046  DECchip 21554
+		0e11 4050  Integrated Smart Array
+		0e11 4051  Integrated Smart Array
+		0e11 4058  Integrated Smart Array
 		103c 10c2  Hewlett-Packard NetRAID-4M
+		12d9 000a  VoIP PCI Gateway
 		9005 0365  Adaptec 5400S
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
+		e4bf 1000  CC8-1-BLUES
 	1065  StrongARM DC21285
-		1069 0020  DAC960P
+		1069 0020  DAC960P / DAC1164P
 1012  Micronics Computers Inc
 1013  Cirrus Logic
 	0038  GD 7548
@@ -392,10 +564,13 @@
 	00d0  GD 5462
 	00d2  GD 5462 [Laguna I]
 	00d4  GD 5464 [Laguna]
+	00d5  GD 5464 BD [Laguna]
 	00d6  GD 5465 [Laguna]
+		13ce 8031  Barco Metheus 2 Megapixel, Dual Head
+		13cf 8031  Barco Metheus 2 Megapixel, Dual Head
 	00e8  GD 5436U
 	1100  CL 6729
-	1110  PD 6832
+	1110  PD 6832 PCMCIA/CardBus Ctrlr
 	1112  PD 6834 PCMCIA/CardBus Ctrlr
 	1113  PD 6833 PCMCIA/CardBus Ctrlr
 	1200  GD 7542 [Nordic]
@@ -406,6 +581,8 @@
 		1014 1010  CS4610 SoundFusion Audio Accelerator
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 		1013 4280  Crystal SoundFusion PCI Audio Accelerator
+		1681 0050  Hercules Game Theater XP
+	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 	6005  Crystal CS4281 PCI Audio
 		1013 4281  Crystal CS4281 PCI Audio
 		10cf 10a8  Crystal CS4281 PCI Audio
@@ -425,6 +602,7 @@
 	0017  CPU to PCI Bridge
 	0018  TR Auto LANstreamer
 	001b  GXT-150P
+	001c  Carrera
 	001d  82G2675
 	0020  MCA
 	0022  IBM27-82351
@@ -465,11 +643,14 @@
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
 		1902 00b8  Fire GL1
 	00be  ATM 622MBPS Controller (1410be00)
+	00fc  CPC710 Dual Bridge and Memory Controller (PCI-64)
+	0105  CPC710 Dual Bridge and Memory Controller (PCI-32)
 	0142  Yotta Video Compositor Input
 		1014 0143  Yotta Input Controller (ytin)
 	0144  Yotta Video Compositor Output
 		1014 0145  Yotta Output Controller (ytout)
 	0156  405GP PLB to PCI Bridge
+	01a7  PCI-X to PCI-X Bridge
 	01bd  Netfinity ServeRAID controller
 	01be  ServeRAID-4M
 	01bf  ServeRAID-4L
@@ -498,20 +679,28 @@
 	c24a  90C
 101e  American Megatrends Inc.
 	1960  MegaRAID
+		101e 0471  MegaRAID 471 Enterprise 1600 RAID Controller
+		101e 0475  MegaRAID 475 Express 500 RAID Controller
+		101e 0493  MegaRAID 493 Elite 1600 RAID Controller
 		1028 0471  PowerEdge RAID Controller 3/QC
+		1028 0475  PowerEdge RAID Controller 3/SC
 		1028 0493  PowerEdge RAID Controller 3/DC
-	9010  MegaRAID
+		1028 0511  PowerEdge Cost Effective RAID Controller ATA100/4Ch
+	9010  MegaRAID 428 Ultra RAID Controller
 	9030  EIDE Controller
 	9031  EIDE Controller
 	9032  EIDE & SCSI Controller
 	9033  SCSI Controller
 	9040  Multimedia card
-	9060  MegaRAID
+	9060  MegaRAID 434 Ultra GT RAID Controller
+	9063  MegaRAC
+		101e 0767  Dell Remote Assistant Card 2
 101f  PictureTel
 1020  Hitachi Computer Products
 1021  OKI Electric Industry Co. Ltd.
 1022  Advanced Micro Devices [AMD]
 	2000  79c970 [PCnet LANCE]
+		1014 2000  NetFinity 10/100 Fast Ethernet
 		103c 104c  Ethernet with LAN remote power Adapter
 		103c 1064  Ethernet with LAN remote power Adapter
 		103c 1065  Ethernet with LAN remote power Adapter
@@ -520,11 +709,15 @@
 		103c 10ea  Ethernet with LAN remote power Adapter
 		1113 1220  EN1220 10/100 Fast Ethernet
 		1259 2450  AT-2450 10/100 Fast Ethernet
+		1259 2454  AT-2450v4 10Mb Ethernet Adapter
 		1259 2700  AT-2700TX 10/100 Fast Ethernet
 		1259 2701  AT-2700FX 100Mb Ethernet
 	2001  79c978 [HomePNA]
+		1092 0a78  Multimedia Home Network Adapter
+		1668 0299  ActionLink Home Network Adapter
 	2020  53c974 [PCscsi]
 	2040  79c974
+	3000  ELanSC520 Microcontroller
 	7006  AMD-751 [Irongate] System Controller
 	7007  AMD-751 [Irongate] AGP Bridge
 	700c  AMD-760 MP [IGD4-2P] System Controller
@@ -539,13 +732,16 @@
 	7409  AMD-756 [Viper] IDE
 	740b  AMD-756 [Viper] ACPI
 	740c  AMD-756 [Viper] USB
-	7410  AMD-765 [Viper] ISA
-	7411  AMD-765 [Viper] IDE
-	7413  AMD-765 [Viper] ACPI
-	7414  AMD-765 [Viper] USB
+	7410  AMD-766 [ViperPlus] ISA
+	7411  AMD-766 [ViperPlus] IDE
+	7413  AMD-766 [ViperPlus] ACPI
+	7414  AMD-766 [ViperPlus] USB
 	7440  AMD-768 [Opus] ISA
+		1043 8044  A7M-D Mainboard
 	7441  AMD-768 [Opus] IDE
 	7443  AMD-768 [Opus] ACPI
+		1043 8044  A7M-D Mainboard
+	7445  AMD-768 [Opus] Audio
 	7448  AMD-768 [Opus] PCI
 	7449  AMD-768 [Opus] USB
 	7454  AMD-8151 System Controller
@@ -558,6 +754,7 @@
 	746a  AMD-8111 SMBus 2.0
 	746b  AMD-8111 ACPI
 	746d  AMD-8111 AC97 Audio
+	756b  AMD-8111 ACPI
 1023  Trident Microsystems
 	0194  82C194
 	2000  4DWave DX
@@ -570,6 +767,7 @@
 	8520  CyberBlade i1
 		0e11 b16e  CyberBlade i1 AGP
 		1023 8520  CyberBlade i1 AGP
+	8820  CyberBlade XPAi1
 	9320  TGUI 9320
 	9350  GUI Accelerator
 	9360  Flat panel GUI Accelerator
@@ -587,13 +785,14 @@
 	9470  TGUI 9470
 	9520  Cyber 9520
 	9525  Cyber 9525
+		10cf 1094  Lifebook C6155
 	9540  Cyber 9540
-	9660  TGUI 9660/968x/968x
+	9660  TGUI 9660/938x/968x
 	9680  TGUI 9680
 	9682  TGUI 9682
 	9683  TGUI 9683
 	9685  ProVIDIA 9685
-	9750  3DIm`age 975
+	9750  3DImage 9750
 		1014 9750  3DImage 9750
 		1023 9750  3DImage 9750
 	9753  TGUI 9753
@@ -633,6 +832,7 @@
 	1621  M1621 Northbridge [Aladdin-Pro II]
 	1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]
 	1641  M1641 Northbridge [Aladdin-Pro IV]
+	1647  M1647 [MaGiK1] PCI North Bridge
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -642,35 +842,48 @@
 	3307  M3307 MPEG-I Video Controller
 	3309  M3309 MPEG-II Video w/ Software Audio Decoder
 	3321  M3321 MPEG-II Audio/Video Decoder
-	5212  ALI M4803
+	5212  M4803
 	5215  ALI PCI EIDE Controller
 	5217  M5217H
 	5219  M5219
 	5225  M5225
 	5229  M5229
 	5235  M5235
-	5237  ALI M5237 PCI USB Host Controller
+	5237  M5237 PCI USB Host Controller
 	5240  EIDE Controller
 	5241  PCMCIA Bridge
 	5242  General Purpose Controller
 	5243  PCI to PCI Bridge Controller
 	5244  Floppy Disk Controller
-	5247  ALI M1541 PCI to PCI Bridge
-	5251  M5251 P1394 OHCI Controller
-	5427  ALI PCI to AGP Bridge
-	5451  ALI M5451 PCI AC-Link Controller Audio Device
-	5453  ALI M5453 PCI AC-Link Controller Modem Device
-	7101  ALI M7101 PCI PMU Power Management Controller
-		10b9 7101  ALI M7101 PCI PMU Power Management Controller
+	5247  M1541 PCI to PCI Bridge
+	5251  M5251 P1394 Controller
+	5427  PCI to AGP Bridge
+	5451  M5451 PCI AC-Link Controller Audio Device
+	5453  M5453 PCI AC-Link Controller Modem Device
+	7101  M7101 PCI PMU Power Management Controller
+		10b9 7101  M7101 PCI PMU Power Management Controller
 1028  Dell Computer Corporation
 	0001  PowerEdge Expandable RAID Controller 2/Si
-	0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 0001  PowerEdge Expandable RAID Controller 2/Si
+	0002  PowerEdge Expandable RAID Controller 3
+		1028 0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d1  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d9  PowerEdge Expandable RAID Controller 3/Di
 	0003  PowerEdge Expandable RAID Controller 3/Si
+		1028 0003  PowerEdge Expandable RAID Controller 3/Si
 	0004  PowerEdge Expandable RAID Controller 3/Si
+		1028 00d0  PowerEdge Expandable RAID Controller 3/Si
 	0005  PowerEdge Expandable RAID Controller 3/Di
 	0006  PowerEdge Expandable RAID Controller 3/Di
+	0007  Remote Assistant Card 3
 	0008  PowerEdge Expandable RAID Controller 3/Di
-	000a  PowerEdge Expandable RAID Controller 3/Di
+	000a  PowerEdge Expandable RAID Controller 3
+		1027 0121  PowerEdge Expandable RAID Controller 3/Di
+		1028 0106  PowerEdge Expandable RAID Controller 3/Di
+		1028 011b  PowerEdge Expandable RAID Controller 3/Di
+	000c  Embedded Systems Management Device 4
+	000e  PowerEdge Expandable RAID Controller
+	000f  PowerEdge Expandable RAID Controller 4/Di
 1029  Siemens Nixdorf IS
 102a  LSI Logic
 	0000  HYDRA
@@ -711,9 +924,23 @@
 		102b ca6c  Millennium G250 AGP
 		102b dbbc  Millennium G200 AGP
 		102b dbc2  Millennium G200 MMS (Dual G200)
+		102b dbc3  G200 Multi-Monitor
 		102b dbc8  Millennium G200 MMS (Dual G200)
+		102b dbd2  G200 Multi-Monitor
+		102b dbd3  G200 Multi-Monitor
+		102b dbd4  G200 Multi-Monitor
+		102b dbd5  G200 Multi-Monitor
+		102b dbd8  G200 Multi-Monitor
+		102b dbd9  G200 Multi-Monitor
 		102b dbe2  Millennium G200 MMS (Quad G200)
+		102b dbe3  G200 Multi-Monitor
 		102b dbe8  Millennium G200 MMS (Quad G200)
+		102b dbf2  G200 Multi-Monitor
+		102b dbf3  G200 Multi-Monitor
+		102b dbf4  G200 Multi-Monitor
+		102b dbf5  G200 Multi-Monitor
+		102b dbf8  G200 Multi-Monitor
+		102b dbf9  G200 Multi-Monitor
 		102b f806  Mystique G200 Video AGP
 		102b ff00  MGA-G200 AGP
 		102b ff02  Mystique G200 AGP
@@ -721,16 +948,18 @@
 		102b ff04  Marvel G200 AGP
 		110a 0032  MGA-G200 AGP
 	0525  MGA G400 AGP
-		0e11 b16f  Matrox MGA-G400 AGP
+		0e11 b16f  MGA-G400 AGP
 		102b 0328  Millennium G400 16Mb SDRAM
 		102b 0338  Millennium G400 16Mb SDRAM
 		102b 0378  Millennium G400 32Mb SDRAM
 		102b 0541  Millennium G450 Dual Head
 		102b 0542  Millennium G450 Dual Head LX
-		102b 0641  Millennium G450 32Mb SDRAM
+		102b 0543  Millennium G450 Single Head LX
+		102b 0641  Millennium G450 32Mb SDRAM Dual Head
 		102b 0642  Millennium G450 32Mb SDRAM Dual Head LX
+		102b 0643  Millennium G450 32Mb SDRAM Single Head LX
 		102b 07c0  Millennium G450 Dual Head LE
-		102b 07c1  Millennium G450 SDR Dual Head
+		102b 07c1  Millennium G450 SDR Dual Head LE
 		102b 0d41  Millennium G450 Dual Head PCI
 		102b 0d42  Millennium G450 Dual Head LX PCI
 		102b 0e00  Marvel G450 eTV
@@ -746,11 +975,26 @@
 		102b 2159  Millennium G400 Dual Head 16Mb
 		102b 2179  Millennium G400 MAX/Dual Head 32Mb
 		102b 217d  Millennium G400 Dual Head Max
+		102b 23c0  Millennium G450
+		102b 23c1  Millennium G450
+		102b 23c2  Millennium G450 DVI
+		102b 23c3  Millennium G450 DVI
 		102b 2f58  Millennium G400
 		102b 2f78  Millennium G400
 		102b 3693  Marvel G400 AGP
-		1705 0001  Millennium G450 32MB SGRAM
-		b16f 0e11  Matrox MGA-G400 AGP
+		102b 5dd0  4Sight II
+		102b 5f50  4Sight II
+		102b 5f51  4Sight II
+		102b 5f52  4Sight II
+		102b 9010  Millennium G400 Dual Head
+		1458 0400  GA-G400
+		1705 0001  Digital First Millennium G450 32MB SGRAM
+		1705 0002  Digital First Millennium G450 16MB SGRAM
+		1705 0003  Digital First Millennium G450 32MB
+		1705 0004  Digital First Millennium G450 16MB
+		b16f 0e11  MGA-G400 AGP
+	0527  MGA Parhelia AGP
+		102b 0840  Parhelia 128Mb
 	0d10  MGA Ultima/Impression
 	1000  MGA G100 [Productiva]
 		102b ff01  Productiva G100
@@ -765,12 +1009,15 @@
 		110a 001e  MGA-G100 AGP
 	2007  MGA Mistral
 	2527  MGA G550 AGP
+		102b 0f83  Millennium G550
 		102b 0f84  Millennium G550 Dual Head DDR 32Mb
+		102b 1e41  Millennium G550
 	4536  VIA Framegrabber
 	6573  Shark 10/100 Multiport SwitchNIC
 102c  Chips and Technologies
 	00b8  F64310
 	00c0  F69000 HiQVideo
+		102c 00c0  F69000 HiQVideo
 	00d0  F65545
 	00d8  F65545
 	00dc  F65548
@@ -781,12 +1028,14 @@
 	00f0  F68554
 	00f4  F68554 HiQVision
 	00f5  F68555
+	0c30  F69030
 102d  Wyse Technology Inc.
 	50dc  3328 Audio
 102e  Olivetti Advanced Technology
 102f  Toshiba America
 	0009  r4x00
 	0020  ATM Meteor 155
+		102f 00f8  ATM Meteor 155
 1030  TMC Research
 1031  Miro Computer Products AG
 	5601  DC20 ASIC
@@ -809,6 +1058,8 @@
 	0029  PowerVR PCX1
 	002a  PowerVR 3D
 	0035  USB
+		1179 0001  USB
+		12ee 7000  Root Hub
 	003e  NAPCCARD Cardbus Controller
 	0046  PowerVR PCX2 [midas]
 	005a  Vrc5074 [Nile 4]
@@ -826,7 +1077,10 @@
 		1033 8014  RCV56ACF 56k Voice Modem
 	009b  Vrc5476
 	00a6  VRC5477 AC97
+	00cd  IEEE 1394 [OrangeLink] Host Controller
+		12ee 8011  Root hub
 	00e0  USB 2.0
+		12ee 7001  Root hub
 1034  Framatome Connectors USA Inc.
 1035  Comp. & Comm. Research Lab
 1036  Future Domain Corp.
@@ -840,10 +1094,12 @@
 	0008  85C503/5513
 	0009  ACPI
 	0018  SiS85C503/5513 (LPC Bridge)
-	0200  5597/5598 VGA
+	0200  5597/5598/6326 VGA
 		1039 0000  SiS5597 SVGA (Shared RAM)
 	0204  82C204
 	0205  SG86C205
+	0300  300/200
+		107d 2720  Leadtek WinFast VR300
 	0406  85C501/2
 	0496  85C496
 	0530  530 Host
@@ -852,10 +1108,19 @@
 	0601  85C601
 	0620  620 Host
 	0630  630 Host
+	0633  633 Host
+	0635  635 Host
+	0645  645 Host
+	0646  645DX Host
+	0650  650 Host
 	0730  730 Host
+	0733  733 Host
 	0735  735 Host
+	0740  740 Host
+	0745  745 Host
 	0900  SiS900 10/100 Ethernet
 		1039 0900  SiS900 10/100 Ethernet Adapter
+	0961  SiS961 [MuTIOL Media IO]
 	3602  83C602
 	5107  5107
 	5300  SiS540 PCI Display Adapter
@@ -877,7 +1142,7 @@
 	6300  SiS630 GUI Accelerator+3D
 	6306  6306 3D-AGP
 		1039 6306  SiS530,620 GUI Accelerator+3D
-	6326  86C326
+	6326  86C326 5598/6326
 		1039 6326  SiS6326 GUI Accelerator
 		1092 0a50  SpeedStar A50
 		1092 0a70  SpeedStar A70
@@ -885,8 +1150,9 @@
 		1092 4920  SpeedStar A70
 		1569 6326  SiS6326 GUI Accelerator
 	7001  7001
-	7007  OHCI Compliant FireWire Controller
+	7007  FireWire Controller
 	7012  SiS7012 PCI Audio Accelerator
+	7013  56k Winmodem (Smart Link HAMR5600 compatible)
 	7016  SiS7016 10/100 Ethernet Adapter
 		1039 7016  SiS7016 10/100 Ethernet Adapter
 	7018  SiS PCI Audio Accelerator
@@ -916,15 +1182,36 @@
 103b  Tatung Co. of America
 103c  Hewlett-Packard Company
 	1005  A4977A Visualize EG
-	1030  J2585A
-	1031  J2585B
+	1006  Visualize FX6
+	1008  Visualize FX4
+	100a  Visualize FX2
+	1028  Tach TL Fibre Channel Host Adapter
+	1029  Tach XL2 Fibre Channel Host Adapter
+		107e 000f  Interphase 5560 Fibre Channel Adapter
+		9004 9210  1Gb/2Gb Family Fibre Channel Controller
+		9004 9211  1Gb/2Gb Family Fibre Channel Controller
+	102a  Tach TS Fibre Channel Host Adapter
+		107e 000e  Interphase 5540/5541 Fibre Channel Adapter
+		9004 9110  1Gb/2Gb Family Fibre Channel Controller
+		9004 9111  1Gb/2Gb Family Fibre Channel Controller
+	1030  J2585A DeskDirect 10/100VG NIC
+	1031  J2585B HP 10/100VG PCI LAN Adapter
 		103c 1040  J2973A DeskDirect 10BaseT NIC
 		103c 1041  J2585B DeskDirect 10/100VG NIC
 		103c 1042  J2970A DeskDirect 10BaseT/2 NIC
 	1040  J2973A DeskDirect 10BaseT NIC
 	1041  J2585B DeskDirect 10/100 NIC
 	1042  J2970A DeskDirect 10BaseT/2 NIC
+	1048  Diva Serial [GSP] Multiport UART
+		103c 1049  Tosca Console
+		103c 104a  Tosca Secondary
+		103c 104b  Maestro SP2
+		103c 1223  Halfdome Console
+		103c 1226  Keystone SP2
+		103c 1227  Powerbar SP2
+		103c 1282  Everest SP2
 	1064  79C970 PCnet Ethernet Controller
+	108b  Visualize FXe
 	10c1  NetServer Smart IRQ Router
 	10ed  TopTools Remote Control
 	1200  82557B 10/100 NIC
@@ -935,8 +1222,9 @@
 	1229  zx1 System Bus Adapter
 	122a  zx1 I/O Controller
 	122e  zx1 Local Bus Adapter
-	2910  E2910A
-	2925  E2925A
+	1290  Auxiliary Diva Serial Port
+	2910  E2910A PCIBus Exerciser
+	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
 103f  Synopsys/Logic Modeling Group
 1040  Accelgraphics Inc.
@@ -948,11 +1236,49 @@
 	3010  Samurai_1
 	3020  Samurai_IDE
 1043  Asustek Computer, Inc.
+	0675  ISDNLink P-IN100-ST-D
+	4057  V8200 GeForce 3
 1044  Distributed Processing Technology
 	1012  Domino RAID Engine
 	a400  SmartCache/Raid I-IV Controller
 	a500  PCI Bridge
 	a501  SmartRAID V Controller
+		1044 c001  PM1554U2 Ultra2 Single Channel
+		1044 c002  PM1654U2 Ultra2 Single Channel
+		1044 c003  PM1564U3 Ultra3 Single Channel
+		1044 c004  PM1564U3 Ultra3 Dual Channel
+		1044 c005  PM1554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00a  PM2554U2 Ultra2 Single Channel
+		1044 c00b  PM2654U2 Ultra2 Single Channel
+		1044 c00c  PM2664U3 Ultra3 Single Channel
+		1044 c00d  PM2664U3 Ultra3 Dual Channel
+		1044 c00e  PM2554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00f  PM2654U2 Ultra2 Single Channel (NON ACPI)
+		1044 c014  PM3754U2 Ultra2 Single Channel (NON ACPI)
+		1044 c015  PM3755U2B Ultra2 Single Channel (NON ACPI)
+		1044 c016  PM3755F Fibre Channel (NON ACPI)
+		1044 c01e  PM3757U2 Ultra2 Single Channel
+		1044 c01f  PM3757U2 Ultra2 Dual Channel
+		1044 c020  PM3767U3 Ultra3 Dual Channel
+		1044 c021  PM3767U3 Ultra3 Quad Channel
+		1044 c028  PM2865U3 Ultra3 Single Channel
+		1044 c029  PM2865U3 Ultra3 Dual Channel
+		1044 c02a  PM2865F Fibre Channel
+		1044 c03c  2000S Ultra3 Single Channel
+		1044 c03d  2000S Ultra3 Dual Channel
+		1044 c03e  2000F Fibre Channel
+		1044 c046  3000S Ultra3 Single Channel
+		1044 c047  3000S Ultra3 Dual Channel
+		1044 c048  3000F Fibre Channel
+		1044 c050  5000S Ultra3 Single Channel
+		1044 c051  5000S Ultra3 Dual Channel
+		1044 c052  5000F Fibre Channel
+		1044 c05a  2400A UDMA Four Channel
+		1044 c05b  2400A UDMA Four Channel DAC
+		1044 c064  3010S Ultra3 Dual Channel
+		1044 c065  3010S Ultra3 Four Channel
+		1044 c066  3010S Fibre Channel
+	a511  SmartRAID V Controller
 1045  OPTi Inc.
 	a0f8  82C750 [Vendetta] USB Controller
 	c101  92C264
@@ -963,8 +1289,8 @@
 	c567  82C750 [Vendetta], device 0
 	c568  82C750 [Vendetta], device 1
 	c569  82C579 [Viper XPress+ Chipset]
-	c621  82C621
-	c700  82C700
+	c621  82C621 [Viper-M/N+]
+	c700  82C700 [FireStar]
 	c701  82C701 [FireStar Plus]
 	c814  82C814 [Firebridge 1]
 	c822  82C822
@@ -975,16 +1301,20 @@
 	c895  82C895
 	c935  EV1935 ECTIVA MachOne PCI Audio
 	d568  82C825 [Firebridge 2]
+	d721  IDE [FireStar]
 1046  IPC Corporation, Ltd.
 1047  Genoa Systems Corp
 1048  Elsa AG
+	0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]
 	1000  QuickStep 1000
 	3000  QuickStep 3000
 1049  Fountain Technologies, Inc.
 104a  SGS Thomson Microelectronics
 	0008  STG 2000X
 	0009  STG 1764X
+	0981  DEC-Tulip compatible 10/100 Ethernet
 	1746  STG 1764X
+	2774  DEC-Tulip compatible 10/100 Ethernet
 	3520  MPEG-II decoder card
 104b  BusLogic
 	0140  BT-946C (old) [multimaster  01]
@@ -996,6 +1326,13 @@
 	1000  Eagle i/f AS
 	3d04  TVP4010 [Permedia]
 	3d07  TVP4020 [Permedia 2]
+		1011 4d10  Comet
+		1040 000f  AccelStar II
+		1040 0011  AccelStar II
+		1048 0a31  WINNER 2000
+		1048 0a32  GLoria Synergy
+		1048 0a35  GLoria Synergy
+		107d 2633  WinFast 3D L2300
 		1092 0127  FIRE GL 1000 PRO
 		1092 0136  FIRE GL 1000 PRO
 		1092 0141  FIRE GL 1000 PRO
@@ -1008,17 +1345,31 @@
 		1092 0156  FIRE GL 1000 PRO
 		1092 0157  FIRE GL 1000 PRO
 		1097 3d01  Jeronimo Pro
+		1102 100f  Graphics Blaster Extreme
 		3d3d 0100  Reference Permedia 2 3D
 	8000  PCILynx/PCILynx2 IEEE 1394 Link Layer Controller
 		e4bf 1010  CF1-1-SNARE
 		e4bf 1020  CF1-2-SNARE
-	8009  OHCI Compliant FireWire Controller
-	8019  TSB12LV23 OHCI Compliant IEEE-1394 Controller
+	8009  FireWire Controller
+		104d 8032  8032 OHCI i.LINK (IEEE 1394) Controller
+	8017  PCI4410 FireWire Controller
+	8019  TSB12LV23 IEEE-1394 Controller
 		11bd 000a  Studio DV500-1394
 		11bd 000e  Studio DV
 		e4bf 1010  CF2-1-CYMBAL
+	8020  TSB12LV26 IEEE-1394 Controller (Link)
+	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	8022  TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link)
+	8023  TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link)
+	8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
+	8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)
+	8027  PCI4451 IEEE-1394 Controller
+		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
 	a001  TDC1570
 	a100  TDC1561
+	a102  TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f
 	ac10  PCI1050
 	ac11  PCI1053
 	ac12  PCI1130
@@ -1035,14 +1386,24 @@
 	ac1e  PCI1211
 	ac1f  PCI1251B
 	ac20  TI 2030
+	ac21  PCI2031
+	ac22  PCI2032 PCI Docking Bridge
+	ac23  PCI2250 PCI-to-PCI Bridge
+	ac28  PCI2050 PCI-to-PCI Bridge
 	ac30  PCI1260 PC card Cardbus Controller
 	ac40  PCI4450 PC card Cardbus Controller
 	ac41  PCI4410 PC card Cardbus Controller
 	ac42  PCI4451 PC card Cardbus Controller
+		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
 	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
+		1014 023b  ThinkPad T23 (2647-4MG)
+		10cf 1095  Lifebook C6155
+		e4bf 1000  CP2-2-HIPHOP
 	ac52  PCI1451 PC card Cardbus Controller
 	ac53  PCI1421 PC card Cardbus Controller
+	ac55  PCI1250 PC card Cardbus Controller
+	ac60  PCI2040 PCI to DSP Bridge Controller
 	fe00  FireWire Host Controller
 	fe03  12C01A FireWire Host Controller
 104d  Sony Corporation
@@ -1073,19 +1434,21 @@
 1053  Young Micro Systems
 1054  Hitachi, Ltd
 1055  Efar Microsystems
-	9130  slc90e66 [Victory66] IDE
-	9460  slc90e66 [Victory66] ISA
-	9462  slc90e66 [Victory66] USB
-	9463  slc90e66 [Victory66] ACPI
+	9130  SLC90E66 [Victory66] IDE
+	9460  SLC90E66 [Victory66] ISA
+	9462  SLC90E66 [Victory66] USB
+	9463  SLC90E66 [Victory66] ACPI
 1056  ICL
 # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.
 1057  Motorola
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
 	0100  MC145575 [HFC-PCI]
 	0431  KTI829c 100VG
 	1801  Audio I/O Controller (MIDI)
 		ecc0 0030  Layla
+	18c0  MPC8265A/MPC8266
 	4801  Raven
 	4802  Falcon
 	4803  Hawk
@@ -1109,19 +1472,34 @@
 		14c8 0302  SM56 PCI Fax Modem
 		1668 0300  SM56 PCI Speakerphone Modem
 		1668 0302  SM56 PCI Fax Modem
+	6400  MPC190 Security Processor (S1 family, encryption)
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
 	0d30  20265
+		105a 4d33  Ultra100
+	0d38  20263
+		105a 4d39  Fasttrak66
 	1275  20275
 	4d30  20267
+		105a 4d33  Ultra100
+		105a 4d39  Fasttrak100
 	4d33  20246
+		105a 4d33  20246 IDE Controller
 	4d38  20262
+		105a 4d30  Ultra Device on SuperTrak
+		105a 4d33  Ultra66
+		105a 4d39  Fasttrak66
 	4d68  20268
-	6268  20268R
+		105a 4d68  Ultra100TX2
 	4d69  20269
-	5275  20276
+	5275  PDC20276 IDE
+		105a 0275  SuperTrak SX6000 IDE
 	5300  DC5300
+	6268  20268R
+	6269  PDC20271
+		105a 6269  Fasttrack tx2
+	7275  PDC20277
 105b  Foxconn International, Inc.
 105c  Wipro Infotech Limited
 105d  Number 9 Computer Company
@@ -1139,7 +1517,24 @@
 		105d 0009  Imagine 128 series 2e 4Mb DRAM
 		105d 000a  Imagine 128 series 2 8Mb VRAM
 		105d 000b  Imagine 128 series 2 8Mb H-VRAM
+		11a4 000a  Barco Metheus 5 Megapixel
+		13cc 0000  Barco Metheus 5 Megapixel
+		13cc 0004  Barco Metheus 5 Megapixel
+		13cc 0005  Barco Metheus 5 Megapixel
+		13cc 0006  Barco Metheus 5 Megapixel
+		13cc 0008  Barco Metheus 5 Megapixel
+		13cc 0009  Barco Metheus 5 Megapixel
+		13cc 000a  Barco Metheus 5 Megapixel
+		13cc 000c  Barco Metheus 5 Megapixel
 	493d  Imagine 128 T2R [Ticket to Ride]
+		11a4 000a  Barco Metheus 5 Megapixel, Dual Head
+		11a4 000b  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0002  Barco Metheus 4 Megapixel, Dual Head
+		13cc 0003  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0007  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0008  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0009  Barco Metheus 5 Megapixel, Dual Head
+		13cc 000a  Barco Metheus 5 Megapixel, Dual Head
 	5348  Revolution 4
 105e  Vtech Computers Ltd
 105f  Infotronic America Inc
@@ -1175,10 +1570,12 @@
 1065  Texas Microsystems
 1066  PicoPower Technology
 	0000  PT80C826
-	0001  PT86C52x [Vesuvius]
-	0002  PT80C524 [Nile]
+	0001  PT86C521 [Vesuvius v1] Host Bridge
+	0002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Master
+	0003  PT86C524 [Nile] PCI-to-PCI Bridge
+	0004  PT86C525 [Nile-II] PCI-to-PCI Bridge
 	0005  National PC87550 System Controller
-	8002  PT80C524 [Nile]
+	8002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave
 1067  Mitsubishi Electric
 	1002  VG500 [VolumePro Volume Rendering Accelerator]
 1068  Diversified Technology
@@ -1186,7 +1583,9 @@
 	0001  DAC960P
 	0002  DAC960PD
 	0010  DAC960PX
-	ba55  eXtremeRAID support Device
+	0050  AcceleRAID 352/170/160 support Device
+	ba55  eXtremeRAID 1100 support Device
+	ba56  eXtremeRAID 2000/3000 support Device
 106a  Aten Research Inc
 106b  Apple Computer Inc.
 	0001  Bandit PowerPC host bridge
@@ -1257,19 +1656,21 @@
 1075  Advanced Integrations Research
 1076  Chaintech Computer Co. Ltd
 1077  QLogic Corp.
-	1016  QLA10160
-	1020  ISP1020
-	1022  ISP1022
-	1080  QLA1080
-	1216  QLA12160
+	1016  ISP10160 Single Channel Ultra3 SCSI Processor
+	1020  ISP1020 Fast-wide SCSI
+	1022  ISP1022 Fast-wide SCSI
+	1080  ISP1080 SCSI Host Adapter
+	1216  ISP12160 Dual Channel Ultra3 SCSI Processor
 		101e 8471  QLA12160 on AMI MegaRAID
 		101e 8493  QLA12160 on AMI MegaRAID
-	1240  QLA1240
-	1280  QLA1280
-	2020  ISP2020A
-	2100  QLA2100
+	1240  ISP1240 SCSI Host Adapter
+	1280  ISP1280
+	2020  ISP2020A Fast!SCSI Basic Adapter
+	2100  QLA2100 64-bit Fibre Channel Adapter
+		1077 0001  QLA2100 64-bit Fibre Channel Adapter
 	2200  QLA2200
-	2300  QLA2300
+	2300  QLA2300 64-bit FC-AL Adapter
+	2312  QLA2312 Fibre Channel Adapter
 1078  Cyrix Corporation
 	0000  5510 [Grappa]
 	0001  PCI Master
@@ -1279,6 +1680,10 @@
 	0102  5530 IDE [Kahlua]
 	0103  5530 Audio [Kahlua]
 	0104  5530 Video [Kahlua]
+	0400  ZFMicro PCI Bridge
+	0401  ZFMicro Chipset SMI
+	0402  ZFMicro Chipset IDE
+	0403  ZFMicro Expansion Bus
 1079  I-Bus
 107a  NetWorth
 107b  Gateway 2000
@@ -1286,9 +1691,22 @@
 107d  LeadTek Research Inc.
 	0000  P86C850
 107e  Interphase Corporation
-	0001  ATM Interface Card
+	0001  5515 ATM Adapter [Flipper]
 	0002  100 VG AnyLan Controller
-	0008  155 Mbit ATM Controller
+	0004  5526 Fibre Channel Host Adapter
+	0005  x526 Fibre Channel Host Adapter
+	0008  5525/5575 ATM Adapter (155 Mbit) [Atlantic]
+	9003  5535-4P-BRI-ST
+	9007  5535-4P-BRI-U
+	9008  5535-1P-SR
+	900c  5535-1P-SR-ST
+	900e  5535-1P-SR-U
+	9011  5535-1P-PRI
+	9013  5535-2P-PRI
+	9023  5536-4P-BRI-ST
+	9027  5536-4P-BRI-U
+	9031  5536-1P-PRI
+	9033  5536-2P-PRI
 107f  Data Technology Corporation
 	0802  SL82C105
 1080  Contaq Microsystems
@@ -1306,9 +1724,10 @@
 1087  Cache Computer
 1088  Microcomputer Systems (M) Son
 1089  Data General Corporation
-108a  Bit3 Computer Corp.
+108a  SBS Technologies (formerly Bit3 Computer Corp.)
 	0001  VME Bridge Model 617
 	0010  VME Bridge Model 618
+	0040  dataBLIZZARD
 	3000  VME Bridge Model 2706
 108c  Oakleigh Systems Inc.
 108d  Olicom
@@ -1361,6 +1780,7 @@
 	00a8  Speedstar 64
 	0550  Viper V550
 	08d4  Supra 2260 Modem
+	094c  SupraExpress 56i Pro
 	1092  Viper V330
 	6120  Maximum DVD
 	8810  Stealth SE
@@ -1404,8 +1824,12 @@
 	0647  PCI0647
 	0648  PCI0648
 	0649  PCI0649
+		0e11 005d  Integrated Ultra ATA-100 Dual Channel Controller
+		0e11 007e  Integrated Ultra ATA-100 IDE RAID Controller
+		101e 0649  AMI MegaRAID IDE 100 Controller
 	0650  PBC0650A
 	0670  USB0670
+		1095 0670  USB0670
 	0673  USB0673
 	0680  PCI0680
 1096  Alacron
@@ -1419,17 +1843,23 @@
 109c  Megachips Corporation
 109d  Zida Technologies Ltd.
 109e  Brooktree Corporation
-	0350  Bt848 TV with DMA push
+	0350  Bt848 Video Capture
 	0351  Bt849A Video capture
+	0369  Bt878 Video Capture
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
 	036c  Bt879(??) Video Capture
 		13e9 0070  Win/TV (Video Section)
-	036e  Bt878
+	036e  Bt878 Video Capture
 		0070 13eb  WinTV/GO
+		0070 ff01  Viewcast Osprey 200
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Mediastream Controller NTSC
 		127a 0002  Bt878 Mediastream Controller PAL BG
 		127a 0003  Bt878a Mediastream Controller PAL BG
 		127a 0048  Bt878/832 Mediastream Controller
 		144f 3000  MagicTView CPH060 - Video
+		1461 0004  AVerTV WDM Video Capture
 		14f1 0001  Bt878 Mediastream Controller NTSC
 		14f1 0002  Bt878 Mediastream Controller PAL BG
 		14f1 0003  Bt878a Mediastream Controller PAL BG
@@ -1437,7 +1867,7 @@
 		1851 1850  FlyVideo'98 - Video
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
-	036f  Bt879
+	036f  Bt879 Video Capture
 		127a 0044  Bt879 Video Capture NTSC
 		127a 0122  Bt879 Video Capture PAL I
 		127a 0144  Bt879 Video Capture NTSC
@@ -1471,19 +1901,24 @@
 		1851 1850  FlyVideo'98
 		1851 1851  FlyVideo'98 EZ - video
 		1852 1852  FlyVideo'98 (with FM Tuner)
-	0878  Bt878
+	0878  Bt878 Audio Capture
 		0070 13eb  WinTV/GO
+		0070 ff01  Viewcast Osprey 200
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Video Capture (Audio Section)
 		127a 0002  Bt878 Video Capture (Audio Section)
 		127a 0003  Bt878 Video Capture (Audio Section)
 		127a 0048  Bt878 Video Capture (Audio Section)
 		13e9 0070  Win/TV (Audio Section)
 		144f 3000  MagicTView CPH060 - Audio
+		1461 0004  AVerTV WDM Audio Capture
 		14f1 0001  Bt878 Video Capture (Audio Section)
 		14f1 0002  Bt878 Video Capture (Audio Section)
 		14f1 0003  Bt878 Video Capture (Audio Section)
 		14f1 0048  Bt878 Video Capture (Audio Section)
-	0879  Bt879 Video Capture (Audio Section)
+	0879  Bt879 Audio Capture
 		127a 0044  Bt879 Video Capture (Audio Section)
 		127a 0122  Bt879 Video Capture (Audio Section)
 		127a 0144  Bt879 Video Capture (Audio Section)
@@ -1510,7 +1945,7 @@
 		14f1 1522  Bt879 Video Capture (Audio Section)
 		14f1 1622  Bt879 Video Capture (Audio Section)
 		14f1 1722  Bt879 Video Capture (Audio Section)
-	0880  Bt880 Video Capture (Audio Section)
+	0880  Bt880 Audio Capture
 	2115  BtV 2115 Mediastream controller
 	2125  BtV 2125 Mediastream controller
 	2164  BtV 2164
@@ -1580,14 +2015,28 @@
 	0001  i960 PCI bus interface
 	1076  VScom 800 8 port serial adaptor
 	1077  VScom 400 4 port serial adaptor
-	9030  PCI <-> IOBus Bridge (Hot Swap)
-		15ed 1002  Macrolink MCCS 8-port Serial (Hot Swap)
-		15ed 1003  Macrolink MCCS 16-port Serial (Hot Swap)
+	1078  VScom 210 2 port serial and 1 port parallel adaptor
+	1103  VScom 200 2 port serial adaptor
+	1146  VScom 010 1 port parallel adaptor
+	1147  VScom 020 2 port parallel adaptor
+	2724  Thales PCSM Security Card
+	9030  PCI <-> IOBus Bridge Hot Swap
+		15ed 1002  MCCS 8-port Serial Hot Swap
+		15ed 1003  MCCS 16-port Serial Hot Swap
 	9036  9036
 	9050  PCI <-> IOBus Bridge
 		10b5 2273  SH-ARC SoHard ARCnet card
+		1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem
+		1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem
+		1522 0003  RockForce 6 Port V.90 Data/Fax/Voice Modem
+		1522 0004  RockForce 8 Port V.90 Data/Fax/Voice Modem
+		1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem
+		1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem
 		15ed 1000  Macrolink MCCS 8-port Serial
 		15ed 1001  Macrolink MCCS 16-port Serial
+		15ed 1002  Macrolink MCCS 8-port Serial Hot Swap
+		15ed 1003  Macrolink MCCS 16-port Serial Hot Swap
+		d531 c002  PCIntelliCAN 2xSJA1000 CAN bus
 		d84d 4006  EX-4006 1P
 		d84d 4008  EX-4008 1P EPP/ECP
 		d84d 4014  EX-4014 2P
@@ -1605,12 +2054,15 @@
 		d84d 4065  EX-4065 8S(16C550) RS-232
 		d84d 4068  EX-4068 8S(16C650) RS-232
 		d84d 4078  EX-4078 2S(16C552) RS-232+1P
+	9054  PCI <-> IOBus Bridge
+		10b5 2455  Wessex Techology PHIL-PCI
 	9060  9060
 	906d  9060SD
 		125c 0640  Aries 16000P
 	906e  9060ES
 	9080  9080
 		10b5 9080  9080 [real subsystem ID not set]
+		129d 0002  Aculab PCI Prosidy card
 	a001  GTEK Jetport II 2 port serial adaptor
 	c001  GTEK Cyclone 16/32 port serial adaptor
 10b6  Madge Networks
@@ -1632,14 +2084,20 @@
 	000a  Smart 100/16/4 PCI Ringnode
 		10b6 000a  Smart 100/16/4 PCI Ringnode
 	000b  16/4 CardBus Adapter Mk2
+		10b6 0008  16/4 CardBus Adapter Mk2
 		10b6 000b  16/4 Cardbus Adapter Mk2
-	1000  Collage 25 ATM Adapter
+	000c  RapidFire 3140V2 16/4 TR Adapter
+		10b6 000c  RapidFire 3140V2 16/4 TR Adapter
+	1000  Collage 25/155 ATM Client Adapter
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
-	0001  3c985 1000BaseSX
-	3390  Token Link Velocity
+	0001  3c985 1000BaseSX (SX/TX)
+	1006  MINI PCI type 3B Data Fax Modem
+	1007  Mini PCI 56k Winmodem
+		10b7 615c  Mini PCI 56K Modem
+	3390  3c339 TokenLink Velocity
 	3590  3c359 TokenLink Velocity XL
-		10b7 3590  TokenLink Velocity XL Adapter
+		10b7 3590  TokenLink Velocity XL Adapter (3C359/359B)
 	4500  3c450 Cyclone/unknown
 	5055  3c555 Laptop Hurricane
 	5057  3c575 [Megahertz] 10/100 LAN CardBus
@@ -1647,6 +2105,7 @@
 	5157  3c575 [Megahertz] 10/100 LAN CardBus
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	5257  3CCFE575CT Cyclone CardBus
+		10b7 5c57  FE575C-3Com 10/100 LAN CardBus-Fast Ethernet
 	5900  3c590 10BaseT [Vortex]
 	5920  3c592 EISA 10mbps Demon/Vortex
 	5950  3c595 100BaseTX [Vortex]
@@ -1657,10 +2116,20 @@
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	6055  3c556 Hurricane CardBus
 	6056  3c556B Hurricane CardBus
+		10b7 6556  10/100 Mini PCI Ethernet Adapter
 	6560  3CCFE656 Cyclone CardBus
+		10b7 656a  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6561  3CCFEM656 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6562  3CCFEM656 [id 6562] Cyclone CardBus
+		10b7 656b  3CCFEM656B 10/100 LAN+56K Modem CardBus
+	6563  3CCFEM656B 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6564  3CCFEM656 [id 6564] Cyclone CardBus
 	7646  3cSOHO100-TX Hurricane
+	7940  3c803 FDDILink UTP Controller
+	7980  3c804 FDDILink SAS Controller
+	7990  3c805 FDDILink DAS Controller
 	8811  Token ring
 	9000  3c900 10BaseT [Boomerang]
 	9001  3c900 Combo [Boomerang]
@@ -1671,7 +2140,7 @@
 	9006  3c900B-TPC [Etherlink XL TPC]
 	900a  3c900B-FL [Etherlink XL FL]
 	9050  3c905 100BaseTX [Boomerang]
-	9051  3c905 100BaseT4
+	9051  3c905 100BaseT4 [Boomerang]
 	9055  3c905B 100BaseTX [Cyclone]
 		1028 0080  3C905B Fast Etherlink XL 10/100
 		1028 0081  3C905B Fast Etherlink XL 10/100
@@ -1694,19 +2163,31 @@
 		1028 0098  3C905B Fast Etherlink XL 10/100
 		1028 0099  3C905B Fast Etherlink XL 10/100
 		10b7 9055  3C905B Fast Etherlink XL 10/100
-	9056  3c905B-T4
+	9056  3c905B-T4 [Fast EtherLink XL 10/100]
 	9058  3c905B-Combo [Deluxe Etherlink XL 10/100]
 	905a  3c905B-FX [Fast Etherlink XL FX 10/100]
-	9200  3c905C-TX [Fast Etherlink]
+	9200  3c905C-TX/TX-M [Tornado]
+		1028 0095  Integrated 3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
+		10b7 7000  10/100 Mini PCI Ethernet Adapter
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
 		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
 	9805  3c980-TX 10/100baseTX NIC [Python-T]
+		10b7 1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
+		10b7 1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
 		10b7 9805  3c980 10/100baseTX NIC [Python-T]
+	9900  3C990-TX Typhoon
+	9902  3CR990-TX-95 56-bit Typhoon Client
+	9903  3CR990-TX-97 168-bit Typhoon Client
+	9904  3C990B-TX-M/3C990BSVR [Typhoon2]
+	9905  3CR990-FX-95/97/95 [Typhon Fiber]
+	9908  3CR990SVR95 56-bit Typhoon Server
+	9909  3CR990SVR97 Typhoon Server
+	990b  3C990SVR [Typhoon Server]
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
-		1055 e000  LANEPIC
-		1055 e002  LANEPIC
+		1055 e000  LANEPIC 10/100 [EVB171Q-PCI]
+		1055 e002  LANEPIC 10/100 [EVB171G-PCI]
 		10b8 a011  EtherPower II 10/100
 		10b8 a014  EtherPower II 10/100
 		10b8 a015  EtherPower II 10/100
@@ -1748,7 +2229,13 @@
 	1543  M1543
 	1621  M1621
 	1631  ALI M1631 PCI North Bridge Aladdin Pro III
+	1632  M1632M Northbridge+Trident
 	1641  ALI M1641 PCI North Bridge Aladdin Pro IV
+	1644  M1644/M1644T Northbridge+Trident
+	1646  M1646 Northbridge+Trident
+	1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]
+	1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]
+	1671  M1671 Northbridge [Aladdin-P4]
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -1763,11 +2250,21 @@
 	5219  M5219
 	5225  M5225
 	5229  M5229 IDE
+		1043 8053  A7A266 Motherboard IDE
 	5235  M5225
-	5237  M5237 USB
-	5243  M5243
-	5247  M5247
-	5451  M5451 PCI South Bridge Audio
+	5237  USB 1.1 Controller
+	5239  USB 2.0 Controller
+	5243  M1541 PCI to AGP Controller
+	5247  PCI to AGP Controller
+	5251  M5251 P1394 OHCI 1.0 Controller
+	5253  M5253 P1394 OHCI 1.1 Controller
+	5261  M5261 Ethernet Controller
+	5451  M5451 PCI AC-Link Controller Audio Device
+	5453  M5453 PCI AC-Link Controller Modem Device
+	5455  M5455 PCI AC-Link Controller Audio Device
+	5457  M5457 AC-Link Modem Interface Controller
+	5471  M5471 Memory Stick Controller
+	5473  M5473 SD-MMC Controller
 	7101  M7101 PMU
 		10b9 7101  ALI M7101 Power Management Controller
 10ba  Mitsubishi Electric Corp.
@@ -1829,6 +2326,7 @@
 		110a 8005  MagicMedia 256AV Audio Device
 		14c0 0004  MagicMedia 256AV Audio Device
 	8006  NM2360 [MagicMedia 256ZX Audio]
+	8016  NM2360 [MagicMedia 256ZX Audio]
 10c9  Dataexpert Corporation
 10ca  Fujitsu Microelectr., Inc.
 10cb  Omron Corporation
@@ -1855,6 +2353,7 @@
 10d9  Macronix, Inc. [MXIC]
 	0512  MX98713
 	0531  MX987x5
+		1186 1200  DFE-540TX ProFAST 10/100 Adapter
 	8625  MX86250
 	8888  MX86200
 10da  Compaq IPG-Austin
@@ -1869,12 +2368,13 @@
 	10dc  ATT2C15-3 FPGA
 10dd  Evans & Sutherland
 10de  nVidia Corporation
-	0008  EDGE 3D [NV1]
-	0009  EDGE 3D [NV1]
-	0010  Mutara V08 [NV2]
-	0020  Riva TnT [NV04]
+	0008  NV1 [EDGE 3D]
+	0009  NV1 [EDGE 3D]
+	0010  NV2 [Mutara V08]
+	0020  NV4 [Riva TnT]
 		1043 0200  V3400 TNT
 		1048 0c18  Erazor II SGRAM
+		1048 0c1b  Erazor II
 		1092 0550  Viper V550
 		1092 0552  Viper V550
 		1092 4804  Viper V550
@@ -1887,10 +2387,12 @@
 		1092 4904  Viper V550
 		1092 4914  Viper V550
 		1092 8225  Viper V550
+		10b4 273d  Velocity 4400
+		10b4 2740  Velocity 4400
 		10de 0020  Riva TNT
 		1102 1015  Graphics Blaster CT6710
 		1102 1016  Graphics Blaster RIVA TNT
-	0028  Riva TnT2 [NV5]
+	0028  NV5 [Riva TnT2]
 		1043 0200  AGP-V3800 SGRAM
 		1043 0201  AGP-V3800 SDRAM
 		1043 0205  PCI-V3800
@@ -1898,13 +2400,15 @@
 		1092 4804  Viper V770
 		1092 4a00  Viper V770
 		1092 4a02  Viper V770 Ultra
+		1092 5a00  RIVA TNT2/TNT2 Pro
 		1092 6a02  Viper V770 Ultra
 		1092 7a02  Viper V770 Ultra
 		10de 0005  RIVA TNT2 Pro
+		10de 000f  Compaq NVIDIA TNT2 Pro
 		1102 1020  3D Blaster RIVA TNT2
 		1102 1026  3D Blaster RIVA TNT2 Digital
 		14af 5810  Maxi Gamer Xentor
-	0029  Riva TnT2 Ultra [NV5]
+	0029  NV5 [Riva TnT2 Ultra]
 		1043 0200  AGP-V3800 Deluxe
 		1043 0201  AGP-V3800 Ultra SDRAM
 		1043 0205  PCI-V3800 Ultra
@@ -1912,55 +2416,97 @@
 		1102 1029  3D Blaster RIVA TNT2 Ultra
 		1102 102f  3D Blaster RIVA TNT2 Ultra
 		14af 5820  Maxi Gamer Xentor 32
-	002a  Riva TnT2 [NV5]
-	002b  Riva TnT2 [NV5]
-	002c  Vanta [NV6]
+	002a  NV5 [Riva TnT2]
+	002b  NV5 [Riva TnT2]
+	002c  NV6 [Vanta]
 		1043 0200  AGP-V3800 Combat SDRAM
 		1043 0201  AGP-V3800 Combat
 		1092 6820  Viper V730
 		1102 1031  CT6938 VANTA 8MB
 		1102 1034  CT6894 VANTA 16MB
 		14af 5008  Maxi Gamer Phoenix 2
-	002d  Vanta [NV6]
+	002d  RIVA TNT2 Model 64
 		1043 0200  AGP-V3800M
 		1043 0201  AGP-V3800M
 		1102 1023  CT6892 RIVA TNT2 Value
 		1102 1024  CT6932 RIVA TNT2 Value 32Mb
-		1102 102c  CT6931 RIVA TNT2 Value (Jumper)
+		1102 102c  CT6931 RIVA TNT2 Value [Jumper]
 		1462 8808  MSI-8808
-	002e  Vanta [NV6]
-	002f  Vanta [NV6]
-	00a0  Riva TNT2
+		1554 1041  PixelView RIVA TNT2 M64 32MB
+	002e  NV6 [Vanta]
+	002f  NV6 [Vanta]
+	00a0  NV5 [Riva TNT2]
 		14af 5810  Maxi Gamer Xentor
-	0100  GeForce 256
+	0100  NV10 [GeForce 256 SDR]
 		1043 0200  AGP-V6600 SGRAM
 		1043 0201  AGP-V6600 SDRAM
 		1043 4008  AGP-V6600 SGRAM
 		1043 4009  AGP-V6600 SDRAM
 		1102 102d  CT6941 GeForce 256
-	0101  GeForce 256 DDR
+		14af 5022  3D Prophet SE
+	0101  NV10 [GeForce 256 DDR]
 		1043 0202  AGP-V6800 DDR
 		1043 400a  AGP-V6800 DDR SGRAM
 		1043 400b  AGP-V6800 DDR SDRAM
 		1102 102e  CT6971 GeForce 256 DDR
 		14af 5021  3D Prophet DDR-DVI
-	0103  Quadro (GeForce 256 GL)
-	0110  NV11 (GeForce2 MX)
-	0111  NV11 (GeForce2 MX DDR)
-	0112  GeForce2 Go
-	0113  NV11 (GeForce2 MXR)
-	0150  NV15 (GeForce2 Pro)
+	0103  NV10 [Quadro]
+	0110  NV11 [GeForce2 MX]
+		1043 4015  AGP-V7100 Pro
+		1043 4031  V7100 Pro with TV output
+		14af 7103  3D Prophet II MX Dual-Display
+	0111  NV11 [GeForce2 MX DDR]
+	0112  NV11 [GeForce2 Go]
+	0113  NV11 [GeForce2 MXR]
+	0150  NV15 [GeForce2 GTS]
+		1043 4016  V7700 AGP Video Card
 		107d 2840  WinFast GeForce2 GTS with TV output
-	0151  NV15 DDR (GeForce2 GTS)
-	0152  NV15 Bladerunner (GeForce2 Ultra)
-	0153  NV15 GL (Quadro2 Pro)
+		1462 8831  Creative GeForce2 Pro
+	0151  NV15 [GeForce2 Ti]
+	0152  NV15 [GeForce2 Ultra, Bladerunner]
+		1048 0c56  GLADIAC Ultra
+	0153  NV15 [Quadro2 Pro]
+	0170  NV17 [GeForce4 MX460]
+	0171  NV17 [GeForce4 MX440]
+	0172  NV17 [GeForce4 MX420]
+	0173  NV1x
+	0174  NV17 [GeForce4 440 Go]
+	0175  NV17 [GeForce4 420 Go]
+	0176  NV17 [GeForce4 420 Go 32M]
+	0178  Quadro4 500XGL
+	0179  NV17 [GeForce4 440 Go 64M]
+	017a  Quadro4 200/400NVS
+	017b  Quadro4 550XGL
+	017c  Quadro4 550 GoGL
+	01a0  NV15 [GeForce2 - nForce GPU]
+	01a4  nForce CPU bridge
+	01ab  nForce 420 Memory Controller (DDR)
+	01ac  nForce 220/420 Memory Controller
+	01ad  nForce 220/420 Memory Controller
+	01b1  nForce Audio
+	01b2  nForce ISA Bridge
+	01b4  nForce PCI System Management
+	01b7  nForce AGP to PCI Bridge
+	01b8  nForce PCI-to-PCI bridge
 	01bc  nForce IDE
-	0200  NV20 (GeForce3)
-	0203  Quadro DCC
+	0200  NV20 [GeForce3]
+		1043 402f  AGP-V8200 DDR
+	0201  NV20 [GeForce3 Ti200]
+	0202  NV20 [GeForce3 Ti500]
+		1043 405b  V8200 T5
+	0203  NV20 [Quadro DCC]
+	0250  NV25 [GeForce4 Ti4600]
+	0251  NV25 [GeForce4 Ti4400]
+	0253  NV25 [GeForce4 Ti4200]
+	0258  Quadro4 900XGL
+	0259  Quadro4 750XGL
+	025b  Quadro4 700XGL
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
 	f700  LP7000 Fibre Channel Host Adapter
+	f800  LP8000 Fibre Channel Host Adapter
+	f900  LP9000 Fibre Channel Host Adapter
 10e0  Integrated Micro Solutions Inc.
 	5026  IMS5026/27/28
 	5027  IMS5027
@@ -1988,14 +2534,15 @@
 	8043  LANai4.x [Myrinet LANai interface chip]
 	8062  S5933_PARASTATION
 	807d  S5933 [Matchmaker]
-	8088  Kingsberg Spacetec Format Synchronizer
-	8089  Kingsberg Spacetec Serial Output Board
+	8088  Kongsberg Spacetec Format Synchronizer
+	8089  Kongsberg Spacetec Serial Output Board
 	809c  S5933_HEPC3
 	80d7  PCI-9112
 	80d9  PCI-9118
 	80da  PCI-9812
 	811a  PCI-IEEE1355-DS-DE Interface
 	8170  S5933 [Matchmaker] (Chipset Development Tool)
+	82db  AJA HDNTV HD SDI Framestore
 10e9  Alps Electric Co., Ltd.
 10ea  Intergraphics Systems
 	1680  IGA-1680
@@ -2010,8 +2557,8 @@
 	8111  Twist3 Frame Grabber
 10ec  Realtek Semiconductor Co., Ltd.
 	8029  RTL-8029(AS)
-		10b8 2011  EZ-Card
-		10ec 8029  RT8029(AS)
+		10b8 2011  EZ-Card (SMC1208)
+		10ec 8029  RTL-8029(AS)
 		1113 1208  EN1208
 		1186 0300  DE-528
 		1259 2400  AT-2400
@@ -2019,14 +2566,16 @@
 		10ec 8129  RT8129 Fast Ethernet Adapter
 	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
 		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
-	8139  RTL-8139
+	8139  RTL-8139/8139C/8139C+
 		1025 8920  ALN-325
 		1025 8921  ALN-325
 		10bd 0320  EP-320X-R
 		10ec 8139  RT8139
 		1186 1300  DFE-538TX
 		1186 1320  SN5200
+		1186 8139  DRN-32TX
 		1259 2500  AT-2500TX
+		1259 2503  AT-2500TX/ACPI
 		1429 d010  ND010
 		1432 9130  EN-9130TX
 		1436 8139  RT8139
@@ -2047,6 +2596,8 @@
 	3fc1  RME Digi96/8
 	3fc2  RME Digi96/8 Pro
 	3fc3  RME Digi96/8 Pad
+	3fc4  RME Digi9652 (Hammerfall)
+	3fc5  RME Hammerfall DSP
 10ef  Racore Computer Products, Inc.
 	8154  M815x Token Ring Adapter
 10f0  Peritek Corporation
@@ -2064,6 +2615,8 @@
 	000c  TARGA 1000
 10fb  Thesys Gesellschaft für Mikroelektronik mbH
 10fc  I-O Data Device, Inc.
+# What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
+	0003  Cardbus IDE Controller
 10fd  Soyo Computer, Inc
 10fe  Fast Multimedia AG
 10ff  NCube
@@ -2086,26 +2639,45 @@
 		1102 8025  SBLive! Mainboard Implementation
 		1102 8026  CT4830 SBLive! Value
 		1102 8027  CT4832 SBLive! Value
+		1102 8028  CT4760 SBLive! OEM version
 		1102 8031  CT4831 SBLive! Value
 		1102 8040  CT4760 SBLive!
 		1102 8051  CT4850 SBLive! Value
-	7002  SB Live!
+		1102 8061  SBLive! Player 5.1
+	0004  SB Audigy
+		1102 0051  SB0090 Audigy Player
+	4001  SB Audigy FireWire Port
+	7002  SB Live! MIDI/Game Port
 		1102 0020  Gameport Joystick
+	7003  SB Audigy MIDI/Game port
+		1102 0040  SB Audigy MIDI/Gameport
 	8938  ES1371
 1103  Triones Technologies, Inc.
 	0003  HPT343
-	0004  HPT366 / HPT370
+# Revisions: 01=HPT366, 03=HPT370, 04=HPT370A, 05=HPT372
+	0004  HPT366/368/370/370A/372
+		1103 0001  HPT370A
 		1103 0005  HPT370 UDMA100
+	0005  HPT372A
+	0006  HPT302
+	0007  HPT371
+	0008  HPT374
 1104  RasterOps Corp.
 1105  Sigma Designs, Inc.
+	1105  REALmagic Xcard MPEG 1/2/3/4 DVD Decoder
 	8300  REALmagic Hollywood Plus DVD Decoder
+	8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder
 1106  VIA Technologies, Inc.
+	0130  VT6305 1394.A Controller
 	0305  VT8363/8365 [KT133/KM133]
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard
 	0391  VT8371 [KX133]
 	0501  VT8501 [Apollo MVP4]
 	0505  VT82C505
 	0561  VT82C561
-	0571  Bus Master IDE
+	0571  VT82C586B PIPC Bus Master IDE
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -2120,6 +2692,8 @@
 	0605  VT8605 [ProSavage PM133]
 	0680  VT82C680 [Apollo P6]
 	0686  VT82C686 [Apollo Super South]
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
 		1106 0000  VT82C686/A PCI to ISA Bridge
 		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C693A/694x [Apollo PRO133x]
@@ -2131,30 +2705,52 @@
 	1106  VT82C570MV
 	1571  VT82C416MV
 	1595  VT82C595/97 [Apollo VP2/97]
-	3038  UHCI USB
+	3038  USB
+		0925 1234  USB Controller
 		1234 0925  MVP3 USB Controller
 	3040  VT82C586B ACPI
-	3043  VT86C100A [Rhine 10/100]
+	3043  VT86C100A [Rhine]
 		10bd 0000  VT86C100A Fast Ethernet Adapter
 		1106 0100  VT86C100A Fast Ethernet Adapter
-		1186 1400  DFE-530TX
-	3044  OHCI Compliant IEEE 1394 Host Controller
+		1186 1400  DFE-530TX rev A
+	3044  IEEE 1394 Host Controller
 	3050  VT82C596 Power Management
 	3051  VT82C596 Power Management
 	3057  VT82C686 [Apollo Super ACPI]
-	3058  AC97 Audio Controller
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+	3058  VT82C686 AC97 Audio Controller
+		0e11 b194  Soundmax integrated digital audio
+		1106 4511  Onboard Audio on EP7KXA
+		1458 7600  Onboard Audio
 		1462 3091  MS-6309 Onboard Audio
-	3059  AC97 Audio Controller
-	3065  Ethernet Controller
+		15dd 7609  Onboard Audio
+	3059  VT8233 AC97 Audio Controller
+	3065  VT6102 [Rhine-II]
+		1186 1400  DFE-530TX rev A
+		1186 1401  DFE-530TX rev B
 	3068  AC97 Modem Controller
 	3074  VT8233 PCI to ISA Bridge
 	3091  VT8633 [Apollo Pro266]
 	3099  VT8367 [KT266]
+		1043 8064  A7V266-E
+		1043 807f  A7V333
+	3101  VT8653 Host Bridge
+	3102  VT8662 Host Bridge
+	3103  VT8615 Host Bridge
+	3104  USB 2.0
 	3109  VT8233C PCI to ISA Bridge
+	3112  VT8361 [KLE133] Host Bridge
+	3128  VT8753 [P4X266 AGP]
+	3133  VT3133 Host Bridge
+	3147  VT8233A ISA Bridge
+	3148  P4M266 Host Bridge
+	3156  P/KN266 Host Bridge
+	3177  VT8233A ISA Bridge
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
-	8235  VT8235 Power Management
+	8235  VT8235 ACPI
 	8305  VT8363/8365 [KT133/KM133 AGP]
 	8391  VT8371 [KX133 AGP]
 	8501  VT8501 [Apollo MVP4 AGP]
@@ -2164,8 +2760,13 @@
 	8601  VT8601 [Apollo ProMedia AGP]
 	8605  VT8605 [PM133 AGP]
 	8691  VT82C691 [Apollo Pro]
+	8693  VT82C693 [Apollo Pro Plus] PCI Bridge
 	b091  VT8633 [Apollo Pro266 AGP]
-	b099  VT8367 [KT266 AGP]
+	b099  VT8367 [KT333 AGP]
+	b101  VT8653 AGP Bridge
+	b102  VT8362 AGP Bridge
+	b103  VT8615 AGP Bridge
+	b112  VT8361 [KLE133] AGP Bridge
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -2187,6 +2788,7 @@
 	6120  SZB6120
 110b  Chromatic Research Inc.
 	0001  Mpact Media Processor
+	0004  Mpact 2
 110c  Mini-Max Technology, Inc.
 110d  Znyx Advanced Systems
 110e  CPU Technology
@@ -2210,6 +2812,7 @@
 	5105  10Mbps Network card
 	9211  EN-1207D Fast Ethernet Adapter
 		1113 9211  EN-1207D Fast Ethernet Adapter
+	9511  Fast Ethernet Adapter
 1114  Atmel Corporation
 1115  3D Labs
 1116  Data Translation
@@ -2314,6 +2917,7 @@
 	0001  Powerbis Bridge
 111d  Integrated Device Tech
 	0001  IDT77211 ATM Adapter
+	0003  IDT77252 ATM network controller
 111e  Eldec
 111f  Precision Digital Images
 	4a47  Precision MX Video engine interface
@@ -2329,9 +2933,10 @@
 	0200  ForeRunner PCA-200 ATM
 	0210  PCA-200PC
 	0250  ATM
-	0300  PCA-200E
+	0300  ForeRunner PCA-200EPC ATM
 	0310  ATM
 	0400  ForeRunnerHE ATM Adapter
+		1127 0400  ForeRunnerHE ATM
 1129  Firmworks
 112a  Hermes Electronics Company, Ltd.
 112b  Linotype - Hell AG
@@ -2343,6 +2948,9 @@
 	0001  MVC IM-PCI Video frame grabber/processor
 1130  Computervision
 1131  Philips Semiconductors
+	7130  SAA7130 Video Broadcast Decoder
+# PCI audio and video broadcast decoder (http://www.semiconductors.philips.com/pip/saa7134hl)
+	7134  SAA7134
 	7145  SAA7145
 	7146  SAA7146
 		114b 2003  DVRaptor Video Edit/Capture Card
@@ -2356,8 +2964,11 @@
 	7912  EiconCard S91
 	7941  EiconCard S94
 	7942  EiconCard S94
+	7943  EiconCard S94
+	7944  EiconCard S94
 	b921  EiconCard P92
 	b922  EiconCard P92
+	b923  EiconCard P92
 	e001  DIVA 20PRO
 		1133 e001  DIVA Pro 2.0 S/T
 	e002  DIVA 20
@@ -2366,10 +2977,15 @@
 		1133 e003  DIVA Pro 2.0 U
 	e004  DIVA 20_U
 		1133 e004  DIVA 2.0 U
+	e005  DIVA LOW
+		1133 e005  DIVA 2.01 S/T
 	e010  DIVA Server BRI-2M
 		1133 e010  DIVA Server BRI-2M
+	e012  DIVA Server BRI-8M
+		1133 e012  DIVA Server BRI-8M
 	e014  DIVA Server PRI-30M
 		1133 e014  DIVA Server PRI-30M
+	e018  DIVA Server BRI-2M/-2F
 1134  Mercury Computer Systems
 	0001  Raceway Bridge
 1135  Fuji Xerox Co Ltd
@@ -2394,8 +3010,8 @@
 113f  Equinox Systems, Inc.
 	0808  SST-64P Adapter
 	1010  SST-128P Adapter
-	80c0  SST-16P Adapter
-	80c4  SST-16P Adapter
+	80c0  SST-16P DB Adapter
+	80c4  SST-16P RJ Adapter
 	80c8  SST-16P Adapter
 	8888  SST-4P Adapter
 	9090  SST-8P Adapter
@@ -2440,8 +3056,10 @@
 		1148 9844  SK-9844 (1000Base-SX dual link)
 		1148 9861  SK-9861 (1000Base-SX VF45 single link)
 		1148 9862  SK-9862 (1000Base-SX VF45 dual link)
+	4400  Gigabit Ethernet
 1149  Win System Corporation
 114a  VMIC
+	5579  VMIPCI-5579 (Reflective Memory Card)
 	7587  VMIVME-7587
 114b  Canopus Co., Ltd
 114c  Annabooks
@@ -2467,12 +3085,24 @@
 	001a  DataFirePRIme E1 (1-port)
 	001b  AccelePort C/X (IBM)
 	001d  DataFire RAS T1/E1/PRI
+		114f 0050  DataFire RAS E1 Adapter
+		114f 0051  DataFire RAS Dual E1 Adapter
+		114f 0052  DataFire RAS T1 Adapter
+		114f 0053  DataFire RAS Dual T1 Adapter
 	0023  AccelePort RAS
 	0024  DataFire RAS B4 ST/U
+		114f 0030  DataFire RAS BRI U Adapter
+		114f 0031  DataFire RAS BRI S/T Adapter
 	0026  AccelePort 4r 920
 	0027  AccelePort Xr 920
 	0034  AccelePort 2r 920
 	0035  DataFire DSP T1/E1/PRI cPCI
+	0040  AccelePort Xp
+	0042  AccelePort 2p PCI
+	0070  Datafire Micro V IOM2 (Europe)
+	0071  Datafire Micro V (Europe)
+	0072  Datafire Micro V IOM2 (North America)
+	0073  Datafire Micro V (North America)
 	6001  Avanstar
 1150  Thinking Machines Corp
 1151  JAE Electronics Inc.
@@ -2495,8 +3125,11 @@
 	0003  Cardbus Ethernet 10/100
 		1014 0181  10/100 EtherJet Cardbus Adapter
 		1014 1181  10/100 EtherJet Cardbus Adapter
+		1014 8181  10/100 EtherJet Cardbus Adapter
+		1014 9181  10/100 EtherJet Cardbus Adapter
 		115d 0181  Cardbus Ethernet 10/100
 		115d 1181  Cardbus Ethernet 10/100
+		1179 0181  Cardbus Ethernet 10/100
 		8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 		8086 9181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 	0005  Cardbus Ethernet 10/100
@@ -2512,12 +3145,15 @@
 	000b  Cardbus Ethernet 10/100
 		1014 0183  10/100 EtherJet Cardbus Adapter
 		115d 0183  Cardbus Ethernet 10/100
+	000c  Mini-PCI V.90 56k Modem
 	000f  Cardbus Ethernet 10/100
 		1014 0183  10/100 EtherJet Cardbus Adapter
 		115d 0183  Cardbus Ethernet 10/100
 	0101  Cardbus 56k modem
 		115d 1081  Cardbus 56k Modem
 	0103  Cardbus Ethernet + 56k Modem
+		1014 9181  Cardbus 56k Modem
+		1115 1181  Cardbus Ethernet 100 + 56k Modem
 		115d 1181  CBEM56G-100 Ethernet + 56k Modem
 		8086 9181  PRO/100 LAN + Modem56 CardBus
 115e  Peer Protocols Inc
@@ -2533,16 +3169,21 @@
 1165  Imagraph Corporation
 	0001  Motion TPEG Recorder/Player with audio
 1166  ServerWorks
+	0005  CNB20-LE Host Bridge
 	0007  CNB20-LE Host Bridge
 	0008  CNB20HE Host Bridge
 	0009  CNB20LE Host Bridge
 	0010  CIOB30
 	0011  CMIC-HE
+	0013  CNB20-HE Host Bridge
+	0014  CNB20-HE Host Bridge
+	0015  CMIC-GC Host Bridge
+	0016  CMIC-GC Host Bridge
 	0200  OSB4 South Bridge
 	0201  CSB5 South Bridge
 	0211  OSB4 IDE Controller
 	0212  CSB5 IDE Controller
-	0220  OSB4/CSB5 OHCI USB Controller
+	0220  OSB4/CSB5 USB Controller
 1167  Mutoh Industries Inc
 1168  Thine Electronics Inc
 1169  Centre for Development of Advanced Computing
@@ -2567,6 +3208,7 @@
 1178  Alfa, Inc.
 	afa1  Fast Ethernet Adapter
 1179  Toshiba America Info Systems
+	0103  EX-IDE Type-B
 	0404  DVD Decoder card
 	0406  Tecra Video Capture device
 	0407  DVD Decoder card (Version 2)
@@ -2578,6 +3220,8 @@
 	0618  CPU to PCI and PCI to ISA bridge
 # Claimed to be Lucent DSP1645 [Mars], but that's apparently incorrect. Does anyone know the correct ID?
 	0701  FIR Port
+	0804  TC6371AF SmartMedia Controller
+	0805  SD TypA Controller
 	0d01  FIR Port Type-DO
 		1179 0001  FIR Port Type-DO
 117a  A-Trend Technology
@@ -2591,16 +3235,29 @@
 	0466  RL5c466
 	0475  RL5c475
 	0476  RL5c476 II
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	0477  RL5c477
 	0478  RL5c478
+		1014 0184  ThinkPad A30p (2653-64G)
+	0522  R5C522 IEEE 1394 Controller
+		1014 01cf  ThinkPad A30p (2653-64G)
+	0551  R5C551 IEEE 1394 Controller
+	0552  R5C552 IEEE 1394 Controller
 1181  Telmatics International
 1183  Fujikura Ltd
 1184  Forks Inc
 1185  Dataworld International Ltd
 1186  D-Link System Inc
 	0100  DC21041
-	1002  Sundance Ethernet
+	1002  DL10050 Sundance Ethernet
+		1186 1002  DFE-550TX
+		1186 1012  DFE-580TX
 	1300  RTL8139 Ethernet
+		1186 1300  DFE-538TX 10/100 Ethernet Adapter
+		1186 1301  DFE-530TX+ 10/100 Ethernet Adapter
+	1340  DFE-690TXD CardBus PC Card
+	1561  DRP-32TXD Cardbus PC Card
 	4000  DL2K Ethernet
 1187  Advanced Technology Laboratories, Inc.
 1188  Shima Seiki Manufacturing Ltd.
@@ -2690,6 +3347,7 @@
 		11ad ffff  LNE100TX
 		1385 f004  FA310TX
 	c115  LNE100TX [Linksys EtherFast 10/100]
+		11ad c001  LNE100TX [ver 2.0]
 11ae  Aztech System Ltd
 11af  Avid Technology Inc.
 11b0  V3 Semiconductor Inc.
@@ -2720,6 +3378,7 @@
 	0440  56k WinModem
 		0001 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		1033 8015  LT WinModem 56k Data+Fax+Voice+Dsvd
+		1033 8047  LT WinModem 56k Data+Fax+Voice+Dsvd
 		1033 804f  LT WinModem 56k Data+Fax+Voice+Dsvd
 		10cf 102c  LB LT Modem V.90 56k
 		10cf 104a  BIBLO LT Modem 56k
@@ -2727,15 +3386,18 @@
 		1179 0001  Internal V.90 Modem
 		11c1 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		122d 4101  MDP7800-U Modem
+		122d 4102  MDP7800SP-U Modem
 		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 0441  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0450  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 f100  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 f101  LT WinModem 56k Data+Fax+Voice+Dsvd
 		144d 2101  LT56PV Modem
 		149f 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 	0441  56k WinModem
 		1033 804d  LT WinModem 56k Data+Fax
+		1033 8065  LT WinModem 56k Data+Fax
 		1092 0440  Supra 56i
 		1179 0001  Internal V.90 Modem
 		11c1 0440  LT WinModem 56k Data+Fax
@@ -2745,11 +3407,16 @@
 		13e0 0100  LT WinModem 56k Data+Fax
 		13e0 0410  LT WinModem 56k Data+Fax
 		13e0 0420  TelePath Internet 56k WinModem
+		13e0 0440  LT WinModem 56k Data+Fax
 		13e0 0443  LT WinModem 56k Data+Fax
+		13e0 f102  LT WinModem 56k Data+Fax
 		1416 9804  CommWave 56k Modem
 		141d 0440  LT WinModem 56k Data+Fax
 		144f 0441  Lucent 56k V.90 DF Modem
+		144f 0449  Lucent 56k V.90 DF Modem
+		144f 110d  Lucent Win Modem
 		1468 0441  Presario 56k V.90 DF Modem
+		1668 0440  Lucent Win Modem
 	0442  56k WinModem
 		0001 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		11c1 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
@@ -2758,6 +3425,7 @@
 		13e0 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		13fc 2471  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		144d 2104  LT56PT Modem
+		144f 1104  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		149f 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		1668 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 	0443  LT WinModem
@@ -2766,14 +3434,23 @@
 	0446  LT WinModem
 	0447  LT WinModem
 	0448  WinModem 56k
+		1014 0131  Lucent Win Modem
+		1033 8066  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0030  56k Voice Modem
 		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
+# Actiontech eth+modem card as used by Dell &c.
+		1668 2400  LT WinModem 56k (MiniPCI Ethernet+Modem)
 	0449  WinModem 56k
 		0e11 b14d  56k V.90 Modem
 		13e0 0020  LT WinModem 56k Data+Fax
 		13e0 0041  TelePath Internet 56k WinModem
+		1436 0440  Lucent Win Modem
 		144f 0449  Lucent 56k V.90 DFi Modem
+		1468 0410  IBM ThinkPad T23 (2647-4MG)
+		1468 0440  Lucent Win Modem
 		1468 0449  Presario 56k V.90 DFi Modem
 	044a  F-1156IV WinModem (V90, 56KFlex)
+		10cf 1072  LB Global LT Modem
 		13e0 0012  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		13e0 0042  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		144f 1005  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
@@ -2781,6 +3458,7 @@
 	044c  LT WinModem
 	044d  LT WinModem
 	044e  LT WinModem
+	044f  V90 WildWire Modem
 	0450  LT WinModem
 	0451  LT WinModem
 	0452  LT WinModem
@@ -2792,7 +3470,13 @@
 	0458  LT WinModem
 	0459  LT WinModem
 	045a  LT WinModem
+	0461  V90 WildWire Modem
+	0462  V90 WildWire Modem
 	0480  Venus Modem (V90, 56KFlex)
+	5801  USB
+	5802  USS-312 USB Controller
+	5811  FW323
+		dead 0800  FireWire Host Bus Adapter
 11c2  Sand Microelectronics
 11c3  NEC Corp
 11c4  Document Technologies, Inc
@@ -2823,6 +3507,7 @@
 11d2  Intercom Inc.
 11d3  Trancell Systems Inc
 11d4  Analog Devices
+	1805  SM56 PCI modem
 	1889  AD1889 sound chip
 11d5  Ikon Corporation
 	0115  10115
@@ -2878,6 +3563,7 @@
 	0113  FreedomLine 100
 	1401  ReadyLink 2000
 	2011  RL100-ATX 10/100
+		11f6 2011  RL100-ATX
 	2201  ReadyLink 100TX (Winbond W89C840)
 		11f6 2011  ReadyLink 100TX
 	9881  RL100TX
@@ -2896,11 +3582,13 @@
 	0004  RocketPort 32 Intf
 	0005  RocketPort Octacable
 	0006  RocketPort 8J
+	0007  RocketPort 4-port
 	0008  RocketPort 8-port
 	0009  RocketPort 16-port
 	000a  RocketPort Plus Quadcable
 	000b  RocketPort Plus Octacable
 	000c  RocketPort 8-port Modem
+	8015  RocketPort 4-port UART 16954
 11ff  Scion Corporation
 1200  CSS Corporation
 1201  Vista Controls Corp
@@ -2917,20 +3605,21 @@
 120c  Technical Corp.
 120d  Compression Labs, Inc.
 120e  Cyclades Corporation
-	0100  Cyclom_Y below first megabyte
-	0101  Cyclom_Y above first megabyte
-	0102  Cyclom_4Y below first megabyte
-	0103  Cyclom_4Y above first megabyte
-	0104  Cyclom_8Y below first megabyte
-	0105  Cyclom_8Y above first megabyte
-	0200  Cyclom_Z below first megabyte
-	0201  Cyclom_Z above first megabyte
+	0100  Cyclom-Y below first megabyte
+	0101  Cyclom-Y above first megabyte
+	0102  Cyclom-4Y below first megabyte
+	0103  Cyclom-4Y above first megabyte
+	0104  Cyclom-8Y below first megabyte
+	0105  Cyclom-8Y above first megabyte
+	0200  Cyclades-Z below first megabyte
+	0201  Cyclades-Z above first megabyte
 	0300  PC300/RSV or /X21 (2 ports)
-	0301  PC300/RSV or /X21 (1 ports)
+	0301  PC300/RSV or /X21 (1 port)
 	0310  PC300/TE (2 ports)
 	0311  PC300/TE (1 port)
 	0320  PC300/TE-M (2 ports)
 	0321  PC300/TE-M (1 port)
+	0400  PC400
 120f  Essential Communications
 	0001  Roadrunner serial HIPPI
 1210  Hyperparallel Technologies
@@ -2941,12 +3630,15 @@
 1215  Interware Co., Ltd
 1216  Purup Prepress A/S
 1217  O2 Micro, Inc.
-	6729  6729
-	673a  6730
-	6832  6832
-	6836  6836
+	6729  OZ6729
+	673a  OZ6730
+	6832  OZ6832/6833 Cardbus Controller
+	6836  OZ6836/6860 Cardbus Controller
 	6872  OZ6812 Cardbus Controller
+	6925  OZ6922 Cardbus Controller
 	6933  OZ6933 Cardbus Controller
+		1025 1016  Travelmate 612 TX
+	6972  OZ6912 Cardbus Controller
 1218  Hybricon Corp.
 1219  First Virtual Corporation
 121a  3Dfx Interactive, Inc.
@@ -2961,7 +3653,7 @@
 		1092 8030  Monster Fusion
 		1092 8035  Monster Fusion AGP
 		10b0 0001  Dragon 4000
-		1102 1017  CT6760 3D Blaster Banshee
+		1102 1018  3D Blaster Banshee VE
 		121a 0001  Voodoo Banshee AGP
 		121a 0003  Voodoo Banshee AGP SGRAM
 		121a 0004  Voodoo Banshee
@@ -2991,6 +3683,7 @@
 		121a 0062  Voodoo3 3500 TV (SECAM)
 	0009  Voodoo 4 / Voodoo 5
 		121a 0009  Voodoo5 AGP 5500/6000
+	0057  Voodoo 3/3000 [Avenger]
 121b  Advanced Telecommunications Modules
 121c  Nippon Texaco., Ltd
 121d  Lippert Automationstechnik GmbH
@@ -3059,12 +3752,19 @@
 1240  Marathon Technologies Corp.
 1241  DSC Communications
 1242  Jaycor Networks, Inc.
+	1242  JNI Corporation (former Jaycor Networks, Inc.)
 	4643  FCI-1063 Fibre Channel Adapter
+	6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter
+	656a  FCX-6562 PCI-X Fibre Channel Adapter
 1243  Delphax
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
+	0800  C4 ISDN
 	0a00  A1 ISDN [Fritz]
 		1244 0a00  FRITZ!Card ISDN Controller
+	0e00  Fritz!PCI v2.0 ISDN
+	1100  C2 ISDN
+	1200  T1 ISDN
 1245  A.P.D., S.A.
 1246  Dipix Technologies, Inc.
 1247  Xylon Research, Inc.
@@ -3072,11 +3772,14 @@
 1249  Samsung Electronics Co., Ltd.
 124a  AEG Electrocom GmbH
 124b  SBS/Greenspring Modular I/O
+	0040  cPCI-200 Four Slot IndustryPack carrier
+		124b 9080  PCI9080 Bridge
 124c  Solitron Technologies, Inc.
 124d  Stallion Technologies, Inc.
 	0000  EasyConnection 8/32
 	0002  EasyConnection 8/64
 	0003  EasyIO
+	0004  EasyConnection/RA
 124e  Cylink
 124f  Infotrend Technology, Inc.
 	0041  IFT-2000 Series RAID Controller
@@ -3102,6 +3805,7 @@
 125b  Asix Electronics Corporation
 	1400  ALFA GFC2204
 125c  Aurora Technologies, Inc.
+	0640  Aries 16000P
 125d  ESS Technology
 	0000  ES336H Fax Modem (Early Model)
 	1948  Solo?
@@ -3123,13 +3827,27 @@
 	1989  ESS Modem
 		125d 1989  ESS Modem
 	1998  ES1983S Maestro-3i PCI Audio Accelerator
+		1028 00e6  ES1983S Maestro-3i (Dell Inspiron 8100)
 	1999  ES1983S Maestro-3i PCI Modem Accelerator
+	199a  ES1983S Maestro-3i PCI Audio Accelerator
+	199b  ES1983S Maestro-3i PCI Modem Accelerator
 	2808  ES336H Fax Modem (Later Model)
 	2838  ES2838/2839 SuperLink Modem
 	2898  ES2898 Modem
+		125d 0424  ES56-PI Data Fax Modem
+		125d 0425  ES56T-PI Data Fax Modem
+		125d 0426  ES56V-PI Data Fax Modem
+		125d 0427  VW-PI Data Fax Modem
+		125d 0428  ES56ST-PI Data Fax Modem
+		125d 0429  ES56SV-PI Data Fax Modem
+		147a c001  ES56-PI Data Fax Modem
+		14fe 0428  ES56-PI Data Fax Modem
+		14fe 0429  ES56-PI Data Fax Modem
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
 1260  Harris Semiconductor
+	3873  Prism 2.5 Wavelan chipset
+		1186 3501  DWL-520 Wireless PCI Adapter
 	8130  HMP8130 NTSC/PAL Video Decoder
 	8131  HMP8131 NTSC/PAL Video Decoder
 1261  Matsushita-Kotobuki Electronics Industries, Ltd.
@@ -3166,6 +3884,7 @@
 	0002  DirecPC
 1274  Ensoniq
 	1371  ES1371 [AudioPCI-97]
+		0e11 0024  AudioPCI on Motherboard Compaq Deskpro
 		0e11 b1a7  ES1371, ES1373 AudioPCI
 		1033 80ac  ES1371, ES1373 AudioPCI
 		1042 1854  Tazer
@@ -3222,7 +3941,9 @@
 		4942 4c4c  Creative Sound Blaster AudioPCI128
 	5880  5880 AudioPCI
 		1274 2000  Creative Sound Blaster AudioPCI128
+		1274 2003  Creative SoundBlaster AudioPCI 128
 		1274 5880  Creative Sound Blaster AudioPCI128
+		1458 a000  5880 AudioPCI On Motherboard 6OXET
 		1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00
 		270f 2001  5880 AudioPCI On Motherboard 6CTR
 		270f 2200  5880 AudioPCI On Motherboard 6WTX
@@ -3231,6 +3952,7 @@
 1276  Switched Network Technologies, Inc.
 1277  Comstream
 1278  Transtech Parallel Systems Ltd.
+	0701  TPE3/TM3 PowerPC Node
 1279  Transmeta Corporation
 	0295  Northbridge
 	0395  LongRun Northbridge
@@ -3238,93 +3960,103 @@
 	0397  BIOS scratchpad
 127a  Rockwell International
 	1002  HCF 56k Data/Fax Modem
-		122d 4002  HPG / MDP3858-U # Aztech
-		122d 4005  MDP3858-E # Aztech
-		122d 4007  MDP3858-A/-NZ # Aztech
-		122d 4012  MDP3858-SA # Aztech
-		122d 4017  MDP3858-W # Aztech
-		122d 4018  MDP3858-W # Aztech
+		1092 094c  SupraExpress 56i PRO [Diamond SUP2380]
+		122d 4002  HPG / MDP3858-U
+		122d 4005  MDP3858-E
+		122d 4007  MDP3858-A/-NZ
+		122d 4012  MDP3858-SA
+		122d 4017  MDP3858-W
+		122d 4018  MDP3858-W
+		127a 1002  Rockwell 56K D/F HCF Modem
 	1003  HCF 56k Data/Fax Modem
-		0e11 b0bc  229-DF Zephyr # Compaq
-		0e11 b114  229-DF Cheetah # Compaq
-		1033 802b  229-DF # NEC
-		13df 1003  PCI56RX Modem # E-Tech Inc
-		13e0 0117  IBM # GVC
-		13e0 0147  IBM # GVC
-		13e0 0197  IBM # GVC
-		13e0 01c7  IBM # GVC
-		13e0 01f7  IBM # GVC
-		1436 1003  IBM # CIS
-		1436 1103  IBM # CIS
+		0e11 b0bc  229-DF Zephyr
+		0e11 b114  229-DF Cheetah
+		1033 802b  229-DF
+		13df 1003  PCI56RX Modem
+		13e0 0117  IBM
+		13e0 0147  IBM F-1156IV+/R3 Spain V.90 Modem
+		13e0 0197  IBM
+		13e0 01c7  IBM F-1156IV+/R3 WW V.90 Modem
+		13e0 01f7  IBM
+		1436 1003  IBM
+		1436 1103  IBM 5614PM3G V.90 Modem
 		1436 1602  Compaq 229-DF Ducati
 	1004  HCF 56k Data/Fax/Voice Modem
+		1048 1500  MicroLink 56k Modem
 		10cf 1059  Fujitsu 229-DFRT
 	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
-		1033 8029  229-DFSV # NEC
-		1033 8054  Modem # NEC
+		1033 8029  229-DFSV
+		1033 8054  Modem
 		10cf 103c  Fujitsu
 		10cf 1055  Fujitsu 229-DFSV
 		10cf 1056  Fujitsu 229-DFSV
-		122d 4003  MDP3858SP-U # Aztech
-		122d 4006  Packard Bell MDP3858V-E # Aztech
-		122d 4008  MDP3858SP-A/SP-NZ # Aztech
-		122d 4009  MDP3858SP-E # Aztech
-		122d 4010  MDP3858V-U # Aztech
-		122d 4011  MDP3858SP-SA # Aztech
-		122d 4013  MDP3858V-A/V-NZ # Aztech
-		122d 4015  MDP3858SP-W # Aztech
-		122d 4016  MDP3858V-W # Aztech
-		122d 4019  MDP3858V-SA # Aztech
-		13df 1005  PCI56RVP Modem  # E-Tech Inc
-		13e0 0187  IBM # GVC
-		13e0 01a7  IBM # GVC
-		13e0 01b7  IBM # GVC
-		13e0 01d7  IBM # GVC
-		1436 1005  IBM # CIS
-		1436 1105  IBM # CIS
+		122d 4003  MDP3858SP-U
+		122d 4006  Packard Bell MDP3858V-E
+		122d 4008  MDP3858SP-A/SP-NZ
+		122d 4009  MDP3858SP-E
+		122d 4010  MDP3858V-U
+		122d 4011  MDP3858SP-SA
+		122d 4013  MDP3858V-A/V-NZ
+		122d 4015  MDP3858SP-W
+		122d 4016  MDP3858V-W
+		122d 4019  MDP3858V-SA
+		13df 1005  PCI56RVP Modem
+		13e0 0187  IBM
+		13e0 01a7  IBM
+		13e0 01b7  IBM DF-1156IV+/R3 Spain V.90 Modem
+		13e0 01d7  IBM DF-1156IV+/R3 WW V.90 Modem
+		1436 1005  IBM
+		1436 1105  IBM
+		1437 1105  IBM 5614PS3G V.90 Modem
+	1022  HCF 56k Modem
+		1436 1303  M3-5614PM3G V.90 Modem
 	1023  HCF 56k Data/Fax Modem
-		122d 4020  Packard Bell MDP3858-WE # Aztech
-		122d 4023  MDP3858-UE # Aztech
-		13e0 0247  IBM # GVC
-		13e0 0297  IBM # GVC
-		13e0 02c7  IBM # GVC
-		1436 1203  IBM # CIS
-		1436 1303  IBM # CIS
+		122d 4020  Packard Bell MDP3858-WE
+		122d 4023  MDP3858-UE
+		13e0 0247  IBM F-1156IV+/R6 Spain V.90 Modem
+		13e0 0297  IBM
+		13e0 02c7  IBM F-1156IV+/R6 WW V.90 Modem
+		1436 1203  IBM
+		1436 1303  IBM
 	1024  HCF 56k Data/Fax/Voice Modem
 	1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 106a  Fujitsu 235-DFSV
-		122d 4021  Packard Bell MDP3858V-WE # Aztech
-		122d 4022  MDP3858SP-WE # Aztech
-		122d 4024  MDP3858V-UE # Aztech
-		122d 4025  MDP3858SP-UE # Aztech
+		122d 4021  Packard Bell MDP3858V-WE
+		122d 4022  MDP3858SP-WE
+		122d 4024  MDP3858V-UE
+		122d 4025  MDP3858SP-UE
 	1026  HCF 56k PCI Speakerphone Modem
+	1032  HCF 56k Modem
+	1033  HCF 56k Modem
+	1034  HCF 56k Modem
 	1035  HCF 56k PCI Speakerphone Modem
+	1036  HCF 56k Modem
 	1085  HCF 56k Volcano PCI Modem
 	2005  HCF 56k Data/Fax Modem
-		104d 8044  229-DFSV # Sony
-		104d 8045  229-DFSV # Sony
-		104d 8055  PBE/Aztech 235W-DFSV # Sony
-		104d 8056  235-DFSV # Sony
-		104d 805a  Modem # Sony
-		104d 805f  Modem # Sony
-		104d 8074  Modem # Sony
+		104d 8044  229-DFSV
+		104d 8045  229-DFSV
+		104d 8055  PBE/Aztech 235W-DFSV
+		104d 8056  235-DFSV
+		104d 805a  Modem
+		104d 805f  Modem
+		104d 8074  Modem
 	2013  HSF 56k Data/Fax Modem
-		1179 0001  Modem # Toshiba
-		1179 ff00  Modem # Toshiba
+		1179 0001  Modem
+		1179 ff00  Modem
 	2014  HSF 56k Data/Fax/Voice Modem
 		10cf 1057  Fujitsu Citicorp III
-		122d 4050  MSP3880-U # Aztech
-		122d 4055  MSP3880-W # Aztech
+		122d 4050  MSP3880-U
+		122d 4055  MSP3880-W
 	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 1063  Fujitsu
 		10cf 1064  Fujitsu
 		1468 2015  Fujitsu
 	2016  HSF 56k Data/Fax/Voice/Spkp Modem
-		122d 4051  MSP3880V-W # Aztech
-		122d 4052  MSP3880SP-W # Aztech
-		122d 4054  MSP3880V-U # Aztech
-		122d 4056  MSP3880SP-U # Aztech
-		122d 4057  MSP3880SP-A # Aztech
+		122d 4051  MSP3880V-W
+		122d 4052  MSP3880SP-W
+		122d 4054  MSP3880V-U
+		122d 4056  MSP3880SP-U
+		122d 4057  MSP3880SP-A
 	4311  Riptide HSF 56k PCI Modem
 		127a 4311  Ring Modular? Riptide HSF RT HP Dom
 		13e0 0210  HP-GVC
@@ -3334,10 +4066,11 @@
 		1235 4321  Hewlett Packard DF
 		1235 4324  Hewlett Packard DF
 		13e0 0210  Hewlett Packard DF
-		144d 2321  Riptide # Samsung
+		144d 2321  Riptide
 	4322  Riptide PCI Game Controller
 		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
+		108d 0022  RapidFire 616X ATM155 Adapter
 		108d 0027  RapidFire 616X ATM155 Adapter
 127b  Pixera Corporation
 127c  Crosspoint Solutions, Inc.
@@ -3389,6 +4122,7 @@
 1298  Spellcaster Telecommunications Inc.
 1299  Knowledge Technology Lab.
 129a  VMetro, inc.
+	0615  PBT-615 PCI-X Bus Analyzer
 129b  Image Access
 129c  Jaycor
 129d  Compcore Multimedia, Inc.
@@ -3410,9 +4144,11 @@
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
-	0001  AceNIC Gigabit Ethernet (Fibre)
-		1410 0104  Gigabit Ethernet-SX PCI Adapter (14100401)
+	0001  AceNIC Gigabit Ethernet
+		12ae 0001  Gigabit Ethernet-SX (Universal)
+		1410 0104  Gigabit Ethernet-SX PCI Adapter
 	0002  AceNIC Gigabit Ethernet (Copper)
+		12ae 0002  Gigabit Ethernet-T (3C986-T)
 12af  TDK USA Corp
 12b0  Jorge Scientific Corp
 12b1  GammaLink
@@ -3459,6 +4195,8 @@
 	5598  PCI NE2K Ethernet
 12c4  Connect Tech Inc
 12c5  Picture Elements Incorporated
+	007e  Imaging/Scanning Subsystem Engine
+	007f  Imaging/Scanning Subsystem Engine
 	0081  PCIVST [Grayscale Thresholding Engine]
 	0085  Video Simulator/Sender
 	0086  THR2 Multi-scale Thresholder
@@ -3478,19 +4216,24 @@
 	0008  NV1
 	0009  DAC64
 	0018  Riva128
+		1048 0c10  VICTORY Erazor
 		107b 8030  STB Velocity 128
 		1092 0350  Viper V330
 		1092 1092  Viper V330
 		10b4 1b1b  STB Velocity 128
-		10b4 1b20  STB Velocity 128
+		10b4 1b1d  STB Velocity 128
+		10b4 1b1e  STB Velocity 128, PAL TV-Out
+		10b4 1b20  STB Velocity 128 Sapphire
 		10b4 1b21  STB Velocity 128
 		10b4 1b22  STB Velocity 128 AGP, NTSC TV-Out
 		10b4 1b23  STB Velocity 128 AGP, PAL TV-Out
 		10b4 1b27  STB Velocity 128 DVD
+		10b4 1b88  MVP Pro 128
 		10b4 222a  STB Velocity 128 AGP
 		10b4 2230  STB Velocity 128
+		10b4 2232  STB Velocity 128
 		10b4 2235  STB Velocity 128 AGP
-		2a15 54a3  3DVision-SAGP
+		2a15 54a3  3DVision-SAGP / 3DexPlorer 3000
 	0019  Riva128ZX
 	0020  TNT
 	0028  TNT2
@@ -3498,7 +4241,7 @@
 	002c  VTNT2
 	00a0  ITNT2
 12d3  Vingmed Sound A/S
-12d4  DGM&S
+12d4  Ulticom (Formerly DGM&S)
 12d5  Equator Technologies
 12d6  Analogic Corp
 12d7  Biotronic SRL
@@ -3531,6 +4274,7 @@
 		1092 2100  Sonic Impact A3D
 		1092 2110  Sonic Impact A3D
 		1092 2200  Sonic Impact A3D
+		122d 1002  AU8820 Vortex Digital Audio Processor
 		12eb 0001  AU8820 Vortex Digital Audio Processor
 		5053 3355  Montego
 	0002  Vortex 2
@@ -3751,6 +4495,7 @@
 135a  Brain Boxes
 135b  Giganet Inc
 135c  Quatech Inc
+	00f0  MPAC-100 Syncronous Serial Card (Zilog 85230)
 135d  ABB Network Partner AB
 135e  Sealevel Systems Inc
 	7101  Single Port RS-232/422/485/530
@@ -3797,6 +4542,7 @@
 1383  Controlnet Inc
 1384  Reality Simulation Systems Inc
 1385  Netgear
+	4100  802.11b Wireless Adapter (MA301)
 	620a  GA620
 	622a  GA622
 	630a  GA630
@@ -3822,6 +4568,8 @@
 	2180  Intellio C218 Turbo PCI
 	3200  Intellio C320 Turbo PCI
 1394  Level One Communications
+	0001  LXT1001 Gigabit Ethernet
+		1394 0001  NetCelerator Adapter
 1395  Ambicom Inc
 1396  Cipher Systems Inc
 1397  Cologne Chip Designs GmbH
@@ -3831,6 +4579,9 @@
 1398  Clarion co. Ltd
 1399  Rios systems Co Ltd
 139a  Alacritech Inc
+	0001  Quad Port 10/100 Server Accelerator
+	0003  Single Port 10/100 Server Accelerator
+	0005  Single Port Gigabit Server Accelerator
 139b  Mediasonic Multimedia Systems Ltd
 139c  Quantum 3d Inc
 139d  EPL limited
@@ -3839,12 +4590,17 @@
 13a0  Crystal Group Inc
 13a1  Kawasaki Heavy Industries Ltd
 13a2  Ositech Communications Inc
-13a3  Hi-Fn
+13a3  Hifn Inc.
+	0005  7751 Security Processor
+	0006  6500 Public Key Processor
+	0007  7811 Security Processor
+	0012  7951 Security Processor
 13a4  Rascom Inc
 13a5  Audio Digital Imaging Inc
 13a6  Videonics Inc
 13a7  Teles AG
 13a8  Exar Corp.
+	0158  XR17C158 Octal UART
 13a9  Siemens Medical Systems, Ultrasound Group
 13aa  Broadband Networks Inc
 13ab  Arcom Control Systems Ltd
@@ -3873,6 +4629,7 @@
 13c1  3ware Inc
 	1000  3ware ATA-RAID
 	1001  3ware 7000-series ATA-RAID
+	1002  3ware ATA-RAID
 13c2  Technotrend Systemtechnik GmbH
 13c3  Janz Computer AG
 13c4  Phase Metrics
@@ -3889,6 +4646,7 @@
 13cf  Studio Audio & Video Ltd
 13d0  Techsan Electronics Co Ltd
 13d1  Abocom Systems Inc
+	ab06  RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter
 13d2  Shark Multimedia Inc
 13d3  IMC Networks
 13d4  Graphics Microsystems Inc
@@ -3922,11 +4680,12 @@
 13ee  Hayes Microcomputer Products Inc
 13ef  Coppercom Inc
 13f0  Sundance Technology Inc
-	0201  Sundance Ethernet
+	0201  ST201 Sundance Ethernet
 13f1  Oce' - Technologies B.V.
 13f2  Ford Microelectronics Inc
 13f3  Mcdata Corporation
-13f4  Troika Design Inc
+13f4  Troika Networks, Inc.
+	1401  Zentai Fibre Channel Adapter
 13f5  Kansai Electric Co. Ltd
 13f6  C-Media Electronics Inc
 	0100  CM8338A
@@ -3934,6 +4693,8 @@
 	0101  CM8338B
 		13f6 0101  CMI8338-031 PCI Audio Device
 	0111  CM8738
+		1043 8077  CMI8738 6-channel audio controller
+		1043 80e2  CMI8738 6ch-MX
 		13f6 0111  CMI8738/C3DX PCI Audio Device
 	0211  CM8738
 13f7  Wildfire Communications
@@ -3944,6 +4705,7 @@
 13fc  Computer Peripherals International
 13fd  Micro Science Inc
 13fe  Advantech Co. Ltd
+	1756  PCI-1756
 13ff  Silicon Spice Inc
 1400  Artx Inc
 	1401  9432 TX
@@ -3963,11 +4725,13 @@
 	0500  Lava Single Serial
 	0600  Lava Port 650
 	8000  Lava Parallel
+	8001  Dual parallel port controller A
 	8002  Lava Dual Parallel port A
 	8003  Lava Dual Parallel port B
 	8800  BOCA Research IOPPAR
 1408  Aloka Co. Ltd
 1409  Timedia Technology Co Ltd
+	7168  PCI2S550 (Dual 16550 UART)
 140a  DSP Research Inc
 140b  Ramix Inc
 140c  Elmic Systems Inc
@@ -3981,13 +4745,16 @@
 1413  Addonics
 1414  Microsoft Corporation
 1415  Oxford Semiconductor Ltd
-	9501  16PCI954 Function 0
-		15ed 2000  Macrolink MCCR Serial p0-3 of 8
-		15ed 2001  Macrolink MCCR Serial p0-3 of 16
-	9511  16PCI954 Function 1
-		15ed 2000  Macrolink MCCR Serial p4-7 of 8
-		15ed 2001  Macrolink MCCR Serial p4-15 of 16
-	9521  16PCI952 PCI/dual 16950 UART
+	8403  VScom 011H-EP1 1 port parallel adaptor
+	9501  OX16PCI954 (Quad 16950 UART) function 0
+		15ed 2000  MCCR Serial p0-3 of 8
+		15ed 2001  MCCR Serial p0-3 of 16
+	950a  EXSYS EX-41092 Dual 16950 Serial adapter
+	950b  OXCB950 Cardbus 16950 UART
+	9511  OX16PCI954 (Quad 16950 UART) function 1
+		15ed 2000  MCCR Serial p4-7 of 8
+		15ed 2001  MCCR Serial p4-15 of 16
+	9521  OX16PCI952 (Dual 16950 UART)
 1416  Multiwave Innovation pte Ltd
 1417  Convergenet Technologies Inc
 1418  Kyushu electronics systems Inc
@@ -4164,6 +4931,10 @@
 14b8  Techsoft Technology Co Ltd
 14b9  AIRONET Wireless Communications
 	0001  PC4800
+	0340  PC4800
+	0350  PC4800
+	4500  PC4500
+	4800  PC4800
 14ba  INTERNIX Inc.
 14bb  SEMTECH Corporation
 14bc  Globespan Semiconductor Inc.
@@ -4189,6 +4960,22 @@
 14d0  Ericsson Axe R & D
 14d1  Computer Hi-Tech Co Ltd
 14d2  Titan Electronics Inc
+	8001  VScom 010L 1 port parallel adaptor
+	8002  VScom 020L 2 port parallel adaptor
+	8010  VScom 100L 1 port serial adaptor
+	8011  VScom 110L 1 port serial and 1 port parallel adaptor
+	8020  VScom 200L 1 port serial adaptor
+	8021  VScom 210L 2 port serial and 1 port parallel adaptor
+	8040  VScom 400L 4 port serial adaptor
+	8080  VScom 800L 8 port serial adaptor
+	a000  VScom 010H 1 port parallel adaptor
+	a001  VScom 100H 1 port serial adaptor
+	a003  VScom 400H 4 port serial adaptor
+	a004  VScom 400HF1 4 port serial adaptor
+	a005  VScom 200H 2 port serial adaptor
+	e001  VScom 010HV2 1 port parallel adaptor
+	e010  VScom 100HV2 1 port serial adaptor
+	e020  VScom 200HV2 2 port serial adaptor
 14d3  CIRTECH (UK) Ltd
 14d4  Panacom Technology Corp
 14d5  Nitsuko Corporation
@@ -4210,62 +4997,75 @@
 	0007  PCI224
 	0008  PCI234
 	0009  PCI236
+	000a  PCI272
+	000b  PCI215
 14dd  Boulder Design Labs Inc
 14de  Applied Integration Corporation
 14df  ASIC Communications Corp
 14e1  INVERTEX
 14e2  INFOLIBRIA
 14e3  AMTELCO
-14e4  BROADCOM Corporation
+14e4  Broadcom Corporation
 	1644  NetXtreme BCM5700 Gigabit Ethernet
-		1014 0277  Broadcom Vigil B5700 1000Base-T
+		1014 0277  Broadcom Vigil B5700 1000BaseTX
 		1028 00d1  Broadcom BCM5700
 		1028 0106  Broadcom BCM5700
-		1028 0109  Broadcom BCM5700
-		1028 010a  Broadcom BCM5700
+		1028 0109  Broadcom BCM5700 1000BaseTX
+		1028 010a  Broadcom BCM5700 1000BaseTX
 		10b7 1000  3C996-T 1000BaseTX
 		10b7 1001  3C996B-T 1000BaseTX
 		10b7 1002  3C996C-T 1000BaseTX
-		10b7 1003  3C997-T 1000BaseTX
+		10b7 1003  3C997-T 1000BaseTX Dual Port
 		10b7 1004  3C996-SX 1000BaseSX
-		10b7 1005  3C997-SX 1000BaseSX
+		10b7 1005  3C997-SX 1000BaseSX Dual Port
 		10b7 1008  3C942 Gigabit LOM (31X31)
 		14e4 0002  NetXtreme 1000BaseSX
 		14e4 0003  NetXtreme 1000BaseSX
 		14e4 0004  NetXtreme 1000BaseTX
-		14e4 1644  NetXtreme BCM5700 1000BaseTX
+		14e4 1028  NetXtreme 1000BaseTX
+		14e4 1644  BCM5700 1000BaseTX
 	1645  NetXtreme BCM5701 Gigabit Ethernet
-		0e11 007c  NC7770 1000BaseTX
-		0e11 007d  NC6770 1000BaseSX
-		0e11 0085  NC7780 1000BaseTX
-		1028 0121  Broadcom BCM5701
+		0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
+		0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		1028 0121  Broadcom BCM5701 1000BaseTX
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1006  3C996B-T 1000BaseTX
 		10b7 1007  3C1000-T 1000BaseTX
 		10b7 1008  3C940-BR01 1000BaseTX
-		14e4 0001  NetXtreme BCM5701 1000BaseTX
-		14e4 0005  NetXtreme BCM5701 1000BaseTX
-		14e4 0006  NetXtreme BCM5701 1000BaseTX
-		14e4 0007  NetXtreme BCM5701 1000BaseSX
-		14e4 0008  NetXtreme BCM5701 1000BaseTX
-		14e4 8008  NetXtreme BCM5701 1000BaseTX
+		14e4 0001  BCM5701 1000BaseTX
+		14e4 0005  BCM5701 1000BaseTX
+		14e4 0006  BCM5701 1000BaseTX
+		14e4 0007  BCM5701 1000BaseSX
+		14e4 0008  BCM5701 1000BaseTX
+		14e4 8008  BCM5701 1000BaseTX
 	1646  NetXtreme BCM5702 Gigabit Ethernet
-		14e4 8009  Broadcom BCM5702
+		0e11 00bb  NC7760 1000BaseTX
+		1028 0126  Broadcom BCM5702 1000BaseTX
+		14e4 8009  BCM5702 1000BaseTX
 	1647  NetXtreme BCM5703 Gigabit Ethernet
-		0e11 009a  NC7770
-		0e11 0099  NC7780
-		14e4 0009  Broadcom BCM5703
-		14e4 8009  Broadcom BCM5703
+		0e11 0099  NC7780 1000BaseTX
+		0e11 009a  NC7770 1000BaseTX
+		14e4 0009  BCM5703 1000BaseTX
+		14e4 000a  BCM5703 1000BaseSX
+		14e4 000b  BCM5703 1000BaseTX
+		14e4 8009  BCM5703 1000BaseTX
+		14e4 800a  BCM5703 1000BaseTX
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
+	4212  BCM v.90 56k modem
 	5820  BCM5820 Crypto Accelerator
+	5821  BCM5821 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
 14e7  3CX
 14e8  RAYCER Inc
 14e9  GARNETS System CO Ltd
-14ea  PLANEX COMMUNICATIONS Inc
+14ea  Planex Communications, Inc
+	ab06  FNW-3603-TX CardBus Fast Ethernet
 14eb  SEIKO EPSON Corp
 14ec  ACQIRIS
 14ed  DATAKINETICS Ltd
@@ -4273,14 +5073,30 @@
 14ef  CARRY Computer ENG. CO Ltd
 14f0  CANON RESEACH CENTRE FRANCE
 14f1  Conexant
+	1002  HCF 56k Modem
+	1003  HCF 56k Modem
+	1004  HCF 56k Modem
+	1005  HCF 56k Modem
+	1006  HCF 56k Modem
+	1022  HCF 56k Modem
+	1023  HCF 56k Modem
+	1024  HCF 56k Modem
+	1025  HCF 56k Modem
+	1026  HCF 56k Modem
+	1032  HCF 56k Modem
 	1033  HCF 56k Data/Fax Modem
+		1033 8077  NEC
 		122d 4027  Dell Zeus - MDP3880-W(B) Data Fax Modem
 		122d 4030  Dell Mercury - MDP3880-U(B) Data Fax Modem
 		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem
 		13e0 020d  Dell Copper
 		13e0 020e  Dell Silver
+		13e0 0261  IBM
 		13e0 0290  Compaq Goldwing
+		13e0 02a0  IBM
+		13e0 02b0  IBM
 		13e0 02c0  Compaq Scooter
+		13e0 02d0  IBM
 		144f 1500  IBM P85-DF (1)
 		144f 1501  IBM P85-DF (2)
 		144f 150a  IBM P85-DF (3)
@@ -4290,6 +5106,7 @@
 	1035  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 1098  Fujitsu P85-DFSV
 	1036  HCF 56k Data/Fax/Voice/Spkp Modem
+		104d 8067  HCF 56k Modem
 		122d 4029  MDP3880SP-W
 		122d 4031  MDP3880SP-U
 		13e0 0209  Dell Titanium
@@ -4313,6 +5130,8 @@
 	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 	1436  HCF 56k Data/Fax Modem
 	1453  HCF 56k Data/Fax Modem
+		13e0 0240  IBM
+		13e0 0250  IBM
 		144f 1502  IBM P95-DF (1)
 		144f 1503  IBM P95-DF (2)
 	1454  HCF 56k Data/Fax/Voice Modem
@@ -4320,6 +5139,8 @@
 	1456  HCF 56k Data/Fax/Voice/Spkp Modem
 		122d 4035  Dell Europa - MDP3900V-W
 		122d 4302  Dell MP3930V-W(C) MiniPCI
+	1610  ADSL AccessRunner PCI Arbitration Device
+	1611  AccessRunner PCI ADSL Interface Device
 	1803  HCF 56k Modem
 		0e11 0023  623-LAN Grizzly
 		0e11 0043  623-LAN Yogi
@@ -4334,6 +5155,9 @@
 		0e11 b195  Bear
 		0e11 b196  Seminole 1
 		0e11 b1be  Seminole 2
+		1025 8013  Acer
+		1033 809d  NEC
+		1033 80bc  NEC
 		155d 6793  HP
 		155d 8850  E Machines
 	2014  HSF 56k Data/Fax/Voice Modem
@@ -4366,6 +5190,9 @@
 	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
 	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)
 	2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)
+		104d 8075  Modem
+		104d 8083  Modem
+		104d 8097  Modem
 	2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)
 	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)
 	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)
@@ -4376,6 +5203,8 @@
 	2f00  HSF 56k HSFi Modem
 		13e0 8d84  IBM HSFi V.90
 		13e0 8d85  Compaq Stinger
+		14f1 2004  Dynalink 56PMi
+	8234  RS8234 ATM SAR Controller [ServiceSAR Plus]
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -4423,6 +5252,8 @@
 1514  TFL LAN Inc
 1515  Advent design
 1516  MYSON Technology Inc
+	0803  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
+		1320 10bd  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
 1517  ECHOTEK Corp
 1518  PEP MODULAR Computers GmbH
 1519  TELEFON AKTIEBOLAGET LM Ericsson
@@ -4435,9 +5266,16 @@
 151d  Fujitsu Computer Products Of America
 151e  MATRIX Corp
 151f  TOPIC SEMICONDUCTOR Corp
+	0000  TP560 Data/Fax/Voice 56k modem
 1520  CHAPLET System Inc
 1521  BELL Corp
 1522  MainPine Ltd
+	0100  PCI <-> IOBus Bridge
+		1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0500  RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem
 1523  MUSIC Semiconductors
 1524  ENE Technology Inc
 1525  IMPACT Technologies
@@ -4592,6 +5430,7 @@
 15a0  Compumaster SRL
 15a1  Geocast Network Systems
 15a2  Catalyst Enterprises Inc
+	0001  TA700 PCI Bus Analyzer/Exerciser
 15a3  Italtel
 15a4  X-Net OY
 15a5  Toyota Macs Inc
@@ -4608,6 +5447,7 @@
 15b1  Source Technology Inc
 15b2  Mosaid Technologies Inc
 15b3  Mellanox Technology
+	5274  MT21108 InfiniBridge
 15b4  CCI/TRIAD
 15b5  Cimetrics Inc
 15b6  Texas Memory Systems Inc
@@ -4617,6 +5457,7 @@
 15ba  Impacct Technology Corp
 15bb  Portwell Inc
 15bc  Agilent Technologies
+	2929  E2929A PCI/PCI-X Bus Analyzer
 15bd  DFI Inc
 15be  Sola Electronics
 15bf  High Tech Computer Corp (HTC)
@@ -4627,7 +5468,8 @@
 15c4  EVSX Inc
 15c5  Procomp Informatics Ltd
 15c6  Technical University of Budapest
-15c7  Tateyama Dystem Laboratory Co Ltd
+15c7  Tateyama System Laboratory Co Ltd
+	0349  Tateyama C-PCI PLC/NC card Rev.01A
 15c8  Penta Media Co Ltd
 15c9  Serome Technology Inc
 15ca  Bitboys OY
@@ -4661,6 +5503,7 @@
 15e6  Agere Inc
 15e7  Get Engineering Corp
 15e8  National Datacomm Corp
+	0130  Wireless PCI Card
 15e9  Pacific Digital Corp
 15ea  Tokyo Denshi Sekei K.K.
 15eb  Drsearch GmbH
@@ -4697,10 +5540,35 @@
 1619  FarSite Communications Ltd
 	0400  FarSync T2P (2 port X.21/V.35/V.24)
 	0440  FarSync T4P (4 port X.21/V.35/V.24)
+1629  Kongsberg Spacetec AS
+	1003  Format synchronizer v3.0
+	2002  Fast Universal Data Output
+1638  Standard Microsystems Corp [SMC]
+	1100  SMC2602W EZConnect / Addtron AWA-100
+1657  Brocade Communications Systems, Inc.
+165d  Hsing Tech. Enterprise Co., Ltd.
+1661  Worldspace Corp.
 1668  Action Tec Electronics Inc
-173b  Altima (nee BroadCom)
+16ec  U.S. Robotics
+	3685  Wireless Access PCI Adapter Model 022415
+16f6  VideoTele.com, Inc.
+170b  NetOctave Inc
+170c  YottaYotta Inc.
+173b  Altima (nee Broadcom)
 	03e8  AC1000 Gigabit Ethernet
 	03ea  AC9100 Gigabit Ethernet
+1743  Peppercon AG
+	8139  ROL/F-100 Fast Ethernet Adapter with ROL
+174b  PC Partner Limited
+175e  Sanera Systems, Inc.
+# also used by Struck Innovative Systeme for joint developments
+1796  Research Centre Juelich
+	0001  SIS1100 [Gigabit link]
+	0002  HOTlink
+	0003  Counter Timer
+	0004  CAMAC Controller
+	0005  PROFIBUS
+	0006  AMCC HOTlink
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
@@ -4726,11 +5594,12 @@
 3000  Hansol Electronics Inc.
 3142  Post Impression Systems.
 3388  Hint Corp
+	0021  HB1-SE33 PCI-PCI Bridge
 	8011  VXPro II Chipset
 		3388 8011  VXPro II Chipset CPU to PCI Bridge
 	8012  VXPro II Chipset
 		3388 8012  VXPro II Chipset PCI to ISA Bridge
-	8013  VXPro II Chipset
+	8013  VXPro II IDE
 		3388 8013  VXPro II Chipset EIDE Controller
 3411  Quantum Designs (H.K.) Inc
 3513  ARCOM Control Systems Ltd
@@ -4745,6 +5614,7 @@
 	0007  3D Extreme
 	0008  GLINT Gamma G1
 	0009  Permedia II 2D+3D
+		1040 0011  AccelStar II
 		3d3d 0100  AccelStar II 3D Accelerator
 		3d3d 0111  Permedia 3:16
 		3d3d 0114  Santa Ana
@@ -4774,6 +5644,7 @@
 	2501  ALG-2564A/25128A
 	4000  ALS4000 Audio Chipset
 		4005 4000  ALS4000 Audio Chipset
+	4710  ALC200/200P
 4033  Addtron Technology Co, Inc.
 	1360  RTL8139 Ethernet
 4143  Digital Equipment Corp
@@ -4795,11 +5666,31 @@
 		4a14 5000  RT8029-Based Ethernet Adapter
 4b10  Buslogic Inc.
 4c48  LUNG HWA Electronics
+4c53  SBS Technologies
 4ca1  Seanix Technology Inc
 4d51  MediaQ Inc.
 	0200  MQ-200
 4d54  Microtechnica Co Ltd
 4ddc  ILC Data Device Corp
+	0100  DD-42924I5-300 (ARINC 429 Data Bus)
+	0801  BU-65570I1 MIL-STD-1553 Test and Simulation
+	0802  BU-65570I2 MIL-STD-1553 Test and Simulation
+	0811  BU-65572I1 MIL-STD-1553 Test and Simulation
+	0812  BU-65572I2 MIL-STD-1553 Test and Simulation
+	0881  BU-65570T1 MIL-STD-1553 Test and Simulation
+	0882  BU-65570T2 MIL-STD-1553 Test and Simulation
+	0891  BU-65572T1 MIL-STD-1553 Test and Simulation
+	0892  BU-65572T2 MIL-STD-1553 Test and Simulation
+	0901  BU-65565C1 MIL-STD-1553 Data Bus
+	0902  BU-65565C2 MIL-STD-1553 Data Bus
+	0903  BU-65565C3 MIL-STD-1553 Data Bus
+	0904  BU-65565C4 MIL-STD-1553 Data Bus
+	0b01  BU-65569I1 MIL-STD-1553 Data Bus
+	0b02  BU-65569I2 MIL-STD-1553 Data Bus
+	0b03  BU-65569I3 MIL-STD-1553 Data Bus
+	0b04  BU-65569I4 MIL-STD-1553 Data Bus
+5046  GemTek Technology Corporation
+	1001  PCI Radio
 5053  Voyetra Technologies
 	2010  Daytona Audio Adapter
 5136  S S Technologies
@@ -4843,7 +5734,7 @@
 	88f3  86c968 [Vision 968 VRAM] rev 3
 	8900  86c755 [Trio 64V2/DX]
 		5333 8900  86C775 Trio64V2/DX
-	8901  Trio 64V2/DX or /GX
+	8901  86c775/86c785 [Trio 64V2/DX or /GX]
 		5333 8901  86C775 Trio64V2/DX, 86C785 Trio64V2/GX
 	8902  Plato/PX
 	8903  Trio 3D business multimedia
@@ -4872,9 +5763,11 @@
 		5333 8a13  Trio3D/2X
 	8a20  86c794 [Savage 3D]
 		5333 8a20  86C391 Savage3D
-	8a21  86c795 [Savage 3D/MV]
+	8a21  86c390 [Savage 3D/MV]
 		5333 8a21  86C390 Savage3D/MV
 	8a22  Savage 4
+		1033 8068  Savage 4
+		1033 8069  Savage 4
 		105d 0018  SR9 8Mb SDRAM
 		105d 002a  SR9 Pro 16Mb SDRAM
 		105d 003a  SR9 Pro 32Mb SDRAM
@@ -4906,12 +5799,27 @@
 	8a26  ProSavage KM133
 	8c00  ViRGE/M3
 	8c01  ViRGE/MX
+		1179 0001  ViRGE/MX
 	8c02  ViRGE/MX+
 	8c03  ViRGE/MX+MV
 	8c10  86C270-294 Savage/MX-MV
 	8c11  82C270-294 Savage/MX
 	8c12  86C270-294 Savage/IX-MV
 	8c13  86C270-294 Savage/IX
+	8c22  SuperSavage MX/128
+	8c24  SuperSavage MX/64
+	8c26  SuperSavage MX/64C
+	8c2a  SuperSavage IX/128 SDR
+	8c2b  SuperSavage IX/128 DDR
+	8c2c  SuperSavage IX/64 SDR
+	8c2d  SuperSavage IX/64 DDR
+	8c2e  SuperSavage IX/C SDR
+		1014 01fc  ThinkPad T23 (2647-4MG)
+	8c2f  SuperSavage IX/C DDR
+# Integrated in VIA ProSavage PN133 North Bridge
+	8d01  VT8603 [ProSavage PN133] AGP4X VGA Controller (Twister)
+	8d02  VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK)
+	8d04  VT8751 [ProSavageDDR P4M266] VGA Controller
 	9102  86C410 Savage 2000
 		1092 5932  Viper II Z200
 		1092 5934  Viper II Z200
@@ -4946,6 +5854,7 @@
 	0011  PWDOG2 [PCI-Watchdog 2]
 8086  Intel Corp.
 	0007  82379AB
+	0008  Extended Express System Support Controller
 	0039  21145
 	0122  82437FX
 	0482  82375EB
@@ -4956,31 +5865,85 @@
 	04d0  82437FX [Triton FX]
 	0600  RAID Controller
 	0960  80960RP [i960 RP Microprocessor/Bridge]
+	0962  80960RM [i960RM Bridge]
 	0964  80960RP [i960 RP Microprocessor/Bridge]
 	1000  82542 Gigabit Ethernet Controller
-		0e11 b0df  NC1632 Gigabit Ethernet Adapter
-		0e11 b0e0  NC1633 Gigabit Ethernet Adapter
-		0e11 b123  NC1634 Gigabit Ethernet Adapter
+		0e11 b0df  NC1632 Gigabit Ethernet Adapter (1000-SX)
+		0e11 b0e0  NC1633 Gigabit Ethernet Adapter (1000-LX)
+		0e11 b123  NC1634 Gigabit Ethernet Adapter (1000-SX)
 		1014 0119  Netfinity Gigabit Ethernet SX Adapter
+		8086 1000  PRO/1000 Gigabit Server Adapter
 	1001  82543GC Gigabit Ethernet Controller
+		0e11 004a  NC6136 Gigabit Server Adapter
+		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
+		8086 1003  PRO/1000 F Server Adapter
+	1002  Pro 100 LAN+Modem 56 Cardbus II
+		8086 200e  Pro 100 LAN+Modem 56 Cardbus II
+		8086 2013  Pro 100 SR Mobile Combo Adapter
+		8086 2017  Pro 100 S Combo Mobile Adapter
 	1004  82543GC Gigabit Ethernet Controller
+		0e11 0049  NC7132 Gigabit Upgrade Module
+		0e11 b1a4  NC7131 Gigabit Server Adapter
+		1014 10f2  Gigabit Ethernet Server Adapter
+		8086 1004  PRO/1000 T Server Adapter
+		8086 2004  PRO/1000 T Server Adapter
 	1008  82544EI Gigabit Ethernet Controller
+		8086 1107  PRO/1000 XT Server Adapter
+		8086 2107  PRO/1000 XT Server Adapter
+		8086 2110  PRO/1000 XT Server Adapter
 	1009  82544EI Gigabit Ethernet Controller
+		8086 1109  PRO/1000 XF Server Adapter
+		8086 2109  PRO/1000 XF Server Adapter
 	100c  82544GC Gigabit Ethernet Controller
+		8086 1112  PRO/1000 T Desktop Adapter
+		8086 2112  PRO/1000 T Desktop Adapter
 	100d  82544GC Gigabit Ethernet Controller
+	100e  82540EM Gigabit Ethernet Controller
+		8086 001e  PRO/1000 MT Desktop Adapter
+		8086 002e  PRO/1000 MT Desktop Adapter
+	100f  82545EM Gigabit Ethernet Controller
+		8086 1001  PRO/1000 MT Server Adapter
+	1010  82546EB Gigabit Ethernet Controller
+		8086 1011  PRO/1000 MT Dual Port Server Adapter
+	1011  82545EM Gigabit Ethernet Controller
+		8086 1002  PRO/1000 MF Server Adapter
+	1012  82546EB Gigabit Ethernet Controller
+		8086 1012  PRO/1000 MF Dual Port Server Adapter
 	1029  82559 Ethernet Controller
 	1030  82559 InBusiness 10/100
-	1031  82801CAM (ICH3) Chipset Ethernet Controller
-	1032  82801CAM (ICH3) Chipset Ethernet Controller
-	1033  82801CAM (ICH3) Chipset Ethernet Controller
-	1034  82801CAM (ICH3) Chipset Ethernet Controller
-	1035  82801CAM (ICH3) Chipset Ethernet Controller
-	1036  82801CAM (ICH3) Chipset Ethernet Controller
+	1031  82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller
+		1014 0209  ThinkPad A30p (2653-64G)
+		104d 80e7  Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		107b 5350  EtherExpress PRO/100 VE
+		1179 0001  EtherExpress PRO/100 VE
+		144d c000  EtherExpress PRO/100 VE
+		144d c001  EtherExpress PRO/100 VE
+		144d c003  EtherExpress PRO/100 VE
+	1032  82801CAM (ICH3) PRO/100 VE Ethernet Controller
+	1033  82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller
+	1034  82801CAM (ICH3) PRO/100 VM Ethernet Controller
+	1035  82801CAM (ICH3)/82562EH (LOM)  Ethernet Controller
+	1036  82801CAM (ICH3) 82562EH Ethernet Controller
 	1037  82801CAM (ICH3) Chipset Ethernet Controller
-	1038  82801CAM (ICH3) Chipset Ethernet Controller
+	1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller
+	1039  82801BD PRO/100 VE (LOM) Ethernet Controller
+	103a  82801BD PRO/100 VE (CNR) Ethernet Controller
+	103b  82801BD PRO/100 VM (LOM) Ethernet Controller
+	103c  82801BD PRO/100 VM (CNR) Ethernet Controller
+	103d  82801BD PRO/100 VE (MOB) Ethernet Controller
+	103e  82801BD PRO/100 VM (MOB) Ethernet Controller
+	1059  82551QM Ethernet Controller
 	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+	1131  82815 815 Chipset AGP Bridge
 	1132  82815 CGC [Chipset Graphics Controller]
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
 	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
+		8086 1161  82806AA PCI64 Hub APIC
+	1200  Intel IXP1200 Network Processor
+		172a 0000  AEP SSL Accelerator
 	1209  82559ER
 	1221  82092AA_0
 	1222  82092AA_1
@@ -4989,31 +5952,69 @@
 	1226  82596 PRO/10 PCI
 	1227  82865 EtherExpress PRO/100A
 	1228  82556 EtherExpress PRO/100 Smart
-	1229  82557 [Ethernet Pro 100]
-		0e11 b01e  NC3120
-		0e11 b01f  NC3122
-		0e11 b02f  NC1120
+# the revision field differentiates between them (1-3 is 82557, 4-5 is 82558, 6-8 is 82559, 9 is 82559ER)
+	1229  82557/8/9 [Ethernet Pro 100]
+		0e11 3001  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3002  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3003  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3004  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3005  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3006  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3007  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 b01e  NC3120 Fast Ethernet NIC
+		0e11 b01f  NC3122 Fast Ethernet NIC (dual port)
+		0e11 b02f  NC1120 Ethernet NIC
 		0e11 b04a  Netelligent 10/100TX NIC with Wake on LAN
-		0e11 b0c6  Embedded NC3120 with Wake on LAN
-		0e11 b0c7  Embedded NC3121
-		0e11 b0d7  NC3121 with Wake on LAN
-		0e11 b0dd  NC3131 (82558B)
-		0e11 b0de  NC3132
-		0e11 b0e1  NC3133
-		0e11 b144  NC3123 (82559)
+		0e11 b0c6  NC3161 Fast Ethernet NIC (embedded, WOL)
+		0e11 b0c7  NC3160 Fast Ethernet NIC (embedded)
+		0e11 b0d7  NC3121 Fast Ethernet NIC (WOL)
+		0e11 b0dd  NC3131 Fast Ethernet NIC (dual port)
+		0e11 b0de  NC3132 Fast Ethernet Module (dual port)
+		0e11 b0e1  NC3133 Fast Ethernet Module (100-FX)
+		0e11 b134  NC3163 Fast Ethernet NIC (embedded, WOL)
+		0e11 b13c  NC3162 Fast Ethernet NIC (embedded)
+		0e11 b144  NC3123 Fast Ethernet NIC (WOL)
+		0e11 b163  NC3134 Fast Ethernet NIC (dual port)
+		0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)
+		0e11 b1a4  NC7131 Gigabit Server Adapter
 		1014 005c  82558B Ethernet Pro 10/100
+		1014 01bc  82559 Fast Ethernet LAN On Motherboard
+		1014 01f1  10/100 Ethernet Server Adapter
+		1014 01f2  10/100 Ethernet Server Adapter
+		1014 0207  Ethernet Pro/100 S
+		1014 0232  10/100 Dual Port Server Adapter
 		1014 105c  Netfinity 10/100
+		1014 305c  10/100 EtherJet Management Adapter
+		1014 405c  10/100 EtherJet Adapter with Alert on LAN
+		1014 505c  10/100 EtherJet Secure Management Adapter
+		1014 605c  10/100 EtherJet Secure Management Adapter
+		1014 705c  10/100 Netfinity 10/100 Ethernet Security Adapter
+		1014 805c  10/100 Netfinity 10/100 Ethernet Security Adapter
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
 		1033 801f  PK-UG-X006
-		103c 10c0  Ethernet Pro 10/100TX
-		103c 10c3  Ethernet Pro 10/100TX
-		103c 1200  Ethernet Pro 10/100TX
+		1033 8026  PK-UG-X006
+		1033 8063  82559-based Fast Ethernet Adapter
+		1033 8064  82559-based Fast Ethernet Adapter
+		103c 10c0  NetServer 10/100TX
+		103c 10c3  NetServer 10/100TX
+		103c 10ca  NetServer 10/100TX
+		103c 10cb  NetServer 10/100TX
+		103c 10e3  NetServer 10/100TX
+		103c 10e4  NetServer 10/100TX
+		103c 1200  NetServer 10/100TX
 		10c3 1100  SmartEther100 SC1100
+		10cf 1115  8255x-based Ethernet Adapter (10/100)
+		10cf 1143  8255x-based Ethernet Adapter (10/100)
+		1179 0001  8255x-based Ethernet Adapter (10/100)
 		1179 0002  PCI FastEther LAN on Docker
+		1179 0003  8255x-based Fast Ethernet
 		1259 2560  AT-2560 100
 		1259 2561  AT-2560 100 FX Ethernet Adapter
 		1266 0001  NE10/100 Adapter
+		144d 2501  SEM-2000 MiniPCI LAN Adapter
+		144d 2502  SEM-2100IL MiniPCI LAN Adapter
+		1668 1100  EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem)
 		8086 0001  EtherExpress PRO/100B (TX)
 		8086 0002  EtherExpress PRO/100B (T4)
 		8086 0003  EtherExpress PRO/10+
@@ -5028,14 +6029,76 @@
 		8086 000c  EtherExpress PRO/100+ Management Adapter
 		8086 000d  EtherExpress PRO/100+ Alert On LAN II* Adapter
 		8086 000e  EtherExpress PRO/100+ Management Adapter with Alert On LAN*
+		8086 000f  EtherExpress PRO/100 Desktop Adapter
+		8086 0010  EtherExpress PRO/100 S Management Adapter
+		8086 0011  EtherExpress PRO/100 S Management Adapter
+		8086 0012  EtherExpress PRO/100 S Advanced Management Adapter (D)
+		8086 0013  EtherExpress PRO/100 S Advanced Management Adapter (E)
+		8086 0030  EtherExpress PRO/100  Management Adapter with Alert On LAN* GC
+		8086 0031  EtherExpress PRO/100 Desktop Adapter
+		8086 0040  EtherExpress PRO/100 S Desktop Adapter
+		8086 0041  EtherExpress PRO/100 S Desktop Adapter
+		8086 0042  EtherExpress PRO/100 Desktop Adapter
+		8086 0050  EtherExpress PRO/100 S Desktop Adapter
 		8086 1009  EtherExpress PRO/100+ Server Adapter
 		8086 100c  EtherExpress PRO/100+ Server Adapter (PILA8470B)
+		8086 1012  EtherExpress PRO/100 S Server Adapter (D)
+		8086 1013  EtherExpress PRO/100 S Server Adapter (E)
+		8086 1015  EtherExpress PRO/100 S Dual Port Server Adapter
+		8086 1017  EtherExpress PRO/100+ Dual Port Server Adapter
+		8086 1030  EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server
+		8086 1040  EtherExpress PRO/100 S Server Adapter
+		8086 1041  EtherExpress PRO/100 S Server Adapter
+		8086 1042  EtherExpress PRO/100 Server Adapter
+		8086 1050  EtherExpress PRO/100 S Server Adapter
+		8086 1051  EtherExpress PRO/100 Server Adapter
+		8086 1052  EtherExpress PRO/100 Server Adapter
 		8086 10f0  EtherExpress PRO/100+ Dual Port Adapter
+		8086 2009  EtherExpress PRO/100 S Mobile Adapter
 		8086 200d  EtherExpress PRO/100 Cardbus
 		8086 200e  EtherExpress PRO/100 LAN+V90 Cardbus Modem
+		8086 200f  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2010  EtherExpress PRO/100 S Mobile Combo Adapter
+		8086 2013  EtherExpress PRO/100 SR Mobile Combo Adapter
+		8086 2016  EtherExpress PRO/100 S Mobile Adapter
+		8086 2017  EtherExpress PRO/100 S Combo Mobile Adapter
+		8086 2018  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2019  EtherExpress PRO/100 SR Combo Mobile Adapter
+		8086 2101  EtherExpress PRO/100 P Mobile Adapter
+		8086 2102  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2103  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2104  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2105  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2106  EtherExpress PRO/100 P Mobile Adapter
+		8086 2107  EtherExpress PRO/100 Network Connection
+		8086 2108  EtherExpress PRO/100 Network Connection
+		8086 2200  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2201  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2202  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2203  EtherExpress PRO/100+ MiniPCI
+		8086 2204  EtherExpress PRO/100+ MiniPCI
+		8086 2205  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2206  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2207  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2208  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2402  EtherExpress PRO/100+ MiniPCI
+		8086 2407  EtherExpress PRO/100+ MiniPCI
+		8086 2408  EtherExpress PRO/100+ MiniPCI
+		8086 2409  EtherExpress PRO/100+ MiniPCI
+		8086 240f  EtherExpress PRO/100+ MiniPCI
+		8086 2410  EtherExpress PRO/100+ MiniPCI
+		8086 2411  EtherExpress PRO/100+ MiniPCI
+		8086 2412  EtherExpress PRO/100+ MiniPCI
+		8086 2413  EtherExpress PRO/100+ MiniPCI
 		8086 3000  82559 Fast Ethernet LAN on Motherboard
 		8086 3001  82559 Fast Ethernet LOM with Basic Alert on LAN*
 		8086 3002  82559 Fast Ethernet LOM with Alert on LAN II*
+		8086 3006  EtherExpress PRO/100 S Network Connection
+		8086 3007  EtherExpress PRO/100 S Network Connection
+		8086 3008  EtherExpress PRO/100 Network Connection
+		8086 3010  EtherExpress PRO/100 S Network Connection
+		8086 3011  EtherExpress PRO/100 S Network Connection
+		8086 3012  EtherExpress PRO/100 Network Connection
 	122d  430FX - 82437FX TSC [Triton I]
 	122e  82371FB PIIX ISA [Triton I]
 	1230  82371FB PIIX IDE [Triton I]
@@ -5047,24 +6110,40 @@
 	123b  82380PB
 	123c  82380AB
 	123d  683053 Programmable Interrupt Device
+	123f  82466GX Integrated Hot-Plug Controller (IHPC)
 	1240  752 AGP
 	124b  82380FB
 	1250  430HX - 82439HX TXC [Triton II]
 	1360  82806AA PCI64 Hub PCI Bridge
 	1361  82806AA PCI64 Hub Controller (HRes)
+		8086 1361  82806AA PCI64 Hub Controller (HRes)
+		8086 8000  82806AA PCI64 Hub Controller (HRes)
+	1460  82870P2 P64H2 Hub PCI Bridge
+	1461  82870P2 P64H2 I/OxAPIC
+	1462  82870P2 P64H2 Hot Plug Controller
 	1960  80960RP [i960RP Microprocessor]
-		101e 0438  MegaRaid 438
-		101e 0466  MegaRaid 466
-		101e 0467  MegaRaid 467
+		101e 0431  MegaRAID 431 RAID Controller
+		101e 0438  MegaRAID 438 Ultra2 LVD RAID Controller
+		101e 0466  MegaRAID 466 Express Plus RAID Controller
+		101e 0467  MegaRAID 467 Enterprise 1500 RAID Controller
+		101e 0490  MegaRAID 490 Express 300 RAID Controller
+		101e 0762  MegaRAID 762 Express RAID Controller
 		101e 09a0  PowerEdge Expandable RAID Controller 2/SC
 		1028 0467  PowerEdge Expandable RAID Controller 2/DC
 		1028 1111  PowerEdge Expandable RAID Controller 2/SC
-		103c 03a2  MegaRaid
-		103c 10c6  MegaRaid 438
-		103c 10c7  MegaRaid T5
-		103c 10cc  MegaRaid
-		1111 1111  MegaRaid 466
-		113c 03a2  MegaRaid
+		103c 03a2  MegaRAID
+		103c 10c6  MegaRAID 438, HP NetRAID-3Si
+		103c 10c7  MegaRAID T5, Integrated HP NetRAID
+		103c 10cc  MegaRAID, Integrated HP NetRAID
+		103c 10cd  HP NetRAID-1Si
+		105a 0000  SuperTrak
+		105a 2168  SuperTrak Pro
+		105a 5168  SuperTrak66/100
+		1111 1111  MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC
+		1111 1112  PowerEdge Expandable RAID Controller 2/SC
+		113c 03a2  MegaRAID
+	1962  80960RM [i960RM Microprocessor]
+		105a 0000  SuperTrak SX6000 I2O CPU
 	1a21  82840 840 (Carmel) Chipset Host Bridge (Hub A)
 	1a23  82840 840 (Carmel) Chipset AGP Bridge
 	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
@@ -5075,6 +6154,7 @@
 	2412  82801AA USB
 	2413  82801AA SMBus
 	2415  82801AA AC'97 Audio
+		1028 0095  Precision Workstation 220 Integrated Digital Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
 		11d4 5340  SoundMAX Integrated Digital Audio
@@ -5091,16 +6171,57 @@
 	2428  82801AB PCI Bridge
 	2440  82801BA ISA Bridge (LPC)
 	2442  82801BA/BAM USB (Hub #1)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2443  82801BA/BAM SMBus
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2444  82801BA/BAM USB (Hub #2)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2445  82801BA/BAM AC'97 Audio
+		104d 80df  Vaio PCG-FX403
+		1462 3370  STAC9721 AC
+		147b 0507  TH7II-RAID
 	2446  82801BA/BAM AC'97 Modem
+		104d 80df  Vaio PCG-FX403
 	2448  82801BAM/CAM PCI Bridge
 	2449  82801BA/BAM/CA/CAM Ethernet Controller
+		0e11 0012  EtherExpress PRO/100 VM
+		0e11 0091  EtherExpress PRO/100 VE
+		1014 01ce  EtherExpress PRO/100 VE
+		1014 01dc  EtherExpress PRO/100 VE
+		1014 01eb  EtherExpress PRO/100 VE
+		1014 01ec  EtherExpress PRO/100 VE
+		1014 0202  EtherExpress PRO/100 VE
+		1014 0205  EtherExpress PRO/100 VE
+		1014 0217  EtherExpress PRO/100 VE
+		1014 0234  EtherExpress PRO/100 VE
+		1014 023d  EtherExpress PRO/100 VE
+		1014 0244  EtherExpress PRO/100 VE
+		1014 0245  EtherExpress PRO/100 VE
+		109f 315d  EtherExpress PRO/100 VE
+		109f 3181  EtherExpress PRO/100 VE
+		1186 7801  EtherExpress PRO/100 VE
+		144d 2602  HomePNA 1M CNR
+		8086 3010  EtherExpress PRO/100 VE
+		8086 3011  EtherExpress PRO/100 VM
+		8086 3012  82562EH based Phoneline
+		8086 3013  EtherExpress PRO/100 VE
+		8086 3014  EtherExpress PRO/100 VM
+		8086 3015  82562EH based Phoneline
+		8086 3016  EtherExpress PRO/100 P Mobile Combo
+		8086 3017  EtherExpress PRO/100 P Mobile
+		8086 3018  EtherExpress PRO/100
 	244a  82801BAM IDE U100
+		1025 1016  Travelmate 612TX
+		104d 80df  Vaio PCG-FX403
 	244b  82801BA IDE U100
+		1043 8027  TUSL2-C Mainboard
+		147b 0507  TH7II-RAID
 	244c  82801BAM ISA Bridge (LPC)
-	244e  82801BA/CA PCI Bridge
+	244e  82801BA/CA/DB PCI Bridge
 	2450  82801E ISA Bridge (LPC)
 	2452  82801E USB
 	2453  82801E SMBus
@@ -5110,28 +6231,72 @@
 	245e  82801E PCI Bridge
 	2480  82801CA ISA Bridge (LPC)
 	2482  82801CA/CAM USB (Hub #1)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2483  82801CA/CAM SMBus
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2484  82801CA/CAM USB (Hub #2)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2485  82801CA/CAM AC'97 Audio
+		1014 0222  ThinkPad T23 (2647-4MG)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2486  82801CA/CAM AC'97 Modem
+		1014 0223  ThinkPad A30p (2653-64G)
+		1014 0503  ThinkPad R31 2656BBG
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		134d 4c21  Dell Inspiron 2100 internal modem
 	2487  82801CA/CAM USB (Hub #3)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248a  82801CAM IDE U100
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248b  82801CA IDE U100
 	248c  82801CAM ISA Bridge (LPC)
+	24c0  82801DB ISA Bridge (LPC)
+	24c2  82801DB USB (Hub #1)
+	24c3  82801DB SMBus
+	24c4  82801DB USB (Hub #2)
+	24c5  82801DB AC'97 Audio
+	24c6  82801DB AC'97 Modem
+	24c7  82801DB USB (Hub #3)
 	24cb  82801DB ICH4 IDE
+	24cd  82801DB USB EHCI Controller
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1028 0095  Precision Workstation 220 Chipset
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	250b  82820 820 (Camino) Chipset Host Bridge
-	250f  82820 820 (Camino) Chipset PCI to AGP Bridge
+	250f  82820 820 (Camino) Chipset AGP Bridge
 	2520  82805AA MTH Memory Translator Hub
 	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
-	2531  82850 860 (Wombat) Chipset Host Bridge (MCH)
+		147b 0507  TH7II-RAID
+	2531  82860 860 (Wombat) Chipset Host Bridge (MCH)
 	2532  82850 850 (Tehama) Chipset AGP Bridge
 	2533  82860 860 (Wombat) Chipset AGP Bridge
+	2534  82860 860 (Wombat) Chipset PCI Bridge
+	2540  e7500 [Plumas] DRAM Controller
+	2541  e7500 [Plumas] DRAM Controller Error Reporting
+	2543  e7500 [Plumas] HI_B Virtual PCI Bridge (F0)
+	2544  e7500 [Plumas] HI_B Virtual PCI Bridge (F1)
+	2545  e7500 [Plumas] HI_C Virtual PCI Bridge (F0)
+	2546  e7500 [Plumas] HI_C Virtual PCI Bridge (F1)
+	2547  e7500 [Plumas] HI_D Virtual PCI Bridge (F0)
+	2548  e7500 [Plumas] HI_D Virtual PCI Bridge (F1)
+	2560  82845G/GL [Brookdale-G] Chipset Host Bridge
+	2561  82845G/GL [Brookdale-G] Chipset AGP Bridge
+	2562  82845G/GL [Brookdale-G] Chipset Integrated Graphics Device
 	3092  Integrated RAID
+	3575  82830 830 Chipset Host Bridge
+		1014 021d  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	3576  82830 830 Chipset AGP Bridge
+	3577  82830 CGC [Chipset Graphics Controller]
+	3578  82830 830 Chipset Host Bridge
 	5200  EtherExpress PRO/100 Intelligent Server
 	5201  EtherExpress PRO/100 Intelligent Server
 		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
@@ -5141,30 +6306,34 @@
 	7020  82371SB PIIX3 USB [Natoma/Triton II]
 	7030  430VX - 82437VX TVX [Triton VX]
 	7100  430TX - 82439TX MTXC
-	7110  82371AB PIIX4 ISA
-	7111  82371AB PIIX4 IDE
-	7112  82371AB PIIX4 USB
-	7113  82371AB PIIX4 ACPI
+	7110  82371AB/EB/MB PIIX4 ISA
+	7111  82371AB/EB/MB PIIX4 IDE
+	7112  82371AB/EB/MB PIIX4 USB
+	7113  82371AB/EB/MB PIIX4 ACPI
 	7120  82810 GMCH [Graphics Memory Controller Hub]
 	7121  82810 CGC [Chipset Graphics Controller]
-	7122  82810-DC100 GMCH [Graphics Memory Controller Hub]
-	7123  82810-DC100 CGC [Chipset Graphics Controller]
-	7124  82810E GMCH [Graphics Memory Controller Hub]
-	7125  82810E CGC [Chipset Graphics Controller]
-	7126  82810 810 Chipset Host Bridge and Memory Controller Hub
+	7122  82810 DC-100 GMCH [Graphics Memory Controller Hub]
+	7123  82810 DC-100 CGC [Chipset Graphics Controller]
+	7124  82810E DC-133 GMCH [Graphics Memory Controller Hub]
+	7125  82810E DC-133 CGC [Chipset Graphics Controller]
+	7126  82810 DC-133 System and Graphics Controller
+	7128  82810-M DC-100 System and Graphics Controller
+	712a  82810-M DC-133 System and Graphics Controller
 	7180  440LX/EX - 82443LX/EX Host bridge
 	7181  440LX/EX - 82443LX/EX AGP bridge
-	7190  440BX/ZX - 82443BX/ZX Host bridge
+	7190  440BX/ZX/DX - 82443BX/ZX/DX Host bridge
 		0e11 0500  Armada 1750 Laptop System Chipset
-	7191  440BX/ZX - 82443BX/ZX AGP bridge
-	7192  440BX/ZX - 82443BX/ZX Host bridge (AGP disabled)
+		1179 0001  Toshiba Tecra 8100 Laptop System Chipset
+	7191  440BX/ZX/DX - 82443BX/ZX/DX AGP bridge
+	7192  440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled)
 		0e11 0460  Armada 1700 Laptop System Chipset
-	7194  82440MX I/O Controller
+	7194  82440MX Host Bridge
 	7195  82440MX AC'97 Audio Controller
 		10cf 1099  QSound_SigmaTel Stac97 PCI Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
-	7198  82440MX PCI to ISA Bridge
+	7196  82440MX AC'97 Modem Controller
+	7198  82440MX ISA Bridge
 	7199  82440MX EIDE Controller
 	719a  82440MX USB Universal Host Controller
 	719b  82440MX Power Management Controller
@@ -5176,7 +6345,12 @@
 	7602  82372FB PIIX5 USB
 	7603  82372FB PIIX5 SMBus
 	7800  i740
+		003d 0008  Starfighter AGP
+		003d 000b  Starfighter AGP
 		1092 0100  Stealth II G460
+		10b4 201a  Lightspeed 740
+		10b4 202f  Lightspeed 740
+		8086 0000  Terminator 2x/i
 		8086 0100  Intel740 Graphics Accelerator
 	84c4  450KX/GX [Orion] - 82454KX/GX PCI bridge
 	84c5  450KX/GX [Orion] - 82453KX/GX Memory controller
@@ -5184,13 +6358,20 @@
 	84cb  450NX - 82454NX/84460GX PCI Expander Bridge
 	84e0  460GX - 84460GX System Address Controller (SAC)
 	84e1  460GX - 84460GX System Data Controller (SDC)
-	84e2  460GX - 84460GX AGP Bridge (GXB)
+	84e2  460GX - 84460GX AGP Bridge (GXB function 2)
 	84e3  460GX - 84460GX Memory Address Controller (MAC)
 	84e4  460GX - 84460GX Memory Data Controller (MDC)
+	84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)
+	84ea  460GX - 84460GX AGP Bridge (GXB function 1)
 	9621  Integrated RAID
 	9622  Integrated RAID
 	9641  Integrated RAID
 	96a1  Integrated RAID
+	b152  21152 PCI-to-PCI Bridge
+# observed, and documented in Intel revision note; new mask of 1011:0026
+	b154  21154 PCI-to-PCI Bridge
+	b555  21555 Non transparent PCI-to-PCI Bridge
+		e4bf 1000  CC8-1-BLUES
 	ffff  450NX/GX [Orion] - 82453KX/GX Memory controller [BUG]
 8800  Trigem Computer Inc.
 	2008  Video assistent component
@@ -5214,12 +6395,13 @@
 	5278  AIC-7852
 	5375  AIC-755x
 	5378  AIC-7850
-	5475  AIC-2930
+	5475  AIC-755x
 	5478  AIC-7850
 	5575  AVA-2930
 	5578  AIC-7855
+	5647  ANA-7711 TCP Offload Engine
 	5675  AIC-755x
-	5678  AIC-7850
+	5678  AIC-7856
 	5775  AIC-755x
 	5778  AIC-7850
 	5800  AIC-5800
@@ -5227,37 +6409,38 @@
 	5905  ANA-5910A/5930A/5940A ATM Adapter
 	6038  AIC-3860
 	6075  AIC-1480 / APA-1480
+		9004 7560  AIC-1480 / APA-1480 Cardbus
 	6078  AIC-7860
 	6178  AIC-7861
 		9004 7861  AHA-2940AU Single
 	6278  AIC-7860
 	6378  AIC-7860
-	6478  AIC-786
+	6478  AIC-786x
 	6578  AIC-786x
-	6678  AIC-786
+	6678  AIC-786x
 	6778  AIC-786x
 	6915  ANA620xx/ANA69011A
 		9004 0008  ANA69011A/TX 10/100
 		9004 0009  ANA69011A/TX 10/100
 		9004 0010  ANA62022 2-port 10/100
 		9004 0018  ANA62044 4-port 10/100
+		9004 0019  ANA62044 4-port 10/100
 		9004 0020  ANA62022 2-port 10/100
 		9004 0028  ANA69011A/TX 10/100
 		9004 8008  ANA69011A/TX 64 bit 10/100
 		9004 8009  ANA69011A/TX 64 bit 10/100
 		9004 8010  ANA62022 2-port 64 bit 10/100
 		9004 8018  ANA62044 4-port 64 bit 10/100
+		9004 8019  ANA62044 4-port 64 bit 10/100
 		9004 8020  ANA62022 2-port 64 bit 10/100
 		9004 8028  ANA69011A/TX 64 bit 10/100
 	7078  AHA-294x / AIC-7870
-	7178  AHA-294x / AIC-7871
-	7278  AHA-3940 / AIC-7872
+	7178  AHA-2940/2940W / AIC-7871
+	7278  AHA-3940/3940W / AIC-7872
 	7378  AHA-3985 / AIC-7873
-	7478  AHA-2944 / AIC-7874
-# DJ: Where did the 3rd number come from?
-	7578  AHA-3944 / AHA-3944W / 7875
-# DJ: Where did the 3rd number come from?
-	7678  AHA-4944W/UW / 7876
+	7478  AHA-2944/2944W / AIC-7874
+	7578  AHA-3944/3944W / AIC-7875
+	7678  AHA-4944W/UW / AIC-7876
 	7778  AIC-787x
 	7810  AIC-7810
 	7815  AIC-7815 RAID+Memory Controller IC
@@ -5278,49 +6461,71 @@
 	7893  AIC-789x
 	7894  AIC-789x
 	7895  AHA-2940U/UW / AHA-39xx / AIC-7895
+		9004 7890  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7891  AHA-2940U/2940UW Dual
+		9004 7892  AHA-3940AU/AUW/AUWD/UWD
+		9004 7894  AHA-3944AUWD
 		9004 7895  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7896  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7897  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
 	7896  AIC-789x
 	7897  AIC-789x
 	8078  AIC-7880U
 		9004 7880  AIC-7880P Ultra/Ultra Wide SCSI Chipset
-	8178  AIC-7881U
+	8178  AHA-2940U/UW/D / AIC-7881U
 		9004 7881  AHA-2940UW SCSI Host Adapter
-	8278  AHA-3940U/UW / AIC-7882U
+	8278  AHA-3940U/UW/UWD / AIC-7882U
 	8378  AHA-3940U/UW / AIC-7883U
-	8478  AHA-294x / AIC-7884U
-	8578  AHA-3944U / AHA-3944UWD / 7885
-	8678  AHA-4944UW / 7886
-	8778  AIC-788x
+	8478  AHA-2944UW / AIC-7884U
+	8578  AHA-3944U/UWD / AIC-7885
+	8678  AHA-4944UW / AIC-7886
+	8778  AHA-2940UW Pro / AIC-788x
 		9004 7887  2940UW Pro Ultra-Wide SCSI Controller
-	8878  7888
+	8878  AHA-2930UW / AIC-7888
+		9004 7888  AHA-2930UW SCSI Controller
 	8b78  ABA-1030
 	ec78  AHA-4944W/UW
 9005  Adaptec
-	0010  AHA-2940U2/W
-	0011  2930U2
+	0010  AHA-2940U2/U2W
+		9005 2180  AHA-2940U2 SCSI Controller
+		9005 8100  AHA-2940U2B SCSI Controller
+		9005 a180  AHA-2940U2W SCSI Controller
+		9005 e100  AHA-2950U2B SCSI Controller
+	0011  AHA-2930U2
 	0013  78902
 		9005 0003  AAA-131U2 Array1000 1 Channel RAID Controller
-	001f  AHA-2940U2/W / 7890
+	001f  AHA-2940U2/U2W / 7890/7891
 		9005 000f  2940U2W SCSI Controller
 		9005 a180  2940U2W SCSI Controller
 	0020  AIC-7890
 	002f  AIC-7890
 	0030  AIC-7890
 	003f  AIC-7890
-	0050  3940U2
-	0051  3950U2D
+	0050  AHA-3940U2x/395U2x
+		9005 f500  AHA-3950U2B
+	0051  AHA-3950U2D
+		9005 b500  AHA-3950U2D
 	0053  AIC-7896 SCSI Controller
 		9005 ffff  AIC-7896 SCSI Controller mainboard implementation
-	005f  7896
-	0080  7892A
-	0081  7892B
-	0083  7892D
-	008f  7892P
-	00c0  7899A
-	00c1  7899B
-	00c3  7899D
+	005f  AIC-7896U2/7897U2
+	0080  AIC-7892A U160/m
+		0e11 e2a0  Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter
+		9005 62a0  29160N Ultra160 SCSI Controller
+		9005 e220  29160LP Low Profile Ultra160 SCSI Controller
+		9005 e2a0  29160 Ultra160 SCSI Controller
+	0081  AIC-7892B U160/m
+		9005 62a1  19160 Ultra160 SCSI Controller
+	0083  AIC-7892D U160/m
+	008f  AIC-7892P U160/m
+	00c0  AHA-3960D / AIC-7899A U160/m
+		0e11 f620  Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter
+		9005 f620  AHA-3960D U160/m
+	00c1  AIC-7899B U160/m
+	00c3  AIC-7899D U160/m
 	00c5  RAID subsystem HBA
-	00cf  7899P
+	00cf  AIC-7899P U160/m
+	0285  AAC-RAID
+		1028 0287  PowerEdge Expandable RAID Controller 320/DC
 907f  Atronics
 	2015  IDE-2015PL
 919a  Gigapixel Corp
@@ -5328,6 +6533,9 @@
 	6565  6565
 9699  Omni Media Technology Inc
 	6565  6565
+9710  NetMos Technology
+	9815  VScom 021H-EP2 2 port parallel adaptor
+	9835  222N-2 I/O Card (2S+1P)
 a0a0  AOPEN Inc.
 a0f1  UNISYS Corporation
 a200  NEC Corporation
@@ -5347,16 +6555,33 @@
 cccc  Catapult Communications
 d4d4  Dy4 Systems Inc
 	0601  PCI Mezzanine Card
+d531  I+ME ACTIA GmbH
 d84d  Exsys
+dead  Indigita Corporation
 e000  Winbond
 	e000  W89C940
 e159  Tiger Jet Network Inc.
 	0001  Model 300 128k
 		0059 0001  128k ISDN-S/T Adapter
 		0059 0003  128k ISDN-U Adapter
+	0002  Tiger100APC ISDN chipset
 e4bf  EKF Elektronik GmbH
 ea01  Eagle Technology
 eabb  Aashima Technology B.V.
+eace  Endace Measurement Systems, Ltd
+	3100  DAG 3.10 OC-3/OC-12
+	3200  DAG 3.2x OC-3/OC-12
+	320e  DAG 3.2E Fast Ethernet
+	340e  DAG 3.4E Fast Ethernet
+	341e  DAG 3.41E Fast Ethernet
+	3500  DAG 3.5 OC-3/OC-12
+	351c  DAG 3.5ECM Fast Ethernet
+	4100  DAG 4.10 OC-48
+	4110  DAG 4.11 OC-48
+	4220  DAG 4.2 OC-48
+	422e  DAG 4.2E Dual Gigabit Ethernet
+ec80  Belkin Corporation
+	ec00  F5D6000
 ecc0  Echo Corporation
 edd8  ARK Logic Inc
 	a091  1000PV [Stingray]
@@ -5364,6 +6589,7 @@
 	a0a1  2000MT
 	a0a9  2000MI
 fa57  Fast Search & Transfer ASA
+febd  Ultraview Corp.
 feda  Epigram Inc
 fffe  VMWare Inc
 	0710  Virtual SVGA
diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c	Tue Aug 27 12:27:51 2002
+++ b/drivers/pci/proc.c	Tue Aug 27 12:27:51 2002
@@ -378,7 +378,7 @@
 	return off ? 0 : sprintf(buf,"%u\n",pci_dev->irq);
 }
 
-static DEVICE_ATTR(irq,"irq",S_IRUGO,pci_show_irq,NULL);
+static DEVICE_ATTR(irq,S_IRUGO,pci_show_irq,NULL);
 
 static ssize_t pci_show_resources(struct device * dev, char * buf, size_t count, loff_t off)
 {
@@ -402,7 +402,7 @@
 	return (str - buf);
 }
 
-static DEVICE_ATTR(resource,"resource",S_IRUGO,pci_show_resources,NULL);
+static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
 
 int pci_proc_attach_device(struct pci_dev *dev)
 {
diff -Nru a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
--- a/drivers/pnp/pnpbios_core.c	Tue Aug 27 12:27:56 2002
+++ b/drivers/pnp/pnpbios_core.c	Tue Aug 27 12:27:57 2002
@@ -90,7 +90,8 @@
 static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;
 
 /* The PnP BIOS entries in the GDT */
-#define PNP_GDT    (0x0060)
+#define PNP_GDT    (GDT_ENTRY_PNPBIOS_BASE * 8)
+
 #define PNP_CS32   (PNP_GDT+0x00)	/* segment for calling fn */
 #define PNP_CS16   (PNP_GDT+0x08)	/* code segment for BIOS */
 #define PNP_DS     (PNP_GDT+0x10)	/* data segment for BIOS */
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/s390/block/dasd.c	Tue Aug 27 12:28:05 2002
@@ -290,11 +290,9 @@
 	gdp = dasd_gendisk_from_devindex(devmap->devindex);
 	if (gdp == NULL)
 		return -ENODEV;
-	minor = devmap->devindex % DASD_PER_MAJOR;
-
 	/* Set kdev and the device name. */
-	device->kdev = mk_kdev(gdp->major, minor << DASD_PARTN_BITS);
-	dasd_device_name(device->name, minor, 0, gdp);
+	device->kdev = mk_kdev(gdp->major, gdp->first_minor);
+	strcpy(device->name, gdp->major_name);
 
 	/* Find a discipline for the device. */
 	rc = dasd_find_disc(device);
@@ -304,7 +302,7 @@
 	/* Add a proc directory and the dasd device entry to devfs. */
 	sprintf(buffer, "%04x", device->devinfo.devno);
 	dir = devfs_mk_dir(dasd_devfs_handle, buffer, device);
-	gdp->de_arr[minor(device->kdev) >> DASD_PARTN_BITS] = dir;
+	gdp->de_arr[0] = dir;
 	if (devmap->features & DASD_FEATURE_READONLY)
 		devfs_perm = S_IFBLK | S_IRUSR;
 	else
@@ -324,19 +322,13 @@
 static inline void
 dasd_state_known_to_new(dasd_device_t * device)
 {
-	struct gendisk *gdp;
-	dasd_devmap_t *devmap;
-	int minor;
-
-	devmap = dasd_devmap_from_devno(device->devinfo.devno);
-	gdp = dasd_gendisk_from_devindex(devmap->devindex);
+	dasd_devmap_t *devmap = dasd_devmap_from_devno(device->devinfo.devno);
+	struct gendisk *gdp = dasd_gendisk_from_devindex(devmap->devindex);
 	if (gdp == NULL)
 		return;
-	minor = devmap->devindex % DASD_PER_MAJOR;
-
 	/* Remove device entry and devfs directory. */
 	devfs_unregister(device->devfs_entry);
-	devfs_unregister(gdp->de_arr[minor]);
+	devfs_unregister(gdp->de_arr[0]);
 
 	/* Forget the discipline information. */
 	device->discipline = NULL;
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/s390/block/dasd_genhd.c	Tue Aug 27 12:28:08 2002
@@ -32,7 +32,12 @@
 
 struct major_info {
 	struct list_head list;
-	struct gendisk gendisk;	/* actually contains the major number */
+	int major;
+	struct gendisk disks[DASD_PER_MAJOR];
+	devfs_handle_t de_arr[DASD_PER_MAJOR];
+	char flags[DASD_PER_MAJOR];
+	char names[DASD_PER_MAJOR * 8];
+	struct hd_struct part[1<<MINORBITS];
 };
 
 /*
@@ -64,24 +69,17 @@
 dasd_register_major(int major)
 {
 	struct major_info *mi;
-	struct hd_struct *gd_part;
-	devfs_handle_t *gd_de_arr;
-	char *gd_flags;
 	int new_major, rc;
+	struct list_head *l;
+	int index;
+	int i;
 
 	rc = 0;
 	/* Allocate major info structure. */
 	mi = kmalloc(sizeof(struct major_info), GFP_KERNEL);
 
-	/* Allocate gendisk arrays. */
-	gd_de_arr = kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t),
-			    GFP_KERNEL);
-	gd_flags = kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
-	gd_part = kmalloc(sizeof (struct hd_struct) << MINORBITS, GFP_ATOMIC);
-
 	/* Check if one of the allocations failed. */
-	if (mi == NULL || gd_de_arr == NULL || gd_flags == NULL ||
-	    gd_part == NULL) {
+	if (mi == NULL) {
 		MESSAGE(KERN_WARNING, "%s",
 			"Cannot get memory to allocate another "
 			"major number");
@@ -99,41 +97,48 @@
 	}
 	if (major != 0)
 		new_major = major;
-
+	
 	/* Initialize major info structure. */
 	memset(mi, 0, sizeof(struct major_info));
-	mi->gendisk.major = new_major;
-	mi->gendisk.major_name = "dasd";
-	mi->gendisk.minor_shift = DASD_PARTN_BITS;
-	mi->gendisk.nr_real = DASD_PER_MAJOR;
-	mi->gendisk.fops = &dasd_device_operations;
-	mi->gendisk.de_arr = gd_de_arr;
-	mi->gendisk.flags = gd_flags;
-	mi->gendisk.part = gd_part;
-
-	/* Initialize the gendisk arrays. */
-	memset(gd_de_arr, 0, DASD_PER_MAJOR * sizeof(devfs_handle_t));
-	memset(gd_flags, 0, DASD_PER_MAJOR * sizeof (char));
-	memset(gd_part, 0, sizeof (struct hd_struct) << MINORBITS);
+	mi->major = new_major;
+	for (i = 0; i < DASD_PER_MAJOR; i++) {
+		struct gendisk *disk = mi->disks + i;
+		disk->major = new_major;
+		disk->first_minor = i << DASD_PARTN_BITS;
+		disk->minor_shift = DASD_PARTN_BITS;
+		disk->nr_real = 1;
+		disk->fops = &dasd_device_operations;
+		disk->de_arr = mi->de_arr + i;
+		disk->flags = mi->flags + i;
+		disk->part = mi->part + (i << DASD_PARTN_BITS);
+	}
 
 	/* Setup block device pointers for the new major. */
 	blk_dev[new_major].queue = dasd_get_queue;
 
-	/* Insert the new major info structure into dasd_major_info list. */
 	spin_lock(&dasd_major_lock);
+	index = 0;
+	list_for_each(l, &dasd_major_info)
+		index += DASD_PER_MAJOR;
+	for (i = 0; i < DASD_PER_MAJOR; i++, index++) {
+		char *name = mi->names + i * 8;
+		mi->disks[i].major_name = name;
+		sprintf(name, "dasd");
+		name += 4;
+		if (index > 701)
+			*name++ = 'a' + (((index - 702) / 676) % 26);
+		if (index > 25)
+			*name++ = 'a' + (((index - 26) / 26) % 26);
+		sprintf(name, "%c", 'a' + (index % 26));
+	}
 	list_add_tail(&mi->list, &dasd_major_info);
 	spin_unlock(&dasd_major_lock);
 
-	/* Make the gendisk known. */
-	add_gendisk(&mi->gendisk);
 	return 0;
 
 	/* Something failed. Do the cleanup and return rc. */
 out_error:
 	/* We rely on kfree to do the != NULL check. */
-	kfree(gd_part);
-	kfree(gd_flags);
-	kfree(gd_de_arr);
 	kfree(mi);
 	return rc;
 }
@@ -146,16 +151,13 @@
 	if (mi == NULL)
 		return;
 
-	/* Remove gendisk information. */
-	del_gendisk(&mi->gendisk);
-
 	/* Delete the major info from dasd_major_info. */
 	spin_lock(&dasd_major_lock);
 	list_del(&mi->list);
 	spin_unlock(&dasd_major_lock);
 
 	/* Clear block device pointers. */
-	major = mi->gendisk.major;
+	major = mi->major;
 	blk_dev[major].queue = NULL;
 	blk_clear(major);
 
@@ -166,9 +168,6 @@
 			major, rc);
 
 	/* Free memory. */
-	kfree(mi->gendisk.part);
-	kfree(mi->gendisk.flags);
-	kfree(mi->gendisk.de_arr);
 	kfree(mi);
 }
 
@@ -189,19 +188,19 @@
 /*
  * Return pointer to gendisk structure by kdev.
  */
-struct gendisk *
-dasd_gendisk_from_major(int major)
+static struct gendisk *dasd_gendisk_by_dev(kdev_t dev)
 {
 	struct list_head *l;
 	struct major_info *mi;
 	struct gendisk *gdp;
+	int major = major(dev);
 
 	spin_lock(&dasd_major_lock);
 	gdp = NULL;
 	list_for_each(l, &dasd_major_info) {
 		mi = list_entry(l, struct major_info, list);
-		if (mi->gendisk.major == major) {
-			gdp = &mi->gendisk;
+		if (mi->major == major) {
+			gdp = &mi->disks[minor(dev) >> DASD_PARTN_BITS];
 			break;
 		}
 	}
@@ -224,7 +223,7 @@
 	list_for_each(l, &dasd_major_info) {
 		mi = list_entry(l, struct major_info, list);
 		if (devindex < DASD_PER_MAJOR) {
-			gdp = &mi->gendisk;
+			gdp = &mi->disks[devindex];
 			break;
 		}
 		devindex -= DASD_PER_MAJOR;
@@ -247,7 +246,7 @@
 	devindex = 0;
 	list_for_each(l, &dasd_major_info) {
 		mi = list_entry(l, struct major_info, list);
-		if (mi->gendisk.major == major) {
+		if (mi->major == major) {
 			rc = devindex;
 			break;
 		}
@@ -257,62 +256,19 @@
 	return rc;
 }
 
-
-/*
- * This one is needed for naming 18000+ possible dasd devices.
- *   dasda - dasdz : 26 devices
- *   dasdaa - dasdzz : 676 devices, added up = 702
- *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
- * This function is called from the partition detection code (see disk_name)
- * via the genhd_dasd_name hook. As mentioned in partition/check.c this
- * is ugly...
- */
-int
-dasd_device_name(char *str, int index, int partition, struct gendisk *hd)
-{
-	struct list_head *l;
-	int len, found;
-
-	/* Check if this is on of our gendisk structures. */
-	found = 0;
-	spin_lock(&dasd_major_lock);
-	list_for_each(l, &dasd_major_info) {
-		struct major_info *mi;
-		mi = list_entry(l, struct major_info, list);
-		if (&mi->gendisk == hd) {
-			found = 1;
-			break;
-		}
-		index += DASD_PER_MAJOR;
-	}
-	spin_unlock(&dasd_major_lock);
-	if (!found)
-		/* Not one of our structures. Can't be a dasd. */
-		return -EINVAL;
-	len = sprintf(str, "dasd");
-	if (index > 25) {
-		if (index > 701)
-			len += sprintf(str + len, "%c",
-				       'a' + (((index - 702) / 676) % 26));
-		len += sprintf(str + len, "%c",
-			       'a' + (((index - 26) / 26) % 26));
-	}
-	len += sprintf(str + len, "%c", 'a' + (index % 26));
-
-	if (partition > DASD_PARTN_MASK)
-		return -EINVAL;
-	if (partition)
-		len += sprintf(str + len, "%d", partition);
-	return 0;
-}
-
 /*
  * Register disk to genhd. This will trigger a partition detection.
  */
 void
 dasd_setup_partitions(dasd_device_t * device)
 {
-	grok_partitions(device->kdev, device->blocks << device->s2b_shift);
+	struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
+	if (disk == NULL)
+		return;
+	add_gendisk(disk);
+	register_disk(disk, mk_kdev(disk->major, disk->first_minor),
+			1<<disk->minor_shift, disk->fops,
+			device->blocks << device->s2b_shift);
 }
 
 /*
@@ -322,11 +278,10 @@
 void
 dasd_destroy_partitions(dasd_device_t * device)
 {
-	struct gendisk *gdp;
+	struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
 	int minor, i;
 
-	gdp = dasd_gendisk_from_major(major(device->kdev));
-	if (gdp == NULL)
+	if (disk == NULL)
 		return;
 
 	wipe_partitions(device->kdev);
@@ -336,13 +291,10 @@
 	 * but the 1 as third parameter makes it do an unregister...
 	 * FIXME: there must be a better way to get rid of the devfs entries
 	 */
-	devfs_register_partitions(gdp, minor(device->kdev), 1);
+	devfs_register_partitions(disk, minor(device->kdev), 1);
+	del_gendisk(disk);
 }
 
-extern int (*genhd_dasd_name)(char *, int, int, struct gendisk *);
-extern int (*genhd_dasd_ioctl) (struct inode *inp, struct file *filp,
-                                unsigned int no, unsigned long data);
-
 int
 dasd_gendisk_init(void)
 {
@@ -350,25 +302,17 @@
 
 	/* Register to static dasd major 94 */
 	rc = dasd_register_major(DASD_MAJOR);
-	if (rc != 0) {
+	if (rc != 0)
 		MESSAGE(KERN_WARNING,
 			"Couldn't register successfully to "
 			"major no %d", DASD_MAJOR);
-		return rc;
-	}
-	genhd_dasd_name = dasd_device_name;
-        genhd_dasd_ioctl = dasd_ioctl;
-	return 0;
-
+	return rc;
 }
 
 void
 dasd_gendisk_exit(void)
 {
 	struct list_head *l, *n;
-
-	genhd_dasd_ioctl = NULL;
-	genhd_dasd_name = NULL;
 	spin_lock(&dasd_major_lock);
 	list_for_each_safe(l, n, &dasd_major_info)
 		dasd_unregister_major(list_entry(l, struct major_info, list));
diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/s390/block/dasd_int.h	Tue Aug 27 12:28:08 2002
@@ -480,9 +480,7 @@
 void dasd_gendisk_exit(void);
 int  dasd_gendisk_new_major(void);
 int  dasd_gendisk_major_index(int);
-struct gendisk *dasd_gendisk_from_major(int);
 struct gendisk *dasd_gendisk_from_devindex(int);
-int  dasd_device_name(char *, int, int, struct gendisk *);
 void dasd_setup_partitions(dasd_device_t *);
 void dasd_destroy_partitions(dasd_device_t *);
 
diff -Nru a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
--- a/drivers/s390/block/dasd_proc.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/s390/block/dasd_proc.c	Tue Aug 27 12:28:01 2002
@@ -173,12 +173,7 @@
 	minor = devmap->devindex % DASD_PER_MAJOR;
 	len += sprintf(str + len, " at (%3d:%3d)", gdp->major, minor);
 	/* Print device name. */
-	if (device == NULL) {
-		dasd_device_name(buffer, minor, 0, gdp);
-		substr = buffer;
-	} else
-		substr = device->name;
-	len += sprintf(str + len, " is %-7s", substr);
+	len += sprintf(str + len, " is %-7s", gdp->major_name);
 	/* Print devices features. */
 	substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
 	len += sprintf(str + len, "%4s: ", substr);
diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
--- a/drivers/sbus/char/jsflash.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/sbus/char/jsflash.c	Tue Aug 27 12:28:05 2002
@@ -674,10 +674,9 @@
 	return 0;
 }
 
-#ifdef MODULE
 MODULE_LICENSE("GPL");
 
-int init_module(void) {
+static int __init jsflash_init_module(void) {
 	int rc;
 
 	if ((rc = jsflash_init()) == 0) {
@@ -687,7 +686,7 @@
 	return rc;
 }
 
-void cleanup_module(void) {
+static void __exit jsflash_cleanup_module(void) {
 
 	/* for (all probed units) {  } */
 	if (jsf0.busy)
@@ -700,4 +699,6 @@
 		printk("jsfd: cleanup_module failed\n");
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
-#endif
+
+module_init(jsflash_init_module);
+module_exit(jsflash_cleanup_module);
diff -Nru a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
--- a/drivers/sbus/sbus.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/sbus/sbus.c	Tue Aug 27 12:28:02 2002
@@ -16,14 +16,15 @@
 #include <asm/oplib.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
-#ifdef CONFIG_SPARC32
-#include <asm/pcic.h>		/* pcic_present */
-#endif
 
 struct sbus_bus *sbus_root = NULL;
 
 static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };
 
+#ifdef CONFIG_PCI
+extern int pcic_present(void);
+#endif
+
 /* Perhaps when I figure out more about the iommu we'll put a
  * device registration routine here that probe_sbus() calls to
  * setup the iommu for each Sbus.
@@ -336,17 +337,10 @@
 		   (nd = prom_getchild(iommund)) == 0 ||
 		   (nd = prom_searchsiblings(nd, "sbus")) == 0) {
 #ifdef CONFIG_PCI
-#ifdef CONFIG_SPARC32
                         if (!pcic_present()) {
                                 prom_printf("Neither SBUS nor PCI found.\n");
                                 prom_halt();
                         }
-#else
-                        if (!pcibios_present()) {
-                                prom_printf("Neither SBUS nor PCI found.\n");
-                                prom_halt();
-                        }
-#endif
                         return 0;
 #else
 			/* No reason to run further - the data access trap will occur. */
diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/scsi/53c700.c	Tue Aug 27 12:28:01 2002
@@ -1360,6 +1360,8 @@
 }
 
 
+/* The queue lock with interrupts disabled must be held on entry to
+ * this function */
 STATIC int
 NCR_700_start_command(Scsi_Cmnd *SCp)
 {
@@ -1367,17 +1369,13 @@
 		(struct NCR_700_command_slot *)SCp->host_scribble;
 	struct NCR_700_Host_Parameters *hostdata =
 		(struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
-	unsigned long flags;
 	__u16 count = 1;	/* for IDENTIFY message */
 	
-	save_flags(flags);
-	cli();
 	if(hostdata->state != NCR_700_HOST_FREE) {
 		/* keep this inside the lock to close the race window where
 		 * the running command finishes on another CPU while we don't
 		 * change the state to queued on this one */
 		slot->state = NCR_700_SLOT_QUEUED;
-		restore_flags(flags);
 
 		DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n",
 		       SCp->host->host_no, slot->cmnd, slot));
@@ -1443,12 +1441,6 @@
 		       SCp->host, SXFER_REG);
 	NCR_700_writel(slot->temp, SCp->host, TEMP_REG);
 	NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG);
-
-	/* allow interrupts here so that if we're selected we can take
-	 * a selection interrupt.  The script start may not be
-	 * effective in this case, but the selection interrupt will
-	 * save our command in that case */
-	restore_flags(flags);
 
 	return 1;
 }
diff -Nru a/drivers/scsi/README.st b/drivers/scsi/README.st
--- a/drivers/scsi/README.st	Tue Aug 27 12:28:01 2002
+++ b/drivers/scsi/README.st	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Mon Jul 15 16:30:40 2002 by makisara
+Last modified: Fri Jul 26 16:01:39 2002 by makisara
 
 
 BASICS
@@ -105,22 +105,31 @@
 
 BUFFERING
 
-The driver uses tape buffers allocated at run-time when needed and it
-is freed when the device file is closed. One buffer is used for each
-open tape device. 
+The driver tries to do tranfers directly to/from user space. If this
+is not possible, a driver buffer allocated at run-time is used. If
+direct i/o is not possible for the whole transfer, the driver buffer
+is used (i.e., bounce buffers for individual pages are not
+used). Direct i/o can be impossible because of several reasons, e.g.:
+- one or more pages are at addresses not reachable by the HBA
+- the number of pages in the transfer exceeds the number of
+  scatter/gather segments permitted by the HBA
+- one or more pages can't be locked into memory (should not happen in
+  any reasonable situation)
 
-The size of the buffers is always at least one tape block. In fixed
+The size of the driver buffers is always at least one tape block. In fixed
 block mode, the minimum buffer size is defined (in 1024 byte units) by
 ST_FIXED_BUFFER_BLOCKS. With small block size this allows buffering of
 several blocks and using one SCSI read or write to transfer all of the
 blocks. Buffering of data across write calls in fixed block mode is
-allowed if ST_BUFFER_WRITES is non-zero. Buffer allocation uses chunks of
-memory having sizes 2^n * (page size). Because of this the actual
-buffer size may be larger than the minimum allowable buffer size.
+allowed if ST_BUFFER_WRITES is non-zero and direct i/o is not used.
+Buffer allocation uses chunks of memory having sizes 2^n * (page
+size). Because of this the actual buffer size may be larger than the
+minimum allowable buffer size.
 
 Asynchronous writing. Writing the buffer contents to the tape is
 started and the write call returns immediately. The status is checked
-at the next tape operation.
+at the next tape operation. Asynchronous writes are not done with
+direct i/o.
 
 Buffered writes and asynchronous writes may in some rare cases cause
 problems in multivolume operations if there is not enough space on the
@@ -181,9 +190,10 @@
 buffer_kbs=xxx             the buffer size for fixed block mode is set
 			   to xxx kilobytes
 write_threshold_kbs=xxx    the write threshold in kilobytes set to xxx
-max_buffers=xxx            the maximum number of tape buffer set to xxx
 max_sg_segs=xxx		   the maximum number of scatter/gather
 			   segments
+try_direct_io=x		   try direct transfer between user buffer and
+			   tape drive if this is non-zero
 
 Note that if the buffer size is changed but the write threshold is not
 set, the write threshold is set to the new buffer size - 2 kB.
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/scsi/aic7xxx_old.c	Tue Aug 27 12:28:02 2002
@@ -5077,7 +5077,6 @@
         }
         else 
         {
-          sti();
           panic("aic7xxx: AWAITING_MSG for an SCB that does "
                 "not have a waiting message.\n");
         }
@@ -6933,7 +6932,6 @@
 #endif
     if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
     {
-      sti();
       panic("aic7xxx: unrecoverable BRKADRINT.\n");
     }
     if (errno & ILLHADDR)
diff -Nru a/drivers/scsi/cpqfc.Readme b/drivers/scsi/cpqfc.Readme
--- a/drivers/scsi/cpqfc.Readme	Tue Aug 27 12:28:08 2002
+++ b/drivers/scsi/cpqfc.Readme	Tue Aug 27 12:28:08 2002
@@ -7,10 +7,17 @@
 SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() 
 	max of 128k bytes contiguous.
 
+Ver 2.5.3  Aug 01, 2002
+   * fix the passthru ioctl to handle the Scsi_Cmnd->request being a pointer
+Ver 2.5.1  Jul 30, 2002
+   * fix ioctl to pay attention to the specified LUN.
 Ver 2.5.0  Nov 29, 2001
    * eliminated io_request_lock.  This change makes the driver specific
      to the 2.5.x kernels.
    * silenced excessively noisy printks.
+
+Ver 2.1.2  July 23, 2002
+   * initialize DumCmnd->lun in cpqfcTS_ioctl (used in fcFindLoggedInPorts as LUN index)
 
 Ver 2.1.1  Oct 18, 2001
    * reinitialize Cmnd->SCp.sent_command (used to identify commands as
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/scsi/cpqfcTSinit.c	Tue Aug 27 12:27:59 2002
@@ -68,7 +68,7 @@
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.1");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.3");
 MODULE_LICENSE("GPL");
   
 int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
@@ -105,15 +105,16 @@
 #  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
 #endif
 
+static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
+
 /* local function to load our per-HBA (local) data for chip
    registers, FC link state, all FC exchanges, etc.
 
    We allocate space and compute address offsets for the
    most frequently accessed addresses; others (like World Wide
    Name) are not necessary.
-   
 */
-static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
+static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
 {
              
   cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
@@ -226,8 +227,11 @@
   cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
   cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
 
- 
-
+      if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
+		printk(KERN_WARNING 
+			"cpqfc: unable to allocate pool for passthru ioctls.  "
+			"Passthru ioctls disabled.\n");
+      }
 }
 
 
@@ -483,6 +487,75 @@
 }   
 
 
+static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
+{
+	hba->private_data_bits = NULL;
+	hba->private_data_pool = NULL;
+	hba->private_data_bits = 
+		kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
+				BITS_PER_LONG)*sizeof(unsigned long), 
+				GFP_KERNEL);
+	if (hba->private_data_bits == NULL)
+		return -1;
+	memset(hba->private_data_bits, 0,
+		((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
+				BITS_PER_LONG)*sizeof(unsigned long));
+	hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
+			CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
+	if (hba->private_data_pool == NULL) {
+		kfree(hba->private_data_bits);
+		hba->private_data_bits = NULL;
+		return -1;
+	}
+	return 0;
+}
+
+static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
+{
+	kfree(hba->private_data_bits);
+	kfree(hba->private_data_pool);
+}
+
+int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
+{
+	/* Is pointer within our private data pool?
+	   We use Scsi_Request->upper_private_data (normally
+	   reserved for upper layer drivers, e.g. the sg driver)
+	   We check to see if the pointer is ours by looking at
+	   its address.  Is this ok?   Hmm, it occurs to me that
+	   a user app might do something bad by using sg to send
+	   a cpqfc passthrough ioctl with upper_data_private
+	   forged to be somewhere in our pool..., though they'd
+	   normally have to be root already to do this.  */
+
+	return (pointer != NULL && 
+		pointer >= (void *) hba->private_data_pool && 
+		pointer < (void *) hba->private_data_pool + 
+			sizeof(*hba->private_data_pool) * 
+				CPQFC_MAX_PASSTHRU_CMDS);
+}
+
+cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
+{
+	int i;
+
+	do {
+		i = find_first_zero_bit(hba->private_data_bits, 
+			CPQFC_MAX_PASSTHRU_CMDS);
+		if (i == CPQFC_MAX_PASSTHRU_CMDS)
+			return NULL;
+	} while ( test_and_set_bit(i & (BITS_PER_LONG - 1), 
+			hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
+	return &hba->private_data_pool[i];
+}
+
+void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
+{
+	int i;
+	i = data - hba->private_data_pool;
+	clear_bit(i&(BITS_PER_LONG-1), 
+			hba->private_data_bits+(i/BITS_PER_LONG));
+}
 
 int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
 {
@@ -490,35 +563,19 @@
   struct Scsi_Host *HostAdapter = ScsiDev->host;
   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
+  PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
   Scsi_Cmnd DumCmnd;
   int i, j;
   VENDOR_IOCTL_REQ ioc;
   cpqfc_passthru_t *vendor_cmd;
   Scsi_Device *SDpnt;
-  Scsi_Cmnd *ScsiPassThruCmnd;
+  Scsi_Request *ScsiPassThruReq;
+  cpqfc_passthru_private_t *privatedata;
 
   ENTER("cpqfcTS_ioctl ");
-  
-  // can we find an FC device mapping to this SCSI target?
-  DumCmnd.channel = ScsiDev->channel;		// For searching
-  DumCmnd.target  = ScsiDev->id;
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    &DumCmnd, // search Scsi Nexus
-    0,        // DON'T search linked list for FC port id
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( pLoggedInPort == NULL )      // not found!
-  {
-    result = -ENXIO;
-  }
- 
-  else  // we know what FC device to operate on...
-  {
-	// printk("ioctl CMND %d", Cmnd);
-    switch (Cmnd) 
-    {
+
+    // printk("ioctl CMND %d", Cmnd);
+    switch (Cmnd) {
       // Passthrough provides a mechanism to bypass the RAID
       // or other controller and talk directly to the devices
       // (e.g. physical disk drive)
@@ -527,6 +584,10 @@
       case CPQFCTS_SCSI_PASSTHRU:
       {
 	void *buf = NULL; // for kernel space buffer for user data
+
+	/* Check that our pool got allocated ok. */
+	if (cpqfcHBAdata->private_data_pool == NULL)
+		return -ENOMEM;
 	
 	if( !arg)
 	  return -EINVAL;
@@ -549,83 +610,70 @@
 	  if( !buf)
 	    return -ENOMEM;
 	}
+        // Now build a Scsi_Request to pass down...
+        ScsiPassThruReq = scsi_allocate_request(ScsiDev);
+	if (ScsiPassThruReq == NULL) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+	ScsiPassThruReq->upper_private_data = 
+			cpqfc_alloc_private_data(cpqfcHBAdata);
+	if (ScsiPassThruReq->upper_private_data == NULL) {
+		kfree(buf);
+		scsi_release_request(ScsiPassThruReq); // "de-allocate"
+		return -ENOMEM;
+	}
 
-        // Now build a SCSI_CMND to pass down...
-	// This function allocates and sets Scsi_Cmnd ptrs such as
-	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
-
-        // Need data from user?
-	// make sure caller's buffer is in kernel space.
-	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
-	    vendor_cmd->len)
-        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
-		return( -EFAULT);
+	if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
+		if (vendor_cmd->len) { // Need data from user?
+        		if (copy_from_user(buf, vendor_cmd->bufp, 
+						vendor_cmd->len)) {
+				kfree(buf);
+				cpqfc_free_private_data(cpqfcHBAdata, 
+					ScsiPassThruReq->upper_private_data);
+				scsi_release_request(ScsiPassThruReq);
+				return( -EFAULT);
+			}
+		}
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_WRITE; 
+	} else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_READ; 
+	} else
+		// maybe this means a bug in the user app
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_NONE;
 	    
-	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
-        memcpy( &ScsiPassThruCmnd->cmnd[0], 
-		&vendor_cmd->cdb[0], 
-		MAX_COMMAND_SIZE);  
-        // we want to copy all 16 bytes into the FCP-SCSI CDB,
-	// although the actual passthru only uses up to the
-	// first 12.
-	
-	ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB
+	ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
+	ScsiPassThruReq->sr_sense_buffer[0] = 0;
+	ScsiPassThruReq->sr_sense_buffer[2] = 0;
 
-	// Unfortunately, the SCSI command cmnd[] field has only
-	// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
-	// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
-	// However, to avoid a mandatory kernel rebuild, we use the SCp
-	// spare field to store the extra 4 bytes ( ugly :-(
-
-	if( MAX_COMMAND_SIZE < 16)
-	{
-          memcpy( &ScsiPassThruCmnd->SCp.buffers_residual,
-		  &vendor_cmd->cdb[12], 4);
-	}	  
-                  
-	
-        ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!
-	                                        // suppress LUN masking
-	                                        // and VSA logic
-
-	// Use spare fields to copy FCP-SCSI LUN address info...
-        ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
-	ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
-
-        // We copy the scheme used by scsi.c to submit commands
+        // We copy the scheme used by sd.c:spinup_disk() to submit commands
 	// to our own HBA.  We do this in order to stall the
 	// thread calling the IOCTL until it completes, and use
 	// the same "_quecommand" function for synchronizing
 	// FC Link events with our "worker thread".
 
-        {
-          CPQFC_DECLARE_COMPLETION(wait);
-          ScsiPassThruCmnd->request->CPQFC_WAITING = &wait;
-          // eventually gets us to our own _quecommand routine
-          scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], 
-	       buf, 
-	       vendor_cmd->len, 
-	       my_ioctl_done, 
-	       10*HZ, 1);// timeout,retries
-          // Other I/Os can now resume; we wait for our ioctl
-	  // command to complete
-	  CPQFC_WAIT_FOR_COMPLETION(&wait);
-          ScsiPassThruCmnd->request->CPQFC_WAITING = NULL;
-        }
+	privatedata = ScsiPassThruReq->upper_private_data;
+	privatedata->bus = vendor_cmd->bus;
+	privatedata->pdrive = vendor_cmd->pdrive;
 	
-        result = ScsiPassThruCmnd->result;
+        // eventually gets us to our own _quecommand routine
+	scsi_wait_req(ScsiPassThruReq, 
+		&vendor_cmd->cdb[0], buf, vendor_cmd->len, 
+		10*HZ,  // timeout
+		1);	// retries
+        result = ScsiPassThruReq->sr_result;
 
         // copy any sense data back to caller
         if( result != 0 )
 	{
 	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
-		  ScsiPassThruCmnd->sense_buffer, 
-		  sizeof(ScsiPassThruCmnd->sense_buffer)); 
+		  ScsiPassThruReq->sr_sense_buffer, 
+		  sizeof(ScsiPassThruReq->sr_sense_buffer)); 
 	}
-        SDpnt = ScsiPassThruCmnd->device;
-        scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
-        ScsiPassThruCmnd = NULL;
+        SDpnt = ScsiPassThruReq->sr_device;
+	/* upper_private_data is already freed in call_scsi_done() */
+        scsi_release_request(ScsiPassThruReq); // "de-allocate"
+        ScsiPassThruReq = NULL;
 
         // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
         //  (*SDpnt->scsi_request_fn)();
@@ -679,10 +727,21 @@
 
 
       case CPQFC_IOCTL_FC_TARGET_ADDRESS:
-      result = 
-        verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
-      if (result) 
-	break;
+	// can we find an FC device mapping to this SCSI target?
+	DumCmnd.channel = ScsiDev->channel;		// For searching
+	DumCmnd.target  = ScsiDev->id;
+	DumCmnd.lun     = ScsiDev->lun;
+	pLoggedInPort = fcFindLoggedInPort( fcChip,
+		&DumCmnd, // search Scsi Nexus
+		0,        // DON'T search linked list for FC port id
+		NULL,     // DON'T search linked list for FC WWN
+		NULL);    // DON'T care about end of list
+	if (pLoggedInPort == NULL) {
+		result = -ENXIO;
+		break;
+	}
+	result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
+	if (result) break;
  
       put_user(pLoggedInPort->port_id,
 		&((Scsi_FCTargAddress *) arg)->host_port_id);
@@ -709,7 +768,6 @@
       result = -EINVAL;
       break;
     }
-  }
 
   LEAVE("cpqfcTS_ioctl");
   return result;
@@ -747,6 +805,7 @@
     
   }
 
+  cpqfc_free_private_data_pool(cpqfcHBAdata);
   // free Linux resources
   DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
   free_irq( HostAdapter->irq, HostAdapter);
@@ -1527,6 +1586,12 @@
   Scsi_Cmnd * SCpnt;
   Scsi_Device * SDpnt;
 
+// FIXME, cpqfcTS_TargetDeviceReset needs to be fixed 
+// similarly to how the passthrough ioctl was fixed 
+// around the 2.5.30 kernel.  Scsi_Cmnd replaced with 
+// Scsi_Request, etc.
+// For now, so people don't fall into a hole...
+return -ENOTSUPP;
 
   // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
 
@@ -1540,9 +1605,10 @@
   SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
   {
     CPQFC_DECLARE_COMPLETION(wait);
-        
+    
     SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
 
+	// FIXME: this would panic, SCpnt->request would be NULL.
 	SCpnt->request->CPQFC_WAITING = &wait;
 	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
 	CPQFC_WAIT_FOR_COMPLETION(&wait);
@@ -1701,6 +1767,18 @@
   	UCHAR IntStat;
   	printk(" cpqfcTS adapter PCI error detected\n");
   	IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
+	printk("cpqfc: ISR = 0x%02x\n", IntStat);
+	if (IntStat & 0x1) {
+		__u16 pcistat;
+		/* read the pci status register */
+		pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
+		printk("PCI status register is 0x%04x\n", pcistat);
+		if (pcistat & 0x8000) printk("Parity Error Detected.\n");
+		if (pcistat & 0x4000) printk("Signalled System Error\n");
+		if (pcistat & 0x2000) printk("Received Master Abort\n");
+		if (pcistat & 0x1000) printk("Received Target Abort\n");
+		if (pcistat & 0x0800) printk("Signalled Target Abort\n");
+	}
 	if (IntStat & 0x4) printk("(INT)\n");
 	if (IntStat & 0x8) 
 		printk("CRS: PCI master address crossed 46 bit bouandary\n");
diff -Nru a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
--- a/drivers/scsi/cpqfcTSstructs.h	Tue Aug 27 12:28:05 2002
+++ b/drivers/scsi/cpqfcTSstructs.h	Tue Aug 27 12:28:05 2002
@@ -33,7 +33,7 @@
 // don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
 #define VER_MAJOR 2
 #define VER_MINOR 5
-#define VER_SUBMINOR 0
+#define VER_SUBMINOR 3
 
 // Macros for kernel (esp. SMP) tracing using a PCI analyzer
 // (e.g. x86).
@@ -907,9 +907,17 @@
 
 } FC_SCSI_QUE, *PFC_SCSI_QUE;
 
+typedef struct {
+	/* This is tacked on to a Scsi_Request in upper_private_data 
+	   for pasthrough ioctls, as a place to hold data that can't 
+	   be stashed anywhere else in the Scsi_Request.  We differentiate
+	   this from _real_ upper_private_data by checking if the virt addr
+	   is within our special pool.  */
+	ushort bus;
+	ushort pdrive;
+} cpqfc_passthru_private_t;
 
-
-
+#define CPQFC_MAX_PASSTHRU_CMDS 100
 
 #define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
 
@@ -949,6 +957,8 @@
   PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
 
   spinlock_t hba_spinlock;           // held/released by WorkerThread
+  cpqfc_passthru_private_t *private_data_pool;
+  unsigned long *private_data_bits;
 
 } CPQFCHBA;
 
@@ -1404,6 +1414,7 @@
 	__u32 uba:13;		/* upper bus address bits 18-31 */
 	__u32 lba;		/* lower bus address bits 0-31 */
 }; 
+
 
 // J. McCarty's LINK.H
 //
diff -Nru a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c
--- a/drivers/scsi/cpqfcTSworker.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/scsi/cpqfcTSworker.c	Tue Aug 27 12:28:08 2002
@@ -2887,15 +2887,22 @@
 Done:  
 }
 
+extern int is_private_data_of_cpqfc(CPQFCHBA *hba, void * pointer);
+extern void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data);
+
 static void 
 call_scsi_done(Scsi_Cmnd *Cmnd)
 {
-	// We have to reinitialize sent_command here, so the scsi-mid
-	// layer won't re-use the scsi command leaving it set incorrectly.
-	// (incorrectly for our purposes...it's normally unused.)
-
-        if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
-		Cmnd->SCp.sent_command = 0;
+	CPQFCHBA *hba;
+	hba = (CPQFCHBA *) Cmnd->host->hostdata;
+	// Was this command a cpqfc passthru ioctl ?
+        if (Cmnd->sc_request != NULL && Cmnd->host != NULL && 
+		Cmnd->host->hostdata != NULL &&
+		is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->host->hostdata,
+			Cmnd->sc_request->upper_private_data)) {
+		cpqfc_free_private_data(hba, 
+			Cmnd->sc_request->upper_private_data);	
+		Cmnd->sc_request->upper_private_data = NULL;
 		Cmnd->result &= 0xff00ffff;
 		Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
 	}
@@ -3293,6 +3300,7 @@
 }
 #endif
 
+extern cpqfc_passthru_private_t *cpqfc_private(Scsi_Request *sr);
 
 // Search the singly (forward) linked list "fcPorts" looking for 
 // either the SCSI target (if != -1), port_id (if not NULL), 
@@ -3366,8 +3374,18 @@
       {
         // For "passthru" modes, the IOCTL caller is responsible
 	// for setting the FCP-LUN addressing
-	if( !Cmnd->SCp.sent_command ) // NOT passthru?
-	{
+	if (Cmnd->sc_request != NULL && Cmnd->host != NULL && 
+		Cmnd->host->hostdata != NULL &&
+		is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->host->hostdata,
+			Cmnd->sc_request->upper_private_data)) { 
+		/* This is a passthru... */
+		cpqfc_passthru_private_t *pd;
+		pd = Cmnd->sc_request->upper_private_data;
+        	Cmnd->SCp.phase = pd->bus;
+		// Cmnd->SCp.have_data_in = pd->pdrive;
+		Cmnd->SCp.have_data_in = Cmnd->lun;
+	} else {
+	  /* This is not a passthru... */
 	
           // set the FCP-LUN addressing type
           Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
@@ -3380,6 +3398,8 @@
 	  // Report Luns command
           if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
 	  {
+	    if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun))
+		return NULL;
             // we KNOW all the valid LUNs... 0xFF is invalid!
             Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
 	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
@@ -3504,7 +3524,6 @@
 	{
           printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
 		  pLoggedInPort->port_id);
-	  Cmnd->SCp.sent_command = 0;
 	}
 	else
 	  call_scsi_done(Cmnd);
@@ -5232,7 +5251,6 @@
 	sgl = (struct scatterlist*)Cmnd->request_buffer;  
 	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
 		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-        // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
   	if( sg_count <= 3 ) {
 
 	// we need to be careful here that no individual mapping
@@ -5261,7 +5279,6 @@
 	//	printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
   }
 
-  // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
   if( totalsgs <= 3 ) // can (must) use "local" SEST list
   {
     while( bytes_to_go)
@@ -6164,13 +6181,11 @@
       }
       else
       {
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
 //	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
 //			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
       }
     }
     else{
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
       printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
 	Exchanges->fcExchange[ x_ID ].type, 
 	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
@@ -6463,10 +6478,10 @@
       for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
 	*payload++ = Cmnd->cmnd[i];
 
-      if( Cmnd->cmd_len == 16 )
-      {
-        memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
-      }
+      // if( Cmnd->cmd_len == 16 )
+      // {
+      //  memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
+      // }
       payload+= (16 - i);  
 
 		      // FCP_DL is largest number of expected data bytes
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/scsi/esp.c	Tue Aug 27 12:28:08 2002
@@ -467,7 +467,6 @@
 /* Resetting various pieces of the ESP scsi driver chipset/buses. */
 static void esp_reset_dma(struct esp *esp)
 {
-	unsigned long flags;
 	int can_do_burst16, can_do_burst32, can_do_burst64;
 	int can_do_sbus64;
 	u32 tmp;
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Tue Aug 27 12:27:56 2002
+++ b/drivers/scsi/ide-scsi.c	Tue Aug 27 12:28:08 2002
@@ -1,12 +1,37 @@
 /*
- * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
  *
+ * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ */
+
+/*
  * Emulation of a SCSI host adapter for IDE ATAPI devices.
  *
  * With this driver, one can use the Linux SCSI drivers instead of the
  * native IDE ATAPI drivers.
+ *
+ * Ver 0.1   Dec  3 96   Initial version.
+ * Ver 0.2   Jan 26 97   Fixed bug in cleanup_module() and added emulation
+ *                        of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
+ *                        to Janos Farkas for pointing this out.
+ *                       Avoid using bitfields in structures for m68k.
+ *                       Added Scatter/Gather and DMA support.
+ * Ver 0.4   Dec  7 97   Add support for ATAPI PD/CD drives.
+ *                       Use variable timeout for each command.
+ * Ver 0.5   Jan  2 98   Fix previous PD/CD support.
+ *                       Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6   Jan 27 98   Allow disabling of SCSI command translation layer
+ *                        for access through /dev/sg.
+ *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
+ * Ver 0.7   Dec 04 98   Ignore commands where lun != 0 to avoid multiple
+ *                        detection of devices with CONFIG_SCSI_MULTI_LUN
+ * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
+ * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
+ * Ver 0.91  Jun 10 02   Fix "off by one" error in transforms
  */
 
+#define IDESCSI_VERSION "0.9"
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -18,23 +43,40 @@
 #include <linux/hdreg.h>
 #include <linux/slab.h>
 #include <linux/ide.h>
-#include <linux/atapi.h>
 
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
-#include <scsi/sg.h>
-
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
+#include <scsi/sg.h>
+
+#define IDESCSI_DEBUG_LOG		0
+
+typedef struct idescsi_pc_s {
+	u8 c[12];				/* Actual packet bytes */
+	int request_transfer;			/* Bytes to transfer */
+	int actually_transferred;		/* Bytes actually transferred */
+	int buffer_size;			/* Size of our data buffer */
+	struct request *rq;			/* The corresponding request */
+	byte *buffer;				/* Data buffer */
+	byte *current_position;			/* Pointer into the above buffer */
+	struct scatterlist *sg;			/* Scatter gather table */
+	int b_count;				/* Bytes transferred from current entry */
+	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
+	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
+	unsigned long flags;			/* Status/Action flags */
+	unsigned long timeout;			/* Command timeout */
+} idescsi_pc_t;
 
-/* FIXME: Right now we always register a single scsi host for every single
- * device. We should be just registering a single scsi host per ATA host chip
- * and deal properly with channels! The reentrancy efforts are therefore not
- * quite right done now.
+/*
+ *	Packet command status bits.
  */
+#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
+#define PC_WRITING			1	/* Data direction */
+#define PC_TRANSFORM			2	/* transform SCSI commands */
 
 /*
  *	SCSI command transformation layer
@@ -48,8 +90,8 @@
 #define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
 
 typedef struct {
-	struct ata_device *drive;
-	struct atapi_packet_command *pc;	/* Current packet command */
+	ide_drive_t *drive;
+	idescsi_pc_t *pc;			/* Current packet command */
 	unsigned long flags;			/* Status/Action flags */
 	unsigned long transform;		/* SCSI cmd translation layer */
 	unsigned long log;			/* log flags */
@@ -71,49 +113,61 @@
 #define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */
 #define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */
 
+static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		IN_BYTE (IDE_DATA_REG);
+}
+
+static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		OUT_BYTE (0, IDE_DATA_REG);
+}
+
 /*
  *	PIO data transfer routines using the scatter gather table.
  */
-static void idescsi_input_buffers(struct ata_device *drive, struct atapi_packet_command *pc, unsigned int bcount)
+static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
 {
 	int count;
 	char *buf;
 
 	while (bcount) {
-		if (pc->s.sg - (struct scatterlist *) pc->s.scsi_cmd->request_buffer > pc->s.scsi_cmd->use_sg) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
 			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
-			atapi_discard_data(drive, bcount);
+			idescsi_discard_data (drive, bcount);
 			return;
 		}
-		count = min(pc->s.sg->length - pc->s.b_count, bcount);
-		buf = page_address(pc->s.sg->page) + pc->s.sg->offset;
-		atapi_read(drive, buf + pc->s.b_count, count);
-		bcount -= count; pc->s.b_count += count;
-		if (pc->s.b_count == pc->s.sg->length) {
-			pc->s.sg++;
-			pc->s.b_count = 0;
+		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		buf = page_address(pc->sg->page) + pc->sg->offset;
+		atapi_input_bytes (drive, buf + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
 		}
 	}
 }
 
-static void idescsi_output_buffers(struct ata_device *drive, struct atapi_packet_command *pc, unsigned int bcount)
+static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
 {
 	int count;
 	char *buf;
 
 	while (bcount) {
-		if (pc->s.sg - (struct scatterlist *) pc->s.scsi_cmd->request_buffer > pc->s.scsi_cmd->use_sg) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
 			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
-			atapi_write_zeros(drive, bcount);
+			idescsi_output_zeros (drive, bcount);
 			return;
 		}
-		count = min(pc->s.sg->length - pc->s.b_count, bcount);
-		buf = page_address(pc->s.sg->page) + pc->s.sg->offset;
-		atapi_write(drive, buf + pc->s.b_count, count);
-		bcount -= count; pc->s.b_count += count;
-		if (pc->s.b_count == pc->s.sg->length) {
-			pc->s.sg++;
-			pc->s.b_count = 0;
+		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		buf = page_address(pc->sg->page) + pc->sg->offset;
+		atapi_output_bytes (drive, buf + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
 		}
 	}
 }
@@ -122,32 +176,34 @@
  *	Most of the SCSI commands are supported directly by ATAPI devices.
  *	idescsi_transform_pc handles the few exceptions.
  */
-static inline void idescsi_transform_pc1(struct ata_device *drive, struct atapi_packet_command *pc)
+static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-	u8 *c = pc->c;
-	char *scsi_buf = pc->buffer;
-	u8 *sc = pc->s.scsi_cmd->cmnd;
+	u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
 	char *atapi_buf;
 
 	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
-	if (drive->type == ATA_ROM || drive->type == ATA_MOD) {
+	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
 			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
 			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
 		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			unsigned short new_len;
 			if (!scsi_buf)
 				return;
 			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
 				return;
 			memset(atapi_buf, 0, pc->buffer_size + 4);
 			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];
-			c[8] = sc[4] + 4;	c[9] = sc[5];
-			if (sc[4] + 4 > 255)
-				c[7] = sc[4] + 4 - 255;
+			c[0] = sc[0] | 0x40;
+			c[1] = sc[1];
+			c[2] = sc[2];
+			new_len = sc[4] + 4;
+			c[8] = new_len;
+			c[9] = sc[5];
+			c[7] = new_len >> 8;
 			if (c[0] == MODE_SELECT_10) {
 				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
 				atapi_buf[2] = scsi_buf[1];	/* Medium type */
@@ -162,15 +218,15 @@
 	}
 }
 
-static inline void idescsi_transform_pc2(struct ata_device *drive, struct atapi_packet_command *pc)
+static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	u8 *atapi_buf = pc->buffer;
-	u8 *sc = pc->s.scsi_cmd->cmnd;
-	u8 *scsi_buf = pc->s.scsi_cmd->request_buffer;
+	u8 *sc = pc->scsi_cmd->cmnd;
+	u8 *scsi_buf = pc->scsi_cmd->request_buffer;
 
 	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
-	if (drive->type == ATA_ROM || drive->type == ATA_MOD) {
+	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
 			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
 			scsi_buf[1] = atapi_buf[2];		/* Medium type */
@@ -187,7 +243,7 @@
 		kfree(atapi_buf);
 }
 
-static inline void idescsi_free_bio(struct bio *bio)
+static inline void idescsi_free_bio (struct bio *bio)
 {
 	struct bio *bhp;
 
@@ -208,108 +264,97 @@
 	printk("]\n");
 }
 
-static inline idescsi_scsi_t *idescsi_private(struct Scsi_Host *host)
-{
-	return (idescsi_scsi_t*) &host[1];
-}
-
-static int idescsi_end_request(struct ata_device *drive, struct request *rq, int uptodate)
+static int idescsi_end_request (ide_drive_t *drive, int uptodate)
 {
-	unsigned long flags;
-	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = idescsi_private(host);
-	struct atapi_packet_command *pc = (struct atapi_packet_command *) rq->special;
+	idescsi_scsi_t *scsi = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
+	idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+	struct Scsi_Host *host;
 	u8 *scsi_buf;
+	unsigned long flags;
 
-	if (!(rq->flags & REQ_PC)) {
-		ata_end_request(drive, rq, uptodate, 0);
+	if (!(rq->flags & REQ_SPECIAL)) {
+		ide_end_request(drive, uptodate);
 		return 0;
 	}
-
-	spin_lock_irqsave(drive->channel->lock, flags);
-
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
-
-	spin_unlock_irqrestore(drive->channel->lock, flags);
-
+	ide_end_drive_cmd (drive, 0, 0);
 	if (rq->errors >= ERROR_MAX) {
-		pc->s.scsi_cmd->result = DID_ERROR << 16;
+		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
-			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->s.scsi_cmd->serial_number);
+			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 	} else if (rq->errors) {
-		pc->s.scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
 		if (log)
-			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->s.scsi_cmd->serial_number);
+			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 	} else {
-		pc->s.scsi_cmd->result = DID_OK << 16;
+		pc->scsi_cmd->result = DID_OK << 16;
 		idescsi_transform_pc2 (drive, pc);
 		if (log) {
-			printk ("ide-scsi: %s: suc %lu", drive->name, pc->s.scsi_cmd->serial_number);
+			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
 			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
 				printk(", rst = ");
-				scsi_buf = pc->s.scsi_cmd->request_buffer;
-				hexdump(scsi_buf, min(16U, pc->s.scsi_cmd->request_bufflen));
+				scsi_buf = pc->scsi_cmd->request_buffer;
+				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
 			} else printk("\n");
 		}
 	}
-	host = pc->s.scsi_cmd->host;
-	pc->s.done(pc->s.scsi_cmd);
-	idescsi_free_bio(rq->bio);
+	host = pc->scsi_cmd->host;
+	spin_lock_irqsave(host->host_lock, flags);
+	pc->done(pc->scsi_cmd);
+	spin_unlock_irqrestore(host->host_lock, flags);
+	idescsi_free_bio (rq->bio);
 	kfree(pc); kfree(rq);
 	scsi->pc = NULL;
-
 	return 0;
 }
 
-static inline unsigned long get_timeout(struct atapi_packet_command *pc)
+static inline unsigned long get_timeout(idescsi_pc_t *pc)
 {
-	return max((unsigned long) WAIT_CMD, pc->s.timeout - jiffies);
+	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
 }
 
 /*
  *	Our interrupt handler.
  */
-static ide_startstop_t idescsi_pc_intr(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
-	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = idescsi_private(host);
-	u8 ireason;
+	idescsi_scsi_t *scsi = drive->driver_data;
+	byte status, ireason;
 	int bcount;
-	struct atapi_packet_command *pc=scsi->pc;
+	idescsi_pc_t *pc=scsi->pc;
+	struct request *rq = pc->rq;
 	unsigned int temp;
 
-#ifdef DEBUG
+#if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-#ifdef DEBUG
+#if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
-		udma_stop(drive);
+		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
 	}
 
-	/* Clear the interrupt */
-	if (ata_status(drive, 0, DRQ_STAT)) {	/* No more interrupts */
+	status = GET_STAT();						/* Clear the interrupt */
+
+	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
 			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 		local_irq_enable();
-		if (drive->status & ERR_STAT)
+		if (status & ERR_STAT)
 			rq->errors++;
-		idescsi_end_request(drive, rq, 1);
-
-		return ATA_OP_FINISHED;
+		idescsi_end_request (drive, 1);
+		return ide_stopped;
 	}
 	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
 	ireason = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason & IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		return ATA_OP_FINISHED;
+		return ide_do_reset (drive);
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
 		temp = pc->actually_transferred + bcount;
@@ -319,205 +364,295 @@
 				temp = pc->buffer_size - pc->actually_transferred;
 				if (temp) {
 					clear_bit(PC_WRITING, &pc->flags);
-					if (pc->s.sg)
+					if (pc->sg)
 						idescsi_input_buffers(drive, pc, temp);
 					else
-						atapi_read(drive, pc->current_position, temp);
+						atapi_input_bytes(drive, pc->current_position, temp);
 					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
 				}
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
-				atapi_discard_data(drive,bcount - temp);
-
-				ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
-
-				return ATA_OP_CONTINUES;
+				idescsi_discard_data (drive,bcount - temp);
+				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				return ide_started;
 			}
-#ifdef DEBUG
+#if IDESCSI_DEBUG_LOG
 			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
 		clear_bit(PC_WRITING, &pc->flags);
-		if (pc->s.sg)
+		if (pc->sg)
 			idescsi_input_buffers (drive, pc, bcount);
 		else
-			atapi_read(drive,pc->current_position,bcount);
+			atapi_input_bytes (drive,pc->current_position,bcount);
 	} else {
 		set_bit(PC_WRITING, &pc->flags);
-		if (pc->s.sg)
+		if (pc->sg)
 			idescsi_output_buffers (drive, pc, bcount);
 		else
-			atapi_write(drive,pc->current_position,bcount);
+			atapi_output_bytes (drive,pc->current_position,bcount);
 	}
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	/* And set the interrupt handler again */
-	ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
-
-	return ATA_OP_CONTINUES;
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	return ide_started;
 }
 
-static ide_startstop_t idescsi_transfer_pc(struct ata_device *drive, struct request *rq)
+static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive)
 {
-	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = idescsi_private(host);
-	struct atapi_packet_command *pc = scsi->pc;
-	u8 ireason;
-	int ret;
+	idescsi_scsi_t *scsi = drive->driver_data;
+	idescsi_pc_t *pc = scsi->pc;
+	byte ireason;
+	ide_startstop_t startstop;
 
-	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq);
-	if (ret != ATA_OP_READY) {
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
-
-		return ret;
+		return startstop;
 	}
-
-	ireason = IN_BYTE(IDE_IREASON_REG);
-
+	ireason = IN_BYTE (IDE_IREASON_REG);
 	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ret = ATA_OP_FINISHED;
-	} else {
-		ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
-		atapi_write(drive, scsi->pc->c, 12);
-		ret = ATA_OP_CONTINUES;
+		return ide_do_reset (drive);
 	}
-
-	return ret;
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
+	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static ide_startstop_t idescsi_issue_pc(struct ata_device *drive, struct request *rq,
-		struct atapi_packet_command *pc)
+static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = idescsi_private(host);
+	idescsi_scsi_t *scsi = drive->driver_data;
 	int bcount;
+	struct request *rq = pc->rq;
 	int dma_ok = 0;
 
 	scsi->pc=pc;							/* Set the current packet command */
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
 	if (drive->using_dma && rq->bio)
-		dma_ok = udma_init(drive, rq);
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 
-	ata_select(drive, 10);
-	ata_irq_enable(drive, 1);
-	OUT_BYTE(dma_ok,IDE_FEATURE_REG);
-	OUT_BYTE(bcount >> 8,IDE_BCOUNTH_REG);
-	OUT_BYTE(bcount & 0xff,IDE_BCOUNTL_REG);
+	SELECT_DRIVE(HWIF(drive), drive);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
+	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
 
 	if (dma_ok) {
-		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		udma_start(drive, rq);
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
-	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ata_set_handler(drive, idescsi_transfer_pc, get_timeout(pc), NULL);
-
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return ATA_OP_CONTINUES;
+	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idescsi_transfer_pc(drive, rq);
+		return idescsi_transfer_pc (drive);
 	}
 }
 
 /*
- * This is our request handling function.
+ *	idescsi_do_request is our request handling function.
  */
-static ide_startstop_t idescsi_do_request(struct ata_device *drive, struct request *rq, sector_t block)
+static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	int ret;
-
-#ifdef DEBUG
-	printk(KERN_INFO "rq_status: %d, cmd: %d, errors: %d\n",
-			rq->rq_status,
-			(unsigned int)
-			rq->cmd,
-			rq->errors);
-	printk(KERN_INFO "sector: %lu, nr_sectors: %lu, current_nr_sectors: %lu\n",
-			rq->sector,
-			rq->nr_sectors,
-			rq->current_nr_sectors);
-#endif
+#if IDESCSI_DEBUG_LOG
+	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+#endif /* IDESCSI_DEBUG_LOG */
 
-	if (rq->flags & REQ_PC) {
-		ret = idescsi_issue_pc(drive, rq, (struct atapi_packet_command *) rq->special);
-	} else {
-	    blk_dump_rq_flags(rq, "ide-scsi: unsup command");
-	    idescsi_end_request(drive, rq, 0);
-	    ret = ATA_OP_FINISHED;
+	if (rq->flags & REQ_SPECIAL) {
+		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
 	}
-
-	return ret;
+	blk_dump_rq_flags(rq, "ide-scsi: unsup command");
+	idescsi_end_request (drive, 0);
+	return ide_stopped;
 }
 
-static int idescsi_open(struct inode *inode, struct file *filp, struct ata_device *drive)
+static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	return 0;
 }
 
-static void idescsi_release(struct inode *inode, struct file *filp, struct ata_device *drive)
+static void idescsi_ide_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_DEC_USE_COUNT;
 }
 
-static Scsi_Host_Template template;
-static int idescsi_cleanup (struct ata_device *drive)
+static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
+static int idescsi_initialized = 0;
+
+static void idescsi_add_settings(ide_drive_t *drive)
 {
-	if (ata_unregister_device(drive))
-		return 1;
-	scsi_unregister_host(&template);
+	idescsi_scsi_t *scsi = drive->driver_data;
 
-	return 0;
+/*
+ *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ */
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
+	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
+	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
+	ide_add_setting(drive,	"log",		SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
 }
 
-static void idescsi_revalidate(struct ata_device *_dummy)
+/*
+ *	Driver initialization.
+ */
+static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
-	/* The partition information will be handled by the SCSI layer.
-	 */
+	DRIVER(drive)->busy++;
+	idescsi_drives[id] = drive;
+	drive->driver_data = scsi;
+	drive->ready_stat = 0;
+	memset (scsi, 0, sizeof (idescsi_scsi_t));
+	scsi->drive = drive;
+	if (drive->id && (drive->id->config & 0x0060) == 0x20)
+		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+	set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
+	idescsi_add_settings(drive);
 }
 
-static void idescsi_attach(struct ata_device *drive);
+static int idescsi_cleanup (ide_drive_t *drive)
+{
+	idescsi_scsi_t *scsi = drive->driver_data;
+
+	if (ide_unregister_subdriver (drive))
+		return 1;
+	drive->driver_data = NULL;
+	kfree (scsi);
+	return 0;
+}
 
 /*
  *	IDE subdriver functions, registered with ide.c
  */
-static struct ata_operations ata_ops = {
-	owner:			THIS_MODULE,
-	attach:			idescsi_attach,
+static ide_driver_t idescsi_driver = {
+	name:			"ide-scsi",
+	version:		IDESCSI_VERSION,
+	media:			ide_scsi,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
 	cleanup:		idescsi_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
+	ioctl:			NULL,
 	open:			idescsi_open,
-	release:		idescsi_release,
-	revalidate:		idescsi_revalidate,
+	release:		idescsi_ide_release,
+	media_change:		NULL,
+	revalidate:		NULL,
+	pre_reset:		NULL,
+	capacity:		NULL,
+	special:		NULL,
+	proc:			NULL,
 };
 
-static int idescsi_detect(Scsi_Host_Template *host_template)
+int idescsi_init (void);
+static ide_module_t idescsi_module = {
+	IDE_DRIVER_MODULE,
+	idescsi_init,
+	&idescsi_driver,
+	NULL
+};
+
+/*
+ *	idescsi_init will register the driver for each scsi.
+ */
+int idescsi_init (void)
 {
-	return register_ata_driver(&ata_ops);
+	ide_drive_t *drive;
+	idescsi_scsi_t *scsi;
+	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	int i, failed, id;
+
+	if (idescsi_initialized)
+		return 0;
+	idescsi_initialized = 1;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+	MOD_INC_USE_COUNT;
+	for (i = 0; media[i] != 255; i++) {
+		failed = 0;
+		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+				continue;
+			}
+			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
+				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+				kfree (scsi);
+				continue;
+			}
+			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
+				idescsi_setup (drive, scsi, id);
+			failed--;
+		}
+	}
+	ide_register_module(&idescsi_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
-static const char *idescsi_info(struct Scsi_Host *host)
+int idescsi_detect (Scsi_Host_Template *host_template)
 {
-	static const char *msg = "SCSI host adapter emulation for ATAPI devices";
+	struct Scsi_Host *host;
+	int id;
+	int last_lun = 0;
 
-	return msg;
+	host_template->proc_name = "ide-scsi";
+	host = scsi_register(host_template, 0);
+	if(host == NULL)
+		return 0;
+		
+	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
+		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);
+	host->max_id = id;
+	host->max_lun = last_lun + 1;
+	host->can_queue = host->cmd_per_lun * id;
+	return 1;
+}
+
+int idescsi_release (struct Scsi_Host *host)
+{
+	ide_drive_t *drive;
+	int id;
+
+	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
+		drive = idescsi_drives[id];
+		if (drive)
+			DRIVER(drive)->busy--;
+	}
+	return 0;
+}
+
+const char *idescsi_info (struct Scsi_Host *host)
+{
+	return "SCSI host adapter emulation for IDE ATAPI devices";
 }
 
-static int idescsi_ioctl(Scsi_Device *dev, int cmd, void *arg)
+int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
 {
-	idescsi_scsi_t *scsi = idescsi_private(dev->host);
+	ide_drive_t *drive = idescsi_drives[dev->id];
+	idescsi_scsi_t *scsi = drive->driver_data;
 
 	if (cmd == SG_SET_TRANSFORM) {
 		if (arg)
@@ -527,11 +662,10 @@
 		return 0;
 	} else if (cmd == SG_GET_TRANSFORM)
 		return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
-
 	return -EINVAL;
 }
 
-static inline struct bio *idescsi_kmalloc_bio(int count)
+static inline struct bio *idescsi_kmalloc_bio (int count)
 {
 	struct bio *bh, *bhp, *first_bh;
 
@@ -550,34 +684,29 @@
 	}
 	return first_bh;
 abort:
-	idescsi_free_bio(first_bh);
-
+	idescsi_free_bio (first_bh);
 	return NULL;
 }
 
-static inline int idescsi_set_direction(struct atapi_packet_command *pc)
+static inline int idescsi_set_direction (idescsi_pc_t *pc)
 {
 	switch (pc->c[0]) {
-		case READ_6:
-		case READ_10:
-		case READ_12:
-			clear_bit(PC_WRITING, &pc->flags);
+		case READ_6: case READ_10: case READ_12:
+			clear_bit (PC_WRITING, &pc->flags);
 			return 0;
-		case WRITE_6:
-		case WRITE_10:
-		case WRITE_12:
-			set_bit(PC_WRITING, &pc->flags);
+		case WRITE_6: case WRITE_10: case WRITE_12:
+			set_bit (PC_WRITING, &pc->flags);
 			return 0;
 		default:
 			return 1;
 	}
 }
 
-static inline struct bio *idescsi_dma_bio(struct ata_device *drive, struct atapi_packet_command *pc)
+static inline struct bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	struct bio *bh = NULL, *first_bh = NULL;
-	int segments = pc->s.scsi_cmd->use_sg;
-	struct scatterlist *sg = pc->s.scsi_cmd->request_buffer;
+	int segments = pc->scsi_cmd->use_sg;
+	struct scatterlist *sg = pc->scsi_cmd->request_buffer;
 
 	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)
 		return NULL;
@@ -586,9 +715,9 @@
 	if (segments) {
 		if ((first_bh = bh = idescsi_kmalloc_bio (segments)) == NULL)
 			return NULL;
-#ifdef DEBUG
+#if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
 			bh->bi_io_vec[0].bv_page = sg->page;
 			bh->bi_io_vec[0].bv_len = sg->length;
@@ -600,36 +729,40 @@
 	} else {
 		if ((first_bh = bh = idescsi_kmalloc_bio (1)) == NULL)
 			return NULL;
-#ifdef DEBUG
+#if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);
-#endif
-		bh->bi_io_vec[0].bv_page = virt_to_page(pc->s.scsi_cmd->request_buffer);
+#endif /* IDESCSI_DEBUG_LOG */
+		bh->bi_io_vec[0].bv_page = virt_to_page(pc->scsi_cmd->request_buffer);
 		bh->bi_io_vec[0].bv_len = pc->request_transfer;
-		bh->bi_io_vec[0].bv_offset = (unsigned long) pc->s.scsi_cmd->request_buffer & ~PAGE_MASK;
+		bh->bi_io_vec[0].bv_offset = (unsigned long) pc->scsi_cmd->request_buffer & ~PAGE_MASK;
 		bh->bi_size = pc->request_transfer;
 	}
 	return first_bh;
 }
 
-static inline int should_transform(struct ata_device *drive, Scsi_Cmnd *cmd)
+static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
 {
-	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = idescsi_private(host);
+	idescsi_scsi_t *scsi = drive->driver_data;
 
 	if (major(cmd->request->rq_dev) == SCSI_GENERIC_MAJOR)
 		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
 }
 
-static int idescsi_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-	idescsi_scsi_t *scsi = idescsi_private(cmd->host);
-	struct ata_device *drive = scsi->drive;
+	ide_drive_t *drive = idescsi_drives[cmd->target];
+	idescsi_scsi_t *scsi;
 	struct request *rq = NULL;
-	struct atapi_packet_command *pc = NULL;
+	idescsi_pc_t *pc = NULL;
 
-	pc = kmalloc(sizeof(*pc), GFP_ATOMIC);
-	rq = kmalloc(sizeof(*rq), GFP_ATOMIC);
+	if (!drive) {
+		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
+		goto abort;
+	}
+	scsi = drive->driver_data;
+	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
 		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
 		goto abort;
@@ -637,19 +770,20 @@
 
 	memset (pc->c, 0, 12);
 	pc->flags = 0;
+	pc->rq = rq;
 	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
 	if (cmd->use_sg) {
 		pc->buffer = NULL;
-		pc->s.sg = cmd->request_buffer;
+		pc->sg = cmd->request_buffer;
 	} else {
 		pc->buffer = cmd->request_buffer;
-		pc->s.sg = NULL;
+		pc->sg = NULL;
 	}
-	pc->s.b_count = 0;
+	pc->b_count = 0;
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
-	pc->s.scsi_cmd = cmd;
-	pc->s.done = done;
-	pc->s.timeout = jiffies + cmd->timeout_per_command;
+	pc->scsi_cmd = cmd;
+	pc->done = done;
+	pc->timeout = jiffies + cmd->timeout_per_command;
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
@@ -664,35 +798,35 @@
 		}
 	}
 
-	memset(rq, 0, sizeof(*rq));
-	rq->flags = REQ_PC;
+	ide_init_drive_cmd (rq);
 	rq->special = (char *) pc;
 	rq->bio = idescsi_dma_bio (drive, pc);
-	ide_do_drive_cmd(drive, rq, ide_end);
-
+	rq->flags = REQ_SPECIAL;
+	spin_unlock_irq(cmd->host->host_lock);
+	(void) ide_do_drive_cmd (drive, rq, ide_end);
+	spin_lock_irq(cmd->host->host_lock);
 	return 0;
 abort:
-	if (pc)
-		kfree (pc);
-	if (rq)
-		kfree (rq);
+	if (pc) kfree (pc);
+	if (rq) kfree (rq);
 	cmd->result = DID_ERROR << 16;
 	done(cmd);
-
 	return 0;
 }
 
-/* FIXME: This needs further investigation.
- */
-static int idescsi_device_reset(Scsi_Cmnd *cmd)
+int idescsi_abort (Scsi_Cmnd *cmd)
 {
-	return SUCCESS;
+	return SCSI_ABORT_SNOOZE;
+}
+
+int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
+{
+	return SCSI_RESET_SUCCESS;
 }
 
 static int idescsi_bios(Disk *disk, struct block_device *dev, int *parm)
 {
-	idescsi_scsi_t *scsi = idescsi_private(disk->device->host);
-	struct ata_device *drive = scsi->drive;
+	ide_drive_t *drive = idescsi_drives[disk->device->id];
 
 	if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
 		parm[0] = drive->bios_head;
@@ -702,19 +836,16 @@
 	return 0;
 }
 
-static Scsi_Host_Template template = {
+static Scsi_Host_Template idescsi_template = {
 	module:		THIS_MODULE,
 	name:		"idescsi",
 	detect:		idescsi_detect,
-	release:	NULL, /* unregister_ata_driver is always
-				 called before scsi_unregister_host,
-				 there never controllers left to
-				 release by that point. */
+	release:	idescsi_release,
 	info:		idescsi_info,
 	ioctl:		idescsi_ioctl,
 	queuecommand:	idescsi_queue,
-	eh_device_reset_handler:
-			idescsi_device_reset,
+	abort:		idescsi_abort,
+	reset:		idescsi_reset,
 	bios_param:	idescsi_bios,
 	can_queue:	10,
 	this_id:	-1,
@@ -722,63 +853,31 @@
 	cmd_per_lun:	5,
 	use_clustering:	DISABLE_CLUSTERING,
 	emulated:	1,
-	/* FIXME: Buggy generic SCSI code doesn't remove /proc/entires! */
-	proc_name:	"atapi"
 };
 
-/*
- *	Driver initialization.
- */
-static void idescsi_attach(struct ata_device *drive)
-{
-	idescsi_scsi_t *scsi;
-	struct Scsi_Host *host;
-
-
-	if (drive->type == ATA_DISK)
-		return;
-
-	host = scsi_register(&template, sizeof(idescsi_scsi_t));
-	if (!host) {
-		printk(KERN_ERR
-			"ide-scsi: %s: Can't allocate a scsi host structure\n",
-			drive->name);
-		return;
-	}
-
-	host->max_lun = drive->last_lun + 1;
-	host->max_id = 1;
-
-	if (ata_register_device(drive, &ata_ops)) {
-		printk(KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-		scsi_unregister(host);
-		return;
-	}
-
-	drive->driver_data = host;
-	drive->ready_stat = 0;
-
-	scsi = idescsi_private(host);
-	memset(scsi,0, sizeof (*scsi));
-	scsi->drive = drive;
-
-	if (drive->id && (drive->id->config & 0x0060) == 0x20)
-		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
-	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
-	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
-#ifdef DEBUG
-	set_bit(IDESCSI_LOG_CMD, &scsi->log);
-#endif
-}
-
 static int __init init_idescsi_module(void)
 {
-	return scsi_register_host(&template);
+	idescsi_init();
+	scsi_register_host(&idescsi_template);
+	return 0;
 }
 
 static void __exit exit_idescsi_module(void)
 {
-	unregister_ata_driver(&ata_ops);
+	ide_drive_t *drive;
+	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	int i, failed;
+
+	scsi_unregister_host(&idescsi_template);
+	for (i = 0; media[i] != 255; i++) {
+		failed = 0;
+		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
+			if (idescsi_cleanup (drive)) {
+				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
+				failed++;
+			}
+	}
+	ide_unregister_module(&idescsi_module);
 }
 
 module_init(init_idescsi_module);
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Tue Aug 27 12:27:45 2002
+++ b/drivers/scsi/ips.c	Tue Aug 27 12:27:45 2002
@@ -326,21 +326,21 @@
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table,
        probe:		ips_insert_device,
-       remove:		ips_remove_device,
+       remove:		__devexit_p(ips_remove_device),
    }; 
            
    struct pci_driver ips_pci_driver_5i = {
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table_5i,
        probe:		ips_insert_device,
-       remove:		ips_remove_device,
+       remove:		__devexit_p(ips_remove_device),
    };
 
    struct pci_driver ips_pci_driver_i960 = {
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table_i960,
        probe:		ips_insert_device,
-       remove:		ips_remove_device,
+       remove:		__devexit_p(ips_remove_device),
    };
 
 #endif
diff -Nru a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
--- a/drivers/scsi/qlogicisp.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/scsi/qlogicisp.c	Tue Aug 27 12:28:05 2002
@@ -1695,7 +1695,6 @@
 	u_short param[6];
 #endif
 	u_short isp_cfg1, hwrev;
-	unsigned long flags;
 	struct isp1020_hostdata *hostdata =
 		(struct isp1020_hostdata *) host->hostdata;
 
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/scsi/scsi_debug.c	Tue Aug 27 12:28:07 2002
@@ -1,4 +1,4 @@
-/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+/* 
  *  linux/kernel/scsi_debug.c
  *
  *  Copyright (C) 1992  Eric Youngdale
@@ -12,10 +12,11 @@
  *
  *  For documentation see http://www.torque.net/sg/sdebug.html
  *
- *   D. Gilbert (dpg) work for MOD device test [20010421]
- *   dpg, work for devfs large number of disks [20010809]
- *   dpg, forked for lk 2.5 series [20011216, 20020101]
- *   dpg, use vmalloc() more inquiry+mode_sense [20020302]
+ *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
+ *   dpg: work for devfs large number of disks [20010809]
+ *        forked for lk 2.5 series [20011216, 20020101]
+ *        use vmalloc() more inquiry+mode_sense [20020302]
+ *        add timers for delayed responses [20020721]
  */
 
 #include <linux/config.h>
@@ -46,7 +47,12 @@
 #include <linux/version.h>
 #endif
 
-static char scsi_debug_version_str[] = "Version: 1.59 (20020302)";
+#include "scsi_debug.h"
+
+static const char * scsi_debug_version_str = "Version: 1.62 (20020812)";
+
+#define DRIVERFS_SUPPORT 1	/* comment out whole line to disable */
+
 
 #ifndef SCSI_CMD_READ_16
 #define SCSI_CMD_READ_16 0x88
@@ -54,29 +60,36 @@
 #ifndef SCSI_CMD_WRITE_16
 #define SCSI_CMD_WRITE_16 0x8a
 #endif
+#ifndef REPORT_LUNS
+#define REPORT_LUNS 0xa0
+#endif
 
 /* A few options that we want selected */
 #define DEF_NR_FAKE_DEVS   1
 #define DEF_DEV_SIZE_MB   8
 #define DEF_FAKE_BLK0   0
+#define DEF_EVERY_NTH   100
+#define DEF_DELAY   1
 
 #define DEF_OPTS   0
 #define SCSI_DEBUG_OPT_NOISE   1
 #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
+#define SCSI_DEBUG_OPT_EVERY_NTH   4
 
 #define OPT_MEDIUM_ERR_ADDR   0x1234
 
 static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
 static int scsi_debug_opts = DEF_OPTS;
+static int scsi_debug_every_nth = DEF_EVERY_NTH;
+static int scsi_debug_cmnd_count = 0;
+static int scsi_debug_delay = DEF_DELAY;
 
 #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
 #define N_HEAD          8
 #define N_SECTOR        32
 #define DEV_READONLY(TGT)      (0)
 #define DEV_REMOVEABLE(TGT)    (0)
-#define DEVICE_TYPE(TGT) (TYPE_DISK);
-
-#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+#define PERIPH_DEVICE_TYPE(TGT) (TYPE_DISK);
 
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
@@ -87,81 +100,79 @@
 
 #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
 
-/* Do not attempt to use a timer to simulate a real disk with latency */
-/* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
-
-#define START_PARTITION 4
-
 /* Time to wait before completing a command */
-#define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
 #define SECT_SIZE_PER(TGT) SECT_SIZE
 
-static int starts[] =
-{N_SECTOR,
- N_HEAD * N_SECTOR,		/* Single cylinder */
- N_HEAD * N_SECTOR * 4,
- 0 /* CAPACITY */, 0};
 
-static unsigned char * fake_storep;
+#define SDEBUG_SENSE_LEN 32
 
-typedef struct sdebug_dev_info {
+struct sdebug_dev_info {
 	Scsi_Device * sdp;
-	unsigned short host_no;
-	unsigned short id;
+	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
 	char reset;
-	char sb_index;
-} Sdebug_dev_info;
-static Sdebug_dev_info * devInfop;
+};
+static struct sdebug_dev_info * devInfop;
+
+typedef void (* done_funct_t) (Scsi_Cmnd *);
+
+struct sdebug_queued_cmd {
+	int in_use;
+	struct timer_list cmnd_timer;
+	done_funct_t done_funct;
+	struct scsi_cmnd * a_cmnd;
+	int scsi_result;
+};
+static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
+
+static unsigned char * fake_storep;	/* ramdisk storage */
+
+static unsigned char broken_buff[SDEBUG_SENSE_LEN];
 
 static int num_aborts = 0;
 static int num_dev_resets = 0;
 static int num_bus_resets = 0;
 static int num_host_resets = 0;
 
-static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
-static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
-
-#include "scsi_debug.h"
-
-typedef void (*done_fct_t) (Scsi_Cmnd *);
-
-static volatile done_fct_t * do_done = 0;
+static spinlock_t queued_arr_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t atomic_rw = RW_LOCK_UNLOCKED;
 
-static struct Scsi_Host * SHpnt = NULL;
+#ifdef DRIVERFS_SUPPORT
+static struct device_driver sdebug_driverfs_driver;
+#endif
 
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip);
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip);
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip);
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip);
-static void scsi_debug_intr_handle(unsigned long);
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+/* function declarations */
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip);
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip);
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+		     int num, struct sdebug_dev_info * devip);
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
+		      struct sdebug_dev_info * devip);
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip);
+static void timer_intr_handler(unsigned long);
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen);
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
-
-static struct timer_list * timeout = 0;
-static Scsi_Cmnd ** SCint = 0;
-
-/*
- * Semaphore used to simulate bus lockups.
- */
-static int scsi_debug_lockup = 0;
-
-#define NUM_SENSE_BUFFS 4
-#define SENSE_BUFF_LEN 32
-static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip);
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip, 
+			 done_funct_t done, int scsi_result, int delta_jiff);
+static void init_all_queued(void);
+static void stop_all_queued(void);
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
+                           const char * dev_id_str, int dev_id_str_len);
+#ifdef DRIVERFS_SUPPORT
+static void do_create_driverfs_files(void);
+static void do_remove_driverfs_files(void);
+#endif
 
 
-static inline 
-unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+static unsigned char * scatg2virt(const struct scatterlist * sclp)
 {
 	if (NULL == sclp)
 		return NULL;
@@ -173,61 +184,47 @@
 }
 
 static
-int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block;
 	int upper_blk;
 	unsigned char *buff;
-	int scsi_debug_errsts;
+	int errsts = 0;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long iflags;
-	int i, num, capac;
-	Sdebug_dev_info * devip = NULL;
-	char * sbuff;
+	int num, capac;
+	struct sdebug_dev_info * devip = NULL;
+	unsigned char * sbuff;
 
-	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
-		printk(KERN_INFO "scsi_debug: queue_command: cmd ");
-		for (i = 0, num = SCpnt->cmd_len; i < num; ++i)
-	            printk("%02x ", cmd[i]);
-		printk("   use_sg=%d\n", SCpnt->use_sg);
-	}
-	/*
-	 * If we are being notified of the mid-level reposessing a command
-	 * due to timeout, just return.
-	 */
-	if (done == NULL) {
-		return 0;
-	}
+	if (done == NULL)
+		return 0;	/* assume mid level reprocessing command */
 
 	if (SCpnt->use_sg) { /* just use first element */
 		struct scatterlist *sgpnt = (struct scatterlist *)
 						SCpnt->request_buffer;
 
-		buff = sdebug_scatg2virt(&sgpnt[0]);
+		buff = scatg2virt(&sgpnt[0]);
 		bufflen = sgpnt[0].length;
 		/* READ and WRITE process scatterlist themselves */
 	}
 	else 
 		buff = (unsigned char *) SCpnt->request_buffer;
+	if (NULL == buff) {
+		printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n");
+		buff = broken_buff;	/* just point at dummy */
+		bufflen = SDEBUG_SENSE_LEN;
+	}
 
-        /*
-         * If a command comes for the ID of the host itself, just print
-         * a silly message and return.
-         */
-        if(target == 7) {
-                printk(KERN_WARNING "How do you do!\n");
-                SCpnt->result = 0;
-                done(SCpnt);
-                return 0;
+        if(target == driver_template.this_id) {
+                printk(KERN_WARNING 
+		       "scsi_debug: initiator's id used as target!\n");
+		return schedule_resp(SCpnt, NULL, done, 0, 0);
         }
 
-	if ((target > 7) || (SCpnt->lun != 0)) {
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		return 0;
-	}
+	if ((target > driver_template.this_id) || (SCpnt->lun != 0))
+		return schedule_resp(SCpnt, NULL, done, 
+				     DID_NO_CONNECT << 16, 0);
 #if 0
 	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
 	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
@@ -235,101 +232,93 @@
 #endif
 	if (NULL == SCpnt->device->hostdata) {
 		devip = devInfoReg(SCpnt->device);
-		if (NULL == devip) {
-			SCpnt->result = DID_NO_CONNECT << 16;
-			done(SCpnt);
-			return 0;
-		}
+		if (NULL == devip)
+			return schedule_resp(SCpnt, NULL, done, 
+					     DID_NO_CONNECT << 16, 0);
 		SCpnt->device->hostdata = devip;
 	}
 	devip = SCpnt->device->hostdata;
 
+        if ((SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts) &&
+            (scsi_debug_every_nth > 0) &&
+            (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) {
+                scsi_debug_cmnd_count =0;
+                return 0; /* ignore command causing timeout */
+        }
+
 	switch (*cmd) {
 	case INQUIRY:     /* mandatory */
-		scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, 
-						       bufflen, devip);
 		/* assume INQUIRY called first so setup max_cmd_len */
 		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
 			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+		errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
 		break;
 	case REQUEST_SENSE:	/* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
+		/* Since this driver indicates autosense by placing the
+		 * sense buffer in the scsi_cmnd structure in the response
+		 * (when CHECK_CONDITION is set), the mid level shouldn't
+		 * need to call REQUEST_SENSE */
 		if (devip) {
-			sbuff = &sense_buffers[(int)devip->sb_index][0];
-			devip->sb_index = 0; 
+			sbuff = devip->sense_buff;
+			memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? 
+					     bufflen : SDEBUG_SENSE_LEN);
+			mk_sense_buffer(devip, 0, 0x0, 0, 7);
+		} else {
+			memset(buff, 0, bufflen);
+			buff[0] = 0x70;
 		}
-		else
-		    sbuff = &sense_buffers[0][0]; 
-		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
-				     bufflen : SENSE_BUFF_LEN);
-		memset(sbuff, 0, SENSE_BUFF_LEN);
-		sbuff[0] = 0x70;
-		SCpnt->result = 0;
-		done(SCpnt);
-		return 0;
+		break;
 	case START_STOP:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
-		scsi_debug_errsts = 0;
+		errsts = check_reset(SCpnt, devip);
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk(
-					"Medium removal inhibited..."));
-		} else {
-			SCSI_LOG_LLQUEUE(2, 
-					printk("Medium removal enabled..."));
-		}
-		scsi_debug_errsts = 0;
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk("\tMedium removal %s\n",
+			       cmd[4] ? "inhibited" : "enabled");
 		break;
 	case SEND_DIAGNOSTIC:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
 	case TEST_UNIT_READY:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", 
-					   buff, bufflen));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
+        case RESERVE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RESERVE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
 	case READ_CAPACITY:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
-                SHpnt = SCpnt->host;
+		errsts = check_reset(SCpnt, devip);
 		memset(buff, 0, bufflen);
-		capac = CAPACITY - 1;
-		buff[0] = (capac >> 24);
-		buff[1] = (capac >> 16) & 0xff;
-		buff[2] = (capac >> 8) & 0xff;
-		buff[3] = capac & 0xff;
-		buff[4] = 0;
-		buff[5] = 0;
-		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-		buff[7] = SECT_SIZE_PER(target) & 0xff;
-
-		scsi_debug_errsts = 0;
+		if (bufflen > 7) {
+			capac = CAPACITY - 1;
+			buff[0] = (capac >> 24);
+			buff[1] = (capac >> 16) & 0xff;
+			buff[2] = (capac >> 8) & 0xff;
+			buff[3] = capac & 0xff;
+			buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+			buff[7] = SECT_SIZE_PER(target) & 0xff;
+		}
 		break;
 	case SCSI_CMD_READ_16:	/* SBC-2 */
 	case READ_12:
 	case READ_10:
 	case READ_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_READ_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -338,38 +327,31 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == READ_12) {
+		} else if ((*cmd) == READ_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == READ_10) {
+		} else if ((*cmd) == READ_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
-				    &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+		break;
+	case REPORT_LUNS:
+		errsts = resp_report_luns(cmd, buff, bufflen, devip);
+		break;
 	case SCSI_CMD_WRITE_16:	/* SBC-2 */
 	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_WRITE_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -378,97 +360,38 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == WRITE_12) {
+		} else if ((*cmd) == WRITE_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == WRITE_10) {
+		} else if ((*cmd) == WRITE_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
-				     &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+		break;
 	case MODE_SENSE:
 	case MODE_SENSE_10:
-		scsi_debug_errsts = 
-		    scsi_debug_mode_sense(cmd, target, buff, bufflen, devip);
+		errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
 		break;
 	default:
 #if 0
 		printk(KERN_INFO "scsi_debug: Unsupported command, "
 		       "opcode=0x%x\n", (int)cmd[0]);
 #endif
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
-				    (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
-		break;
-	}
-
-	spin_lock_irqsave(&mailbox_lock, iflags);
-	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
-		if (timeout[i].function == NULL)
+		if ((errsts = check_reset(SCpnt, devip)))
 			break;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
+		errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+		break;
 	}
-
-	/*
-	 * If all of the slots are full, just return 1.  The new error 
-	 * handling scheme allows this, and the mid-level should queue things.
-	 */
-	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
-		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		spin_unlock_irqrestore(&mailbox_lock, iflags);
-		return 1;
-	}
-	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
-
-#ifdef IMMEDIATE
-	if (!scsi_debug_lockup) {
-		SCpnt->result = scsi_debug_errsts;
-		SCint[i] = SCpnt;
-		do_done[i] = done;
-		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
-	}
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-#else
-
-	SCpnt->result = scsi_debug_errsts;
-	timeout[i].function = scsi_debug_intr_handle;
-	timeout[i].data = i;
-	timeout[i].expires = jiffies + DISK_SPEED;
-	SCint[i] = SCpnt;
-	do_done[i] = done;
-
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-	add_timer(&timeout[i]);
-	if (!done)
-		printk(KERN_ERR "scsi_debug_queuecommand: "
-		       "done can't be NULL\n");
-
-#if 0
-	printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, 
-	       timeout[i].expires, jiffies);
-#endif
-#endif
-
-	return 0;
+	return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
 }
 
 static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
@@ -476,58 +399,101 @@
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
 	}
-	return -ENOTTY;
+	return -EINVAL;
+	/* return -ENOTTY; // correct return but upsets fdisk */
 }
 
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip)
 {
 	if (devip->reset) {
 		devip->reset = 0;
-		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
-		SCpnt->result = (COMMAND_COMPLETE << 8) | 
-				(CHECK_CONDITION << 1);
-                return 1;
+		mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	return 0;
 }
 
-#define SDEBUG_MAX_INQ_SZ 58
+#define SDEBUG_LONG_INQ_SZ 58
+#define SDEBUG_MAX_INQ_ARR_SZ 128
+
+static const char * vendor_id = "Linux   ";
+static const char * product_id = "scsi_debug      ";
+static const char * product_rev = "0004";
+
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, 
+			   const char * dev_id_str, int dev_id_str_len)
+{
+	int num;
+
+	/* Two identification descriptors: */
+	/* T10 vendor identifier field format (faked) */
+	arr[0] = 0x2;	/* ASCII */
+	arr[1] = 0x1;
+	arr[2] = 0x0;
+	memcpy(&arr[4], vendor_id, 8);
+	memcpy(&arr[12], product_id, 16);
+	memcpy(&arr[28], dev_id_str, dev_id_str_len);
+	num = 8 + 16 + dev_id_str_len;
+	arr[3] = num;
+	num += 4;
+	/* NAA IEEE registered identifier (faked) */
+	arr[num] = 0x1;	/* binary */
+	arr[num + 1] = 0x3;
+	arr[num + 2] = 0x0;
+	arr[num + 3] = 0x8;
+	arr[num + 4] = 0x51;	/* ieee company id=0x123456 (faked) */
+	arr[num + 5] = 0x23;
+	arr[num + 6] = 0x45;
+	arr[num + 7] = 0x60;
+	arr[num + 8] = (dev_id_num >> 24);
+	arr[num + 9] = (dev_id_num >> 16) & 0xff;
+	arr[num + 10] = (dev_id_num >> 8) & 0xff;
+	arr[num + 11] = dev_id_num & 0xff;
+	return num + 12;
+}
 
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip)
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip)
 {
 	unsigned char pq_pdt;
-	unsigned char arr[SDEBUG_MAX_INQ_SZ];
-	int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? 
-			SDEBUG_MAX_INQ_SZ : bufflen;
+	unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+	int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? 
+			SDEBUG_MAX_INQ_ARR_SZ : bufflen;
 
-	SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 	if (bufflen < cmd[4])
 		printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d "
 		       "< alloc_length=%d\n", bufflen, (int)cmd[4]);
 	memset(buff, 0, bufflen);
-	memset(arr, 0, SDEBUG_MAX_INQ_SZ);
-	pq_pdt = DEVICE_TYPE(target);
+	memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+	pq_pdt = PERIPH_DEVICE_TYPE(target);
 	arr[0] = pq_pdt;
 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-	}
-	else if (0x1 & cmd[1]) {  /* EVPD bit set */
+	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
+		int dev_id_num, len;
+		char dev_id_str[6];
+		
+		dev_id_num = ((devip->sdp->host->host_no + 1) * 1000) + 
+			      devip->sdp->id;
+		len = snprintf(dev_id_str, 6, "%d", dev_id_num);
+		len = (len > 6) ? 6 : len;
 		if (0 == cmd[2]) { /* supported vital product data pages */
-			arr[3] = 1;
-			arr[4] = 0x80; /* ... only unit serial number */
-		}
-		else if (0x80 == cmd[2]) { /* unit serial number */
+			arr[3] = 3;
+			arr[4] = 0x0; /* this page */
+			arr[5] = 0x80; /* unit serial number */
+			arr[6] = 0x83; /* device identification */
+		} else if (0x80 == cmd[2]) { /* unit serial number */
 			arr[1] = 0x80;
-			arr[3] = 4;
-			arr[4] = '1'; arr[5] = '2'; arr[6] = '3';
-			arr[7] = '4';
-		}
-		else {
+			arr[3] = len;
+			memcpy(&arr[4], dev_id_str, len);
+		} else if (0x83 == cmd[2]) { /* device identification */
+			arr[1] = 0x83;
+			arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
+						 dev_id_str, len);
+		} else {
 			/* Illegal request, invalid field in cdb */
-			mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 			return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 		}
 		memcpy(buff, arr, min_len); 
@@ -536,18 +502,18 @@
 	/* drops through here for a standard inquiry */
 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
 	arr[2] = 3;	/* claim SCSI 3 */
-	arr[4] = SDEBUG_MAX_INQ_SZ - 5;
+	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
-	memcpy(&arr[8], "Linux   ", 8);
-	memcpy(&arr[16], "scsi_debug      ", 16);
-	memcpy(&arr[32], "0003", 4);
+	memcpy(&arr[8], vendor_id, 8);
+	memcpy(&arr[16], product_id, 16);
+	memcpy(&arr[32], product_rev, 4);
 	memcpy(buff, arr, min_len);
 	return 0;
 }
 
 /* <<Following mode page info copied from ST318451LW>> */ 
 
-static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target)
+static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
 {	/* Read-Write Error Recovery page for mode_sense */
 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 
 					5, 0, 0xff, 0xff};
@@ -558,7 +524,7 @@
 	return sizeof(err_recov_pg);
 }
 
-static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target)
+static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Disconnect-Reconnect page for mode_sense */
 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 
 					 0, 0, 0, 0, 0, 0, 0, 0};
@@ -569,7 +535,25 @@
 	return sizeof(disconnect_pg);
 }
 
-static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target)
+static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+{       /* Format device page for mode_sense */
+        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0x40, 0, 0, 0};
+
+        memcpy(p, format_pg, sizeof(format_pg));
+        p[10] = (N_SECTOR >> 8) & 0xff;
+        p[11] = N_SECTOR & 0xff;
+        p[12] = (SECT_SIZE >> 8) & 0xff;
+        p[13] = SECT_SIZE & 0xff;
+        if (DEV_REMOVEABLE(target))
+                p[20] |= 0x20; /* should agree with INQUIRY */
+        if (1 == pcontrol)
+                memset(p + 2, 0, sizeof(format_pg) - 2);
+        return sizeof(format_pg);
+}
+
+static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Caching page for mode_sense */
 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 
 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
@@ -580,7 +564,7 @@
 	return sizeof(caching_pg);
 }
 
-static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Control mode page for mode_sense */
 	unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
 				     0, 0, 0x2, 0x4b};
@@ -594,9 +578,9 @@
 
 #define SDEBUG_MAX_MSENSE_SZ 256
 
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip)
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip)
 {
 	unsigned char dbd;
 	int pcontrol, pcode;
@@ -622,15 +606,14 @@
 	memset(buff, 0, bufflen);
 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
 	if (0x3 == pcontrol) {  /* Saving values not supported */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
 	if (msense_6) {
 		arr[2] = dev_spec;
 		offset = 4;
-	}
-	else {
+	} else {
 		arr[3] = dev_spec;
 		offset = 8;
 	}
@@ -638,30 +621,34 @@
 
 	switch (pcode) {
 	case 0x1:	/* Read-Write error recovery page, direct access */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x2:	/* Disconnect-Reconnect page, all devices */
-		len = sdebug_disconnect_pg(ap, pcontrol, target);
+		len = resp_disconnect_pg(ap, pcontrol, target);
 		offset += len;
 		break;
+        case 0x3:       /* Format device page, direct access */
+                len = resp_format_pg(ap, pcontrol, target);
+                offset += len;
+                break;
 	case 0x8:	/* Caching page, direct access */
-		len = sdebug_caching_pg(ap, pcontrol, target);
+		len = resp_caching_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0xa:	/* Control Mode page, all devices */
-		len = sdebug_ctrl_m_pg(ap, pcontrol, target);
+		len = resp_ctrl_m_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x3f:	/* Read all Mode pages */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
-		len += sdebug_disconnect_pg(ap + len, pcontrol, target);
-		len += sdebug_caching_pg(ap + len, pcontrol, target);
-		len += sdebug_ctrl_m_pg(ap + len, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
+		len += resp_disconnect_pg(ap + len, pcontrol, target);
+		len += resp_caching_pg(ap + len, pcontrol, target);
+		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
 		offset += len;
 		break;
 	default:
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	if (msense_6)
@@ -675,8 +662,8 @@
 	return 0;
 }
 
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		     struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -685,30 +672,17 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
-	}
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-	{
-		int delay = SCSI_SETUP_LATENCY;
-
-		delay += SCpnt->request->nr_sectors * SCSI_DATARATE;
-		if (delay)
-			usleep(delay);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-#endif
 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
 	    (block >= OPT_MEDIUM_ERR_ADDR) && 
 	    (block < (OPT_MEDIUM_ERR_ADDR + num))) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14);
+		mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14);
 		/* claim unrecoverable read error */
-		return 1;
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+	read_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", 
@@ -716,46 +690,29 @@
 	if (SCpnt->use_sg) {
 		sgcount = 0;
 		sgpnt = (struct scatterlist *) buff;
-		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		buff = scatg2virt(&sgpnt[sgcount]);
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen);
-#if 0
-		/* Simulate a disk change */
-		if (block == 0xfff0) {
-			sense_buffer[0] = 0x70;
-			sense_buffer[2] = UNIT_ATTENTION;
-			starts[0] += 10;
-			starts[1] += 10;
-			starts[2] += 10;
-
-			*errstsp = (COMMAND_COMPLETE << 8) | 
-				   (CHECK_CONDITION << 1);
-			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
-			return 1;
-		}	/* End phony disk change code */
-#endif
 		nbytes -= bufflen;
 		if (SCpnt->use_sg) {
 			block += bufflen >> POW2_SECT_SIZE;
 			sgcount++;
 			if (nbytes) {
-				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				buff = scatg2virt(&sgpnt[sgcount]);
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_read: unexpected "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_read: unexpected "
 			       "nbytes=%d\n", nbytes);
 	} while (nbytes);
-	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	read_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		      struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -764,22 +721,19 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 
-	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+	write_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	if (SCpnt->use_sg) {
 		sgcount = 0;
 		sgpnt = (struct scatterlist *) buff;
-		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		buff = scatg2virt(&sgpnt[sgcount]);
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen);
 
@@ -788,104 +742,64 @@
 			block += bufflen >> POW2_SECT_SIZE;
 			sgcount++;
 			if (nbytes) {
-				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				buff = scatg2virt(&sgpnt[sgcount]);
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_write: "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_write: "
 			       "unexpected nbytes=%d\n", nbytes);
 	} while (nbytes);
-	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	write_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-/* A "high" level interrupt handler.  This should be called once per jiffy
- * to simulate a regular scsi disk.  We use a timer to do this. */
-
-static void scsi_debug_intr_handle(unsigned long indx)
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip)
 {
-	Scsi_Cmnd *SCtmp;
-	void (*my_done) (Scsi_Cmnd *);
-#if 0
-	del_timer(&timeout[indx]);
-#endif
+	unsigned int alloc_len;
+	int select_report = (int)cmd[2];
 
-	SCtmp = (Scsi_Cmnd *) SCint[indx];
-	my_done = do_done[indx];
-	do_done[indx] = NULL;
-	timeout[indx].function = NULL;
-	SCint[indx] = NULL;
-
-	if (!my_done) {
-		printk(KERN_ERR "scsi_debug_intr_handle: Unexpected "
-		       "interrupt\n");
-		return;
+	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);
 	}
-#if 0
-	printk(KERN_INFO "In intr_handle...");
-	printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies);
-	printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done);
-#endif
-
-	my_done(SCtmp);
-#if 0
-	printk(KERN_INFO "Called done.\n");
-#endif
+	if (bufflen > 3) {
+		memset(buff, 0, bufflen);
+		buff[3] = 8;
+	}
+	return 0;
 }
 
-static int initialized = 0;
-
-static int do_init(void)
+/* When timer goes off this function is called. */
+static void timer_intr_handler(unsigned long indx)
 {
-	int sz = STORE_SIZE;
-
-	starts[3] = CAPACITY;
-	fake_storep = vmalloc(sz);
-	if (NULL == fake_storep)
-		return 1;
-	memset(fake_storep, 0, sz);
-
-	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
-	do_done = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == do_done)
-		goto out;
-	memset((void *)do_done, 0, sz);
-
-	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
-	timeout = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == timeout)
-		goto out;
-	memset(timeout, 0, sz);
-
-	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
-	SCint = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == SCint)
-		goto out;
-	memset(SCint, 0, sz);
-
-	return 0;
-
-out:
-	if (fake_storep)
-		vfree(fake_storep);
-	if (do_done)
-		kfree((void *)do_done);
-	if (timeout)
-		kfree(timeout);
-	if (SCint)
-		kfree(SCint);
-	return 1;
-}
+	struct sdebug_queued_cmd * sqcp;
+	unsigned int iflags;
 
-static void do_end(void)
-{
-	kfree(SCint);
-	kfree(timeout);
-	kfree((void *)do_done);
-	vfree(fake_storep);
+	if (indx >= SCSI_DEBUG_CANQUEUE) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
+		       "large\n");
+		return;
+	}
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	sqcp = &queued_arr[(int)indx];
+	if (! sqcp->in_use) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
+		       "interrupt\n");
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return;
+	}
+	sqcp->in_use = 0;
+	if (sqcp->done_funct)
+		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
+	sqcp->done_funct = NULL;
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
+static int initialized = 0;
+static int num_present = 0;
+static const char * sdebug_proc_name = "scsi_debug";
 
 static int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
@@ -895,28 +809,41 @@
 		printk(KERN_INFO "scsi_debug: detect\n");
 	if (0 == initialized) {
 		++initialized;
-		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
-		devInfop = kmalloc(sz, GFP_ATOMIC);
+		sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = vmalloc(sz);
 		if (NULL == devInfop) {
 			printk(KERN_ERR "scsi_debug_detect: out of "
 			       "memory, 0.5\n");
 			return 0;
 		}
 		memset(devInfop, 0, sz);
-		if (do_init()) {
+		sz = STORE_SIZE;
+		fake_storep = vmalloc(sz);
+		if (NULL == fake_storep) {
 			printk(KERN_ERR "scsi_debug_detect: out of memory"
 			       ", 0\n");
 			return 0;
 		}
-		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
-			sense_buffers[k][0] = 0x70;
-		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
-			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
-			scsi_register(tpnt, 0);
+		memset(fake_storep, 0, sz);
+		init_all_queued();
+		tpnt->proc_name = (char *)sdebug_proc_name;
+		for (num_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
+			if (NULL == scsi_register(tpnt, 0))
+				printk(KERN_ERR "scsi_debug_detect: "
+					"scsi_register failed k=%d\n", k);
+			else
+				++num_present;
+		}
+#ifdef DRIVERFS_SUPPORT
+		if (num_present) {
+			sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
+			sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
+			driver_register(&sdebug_driverfs_driver);
+			do_create_driverfs_files();
 		}
-		return NR_HOSTS_PRESENT;
-	}
-	else {
+#endif
+		return num_present;
+	} else {
 		printk(KERN_WARNING "scsi_debug_detect: called again\n");
 		return 0;
 	}
@@ -929,51 +856,52 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: release\n");
+	stop_all_queued();
 	scsi_unregister(hpnt);
-	if (++num_releases != NR_HOSTS_PRESENT)
-		return 0;
-	do_end();
-	kfree(devInfop);
+	if (++num_releases == num_present) {
+#ifdef DRIVERFS_SUPPORT
+		do_remove_driverfs_files();
+		remove_driver(&sdebug_driverfs_driver);
+		// driver_unregister(&sdebug_driverfs_driver);
+#endif
+		vfree(fake_storep);
+		vfree(devInfop);
+	}
 	return 0;
 }
 
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
 {
 	int k;
-	unsigned short host_no, id;
-	Sdebug_dev_info * devip;
+	struct sdebug_dev_info * devip;
 
-	host_no = sdp->host->host_no;
-	id = (unsigned short)sdp->id;
 	for (k = 0; k < scsi_debug_num_devs; ++k) {
 		devip = &devInfop[k];
-		if (devip->sdp && (host_no == devip->host_no) &&
-		    (id == devip->id)) {
-			devip->sdp = sdp; /* overwrite previous sdp */
+		if (devip->sdp == sdp)
 			return devip;
-		}
+	}
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
 		if (NULL == devip->sdp) {
 			devip->sdp = sdp;
-			devip->host_no = host_no;
-			devip->id = id;
 			devip->reset = 1;
-			devip->sb_index = 0;
+			memset(devip->sense_buff, 0, SDEBUG_SENSE_LEN);
+			devip->sense_buff[0] = 0x70;
 			return devip;
 		}
 	}
 	return NULL;
 }
 
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen)
 {
-	char * sbuff;
-	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
-		return;
-	if (devip)
-		devip->sb_index = index;
-	sbuff = &sense_buffers[index][0];
-	memset(sbuff, 0, SENSE_BUFF_LEN);
+	unsigned char * sbuff;
+
+	sbuff = devip->sense_buff;
+	memset(sbuff, 0, SDEBUG_SENSE_LEN);
+	if (inbandLen > SDEBUG_SENSE_LEN)
+		inbandLen = SDEBUG_SENSE_LEN;
 	sbuff[0] = 0x70;
 	sbuff[2] = key;
 	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
@@ -985,30 +913,13 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: abort\n");
-#if 1
 	++num_aborts;
+	stop_queued_cmnd(SCpnt);
 	return SUCCESS;
-#else
-	int j;
-	void (*my_done) (Scsi_Cmnd *);
-	unsigned long iflags;
-	SCpnt->result = SCpnt->abort_reason << 16;
-	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
-		if (SCpnt == SCint[j]) {
-			my_done = do_done[j];
-			my_done(SCpnt);
-			spin_lock_irqsave(&mailbox_lock, iflags);
-			timeout[j] = 0;
-			SCint[j] = NULL;
-			do_done[j] = NULL;
-			spin_unlock_irqrestore(&mailbox_lock, iflags);
-		}
-	}
-	return SCSI_ABORT_SNOOZE;
-#endif
 }
 
-static int scsi_debug_biosparam(Disk * disk, struct block_device *dev, int *info)
+static int scsi_debug_biosparam(Disk * disk, struct block_device * bdev, 
+				int *info)
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: biosparam\n");
@@ -1067,12 +978,124 @@
 	++num_host_resets;
 	for (k = 0; k < scsi_debug_num_devs; ++k)
 		devInfop[k].reset = 1;
+	stop_all_queued();
 
 	return SUCCESS;
 }
 
+/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+}
+
+/* Deletes (stops) timers of all queued commands */
+static void stop_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && sqcp->a_cmnd) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+/* Initializes timers in queued array */
+static void init_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		init_timer(&sqcp->cmnd_timer);
+		sqcp->in_use = 0;
+		sqcp->a_cmnd = NULL;
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip,
+			 done_funct_t done, int scsi_result, int delta_jiff)
+{
+	int k, num; 
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: cmd ");
+		for (k = 0, num = cmnd->cmd_len; k < num; ++k)
+	            printk("%02x ", (int)cmnd->cmnd[k]);
+		printk("result=0x%x\n", scsi_result);
+	}
+	if (cmnd && devip) {
+		/* simulate autosense by this driver */
+		if (CHECK_CONDITION == status_byte(scsi_result))
+			memcpy(cmnd->sense_buffer, devip->sense_buff, 
+			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
+			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
+	}
+	if (delta_jiff <= 0) {
+		if (cmnd)
+			cmnd->result = scsi_result;
+		if (done)
+			done(cmnd);
+		return 0;
+	} else {
+		unsigned long iflags;
+		int k;
+		struct sdebug_queued_cmd * sqcp = NULL;
+
+		spin_lock_irqsave(&queued_arr_lock, iflags);
+		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+			sqcp = &queued_arr[k];
+			if (! sqcp->in_use)
+				break;
+		}
+		if (k >= SCSI_DEBUG_CANQUEUE) {
+			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
+			return 1;	/* report busy to mid level */
+		}
+		sqcp->in_use = 1;
+		sqcp->a_cmnd = cmnd;
+		sqcp->scsi_result = scsi_result;
+		sqcp->done_funct = done;
+		sqcp->cmnd_timer.function = timer_intr_handler;
+		sqcp->cmnd_timer.data = k;
+		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
+		add_timer(&sqcp->cmnd_timer);
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return 0;
+	}
+}
+
 #ifndef MODULE
-static int __init scsi_debug_num_devs_setup(char *str)
+static int __init num_devs_setup(char *str)
 {   
     int tmp; 
     
@@ -1086,10 +1109,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_num_devs=", num_devs_setup);
 
-__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
-
-static int __init scsi_debug_dev_size_mb_setup(char *str)
+static int __init dev_size_mb_setup(char *str)
 {   
     int tmp; 
     
@@ -1104,10 +1126,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_dev_size_mb=", dev_size_mb_setup);
 
-__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
-
-static int __init scsi_debug_opts_setup(char *str)
+static int __init opts_setup(char *str)
 {   
     int tmp; 
     
@@ -1122,8 +1143,41 @@
         return 0;
     }
 }
+__setup("scsi_debug_opts=", opts_setup);
+
+static int __init every_nth_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_every_nth = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_every_nth: usage "
+               "scsi_debug_every_nth=<n>\n"
+               "    timeout every nth command (when ...)\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_every_nth=", every_nth_setup);
+
+static int __init delay_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+	scsi_debug_delay = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_delay: usage "
+               "scsi_debug_delay=<n>\n"
+               "    delay response <n> jiffies\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_delay=", delay_setup);
 
-__setup("scsi_debug_opts=", scsi_debug_opts_setup);
 #endif
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
@@ -1134,10 +1188,11 @@
 MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
 MODULE_PARM(scsi_debug_opts, "i");
 MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->...");
-
-#ifdef MODULE_LICENSE
+MODULE_PARM(scsi_debug_every_nth, "i");
+MODULE_PARM_DESC(scsi_debug_every_nth, "timeout every nth command(def=100)");
+MODULE_PARM(scsi_debug_delay, "i");
+MODULE_PARM_DESC(scsi_debug_delay, "# of jiffies to delay response(def=1)");
 MODULE_LICENSE("GPL");
-#endif
 
 static char sdebug_info[256];
 
@@ -1172,17 +1227,21 @@
 		if (1 != sscanf(arr, "%d", &pos))
 			return -EINVAL;
 		scsi_debug_opts = pos;
+		if (SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts)
+                        scsi_debug_cmnd_count = 0;
 		return length;
 	}
 	begin = 0;
 	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
-	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n"
-	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
-	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
+	    "every_nth=%d(curr:%d)\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d, "
+	    "delay=%d\nnumber of aborts=%d, device_reset=%d, bus_resets=%d, " 
 	    "host_resets=%d\n",
 	    scsi_debug_version_str, scsi_debug_num_devs, 
-	    scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE,
-	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
+	    scsi_debug_cmnd_count,
+	    SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, scsi_debug_delay,
 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
 	if (pos < offset) {
 		len = 0;
@@ -1196,8 +1255,86 @@
 	return (len);
 }
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
+#ifdef DRIVERFS_SUPPORT
+static ssize_t sdebug_delay_read(struct device_driver * ddp, char * buf, 
+				 size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_delay);
+}
 
-#include "scsi_module.c"
+static ssize_t sdebug_delay_write(struct device_driver * ddp, 
+				  const char * buf, size_t count, loff_t off)
+{
+        int delay;
+	char work[20];
 
+        if (off)
+                return 0;
+        if (1 == sscanf(buf, "%10s", work)) {
+		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
+			scsi_debug_delay = delay;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_read, 
+	    sdebug_delay_write)
+
+static ssize_t sdebug_opts_read(struct device_driver * ddp, char * buf, 
+				size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "0x%x\n", scsi_debug_opts);
+}
+
+static ssize_t sdebug_opts_write(struct device_driver * ddp, 
+				 const char * buf, size_t count, loff_t off)
+{
+        int opts;
+	char work[20];
+
+        if (off)
+                return 0;
+        if (1 == sscanf(buf, "%10s", work)) {
+		if (0 == strnicmp(work,"0x", 2)) {
+			if (1 == sscanf(&work[2], "%x", &opts))
+				goto opts_done;
+		} else {
+			if (1 == sscanf(work, "%d", &opts))
+				goto opts_done;
+		}
+	}
+	return -EINVAL;
+opts_done:
+	scsi_debug_opts = opts;
+	return count;
+}
+
+DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_read, 
+	    sdebug_opts_write)
+
+static ssize_t sdebug_num_devs_read(struct device_driver * ddp, char * buf, 
+				    size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_num_devs);
+}
+
+DRIVER_ATTR(num_devs, S_IRUGO, sdebug_num_devs_read, NULL) 
+
+static void do_create_driverfs_files()
+{
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
+}
+
+static void do_remove_driverfs_files()
+{
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
+}
+#endif
+
+#include "scsi_module.c"
diff -Nru a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
--- a/drivers/scsi/scsi_debug.h	Tue Aug 27 12:28:05 2002
+++ b/drivers/scsi/scsi_debug.h	Tue Aug 27 12:28:05 2002
@@ -1,12 +1,15 @@
 #ifndef _SCSI_DEBUG_H
 
 #include <linux/types.h>
+#include <linux/kdev_t.h>
 
 static int scsi_debug_detect(Scsi_Host_Template *);
+static int scsi_debug_release(struct Scsi_Host *);
 /* static int scsi_debug_command(Scsi_Cmnd *); */
 static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int scsi_debug_abort(Scsi_Cmnd *);
+static int scsi_debug_ioctl(Scsi_Device *, int, void *);
 static int scsi_debug_biosparam(Disk *, struct block_device *, int[]);
+static int scsi_debug_abort(Scsi_Cmnd *);
 static int scsi_debug_bus_reset(Scsi_Cmnd *);
 static int scsi_debug_device_reset(Scsi_Cmnd *);
 static int scsi_debug_host_reset(Scsi_Cmnd *);
@@ -20,29 +23,29 @@
 /*
  * This driver is written for the lk 2.5 series
  */
-#define SCSI_DEBUG_CANQUEUE  255
+#define SCSI_DEBUG_CANQUEUE  255 	/* needs to be >= 1 */
 
 #define SCSI_DEBUG_MAX_CMD_LEN 16
 
-#define SCSI_DEBUG_TEMPLATE \
-		   {proc_info:         scsi_debug_proc_info,	\
-		    name:              "SCSI DEBUG",		\
-		    info:              scsi_debug_info,		\
-		    detect:            scsi_debug_detect,	\
-		    release:           scsi_debug_release,	\
-		    ioctl:             scsi_debug_ioctl,	\
-		    queuecommand:      scsi_debug_queuecommand, \
-		    eh_abort_handler:  scsi_debug_abort,	\
-		    eh_bus_reset_handler: scsi_debug_bus_reset,	\
-		    eh_device_reset_handler: scsi_debug_device_reset,	\
-		    eh_host_reset_handler: scsi_debug_host_reset,	\
-		    bios_param:        scsi_debug_biosparam,	\
-		    can_queue:         SCSI_DEBUG_CANQUEUE,	\
-		    this_id:           7,			\
-		    sg_tablesize:      64,			\
-		    cmd_per_lun:       3,			\
-		    unchecked_isa_dma: 0,			\
-		    use_clustering:    ENABLE_CLUSTERING,	\
-}
+static Scsi_Host_Template driver_template = {
+	.proc_info =		scsi_debug_proc_info,
+	.name =			"SCSI DEBUG",
+	.info =			scsi_debug_info,
+	.detect =		scsi_debug_detect,
+	.release =		scsi_debug_release,
+	.ioctl =		scsi_debug_ioctl,
+	.queuecommand =		scsi_debug_queuecommand,
+	.eh_abort_handler =	scsi_debug_abort,
+	.eh_bus_reset_handler = scsi_debug_bus_reset,
+	.eh_device_reset_handler = scsi_debug_device_reset,
+	.eh_host_reset_handler = scsi_debug_host_reset,
+	.bios_param =		scsi_debug_biosparam,
+	.can_queue =		SCSI_DEBUG_CANQUEUE,
+	.this_id =		7,
+	.sg_tablesize =		64,
+	.cmd_per_lun =		3,
+	.unchecked_isa_dma = 	0,
+	.use_clustering = 	ENABLE_CLUSTERING,
+};	/* the name 'driver_template' is used by scsi_module.c */
 
 #endif
diff -Nru a/drivers/scsi/scsi_mid_low_api.txt b/drivers/scsi/scsi_mid_low_api.txt
--- a/drivers/scsi/scsi_mid_low_api.txt	Tue Aug 27 12:28:08 2002
+++ b/drivers/scsi/scsi_mid_low_api.txt	Tue Aug 27 12:28:08 2002
@@ -34,12 +34,15 @@
 level driver. For it to work a declaration like this is needed before
 it is included:
     static Scsi_Host_Template driver_template = DRIVER_TEMPLATE;
-    /* DRIVER_TEMPLATE should contain pointers to supported interface
-       functions. Scsi_Host_Template is defined in hosts.h */
     #include "scsi_module.c"
 
+In this case "DRIVER_TEMPLATE" is defined to be a structure initializer
+that is placed in the driver header file by convention. It contains
+pointers to supported interface functions and other values.
+Scsi_Host_Template is defined in hosts.h . 
+
 The scsi_module.c assumes the name "driver_template" is appropriately
-defined. It contains 2 functions:
+defined. scsi_module.c contains 2 functions:
   1) init_this_scsi_driver() called during builtin and module driver
      initialization: invokes mid level's scsi_register_host()
   2) exit_this_scsi_driver() called during closedown: invokes
@@ -68,7 +71,7 @@
 /**
  *      bios_param - fetch head, sector, cylinder info for a disk
  *      @sdkp: pointer to disk structure (defined in sd.h)
- *      @dev: corresponds to dev_t of device file name (e.g. /dev/sdb)
+ *      @bdev: pointer to block device context (defined in fs.h)
  *      @params: three element array to place output:
  *              params[0] number of heads
  *              params[1] number of sectors
@@ -267,6 +270,8 @@
  *      unsupported ioctl() 'cmd' numbers should return -ENOTTY.
  *      However the mid level returns -EINVAL for unrecognized 'cmd'
  *      numbers when this function is not supplied by the driver.
+ *      Unfortunately some applications expect -EINVAL and react badly
+ *	when -ENOTTY is returned; stick with -EINVAL.
  **/
     int ioctl(Scsi_Device *sdp, int cmd, void *arg);
 
@@ -304,7 +309,10 @@
  *      @scp: pointer to scsi command object
  *      @done: function pointer to be invoked on completion
  *
- *      Returns 1 if the adapter is busy, else returns 0.
+ *      Returns 1 if the adapter (host) is busy, else returns 0. One
+ *		reason for an adapter to be busy is that the number
+ *		of outstanding queued commands is already equal to
+ *		Scsi_Host::can_queue .
  *
  *      Required: if Scsi_Host::can_queue is ever non-zero
  *                then this function is required.
@@ -324,6 +332,9 @@
  *      return value should be generated by this function. However, in
  *      this case, it should be placed in scp->result before this function 
  *      returns.
+ *      If a status of CHECK CONDITION is placed in "result" when the
+ *	'done' callback is invoked, then the lower level driver should 
+ *	perform autosense and fill in the Scsi_Cmnd::sense_buffer array.
  **/
     int queuecommand(Scsi_Cmnd * scp, void (*done)(Scsi_Cmnd *));
 
@@ -505,6 +516,28 @@
 (e.g. per scsi device) may be possible by juggling locks in
 queuecommand().
 
+Autosense
+=========
+Autosense (or auto-sense) is defined in the SAM-2 document as "the
+automatic return of sense data to the application client coincident
+with the completion of a SCSI command" when a status of CHECK CONDITION
+occurs. Lower level drivers should perform autosense. This should be
+done when the lower level driver detects a CHECK CONDITION status by either: 
+    a) instructing the SCSI protocol (e.g. SCSI Parallel Interface (SPI))
+       to perform an extra data in phase on such responses
+    b) or, the lower level driver issuing a REQUEST SENSE command itself
+
+Either way, the mid level decides whether the lower level driver has 
+performed autosense by checking Scsi_Cmnd::sense_buffer[0] . If this
+byte has an upper nibble of 7 then autosense is assumed to have taken 
+place. If it has another value (and this byte is initialized to 0 before
+each command) then the mid level will issue a REQUEST SENSE command.
+
+In the presence of queued commands the "nexus" that maintains sense
+buffer data from the command that failed until a following REQUEST SENSE
+may get out of synchronization. This is why it is best for the lower
+level driver to perform autosense.
+
 
 Changes since lk 2.4 series
 ===========================
@@ -514,6 +547,7 @@
 
 The older error handling mechanism has been removed. This means the
 lower level interface functions abort() and reset() have been removed.
+The Scsi_Host_Template::use_new_eh_code flag has been removed.
 
 In the 2.4 series the scsi subsystem configuration descriptions were 
 aggregated with the configuration descriptions from all other Linux 
@@ -532,4 +566,4 @@
 
 Douglas Gilbert
 dgilbert@interlog.com
-27th April 2002
+13th August 2002
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/scsi/scsi_scan.c	Tue Aug 27 12:28:08 2002
@@ -1,11 +1,28 @@
 /*
- *  scsi_scan.c Copyright (C) 2000 Eric Youngdale
+ * scsi_scan.c
  *
- *  Bus scan logic.
+ * Copyright (C) 2000 Eric Youngdale,
+ * Copyright (C) 2002 Patrick Mansfield
  *
- *  This used to live in scsi.c, but that file was just a laundry basket
- *  full of misc stuff.  This got separated out in order to make things
- *  clearer.
+ * The general scanning/probing algorithm is as follows, exceptions are
+ * made to it depending on device specific flags, compilation options, and
+ * global variable (boot or module load time) settings.
+ *
+ * A specific LUN is scanned via an INQUIRY command; if the LUN has a
+ * device attached, a Scsi_Device is allocated and setup for it.
+ *
+ * For every id of every channel on the given host:
+ *
+ * 	Scan LUN 0; if the target responds to LUN 0 (even if there is no
+ * 	device or storage attached to LUN 0):
+ *
+ * 		If LUN 0 has a device attached, allocate and setup a
+ * 		Scsi_Device for it.
+ *
+ * 		If target is SCSI-3 or up, issue a REPORT LUN, and scan
+ * 		all of the LUNs returned by the REPORT LUN; else,
+ * 		sequentially scan LUNs up until some maximum is reached,
+ * 		or a LUN is seen that cannot have a device attached to it.
  */
 
 #include <linux/config.h>
@@ -22,172 +39,180 @@
 #endif
 
 /*
- * Flags for irregular SCSI devices that need special treatment
+ * Flags for SCSI devices that need special treatment
  */
-#define BLIST_NOLUN		0x001	/* Don't scan for LUNs */
-#define BLIST_FORCELUN		0x002	/* Known to have LUNs, force sanning */
-#define BLIST_BORKEN		0x004	/* Flag for broken handshaking */
-#define BLIST_KEY		0x008	/* Needs to be unlocked by special command */
-#define BLIST_SINGLELUN		0x010	/* LUNs should better not be used in parallel */
+#define BLIST_NOLUN     	0x001	/* Only scan LUN 0 */
+#define BLIST_FORCELUN  	0x002	/* Known to have LUNs, force scanning */
+#define BLIST_BORKEN    	0x004	/* Flag for broken handshaking */
+#define BLIST_KEY       	0x008	/* unlock by special command */
+#define BLIST_SINGLELUN 	0x010	/* Do not use LUNs in parallel */
 #define BLIST_NOTQ		0x020	/* Buggy Tagged Command Queuing */
-#define BLIST_SPARSELUN		0x040	/* Non consecutive LUN numbering */
+#define BLIST_SPARSELUN 	0x040	/* Non consecutive LUN numbering */
 #define BLIST_MAX5LUN		0x080	/* Avoid LUNS >= 5 */
-#define BLIST_ISDISK		0x100	/* Treat as (removable) disk */
-#define BLIST_ISROM		0x200	/* Treat as (removable) CD-ROM */
-#define BLIST_LARGELUN		0x400	/* LUNs larger than 7 despite reporting as SCSI 2 */
-#define BLIST_INQUIRY_36	0x800	/* override additional length field */
-#define BLIST_INQUIRY_58	0x1000	/* ... for broken inquiry responses */
-
-/*
- * scan_scsis_single() return values.
- */
-#define SCSI_SCAN_NO_RESPONSE      0
-#define SCSI_SCAN_DEVICE_PRESENT   1
-#define SCSI_SCAN_DEVICE_ADDED     2
-
-static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(unsigned int channel, unsigned int dev,
-		unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2,
-		struct Scsi_Host *shpnt, char *scsi_result);
-static void scan_scsis_target(unsigned int channel, unsigned int dev,
-		Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt,
-		char *scsi_result);
-static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
-				struct Scsi_Host *shpnt);
-static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt);
+#define BLIST_ISROM     	0x100	/* Treat as (removable) CD-ROM */
+#define BLIST_LARGELUN		0x200	/* LUNs past 7 on a SCSI-2 device */
+#define BLIST_INQUIRY_36	0x400	/* override additional length field */
+#define BLIST_INQUIRY_58	0x800	/* ... for broken inquiry responses */
 
 struct dev_info {
 	const char *vendor;
 	const char *model;
-	const char *revision;	/* Latest revision known to be bad.  Not used yet */
+	const char *revision;	/* revision known to be bad, unused */
 	unsigned flags;
 };
 
 /*
- * This is what was previously known as the blacklist.  The concept
- * has been expanded so that we can specify other types of things we
- * need to be aware of.
+ * device_list: devices that require settings that differ from the
+ * default, includes black-listed (broken) devices.
  */
-static struct dev_info device_list[] =
-{
-/* The following devices are known not to tolerate a lun != 0 scan for
- * one reason or another.  Some will respond to all luns, others will
- * lock up.
- */
-	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* Locks up if probed for lun != 0 */
-	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},		/* Responds to all lun - dtg */
-	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},		/* responds to all lun */
-	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},		/* Locks up when LUN>0 polled */
-	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},		/* Locks-up sometimes when LUN>0 polled. */
-	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},		/* guess what? */
-	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* Responds to all lun */
-	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
-	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},		/* Responds to all lun */
-	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for aha152x controller, which causes
-								 * SCSI code to reset bus.*/
-	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for aha152x controller, which causes
-								 * SCSI code to reset bus.*/
-	{"SEAGATE", "ST296", "921", BLIST_NOLUN},		/* Responds to all lun */
-	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},		/* Responds to all lun */
+static struct dev_info device_list[] = {
+	/*
+	 * The following devices are known not to tolerate a lun != 0 scan
+	 * for one reason or another. Some will respond to all luns,
+	 * others will lock up.
+	 */
+	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* locks up */
+	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* locks up */
+	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},	/* responds to all lun */
+	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},	/* responds to all lun */
+	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* locks up */
+	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* responds to all lun */
+	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
+	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* responds to all lun */
+	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* locks up */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},
+	{"SEAGATE", "ST296", "921", BLIST_NOLUN},	/* responds to all lun */
+	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},	/* responds to all lun */
 	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
 	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
 	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
-	{"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN},
-	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for seagate controller, which causes
-								 * SCSI code to reset bus.*/
-	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* Responds to all lun */
-	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for seagate controller, which causes
-								 * SCSI code to reset bus.*/
-	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
-	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
-	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* Locks up when polled for lun != 0 */
-	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},		/* causes failed REQ SENSE, extra reset */
-	{"HP", "C1750A", "3226", BLIST_NOLUN},			/* scanjet iic */
-	{"HP", "C1790A", "", BLIST_NOLUN},			/* scanjet iip */
-	{"HP", "C2500A", "", BLIST_NOLUN},			/* scanjet iicx */
-	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0 extra reset */
-	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-	{"RELISYS", "Scorpio", "*", BLIST_NOLUN},		/* responds to all LUN */
-	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all LUN */
-
-/*
- * Other types of devices that have special flags.
- */
-	{"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN},
-	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
-	{"IOMEGA", "Io20S         *F", "*", BLIST_KEY},
-	{"INSITE", "Floptical   F*8I", "*", BLIST_KEY},
-	{"INSITE", "I325VM", "*", BLIST_KEY},
-	{"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"MICROP", "4110", "*", BLIST_NOTQ},			/* Buggy Tagged Queuing */
-	{"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
-	{"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
-	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
-	{"DEC","HSG80","*", BLIST_FORCELUN},
-	{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
-	{"COMPAQ","CR3500","*", BLIST_FORCELUN},
-	{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
- 	{"TOSHIBA","CDROM","*", BLIST_ISROM},
- 	{"TOSHIBA","CD-ROM","*", BLIST_ISROM},
-	{"MegaRAID", "LD", "*", BLIST_FORCELUN},
-	{"DGC",  "RAID",      "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
-	{"DGC",  "DISK",      "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) 
-	{"DELL", "PV660F",   "*", BLIST_SPARSELUN},
-	{"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
-	{"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
-	{"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
-	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
-	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
-	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN},   // CMD RAID Controller
-	{"CNSI", "G7324", "*", BLIST_SPARSELUN},     // Chaparral G7324 RAID
-	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
-	{"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN},
-	{"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN},
-	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
-	{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
-	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
-	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
-	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
-	{"COMPAQ", "MSA1000", "*", BLIST_FORCELUN},
-	{"HP", "C1557A", "*", BLIST_FORCELUN},
-	{"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
+	{"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN},
+	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},	/* locks up */
+	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},	/* locks up */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* responds to all lun */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* locks up */
+	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
+	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
+	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
+	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},	/* locks up */
+	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
+	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
+	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
 
 	/*
-	 * Must be at end of list...
+	 * Other types of devices that have special flags.
 	 */
-	{NULL, NULL, NULL}
+	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
+	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
+	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
+	{"INSITE", "I325VM", NULL, BLIST_KEY},
+	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"MICROP", "4110", NULL, BLIST_NOTQ},
+	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
+	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
+	{"DEC", "HSG80", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
+	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
+	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
+	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
+	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
+	{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
+	{"DELL", "PV660F   PSEUDO", NULL, BLIST_SPARSELUN},
+	{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN},	/* Dell PV 530F */
+	{"DELL", "PV530F", NULL, BLIST_SPARSELUN},
+	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
+	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
+	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
+	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
+	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
+	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
+	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
+	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
+	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", NULL, BLIST_FORCELUN},
+	{"HP", "C1557A", NULL, BLIST_FORCELUN},
+	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
 };
 
-static char * scsi_null_device_strs = "nullnullnullnull";
+#define ALLOC_FAILURE_MSG	KERN_ERR "%s: Allocation failure during" \
+	" SCSI scanning, some SCSI devices might not be configured\n"
+
+/*
+ * Prefix values for the SCSI id's (stored in driverfs name field)
+ */
+#define SCSI_UID_SER_NUM 'S'
+#define SCSI_UID_UNKNOWN 'Z'
+
+/*
+ * Return values of some of the scanning functions.
+ *
+ * SCSI_SCAN_NO_RESPONSE: no valid response received from the target, this
+ * includes allocation or general failures preventing IO from being sent.
+ *
+ * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is available
+ * on the given LUN.
+ *
+ * SCSI_SCAN_LUN_PRESENT: target responded, and a device is available on a
+ * given LUN.
+ */
+#define SCSI_SCAN_NO_RESPONSE		0
+#define SCSI_SCAN_TARGET_PRESENT	1
+#define SCSI_SCAN_LUN_PRESENT		2
+
+static char *scsi_null_device_strs = "nullnullnullnull";
 
-#define MAX_SCSI_LUNS 0xFFFFFFFF
+#define MAX_SCSI_LUNS	512
 
 #ifdef CONFIG_SCSI_MULTI_LUN
 static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
@@ -195,27 +220,10 @@
 static unsigned int max_scsi_luns = 1;
 #endif
 
-#ifdef CONFIG_SCSI_REPORT_LUNS
-/* 
- * max_scsi_report_luns: the maximum number of LUNS that will be
- * returned from the REPORT LUNS command. 8 times this value must
- * be allocated. In theory this could be up to an 8 byte value, but
- * in practice, the maximum number of LUNs suppored by any device
- * is about 16k.
- */
-static unsigned int max_scsi_report_luns = 128;
-#endif
-
 #ifdef MODULE
-
 MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
-
-#ifdef CONFIG_SCSI_REPORT_LUNS
-MODULE_PARM(max_scsi_report_luns, "i");
-MODULE_PARM_DESC(max_scsi_report_luns, "REPORT LUNS maximum number of LUNS received (should be between 1 and 16384)");
-#endif
-
+MODULE_PARM_DESC(max_scsi_luns,
+		 "last scsi LUN (should be between 1 and 2^32-1)");
 #else
 
 static int __init scsi_luns_setup(char *str)
@@ -226,7 +234,7 @@
 		max_scsi_luns = tmp;
 		return 1;
 	} else {
-		printk("scsi_luns_setup : usage max_scsi_luns=n "
+		printk(KERN_WARNING "scsi_luns_setup: usage max_scsi_luns=n "
 		       "(n should be between 1 and 2^32-1)\n");
 		return 0;
 	}
@@ -234,8 +242,25 @@
 
 __setup("max_scsi_luns=", scsi_luns_setup);
 
+#endif
+
 #ifdef CONFIG_SCSI_REPORT_LUNS
-static int __init max_scsi_report_luns_setup(char *str)
+/*
+ * max_scsi_report_luns: the maximum number of LUNS that will be
+ * returned from the REPORT LUNS command. 8 times this value must
+ * be allocated. In theory this could be up to an 8 byte value, but
+ * in practice, the maximum number of LUNs suppored by any device
+ * is about 16k.
+ */
+static unsigned int max_scsi_report_luns = 128;
+
+#ifdef MODULE
+MODULE_PARM(max_scsi_report_luns, "i");
+MODULE_PARM_DESC(max_scsi_report_luns,
+		 "REPORT LUNS maximum number of LUNS received (should be"
+		 " between 1 and 16384)");
+#else
+static int __init scsi_report_luns_setup(char *str)
 {
 	unsigned int tmp;
 
@@ -243,541 +268,1098 @@
 		max_scsi_report_luns = tmp;
 		return 1;
 	} else {
-		printk("scsi_report_luns_setup : usage max_scsi_report_luns=n "
-		       "(n should be between 1 and 16384)\n");
+		printk(KERN_WARNING "scsi_report_luns_setup: usage"
+		       " max_scsi_report_luns=n (n should be between 1"
+		       " and 16384)\n");
 		return 0;
 	}
 }
 
-__setup("max_scsi_report_luns=", max_scsi_report_luns_setup);
-#endif /* CONFIG_SCSI_REPORT_LUNS */
-
+__setup("max_scsi_report_luns=", scsi_report_luns_setup);
+#endif
 #endif
 
-#ifdef CONFIG_SCSI_REPORT_LUNS
-/*
- * Function:    scsilun_to_int
- *
- * Purpose:     Convert ScsiLun (8 byte LUN) to an int.
- *
- * Arguments:   scsilun_pnt - pointer to a ScsiLun to be converted
- *
- * Lock status: None
- *
- * Returns:     cpu ordered integer containing the truncated LUN value
- *
- * Notes:       The ScsiLun is assumed to be four levels, with each level
- * 		effectively containing a SCSI byte-ordered (big endidan)
- * 		short; the addressing bits of each level are ignored (the
- * 		highest two bits). For a description of the LUN format, post
- * 		SCSI-3 see the SCSI Architecture Model, for SCSI-3 see the
- * 		SCSI Controller Commands.
- *
- * 		Given a ScsiLun of: 0a 04 0b 03 00 00 00 00, this function
- * 		returns the integer: 0x0b030a04
- */
-static int scsilun_to_int(ScsiLun *scsilun_pnt) 
+/**
+ * scsi_unlock_floptical - unlock device via a special MODE SENSE command
+ * @sreq:	used to send the command
+ * @result:	area to store the result of the MODE SENSE
+ *
+ * Description:
+ *     Send a vendor specific MODE SENSE (not a MODE SELECT) command using
+ *     @sreq to unlock a device, storing the (unused) results into result.
+ *     Called for BLIST_KEY devices.
+ **/
+static void scsi_unlock_floptical(Scsi_Request *sreq, unsigned char *result)
 {
-	int i;
-	unsigned int lun;
+	Scsi_Device *sdscan = sreq->sr_device;
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
 
-	lun = 0;
-	for (i = 0; i < sizeof(lun); i += 2)
-		lun = lun | (((scsilun_pnt->scsi_lun[i] << 8) |
-			scsilun_pnt->scsi_lun[i + 1]) << (i * 8));
-	return lun;
+	printk(KERN_NOTICE "scsi: unlocking floptical drive\n");
+	scsi_cmd[0] = MODE_SENSE;
+	if (sdscan->scsi_level <= SCSI_2)
+		scsi_cmd[1] = (sdscan->lun << 5) & 0xe0;
+	else
+		scsi_cmd[1] = 0;
+	scsi_cmd[2] = 0x2e;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 0x2a;	/* size */
+	scsi_cmd[5] = 0;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) result, 0x2a /* size */,
+		      SCSI_TIMEOUT, 3);
 }
-#endif
 
-/* Driverfs file content handlers */
-static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page, 
+/**
+ * scsi_device_type_read - copy out the SCSI type
+ * @driverfs_dev:	driverfs device to check
+ * @page:		copy data into this area
+ * @count:		number of bytes to copy
+ * @off:		start at this offset in page
+ *
+ * Description:
+ *     Called via driverfs when the "type" (in scsi_device_type_file)
+ *     field is read. Copy the appropriate SCSI type string into @page,
+ *     followed by a newline and a '\0'. Go through gyrations so we don't
+ *     write more than @count, and we don't write past @off.
+ *
+ * Notes:
+ *     This is for the top-most scsi entry in driverfs, the upper-level
+ *     drivers have their own type file. XXX This is not part of scanning,
+ *     other than we reference the attr struct in this file, move to
+ *     scsi.c or scsi_lib.c.
+ *
+ * Return:
+ *     number of bytes written into page.
+ **/
+static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page,
 	size_t count, loff_t off)
 {
-	struct scsi_device *SDpnt = to_scsi_device(driverfs_dev);
-
-	if ((SDpnt->type <= MAX_SCSI_DEVICE_CODE) && 
-		(scsi_device_types[(int)SDpnt->type] != NULL))
-		return off ? 0 : 
-			sprintf(page, "%s\n", 
-				scsi_device_types[(int)SDpnt->type]);
+	struct scsi_device *sdev = to_scsi_device(driverfs_dev);
+	const char *type;
+	size_t size, len;
+
+	if ((sdev->type > MAX_SCSI_DEVICE_CODE) ||
+	    (scsi_device_types[(int)sdev->type] == NULL))
+		type = "Unknown";
 	else
-		return off ? 0 : sprintf(page, "UNKNOWN\n");
-
-	return 0;
+		type = scsi_device_types[(int)sdev->type];
+	size = strlen(type);
+	/*
+	 * Check if off is past size + 1 for newline + 1 for a '\0'.
+	 */
+	if (off >= (size + 2))
+		return 0;
+	if (size > off) {
+		len = min((size_t) (size - off), count);
+		memcpy(page + off, type + off, len);
+	} else
+		len = 0;
+	if (((len + off) == size) && (len < count))
+		/*
+		 * We are at the end of the string and have space, add a
+		 * new line.
+		 */
+		*(page + off + len++) = '\n';
+	if (((len + off) == (size + 1)) && (len < count))
+		/*
+		 * We are past the newline and have space, add a
+		 * terminating '\0'.
+		 */
+		*(page + off + len++) = '\0';
+	return len;
 }
-static DEVICE_ATTR(type,"type",S_IRUGO,scsi_device_type_read,NULL);
 
-/* end content handlers */
+/*
+ * Create dev_attr_type. This is different from the dev_attr_type in scsi
+ * upper level drivers.
+ */
+static DEVICE_ATTR(type,S_IRUGO,scsi_device_type_read,NULL);
 
-static void print_inquiry(unsigned char *data)
+
+/**
+ * print_inquiry - printk the inquiry information
+ * @inq_result:	printk this SCSI INQUIRY
+ *
+ * Description:
+ *     printk the vendor, model, and other information found in the
+ *     INQUIRY data in @inq_result.
+ *
+ * Notes:
+ *     Remove this, and replace with a hotplug event that logs any
+ *     relevant information.
+ **/
+static void print_inquiry(unsigned char *inq_result)
 {
 	int i;
 
-	printk("  Vendor: ");
-	for (i = 8; i < 16; i++) {
-		if (data[i] >= 0x20 && i < data[4] + 5)
-			printk("%c", data[i]);
+	printk(KERN_NOTICE "  Vendor: ");
+	for (i = 8; i < 16; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
 		else
 			printk(" ");
-	}
 
 	printk("  Model: ");
-	for (i = 16; i < 32; i++) {
-		if (data[i] >= 0x20 && i < data[4] + 5)
-			printk("%c", data[i]);
+	for (i = 16; i < 32; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
 		else
 			printk(" ");
-	}
 
 	printk("  Rev: ");
-	for (i = 32; i < 36; i++) {
-		if (data[i] >= 0x20 && i < data[4] + 5)
-			printk("%c", data[i]);
+	for (i = 32; i < 36; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
 		else
 			printk(" ");
-	}
 
 	printk("\n");
 
-	i = data[0] & 0x1f;
+	i = inq_result[0] & 0x1f;
 
-	printk("  Type:   %s ",
-	       i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          ");
-	printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
-	if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
+	printk(KERN_NOTICE "  Type:   %s ",
+	       i <
+	       MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
+	       "Unknown          ");
+	printk("                 ANSI SCSI revision: %02x",
+	       inq_result[2] & 0x07);
+	if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
 		printk(" CCS\n");
 	else
 		printk("\n");
 }
 
-static int get_device_flags(unsigned char *vendor_pnt, unsigned char *model_pnt)
+/**
+ * get_device_flags - get device specific flags from the device_list
+ * @vendor:	vendor name
+ * @model:	model name
+ *
+ * Description:
+ *     Search device_list for an entry matching @vendor and @model, if
+ *     found, return the matching flags value, else return 0.
+ *     Partial matches count as success - good for @model, but maybe not
+ *     @vendor.
+ **/
+static int get_device_flags(unsigned char *vendor, unsigned char *model)
 {
-	int i = 0;
-	for (i = 0; 1; i++) {
-		if (device_list[i].vendor == NULL)
-			return 0;
-		while (*vendor_pnt && *vendor_pnt == ' ')
-			vendor_pnt++;
-		if (memcmp(device_list[i].vendor, vendor_pnt,
-			   strlen(device_list[i].vendor)))
+	int i;
+	size_t max;
+
+	for (i = 0; i < ARRAY_SIZE(device_list); i++) {
+		/*
+		 * XXX why skip leading spaces? If an odd INQUIRY value,
+		 * that should have been part of the device_list[] entry,
+		 * such as "  FOO" rather than "FOO". Since this code is
+		 * already here, and we don't know what device it is
+		 * trying to work with, leave it as-is.
+		 */
+		max = 8;	/* max length of vendor */
+		while ((max > 0) && *vendor == ' ') {
+			max--;
+			vendor++;
+		}
+		/*
+		 * XXX removing the following strlen() would be good,
+		 * using it means that for a an entry not in the list, we
+		 * scan every byte of every vendor listed in
+		 * device_list[], and never match a single one (and still
+		 * have to compare at least the first byte of each
+		 * vendor).
+		 */
+		if (memcmp(device_list[i].vendor, vendor,
+			    min(max, strlen(device_list[i].vendor))))
 			continue;
-		while (*model_pnt && *model_pnt == ' ')
-			model_pnt++;
-		if (memcmp(device_list[i].model, model_pnt,
-			   strlen(device_list[i].model)))
+		/*
+		 * Skip spaces again.
+		 */
+		max = 16;	/* max length of model */
+		while ((max > 0) && *model == ' ') {
+			max--;
+			model++;
+		}
+		if (memcmp(device_list[i].model, model,
+			   min(max, strlen(device_list[i].model))))
 			continue;
 		return device_list[i].flags;
 	}
 	return 0;
 }
 
-/*
- *  Detecting SCSI devices :
- *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
- *  We use the INQUIRY command, determine device type, and pass the ID /
- *  lun address of all sequential devices to the tape driver, all random
- *  devices to the disk driver.
- */
-void scan_scsis(struct Scsi_Host *shpnt,
-		       uint hardcoded,
-		       uint hchannel,
-		       uint hid,
-		       uint hlun)
+/**
+ * scsi_alloc_sdev - allocate and setup a Scsi_Device
+ *
+ * Description:
+ *     Allocate, initialize for io, and return a pointer to a Scsi_Device.
+ *     Stores the @shost, @channel, @id, and @lun in the Scsi_Device, and
+ *     adds Scsi_Device to the appropriate list.
+ *
+ * Return value:
+ *     Scsi_Device pointer, or NULL on failure.
+ **/
+static Scsi_Device *scsi_alloc_sdev(struct Scsi_Host *shost, uint channel,
+				    uint id, uint lun)
 {
-	uint channel;
-	unsigned int dev;
-	unsigned int lun;
-	unsigned char *scsi_result;
-	unsigned char scsi_result0[256];
-	Scsi_Device *SDpnt;
-	Scsi_Device *SDtail;
-
-	scsi_result = NULL;
-
-	SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device),
-					GFP_ATOMIC);
-	if (SDpnt) {
-		memset(SDpnt, 0, sizeof(Scsi_Device));
-		SDpnt->vendor = scsi_null_device_strs;
-		SDpnt->model = scsi_null_device_strs;
-		SDpnt->rev = scsi_null_device_strs;
-		/*
-		 * Register the queue for the device.  All I/O requests will
-		 * come in through here.  We also need to register a pointer to
-		 * ourselves, since the queue handler won't know what device
-		 * the queue actually represents.   We could look it up, but it
-		 * is pointless work.
-		 */
-		scsi_initialize_queue(SDpnt, shpnt);
-		SDpnt->request_queue.queuedata = (void *) SDpnt;
-		/* Make sure we have something that is valid for DMA purposes */
-		scsi_result = ((!shpnt->unchecked_isa_dma)
-			       ? &scsi_result0[0] : kmalloc(512, GFP_DMA));
+	Scsi_Device *sdev;
+
+	sdev = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC);
+	if (sdev == NULL)
+		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+	else {
+		memset(sdev, 0, sizeof(Scsi_Device));
+		sdev->vendor = scsi_null_device_strs;
+		sdev->model = scsi_null_device_strs;
+		sdev->rev = scsi_null_device_strs;
+		sdev->host = shost;
+		sdev->id = id;
+		sdev->lun = lun;
+		sdev->channel = channel;
+		sdev->online = TRUE;
+		/*
+		 * Some low level driver could use device->type
+		 */
+		sdev->type = -1;
+		/*
+		 * Assume that the device will have handshaking problems,
+		 * and then fix this field later if it turns out it
+		 * doesn't
+		 */
+		sdev->borken = 1;
+		scsi_initialize_queue(sdev, shost);
+		sdev->request_queue.queuedata = (void *) sdev;
+
+		scsi_initialize_merge_fn(sdev);
+		init_waitqueue_head(&sdev->scpnt_wait);
+
+		/*
+		 * Add it to the end of the shost->host_queue list.
+		 */
+		if (shost->host_queue != NULL) {
+			sdev->prev = shost->host_queue;
+			while (sdev->prev->next != NULL)
+				sdev->prev = sdev->prev->next;
+			sdev->prev->next = sdev;
+		} else
+			shost->host_queue = sdev;
+
 	}
+	return (sdev);
+}
 
-	if (scsi_result == NULL) {
-		printk("Unable to obtain scsi_result buffer\n");
-		goto leave;
+/**
+ * scsi_free_sdev - cleanup and free a Scsi_Device
+ * @sdev:	cleanup and free this Scsi_Device
+ *
+ * Description:
+ *     Undo the actions in scsi_alloc_sdev, including removing @sdev from
+ *     the list, and freeing @sdev.
+ **/
+static void scsi_free_sdev(Scsi_Device *sdev)
+{
+	if (sdev->prev != NULL)
+		sdev->prev->next = sdev->next;
+	else
+		sdev->host->host_queue = sdev->next;
+	if (sdev->next != NULL)
+		sdev->next->prev = sdev->prev;
+
+	blk_cleanup_queue(&sdev->request_queue);
+	if (sdev->inquiry != NULL)
+		kfree(sdev->inquiry);
+	kfree(sdev);
+}
+
+/**
+ * scsi_check_id_size - check if size fits in the driverfs name
+ * @sdev:	Scsi_Device to use for error message
+ * @size:	the length of the id we want to store
+ *
+ * Description:
+ *     Use a function for this since the same code is used in various
+ *     places, and we only create one string and call to printk.
+ *
+ * Return:
+ *     0 - fits
+ *     1 - size too large
+ **/
+static int scsi_check_id_size(Scsi_Device *sdev, int size)
+{
+	if (size > DEVICE_NAME_SIZE) {
+		printk(KERN_WARNING "scsi scan: host %d channel %d id %d lun %d"
+		       " identifier too long, length %d, max %d. Device might"
+		       " be improperly identified.\n", sdev->host->host_no,
+		       sdev->channel, sdev->id, sdev->lun, size,
+		       DEVICE_NAME_SIZE);
+		return 1;
+	} else
+		return 0;
+}
+
+/**
+ * scsi_get_evpd_page - get a list of supported vpd pages
+ * @sdev:	Scsi_Device to send an INQUIRY VPD
+ * @sreq:	Scsi_Request associated with @sdev
+ *
+ * Description:
+ *     Get SCSI INQUIRY Vital Product Data page 0 - a list of supported
+ *     VPD pages.
+ *
+ * Return:
+ *     A pointer to data containing the results on success, else NULL.
+ **/
+unsigned char *scsi_get_evpd_page(Scsi_Device *sdev, Scsi_Request *sreq)
+{
+	unsigned char *evpd_page;
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+	int lun = sdev->lun;
+	int scsi_level = sdev->scsi_level;
+	int max_lgth = 255;
+
+retry:
+	evpd_page = kmalloc(max_lgth, GFP_ATOMIC |
+			      (sdev->host->unchecked_isa_dma) ?
+			      GFP_DMA : 0);
+	if (!evpd_page) {
+		printk(KERN_WARNING "scsi scan: Allocation failure identifying"
+		       " host %d channel %d id %d lun %d, device might be"
+		       " improperly identified.\n", sdev->host->host_no,
+		       sdev->channel, sdev->id, sdev->lun);
+		return NULL;
 	}
+
+	memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[4] = max_lgth;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_sense_buffer[0] = 0;
+	sreq->sr_sense_buffer[2] = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) evpd_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (sreq->sr_result) {
+		kfree(evpd_page);
+		return NULL;
+	}
+
 	/*
-	 * We must chain ourself in the host_queue, so commands can time out 
+	 * check to see if response was truncated
 	 */
-	SDpnt->queue_depth = 1;
-	SDpnt->host = shpnt;
-	SDpnt->online = TRUE;
+	if (evpd_page[3] > max_lgth) {
+		max_lgth = evpd_page[3] + 4;
+		kfree(evpd_page);
+		goto retry;
+	}
 
-	scsi_initialize_merge_fn(SDpnt);
+	/*
+	 * Some ill behaved devices return the standard inquiry here
+	 * rather than the evpd data, snoop the data to verify.
+	 */
+	if (evpd_page[3] > 16) {
+		/*
+		 * If the vendor id appears in the evpd page assume the
+		 * page is invalid.
+		 */
+		if (!strncmp(&evpd_page[8], sdev->vendor, 8)) {
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	return evpd_page;
+}
 
-        /*
-         * Initialize the object that we will use to wait for command blocks.
-         */
-	init_waitqueue_head(&SDpnt->scpnt_wait);
+
+/*
+ * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the
+ * SCSI Primary Commands specification for details.
+ *
+ * XXX The following defines should be in scsi.h
+ */
+
+/*
+ * id type values of id descriptors. These are assumed to fit in 4 bits,
+ * else the code using hex_str[id_type] needs modification.
+ */
+#define SCSI_ID_VENDOR_SPECIFIC	0
+#define SCSI_ID_T10_VENDOR	1
+#define SCSI_ID_EUI_64		2
+#define SCSI_ID_NAA		3
+
+/*
+ * Supported NAA values. These fit in 4 bits, so the don't care value
+ * cannot conflict with real values.
+ *
+ */
+#define	SCSI_ID_NAA_DONT_CARE		0xff
+#define	SCSI_ID_NAA_IEEE_REG		5
+#define	SCSI_ID_NAA_IEEE_REG_EXTENDED	6
+
+/*
+ * Supported Code Set values.
+ */
+#define	SCSI_ID_BINARY	1
+#define	SCSI_ID_ASCII	2
+
+/*
+ * Use a priority based list of id, naa, and binary/ascii for the
+ * identifier descriptor in VPD page 0x83.
+ *
+ * Brute force search for a match starting with the first value in
+ * id_search_list. This is not a performance issue, since there
+ * is normally one or some small number of descriptors.
+ */
+struct scsi_id_search_values {
+	int	id_type;
+	int	naa_type;
+	int	code_set;
+};
+
+static const struct scsi_id_search_values id_search_list[] = {
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_IEEE_REG_EXTENDED,	SCSI_ID_BINARY },
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_IEEE_REG_EXTENDED,	SCSI_ID_ASCII },
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_IEEE_REG,	SCSI_ID_BINARY },
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_IEEE_REG,	SCSI_ID_ASCII },
+	/*
+	 * Devices already exist using NAA values that are now marked
+	 * reserved. These should not conflict with other values, or it is
+	 * a bug in the device. As long as we find the IEEE extended one
+	 * first, we really don't care what other ones are used. Using
+	 * don't care here means that a device that returns multiple
+	 * non-IEEE descriptors in a random order will get different
+	 * names.
+	 */
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_BINARY },
+	{ SCSI_ID_NAA,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_ASCII },
+	{ SCSI_ID_EUI_64,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_BINARY },
+	{ SCSI_ID_EUI_64,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_ASCII },
+	{ SCSI_ID_T10_VENDOR,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_BINARY },
+	{ SCSI_ID_T10_VENDOR,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_ASCII },
+	{ SCSI_ID_VENDOR_SPECIFIC,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_BINARY },
+	{ SCSI_ID_VENDOR_SPECIFIC,	SCSI_ID_NAA_DONT_CARE,	SCSI_ID_ASCII },
+};
+
+/**
+ * scsi_check_fill_deviceid - check the id and if OK fill it
+ * @sdev:	device to use for error messages
+ * @id_page:	id descriptor for INQUIRY VPD DEVICE ID, page 0x83
+ * @name:	store the id in name
+ * @id_search:	store if the id_page matches these values
+ *
+ * Description:
+ *     Check if @id_page matches the @id_search, if so store an id (uid)
+ *     into name.
+ *
+ * Return:
+ *     0: Success
+ *     1: No match
+ *     2: Failure due to size constraints
+ **/
+static int scsi_check_fill_deviceid(Scsi_Device *sdev, char *id_page,
+	char *name, const struct scsi_id_search_values *id_search)
+{
+	static const char hex_str[]="0123456789abcdef";
+	int i, j;
 
 	/*
-	 * Next, hook the device to the host in question.
+	 * ASSOCIATION must be with the device (value 0)
 	 */
-	SDpnt->prev = NULL;
-	SDpnt->next = NULL;
-	if (shpnt->host_queue != NULL) {
-		SDtail = shpnt->host_queue;
-		while (SDtail->next != NULL)
-			SDtail = SDtail->next;
+	if ((id_page[1] & 0x30) != 0)
+		return 1;
 
-		SDtail->next = SDpnt;
-		SDpnt->prev = SDtail;
-	} else {
-		shpnt->host_queue = SDpnt;
+	if ((id_page[1] & 0x0f) != id_search->id_type)
+		return 1;
+	/*
+	 * Possibly check NAA sub-type.
+	 */
+	if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) &&
+	    (id_search->naa_type != (id_page[4] & 0xf0) >> 4)) {
+		return 1;
 	}
 
 	/*
-	 * We need to increment the counter for this one device so we can track
-	 * when things are quiet.
+	 * Check for matching code set - ASCII or BINARY.
 	 */
-	if (hardcoded == 1) {
-		Scsi_Device *oldSDpnt = SDpnt;
-		struct Scsi_Device_Template *sdtpnt;
-		unsigned int lun0_sl;
-
-		channel = hchannel;
-		if (channel > shpnt->max_channel)
-			goto leave;
-		dev = hid;
-		if (dev >= shpnt->max_id)
-			goto leave;
-		lun = hlun;
-		if (lun >= shpnt->max_lun)
-			goto leave;
-		if ((0 == lun) || (lun > 7))
-			lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
-		else
-			lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
-		scan_scsis_single(channel, dev, lun, lun0_sl, &SDpnt, shpnt,
-				  scsi_result);
-		if (SDpnt != oldSDpnt) {
-
-			/* it could happen the blockdevice hasn't yet been inited */
-			/* queue_depth() moved from scsi_proc_info() so that
-			   it is called before scsi_build_commandblocks() */
-			if (shpnt->select_queue_depths != NULL)
-				(shpnt->select_queue_depths)(shpnt,
-							     shpnt->host_queue);
-
-			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-				if (sdtpnt->init && sdtpnt->dev_noticed)
-					(*sdtpnt->init) ();
-
-			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-				if (sdtpnt->attach) {
-					(*sdtpnt->attach) (oldSDpnt);
-					if (oldSDpnt->attached) {
-						scsi_build_commandblocks(oldSDpnt);
-						if (0 == oldSDpnt->has_cmdblocks) {
-							printk("scan_scsis: DANGER, no command blocks\n");
-							/* What to do now ?? */
-						}
-					}
-				}
-			}
-			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-				if (sdtpnt->finish && sdtpnt->nr_dev) {
-					(*sdtpnt->finish) ();
-				}
-			}
-		}
-	} else {
-		/* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
-		int order_dev;
-
-		for (channel = 0; channel <= shpnt->max_channel; channel++) {
-			for (dev = 0; dev < shpnt->max_id; ++dev) {
-				if (shpnt->reverse_ordering)
-					/* Shift to scanning 15,14,13... or 7,6,5,4, */
-					order_dev = shpnt->max_id - dev - 1;
-				else
-					order_dev = dev;
+	if ((id_page[0] & 0x0f) != id_search->code_set)
+		return 1;
 
-				if (shpnt->this_id != order_dev) {
-					scan_scsis_target(channel, order_dev,
-						&SDpnt, shpnt, scsi_result);
-				}
+	name[0]  = hex_str[id_search->id_type];
+	if ((id_page[0] & 0x0f) == SCSI_ID_ASCII) {
+		/*
+		 * ASCII descriptor.
+		 */
+		if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) {
+			/*
+			 * Prepend the vendor and model before the id,
+			 * since the id might not be unique across all
+			 * vendors and models. The same code is used
+			 * below, with a differnt size.
+			 *
+			 * Need 1 byte for the idtype, 1 for trailing
+			 * '\0', 8 for vendor, 16 for model total 26, plus
+			 * the name descriptor length.
+			 */
+			if (scsi_check_id_size(sdev, 26 + id_page[3]))
+				return 2;
+			else {
+				strncat(name, sdev->vendor, 8);
+				strncat(name, sdev->model, 16);
 			}
+		} else if (scsi_check_id_size (sdev, (2 + id_page[3])))
+			/*
+			 * Need 1 byte for the idtype, 1 byte for
+			 * the trailing '\0', plus the descriptor length.
+			 */
+			return 2;
+		memcpy(&name[strlen(name)], &id_page[4], id_page[3]);
+		return 0;
+	} else if ((id_page[0] & 0x0f) == SCSI_ID_BINARY) {
+		if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) {
+			/*
+			 * Prepend the vendor and model before the id.
+			 */
+			if (scsi_check_id_size(sdev, 26 + (id_page[3] * 2)))
+				return 2;
+			else {
+				strncat(name, sdev->vendor, 8);
+				strncat(name, sdev->model, 16);
+			}
+		} else if (scsi_check_id_size(sdev, 2 + (id_page[3] * 2)))
+			/*
+			 * Need 1 byte for the idtype, 1 for trailing
+			 * '\0', 8 for vendor, 16 for model total 26, plus
+			 * the name descriptor length.
+			 */
+			return 2;
+		/*
+		 * Binary descriptor, convert to ASCII, using two bytes of
+		 * ASCII for each byte in the id_page. Store starting at
+		 * the end of name.
+		 */
+		for(i = 4, j = strlen(name); i < 4 + id_page[3]; i++) {
+			name[j++] = hex_str[(id_page[i] & 0xf0) >> 4];
+			name[j++] = hex_str[id_page[i] & 0x0f];
 		}
-	}			/* if/else hardcoded */
-
-      leave:
+		return 0;
+	}
+	/*
+	 * Code set must have already matched.
+	 */
+	printk(KERN_ERR "scsi scan: scsi_check_fill_deviceid unexpected state.\n");
+	return 1;
+}
 
-	{			/* Unchain SRpnt from host_queue */
-		Scsi_Device *prev, *next;
-		Scsi_Device *dqptr;
+/**
+ * scsi_get_deviceid - get a device id using INQUIRY VPD page 0x83
+ * @sdev:	get the identifer of this device
+ * @sreq:	Scsi_Requeset associated with @sdev
+ *
+ * Description:
+ *     Try to get an id (serial number) for device @sdev using a SCSI
+ *     Vital Product Data page 0x83 (device id).
+ *
+ * Return:
+ *     0: Failure
+ *     1: Success
+ **/
+int scsi_get_deviceid(Scsi_Device *sdev, Scsi_Request *sreq)
+{
+	unsigned char *id_page;
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+	int id_idx, scnt, ret;
+	int lun = sdev->lun;
+	int scsi_level = sdev->scsi_level;
+	int max_lgth = 255;
+
+retry:
+	id_page = kmalloc(max_lgth, GFP_ATOMIC |
+			      (sdev->host->unchecked_isa_dma) ?
+			      GFP_DMA : 0);
+	if (!id_page) {
+		printk(KERN_WARNING "scsi scan: Allocation failure identifying"
+		       " host %d channel %d id %d lun %d, device might be"
+		       " improperly identified.\n", sdev->host->host_no,
+		       sdev->channel, sdev->id, sdev->lun);
+		return 0;
+	}
 
-		for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)
-			continue;
-		if (dqptr) {
-			prev = dqptr->prev;
-			next = dqptr->next;
-			if (prev)
-				prev->next = next;
-			else
-				shpnt->host_queue = next;
-			if (next)
-				next->prev = prev;
-		}
+	memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x83;
+	scsi_cmd[4] = max_lgth;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_sense_buffer[0] = 0;
+	sreq->sr_sense_buffer[2] = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) id_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+	if (sreq->sr_result) {
+		ret = 0;
+		goto leave;
 	}
 
-	/* Last device block does not exist.  Free memory. */
-	if (SDpnt != NULL) {
-		blk_cleanup_queue(&SDpnt->request_queue);
-		if (SDpnt->inquiry)
-			kfree(SDpnt->inquiry);
-		kfree((char *) SDpnt);
+	/*
+	 * check to see if response was truncated
+	 */
+	if (id_page[3] > max_lgth) {
+		max_lgth = id_page[3] + 4;
+		kfree(id_page);
+		goto retry;
 	}
 
-	/* If we allocated a buffer so we could do DMA, free it now */
-	if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
-		kfree(scsi_result);
-	} {
-		Scsi_Device *sdev;
-		Scsi_Cmnd *scmd;
-
-		SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt));
-		for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) {
-			SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev));
-			for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
-				SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd));
+	/*
+	 * Search for a match in the proiritized id_search_list.
+	 */
+	for (id_idx = 0; id_idx < ARRAY_SIZE(id_search_list); id_idx++) {
+		/*
+		 * Examine each descriptor returned. There is normally only
+		 * one or a small number of descriptors.
+		 */
+		for(scnt = 4; scnt <= id_page[3] + 3;
+			scnt += id_page[scnt + 3] + 4) {
+			if ((scsi_check_fill_deviceid(sdev, &id_page[scnt],
+			     sdev->sdev_driverfs_dev.name,
+			     &id_search_list[id_idx])) == 0) {
+				SCSI_LOG_SCAN_BUS(4, printk(KERN_INFO
+				  "scsi scan: host %d channel %d id %d lun %d"
+				  " used id desc %d/%d/%d\n",
+				  sdev->host->host_no, sdev->channel,
+				  sdev->id, sdev->lun,
+				  id_search_list[id_idx].id_type,
+				  id_search_list[id_idx].naa_type,
+				  id_search_list[id_idx].code_set));
+				ret = 1;
+				goto leave;
+			} else {
+				SCSI_LOG_SCAN_BUS(4, printk(KERN_INFO
+				  "scsi scan: host %d channel %d id %d lun %d"
+				  " no match/error id desc %d/%d/%d\n",
+				  sdev->host->host_no, sdev->channel,
+				  sdev->id, sdev->lun,
+				  id_search_list[id_idx].id_type,
+				  id_search_list[id_idx].naa_type,
+				  id_search_list[id_idx].code_set));
 			}
-			SCSI_LOG_SCAN_BUS(4, printk("\n"));
+			/*
+			 * scsi_check_fill_deviceid can fill the first
+			 * byte of name with a non-zero value, reset it.
+			 */
+			sdev->sdev_driverfs_dev.name[0] = '\0';
 		}
 	}
+	ret = 0;
+
+  leave:
+	kfree(id_page);
+	return ret;
 }
 
-/*
- * Function:    scan_scsis_single
- *
- * Purpose:     Determine if a SCSI device (a single LUN) exists, and
- * 		configure it into the system.
- *
- * Arguments:   channel    - the host's channel
- * 		dev        - target dev (target id)
- * 		lun        - LUN
- * 		scsi_level - SCSI 1, 2 or 3
- * 		SDpnt2     - pointer to pointer of a preallocated Scsi_Device
- * 		shpnt      - host device to use
- * 		scsi_result - preallocated buffer for the SCSI command result
- *
- * Lock status: None
- *
- * Returns:     SCSI_SCAN_NO_RESPONSE - no valid response received from the
- * 		device, this includes allocation failures preventing IO from
- * 		being sent, or any general failures.
- *
- *		SCSI_SCAN_DEVICE_PRESENT - device responded, SDpnt2 has all
- *		values needed to send IO set, plus scsi_level is set, but no
- *		new Scsi_Device was added/allocated.
- *
- *   		SCSI_SCAN_DEVICE_ADDED - device responded, and added to list;
- *   		SDpnt2 filled, and pointed to new allocated Scsi_Device.
- *
- * Notes:       This could be cleaned up more by moving SDpnt2 and Scsi_Device
- * 		allocation into scan_scsis_target.
- */
-static int scan_scsis_single(unsigned int channel, unsigned int dev,
-		unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2,
-		struct Scsi_Host *shpnt, char *scsi_result)
+/**
+ * scsi_get_serialnumber - get a serial number using INQUIRY page 0x80
+ * @sdev:	get the serial number of this device
+ * @sreq:	Scsi_Requeset associated with @sdev
+ *
+ * Description:
+ *     Send a SCSI INQUIRY page 0x80 to @sdev to get a serial number.
+ *
+ * Return:
+ *     0: Failure
+ *     1: Success
+ **/
+int scsi_get_serialnumber(Scsi_Device *sdev, Scsi_Request *sreq)
 {
-	char devname[64];
+	unsigned char *serialnumber_page;
 	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
-	struct Scsi_Device_Template *sdtpnt;
-	Scsi_Device *SDtail, *SDpnt = *SDpnt2;
-	Scsi_Request * SRpnt;
-	int bflags, type = -1;
-	int possible_inq_resp_len;
-	extern devfs_handle_t scsi_devfs_handle;
+	int lun = sdev->lun;
+	int scsi_level = sdev->scsi_level;
+	int max_lgth = 255;
+
+ retry:
+	serialnumber_page = kmalloc(max_lgth, GFP_ATOMIC |
+			      (sdev->host->unchecked_isa_dma) ?
+			      GFP_DMA : 0);
+	if (!serialnumber_page) {
+		printk(KERN_WARNING "scsi scan: Allocation failure identifying"
+		       " host %d channel %d id %d lun %d, device might be"
+		       " improperly identified.\n", sdev->host->host_no,
+		       sdev->channel, sdev->id, sdev->lun);
+		return 0;
+	}
 
-	SDpnt->host = shpnt;
-	SDpnt->id = dev;
-	SDpnt->lun = lun;
-	SDpnt->channel = channel;
-	SDpnt->online = TRUE;
-
-	scsi_build_commandblocks(SDpnt);
- 
-	/* Some low level driver could use device->type (DB) */
-	SDpnt->type = -1;
-
-	/*
-	 * Assume that the device will have handshaking problems, and then fix
-	 * this field later if it turns out it doesn't
-	 */
-	SDpnt->borken = 1;
-	SDpnt->was_reset = 0;
-	SDpnt->expecting_cc_ua = 0;
-	SDpnt->starved = 0;
-
-	if (NULL == (SRpnt = scsi_allocate_request(SDpnt))) {
-		printk("scan_scsis_single: no memory\n");
-		scsi_release_commandblocks(SDpnt);
-		return SCSI_SCAN_NO_RESPONSE;
+	memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x80;
+	scsi_cmd[4] = max_lgth;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_sense_buffer[0] = 0;
+	sreq->sr_sense_buffer[2] = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) serialnumber_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (sreq->sr_result)
+		goto leave;
+	/*
+	 * check to see if response was truncated
+	 */
+	if (serialnumber_page[3] > max_lgth) {
+		max_lgth = serialnumber_page[3] + 4;
+		kfree(serialnumber_page);
+		goto retry;
 	}
 
 	/*
-	 * We used to do a TEST_UNIT_READY before the INQUIRY but that was 
-	 * not really necessary.  Spec recommends using INQUIRY to scan for
-	 * devices (and TEST_UNIT_READY to poll for media change). - Paul G.
+	 * Need 1 byte for SCSI_UID_SER_NUM, 1 for trailing '\0', 8 for
+	 * vendor, 16 for model = 26, plus serial number size.
 	 */
+	if (scsi_check_id_size (sdev, (26 + serialnumber_page[3])))
+		goto leave;
+	sdev->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
+	strncat(sdev->sdev_driverfs_dev.name, sdev->vendor, 8);
+	strncat(sdev->sdev_driverfs_dev.name, sdev->model, 16);
+	strncat(sdev->sdev_driverfs_dev.name, &serialnumber_page[4],
+		serialnumber_page[3]);
+	kfree(serialnumber_page);
+	return 1;
+ leave:
+	memset(sdev->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	kfree(serialnumber_page);
+	return 0;
+}
+
+/**
+ * scsi_get_default_name - get a default name
+ * @sdev:	get a default name for this device
+ *
+ * Description:
+ *     Set the name of @sdev to the concatenation of the vendor, model,
+ *     and revision found in @sdev.
+ *
+ * Return:
+ *     1: Success
+ **/
+int scsi_get_default_name(Scsi_Device *sdev)
+{
+	if (scsi_check_id_size(sdev, 29))
+		return 0;
+	else {
+		sdev->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
+		strncpy(&sdev->sdev_driverfs_dev.name[1], sdev->vendor, 8);
+		strncat(sdev->sdev_driverfs_dev.name, sdev->model, 16);
+		strncat(sdev->sdev_driverfs_dev.name, sdev->rev, 4);
+		return 1;
+	}
+}
 
-	SCSI_LOG_SCAN_BUS(3,
-		printk("scsi scan: INQUIRY to host %d channel %d id %d lun %d\n",
-		       shpnt->host_no, channel, dev, lun)
-	);
+/**
+ * scsi_load_identifier:
+ * @sdev:	get an identifier (name) of this device
+ * @sreq:	Scsi_Requeset associated with @sdev
+ *
+ * Description:
+ *     Determine what INQUIRY pages are supported by @sdev, and try the
+ *     different pages until we get an identifier, or no other pages are
+ *     left. Start with page 0x83 (device id) and then try page 0x80
+ *     (serial number). If neither of these pages gets an id, use the
+ *     default naming convention.
+ *
+ *     The first character of sdev_driverfs_dev.name is SCSI_UID_SER_NUM
+ *     (S) if we used page 0x80, SCSI_UID_UNKNOWN (Z) if we used the
+ *     default name, otherwise it starts with the page 0x83 id type
+ *     (see the SCSI Primary Commands specification for details).
+ *
+ * Notes:
+ *     If a device returns the same serial number for different LUNs or
+ *     even for different LUNs on different devices, special handling must
+ *     be added to get an id, or a new black list flag must to added and
+ *     used in device_list[] (so we use the default name, or add a way to
+ *     prefix the id/name with SCSI_UID_UNKNOWN - and change the define to
+ *     something meaningful like SCSI_UID_NOT_UNIQUE). Complete user level
+ *     scanning would be nice for such devices, so we do not need device
+ *     specific code in the kernel.
+ **/
+static void scsi_load_identifier(Scsi_Device *sdev, Scsi_Request *sreq)
+{
+	unsigned char *evpd_page = NULL;
+	int cnt;
 
+	memset(sdev->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	evpd_page = scsi_get_evpd_page(sdev, sreq);
+	if (evpd_page == NULL) {
+		/*
+		 * try to obtain serial number anyway
+		 */
+		(void)scsi_get_serialnumber(sdev, sreq);
+	} else {
+		/*
+		 * XXX search high to low, since the pages are lowest to
+		 * highest - page 0x83 will be after page 0x80.
+		 */
+		for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++)
+			if (evpd_page[cnt] == 0x83)
+				if (scsi_get_deviceid(sdev, sreq))
+					goto leave;
+
+		for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++)
+			if (evpd_page[cnt] == 0x80)
+				if (scsi_get_serialnumber(sdev, sreq))
+					goto leave;
+
+		if (sdev->sdev_driverfs_dev.name[0] == 0)
+			scsi_get_default_name(sdev);
+
+	}
+leave:
+	if (evpd_page) kfree(evpd_page);
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: host %d channel %d"
+	    " id %d lun %d name/id: '%s'\n", sdev->host->host_no,
+	    sdev->channel, sdev->id, sdev->lun, sdev->sdev_driverfs_dev.name));
+	return;
+}
+
+/**
+ * scsi_find_scsi_level - return the scsi_level of a matching target
+ *
+ * Description:
+ *     Return the scsi_level of any Scsi_Device matching @channel, @id,
+ *     and @shost.
+ * Notes:
+ *     Needs to issue an INQUIRY to LUN 0 if no Scsi_Device matches, and
+ *     if the INQUIRY can't be sent return a failure.
+ **/
+static int scsi_find_scsi_level(unsigned int channel, unsigned int id,
+				struct Scsi_Host *shost)
+{
+	int res = SCSI_2;
+	Scsi_Device *sdev;
+
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next)
+		if ((id == sdev->id) && (channel == sdev->channel))
+			return (int) sdev->scsi_level;
 	/*
-	 * Build an INQUIRY command block.
+	 * FIXME No matching target id is configured, this needs to get
+	 * the INQUIRY for LUN 0, and use it to determine the scsi_level.
 	 */
+	return res;
+}
+
+/**
+ * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
+ * @sreq:	used to send the INQUIRY
+ * @inq_result:	area to store the INQUIRY result
+ * @bflags:	store any bflags found here
+ *
+ * Description:
+ *     Probe the lun associated with @sreq using a standard SCSI INQUIRY;
+ *
+ *     If the INQUIRY is successful, sreq->sr_result is zero and: the
+ *     INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
+ *     are copied to the Scsi_Device at @sreq->sr_device (sdev);
+ *     any device_list flags value is stored in *@bflags.
+ **/
+static void scsi_probe_lun(Scsi_Request *sreq, char *inq_result,
+			   int *bflags)
+{
+	Scsi_Device *sdev = sreq->sr_device;	/* a bit ugly */
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+	int possible_inq_resp_len;
+
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY to host %d"
+			" channel %d id %d lun %d\n", sdev->host->host_no,
+			sdev->channel, sdev->id, sdev->lun));
+
 	memset(scsi_cmd, 0, 6);
 	scsi_cmd[0] = INQUIRY;
-	if ((lun > 0) && (scsi_level <= SCSI_2))
-		scsi_cmd[1] = (lun << 5) & 0xe0;
+	if ((sdev->lun > 0) && (sdev->scsi_level <= SCSI_2))
+		scsi_cmd[1] = (sdev->lun << 5) & 0xe0;
 	scsi_cmd[4] = 36;	/* issue conservative alloc_length */
-	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
 
-	memset(scsi_result, 0, 36);
-	scsi_wait_req (SRpnt, (void *) scsi_cmd,
-	          (void *) scsi_result,
-	          36, SCSI_TIMEOUT+4*HZ, 3);
-
-	SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
-		SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result));
-
-	/*
-	 * Now that we don't do TEST_UNIT_READY anymore, we must be prepared
-	 * for media change conditions here, so cannot require zero result.
-	 */
-	if (SRpnt->sr_result) {
-		if ((driver_byte(SRpnt->sr_result) & DRIVER_SENSE) != 0 &&
-		    (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION &&
-		    SRpnt->sr_sense_buffer[12] == 0x28 &&
-		    SRpnt->sr_sense_buffer[13] == 0) {
+	memset(inq_result, 0, 36);
+	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result, 36,
+		      SCSI_TIMEOUT + 4 * HZ, 3);
+
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: 1st INQUIRY %s with"
+			" code 0x%x\n", sreq->sr_result ?
+			"failed" : "successful", sreq->sr_result));
+
+	if (sreq->sr_result) {
+		if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) != 0 &&
+		    (sreq->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION &&
+		    sreq->sr_sense_buffer[12] == 0x28 &&
+		    sreq->sr_sense_buffer[13] == 0) {
 			/* not-ready to ready transition - good */
-	 		/* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */
-		} else {
-			/* assume no peripheral if any other sort of error */
-			scsi_release_request(SRpnt);
-			return 0;
-		}
+			/* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */
+		} else
+			/*
+			 * assume no peripheral if any other sort of error
+			 */
+			return;
 	}
 
 	/*
-	 * Get any flags for this device.  
+	 * Get any flags for this device.
+	 *
+	 * XXX add a bflags to Scsi_Device, and replace the corresponding
+	 * bit fields in Scsi_Device, so bflags need not be passed as an
+	 * argument.
 	 */
-	bflags = get_device_flags (&scsi_result[8], &scsi_result[16]);
+	BUG_ON(bflags == NULL);
+	*bflags = get_device_flags(&inq_result[8], &inq_result[16]);
 
-	possible_inq_resp_len = (unsigned char)scsi_result[4] + 5;
-	if (BLIST_INQUIRY_36 & bflags)
+	possible_inq_resp_len = (unsigned char) inq_result[4] + 5;
+	if (BLIST_INQUIRY_36 & *bflags)
 		possible_inq_resp_len = 36;
-	else if (BLIST_INQUIRY_58 & bflags)
+	else if (BLIST_INQUIRY_58 & *bflags)
 		possible_inq_resp_len = 58;
 	else if (possible_inq_resp_len > 255)
 		possible_inq_resp_len = 36;	/* sanity */
 
-	if (possible_inq_resp_len > 36) { /* do additional INQUIRY */
+	if (possible_inq_resp_len > 36) {	/* do additional INQUIRY */
 		memset(scsi_cmd, 0, 6);
 		scsi_cmd[0] = INQUIRY;
-		if ((lun > 0) && (scsi_level <= SCSI_2))
-			scsi_cmd[1] = (lun << 5) & 0xe0;
-		scsi_cmd[4] = (unsigned char)possible_inq_resp_len;
-		SRpnt->sr_cmd_len = 0;
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
-
-		scsi_wait_req (SRpnt, (void *) scsi_cmd,
-			  (void *) scsi_result,
-			  scsi_cmd[4], SCSI_TIMEOUT+4*HZ, 3);
-		/* assume successful */
-	}
-	SDpnt->inquiry_len = possible_inq_resp_len;
-	SDpnt->inquiry = kmalloc(possible_inq_resp_len, GFP_ATOMIC);
-	if (NULL == SDpnt->inquiry) {
-		scsi_release_commandblocks(SDpnt);
-		scsi_release_request(SRpnt);
+		if ((sdev->lun > 0) && (sdev->scsi_level <= SCSI_2))
+			scsi_cmd[1] = (sdev->lun << 5) & 0xe0;
+		scsi_cmd[4] = (unsigned char) possible_inq_resp_len;
+		sreq->sr_cmd_len = 0;
+		sreq->sr_data_direction = SCSI_DATA_READ;
+		/*
+		 * re-zero inq_result just to be safe.
+		 */
+		memset(inq_result, 0, possible_inq_resp_len);
+		scsi_wait_req(sreq, (void *) scsi_cmd,
+			      (void *) inq_result,
+			      possible_inq_resp_len, SCSI_TIMEOUT + 4 * HZ, 3);
+		SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: 2nd INQUIRY"
+				" %s with code 0x%x\n", sreq->sr_result ?
+				"failed" : "successful", sreq->sr_result));
+		if (sreq->sr_result)
+			return;
+
+		/*
+		 * The INQUIRY can change, this means the length can change.
+		 */
+		possible_inq_resp_len = (unsigned char) inq_result[4] + 5;
+		if (BLIST_INQUIRY_58 & *bflags)
+			possible_inq_resp_len = 58;
+		else if (possible_inq_resp_len > 255)
+			possible_inq_resp_len = 36;	/* sanity */
+	}
+
+	sdev->inquiry_len = possible_inq_resp_len;
+
+	/*
+	 * XXX Abort if the response length is less than 36? If less than
+	 * 32, the lookup of the device flags (above) could be invalid,
+	 * and it would be possible to take an incorrect action - we do
+	 * not want to hang because of a short INQUIRY. On the flip side,
+	 * if the device is spun down or becoming ready (and so it gives a
+	 * short INQUIRY), an abort here prevents any further use of the
+	 * device, including spin up.
+	 *
+	 * Related to the above issue:
+	 *
+	 * XXX Devices (disk or all?) should be sent a TEST UNIT READY,
+	 * and if not ready, sent a START_STOP to start (maybe spin up) and
+	 * then send the INQUIRY again, since the INQUIRY can change after
+	 * a device is initialized.
+	 *
+	 * Ideally, start a device if explicitly asked to do so.  This
+	 * assumes that a device is spun up on power on, spun down on
+	 * request, and then spun up on request.
+	 */
+
+	/*
+	 * The scanning code needs to know the scsi_level, even if no
+	 * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so
+	 * non-zero LUNs can be scanned.
+	 */
+	sdev->scsi_level = inq_result[2] & 0x07;
+	if (sdev->scsi_level >= 2 ||
+	    (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
+		sdev->scsi_level++;
+
+	return;
+}
+
+/**
+ * scsi_add_lun - allocate and fully initialze a Scsi_Device
+ * @sdevscan:	holds information to be stored in the new Scsi_Device
+ * @sdevnew:	store the address of the newly allocated Scsi_Device
+ * @sreq:	scsi request used when getting an identifier
+ * @inq_result:	holds the result of a previous INQUIRY to the LUN
+ * @bflags:	flags value from device_list
+ *
+ * Description:
+ *     Allocate and initialize a Scsi_Device matching sdevscan. Optionally
+ *     set fields based on values in *@bflags. If @sdevnew is not
+ *     NULL, store the address of the new Scsi_Device in *@sdevnew (needed
+ *     when scanning a particular LUN).
+ *
+ * Return:
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ **/
+static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
+			Scsi_Request *sreq, char *inq_result, int *bflags)
+{
+	Scsi_Device *sdev;
+	struct Scsi_Device_Template *sdt;
+	char devname[64];
+	extern devfs_handle_t scsi_devfs_handle;
+
+	sdev = scsi_alloc_sdev(sdevscan->host, sdevscan->channel,
+				     sdevscan->id, sdevscan->lun);
+	if (sdev == NULL)
+		return SCSI_SCAN_NO_RESPONSE;
+
+	sdev->scsi_level = sdevscan->scsi_level;
+	/*
+	 * XXX do not save the inquiry, since it can change underneath us,
+	 * save just vendor/model/rev.
+	 *
+	 * Rather than save it and have an ioctl that retrieves the saved
+	 * value, have an ioctl that executes the same INQUIRY code used
+	 * in scsi_probe_lun, let user level programs doing INQUIRY
+	 * scanning run at their own risk, or supply a user level program
+	 * that can correctly scan.
+	 */
+	sdev->inquiry_len = sdevscan->inquiry_len;
+	sdev->inquiry = kmalloc(sdev->inquiry_len, GFP_ATOMIC);
+	if (sdev->inquiry == NULL) {
+		scsi_free_sdev(sdev);
 		return SCSI_SCAN_NO_RESPONSE;
 	}
-	memcpy(SDpnt->inquiry, scsi_result, possible_inq_resp_len);
-	SDpnt->vendor = (char *)(SDpnt->inquiry + 8);
-	SDpnt->model = (char *)(SDpnt->inquiry + 16);
-	SDpnt->rev = (char *)(SDpnt->inquiry + 32);
-
-	SDpnt->scsi_level = scsi_result[2] & 0x07;
-	if (SDpnt->scsi_level >= 2 ||
-	    (SDpnt->scsi_level == 1 &&
-	     (scsi_result[3] & 0x0f) == 1))
-		SDpnt->scsi_level++;
-
-	/*
-	 * Check the peripheral qualifier field - this tells us whether LUNS
-	 * are supported here or not.
-	 */
-	if ((scsi_result[0] >> 5) == 3) {
-		/*
-		 * Peripheral qualifier 3 (011b): The device server is not
-		 * capable of supporting a physical device on this logical
-		 * unit.
-		 */
-		scsi_release_commandblocks(SDpnt);
-  		scsi_release_request(SRpnt);
-		return SCSI_SCAN_DEVICE_PRESENT;
-	}
-	 /*   The Toshiba ROM was "gender-changed" here as an inline hack.
-	      This is now much more generic.
-	      This is a mess: What we really want is to leave the scsi_result
-	      alone, and just change the SDpnt structure. And the SDpnt is what
-	      we want print_inquiry to print.  -- REW
-	 */
-	if (bflags & BLIST_ISDISK) {
-		scsi_result[0] = TYPE_DISK;                                                
-		scsi_result[1] |= 0x80;     /* removable */
-	}
-
-	if (bflags & BLIST_ISROM) {
-		scsi_result[0] = TYPE_ROM;
-		scsi_result[1] |= 0x80;     /* removable */
-	}
-    
-
-	SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
-	/* Use the peripheral qualifier field to determine online/offline */
-	if (((scsi_result[0] >> 5) & 7) == 1) 	SDpnt->online = FALSE;
-	else SDpnt->online = TRUE;
-	SDpnt->lockable = SDpnt->removable;
-	SDpnt->changed = 0;
-	SDpnt->access_count = 0;
-	SDpnt->busy = 0;
-	SDpnt->has_cmdblocks = 0;
-	/*
-	 * Currently, all sequential devices are assumed to be tapes, all random
-	 * devices disk, with the appropriate read only flags set for ROM / WORM
-	 * treated as RO.
-	 */
-	switch (type = (scsi_result[0] & 0x1f)) {
+
+	memcpy(sdev->inquiry, inq_result, sdev->inquiry_len);
+	sdev->vendor = (char *) (sdev->inquiry + 8);
+	sdev->model = (char *) (sdev->inquiry + 16);
+	sdev->rev = (char *) (sdev->inquiry + 32);
+
+	if (*bflags & BLIST_ISROM) {
+		/*
+		 * It would be better to modify sdev->type, and set
+		 * sdev->removable, but then the print_inquiry() output
+		 * would not show TYPE_ROM; if print_inquiry() is removed
+		 * the issue goes away.
+		 */
+		inq_result[0] = TYPE_ROM;
+		inq_result[1] |= 0x80;	/* removable */
+	}
+
+	switch (sdev->type = (inq_result[0] & 0x1f)) {
 	case TYPE_TAPE:
 	case TYPE_DISK:
 	case TYPE_PRINTER:
@@ -787,201 +1369,357 @@
 	case TYPE_MEDIUM_CHANGER:
 	case TYPE_ENCLOSURE:
 	case TYPE_COMM:
-		SDpnt->writeable = 1;
+		sdev->writeable = 1;
 		break;
 	case TYPE_WORM:
 	case TYPE_ROM:
-		SDpnt->writeable = 0;
+		sdev->writeable = 0;
 		break;
 	default:
-		printk("scsi: unknown type %d\n", type);
+		printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
 	}
 
-	SDpnt->device_blocked = FALSE;
-	SDpnt->device_busy = 0;
-	SDpnt->single_lun = 0;
-	SDpnt->soft_reset =
-	    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
-	SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
-	SDpnt->type = (type & 0x1f);
-
-	print_inquiry(scsi_result);
+	sdev->random = (sdev->type == TYPE_TAPE) ? 0 : 1;
 
-	/* interrogate scsi target to provide device identifier */
-	scsi_load_identifier(SDpnt, SRpnt);
+	print_inquiry(inq_result);
 
-	/* create driverfs files */
-	sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
-		SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
-	
-	SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev;
-	SDpnt->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type;
-
-	device_register(&SDpnt->sdev_driverfs_dev); 
-
-	/* Create driverfs file entries */
-	device_create_file(&SDpnt->sdev_driverfs_dev, 
-			   &dev_attr_type);
+	/*
+	 * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
+	 * spec says: The device server is capable of supporting the
+	 * specified peripheral device type on this logical unit. However,
+	 * the physical device is not currently connected to this logical
+	 * unit.
+	 *
+	 * The above is vague, as it implies that we could treat 001 and
+	 * 011 the same. Stay compatible with previous code, and create a
+	 * Scsi_Device for a PQ of 1
+	 *
+	 * XXX Save the PQ field let the upper layers figure out if they
+	 * want to attach or not to this device, do not set online FALSE;
+	 * otherwise, offline devices still get an sd allocated, and they
+	 * use up an sd slot.
+	 */
+	if (((inq_result[0] >> 5) & 7) == 1) {
+		SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: peripheral"
+				" qualifier of 1, device offlined\n"));
+		sdev->online = FALSE;
+	}
 
-        sprintf (devname, "host%d/bus%d/target%d/lun%d",
-                 SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
-        if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
-        else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, NULL);
+	sdev->removable = (0x80 & inq_result[1]) >> 7;
+	sdev->lockable = sdev->removable;
+	sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
 
-	for (sdtpnt = scsi_devicelist; sdtpnt;
-	     sdtpnt = sdtpnt->next)
-		if (sdtpnt->detect)
-			SDpnt->attached +=
-			    (*sdtpnt->detect) (SDpnt);
+	/*
+	 * XXX maybe move the identifier and driverfs/devfs setup to a new
+	 * function, and call them after this function is called.
+	 *
+	 * scsi_load_identifier is the only reason sreq is needed in this
+	 * function.
+	 */
+	scsi_load_identifier(sdev, sreq);
 
 	/*
-	 * Accommodate drivers that want to sleep when they should be in a polling
-	 * loop.
+	 * create driverfs files
 	 */
-	SDpnt->disconnect = 0;
+	sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
+		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+	sdev->sdev_driverfs_dev.parent = &sdev->host->host_driverfs_dev;
+	sdev->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type;
+	device_register(&sdev->sdev_driverfs_dev);
 
+	/*
+	 * Create driverfs file entries
+	 */
+	device_create_file(&sdev->sdev_driverfs_dev, &dev_attr_type);
 
+	sprintf(devname, "host%d/bus%d/target%d/lun%d",
+		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+	if (sdev->de)
+		printk(KERN_WARNING "scsi devfs dir: \"%s\" already exists\n",
+		       devname);
+	else
+		sdev->de = devfs_mk_dir(scsi_devfs_handle, devname, NULL);
 	/*
-	 * Set the tagged_queue flag for SCSI-II devices that purport to support
-	 * tagged queuing in the INQUIRY data.
+	 * End driverfs/devfs code.
 	 */
-	SDpnt->tagged_queue = 0;
-	if ((SDpnt->scsi_level >= SCSI_2) &&
-	    (scsi_result[7] & 2) &&
-	    !(bflags & BLIST_NOTQ)) {
-		SDpnt->tagged_supported = 1;
-		SDpnt->current_tag = 0;
-	}
+
+	if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
+	    !(*bflags & BLIST_NOTQ))
+		sdev->tagged_supported = 1;
 	/*
-	 * Some revisions of the Texel CD ROM drives have handshaking problems when
-	 * used with the Seagate controllers.  Before we know what type of device
-	 * we're talking to, we assume it's borken and then change it here if it
-	 * turns out that it isn't a TEXEL drive.
+	 * Some devices (Texel CD ROM drives) have handshaking problems
+	 * when used with the Seagate controllers. borken is initialized
+	 * to 1, and then set it to 0 here.
 	 */
-	if ((bflags & BLIST_BORKEN) == 0)
-		SDpnt->borken = 0;
+	if ((*bflags & BLIST_BORKEN) == 0)
+		sdev->borken = 0;
 
 	/*
-	 * If we want to only allow I/O to one of the luns attached to this device
-	 * at a time, then we set this flag.
+	 * If we need to allow I/O to only one of the luns attached to
+	 * this target id at a time, then we set this flag.
 	 */
-	if (bflags & BLIST_SINGLELUN)
-		SDpnt->single_lun = 1;
+	if (*bflags & BLIST_SINGLELUN)
+		sdev->single_lun = 1;
+
+	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+		if (sdt->detect)
+			sdev->attached += (*sdt->detect) (sdev);
+
+	if (sdevnew != NULL)
+		*sdevnew = sdev;
+
+	return SCSI_SCAN_LUN_PRESENT;
+}
+
+/**
+ * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
+ * @sdevscan:	probe the LUN corresponding to this Scsi_Device
+ * @sdevnew:	store the value of any new Scsi_Device allocated
+ * @bflagsp:	store bflags here if not NULL
+ *
+ * Description:
+ *     Call scsi_probe_lun, if a LUN with an attached device is found,
+ *     allocate and set it up by calling scsi_add_lun.
+ *
+ * Return:
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_TARGET_PRESENT: target responded, but no device is
+ *         attached at the LUN
+ *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ **/
+static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
+				  int *bflagsp)
+{
+	Scsi_Device *sdev = NULL;
+	Scsi_Request *sreq = NULL;
+	unsigned char *scsi_result = NULL;
+	int bflags;
+	int res;
 
 	/*
-	 * These devices need this "key" to unlock the devices so we can use it
+	 * Any command blocks allocated are fixed to use sdevscan->lun,
+	 * so they must be allocated and released if sdevscan->lun
+	 * changes.
+	 *
+	 * XXX optimize and don't call build/release commandblocks, instead
+	 * modify the LUN value of the existing command block - this means
+	 * the build/release calls would be moved to the alloc/free of
+	 * sdevscan, and the modifying function would be called here.
+	 *
+	 * XXX maybe change scsi_release_commandblocks to not reset
+	 * queue_depth to 0.
 	 */
-	if ((bflags & BLIST_KEY) != 0) {
-		printk("Unlocked floptical drive.\n");
-		SDpnt->lockable = 0;
-		scsi_cmd[0] = MODE_SENSE;
-		if (shpnt->max_lun <= 8)
-			scsi_cmd[1] = (lun << 5) & 0xe0;
-		else	scsi_cmd[1] = 0;	/* any other idea? */
-		scsi_cmd[2] = 0x2e;
-		scsi_cmd[3] = 0;
-		scsi_cmd[4] = 0x2a;
-		scsi_cmd[5] = 0;
-		SRpnt->sr_cmd_len = 0;
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
-		scsi_wait_req (SRpnt, (void *) scsi_cmd,
-	        	(void *) scsi_result, 0x2a,
-	        	SCSI_TIMEOUT, 3);
+	sdevscan->queue_depth = 1;
+	scsi_build_commandblocks(sdevscan);
+	if (sdevscan->has_cmdblocks == 0)
+		goto alloc_failed;
+
+	sreq = scsi_allocate_request(sdevscan);
+	if (sreq == NULL)
+		goto alloc_failed;
+	/*
+	 * The sreq is for use only with sdevscan.
+	 */
+
+	scsi_result = kmalloc(256, GFP_ATOMIC |
+			      (sdevscan->host->unchecked_isa_dma) ?
+			      GFP_DMA : 0);
+	if (scsi_result == NULL)
+		goto alloc_failed;
+
+	scsi_probe_lun(sreq, scsi_result, &bflags);
+	if (sreq->sr_result)
+		res = SCSI_SCAN_NO_RESPONSE;
+	else {
 		/*
-		 * scsi_result no longer holds inquiry data.
+		 * scsi_result contains valid SCSI INQUIRY data.
 		 */
+		if ((scsi_result[0] >> 5) == 3) {
+			/*
+			 * For a Peripheral qualifier 3 (011b), the SCSI
+			 * spec says: The device server is not capable of
+			 * supporting a physical device on this logical
+			 * unit.
+			 *
+			 * For disks, this implies that there is no
+			 * logical disk configured at sdev->lun, but there
+			 * is a target id responding.
+			 */
+			SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+					"scsi scan: peripheral qualifier of 3,"
+					" no device added\n"));
+			res = SCSI_SCAN_TARGET_PRESENT;
+		} else {
+			res = scsi_add_lun(sdevscan, &sdev, sreq, scsi_result,
+					   &bflags);
+			if (res == SCSI_SCAN_LUN_PRESENT) {
+				BUG_ON(sdev == NULL);
+				if ((bflags & BLIST_KEY) != 0) {
+					sdev->lockable = 0;
+					scsi_unlock_floptical(sreq,
+							      scsi_result);
+					/*
+					 * scsi_result no longer contains
+					 * the INQUIRY data.
+					 */
+				}
+				/*
+				 * "hardcoded" scans of a single LUN need
+				 * to know the sdev just allocated.
+				 */
+				if (sdevnew != NULL)
+					*sdevnew = sdev;
+				if (bflagsp != NULL)
+					*bflagsp = bflags;
+			}
+		}
 	}
+	kfree(scsi_result);
+	scsi_release_request(sreq);
+	scsi_release_commandblocks(sdevscan);
+	return res;
 
-	scsi_release_request(SRpnt);
-	SRpnt = NULL;
+alloc_failed:
+	printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+	if (scsi_result != NULL)
+		kfree(scsi_result);
+	if (sreq != NULL)
+		scsi_release_request(sreq);
+	if (sdevscan->has_cmdblocks != 0)
+		scsi_release_commandblocks(sdevscan);
+	return SCSI_SCAN_NO_RESPONSE;
+}
 
-	scsi_release_commandblocks(SDpnt);
+/**
+ * scsi_sequential_lun_scan - sequentially scan a SCSI target
+ * @sdevscan:	scan the host, channel, and id of this Scsi_Device
+ * @bflags:	flags from device_list for LUN 0
+ * @lun0_res:	result of scanning LUN 0
+ *
+ * Description:
+ *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
+ *     scanned) to some maximum lun until a LUN is found with no device
+ *     attached. Use the bflags to figure out any oddities.
+ *
+ *     Modifies sdevscan->lun.
+ **/
+static void scsi_sequential_lun_scan(Scsi_Device *sdevscan, int bflags,
+				     int lun0_res)
+{
+	struct Scsi_Host *shost = sdevscan->host;
+	unsigned int sparse_lun;
+	unsigned int max_dev_lun;
+
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of"
+			" host %d channel %d id %d\n", sdevscan->host->host_no,
+			sdevscan->channel, sdevscan->id));
 
+	max_dev_lun = min(max_scsi_luns, shost->max_lun);
 	/*
-	 * This device was already hooked up to the host in question,
-	 * so at this point we just let go of it and it should be fine.  We do need to
-	 * allocate a new one and attach it to the host so that we can further scan the bus.
+	 * If this device is known to support sparse multiple units,
+	 * override the other settings, and scan all of them. Normally,
+	 * SCSI-3 devices should be scanned via the REPORT LUNS.
 	 */
-	SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC);
-	if (!SDpnt) {
-		printk("scsi: scan_scsis_single: Cannot malloc\n");
-		return SCSI_SCAN_NO_RESPONSE;
-	}
-        memset(SDpnt, 0, sizeof(Scsi_Device));
-	SDpnt->vendor = scsi_null_device_strs;
-	SDpnt->model = scsi_null_device_strs;
-	SDpnt->rev = scsi_null_device_strs;
-
-	*SDpnt2 = SDpnt;
-	SDpnt->queue_depth = 1;
-	SDpnt->host = shpnt;
-	SDpnt->online = TRUE;
-	SDpnt->scsi_level = scsi_level;
+	if (bflags & BLIST_SPARSELUN) {
+		max_dev_lun = shost->max_lun;
+		sparse_lun = 1;
+	} else
+		sparse_lun = 0;
 
 	/*
-	 * Register the queue for the device.  All I/O requests will come
-	 * in through here.  We also need to register a pointer to
-	 * ourselves, since the queue handler won't know what device
-	 * the queue actually represents.   We could look it up, but it
-	 * is pointless work.
+	 * If not sparse lun and no device attached at LUN 0 do not scan
+	 * any further.
 	 */
-	scsi_initialize_queue(SDpnt, shpnt);
-	SDpnt->host = shpnt;
-	scsi_initialize_merge_fn(SDpnt);
+	if (!sparse_lun && (lun0_res != SCSI_SCAN_LUN_PRESENT))
+		return;
 
 	/*
-	 * Mark this device as online, or otherwise we won't be able to do much with it.
+	 * If less than SCSI_1_CSS, and no special lun scaning, stop
+	 * scanning; this matches 2.4 behaviour, but could just be a bug
+	 * (to continue scanning a SCSI_1_CSS device).
+	 */
+	if ((sdevscan->scsi_level < SCSI_1_CCS) &&
+	    ((bflags & (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN))
+	     == 0))
+		return;
+	/*
+	 * If this device is known to support multiple units, override
+	 * the other settings, and scan all of them.
+	 */
+	if (bflags & BLIST_FORCELUN)
+		max_dev_lun = shost->max_lun;
+	/*
+	 * REGAL CDC-4X: avoid hang after LUN 4
 	 */
-	SDpnt->online = TRUE;
-
-        /*
-         * Initialize the object that we will use to wait for command blocks.
-         */
-	init_waitqueue_head(&SDpnt->scpnt_wait);
-
+	if (bflags & BLIST_MAX5LUN)
+		max_dev_lun = min(5U, max_dev_lun);
 	/*
-	 * Since we just found one device, there had damn well better be one in the list
-	 * already.
+	 * Do not scan SCSI-2 or lower device past LUN 7, unless
+	 * BLIST_LARGELUN.
 	 */
-	if (shpnt->host_queue == NULL)
-		panic("scan_scsis_single: Host queue == NULL\n");
+	if ((sdevscan->scsi_level < SCSI_3) && !(bflags & BLIST_LARGELUN))
+		max_dev_lun = min(8U, max_dev_lun);
 
-	SDtail = shpnt->host_queue;
-	while (SDtail->next) {
-		SDtail = SDtail->next;
-	}
+	/*
+	 * We have already scanned LUN 0, so start at LUN 1. Keep scanning
+	 * until we reach the max, or no LUN is found and we are not
+	 * sparse_lun.
+	 */
+	for (sdevscan->lun = 1; sdevscan->lun < max_dev_lun; ++sdevscan->lun)
+		if ((scsi_probe_and_add_lun(sdevscan, NULL, NULL)
+		     != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
+			return;
+}
 
-	/* Add this device to the linked list at the end */
-	SDtail->next = SDpnt;
-	SDpnt->prev = SDtail;
-	SDpnt->next = NULL;
+#ifdef CONFIG_SCSI_REPORT_LUNS
+/**
+ * scsilun_to_int: convert a ScsiLun to an int
+ * @scsilun:	ScsiLun to be converted.
+ *
+ * Description:
+ *     Convert @scsilun from a ScsiLun to a four byte host byte-ordered
+ *     integer, and return the result. The caller must check for
+ *     truncation before using this function.
+ *
+ * Notes:
+ *     The ScsiLun is assumed to be four levels, with each level
+ *     effectively containing a SCSI byte-ordered (big endian) short; the
+ *     addressing bits of each level are ignored (the highest two bits).
+ *     For a description of the LUN format, post SCSI-3 see the SCSI
+ *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.
+ *
+ *     Given a ScsiLun of: 0a 04 0b 03 00 00 00 00, this function returns
+ *     the integer: 0x0b030a04
+ **/
+static int scsilun_to_int(ScsiLun *scsilun)
+{
+	int i;
+	unsigned int lun;
 
-	return SCSI_SCAN_DEVICE_ADDED;
+	lun = 0;
+	for (i = 0; i < sizeof(lun); i += 2)
+		lun = lun | (((scsilun->scsi_lun[i] << 8) |
+			      scsilun->scsi_lun[i + 1]) << (i * 8));
+	return lun;
 }
+#endif
 
-/*
- * Function:    scsi_report_lun_scan
- *
- * Purpose:     Use a SCSI REPORT LUN to determine what LUNs to scan.
- *
- * Arguments:   SDlun0_pnt - pointer to a Scsi_Device for LUN 0
- * 		channel    - the host's channel
- * 		dev        - target dev (target id)
- * 		SDpnt2     - pointer to pointer of a preallocated Scsi_Device
- * 		shpnt      - host device to use
- * 		scsi_result - preallocated buffer for the SCSI command result
- *
- * Lock status: None
- *
- * Returns:     If the LUNs for device at shpnt/channel/dev are scanned,
- * 		return 0, else return 1.
- *
- * Notes:       This code copies and truncates the 8 byte LUN into the
- * 		current 4 byte (int) lun.
- */
-static int scsi_report_lun_scan(Scsi_Device *SDlun0_pnt, unsigned
-		int channel, unsigned int dev, Scsi_Device **SDpnt2,
-		struct Scsi_Host *shpnt, char *scsi_result)
+/**
+ * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
+ * @sdevscan:	scan the host, channel, and id of this Scsi_Device
+ *
+ * Description:
+ *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
+ *     command, and scan the resulting list of LUNs by calling
+ *     scsi_probe_and_add_lun.
+ *
+ *     Modifies sdevscan->lun.
+ *
+ * Return:
+ *     0: scan completed (or no memory, so further scanning is futile)
+ *     1: no report lun scan, or not configured
+ **/
+static int scsi_report_lun_scan(Scsi_Device *sdevscan)
 {
 #ifdef CONFIG_SCSI_REPORT_LUNS
 
@@ -991,53 +1729,50 @@
 	unsigned int lun;
 	unsigned int num_luns;
 	unsigned int retries;
-	ScsiLun *fcp_cur_lun_pnt, *lun_data_pnt;
-	Scsi_Request *SRpnt;
-	int scsi_level;
-	char *byte_pnt;
-	int got_command_blocks = 0;
+	ScsiLun *fcp_cur_lun, *lun_data;
+	Scsi_Request *sreq;
+	char *data;
 
 	/*
 	 * Only support SCSI-3 and up devices.
 	 */
-	if (SDlun0_pnt->scsi_level < SCSI_3)
+	if (sdevscan->scsi_level < SCSI_3)
 		return 1;
 
-	/*
-	 * Note SDlun0_pnt might be invalid after scan_scsis_single is called.
-	 */
-
-	/*
-	 * Command blocks might be built depending on whether LUN 0 was
-	 * configured or not. Checking has_cmdblocks here is ugly.
-	 */
-	if (SDlun0_pnt->has_cmdblocks == 0) {
-		got_command_blocks = 1;
-		scsi_build_commandblocks(SDlun0_pnt);
+	sdevscan->queue_depth = 1;
+	scsi_build_commandblocks(sdevscan);
+	if (sdevscan->has_cmdblocks == 0) {
+		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+		/*
+		 * We are out of memory, don't try scanning any further.
+		 */
+		return 0;
 	}
-	SRpnt = scsi_allocate_request(SDlun0_pnt);
+	sreq = scsi_allocate_request(sdevscan);
 
-	sprintf (devname, "host %d channel %d id %d",
-		 SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
-		 SDlun0_pnt->id);
+	sprintf(devname, "host %d channel %d id %d", sdevscan->host->host_no,
+		sdevscan->channel, sdevscan->id);
 	/*
 	 * Allocate enough to hold the header (the same size as one ScsiLun)
 	 * plus the max number of luns we are requesting.
 	 *
-	 * XXX: Maybe allocate this once, like scsi_result, and pass it down.
-	 * scsi_result can't be used, as it is needed for the scan INQUIRY
-	 * data. In addition, reallocating and trying again (with the exact
-	 * amount we need) would be nice, but then we need to somehow limit the
-	 * size allocated based on the available memory (and limits of kmalloc).
+	 * Reallocating and trying again (with the exact amount we need)
+	 * would be nice, but then we need to somehow limit the size
+	 * allocated based on the available memory and the limits of
+	 * kmalloc - we don't want a kmalloc() failure of a huge value to
+	 * prevent us from finding any LUNs on this target.
 	 */
 	length = (max_scsi_report_luns + 1) * sizeof(ScsiLun);
-	lun_data_pnt = (ScsiLun *) kmalloc(length,
-			(shpnt->unchecked_isa_dma ?  GFP_DMA : GFP_ATOMIC));
-	if (lun_data_pnt == NULL) {
-		printk("scsi: scsi_report_lun_scan: Cannot malloc\n");
-		if (got_command_blocks)
-			scsi_release_commandblocks(SDlun0_pnt);
-		return 1;
+	lun_data = (ScsiLun *) kmalloc(length, GFP_ATOMIC |
+					   (sdevscan->host->unchecked_isa_dma ?
+					    GFP_DMA : 0));
+	if (lun_data == NULL) {
+		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+		scsi_release_commandblocks(sdevscan);
+		/*
+		 * We are out of memory, don't try scanning any further.
+		 */
+		return 0;
 	}
 
 	scsi_cmd[0] = REPORT_LUNS;
@@ -1053,83 +1788,78 @@
 	scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff;
 	scsi_cmd[9] = (unsigned char) length & 0xff;
 
-	scsi_cmd[10] = 0; /* reserved */
-	scsi_cmd[11] = 0; /* control */
-	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_cmd[10] = 0;	/* reserved */
+	scsi_cmd[11] = 0;	/* control */
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = SCSI_DATA_READ;
 
 	/*
-	 * We can get a UNIT ATTENTION, for example a power on/reset, so retry
-	 * a few times (like sd.c does for TEST UNIT READY). Experience shows
-	 * some combinations of adapter/devices get at least two power
-	 * on/resets.
+	 * We can get a UNIT ATTENTION, for example a power on/reset, so
+	 * retry a few times (like sd.c does for TEST UNIT READY).
+	 * Experience shows some combinations of adapter/devices get at
+	 * least two power on/resets.
 	 *
 	 * Illegal requests (for devices that do not support REPORT LUNS)
-	 * should come through as a check condition, and will not generate a
-	 * retry.
+	 * should come through as a check condition, and will not generate
+	 * a retry.
 	 */
 	retries = 0;
 	while (retries++ < 3) {
-		SCSI_LOG_SCAN_BUS(3,
-			printk("scsi: Sending REPORT LUNS to %s (try %d)\n",
-				devname, retries));
-
-		scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) lun_data_pnt,
-			  length, SCSI_TIMEOUT+4*HZ, 3);
-
-		SCSI_LOG_SCAN_BUS(3,
-			printk("scsi: REPORT LUNS %s (try %d) result 0x%x\n",
-			SRpnt->sr_result ? "failed" : "successful", retries,
-			SRpnt->sr_result));
-
-		if (SRpnt->sr_result == 0
-		    || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
+		SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending"
+				" REPORT LUNS to %s (try %d)\n", devname,
+				retries));
+		scsi_wait_req(sreq, (void *) scsi_cmd, (void *) lun_data,
+			      length, SCSI_TIMEOUT + 4 * HZ, 3);
+		SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
+				" %s (try %d) result 0x%x\n", sreq->sr_result
+				?  "failed" : "successful", retries,
+				sreq->sr_result));
+		if (sreq->sr_result == 0
+		    || sreq->sr_sense_buffer[2] != UNIT_ATTENTION)
 			break;
 	}
+	scsi_release_commandblocks(sdevscan);
 
-	scsi_release_request(SRpnt);
-	if (got_command_blocks)
-		scsi_release_commandblocks(SDlun0_pnt);
-
-	if (SRpnt->sr_result) {
-		kfree((char *) lun_data_pnt);
+	if (sreq->sr_result) {
+		/*
+		 * The device probably does not support a REPORT LUN command
+		 */
+		kfree((char *) lun_data);
+		scsi_release_request(sreq);
 		return 1;
 	}
+	scsi_release_request(sreq);
 
 	/*
-	 * Get the length from the first four bytes of lun_data_pnt.
+	 * Get the length from the first four bytes of lun_data.
 	 */
-	byte_pnt = (char*) lun_data_pnt->scsi_lun;
-	length = ((byte_pnt[0] << 24) | (byte_pnt[1] << 16) |
-			 (byte_pnt[2] << 8) | (byte_pnt[3] << 0));
+	data = (char *) lun_data->scsi_lun;
+	length = ((data[0] << 24) | (data[1] << 16) |
+		  (data[2] << 8) | (data[3] << 0));
 	if ((length / sizeof(ScsiLun)) > max_scsi_report_luns) {
-		printk("scsi: On %s only %d (max_scsi_report_luns) of %d luns"
-			" reported, try increasing max_scsi_report_luns.\n",
-			devname, max_scsi_report_luns,
-			length / sizeof(ScsiLun));
+		printk(KERN_WARNING "scsi: On %s only %d (max_scsi_report_luns)"
+		       " of %d luns reported, try increasing"
+		       " max_scsi_report_luns.\n", devname,
+		       max_scsi_report_luns, length / sizeof(ScsiLun));
 		num_luns = max_scsi_report_luns;
 	} else
 		num_luns = (length / sizeof(ScsiLun));
 
-	scsi_level = SDlun0_pnt->scsi_level;
-
-	SCSI_LOG_SCAN_BUS(3,
-		printk("scsi: REPORT LUN scan of host %d channel %d id %d\n",
-		 SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
-		 SDlun0_pnt->id));
+	SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUN scan of"
+			" host %d channel %d id %d\n", sdevscan->host->host_no,
+			sdevscan->channel, sdevscan->id));
 	/*
-	 * Scan the luns in lun_data_pnt. The entry at offset 0 is really
+	 * Scan the luns in lun_data. The entry at offset 0 is really
 	 * the header, so start at 1 and go up to and including num_luns.
 	 */
-	for (fcp_cur_lun_pnt = &lun_data_pnt[1];
-	     fcp_cur_lun_pnt <= &lun_data_pnt[num_luns];
-	     fcp_cur_lun_pnt++) {
-		lun = scsilun_to_int(fcp_cur_lun_pnt);
+	for (fcp_cur_lun = &lun_data[1];
+	     fcp_cur_lun <= &lun_data[num_luns]; fcp_cur_lun++) {
+		lun = scsilun_to_int(fcp_cur_lun);
 		/*
-		 * Check if the unused part of fcp_cur_lun_pnt is non-zero,
+		 * Check if the unused part of fcp_cur_lun is non-zero,
 		 * and so does not fit in lun.
 		 */
-		if (memcmp(&fcp_cur_lun_pnt->scsi_lun[sizeof(lun)],
+		if (memcmp(&fcp_cur_lun->scsi_lun[sizeof(lun)],
 			   "\0\0\0\0", 4) != 0) {
 			int i;
 
@@ -1138,40 +1868,37 @@
 			 * this differs from what linux would print for the
 			 * integer LUN value.
 			 */
-			printk("scsi: %s lun 0x", devname);
-			byte_pnt = (char*) fcp_cur_lun_pnt->scsi_lun;
+			printk(KERN_WARNING "scsi: %s lun 0x", devname);
+			data = (char *) fcp_cur_lun->scsi_lun;
 			for (i = 0; i < sizeof(ScsiLun); i++)
-				printk("%02x", byte_pnt[i]);
-			printk(" has a LUN larger than that supported by"
-				" the kernel\n");
+				printk("%02x", data[i]);
+			printk(" has a LUN larger than currently supported.\n");
 		} else if (lun == 0) {
 			/*
 			 * LUN 0 has already been scanned.
 			 */
-		} else if (lun > shpnt->max_lun) {
-			printk("scsi: %s lun %d has a LUN larger than allowed"
-				" by the host adapter\n", devname, lun);
+		} else if (lun > sdevscan->host->max_lun) {
+			printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
+			       " than allowed by the host adapter\n",
+			       devname, lun);
 		} else {
-			/*
-			 * Don't use SDlun0_pnt after this call - it can be
-			 * overwritten via SDpnt2 if there was no real device
-			 * at LUN 0.
-			 */
-			if (scan_scsis_single(channel, dev, lun,
-			    scsi_level, SDpnt2, shpnt, scsi_result)
-				== SCSI_SCAN_NO_RESPONSE) {
+			int res;
+
+			sdevscan->lun = lun;
+			res = scsi_probe_and_add_lun(sdevscan, NULL, NULL);
+			if (res == SCSI_SCAN_NO_RESPONSE) {
 				/*
 				 * Got some results, but now none, abort.
 				 */
-				printk("scsi: no response from %s lun %d while"
-				       " scanning, scan aborted\n", devname, 
-				       lun);
+				printk(KERN_ERR "scsi: Unexpected response"
+				       " from %s lun %d while scanning, scan"
+				       " aborted\n", devname, sdevscan->lun);
 				break;
 			}
 		}
 	}
 
-	kfree((char *) lun_data_pnt);
+	kfree((char *) lun_data);
 	return 0;
 
 #else
@@ -1180,537 +1907,210 @@
 
 }
 
-/*
- * Function:    scan_scsis_target
- *
- * Purpose:     Scan the given scsi target dev, and as needed all LUNs
- * 		on the target dev.
- *
- * Arguments:   channel    - the host's channel
- * 		dev        - target dev (target id)
- * 		SDpnt2     - pointer to pointer of a preallocated Scsi_Device
- * 		shpnt      - host device to use
- * 		scsi_result - preallocated buffer for the SCSI command result
- *
- * Lock status: None
- *
- * Returns:     void
- *
- * Notes:       This tries to be compatible with linux 2.4.x. This function
- * 		relies on scan_scsis_single to setup SDlun0_pnt. 
- *
- * 		It would be better if the Scsi_Device allocation and freeing
- * 		was done here, rather than oddly embedded in scan_scsis_single
- * 		and scan_scsis.
- */
-static void scan_scsis_target(unsigned int channel, unsigned int dev,
-		Scsi_Device **SDpnt2, struct Scsi_Host *shpnt,
-		char *scsi_result)
-{
-	int bflags, scsi_level;
-	Scsi_Device *SDlun0_pnt;
-	unsigned int sparse_lun = 0;
-	unsigned int max_dev_lun, lun;
-	unsigned int sdlun0_res;
-
-	/*
-	 * Scan lun 0, use the results to determine whether to scan further.
-	 * Ideally, we would not configure LUN 0 until we scan.
-	 */
-	SDlun0_pnt = *SDpnt2;
-	sdlun0_res = scan_scsis_single(channel, dev, 0 /* LUN 0 */, SCSI_2,
-		SDpnt2, shpnt, scsi_result);
-	if (sdlun0_res == SCSI_SCAN_NO_RESPONSE)
-		return;
-
-	/*
-	 * If no new SDpnt was allocated (SCSI_SCAN_DEVICE_PRESENT), SDlun0_pnt
-	 * can later be modified. It is unlikely the lun level would change,
-	 * but save it just in case.
-	 */
-	scsi_level = SDlun0_pnt->scsi_level;
-
-	/*
-	 * We could probably use and save the bflags from lun 0 for all luns
-	 * on a target, but be safe and match current behaviour. (LUN 0
-	 * bflags controls the target settings checked within this function.)
-	 */
-	bflags = get_device_flags (SDlun0_pnt->vendor,  SDlun0_pnt->model);
-
-	/*
-	 * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
-	 */
-	if (bflags & BLIST_NOLUN)
-		return;
-
-	/*
-	 * Ending the scan here if max_scsi_luns == 1 breaks scanning of
-	 * SPARSE, FORCE, MAX5 LUN devices, and the report lun scans.
-	 */
-
-	if (scsi_report_lun_scan(SDlun0_pnt, channel, dev, SDpnt2, shpnt,
-	    scsi_result) == 0)
-		return;
-
-	SCSI_LOG_SCAN_BUS(3,
-		printk("scsi: Sequential scan of host %d channel %d id %d\n",
-		 SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
-		 SDlun0_pnt->id));
+/**
+ * scsi_scan_target - scan a target id, possibly including all LUNs on the
+ *     target.
+ * @sdevsca:	Scsi_Device handle for scanning
+ * @shost:	host to scan
+ * @channel:	channel to scan
+ * @id:		target id to scan
+ *
+ * Description:
+ *     Scan the target id on @shost, @channel, and @id. Scan at least LUN
+ *     0, and possibly all LUNs on the target id.
+ *
+ *     Use the pre-allocated @sdevscan as a handle for the scanning. This
+ *     function sets sdevscan->host, sdevscan->id and sdevscan->lun; the
+ *     scanning functions modify sdevscan->lun.
+ *
+ *     First try a REPORT LUN scan, if that does not scan the target, do a
+ *     sequential scan of LUNs on the target id.
+ **/
+static void scsi_scan_target(Scsi_Device *sdevscan, struct Scsi_Host *shost,
+			     unsigned int channel, unsigned int id)
+{
+	int bflags;
+	int res;
 
-	max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
-			max_scsi_luns : shpnt->max_lun);
-	/*
-	 * If this device is known to support sparse multiple units,
-	 * override the other settings, and scan all of them.
-	 */
-	if (bflags & BLIST_SPARSELUN) {
-		max_dev_lun = shpnt->max_lun;
-		sparse_lun = 1;
-	} else if (sdlun0_res == SCSI_SCAN_DEVICE_PRESENT) {
+	if (shost->this_id == id)
 		/*
-		 * LUN 0 responded, but no LUN 0 was added, don't scan any
-		 * further. This matches linux 2.4.x behaviour.
+		 * Don't scan the host adapter
 		 */
 		return;
-	}
-	/*
-	 * If less than SCSI_1_CSS, and not a forced lun scan, stop
-	 * scanning, this matches 2.4 behaviour, but it could be a bug
-	 * to scan SCSI_1_CSS devices past LUN 0.
-	 */
-	if ((scsi_level < SCSI_1_CCS) && ((bflags &
-	     (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN)) == 0))
-		return;
-	/*
-	 * If this device is known to support multiple units, override
-	 * the other settings, and scan all of them.
-	 */
-	if (bflags & BLIST_FORCELUN)
-		max_dev_lun = shpnt->max_lun;
-	/*
-	 * REGAL CDC-4X: avoid hang after LUN 4
-	 */
-	if (bflags & BLIST_MAX5LUN)
-		max_dev_lun = min(5U, max_dev_lun);
-	/*
-	 * Do not scan past LUN 7.
-	 */
-	if (scsi_level < SCSI_3)
-		max_dev_lun = min(8U, max_dev_lun);
 
+	sdevscan->host = shost;
+	sdevscan->id = id;
+	sdevscan->channel = channel;
 	/*
-	 * We have already scanned lun 0.
+	 * Scan LUN 0, if there is some response, scan further. Ideally, we
+	 * would not configure LUN 0 until all LUNs are scanned.
+	 *
+	 * The scsi_level is set (in scsi_probe_lun) if a target responds.
 	 */
-	for (lun = 1; lun < max_dev_lun; ++lun) {
-		int res;
+	sdevscan->lun = 0;
+	res = scsi_probe_and_add_lun(sdevscan, NULL, &bflags);
+	if (res != SCSI_SCAN_NO_RESPONSE) {
 		/*
-		 * Scan until scan_scsis_single says stop,
-		 * unless sparse_lun is set.
+		 * Some scsi devices cannot properly handle a lun != 0.
+		 * BLIST_NOLUN also prevents a REPORT LUN from being sent.
+		 * Any multi-lun SCSI-3 device that hangs because of a
+		 * REPORT LUN command is seriously broken.
 		 */
-		res = scan_scsis_single(channel, dev, lun,
-		     scsi_level, SDpnt2, shpnt, scsi_result);
-		if (res == SCSI_SCAN_NO_RESPONSE) {
+		if (!(bflags & BLIST_NOLUN))
 			/*
-			 * Got a response on LUN 0, but now no response.
+			 * Ending the scan here if max_scsi_luns == 1
+			 * breaks scanning of SPARSE, FORCE, MAX5 LUN
+			 * devices, and the report lun scan.
 			 */
-			printk("scsi: no response from device"
-				" host%d/bus%d/target%d/lun%d"
-				" while scanning, scan aborted\n",
-				shpnt->host_no, channel, dev, lun);
-			return;
-		} else if ((res == SCSI_SCAN_DEVICE_PRESENT)
-			    && !sparse_lun)
-			return;
-	}
-}
-
-/*
- * Returns the scsi_level of lun0 on this host, channel and dev (if already
- * known), otherwise returns SCSI_2.
- */
-static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
-				struct Scsi_Host *shpnt)
-{
-	int res = SCSI_2;
-	Scsi_Device *SDpnt;
-
-	for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
-	{
-		if ((0 == SDpnt->lun) && (dev == SDpnt->id) &&
-		    (channel == SDpnt->channel))
-			return (int)SDpnt->scsi_level;
-	}
-	/* haven't found lun0, should send INQUIRY but take easy route */
-	return res;
-}
-
-#define SCSI_UID_DEV_ID  'U'
-#define SCSI_UID_SER_NUM 'S'
-#define SCSI_UID_UNKNOWN 'Z'
-
-unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
-{
-	unsigned char *evpd_page = NULL;
-	unsigned char *scsi_cmd = NULL;
-	int lun = SDpnt->lun;
-	int scsi_level = SDpnt->scsi_level;
-
-	evpd_page = kmalloc(255, 
-		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
-	if (!evpd_page)
-		return NULL;
-
-	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
-	if (!scsi_cmd) {
-		kfree(evpd_page);
-		return NULL;
-	}
-
-	/* Use vital product pages to determine serial number */
-	/* Try Supported vital product data pages 0x00 first */
-	scsi_cmd[0] = INQUIRY;
-	if ((lun > 0) && (scsi_level <= SCSI_2))
-		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-	else
-		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
-	scsi_cmd[2] = 0x00;
-	scsi_cmd[3] = 0;
-	scsi_cmd[4] = 255;
-	scsi_cmd[5] = 0;
-	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_sense_buffer[0] = 0;
-	SRpnt->sr_sense_buffer[2] = 0;
-	SRpnt->sr_data_direction = SCSI_DATA_READ;
-	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
-			255, SCSI_TIMEOUT+4*HZ, 3);
-
-	if (SRpnt->sr_result) {
-		kfree(scsi_cmd);
-		kfree(evpd_page);
-		return NULL;
-	}
-
-	/* check to see if response was truncated */
-	if (evpd_page[3] > 255) {
-		int max_lgth = evpd_page[3] + 4;
-
-		kfree(evpd_page);
-		evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ? 
-			GFP_DMA : GFP_ATOMIC));
-		if (!evpd_page) {
-			kfree(scsi_cmd);
-			return NULL;
-		}
-		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
-		scsi_cmd[0] = INQUIRY;
-		if ((lun > 0) && (scsi_level <= SCSI_2))
-			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-		else
-			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
-		scsi_cmd[2] = 0x00;
-		scsi_cmd[3] = 0;
-		scsi_cmd[4] = max_lgth;
-		scsi_cmd[5] = 0;
-		SRpnt->sr_cmd_len = 0;
-		SRpnt->sr_sense_buffer[0] = 0;
-		SRpnt->sr_sense_buffer[2] = 0;
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
-		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
-			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
-		if (SRpnt->sr_result) {
-			kfree(scsi_cmd);
-			kfree(evpd_page);
-			return NULL;
-		}
-	}
-	kfree(scsi_cmd);
-	/* some ill behaved devices return the std inquiry here rather than
-		the evpd data. snoop the data to verify */
-	if (evpd_page[3] > 16) {
-		/* if vend id appears in the evpd page assume evpd is invalid */
-		if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) {
-			kfree(evpd_page);
-			return NULL;
-		}
+			if (scsi_report_lun_scan(sdevscan) != 0)
+				/*
+				 * The REPORT LUN did not scan the target,
+				 * do a sequential scan.
+				 */
+				scsi_sequential_lun_scan(sdevscan, bflags, res);
 	}
-	return evpd_page;
 }
 
-int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt)
+/**
+ * scsi_scan_selected_lun - probe and add one LUN
+ *
+ * Description:
+ *     Probe a single LUN on @shost, @channel, @id and @lun. If the LUN is
+ *     found, set the queue depth, allocate command blocks, and call
+ *     init/attach/finish of the upper level (sd, sg, etc.) drivers.
+ **/
+static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
+				   uint id, uint lun)
 {
-	unsigned char *id_page = NULL;
-	unsigned char *scsi_cmd = NULL;
-	int scnt, i, j, idtype;
-	char * id = SDpnt->sdev_driverfs_dev.name;
-	int lun = SDpnt->lun;
-	int scsi_level = SDpnt->scsi_level;
-
-	id_page = kmalloc(255, 
-		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); 
-	if (!id_page)
-		return 0;
+	Scsi_Device *sdevscan, *sdev = NULL;
+	struct Scsi_Device_Template *sdt;
+	int res;
 
-	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
-	if (!scsi_cmd)
-		goto leave;
-
-	/* Use vital product pages to determine serial number */
-	/* Try Supported vital product data pages 0x00 first */
-	scsi_cmd[0] = INQUIRY;
-	if ((lun > 0) && (scsi_level <= SCSI_2))
-		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-	else
-		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
-	scsi_cmd[2] = 0x83;
-	scsi_cmd[3] = 0;
-	scsi_cmd[4] = 255;
-	scsi_cmd[5] = 0;
-	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_sense_buffer[0] = 0;
-	SRpnt->sr_sense_buffer[2] = 0;
-	SRpnt->sr_data_direction = SCSI_DATA_READ;
-	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
-			255, SCSI_TIMEOUT+4*HZ, 3);
-	if (SRpnt->sr_result) {
-		kfree(scsi_cmd);
-		goto leave;
-	}
+	if ((channel > shost->max_channel) || (id >= shost->max_id) ||
+	    (lun >= shost->max_lun))
+		return;
 
-	/* check to see if response was truncated */
-	if (id_page[3] > 255) {
-		int max_lgth = id_page[3] + 4;
+	sdevscan = scsi_alloc_sdev(shost, channel, id, lun);
+	if (sdevscan == NULL)
+		return;
 
-		kfree(id_page);
-		id_page = kmalloc(max_lgth,
-			(SDpnt->host->unchecked_isa_dma ? 
-			GFP_DMA : GFP_ATOMIC)); 
-		if (!id_page) {
-			kfree(scsi_cmd);
-			return 0;
-		}
-		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
-		scsi_cmd[0] = INQUIRY;
-		if ((lun > 0) && (scsi_level <= SCSI_2))
-			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-		else
-			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
-		scsi_cmd[2] = 0x83;
-		scsi_cmd[3] = 0;
-		scsi_cmd[4] = max_lgth;
-		scsi_cmd[5] = 0;
-		SRpnt->sr_cmd_len = 0;
-		SRpnt->sr_sense_buffer[0] = 0;
-		SRpnt->sr_sense_buffer[2] = 0;
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
-		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
-				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
-		if (SRpnt->sr_result) {
-			kfree(scsi_cmd);
-			goto leave;
-		}
-	}
-	kfree(scsi_cmd);
+	sdevscan->scsi_level = scsi_find_scsi_level(channel, id, shost);
+	res = scsi_probe_and_add_lun(sdevscan, &sdev, NULL);
+	scsi_free_sdev(sdevscan);
+	if (res == SCSI_SCAN_LUN_PRESENT) {
+		BUG_ON(sdev == NULL);
+		/*
+		 * FIXME calling select_queue_depths is wrong for adapters
+		 * that modify queue depths of all scsi devices - the
+		 * adapter might change a queue depth (not for this sdev),
+		 * but the mid-layer will not change the queue depth. This
+		 * does not cause an oops, but queue_depth will not match
+		 * the actual queue depth used.
+		 *
+		 * Perhaps use a default queue depth, and allow them to be
+		 * modified at boot/insmod time, and/or via sysctl/ioctl/proc;
+		 * plus have dynamic queue depth adjustment like the
+		 * aic7xxx driver.
+		 */
+		if (shost->select_queue_depths != NULL)
+			(shost->select_queue_depths) (shost, shost->host_queue);
 
-	idtype = 3;
-	while (idtype > 0) {
-		for(scnt = 4; scnt <= id_page[3] + 3; 
-		    scnt += id_page[scnt + 3] + 4) {
-			if ((id_page[scnt + 1] & 0x0f) != idtype) {
-				continue;
-			}
-			if ((id_page[scnt] & 0x0f) == 2) {  
-				for(i = scnt + 4, j = 1;
-				    i < scnt + 4 + id_page[scnt + 3]; 
-				    i++) {
-					if (id_page[i] > 0x20) {
-						if (j == DEVICE_NAME_SIZE) {
-							memset(id, 0, 
-							    DEVICE_NAME_SIZE);
-							break;
-						}
-						id[j++] = id_page[i];
-					}
-				}
-			} else if ((id_page[scnt] & 0x0f) == 1) {
-				static const char hex_str[]="0123456789abcdef";
-				for(i = scnt + 4, j = 1;
-				    i < scnt + 4 + id_page[scnt + 3]; 
-				    i++) {
-					if ((j + 1) == DEVICE_NAME_SIZE) {
-						memset(id, 0, DEVICE_NAME_SIZE);
-						break;
-					}
-					id[j++] = hex_str[(id_page[i] & 0xf0) >>
-								4];
-					id[j++] = hex_str[id_page[i] & 0x0f];
+		for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+			if (sdt->init && sdt->dev_noticed)
+				(*sdt->init) ();
+
+		for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+			if (sdt->attach) {
+				(*sdt->attach) (sdev);
+				if (sdev->attached) {
+					scsi_build_commandblocks(sdev);
+					if (sdev->has_cmdblocks == 0)
+						printk(ALLOC_FAILURE_MSG,
+						       __FUNCTION__);
 				}
 			}
-			if (id[1] != 0) goto leave;
-		}
-		idtype--;
-	}
- leave:
-	kfree(id_page);
-	if (id[1] != 0) {
-		id[0] = SCSI_UID_DEV_ID;
-		return 1;
-	}
-	return 0;
-}
-
-int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
-{
-	unsigned char *serialnumber_page = NULL;
-	unsigned char *scsi_cmd = NULL;
-	int lun = SDpnt->lun;
-	int scsi_level = SDpnt->scsi_level;
-	int i, j;
-
-	serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ? 
-			GFP_DMA : GFP_ATOMIC));
-	if (!serialnumber_page)
-		return 0;
-
-	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
-	if (!scsi_cmd)
-		goto leave;
-
-	/* Use vital product pages to determine serial number */
-	/* Try Supported vital product data pages 0x00 first */
-	scsi_cmd[0] = INQUIRY;
-	if ((lun > 0) && (scsi_level <= SCSI_2))
-		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-	else	
-		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
-	scsi_cmd[2] = 0x80;
-	scsi_cmd[3] = 0;
-	scsi_cmd[4] = 255;
-	scsi_cmd[5] = 0;
-	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_sense_buffer[0] = 0;
-	SRpnt->sr_sense_buffer[2] = 0;
-	SRpnt->sr_data_direction = SCSI_DATA_READ;
-	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page,
-			255, SCSI_TIMEOUT+4*HZ, 3);
-
-	if (SRpnt->sr_result) {
-		kfree(scsi_cmd);
-		goto leave;
-	}
-	/* check to see if response was truncated */
-	if (serialnumber_page[3] > 255) {
-		int max_lgth = serialnumber_page[3] + 4;
-
-		kfree(serialnumber_page);
-		serialnumber_page = kmalloc(max_lgth, 
-			(SDpnt->host->unchecked_isa_dma ? 
-			GFP_DMA : GFP_ATOMIC));
-		if (!serialnumber_page) {
-			kfree(scsi_cmd);
-			return 0;
-		}
-		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
-		scsi_cmd[0] = INQUIRY;
-		if ((lun > 0) && (scsi_level <= SCSI_2))
-			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
-		else
-			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
-		scsi_cmd[2] = 0x80;
-		scsi_cmd[3] = 0;
-		scsi_cmd[4] = max_lgth;
-		scsi_cmd[5] = 0;
-		SRpnt->sr_cmd_len = 0;
-		SRpnt->sr_sense_buffer[0] = 0;
-		SRpnt->sr_sense_buffer[2] = 0;
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
-		scsi_wait_req(SRpnt, (void *) scsi_cmd, 
-				(void *) serialnumber_page,
-				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
-		if (SRpnt->sr_result) {
-			kfree(scsi_cmd);
-			goto leave;
-		}
-	}
-	kfree(scsi_cmd);
-
-	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
-	for(i = 0, j = 1; i < serialnumber_page[3]; i++) {
-		if (serialnumber_page[4 + i] > 0x20)
-			SDpnt->sdev_driverfs_dev.name[j++] = 
-				serialnumber_page[4 + i];
-	}
-	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) {
-		if (SDpnt->vendor[i] > 0x20) {
-			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i];
-		}
-	}
-	kfree(serialnumber_page);
-	return 1;
- leave:
-	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
-	kfree(serialnumber_page);
-	return 0;
-}
 
-int scsi_get_default_name(Scsi_Device *SDpnt)
-{
-	int i, j;
+		for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+			if (sdt->finish && sdt->nr_dev)
+				(*sdt->finish) ();
 
-	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
-	for(i = 0, j = 1; i < 8; i++) {
-		if (SDpnt->vendor[i] > 0x20) {
-			SDpnt->sdev_driverfs_dev.name[j++] = 
-				SDpnt->vendor[i];
-		}
-	}
-	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); 
-	    i < 16; i++) {
-		if (SDpnt->model[i] > 0x20) {
-			SDpnt->sdev_driverfs_dev.name[j++] = 
-				SDpnt->model[i];
-		}
 	}
-	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) {
-		if (SDpnt->rev[i] > 0x20) {
-			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i];
-		}
-	}	
-	return 1;
 }
 
-
-static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+/**
+ * scan_scsis - scan the given adapter, or scan a single LUN
+ * @shost:	adapter to scan
+ * @hardcoded:	1 if a single channel/id/lun should be scanned, else 0
+ * @hchannel:	channel to scan for hardcoded case
+ * @hid:	target id to scan for hardcoded case
+ * @hlun:	lun to scan for hardcoded case
+ *
+ * Description:
+ *     If @hardcoded is 1, call scsi_scan_selected_lun to scan a single
+ *     LUN; else, iterate and call scsi_scan_target to scan all possible
+ *     target id's on all possible channels.
+ **/
+void scan_scsis(struct Scsi_Host *shost, uint hardcoded, uint hchannel,
+		uint hid, uint hlun)
 {
-	unsigned char *evpd_page = NULL;
-	int cnt;
-
-	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
-	evpd_page = scsi_get_evpd_page(SDpnt, SRpnt);
-	if (!evpd_page) {
-		/* try to obtain serial number anyway */
-		if (!scsi_get_serialnumber(SDpnt, SRpnt))
-			goto leave;
-		goto leave;
-	}
-
-	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
-		if (evpd_page[cnt] == 0x83) {
-			if (scsi_get_deviceid(SDpnt, SRpnt))
-				goto leave;
-		}
-	}
+	if (hardcoded == 1) {
+		/*
+		 * XXX Overload hchannel/hid/hlun to figure out what to
+		 * scan, and use the standard scanning code rather than
+		 * this function - that way, an entire bus (or fabric), or
+		 * target id can be scanned. There are problems with queue
+		 * depth and the init/attach/finish that must be resolved
+		 * before (re-)scanning can handle finding more than one new
+		 * LUN.
+		 *
+		 * For example, set hchannel 0 and hid to 5, and hlun to -1
+		 * in order to scan all LUNs on channel 0, target id 5.
+		 */
+		scsi_scan_selected_lun(shost, hchannel, hid, hlun);
+	} else {
+		Scsi_Device *sdevscan;
+		uint channel;
+		unsigned int id, order_id;
 
-	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
-		if (evpd_page[cnt] == 0x80) {
-			if (scsi_get_serialnumber(SDpnt, SRpnt))
-				goto leave;
+		/*
+		 * The blk layer queue allocation is a bit expensive to
+		 * repeat for each channel and id - for FCP max_id is near
+		 * 255: each call to scsi_alloc_sdev() implies a call to
+		 * blk_init_queue, and then blk_init_free_list, where 2 *
+		 * queue_nr_requests requests are allocated. Don't do so
+		 * here for scsi_scan_selected_lun, since we end up
+		 * calling select_queue_depths with an extra Scsi_Device
+		 * on the host_queue list.
+		 */
+		sdevscan = scsi_alloc_sdev(shost, 0, 0, 0);
+		if (sdevscan == NULL)
+			return;
+		/*
+		 * The sdevscan host, channel, id and lun are filled in as
+		 * needed to scan.
+		 */
+		for (channel = 0; channel <= shost->max_channel; channel++) {
+			/*
+			 * XXX adapter drivers when possible (FCP, iSCSI)
+			 * could modify max_id to match the current max,
+			 * not the absolute max.
+			 *
+			 * XXX add a shost id iterator, so for example,
+			 * the FC ID can be the same as a target id
+			 * without a huge overhead of sparse id's.
+			 */
+			for (id = 0; id < shost->max_id; ++id) {
+				if (shost->reverse_ordering)
+					/*
+					 * Scan from high to low id.
+					 */
+					order_id = shost->max_id - id - 1;
+				else
+					order_id = id;
+				scsi_scan_target(sdevscan, shost, channel,
+						 order_id);
+			}
 		}
+		scsi_free_sdev(sdevscan);
 	}
-
-leave:
-	if (SDpnt->sdev_driverfs_dev.name[0] == 0)
-		scsi_get_default_name(SDpnt);
-
-	if (evpd_page) kfree(evpd_page);
-	return;
 }
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/scsi/sg.c	Tue Aug 27 12:28:05 2002
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char * sg_version_str = "Version: 3.5.26 (20020708)";
+static char *sg_version_str = "Version: 3.5.27 (20020812)";
 #endif
- static int sg_version_num = 30525; /* 2 digits for each component */
+static int sg_version_num = 30527;	/* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -74,15 +74,10 @@
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
-#endif /* LINUX_VERSION_CODE */
+#endif				/* LINUX_VERSION_CODE */
 
 #define SG_ALLOW_DIO_DEF 0
-/* #define SG_ALLOW_DIO_CODE */	/* compile out be commenting this define */
-#ifdef SG_ALLOW_DIO_CODE
-#include <linux/iobuf.h>
-#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
-#endif
-
+#define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
 
 #define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
 
@@ -93,1484 +88,1494 @@
    for use by this file descriptor. [Deprecated usage: this variable is also
    readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
    the kernel (i.e. it is not a module).] */
-static int def_reserved_size = -1;      /* picks up init parameter */
+static int def_reserved_size = -1;	/* picks up init parameter */
 static int sg_allow_dio = SG_ALLOW_DIO_DEF;
 
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
-#define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
-#define SG_USER_MEM 4   /* memory belongs to user space */
-
-#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
-
+#define SG_DEV_ARR_LUMP 6	/* amount to over allocate sg_dev_arr by */
 
 static int sg_init(void);
 static int sg_attach(Scsi_Device *);
-static void sg_finish(void);
 static int sg_detect(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
 
-static Scsi_Request * dummy_cmdp;	/* only used for sizeof */
+static Scsi_Request *dummy_cmdp;	/* only used for sizeof */
 
-static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;  /* Also used to lock
-			file descriptor list for device */
+static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;	/* Also used to lock
+							   file descriptor list for device */
 
-static struct Scsi_Device_Template sg_template =
-{
-      module:THIS_MODULE,
-      tag:"sg",
-      scsi_type:0xff,
-      major:SCSI_GENERIC_MAJOR,
-      detect:sg_detect,
-      init:sg_init,
-      finish:sg_finish,
-      attach:sg_attach,
-      detach:sg_detach
+static struct Scsi_Device_Template sg_template = {
+	.module = THIS_MODULE,
+	.name = "generic",
+	.tag = "sg",
+	.scsi_type = 0xff,
+	.major = SCSI_GENERIC_MAJOR,
+	.detect = sg_detect,
+	.init = sg_init,
+	.attach = sg_attach,
+	.detach = sg_detach
 };
 
+typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
+	unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
+	unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+	unsigned bufflen;	/* Size of (aggregate) data buffer */
+	unsigned b_malloc_len;	/* actual len malloc'ed in buffer */
+	void *buffer;		/* Data buffer or scatter list (k_use_sg>0) */
+	char dio_in_use;	/* 0->indirect IO (or mmap), 1->dio */
+	unsigned char cmd_opcode; /* first byte of command */
+} Sg_scatter_hold;
 
-typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
-{
-    unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */
-    unsigned short sglist_len;  /* size of malloc'd scatter-gather list ++ */
-    unsigned bufflen;           /* Size of (aggregate) data buffer */
-    unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list + mem_src_arr */
-#ifdef SG_ALLOW_DIO_CODE
-    struct kiobuf * kiobp;      /* for direct IO information */
-    char mapped;                /* indicates kiobp has locked pages */
-#endif
-    char buffer_mem_src;        /* heap whereabouts of 'buffer' */
-    unsigned char cmd_opcode;   /* first byte of command */
-} Sg_scatter_hold;    /* 24 bytes long on i386 */
-
-struct sg_device;               /* forward declarations */
+struct sg_device;		/* forward declarations */
 struct sg_fd;
 
-typedef struct sg_request  /* SG_MAX_QUEUE requests outstanding per file */
-{
-    Scsi_Request * my_cmdp;     /* != 0  when request with lower levels */
-    struct sg_request * nextrp; /* NULL -> tail request (slist) */
-    struct sg_fd * parentfp;    /* NULL -> not in use */
-    Sg_scatter_hold data;       /* hold buffer, perhaps scatter list */
-    sg_io_hdr_t header;         /* scsi command+info, see <scsi/sg.h> */
-    unsigned char sense_b[sizeof(dummy_cmdp->sr_sense_buffer)];
-    char res_used;              /* 1 -> using reserve buffer, 0 -> not ... */
-    char orphan;                /* 1 -> drop on sight, 0 -> normal */
-    char sg_io_owned;           /* 1 -> packet belongs to SG_IO */
-    volatile char done;         /* 0->before bh, 1->before read, 2->read */
-} Sg_request; /* 168 bytes long on i386 */
-
-typedef struct sg_fd /* holds the state of a file descriptor */
-{
-    struct sg_fd * nextfp; /* NULL when last opened fd on this device */
-    struct sg_device * parentdp;     /* owning device */
-    wait_queue_head_t read_wait;     /* queue read until command done */
-    rwlock_t rq_list_lock;	     /* protect access to list in req_arr */
-    int timeout;                     /* defaults to SG_DEFAULT_TIMEOUT */
-    Sg_scatter_hold reserve;  /* buffer held for this file descriptor */
-    unsigned save_scat_len;   /* original length of trunc. scat. element */
-    Sg_request * headrp;      /* head of request slist, NULL->empty */
-    struct fasync_struct * async_qp; /* used by asynchronous notification */
-    Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
-    char low_dma;       /* as in parent but possibly overridden to 1 */
-    char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
-    volatile char closed; /* 1 -> fd closed but request(s) outstanding */
-    char fd_mem_src;    /* heap whereabouts of this Sg_fd object */
-    char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
-    char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
-    char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
-    char mmap_called;   /* 0 -> mmap() never called on this fd */
-} Sg_fd; /* 2760 bytes long on i386 */
-
-typedef struct sg_device /* holds the state of each scsi generic device */
-{
-    Scsi_Device * device;
-    wait_queue_head_t o_excl_wait;   /* queue open() when O_EXCL in use */
-    int sg_tablesize;   /* adapter's max scatter-gather table size */
-    Sg_fd * headfp;     /* first open fd belonging to this device */
-    devfs_handle_t de;
-    kdev_t i_rdev;      /* holds device major+minor number */
-    volatile char detached;  /* 0->attached, 1->detached pending removal */
-    volatile char exclude;   /* opened for exclusive access */
-    char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
-    struct device sg_driverfs_dev;
-} Sg_device; /* 36 bytes long on i386 */
-
+typedef struct sg_request {	/* SG_MAX_QUEUE requests outstanding per file */
+	Scsi_Request *my_cmdp;	/* != 0  when request with lower levels */
+	struct sg_request *nextrp;	/* NULL -> tail request (slist) */
+	struct sg_fd *parentfp;	/* NULL -> not in use */
+	Sg_scatter_hold data;	/* hold buffer, perhaps scatter list */
+	sg_io_hdr_t header;	/* scsi command+info, see <scsi/sg.h> */
+	unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)];
+	char res_used;		/* 1 -> using reserve buffer, 0 -> not ... */
+	char orphan;		/* 1 -> drop on sight, 0 -> normal */
+	char sg_io_owned;	/* 1 -> packet belongs to SG_IO */
+	volatile char done;	/* 0->before bh, 1->before read, 2->read */
+} Sg_request;
+
+typedef struct sg_fd {		/* holds the state of a file descriptor */
+	struct sg_fd *nextfp;	/* NULL when last opened fd on this device */
+	struct sg_device *parentdp;	/* owning device */
+	wait_queue_head_t read_wait;	/* queue read until command done */
+	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
+	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT */
+	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
+	unsigned save_scat_len;	/* original length of trunc. scat. element */
+	Sg_request *headrp;	/* head of request slist, NULL->empty */
+	struct fasync_struct *async_qp;	/* used by asynchronous notification */
+	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
+	char low_dma;		/* as in parent but possibly overridden to 1 */
+	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
+	volatile char closed;	/* 1 -> fd closed but request(s) outstanding */
+	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
+	char next_cmd_len;	/* 0 -> automatic (def), >0 -> use on next write() */
+	char keep_orphan;	/* 0 -> drop orphan (def), 1 -> keep for read() */
+	char mmap_called;	/* 0 -> mmap() never called on this fd */
+} Sg_fd;
+
+typedef struct sg_device { /* holds the state of each scsi generic device */
+	Scsi_Device *device;
+	wait_queue_head_t o_excl_wait;	/* queue open() when O_EXCL in use */
+	int sg_tablesize;	/* adapter's max scatter-gather table size */
+	Sg_fd *headfp;		/* first open fd belonging to this device */
+	devfs_handle_t de;
+	kdev_t i_rdev;		/* holds device major+minor number */
+	volatile char detached;	/* 0->attached, 1->detached pending removal */
+	volatile char exclude;	/* opened for exclusive access */
+	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+	struct device sg_driverfs_dev;
+} Sg_device;
 
-static int sg_fasync(int fd, struct file * filp, int mode);
-static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt);
+static int sg_fasync(int fd, struct file *filp, int mode);
+static void sg_cmd_done(Scsi_Cmnd * SCpnt);	/* tasklet or soft irq callback */
 static int sg_start_req(Sg_request * srp);
 static void sg_finish_rem_req(Sg_request * srp);
-static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
+static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
 static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
 			 int tablesize);
-static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
+static ssize_t sg_new_read(Sg_fd * sfp, char *buf, size_t count,
 			   Sg_request * srp);
-static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
-			int blocking, int read_only, Sg_request ** o_srp);
+static ssize_t sg_new_write(Sg_fd * sfp, const char *buf, size_t count,
+			    int blocking, int read_only, Sg_request ** o_srp);
 static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
-			   unsigned char * cmnd, int timeout, int blocking);
+			   unsigned char *cmnd, int timeout, int blocking);
 static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
-		      int wr_xf, int * countp, unsigned char ** up);
+		      int wr_xf, int *countp, unsigned char **up);
 static int sg_write_xfer(Sg_request * srp);
 static int sg_read_xfer(Sg_request * srp);
-static int sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer);
+static int sg_read_oxfer(Sg_request * srp, char *outp, int num_read_xfer);
 static void sg_remove_scat(Sg_scatter_hold * schp);
-static char * sg_get_sgat_msa(Sg_scatter_hold * schp);
 static void sg_build_reserve(Sg_fd * sfp, int req_size);
 static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
 static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
-static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
-                        int * mem_srcp);
-static void sg_free(char * buff, int size, int mem_src);
-static char * sg_low_malloc(int rqSz, int lowDma, int mem_src,
-                            int * retSzp);
-static void sg_low_free(char * buff, int size, int mem_src);
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
+static char *sg_page_malloc(int rqSz, int lowDma, int *retSzp);
+static void sg_page_free(char *buff, int size);
+static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
-static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
-static Sg_request * sg_add_request(Sg_fd * sfp);
+static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
+static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
 static int sg_ms_to_jif(unsigned int msecs);
 static inline unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
-static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
-static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
-static Sg_device * sg_get_dev(int dev);
-static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
+static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
+// static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
+static Sg_device *sg_get_dev(int dev);
+static inline unsigned char *sg_scatg2virt(const struct scatterlist *sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
-#ifdef SG_ALLOW_DIO_CODE
-static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
-static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
-#endif
 
-static Sg_device ** sg_dev_arr = NULL;
+static Sg_device **sg_dev_arr = NULL;
 
 #define SZ_SG_HEADER sizeof(struct sg_header)
 #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
 #define SZ_SG_IOVEC sizeof(sg_iovec_t)
 #define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
 
-
-static int sg_open(struct inode * inode, struct file * filp)
+static int
+sg_open(struct inode *inode, struct file *filp)
 {
-    int dev = minor(inode->i_rdev);
-    int flags = filp->f_flags;
-    Sg_device * sdp;
-    Sg_fd * sfp;
-    int res;
-    int retval = -EBUSY;
-
-    SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
-    sdp = sg_get_dev(dev);
-    if ((! sdp) || (! sdp->device))
-        return -ENXIO;
-    if (sdp->detached)
-    	return -ENODEV;
-
-     /* This driver's module count bumped by fops_get in <linux/fs.h> */
-     /* Prevent the device driver from vanishing while we sleep */
-     if (sdp->device->host->hostt->module)
-        __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
-    sdp->device->access_count++;
-
-    if (! ((flags & O_NONBLOCK) ||
-	   scsi_block_when_processing_errors(sdp->device))) {
-        retval = -ENXIO;
-	/* we are in error recovery for this device */
-	goto error_out;
-    }
-
-    if (flags & O_EXCL) {
-        if (O_RDONLY == (flags & O_ACCMODE))  {
-            retval = -EPERM;   /* Can't lock it with read only access */
-	    goto error_out;
-	}
-	if (sdp->headfp && (flags & O_NONBLOCK))
-            goto error_out;
-        res = 0; 
-	__wait_event_interruptible(sdp->o_excl_wait,
-	       ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),
-                                   res);
-        if (res) {
-            retval = res; /* -ERESTARTSYS because signal hit process */
-	    goto error_out;
-        }
-    }
-    else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
-        if (flags & O_NONBLOCK)
-            goto error_out;
-        res = 0; 
-        __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
-        if (res) {
-            retval = res; /* -ERESTARTSYS because signal hit process */
-	    goto error_out;
-        }
-    }
-    if (sdp->detached) {
-    	retval = -ENODEV;
-	goto error_out;
-    }
-    if (! sdp->headfp) { /* no existing opens on this device */
-        sdp->sgdebug = 0;
-        sdp->sg_tablesize = sdp->device->host->sg_tablesize;
-    }
-    if ((sfp = sg_add_sfp(sdp, dev)))
-        filp->private_data = sfp;
-    else {
-        if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
-        retval = -ENOMEM;
-	goto error_out;
-    }
-    return 0;
-
-error_out:
-    sdp->device->access_count--;
-    if ((! sdp->detached) && sdp->device->host->hostt->module)
-        __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
-    return retval;
+	int dev = minor(inode->i_rdev);
+	int flags = filp->f_flags;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	int res;
+	int retval = -EBUSY;
+
+	SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
+	sdp = sg_get_dev(dev);
+	if ((!sdp) || (!sdp->device))
+		return -ENXIO;
+	if (sdp->detached)
+		return -ENODEV;
+
+	/* This driver's module count bumped by fops_get in <linux/fs.h> */
+	/* Prevent the device driver from vanishing while we sleep */
+	if (sdp->device->host->hostt->module)
+		__MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
+	sdp->device->access_count++;
+
+	if (!((flags & O_NONBLOCK) ||
+	      scsi_block_when_processing_errors(sdp->device))) {
+		retval = -ENXIO;
+		/* we are in error recovery for this device */
+		goto error_out;
+	}
+
+	if (flags & O_EXCL) {
+		if (O_RDONLY == (flags & O_ACCMODE)) {
+			retval = -EPERM; /* Can't lock it with read only access */
+			goto error_out;
+		}
+		if (sdp->headfp && (flags & O_NONBLOCK))
+			goto error_out;
+		res = 0;
+		__wait_event_interruptible(sdp->o_excl_wait,
+			((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
+		if (res) {
+			retval = res;	/* -ERESTARTSYS because signal hit process */
+			goto error_out;
+		}
+	} else if (sdp->exclude) {	/* some other fd has an exclusive lock on dev */
+		if (flags & O_NONBLOCK)
+			goto error_out;
+		res = 0;
+		__wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude),
+					   res);
+		if (res) {
+			retval = res;	/* -ERESTARTSYS because signal hit process */
+			goto error_out;
+		}
+	}
+	if (sdp->detached) {
+		retval = -ENODEV;
+		goto error_out;
+	}
+	if (!sdp->headfp) {	/* no existing opens on this device */
+		sdp->sgdebug = 0;
+		sdp->sg_tablesize = sdp->device->host->sg_tablesize;
+	}
+	if ((sfp = sg_add_sfp(sdp, dev)))
+		filp->private_data = sfp;
+	else {
+		if (flags & O_EXCL)
+			sdp->exclude = 0;	/* undo if error */
+		retval = -ENOMEM;
+		goto error_out;
+	}
+	return 0;
+
+      error_out:
+	sdp->device->access_count--;
+	if ((!sdp->detached) && sdp->device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+	return retval;
 }
 
 /* Following function was formerly called 'sg_close' */
-static int sg_release(struct inode * inode, struct file * filp)
+static int
+sg_release(struct inode *inode, struct file *filp)
 {
-    Sg_device * sdp;
-    Sg_fd * sfp;
+	Sg_device *sdp;
+	Sg_fd *sfp;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
-    sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
-    if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
-        if (! sdp->detached) {
-            sdp->device->access_count--;
-            if (sdp->device->host->hostt->module)
-                __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
-        }
-	sdp->exclude = 0;
-	wake_up_interruptible(&sdp->o_excl_wait);
-    }
-    return 0;
-}
-
-static ssize_t sg_read(struct file * filp, char * buf,
-                       size_t count, loff_t *ppos)
-{
-    int k, res;
-    Sg_device * sdp;
-    Sg_fd * sfp;
-    Sg_request * srp;
-    int req_pack_id = -1;
-    struct sg_header old_hdr;
-    sg_io_hdr_t new_hdr;
-    sg_io_hdr_t * hp;
-
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
-                               minor(sdp->i_rdev), (int)count));
-    if (ppos != &filp->f_pos)
-        ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
-    if ((k = verify_area(VERIFY_WRITE, buf, count)))
-        return k;
-    if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
-	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
-	    return -EFAULT;
-	if (old_hdr.reply_len < 0) {
-	    if (count >= SZ_SG_IO_HDR) {
-		if (__copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR))
-		    return -EFAULT;
-		req_pack_id = new_hdr.pack_id;
-	    }
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
+	sg_fasync(-1, filp, 0);	/* remove filp from async notification list */
+	if (0 == sg_remove_sfp(sdp, sfp)) {	/* Returns 1 when sdp gone */
+		if (!sdp->detached) {
+			sdp->device->access_count--;
+			if (sdp->device->host->hostt->module)
+				__MOD_DEC_USE_COUNT(sdp->device->host->hostt->
+						    module);
+		}
+		sdp->exclude = 0;
+		wake_up_interruptible(&sdp->o_excl_wait);
 	}
-	else
-	    req_pack_id = old_hdr.pack_id;
-    }
-    srp = sg_get_rq_mark(sfp, req_pack_id);
-    if (! srp) { /* now wait on packet to arrive */
-	if (sdp->detached)
-	    return -ENODEV;
-        if (filp->f_flags & O_NONBLOCK)
-            return -EAGAIN;
-	while (1) {
-	    res = 0;  /* following is a macro that beats race condition */
-	    __wait_event_interruptible(sfp->read_wait, (sdp->detached || 
-		    (srp = sg_get_rq_mark(sfp, req_pack_id))), res);
-	    if (sdp->detached)
-		return -ENODEV;
-	    if (0 == res)
-		break;
-	    return res; /* -ERESTARTSYS because signal hit process */
+	return 0;
+}
+
+static ssize_t
+sg_read(struct file *filp, char *buf, size_t count, loff_t * ppos)
+{
+	int k, res;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	int req_pack_id = -1;
+	struct sg_header old_hdr;
+	sg_io_hdr_t new_hdr;
+	sg_io_hdr_t *hp;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
+				   minor(sdp->i_rdev), (int) count));
+	if (ppos != &filp->f_pos) ;	/* FIXME: Hmm.  Seek to the right place, or fail?  */
+	if ((k = verify_area(VERIFY_WRITE, buf, count)))
+		return k;
+	if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
+		if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+			return -EFAULT;
+		if (old_hdr.reply_len < 0) {
+			if (count >= SZ_SG_IO_HDR) {
+				if (__copy_from_user
+				    (&new_hdr, buf, SZ_SG_IO_HDR))
+					return -EFAULT;
+				req_pack_id = new_hdr.pack_id;
+			}
+		} else
+			req_pack_id = old_hdr.pack_id;
 	}
-    }
-    if (srp->header.interface_id != '\0')
-	return sg_new_read(sfp, buf, count, srp);
-
-    hp = &srp->header;
-    memset(&old_hdr, 0, SZ_SG_HEADER);
-    old_hdr.reply_len = (int)hp->timeout;
-    old_hdr.pack_len = old_hdr.reply_len;   /* very old, strange behaviour */
-    old_hdr.pack_id = hp->pack_id;
-    old_hdr.twelve_byte =
+	srp = sg_get_rq_mark(sfp, req_pack_id);
+	if (!srp) {		/* now wait on packet to arrive */
+		if (sdp->detached)
+			return -ENODEV;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		while (1) {
+			res = 0;	/* following is a macro that beats race condition */
+			__wait_event_interruptible(sfp->read_wait,
+				(sdp->detached || (srp = sg_get_rq_mark(sfp, req_pack_id))), 
+						   res);
+			if (sdp->detached)
+				return -ENODEV;
+			if (0 == res)
+				break;
+			return res;	/* -ERESTARTSYS because signal hit process */
+		}
+	}
+	if (srp->header.interface_id != '\0')
+		return sg_new_read(sfp, buf, count, srp);
+
+	hp = &srp->header;
+	memset(&old_hdr, 0, SZ_SG_HEADER);
+	old_hdr.reply_len = (int) hp->timeout;
+	old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */
+	old_hdr.pack_id = hp->pack_id;
+	old_hdr.twelve_byte =
 	    ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0;
-    old_hdr.target_status = hp->masked_status;
-    old_hdr.host_status = hp->host_status;
-    old_hdr.driver_status = hp->driver_status;
-    if ((CHECK_CONDITION & hp->masked_status) ||
-	(DRIVER_SENSE & hp->driver_status))
-	memcpy(old_hdr.sense_buffer, srp->sense_b,
-	       sizeof(old_hdr.sense_buffer));
-    switch (hp->host_status)
-    { /* This setup of 'result' is for backward compatibility and is best
-	 ignored by the user who should use target, host + driver status */
+	old_hdr.target_status = hp->masked_status;
+	old_hdr.host_status = hp->host_status;
+	old_hdr.driver_status = hp->driver_status;
+	if ((CHECK_CONDITION & hp->masked_status) ||
+	    (DRIVER_SENSE & hp->driver_status))
+		memcpy(old_hdr.sense_buffer, srp->sense_b,
+		       sizeof (old_hdr.sense_buffer));
+	switch (hp->host_status) {
+	/* This setup of 'result' is for backward compatibility and is best
+	   ignored by the user who should use target, host + driver status */
 	case DID_OK:
 	case DID_PASSTHROUGH:
 	case DID_SOFT_ERROR:
-	    old_hdr.result = 0;
-	    break;
+		old_hdr.result = 0;
+		break;
 	case DID_NO_CONNECT:
 	case DID_BUS_BUSY:
 	case DID_TIME_OUT:
-	    old_hdr.result = EBUSY;
-	    break;
+		old_hdr.result = EBUSY;
+		break;
 	case DID_BAD_TARGET:
 	case DID_ABORT:
 	case DID_PARITY:
 	case DID_RESET:
 	case DID_BAD_INTR:
-	    old_hdr.result = EIO;
-	    break;
+		old_hdr.result = EIO;
+		break;
 	case DID_ERROR:
-	    old_hdr.result =
-	      (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO;
-	    break;
+		old_hdr.result = (srp->sense_b[0] == 0 && 
+				  hp->masked_status == GOOD) ? 0 : EIO;
+		break;
 	default:
-	    old_hdr.result = EIO;
-	    break;
-    }
-
-    /* Now copy the result back to the user buffer.  */
-    if (count >= SZ_SG_HEADER) {
-	if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER))
-	    return -EFAULT;
-	buf += SZ_SG_HEADER;
-	if (count > old_hdr.reply_len)
-	    count = old_hdr.reply_len;
-	if (count > SZ_SG_HEADER) {
-	    if ((res = sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)))
-		return -EFAULT;
+		old_hdr.result = EIO;
+		break;
 	}
-    }
-    else
-	count = (old_hdr.result == 0) ? 0 : -EIO;
-    sg_finish_rem_req(srp);
-    return count;
-}
-
-static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
-			   Sg_request * srp)
-{
-    sg_io_hdr_t * hp = &srp->header;
-    int err = 0;
-    int len;
-
-    if (count < SZ_SG_IO_HDR) {
-	err = -EINVAL;
-    	goto err_out;
-    }
-    hp->sb_len_wr = 0;
-    if ((hp->mx_sb_len > 0) && hp->sbp) {
-	if ((CHECK_CONDITION & hp->masked_status) ||
-	    (DRIVER_SENSE & hp->driver_status)) {
-	    int sb_len = sizeof(dummy_cmdp->sr_sense_buffer);
-	    sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
-	    len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */
-	    len = (len > sb_len) ? sb_len : len;
-	    if ((err = verify_area(VERIFY_WRITE, hp->sbp, len)))
+
+	/* Now copy the result back to the user buffer.  */
+	if (count >= SZ_SG_HEADER) {
+		if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER))
+			return -EFAULT;
+		buf += SZ_SG_HEADER;
+		if (count > old_hdr.reply_len)
+			count = old_hdr.reply_len;
+		if (count > SZ_SG_HEADER) {
+			if ((res =
+			     sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)))
+				return -EFAULT;
+		}
+	} else
+		count = (old_hdr.result == 0) ? 0 : -EIO;
+	sg_finish_rem_req(srp);
+	return count;
+}
+
+static ssize_t
+sg_new_read(Sg_fd * sfp, char *buf, size_t count, Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	int err = 0;
+	int len;
+
+	if (count < SZ_SG_IO_HDR) {
+		err = -EINVAL;
 		goto err_out;
-	    if (__copy_to_user(hp->sbp, srp->sense_b, len)) {
+	}
+	hp->sb_len_wr = 0;
+	if ((hp->mx_sb_len > 0) && hp->sbp) {
+		if ((CHECK_CONDITION & hp->masked_status) ||
+		    (DRIVER_SENSE & hp->driver_status)) {
+			int sb_len = sizeof (dummy_cmdp->sr_sense_buffer);
+			sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
+			len = 8 + (int) srp->sense_b[7];	/* Additional sense length field */
+			len = (len > sb_len) ? sb_len : len;
+			if ((err = verify_area(VERIFY_WRITE, hp->sbp, len)))
+				goto err_out;
+			if (__copy_to_user(hp->sbp, srp->sense_b, len)) {
+				err = -EFAULT;
+				goto err_out;
+			}
+			hp->sb_len_wr = len;
+		}
+	}
+	if (hp->masked_status || hp->host_status || hp->driver_status)
+		hp->info |= SG_INFO_CHECK;
+	if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
 		err = -EFAULT;
 		goto err_out;
-	    }
-	    hp->sb_len_wr = len;
 	}
-    }
-    if (hp->masked_status || hp->host_status || hp->driver_status)
-	hp->info |= SG_INFO_CHECK;
-    if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
-	err = -EFAULT;
-	goto err_out;
-    }
-    err = sg_read_xfer(srp);
-err_out:
-    sg_finish_rem_req(srp);
-    return (0 == err) ? count : err;
-}
-
-
-static ssize_t sg_write(struct file * filp, const char * buf,
-                        size_t count, loff_t *ppos)
-{
-    int                   mxsize, cmd_size, k;
-    int                   input_size, blocking;
-    unsigned char         opcode;
-    Sg_device           * sdp;
-    Sg_fd               * sfp;
-    Sg_request          * srp;
-    struct sg_header      old_hdr;
-    sg_io_hdr_t         * hp;
-    unsigned char         cmnd[sizeof(dummy_cmdp->sr_cmnd)];
-
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
-                               minor(sdp->i_rdev), (int)count));
-    if (sdp->detached)
-    	return -ENODEV;
-    if (! ((filp->f_flags & O_NONBLOCK) ||
-           scsi_block_when_processing_errors(sdp->device)))
-        return -ENXIO;
-    if (ppos != &filp->f_pos)
-        ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
-
-    if ((k = verify_area(VERIFY_READ, buf, count)))
-        return k;  /* protects following copy_from_user()s + get_user()s */
-    if (count < SZ_SG_HEADER)
-	return -EIO;
-    if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
-	return -EFAULT;
-    blocking = !(filp->f_flags & O_NONBLOCK);
-    if (old_hdr.reply_len < 0)
-	return sg_new_write(sfp, buf, count, blocking, 0, NULL);
-    if (count < (SZ_SG_HEADER + 6))
-	return -EIO;   /* The minimum scsi command length is 6 bytes. */
-
-    if (! (srp = sg_add_request(sfp))) {
-	SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
-	return -EDOM;
-    }
-    buf += SZ_SG_HEADER;
-    __get_user(opcode, buf);
-    if (sfp->next_cmd_len > 0) {
-        if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
-            SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
-            sfp->next_cmd_len = 0;
-	    sg_remove_request(sfp, srp);
-            return -EIO;
-        }
-        cmd_size = sfp->next_cmd_len;
-        sfp->next_cmd_len = 0; /* reset so only this write() effected */
-    }
-    else {
-        cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */
-	if ((opcode >= 0xc0) && old_hdr.twelve_byte)
-            cmd_size = 12;
-    }
-    SCSI_LOG_TIMEOUT(4, printk("sg_write:   scsi opcode=0x%02x, cmd_size=%d\n",
-                               (int)opcode, cmd_size));
-/* Determine buffer size.  */
-    input_size = count - cmd_size;
-    mxsize = (input_size > old_hdr.reply_len) ? input_size :
-						old_hdr.reply_len;
-    mxsize -= SZ_SG_HEADER;
-    input_size -= SZ_SG_HEADER;
-    if (input_size < 0) {
-        sg_remove_request(sfp, srp);
-        return -EIO; /* User did not pass enough bytes for this command. */
-    }
-    hp = &srp->header;
-    hp->interface_id = '\0'; /* indicator of old interface tunnelled */
-    hp->cmd_len = (unsigned char)cmd_size;
-    hp->iovec_count = 0;
-    hp->mx_sb_len = 0;
-    if (input_size > 0)
-	hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
-			      SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
-    else
-	hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
-					     SG_DXFER_NONE;
-    hp->dxfer_len = mxsize;
-    hp->dxferp = (unsigned char *)buf + cmd_size;
-    hp->sbp = NULL;
-    hp->timeout = old_hdr.reply_len;    /* structure abuse ... */
-    hp->flags = input_size;             /* structure abuse ... */
-    hp->pack_id = old_hdr.pack_id;
-    hp->usr_ptr = NULL;
-    if (__copy_from_user(cmnd, buf, cmd_size))
-	return -EFAULT;
-    k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
-    return (k < 0) ? k : count;
-}
-
-static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
-			    int blocking, int read_only, Sg_request ** o_srp)
-{
-    int                   k;
-    Sg_request          * srp;
-    sg_io_hdr_t         * hp;
-    unsigned char         cmnd[sizeof(dummy_cmdp->sr_cmnd)];
-    int                   timeout;
-
-    if (count < SZ_SG_IO_HDR)
-	return -EINVAL;
-    if ((k = verify_area(VERIFY_READ, buf, count)))
-	return k;  /* protects following copy_from_user()s + get_user()s */
-
-    sfp->cmd_q = 1;  /* when sg_io_hdr seen, set command queuing on */
-    if (! (srp = sg_add_request(sfp))) {
-	SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n"));
-	return -EDOM;
-    }
-    hp = &srp->header;
-    if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
-	sg_remove_request(sfp, srp);
-	return -EFAULT;
-    }
-    if (hp->interface_id != 'S') {
-	sg_remove_request(sfp, srp);
-	return -ENOSYS;
-    }
-    if (hp->flags & SG_FLAG_MMAP_IO) {
-    	if (hp->dxfer_len > sfp->reserve.bufflen) {
-	    sg_remove_request(sfp, srp);
-	    return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
-	}
-	if (hp->flags & SG_FLAG_DIRECT_IO) {
-	    sg_remove_request(sfp, srp);
-	    return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
-	}
-	if (sg_res_in_use(sfp)) {
-	    sg_remove_request(sfp, srp);
-	    return -EBUSY;	/* reserve buffer already being used */
-	}
-    }
-    timeout = sg_ms_to_jif(srp->header.timeout);
-    if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
-	sg_remove_request(sfp, srp);
-	return -EMSGSIZE;
-    }
-    if ((k = verify_area(VERIFY_READ, hp->cmdp, hp->cmd_len))) {
-	sg_remove_request(sfp, srp);
-	return k;  /* protects following copy_from_user()s + get_user()s */
-    }
-    if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
-	sg_remove_request(sfp, srp);
-	return -EFAULT;
-    }
-    if (read_only &&
-	(! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
-	sg_remove_request(sfp, srp);
-	return -EPERM;
-    }
-    k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
-    if (k < 0) return k;
-    if (o_srp) *o_srp = srp;
-    return count;
+	err = sg_read_xfer(srp);
+      err_out:
+	sg_finish_rem_req(srp);
+	return (0 == err) ? count : err;
 }
 
-static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
-			   unsigned char * cmnd, int timeout, int blocking)
+static ssize_t
+sg_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
 {
-    int                   k;
-    Scsi_Request        * SRpnt;
-    Sg_device           * sdp = sfp->parentdp;
-    sg_io_hdr_t         * hp = &srp->header;
-    request_queue_t	* q;
-
-    srp->data.cmd_opcode = cmnd[0];  /* hold opcode of command */
-    hp->status = 0;
-    hp->masked_status = 0;
-    hp->msg_status = 0;
-    hp->info = 0;
-    hp->host_status = 0;
-    hp->driver_status = 0;
-    hp->resid = 0;
-    SCSI_LOG_TIMEOUT(4,
-	printk("sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
-	       (int)cmnd[0], (int)hp->cmd_len));
+	int mxsize, cmd_size, k;
+	int input_size, blocking;
+	unsigned char opcode;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	struct sg_header old_hdr;
+	sg_io_hdr_t *hp;
+	unsigned char cmnd[sizeof (dummy_cmdp->sr_cmnd)];
 
-    if ((k = sg_start_req(srp))) {
-	SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k));
-	sg_finish_rem_req(srp);
-        return k;    /* probably out of space --> ENOMEM */
-    }
-    if ((k = sg_write_xfer(srp))) {
-	SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n"));
-	sg_finish_rem_req(srp);
-	return k;
-    }
-    if (sdp->detached) {
-    	sg_finish_rem_req(srp);
-    	return -ENODEV;
-    }
-    SRpnt = scsi_allocate_request(sdp->device);
-    if(SRpnt == NULL) {
-    	SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n"));
-    	sg_finish_rem_req(srp);
-    	return -ENOMEM;
-    }
-
-    srp->my_cmdp = SRpnt;
-    q = &SRpnt->sr_device->request_queue;
-    SRpnt->sr_request->rq_dev = sdp->i_rdev;
-    SRpnt->sr_sense_buffer[0] = 0;
-    SRpnt->sr_cmd_len = hp->cmd_len;
-    if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
-	if (sdp->device->scsi_level <= SCSI_2)
-	    cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
-    }
-    SRpnt->sr_use_sg = srp->data.k_use_sg;
-    SRpnt->sr_sglist_len = srp->data.sglist_len;
-    SRpnt->sr_bufflen = srp->data.bufflen;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_buffer = srp->data.buffer;
-    switch (hp->dxfer_direction) {
-    case SG_DXFER_TO_FROM_DEV:
-    case SG_DXFER_FROM_DEV:
-	SRpnt->sr_data_direction = SCSI_DATA_READ; break;
-    case SG_DXFER_TO_DEV:
-	SRpnt->sr_data_direction = SCSI_DATA_WRITE; break;
-    case SG_DXFER_UNKNOWN:
-	SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; break;
-    default:
-	SRpnt->sr_data_direction = SCSI_DATA_NONE; break;
-    }
-    SRpnt->upper_private_data = srp;
-    srp->data.k_use_sg = 0;
-    srp->data.sglist_len = 0;
-    srp->data.bufflen = 0;
-    srp->data.buffer = NULL;
-    hp->duration = jiffies;	/* unit jiffies now, millisecs after done */
-/* Now send everything of to mid-level. The next time we hear about this
-   packet is when sg_cmd_done_bh() is called (i.e. a callback). */
-    scsi_do_req(SRpnt, (void *)cmnd,
-		(void *)SRpnt->sr_buffer, hp->dxfer_len,
-		sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES);
-    /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */
-    generic_unplug_device(q);
-    return 0;
-}
-
-static int sg_ioctl(struct inode * inode, struct file * filp,
-                    unsigned int cmd_in, unsigned long arg)
-{
-    int result, val, read_only;
-    Sg_device * sdp;
-    Sg_fd * sfp;
-    Sg_request * srp;
-    unsigned long iflags;
-
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
-                               minor(sdp->i_rdev), (int)cmd_in));
-    read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
-
-    switch(cmd_in)
-    {
-    case SG_IO:
-	{
-	    int blocking = 1;   /* ignore O_NONBLOCK flag */
-
-	    if (sdp->detached)
-		return -ENODEV;
-	    if(! scsi_block_when_processing_errors(sdp->device) )
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
-	    result = verify_area(VERIFY_WRITE, (void *)arg, SZ_SG_IO_HDR);
-	    if (result) return result;
-	    result = sg_new_write(sfp, (const char *)arg, SZ_SG_IO_HDR,
-				  blocking, read_only, &srp);
-	    if (result < 0) return result;
-	    srp->sg_io_owned = 1;
-	    while (1) {
-		result = 0;  /* following macro to beat race condition */
-		__wait_event_interruptible(sfp->read_wait,
-		       (sdp->detached || sfp->closed || srp->done), result);
-		if (sdp->detached)
-		    return -ENODEV;
-		if (sfp->closed)
-		    return 0;       /* request packet dropped already */
-		if (0 == result)
-		    break;
-		srp->orphan = 1;
-		return result; /* -ERESTARTSYS because signal hit process */
-	    }
-	    srp->done = 2;
-	    result = sg_new_read(sfp, (char *)arg, SZ_SG_IO_HDR, srp);
-	    return (result < 0) ? result : 0;
-	}
-    case SG_SET_TIMEOUT:
-        result =  get_user(val, (int *)arg);
-        if (result) return result;
-        if (val < 0)
-            return -EIO;
-        sfp->timeout = val;
-        return 0;
-    case SG_GET_TIMEOUT:  /* N.B. User receives timeout as return value */
-        return sfp->timeout; /* strange ..., for backward compatibility */
-    case SG_SET_FORCE_LOW_DMA:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        if (val) {
-            sfp->low_dma = 1;
-            if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-                val = (int)sfp->reserve.bufflen;
-                sg_remove_scat(&sfp->reserve);
-                sg_build_reserve(sfp, val);
-            }
-        }
-        else {
-	    if (sdp->detached)
+	SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
+				   minor(sdp->i_rdev), (int) count));
+	if (sdp->detached)
 		return -ENODEV;
-            sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-	}
-        return 0;
-    case SG_GET_LOW_DMA:
-        return put_user((int)sfp->low_dma, (int *)arg);
-    case SG_GET_SCSI_ID:
-	result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(sg_scsi_id_t));
-        if (result) return result;
-        else {
-	    sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg;
+	if (!((filp->f_flags & O_NONBLOCK) ||
+	      scsi_block_when_processing_errors(sdp->device)))
+		return -ENXIO;
+	if (ppos != &filp->f_pos) ;	/* FIXME: Hmm.  Seek to the right place, or fail?  */
 
-	    if (sdp->detached)
-		return -ENODEV;
-            __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
-            __put_user((int)sdp->device->channel, &sg_idp->channel);
-            __put_user((int)sdp->device->id, &sg_idp->scsi_id);
-            __put_user((int)sdp->device->lun, &sg_idp->lun);
-            __put_user((int)sdp->device->type, &sg_idp->scsi_type);
-	    __put_user((short)sdp->device->host->cmd_per_lun,
-                       &sg_idp->h_cmd_per_lun);
-	    __put_user((short)sdp->device->queue_depth,
-                       &sg_idp->d_queue_depth);
-	    __put_user(0, &sg_idp->unused[0]);
-	    __put_user(0, &sg_idp->unused[1]);
-            return 0;
-        }
-    case SG_SET_FORCE_PACK_ID:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        sfp->force_packid = val ? 1 : 0;
-        return 0;
-    case SG_GET_PACK_ID:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-	read_lock_irqsave(&sfp->rq_list_lock, iflags);
-	for (srp = sfp->headrp; srp; srp = srp->nextrp) {
-	    if ((1 == srp->done) && (! srp->sg_io_owned)) {
-		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-                __put_user(srp->header.pack_id, (int *)arg);
-                return 0;
-            }
-        }
-	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-        __put_user(-1, (int *)arg);
-        return 0;
-    case SG_GET_NUM_WAITING:
-	read_lock_irqsave(&sfp->rq_list_lock, iflags);
-        for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
-	    if ((1 == srp->done) && (! srp->sg_io_owned))
-                ++val;
-        }
-	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-        return put_user(val, (int *)arg);
-    case SG_GET_SG_TABLESIZE:
-        return put_user(sdp->sg_tablesize, (int *)arg);
-    case SG_SET_RESERVED_SIZE:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        if (val != sfp->reserve.bufflen) {
-            if (sg_res_in_use(sfp) || sfp->mmap_called)
-                return -EBUSY;
-            sg_remove_scat(&sfp->reserve);
-            sg_build_reserve(sfp, val);
-        }
-        return 0;
-    case SG_GET_RESERVED_SIZE:
-        val = (int)sfp->reserve.bufflen;
-        return put_user(val, (int *)arg);
-    case SG_SET_COMMAND_Q:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        sfp->cmd_q = val ? 1 : 0;
-        return 0;
-    case SG_GET_COMMAND_Q:
-        return put_user((int)sfp->cmd_q, (int *)arg);
-    case SG_SET_KEEP_ORPHAN:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-	sfp->keep_orphan = val;
-        return 0;
-    case SG_GET_KEEP_ORPHAN:
-	return put_user((int)sfp->keep_orphan, (int *)arg);
-    case SG_NEXT_CMD_LEN:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        sfp->next_cmd_len = (val > 0) ? val : 0;
-        return 0;
-    case SG_GET_VERSION_NUM:
-        return put_user(sg_version_num, (int *)arg);
-    case SG_GET_ACCESS_COUNT:
-    	val = (sdp->device ? sdp->device->access_count : 0);
-	return put_user(val, (int *)arg);
-    case SG_GET_REQUEST_TABLE:
-	result = verify_area(VERIFY_WRITE, (void *) arg,
-			     SZ_SG_REQ_INFO * SG_MAX_QUEUE);
-	if (result) return result;
-	else {
-	    sg_req_info_t rinfo[SG_MAX_QUEUE];
-	    Sg_request * srp;
-	    read_lock_irqsave(&sfp->rq_list_lock, iflags);
-	    for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
-		 ++val, srp = srp ? srp->nextrp : srp) {
-		memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
-		if (srp) {
-		    rinfo[val].req_state = srp->done + 1;
-		    rinfo[val].problem = srp->header.masked_status &
-			srp->header.host_status & srp->header.driver_status;
-		    rinfo[val].duration = srp->done ?
-			    srp->header.duration :
-			    sg_jif_to_ms(jiffies - srp->header.duration);
-		    rinfo[val].orphan = srp->orphan;
-		    rinfo[val].sg_io_owned = srp->sg_io_owned;
-		    rinfo[val].pack_id = srp->header.pack_id;
-		    rinfo[val].usr_ptr = srp->header.usr_ptr;
-		}
-	    }
-	    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	    return (__copy_to_user((void *)arg, rinfo, 
-			SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0);
+	if ((k = verify_area(VERIFY_READ, buf, count)))
+		return k;	/* protects following copy_from_user()s + get_user()s */
+	if (count < SZ_SG_HEADER)
+		return -EIO;
+	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+		return -EFAULT;
+	blocking = !(filp->f_flags & O_NONBLOCK);
+	if (old_hdr.reply_len < 0)
+		return sg_new_write(sfp, buf, count, blocking, 0, NULL);
+	if (count < (SZ_SG_HEADER + 6))
+		return -EIO;	/* The minimum scsi command length is 6 bytes. */
+
+	if (!(srp = sg_add_request(sfp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
+		return -EDOM;
 	}
-    case SG_EMULATED_HOST:
-	if (sdp->detached)
-	    return -ENODEV;
-        return put_user(sdp->device->host->hostt->emulated, (int *)arg);
-    case SG_SCSI_RESET:
-	if (sdp->detached)
-	    return -ENODEV;
-        if (filp->f_flags & O_NONBLOCK) {
-	    if (sdp->device->host->in_recovery)
-		return -EBUSY;
-	}
-	else if (! scsi_block_when_processing_errors(sdp->device))
-            return -EBUSY;
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-	if (SG_SCSI_RESET_NOTHING == val)
-	    return 0;
-#ifdef SCSI_TRY_RESET_DEVICE
-	switch (val)
-	{
-	case SG_SCSI_RESET_DEVICE:
-	    val = SCSI_TRY_RESET_DEVICE;
-	    break;
-	case SG_SCSI_RESET_BUS:
-	    val = SCSI_TRY_RESET_BUS;
-	    break;
-	case SG_SCSI_RESET_HOST:
-	    val = SCSI_TRY_RESET_HOST;
-	    break;
-	default:
-	    return -EINVAL;
+	buf += SZ_SG_HEADER;
+	__get_user(opcode, buf);
+	if (sfp->next_cmd_len > 0) {
+		if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+			SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+			sfp->next_cmd_len = 0;
+			sg_remove_request(sfp, srp);
+			return -EIO;
+		}
+		cmd_size = sfp->next_cmd_len;
+		sfp->next_cmd_len = 0;	/* reset so only this write() effected */
+	} else {
+		cmd_size = COMMAND_SIZE(opcode);	/* based on SCSI command group */
+		if ((opcode >= 0xc0) && old_hdr.twelve_byte)
+			cmd_size = 12;
 	}
-	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-	    return -EACCES;
-	return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
-#else
-	SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
-	result = -EINVAL;
-#endif
-    case SCSI_IOCTL_SEND_COMMAND:
-	if (sdp->detached)
-	    return -ENODEV;
-	if (read_only) {
-	    unsigned char opcode = WRITE_6;
-	    Scsi_Ioctl_Command * siocp = (void *)arg;
+	SCSI_LOG_TIMEOUT(4, printk(
+		"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
+/* Determine buffer size.  */
+	input_size = count - cmd_size;
+	mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len;
+	mxsize -= SZ_SG_HEADER;
+	input_size -= SZ_SG_HEADER;
+	if (input_size < 0) {
+		sg_remove_request(sfp, srp);
+		return -EIO;	/* User did not pass enough bytes for this command. */
+	}
+	hp = &srp->header;
+	hp->interface_id = '\0';	/* indicator of old interface tunnelled */
+	hp->cmd_len = (unsigned char) cmd_size;
+	hp->iovec_count = 0;
+	hp->mx_sb_len = 0;
+	if (input_size > 0)
+		hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
+		    SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
+	else
+		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
+	hp->dxfer_len = mxsize;
+	hp->dxferp = (unsigned char *) buf + cmd_size;
+	hp->sbp = NULL;
+	hp->timeout = old_hdr.reply_len;	/* structure abuse ... */
+	hp->flags = input_size;	/* structure abuse ... */
+	hp->pack_id = old_hdr.pack_id;
+	hp->usr_ptr = NULL;
+	if (__copy_from_user(cmnd, buf, cmd_size))
+		return -EFAULT;
+	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
+	return (k < 0) ? k : count;
+}
 
-	    if (copy_from_user(&opcode, siocp->data, 1))
+static ssize_t
+sg_new_write(Sg_fd * sfp, const char *buf, size_t count,
+	     int blocking, int read_only, Sg_request ** o_srp)
+{
+	int k;
+	Sg_request *srp;
+	sg_io_hdr_t *hp;
+	unsigned char cmnd[sizeof (dummy_cmdp->sr_cmnd)];
+	int timeout;
+
+	if (count < SZ_SG_IO_HDR)
+		return -EINVAL;
+	if ((k = verify_area(VERIFY_READ, buf, count)))
+		return k; /* protects following copy_from_user()s + get_user()s */
+
+	sfp->cmd_q = 1;	/* when sg_io_hdr seen, set command queuing on */
+	if (!(srp = sg_add_request(sfp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n"));
+		return -EDOM;
+	}
+	hp = &srp->header;
+	if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
+		sg_remove_request(sfp, srp);
+		return -EFAULT;
+	}
+	if (hp->interface_id != 'S') {
+		sg_remove_request(sfp, srp);
+		return -ENOSYS;
+	}
+	if (hp->flags & SG_FLAG_MMAP_IO) {
+		if (hp->dxfer_len > sfp->reserve.bufflen) {
+			sg_remove_request(sfp, srp);
+			return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
+		}
+		if (hp->flags & SG_FLAG_DIRECT_IO) {
+			sg_remove_request(sfp, srp);
+			return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
+		}
+		if (sg_res_in_use(sfp)) {
+			sg_remove_request(sfp, srp);
+			return -EBUSY;	/* reserve buffer already being used */
+		}
+	}
+	timeout = sg_ms_to_jif(srp->header.timeout);
+	if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) {
+		sg_remove_request(sfp, srp);
+		return -EMSGSIZE;
+	}
+	if ((k = verify_area(VERIFY_READ, hp->cmdp, hp->cmd_len))) {
+		sg_remove_request(sfp, srp);
+		return k;	/* protects following copy_from_user()s + get_user()s */
+	}
+	if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
+		sg_remove_request(sfp, srp);
 		return -EFAULT;
-	    if (! sg_allow_access(opcode, sdp->device->type))
+	}
+	if (read_only &&
+	    (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
+		sg_remove_request(sfp, srp);
 		return -EPERM;
 	}
-        return scsi_ioctl_send_command(sdp->device, (void *)arg);
-    case SG_SET_DEBUG:
-        result = get_user(val, (int *)arg);
-        if (result) return result;
-        sdp->sgdebug = (char)val;
-        return 0;
-    case SCSI_IOCTL_GET_IDLUN:
-    case SCSI_IOCTL_GET_BUS_NUMBER:
-    case SCSI_IOCTL_PROBE_HOST:
-    case SG_GET_TRANSFORM:
-	if (sdp->detached)
-	    return -ENODEV;
-        return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
-    default:
-	if (read_only)
-            return -EPERM; /* don't know so take safe approach */
-        return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
-    }
-}
-
-static unsigned int sg_poll(struct file * filp, poll_table * wait)
-{
-    unsigned int res = 0;
-    Sg_device * sdp;
-    Sg_fd * sfp;
-    Sg_request * srp;
-    int count = 0;
-    unsigned long iflags;
-
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))
-    	|| sfp->closed)
-        return POLLERR;
-    poll_wait(filp, &sfp->read_wait, wait);
-    read_lock_irqsave(&sfp->rq_list_lock, iflags);
-    for (srp = sfp->headrp; srp; srp = srp->nextrp) {   
-    	/* if any read waiting, flag it */
-	if ((0 == res) && (1 == srp->done) && (! srp->sg_io_owned))
-            res = POLLIN | POLLRDNORM;
-        ++count;
-    }
-    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-
-    if (sdp->detached)
-	res |= POLLHUP;
-    else if (! sfp->cmd_q) {
-        if (0 == count)
-            res |= POLLOUT | POLLWRNORM;
-    }
-    else if (count < SG_MAX_QUEUE)
-        res |= POLLOUT | POLLWRNORM;
-    SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n",
-                        minor(sdp->i_rdev), (int)res));
-    return res;
-}
-
-static int sg_fasync(int fd, struct file * filp, int mode)
-{
-    int retval;
-    Sg_device * sdp;
-    Sg_fd * sfp;
-
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n",
-                               minor(sdp->i_rdev), mode));
-
-    retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
-    return (retval < 0) ? retval : 0;
-}
-
-static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
-{
-    return (sclp && sclp->page) ? 
-    		(unsigned char *)page_address(sclp->page) + sclp->offset :
-		NULL;
-}
-
-static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
-{
-    void * page_ptr;
-    struct page * page;
-    int k, m;
-
-    SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
-			   "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); 
-    /* N.B. correction _not_ applied to base page of aech allocation */
-    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
-        struct scatterlist * sclp = rsv_schp->buffer;
-
-        for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
-	    for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
-		page_ptr = sg_scatg2virt(sclp) + m;
-		page = virt_to_page(page_ptr);
-		if (startFinish)
-		    get_page(page);	/* increment page count */
+	k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
+	if (k < 0)
+		return k;
+	if (o_srp)
+		*o_srp = srp;
+	return count;
+}
+
+static int
+sg_common_write(Sg_fd * sfp, Sg_request * srp,
+		unsigned char *cmnd, int timeout, int blocking)
+{
+	int k;
+	Scsi_Request *SRpnt;
+	Sg_device *sdp = sfp->parentdp;
+	sg_io_hdr_t *hp = &srp->header;
+	request_queue_t *q;
+
+	srp->data.cmd_opcode = cmnd[0];	/* hold opcode of command */
+	hp->status = 0;
+	hp->masked_status = 0;
+	hp->msg_status = 0;
+	hp->info = 0;
+	hp->host_status = 0;
+	hp->driver_status = 0;
+	hp->resid = 0;
+	SCSI_LOG_TIMEOUT(4, printk("sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
+			  (int) cmnd[0], (int) hp->cmd_len));
+
+	if ((k = sg_start_req(srp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k));
+		sg_finish_rem_req(srp);
+		return k;	/* probably out of space --> ENOMEM */
+	}
+	if ((k = sg_write_xfer(srp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n"));
+		sg_finish_rem_req(srp);
+		return k;
+	}
+	if (sdp->detached) {
+		sg_finish_rem_req(srp);
+		return -ENODEV;
+	}
+	SRpnt = scsi_allocate_request(sdp->device);
+	if (SRpnt == NULL) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n"));
+		sg_finish_rem_req(srp);
+		return -ENOMEM;
+	}
+
+	srp->my_cmdp = SRpnt;
+	q = &SRpnt->sr_device->request_queue;
+	SRpnt->sr_request->rq_dev = sdp->i_rdev;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_cmd_len = hp->cmd_len;
+	if (!(hp->flags & SG_FLAG_LUN_INHIBIT)) {
+		if (sdp->device->scsi_level <= SCSI_2)
+			cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+	}
+	SRpnt->sr_use_sg = srp->data.k_use_sg;
+	SRpnt->sr_sglist_len = srp->data.sglist_len;
+	SRpnt->sr_bufflen = srp->data.bufflen;
+	SRpnt->sr_underflow = 0;
+	SRpnt->sr_buffer = srp->data.buffer;
+	switch (hp->dxfer_direction) {
+	case SG_DXFER_TO_FROM_DEV:
+	case SG_DXFER_FROM_DEV:
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		break;
+	case SG_DXFER_TO_DEV:
+		SRpnt->sr_data_direction = SCSI_DATA_WRITE;
+		break;
+	case SG_DXFER_UNKNOWN:
+		SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+		break;
+	default:
+		SRpnt->sr_data_direction = SCSI_DATA_NONE;
+		break;
+	}
+	SRpnt->upper_private_data = srp;
+	srp->data.k_use_sg = 0;
+	srp->data.sglist_len = 0;
+	srp->data.bufflen = 0;
+	srp->data.buffer = NULL;
+	hp->duration = jiffies;	/* unit jiffies now, millisecs after done */
+/* Now send everything of to mid-level. The next time we hear about this
+   packet is when sg_cmd_done() is called (i.e. a callback). */
+	scsi_do_req(SRpnt, (void *) cmnd,
+		    (void *) SRpnt->sr_buffer, hp->dxfer_len,
+		    sg_cmd_done, timeout, SG_DEFAULT_RETRIES);
+	/* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */
+	generic_unplug_device(q);
+	return 0;
+}
+
+static int
+sg_ioctl(struct inode *inode, struct file *filp,
+	 unsigned int cmd_in, unsigned long arg)
+{
+	int result, val, read_only;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	unsigned long iflags;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
+				   minor(sdp->i_rdev), (int) cmd_in));
+	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
+
+	switch (cmd_in) {
+	case SG_IO:
+		{
+			int blocking = 1;	/* ignore O_NONBLOCK flag */
+
+			if (sdp->detached)
+				return -ENODEV;
+			if (!scsi_block_when_processing_errors(sdp->device))
+				return -ENXIO;
+			result = verify_area(VERIFY_WRITE, (void *) arg,
+					SZ_SG_IO_HDR);
+			if (result)
+				return result;
+			result =
+			    sg_new_write(sfp, (const char *) arg, SZ_SG_IO_HDR,
+					 blocking, read_only, &srp);
+			if (result < 0)
+				return result;
+			srp->sg_io_owned = 1;
+			while (1) {
+				result = 0;	/* following macro to beat race condition */
+				__wait_event_interruptible(sfp->read_wait,
+					(sdp->detached || sfp->closed || srp->done),
+							   result);
+				if (sdp->detached)
+					return -ENODEV;
+				if (sfp->closed)
+					return 0;	/* request packet dropped already */
+				if (0 == result)
+					break;
+				srp->orphan = 1;
+				return result;	/* -ERESTARTSYS because signal hit process */
+			}
+			srp->done = 2;
+			result = sg_new_read(sfp, (char *) arg, SZ_SG_IO_HDR, srp);
+			return (result < 0) ? result : 0;
+		}
+	case SG_SET_TIMEOUT:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		if (val < 0)
+			return -EIO;
+		sfp->timeout = val;
+		return 0;
+	case SG_GET_TIMEOUT:	/* N.B. User receives timeout as return value */
+		return sfp->timeout;	/* strange ..., for backward compatibility */
+	case SG_SET_FORCE_LOW_DMA:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		if (val) {
+			sfp->low_dma = 1;
+			if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+				val = (int) sfp->reserve.bufflen;
+				sg_remove_scat(&sfp->reserve);
+				sg_build_reserve(sfp, val);
+			}
+		} else {
+			if (sdp->detached)
+				return -ENODEV;
+			sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+		}
+		return 0;
+	case SG_GET_LOW_DMA:
+		return put_user((int) sfp->low_dma, (int *) arg);
+	case SG_GET_SCSI_ID:
+		result =
+		    verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof (sg_scsi_id_t));
+		if (result)
+			return result;
 		else {
-		    if (page_count(page) > 0)
-			put_page_testzero(page); /* decrement page count */
+			sg_scsi_id_t *sg_idp = (sg_scsi_id_t *) arg;
+
+			if (sdp->detached)
+				return -ENODEV;
+			__put_user((int) sdp->device->host->host_no,
+				   &sg_idp->host_no);
+			__put_user((int) sdp->device->channel,
+				   &sg_idp->channel);
+			__put_user((int) sdp->device->id, &sg_idp->scsi_id);
+			__put_user((int) sdp->device->lun, &sg_idp->lun);
+			__put_user((int) sdp->device->type, &sg_idp->scsi_type);
+			__put_user((short) sdp->device->host->cmd_per_lun,
+				   &sg_idp->h_cmd_per_lun);
+			__put_user((short) sdp->device->queue_depth,
+				   &sg_idp->d_queue_depth);
+			__put_user(0, &sg_idp->unused[0]);
+			__put_user(0, &sg_idp->unused[1]);
+			return 0;
 		}
-	    }
-        }
-    }
-    else { /* reserve buffer is just a single allocation */
-	for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
-	    page_ptr = (unsigned char *)rsv_schp->buffer + m;
-	    page = virt_to_page(page_ptr);
-	    if (startFinish)
-		get_page(page);	/* increment page count */
-	    else {
-		if (page_count(page) > 0)
-		    put_page_testzero(page); /* decrement page count */
-	    }
+	case SG_SET_FORCE_PACK_ID:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		sfp->force_packid = val ? 1 : 0;
+		return 0;
+	case SG_GET_PACK_ID:
+		result = verify_area(VERIFY_WRITE, (void *) arg, sizeof (int));
+		if (result)
+			return result;
+		read_lock_irqsave(&sfp->rq_list_lock, iflags);
+		for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+			if ((1 == srp->done) && (!srp->sg_io_owned)) {
+				read_unlock_irqrestore(&sfp->rq_list_lock,
+						       iflags);
+				__put_user(srp->header.pack_id, (int *) arg);
+				return 0;
+			}
+		}
+		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+		__put_user(-1, (int *) arg);
+		return 0;
+	case SG_GET_NUM_WAITING:
+		read_lock_irqsave(&sfp->rq_list_lock, iflags);
+		for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+			if ((1 == srp->done) && (!srp->sg_io_owned))
+				++val;
+		}
+		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+		return put_user(val, (int *) arg);
+	case SG_GET_SG_TABLESIZE:
+		return put_user(sdp->sg_tablesize, (int *) arg);
+	case SG_SET_RESERVED_SIZE:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		if (val != sfp->reserve.bufflen) {
+			if (sg_res_in_use(sfp) || sfp->mmap_called)
+				return -EBUSY;
+			sg_remove_scat(&sfp->reserve);
+			sg_build_reserve(sfp, val);
+		}
+		return 0;
+	case SG_GET_RESERVED_SIZE:
+		val = (int) sfp->reserve.bufflen;
+		return put_user(val, (int *) arg);
+	case SG_SET_COMMAND_Q:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		sfp->cmd_q = val ? 1 : 0;
+		return 0;
+	case SG_GET_COMMAND_Q:
+		return put_user((int) sfp->cmd_q, (int *) arg);
+	case SG_SET_KEEP_ORPHAN:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		sfp->keep_orphan = val;
+		return 0;
+	case SG_GET_KEEP_ORPHAN:
+		return put_user((int) sfp->keep_orphan, (int *) arg);
+	case SG_NEXT_CMD_LEN:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		sfp->next_cmd_len = (val > 0) ? val : 0;
+		return 0;
+	case SG_GET_VERSION_NUM:
+		return put_user(sg_version_num, (int *) arg);
+	case SG_GET_ACCESS_COUNT:
+		val = (sdp->device ? sdp->device->access_count : 0);
+		return put_user(val, (int *) arg);
+	case SG_GET_REQUEST_TABLE:
+		result = verify_area(VERIFY_WRITE, (void *) arg,
+				     SZ_SG_REQ_INFO * SG_MAX_QUEUE);
+		if (result)
+			return result;
+		else {
+			sg_req_info_t rinfo[SG_MAX_QUEUE];
+			Sg_request *srp;
+			read_lock_irqsave(&sfp->rq_list_lock, iflags);
+			for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
+			     ++val, srp = srp ? srp->nextrp : srp) {
+				memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+				if (srp) {
+					rinfo[val].req_state = srp->done + 1;
+					rinfo[val].problem =
+					    srp->header.masked_status & 
+					    srp->header.host_status & 
+					    srp->header.driver_status;
+					rinfo[val].duration =
+					    srp->done ? srp->header.duration :
+					    sg_jif_to_ms(
+						jiffies - srp->header.duration);
+					rinfo[val].orphan = srp->orphan;
+					rinfo[val].sg_io_owned = srp->sg_io_owned;
+					rinfo[val].pack_id = srp->header.pack_id;
+					rinfo[val].usr_ptr = srp->header.usr_ptr;
+				}
+			}
+			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+			return (__copy_to_user((void *) arg, rinfo,
+			        SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0);
+		}
+	case SG_EMULATED_HOST:
+		if (sdp->detached)
+			return -ENODEV;
+		return put_user(sdp->device->host->hostt->emulated, (int *) arg);
+	case SG_SCSI_RESET:
+		if (sdp->detached)
+			return -ENODEV;
+		if (filp->f_flags & O_NONBLOCK) {
+			if (sdp->device->host->in_recovery)
+				return -EBUSY;
+		} else if (!scsi_block_when_processing_errors(sdp->device))
+			return -EBUSY;
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		if (SG_SCSI_RESET_NOTHING == val)
+			return 0;
+		switch (val) {
+		case SG_SCSI_RESET_DEVICE:
+			val = SCSI_TRY_RESET_DEVICE;
+			break;
+		case SG_SCSI_RESET_BUS:
+			val = SCSI_TRY_RESET_BUS;
+			break;
+		case SG_SCSI_RESET_HOST:
+			val = SCSI_TRY_RESET_HOST;
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return (scsi_reset_provider(sdp->device, val) ==
+			SUCCESS) ? 0 : -EIO;
+	case SCSI_IOCTL_SEND_COMMAND:
+		if (sdp->detached)
+			return -ENODEV;
+		if (read_only) {
+			unsigned char opcode = WRITE_6;
+			Scsi_Ioctl_Command *siocp = (void *) arg;
+
+			if (copy_from_user(&opcode, siocp->data, 1))
+				return -EFAULT;
+			if (!sg_allow_access(opcode, sdp->device->type))
+				return -EPERM;
+		}
+		return scsi_ioctl_send_command(sdp->device, (void *) arg);
+	case SG_SET_DEBUG:
+		result = get_user(val, (int *) arg);
+		if (result)
+			return result;
+		sdp->sgdebug = (char) val;
+		return 0;
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+	case SCSI_IOCTL_PROBE_HOST:
+	case SG_GET_TRANSFORM:
+		if (sdp->detached)
+			return -ENODEV;
+		return scsi_ioctl(sdp->device, cmd_in, (void *) arg);
+	default:
+		if (read_only)
+			return -EPERM;	/* don't know so take safe approach */
+		return scsi_ioctl(sdp->device, cmd_in, (void *) arg);
 	}
-    }
 }
 
-static struct page * sg_vma_nopage(struct vm_area_struct *vma, 
-				   unsigned long addr, int unused)
+static unsigned int
+sg_poll(struct file *filp, poll_table * wait)
 {
-    Sg_fd * sfp;
-    struct page * page = NOPAGE_SIGBUS;
-    void * page_ptr = NULL;
-    unsigned long offset;
-    Sg_scatter_hold * rsv_schp;
+	unsigned int res = 0;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	int count = 0;
+	unsigned long iflags;
 
-    if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
-	return page;
-    rsv_schp = &sfp->reserve;
-    offset = addr - vma->vm_start;
-    if (offset >= rsv_schp->bufflen)
-	return page;
-    SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", 
-			       offset, rsv_schp->k_use_sg));
-    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
-        int k;
-        unsigned long sa = vma->vm_start;
-        unsigned long len;
-        struct scatterlist * sclp = rsv_schp->buffer;
-
-        for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
-             ++k, ++sclp) {
-            len = vma->vm_end - sa;
-            len = (len < sclp->length) ? len : sclp->length;
-	    if (offset < len) {
-		page_ptr = sg_scatg2virt(sclp) + offset;
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))
+	    || sfp->closed)
+		return POLLERR;
+	poll_wait(filp, &sfp->read_wait, wait);
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+		/* if any read waiting, flag it */
+		if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
+			res = POLLIN | POLLRDNORM;
+		++count;
+	}
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+
+	if (sdp->detached)
+		res |= POLLHUP;
+	else if (!sfp->cmd_q) {
+		if (0 == count)
+			res |= POLLOUT | POLLWRNORM;
+	} else if (count < SG_MAX_QUEUE)
+		res |= POLLOUT | POLLWRNORM;
+	SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n",
+				   minor(sdp->i_rdev), (int) res));
+	return res;
+}
+
+static int
+sg_fasync(int fd, struct file *filp, int mode)
+{
+	int retval;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n",
+				   minor(sdp->i_rdev), mode));
+
+	retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
+	return (retval < 0) ? retval : 0;
+}
+
+static inline unsigned char *
+sg_scatg2virt(const struct scatterlist *sclp)
+{
+	return (sclp && sclp->page) ?
+	    (unsigned char *) page_address(sclp->page) + sclp->offset : NULL;
+}
+
+/* When startFinish==1 increments page counts for pages other than the 
+   first of scatter gather elements obtained from __get_free_pages().
+   When startFinish==0 decrements ... */
+static void
+sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+	void *page_ptr;
+	struct page *page;
+	int k, m;
+
+	SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, scatg=%d\n", 
+				   startFinish, rsv_schp->k_use_sg));
+	/* N.B. correction _not_ applied to base page of each allocation */
+	if (rsv_schp->k_use_sg) {	/* reserve buffer is a scatter gather list */
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+			for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+				page_ptr = sg_scatg2virt(sclp) + m;
+				page = virt_to_page(page_ptr);
+				if (startFinish)
+					atomic_inc(&page->count);
+				else {
+					if (page_count(page) > 0)
+						atomic_dec(&page->count);
+				}
+			}
+		}
+	} else {		/* reserve buffer is just a single allocation */
+		for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+			page_ptr = (unsigned char *) rsv_schp->buffer + m;
+			page = virt_to_page(page_ptr);
+			if (startFinish)
+				atomic_inc(&page->count);
+			else {
+				if (page_count(page) > 0)
+					atomic_dec(&page->count);
+			}
+		}
+	}
+}
+
+static struct page *
+sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int unused)
+{
+	Sg_fd *sfp;
+	struct page *page = NOPAGE_SIGBUS;
+	void *page_ptr = NULL;
+	unsigned long offset;
+	Sg_scatter_hold *rsv_schp;
+
+	if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
+		return page;
+	rsv_schp = &sfp->reserve;
+	offset = addr - vma->vm_start;
+	if (offset >= rsv_schp->bufflen)
+		return page;
+	SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n",
+				   offset, rsv_schp->k_use_sg));
+	if (rsv_schp->k_use_sg) {	/* reserve buffer is a scatter gather list */
+		int k;
+		unsigned long sa = vma->vm_start;
+		unsigned long len;
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+		     ++k, ++sclp) {
+			len = vma->vm_end - sa;
+			len = (len < sclp->length) ? len : sclp->length;
+			if (offset < len) {
+				page_ptr = sg_scatg2virt(sclp) + offset;
+				page = virt_to_page(page_ptr);
+				get_page(page);	/* increment page count */
+				break;
+			}
+			sa += len;
+			offset -= len;
+		}
+	} else {		/* reserve buffer is just a single allocation */
+		page_ptr = (unsigned char *) rsv_schp->buffer + offset;
 		page = virt_to_page(page_ptr);
 		get_page(page);	/* increment page count */
-		break;
-	    }
-            sa += len;
-	    offset -= len;
-        }
-    }
-    else { /* reserve buffer is just a single allocation */
-        page_ptr = (unsigned char *)rsv_schp->buffer + offset;
-	page = virt_to_page(page_ptr);
-	get_page(page);	/* increment page count */
-    }
-    return page;
+	}
+	return page;
 }
 
 static struct vm_operations_struct sg_mmap_vm_ops = {
-    nopage : sg_vma_nopage,
+	.nopage = sg_vma_nopage,
 };
 
-static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+static int
+sg_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-    Sg_fd * sfp;
-    unsigned long req_sz = vma->vm_end - vma->vm_start;
-    Sg_scatter_hold * rsv_schp;
-
-    if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
-        return -ENXIO;
-    SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", 
-			       (void *)vma->vm_start, (int)req_sz));
-    if (vma->vm_pgoff)
-    	return -EINVAL;		/* want no offset */
-    rsv_schp = &sfp->reserve;
-    if (req_sz > rsv_schp->bufflen)
-    	return -ENOMEM;		/* cannot map more than reserved buffer */
-
-    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
-    	int k;
-	unsigned long sa = vma->vm_start;
-	unsigned long len;
-	struct scatterlist * sclp = rsv_schp->buffer;
-
-	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); 
-	     ++k, ++sclp) {
-	    if (0 != sclp->offset)
-	    	return -EFAULT;     /* non page aligned memory ?? */
-	    len = vma->vm_end - sa;
-	    len = (len < sclp->length) ? len : sclp->length;
-	    sa += len;
-	}
-    }
-    else { /* reserve buffer is just a single allocation */
-    	if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
-	    return -EFAULT;	/* non page aligned memory ?? */
-    }
-    if (0 == sfp->mmap_called) {
-    	sg_rb_correct4mmap(rsv_schp, 1);  /* do only once per fd lifetime */
-	sfp->mmap_called = 1;
-    }
-    vma->vm_flags |= (VM_RESERVED | VM_IO);
-    vma->vm_private_data = sfp;
-    vma->vm_ops = &sg_mmap_vm_ops;
-    return 0;
+	Sg_fd *sfp;
+	unsigned long req_sz = vma->vm_end - vma->vm_start;
+	Sg_scatter_hold *rsv_schp;
+
+	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n",
+				   (void *) vma->vm_start, (int) req_sz));
+	if (vma->vm_pgoff)
+		return -EINVAL;	/* want no offset */
+	rsv_schp = &sfp->reserve;
+	if (req_sz > rsv_schp->bufflen)
+		return -ENOMEM;	/* cannot map more than reserved buffer */
+
+	if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+		int k;
+		unsigned long sa = vma->vm_start;
+		unsigned long len;
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+		     ++k, ++sclp) {
+			if (0 != sclp->offset)
+				return -EFAULT;	/* non page aligned memory ?? */
+			len = vma->vm_end - sa;
+			len = (len < sclp->length) ? len : sclp->length;
+			sa += len;
+		}
+	} else {	/* reserve buffer is just a single allocation */
+		if ((unsigned long) rsv_schp->buffer & (PAGE_SIZE - 1))
+			return -EFAULT;	/* non page aligned memory ?? */
+	}
+	if (0 == sfp->mmap_called) {
+		sg_rb_correct4mmap(rsv_schp, 1);	/* do only once per fd lifetime */
+		sfp->mmap_called = 1;
+	}
+	vma->vm_flags |= (VM_RESERVED | VM_IO);
+	vma->vm_private_data = sfp;
+	vma->vm_ops = &sg_mmap_vm_ops;
+	return 0;
 }
 
 /* This function is a "bottom half" handler that is called by the
  * mid level when a command is completed (or has failed). */
-static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
+static void
+sg_cmd_done(Scsi_Cmnd * SCpnt)
 {
-    Scsi_Request * SRpnt = NULL;
-    Sg_device * sdp = NULL;
-    Sg_fd * sfp;
-    Sg_request * srp = NULL;
-
-    if (SCpnt && (SRpnt = SCpnt->sc_request))
-	srp = (Sg_request *)SRpnt->upper_private_data;
-    if (NULL == srp) {
-    	printk(KERN_ERR "sg_cmd_done_bh: NULL request\n");
-	if (SRpnt)
-	    scsi_release_request(SRpnt);
-	return;
-    }
-    sfp = srp->parentfp;
-    if (sfp)
-    	sdp = sfp->parentdp;
-    if ((NULL == sdp) || sdp->detached) {
-    	printk(KERN_INFO "sg_cmd_done_bh: device detached\n");
-        scsi_release_request(SRpnt);
-        return;
-    }
-
-    /* First transfer ownership of data buffers to sg_device object. */
-    srp->data.k_use_sg = SRpnt->sr_use_sg;
-    srp->data.sglist_len = SRpnt->sr_sglist_len;
-    srp->data.bufflen = SRpnt->sr_bufflen;
-    srp->data.buffer = SRpnt->sr_buffer;
-    /* now clear out request structure */
-    SRpnt->sr_use_sg = 0;
-    SRpnt->sr_sglist_len = 0;
-    SRpnt->sr_bufflen = 0;
-    SRpnt->sr_buffer = NULL;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_request->rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
-
-    srp->my_cmdp = NULL;
-    srp->done = 1;
-
-    SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n",
-		     minor(sdp->i_rdev), srp->header.pack_id, 
-		     (int)SRpnt->sr_result));
-    srp->header.resid = SCpnt->resid;
-    /* sg_unmap_and(&srp->data, 0); */     /* unmap locked pages a.s.a.p. */
-    /* N.B. unit of duration changes here from jiffies to millisecs */
-    srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration);
-    if (0 != SRpnt->sr_result) {
-	memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof(srp->sense_b));
-	srp->header.status = 0xff & SRpnt->sr_result;
-	srp->header.masked_status  = status_byte(SRpnt->sr_result);
-	srp->header.msg_status  = msg_byte(SRpnt->sr_result);
-	srp->header.host_status = host_byte(SRpnt->sr_result);
-	srp->header.driver_status = driver_byte(SRpnt->sr_result);
-	if ((sdp->sgdebug > 0) &&
-	    ((CHECK_CONDITION == srp->header.masked_status) ||
-	     (COMMAND_TERMINATED == srp->header.masked_status)))
-	    print_req_sense("sg_cmd_done_bh", SRpnt);
-
-	/* Following if statement is a patch supplied by Eric Youngdale */
-	if (driver_byte(SRpnt->sr_result) != 0
-	    && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70
-	    && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION
-	    && sdp->device->removable) {
-	    /* Detected disc change. Set the bit - this may be used if */
-	    /* there are filesystems using this device. */
-	    sdp->device->changed = 1;
-	}
-    }
-    /* Rely on write phase to clean out srp status values, so no "else" */
-
-    scsi_release_request(SRpnt);
-    SRpnt = NULL;
-    if (sfp->closed) { /* whoops this fd already released, cleanup */
-        SCSI_LOG_TIMEOUT(1,
-	       printk("sg...bh: already closed, freeing ...\n"));
-	sg_finish_rem_req(srp);
-	srp = NULL;
-	if (NULL == sfp->headrp) {
-            SCSI_LOG_TIMEOUT(1,
-		printk("sg...bh: already closed, final cleanup\n"));
-            if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
-		sdp->device->access_count--;
-		if (sdp->device->host->hostt->module)
-		    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
-	    }
-	    if (sg_template.module)
-		    __MOD_DEC_USE_COUNT(sg_template.module);
-	    sfp = NULL;
-        }
-    }
-    else if (srp && srp->orphan) {
-	if (sfp->keep_orphan)
-	    srp->sg_io_owned = 0;
-	else {
-	    sg_finish_rem_req(srp);
-	    srp = NULL;
-        }
-    }
-    if (sfp && srp) {
-	/* Now wake up any sg_read() that is waiting for this packet. */
-	wake_up_interruptible(&sfp->read_wait);
-	kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
-    }
+	Scsi_Request *SRpnt = NULL;
+	Sg_device *sdp = NULL;
+	Sg_fd *sfp;
+	Sg_request *srp = NULL;
+
+	if (SCpnt && (SRpnt = SCpnt->sc_request))
+		srp = (Sg_request *) SRpnt->upper_private_data;
+	if (NULL == srp) {
+		printk(KERN_ERR "sg_cmd_done: NULL request\n");
+		if (SRpnt)
+			scsi_release_request(SRpnt);
+		return;
+	}
+	sfp = srp->parentfp;
+	if (sfp)
+		sdp = sfp->parentdp;
+	if ((NULL == sdp) || sdp->detached) {
+		printk(KERN_INFO "sg_cmd_done: device detached\n");
+		scsi_release_request(SRpnt);
+		return;
+	}
+
+	/* First transfer ownership of data buffers to sg_device object. */
+	srp->data.k_use_sg = SRpnt->sr_use_sg;
+	srp->data.sglist_len = SRpnt->sr_sglist_len;
+	srp->data.bufflen = SRpnt->sr_bufflen;
+	srp->data.buffer = SRpnt->sr_buffer;
+	/* now clear out request structure */
+	SRpnt->sr_use_sg = 0;
+	SRpnt->sr_sglist_len = 0;
+	SRpnt->sr_bufflen = 0;
+	SRpnt->sr_buffer = NULL;
+	SRpnt->sr_underflow = 0;
+	SRpnt->sr_request->rq_dev = mk_kdev(0, 0);	/* "sg" _disowns_ request blk */
+
+	srp->my_cmdp = NULL;
+	srp->done = 1;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: dev=%d, pack_id=%d, res=0x%x\n",
+		minor(sdp->i_rdev), srp->header.pack_id, (int) SRpnt->sr_result));
+	srp->header.resid = SCpnt->resid;
+	/* N.B. unit of duration changes here from jiffies to millisecs */
+	srp->header.duration =
+	    sg_jif_to_ms(jiffies - (int) srp->header.duration);
+	if (0 != SRpnt->sr_result) {
+		memcpy(srp->sense_b, SRpnt->sr_sense_buffer,
+		       sizeof (srp->sense_b));
+		srp->header.status = 0xff & SRpnt->sr_result;
+		srp->header.masked_status = status_byte(SRpnt->sr_result);
+		srp->header.msg_status = msg_byte(SRpnt->sr_result);
+		srp->header.host_status = host_byte(SRpnt->sr_result);
+		srp->header.driver_status = driver_byte(SRpnt->sr_result);
+		if ((sdp->sgdebug > 0) &&
+		    ((CHECK_CONDITION == srp->header.masked_status) ||
+		     (COMMAND_TERMINATED == srp->header.masked_status)))
+			print_req_sense("sg_cmd_done", SRpnt);
+
+		/* Following if statement is a patch supplied by Eric Youngdale */
+		if (driver_byte(SRpnt->sr_result) != 0
+		    && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70
+		    && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION
+		    && sdp->device->removable) {
+			/* Detected disc change. Set the bit - this may be used if */
+			/* there are filesystems using this device. */
+			sdp->device->changed = 1;
+		}
+	}
+	/* Rely on write phase to clean out srp status values, so no "else" */
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+	if (sfp->closed) {	/* whoops this fd already released, cleanup */
+		SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, freeing ...\n"));
+		sg_finish_rem_req(srp);
+		srp = NULL;
+		if (NULL == sfp->headrp) {
+			SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n"));
+			if (0 == sg_remove_sfp(sdp, sfp)) {	/* device still present */
+				sdp->device->access_count--;
+				if (sdp->device->host->hostt->module)
+					__MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+			}
+			if (sg_template.module)
+				__MOD_DEC_USE_COUNT(sg_template.module);
+			sfp = NULL;
+		}
+	} else if (srp && srp->orphan) {
+		if (sfp->keep_orphan)
+			srp->sg_io_owned = 0;
+		else {
+			sg_finish_rem_req(srp);
+			srp = NULL;
+		}
+	}
+	if (sfp && srp) {
+		/* Now wake up any sg_read() that is waiting for this packet. */
+		wake_up_interruptible(&sfp->read_wait);
+		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
+	}
 }
 
 static struct file_operations sg_fops = {
-	owner:		THIS_MODULE,
-	read:		sg_read,
-	write:		sg_write,
-	poll:		sg_poll,
-	ioctl:		sg_ioctl,
-	open:		sg_open,
-	mmap:		sg_mmap,
-	release:	sg_release,
-	fasync:		sg_fasync,
+	.owner = THIS_MODULE,
+	.read = sg_read,
+	.write = sg_write,
+	.poll = sg_poll,
+	.ioctl = sg_ioctl,
+	.open = sg_open,
+	.mmap = sg_mmap,
+	.release = sg_release,
+	.fasync = sg_fasync,
 };
 
-
-static int sg_detect(Scsi_Device * scsidp)
+static int
+sg_detect(Scsi_Device * scsidp)
 {
-    sg_template.dev_noticed++;
-    return 1;
+	sg_template.dev_noticed++;
+	return 1;
 }
 
 /* Driver initialization */
-static int sg_init()
+static int
+sg_init()
 {
-    static int sg_registered = 0;
-    unsigned long iflags;
+	static int sg_registered = 0;
+	unsigned long iflags;
 
-    if ((sg_template.dev_noticed == 0) || sg_dev_arr)
-    	return 0;
+	if ((sg_template.dev_noticed == 0) || sg_dev_arr)
+		return 0;
 
-    write_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if(!sg_registered) {
-	if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) {
-            printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
-                   SCSI_GENERIC_MAJOR);
-	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-            return 1;
-        }
-        sg_registered++;
-    }
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	if (!sg_registered) {
+		if (register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops)) {
+			printk(KERN_ERR
+			       "Unable to get major %d for generic SCSI device\n",
+			       SCSI_GENERIC_MAJOR);
+			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+			return 1;
+		}
+		sg_registered++;
+	}
 
-    SCSI_LOG_TIMEOUT(3, printk("sg_init\n"));
-    sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP;
-    sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
-    					sizeof(Sg_device *), GFP_ATOMIC);
-    if (NULL == sg_dev_arr) {
-        printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
+	SCSI_LOG_TIMEOUT(3, printk("sg_init\n"));
+	sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP;
+	sg_dev_arr = (Sg_device **)vmalloc(
+			sg_template.dev_max * sizeof(Sg_device *));
+	if (NULL == sg_dev_arr) {
+		printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+		return 1;
+	}
+	memset(sg_dev_arr, 0, sg_template.dev_max * sizeof (Sg_device *));
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-        return 1;
-    }
-    memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *));
-    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 #ifdef CONFIG_PROC_FS
-    sg_proc_init();
-#endif  /* CONFIG_PROC_FS */
-    return 0;
+	sg_proc_init();
+#endif				/* CONFIG_PROC_FS */
+	return 0;
 }
 
 #ifndef MODULE
-static int __init sg_def_reserved_size_setup(char *str)
+static int __init
+sg_def_reserved_size_setup(char *str)
 {
-    int tmp;
+	int tmp;
 
-    if (get_option(&str, &tmp) == 1) {
-	def_reserved_size = tmp;
-	if (tmp >= 0)
-	    sg_big_buff = tmp;
-	return 1;
-    } else {
-	printk(KERN_WARNING "sg_def_reserved_size : usage "
-	    "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
-	return 0;
-    }
+	if (get_option(&str, &tmp) == 1) {
+		def_reserved_size = tmp;
+		if (tmp >= 0)
+			sg_big_buff = tmp;
+		return 1;
+	} else {
+		printk(KERN_WARNING "sg_def_reserved_size : usage "
+		       "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
+		return 0;
+	}
 }
 
 __setup("sg_def_reserved_size=", sg_def_reserved_size_setup);
 #endif
 
 /* Driverfs file support */
-static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page, 
-		size_t count, loff_t off)
+static ssize_t
+sg_device_kdev_read(struct device *driverfs_dev, char *page,
+		    size_t count, loff_t off)
 {
-	Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
-	return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value);
+	Sg_device *sdp = list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
+	return off ? 0 : sprintf(page, "%x\n", sdp->i_rdev.value);
 }
-static DEVICE_ATTR(kdev,"kdev",S_IRUGO,sg_device_kdev_read,NULL);
+static DEVICE_ATTR(kdev,S_IRUGO,sg_device_kdev_read,NULL);
 
-static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page, 
-		size_t count, loff_t off) 
-{
-	return off ? 0 : sprintf (page, "CHR\n");
-}
-static DEVICE_ATTR(type,"type",S_IRUGO,sg_device_type_read,NULL);
-
-static int sg_attach(Scsi_Device * scsidp)
-{
-    Sg_device * sdp;
-    unsigned long iflags;
-    int k;
-
-    write_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */
-    	Sg_device ** tmp_da;
-	int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP;
-
-	tmp_da = (Sg_device **)kmalloc(tmp_dev_max * 
-    					sizeof(Sg_device *), GFP_ATOMIC);
-	if (NULL == tmp_da) {
-	    scsidp->attached--;
-	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	    printk(KERN_ERR "sg_attach: device array cannot be resized\n");
-	    return 1;
-	}
-	memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
-	memcpy(tmp_da, sg_dev_arr, sg_template.dev_max * sizeof(Sg_device *));
-	kfree((char *)sg_dev_arr);
-	sg_dev_arr = tmp_da;
-	sg_template.dev_max = tmp_dev_max;
-    }
-
-    for(k = 0; k < sg_template.dev_max; k++)
-        if(! sg_dev_arr[k]) break;
-    if (k > SG_MAX_DEVS_MASK) {
-	scsidp->attached--;
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
-	       " type=%d, minor number exceed %d\n", scsidp->host->host_no, 
-	       scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
-	       SG_MAX_DEVS_MASK);
-	return 1;
-    }
-    if(k < sg_template.dev_max)
-    	sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
-    else
-    	sdp = NULL;
-    if (NULL == sdp) {
-	scsidp->attached--;
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
-	return 1;
-    }
+static ssize_t
+sg_device_type_read(struct device *driverfs_dev, char *page,
+		    size_t count, loff_t off)
+{
+	return off ? 0 : sprintf(page, "CHR\n");
+}
+
+static DEVICE_ATTR(type,S_IRUGO,sg_device_type_read,NULL);
 
-    SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
-    sdp->device = scsidp;
-    init_waitqueue_head(&sdp->o_excl_wait);
-    sdp->headfp= NULL;
-    sdp->exclude = 0;
-    sdp->sgdebug = 0;
-    sdp->detached = 0;
-    sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
-    sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
-
-    memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device));
-    sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
-	    scsidp->sdev_driverfs_dev.bus_id);
-    sprintf(sdp->sg_driverfs_dev.name, "%sgeneric", 
-	    scsidp->sdev_driverfs_dev.name);
-    sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
-    sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
-    device_register(&sdp->sg_driverfs_dev);
-    device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
-    device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
-
-    sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
-                             SCSI_GENERIC_MAJOR, k,
-                             S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-                             &sg_fops, sdp);
-    sg_template.nr_dev++;
-    sg_dev_arr[k] = sdp;
-    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    switch (scsidp->type) {
+static int
+sg_attach(Scsi_Device * scsidp)
+{
+	Sg_device *sdp;
+	unsigned long iflags;
+	int k;
+
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	if (sg_template.nr_dev >= sg_template.dev_max) {	/* try to resize */
+		Sg_device **tmp_da;
+		int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP;
+
+		tmp_da = (Sg_device **)vmalloc(
+				tmp_dev_max * sizeof(Sg_device *));
+		if (NULL == tmp_da) {
+			scsidp->attached--;
+			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+			printk(KERN_ERR
+			       "sg_attach: device array cannot be resized\n");
+			return 1;
+		}
+		memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
+		memcpy(tmp_da, sg_dev_arr,
+		       sg_template.dev_max * sizeof (Sg_device *));
+		vfree((char *) sg_dev_arr);
+		sg_dev_arr = tmp_da;
+		sg_template.dev_max = tmp_dev_max;
+	}
+
+	for (k = 0; k < sg_template.dev_max; k++)
+		if (!sg_dev_arr[k])
+			break;
+	if (k > SG_MAX_DEVS_MASK) {
+		scsidp->attached--;
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+		printk(KERN_WARNING
+		       "Unable to attach sg device <%d, %d, %d, %d>"
+		       " type=%d, minor number exceed %d\n",
+		       scsidp->host->host_no, scsidp->channel, scsidp->id,
+		       scsidp->lun, scsidp->type, SG_MAX_DEVS_MASK);
+		return 1;
+	}
+	if (k < sg_template.dev_max)
+		sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
+	else
+		sdp = NULL;
+	if (NULL == sdp) {
+		scsidp->attached--;
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+		printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
+		return 1;
+	}
+
+	SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
+	sdp->device = scsidp;
+	init_waitqueue_head(&sdp->o_excl_wait);
+	sdp->headfp = NULL;
+	sdp->exclude = 0;
+	sdp->sgdebug = 0;
+	sdp->detached = 0;
+	sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
+	sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
+
+	memset(&sdp->sg_driverfs_dev, 0, sizeof (struct device));
+	sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
+		scsidp->sdev_driverfs_dev.bus_id);
+	sprintf(sdp->sg_driverfs_dev.name, "%sgeneric",
+		scsidp->sdev_driverfs_dev.name);
+	sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
+	sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
+	device_register(&sdp->sg_driverfs_dev);
+	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
+	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
+
+	sdp->de = devfs_register(scsidp->de, "generic", DEVFS_FL_DEFAULT,
+				 SCSI_GENERIC_MAJOR, k,
+				 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+				 &sg_fops, sdp);
+	sg_template.nr_dev++;
+	sg_dev_arr[k] = sdp;
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	switch (scsidp->type) {
 	case TYPE_DISK:
 	case TYPE_MOD:
 	case TYPE_ROM:
 	case TYPE_WORM:
-	case TYPE_TAPE: break;
+	case TYPE_TAPE:
+		break;
 	default:
-	    printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
-	    	   " %d, id %d, lun %d,  type %d\n", k, scsidp->host->host_no, 
-		   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
-    }
-    return 0;
-}
-
-/* Called at 'finish' of init process, after all attaches */
-static void sg_finish(void)
-{ }
-
-static void sg_detach(Scsi_Device * scsidp)
-{
-    Sg_device * sdp;
-    unsigned long iflags;
-    Sg_fd * sfp;
-    Sg_fd * tsfp;
-    Sg_request * srp;
-    Sg_request * tsrp;
-    int k, delay;
-
-    if (NULL == sg_dev_arr)
-    	return;
-    delay = 0;
-    write_lock_irqsave(&sg_dev_arr_lock, iflags);
-    for (k = 0; k < sg_template.dev_max; k++) {
-    	sdp = sg_dev_arr[k];
-        if ((NULL == sdp) || (sdp->device != scsidp))
-            continue;   /* dirty but lowers nesting */
-        if (sdp->headfp) {
-	    sdp->detached = 1;
-	    for (sfp = sdp->headfp; sfp; sfp = tsfp) {
-	    	tsfp = sfp->nextfp;
-		for (srp = sfp->headrp; srp; srp = tsrp) {
-		    tsrp = srp->nextrp;
-		    if (sfp->closed || (0 == srp->done))
-			sg_finish_rem_req(srp);
-		}
-		if (sfp->closed) {
-		    sdp->device->access_count--;
-		    if (sg_template.module)
-			__MOD_DEC_USE_COUNT(sg_template.module);
-		    if (sdp->device->host->hostt->module)
-			__MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
-		    __sg_remove_sfp(sdp, sfp);
+		printk(KERN_NOTICE
+		       "Attached scsi generic sg%d at scsi%d, channel"
+		       " %d, id %d, lun %d,  type %d\n", k,
+		       scsidp->host->host_no, scsidp->channel, scsidp->id,
+		       scsidp->lun, scsidp->type);
+	}
+	return 0;
+}
+
+static void
+sg_detach(Scsi_Device * scsidp)
+{
+	Sg_device *sdp;
+	unsigned long iflags;
+	Sg_fd *sfp;
+	Sg_fd *tsfp;
+	Sg_request *srp;
+	Sg_request *tsrp;
+	int k, delay;
+
+	if (NULL == sg_dev_arr)
+		return;
+	delay = 0;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = 0; k < sg_template.dev_max; k++) {
+		sdp = sg_dev_arr[k];
+		if ((NULL == sdp) || (sdp->device != scsidp))
+			continue;	/* dirty but lowers nesting */
+		if (sdp->headfp) {
+			sdp->detached = 1;
+			for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+				tsfp = sfp->nextfp;
+				for (srp = sfp->headrp; srp; srp = tsrp) {
+					tsrp = srp->nextrp;
+					if (sfp->closed || (0 == srp->done))
+						sg_finish_rem_req(srp);
+				}
+				if (sfp->closed) {
+					sdp->device->access_count--;
+					if (sg_template.module)
+						__MOD_DEC_USE_COUNT(sg_template.module);
+					if (sdp->device->host->hostt->module)
+						__MOD_DEC_USE_COUNT(
+							sdp->device->host->
+							 hostt->module);
+					__sg_remove_sfp(sdp, sfp);
+				} else {
+					delay = 1;
+					wake_up_interruptible(&sfp->read_wait);
+					kill_fasync(&sfp->async_qp, SIGPOLL,
+						    POLL_HUP);
+				}
+			}
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
+			devfs_unregister(sdp->de);
+			device_remove_file(&sdp->sg_driverfs_dev,
+					   &dev_attr_type);
+			device_remove_file(&sdp->sg_driverfs_dev,
+					   &dev_attr_kdev);
+			put_device(&sdp->sg_driverfs_dev);
+			sdp->de = NULL;
+			if (NULL == sdp->headfp) {
+				vfree((char *) sdp);
+				sg_dev_arr[k] = NULL;
+			}
+		} else {	/* nothing active, simple case */
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
+			devfs_unregister(sdp->de);
+			put_device(&sdp->sg_driverfs_dev);
+			vfree((char *) sdp);
+			sg_dev_arr[k] = NULL;
 		}
-		else {
-		    delay = 1;
-		    wake_up_interruptible(&sfp->read_wait);
-		    kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
-		}
-            }
-	    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
-	    devfs_unregister (sdp->de);
-	    device_remove_file(&sdp->sg_driverfs_dev,&dev_attr_type);
-	    device_remove_file(&sdp->sg_driverfs_dev,&dev_attr_kdev);
-	    put_device(&sdp->sg_driverfs_dev);
-	    sdp->de = NULL;
-	    if (NULL == sdp->headfp) {
-		kfree((char *)sdp);
-		sg_dev_arr[k] = NULL;
-	    }
-        }
-        else { /* nothing active, simple case */
-            SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
-	    devfs_unregister (sdp->de);
-	    put_device(&sdp->sg_driverfs_dev);
-	    kfree((char *)sdp);
-	    sg_dev_arr[k] = NULL;
-        }
-        scsidp->attached--;
-        sg_template.nr_dev--;
-        sg_template.dev_noticed--;	/* from <dan@lectra.fr> */
-        break;
-    }
-    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    if (delay)
-	scsi_sleep(2);	/* dirty detach so delay device destruction */
+		scsidp->attached--;
+		sg_template.nr_dev--;
+		sg_template.dev_noticed--;	/* from <dan@lectra.fr> */
+		break;
+	}
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	if (delay)
+		scsi_sleep(2);	/* dirty detach so delay device destruction */
 }
 
 MODULE_AUTHOR("Douglas Gilbert");
@@ -1583,1215 +1588,1144 @@
 MODULE_PARM(def_reserved_size, "i");
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
 
-static int __init init_sg(void) {
-    int rc;
-    if (def_reserved_size >= 0)
-	sg_big_buff = def_reserved_size;
-    rc = scsi_register_device(&sg_template);
-    if (!rc) {
-	sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag;
-	sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
-	driver_register(&sg_template.scsi_driverfs_driver);
-    }
-    return rc; 
+static int __init
+init_sg(void)
+{
+	int rc;
+	if (def_reserved_size >= 0)
+		sg_big_buff = def_reserved_size;
+	rc = scsi_register_device(&sg_template);
+	if (!rc) {
+		sg_template.scsi_driverfs_driver.name =
+		    (char *) sg_template.tag;
+		sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sg_template.scsi_driverfs_driver);
+	}
+	return rc;
 }
 
-static void __exit exit_sg( void)
+static void __exit
+exit_sg(void)
 {
 #ifdef CONFIG_PROC_FS
-    sg_proc_cleanup();
-#endif  /* CONFIG_PROC_FS */
-    scsi_unregister_device(&sg_template);
-    unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
-    if(sg_dev_arr != NULL) {
-	kfree((char *)sg_dev_arr);
-        sg_dev_arr = NULL;
-    }
-    sg_template.dev_max = 0;
-    remove_driver(&sg_template.scsi_driverfs_driver);
-}
-
-
-static int sg_start_req(Sg_request * srp)
-{
-    int res;
-    Sg_fd * sfp = srp->parentfp;
-    sg_io_hdr_t * hp = &srp->header;
-    int dxfer_len = (int)hp->dxfer_len;
-    int dxfer_dir = hp->dxfer_direction;
-    Sg_scatter_hold * req_schp = &srp->data;
-    Sg_scatter_hold * rsv_schp = &sfp->reserve;
-
-    SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
-    if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
-    	return 0;
-    if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) && 
-	(dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
-	(! sfp->parentdp->device->host->unchecked_isa_dma)) {
-	res = sg_build_dir(srp, sfp, dxfer_len);
-	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
-	    return res;
-    }
-    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
-	sg_link_reserve(sfp, srp, dxfer_len);
-    else {
-	res = sg_build_indi(req_schp, sfp, dxfer_len);
-        if (res) {
-            sg_remove_scat(req_schp);
-            return res;
-        }
-    }
-    return 0;
+	sg_proc_cleanup();
+#endif				/* CONFIG_PROC_FS */
+	scsi_unregister_device(&sg_template);
+	unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
+	if (sg_dev_arr != NULL) {
+		vfree((char *) sg_dev_arr);
+		sg_dev_arr = NULL;
+	}
+	sg_template.dev_max = 0;
+	remove_driver(&sg_template.scsi_driverfs_driver);
+}
+
+static int
+sg_start_req(Sg_request * srp)
+{
+	int res;
+	Sg_fd *sfp = srp->parentfp;
+	sg_io_hdr_t *hp = &srp->header;
+	int dxfer_len = (int) hp->dxfer_len;
+	int dxfer_dir = hp->dxfer_direction;
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
+	if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
+		return 0;
+	if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
+	    (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
+	    (!sfp->parentdp->device->host->unchecked_isa_dma)) {
+		res = sg_build_direct(srp, sfp, dxfer_len);
+		if (res <= 0)	/* -ve -> error, 0 -> done, 1 -> try indirect */
+			return res;
+	}
+	if ((!sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
+		sg_link_reserve(sfp, srp, dxfer_len);
+	else {
+		res = sg_build_indirect(req_schp, sfp, dxfer_len);
+		if (res) {
+			sg_remove_scat(req_schp);
+			return res;
+		}
+	}
+	return 0;
 }
 
-static void sg_finish_rem_req(Sg_request * srp)
+static void
+sg_finish_rem_req(Sg_request * srp)
 {
-    Sg_fd * sfp = srp->parentfp;
-    Sg_scatter_hold * req_schp = &srp->data;
+	Sg_fd *sfp = srp->parentfp;
+	Sg_scatter_hold *req_schp = &srp->data;
 
-    SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n",
-			       (int)srp->res_used));
-    sg_unmap_and(&srp->data, 1);
-    if (srp->res_used)
-        sg_unlink_reserve(sfp, srp);
-    else
-        sg_remove_scat(req_schp);
-    sg_remove_request(sfp, srp);
+	SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used));
+	// sg_unmap_and(&srp->data, 1);
+	if (srp->res_used)
+		sg_unlink_reserve(sfp, srp);
+	else
+		sg_remove_scat(req_schp);
+	sg_remove_request(sfp, srp);
 }
 
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
-			 int tablesize)
+static int
+sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
 {
-    int mem_src, ret_sz;
-    int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    /* scatter gather array, followed by mem_src_arr (array of chars) */
-    int sg_bufflen = tablesize * elem_sz;
-    int mx_sc_elems = tablesize;
-
-    mem_src = SG_HEAP_KMAL;
-    schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
-    if (! schp->buffer)
-	return -ENOMEM;
-    else if (ret_sz != sg_bufflen) {
-	sg_bufflen = ret_sz;
-	mx_sc_elems = sg_bufflen / elem_sz;
-    }
-    schp->buffer_mem_src = (char)mem_src;
-    schp->sglist_len = sg_bufflen;
-    memset(schp->buffer, 0, sg_bufflen);
-    return mx_sc_elems; /* number of scat_gath elements allocated */
+	int ret_sz;
+	int elem_sz = sizeof (struct scatterlist);
+	int sg_bufflen = tablesize * elem_sz;
+	int mx_sc_elems = tablesize;
+
+	schp->buffer = sg_page_malloc(sg_bufflen, sfp->low_dma, &ret_sz);
+	if (!schp->buffer)
+		return -ENOMEM;
+	else if (ret_sz != sg_bufflen) {
+		sg_bufflen = ret_sz;
+		mx_sc_elems = sg_bufflen / elem_sz;
+	}
+	schp->sglist_len = sg_bufflen;
+	memset(schp->buffer, 0, sg_bufflen);
+	return mx_sc_elems;	/* number of scat_gath elements allocated */
 }
 
-static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
-{
 #ifdef SG_ALLOW_DIO_CODE
-    int nbhs = 0;
+/* vvvvvvvv  following code borrowed from st driver's direct IO vvvvvvvvv */
+	/* hopefully this generic code will moved to a library */
 
-    if (schp && schp->kiobp) {
-	if (schp->mapped) {
-	    unmap_kiobuf(schp->kiobp);
-	    schp->mapped = 0;
-	}
-	if (free_also) {
-	    sg_free_kiovec(1, &schp->kiobp, &nbhs);
-	    schp->kiobp = NULL;
+/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
+   - mapping of all pages not successful
+   - any page is above max_pfn
+   (i.e., either completely successful or fails)
+*/
+static int 
+st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+	          unsigned long uaddr, size_t count, int rw,
+	          unsigned long max_pfn)
+{
+	int res, i, j;
+	unsigned int nr_pages;
+	struct page **pages;
+
+	nr_pages = ((uaddr & ~PAGE_MASK) + count - 1 + ~PAGE_MASK) >> PAGE_SHIFT;
+
+	/* User attempted Overflow! */
+	if ((uaddr + count) < uaddr)
+		return -EINVAL;
+
+	/* Too big */
+        if (nr_pages > max_pages)
+		return -ENOMEM;
+
+	/* Hmm? */
+	if (count == 0)
+		return 0;
+
+	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+        /* Try to fault in all of the necessary pages */
+	down_read(&current->mm->mmap_sem);
+        /* rw==READ means read from drive, write into memory area */
+	res = get_user_pages(
+		current,
+		current->mm,
+		uaddr,
+		nr_pages,
+		rw == READ,
+		0, /* don't force */
+		pages,
+		NULL);
+	up_read(&current->mm->mmap_sem);
+
+	/* Errors and no page mapped should return here */
+	if (res < nr_pages)
+		goto out_unmap;
+
+        for (i=0; i < nr_pages; i++) {
+                /* FIXME: flush superflous for rw==READ,
+                 * probably wrong function for rw==WRITE
+                 */
+		flush_dcache_page(pages[i]);
+		if (page_to_pfn(pages[i]) > max_pfn)
+			goto out_unlock;
+		/* ?? Is locking needed? I don't think so */
+		/* if (TestSetPageLocked(pages[i]))
+		   goto out_unlock; */
+        }
+
+	/* Populate the scatter/gather list */
+	sgl[0].page = pages[0]; 
+	sgl[0].offset = uaddr & ~PAGE_MASK;
+	if (nr_pages > 1) {
+		sgl[0].length = PAGE_SIZE - sgl[0].offset;
+		count -= sgl[0].length;
+		for (i=1; i < nr_pages ; i++) {
+			sgl[i].offset = 0;
+			sgl[i].page = pages[i]; 
+			sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+			count -= PAGE_SIZE;
+		}
 	}
-    }
-#endif
+	else {
+		sgl[0].length = count;
+	}
+
+	kfree(pages);
+	return nr_pages;
+
+ out_unlock:
+	/* for (j=0; j < i; j++)
+	   unlock_page(pages[j]); */
+	res = 0;
+ out_unmap:
+	if (res > 0)
+		for (j=0; j < res; j++)
+			page_cache_release(pages[j]);
+	kfree(pages);
+	return res;
 }
 
-static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
+
+/* And unmap them... */
+static int 
+st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
+		    int dirtied)
+{
+	int i;
+
+	for (i=0; i < nr_pages; i++) {
+		if (dirtied && !PageReserved(sgl[i].page))
+			SetPageDirty(sgl[i].page);
+		/* unlock_page(sgl[i].page); */
+		/* FIXME: cache flush missing for rw==READ
+		 * FIXME: call the correct reference counting function
+		 */
+		page_cache_release(sgl[i].page);
+	}
+
+	return 0;
+}
+
+/* ^^^^^^^^  above code borrowed from st driver's direct IO ^^^^^^^^^ */
+#endif
+
+
+/* Returns: -ve -> error, 0 -> done, 1 -> try indirect */
+static int
+sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
 {
 #ifdef SG_ALLOW_DIO_CODE
-    int res, k, j, split, offset, num, mx_sc_elems, rem_sz;
-    struct kiobuf * kp;
-    char * mem_src_arr;
-    struct scatterlist * sclp;
-    unsigned long addr, prev_addr;
-    sg_io_hdr_t * hp = &srp->header;
-    Sg_scatter_hold * schp = &srp->data;
-    int sg_tablesize = sfp->parentdp->sg_tablesize;
-    unsigned char * pg_addr;
-    unsigned char * hold_pg_addr = NULL;
-    int nbhs = 0;
-
-    res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
-    if (0 != res) {
-	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", 
-			 res));
-	return 1;
-    }
-    res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
-			  schp->kiobp, (unsigned long)hp->dxferp, dxfer_len);
-    if (0 != res) {
-	SCSI_LOG_TIMEOUT(5,
-		printk("sg_build_dir: map_user_kiobuf res=%d\n", res));
-	sg_unmap_and(schp, 1);
-	return 1;
-    }
-    schp->mapped = 1;
-    kp = schp->kiobp;
-    prev_addr = (unsigned long) page_address(kp->maplist[0]);
-    for (k = 1, split = 0; k < kp->nr_pages; ++k, prev_addr = addr) {
-	addr = (unsigned long) page_address(kp->maplist[k]);
-	if ((prev_addr + PAGE_SIZE) != addr) {
-	    split = k;
-	    break;
-	}
-    }
-    if (! split) {
-	schp->k_use_sg = 0;
-	schp->buffer = page_address(kp->maplist[0]) + kp->offset;
-	schp->bufflen = dxfer_len;
-	schp->buffer_mem_src = SG_USER_MEM;
-	schp->b_malloc_len = dxfer_len;
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int sg_tablesize = sfp->parentdp->sg_tablesize;
+	struct scatterlist *sgl;
+	int mx_sc_elems, res;
+
+	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
+        if (mx_sc_elems <= 0) {
+                return 1;
+        }
+	sgl = (struct scatterlist *)schp->buffer;
+	res = st_map_user_pages(sgl, mx_sc_elems, (unsigned long)hp->dxferp, dxfer_len, 
+				(SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, ULONG_MAX);
+	if (res <= 0)
+		return 1;
+	schp->k_use_sg = res;
+	schp->dio_in_use = 1;
 	hp->info |= SG_INFO_DIRECT_IO;
 	return 0;
-    }
-    mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
-    if (mx_sc_elems <= 1) {
-	sg_unmap_and(schp, 1);
-	sg_remove_scat(schp);
-	return 1;
-    }
-    mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
-    for (k = 0, j = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-	 (rem_sz > 0) && (j < mx_sc_elems); ++k) {
-	offset = (0 == k) ? kp->offset : 0;
-	num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
-						rem_sz;
-	pg_addr = page_address(kp->maplist[k]);
-	if ((k > 0) && ((hold_pg_addr + PAGE_SIZE) == pg_addr))
-	    (sclp - 1)->length += num;
-	else {
-	    sclp->page = kp->maplist[k];
-	    sclp->offset = offset;
-	    sclp->length = num;
-	    mem_src_arr[j] = SG_USER_MEM;
-	    ++j;
-	    ++sclp;
-	}
-        hold_pg_addr = pg_addr;
-	rem_sz -= num;
-    }
-    schp->k_use_sg = j;
-    SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k_use_sg=%d, k=%d, rem_sz=%d\n",
-		     j, k, rem_sz));
-    schp->bufflen = dxfer_len;
-    if (rem_sz > 0) {   /* must have failed */
-	sg_unmap_and(schp, 1);
-	sg_remove_scat(schp);
-	return 1;   /* out of scatter gather elements, try indirect */
-    }
-    hp->info |= SG_INFO_DIRECT_IO;
-    return 0;
 #else
-    return 1;
-#endif /* SG_ALLOW_DIO_CODE */
+	return 1;
+#endif
 }
 
-static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
+static int
+sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
 {
-    int ret_sz, mem_src;
-    int blk_size = buff_size;
-    unsigned char * p = NULL;
+	int ret_sz;
+	int blk_size = buff_size;
+	unsigned char *p = NULL;
 
-    if ((blk_size < 0) || (! sfp))
-        return -EFAULT;
-    if (0 == blk_size)
-        ++blk_size;             /* don't know why */
+	if ((blk_size < 0) || (!sfp))
+		return -EFAULT;
+	if (0 == blk_size)
+		++blk_size;	/* don't know why */
 /* round request up to next highest SG_SECTOR_SZ byte boundary */
-    blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
-    SCSI_LOG_TIMEOUT(4, printk("sg_build_indi: buff_size=%d, blk_size=%d\n",
-                               buff_size, blk_size));
-    if (blk_size <= SG_SCATTER_SZ) {
-        mem_src = SG_HEAP_PAGE;
-        p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src);
-        if (! p)
-            return -ENOMEM;
-        if (blk_size == ret_sz) { /* got it on the first attempt */
-	    schp->k_use_sg = 0;
-            schp->buffer = p;
-            schp->bufflen = blk_size;
-	    schp->buffer_mem_src = (char)mem_src;
-            schp->b_malloc_len = blk_size;
-            return 0;
-        }
-    }
-    else {
-        mem_src = SG_HEAP_PAGE;
-        p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src);
-        if (! p)
-            return -ENOMEM;
-    }
+	blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
+	SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n",
+				   buff_size, blk_size));
+	if (blk_size <= SG_SCATTER_SZ) {
+		p = sg_page_malloc(blk_size, sfp->low_dma, &ret_sz);
+		if (!p)
+			return -ENOMEM;
+		if (blk_size == ret_sz) {	/* got it on the first attempt */
+			schp->k_use_sg = 0;
+			schp->buffer = p;
+			schp->bufflen = blk_size;
+			schp->b_malloc_len = blk_size;
+			return 0;
+		}
+	} else {
+		p = sg_page_malloc(SG_SCATTER_SZ, sfp->low_dma, &ret_sz);
+		if (!p)
+			return -ENOMEM;
+	}
 /* Want some local declarations, so start new block ... */
-    {   /* lets try and build a scatter gather list */
-        struct scatterlist * sclp;
-	int k, rem_sz, num;
-	int mx_sc_elems;
-        int sg_tablesize = sfp->parentdp->sg_tablesize;
-        int first = 1;
-	char * mem_src_arr;
-
-        /* N.B. ret_sz and mem_src carried into this block ... */
-	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
-	if (mx_sc_elems < 0)
-	    return mx_sc_elems; /* most likely -ENOMEM */
-	mem_src_arr = schp->buffer +
-		      (mx_sc_elems * sizeof(struct scatterlist));
-
-	for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
-	     (rem_sz > 0) && (k < mx_sc_elems);
-             ++k, rem_sz -= ret_sz, ++sclp) {
-	    if (first)
-                first = 0;
-            else {
-                num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
-                mem_src = SG_HEAP_PAGE;
-                p = sg_malloc(sfp, num, &ret_sz, &mem_src);
-                if (! p)
-                    break;
-            }
-            sclp->page = virt_to_page(p);
-            sclp->offset = (unsigned long)p & ~PAGE_MASK;
-            sclp->length = ret_sz;
-	    mem_src_arr[k] = mem_src;
-
-	    SCSI_LOG_TIMEOUT(5,
-		printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
-                k, sg_scatg2virt(sclp), ret_sz, mem_src));
-        } /* end of for loop */
-	schp->k_use_sg = k;
-	SCSI_LOG_TIMEOUT(5,
-	    printk("sg_build_indi: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));
-        schp->bufflen = blk_size;
-        if (rem_sz > 0)   /* must have failed */
-            return -ENOMEM;
-    }
-    return 0;
-}
-
-static int sg_write_xfer(Sg_request * srp)
-{
-    sg_io_hdr_t * hp = &srp->header;
-    Sg_scatter_hold * schp = &srp->data;
-    int num_xfer = 0;
-    int j, k, onum, usglen, ksglen, res, ok;
-    int iovec_count = (int)hp->iovec_count;
-    int dxfer_dir = hp->dxfer_direction;
-    unsigned char * p;
-    unsigned char * up;
-    int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
-
-    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
-	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
-	num_xfer = (int)(new_interface ?  hp->dxfer_len : hp->flags);
-	if (schp->bufflen < num_xfer)
-	    num_xfer = schp->bufflen;
-    }
-    if ((num_xfer <= 0) || 
-    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+	{			/* lets try and build a scatter gather list */
+		struct scatterlist *sclp;
+		int k, rem_sz, num;
+		int mx_sc_elems;
+		int sg_tablesize = sfp->parentdp->sg_tablesize;
+		int first = 1;
+
+		/* N.B. ret_sz carried into this block ... */
+		mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
+		if (mx_sc_elems < 0)
+			return mx_sc_elems;	/* most likely -ENOMEM */
+
+		for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
+		     (rem_sz > 0) && (k < mx_sc_elems);
+		     ++k, rem_sz -= ret_sz, ++sclp) {
+			if (first)
+				first = 0;
+			else {
+				num =
+				    (rem_sz >
+				     SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
+				p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
+				if (!p)
+					break;
+			}
+			sclp->page = virt_to_page(p);
+			sclp->offset = (unsigned long) p & ~PAGE_MASK;
+			sclp->length = ret_sz;
+
+			SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n",
+					  k, sg_scatg2virt(sclp), ret_sz));
+		}		/* end of for loop */
+		schp->k_use_sg = k;
+		SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));
+		schp->bufflen = blk_size;
+		if (rem_sz > 0)	/* must have failed */
+			return -ENOMEM;
+	}
 	return 0;
+}
 
-    SCSI_LOG_TIMEOUT(4,
-	 printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
-		num_xfer, iovec_count, schp->k_use_sg));
-    if (iovec_count) {
-	onum = iovec_count;
-	if ((k = verify_area(VERIFY_READ, hp->dxferp,
-			     SZ_SG_IOVEC * onum)))
-	    return k;
-    }
-    else
-	onum = 1;
-
-    if (0 == schp->k_use_sg) {  /* kernel has single buffer */
-	if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */
-
-	    for (j = 0, p = schp->buffer; j < onum; ++j) {
-		res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
-		if (res) return res;
-		usglen = (num_xfer > usglen) ? usglen : num_xfer;
-		if (__copy_from_user(p, up, usglen))
-		    return -EFAULT;
-		p += usglen;
-		num_xfer -= usglen;
-		if (num_xfer <= 0)
-		    return 0;
-            }
-	}
-    }
-    else {      /* kernel using scatter gather list */
-	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
-	char * mem_src_arr = sg_get_sgat_msa(schp);
-
-	ksglen = (int)sclp->length;
-	p = sg_scatg2virt(sclp);
-	for (j = 0, k = 0; j < onum; ++j) {
-	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
-	    if (res) return res;
-
-	    for (; k < schp->k_use_sg; ++k, ++sclp) {
-		ksglen = (int)sclp->length; 
-		p = sg_scatg2virt(sclp);
-		if (NULL == p)
-		    break;
-		ok = (SG_USER_MEM != mem_src_arr[k]);
-		if (usglen <= 0)
-		    break;
-		if (ksglen > usglen) {
-		    if (usglen >= num_xfer) {
-			if (ok) {
-			   if (__copy_from_user(p, up, num_xfer))
-				return -EFAULT;
-			}
-			return 0;
-		    }
-		    if (ok) {
+static int
+sg_write_xfer(Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int num_xfer = 0;
+	int j, k, onum, usglen, ksglen, res;
+	int iovec_count = (int) hp->iovec_count;
+	int dxfer_dir = hp->dxfer_direction;
+	unsigned char *p;
+	unsigned char *up;
+	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
+
+	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
+	    (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
+		num_xfer = (int) (new_interface ? hp->dxfer_len : hp->flags);
+		if (schp->bufflen < num_xfer)
+			num_xfer = schp->bufflen;
+	}
+	if ((num_xfer <= 0) || (schp->dio_in_use) ||
+	    (new_interface
+	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+		return 0;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
+			  num_xfer, iovec_count, schp->k_use_sg));
+	if (iovec_count) {
+		onum = iovec_count;
+		if ((k = verify_area(VERIFY_READ, hp->dxferp,
+				     SZ_SG_IOVEC * onum)))
+			return k;
+	} else
+		onum = 1;
+
+	if (0 == schp->k_use_sg) {	/* kernel has single buffer */
+		for (j = 0, p = schp->buffer; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
+			if (res)
+				return res;
+			usglen = (num_xfer > usglen) ? usglen : num_xfer;
 			if (__copy_from_user(p, up, usglen))
-			    return -EFAULT;
-		    }
-		    p += usglen;
-		    ksglen -= usglen;
-                    break;
-		}
-		else {
-		    if (ksglen >= num_xfer) {
-			if (ok) {
-			    if (__copy_from_user(p, up, num_xfer))
 				return -EFAULT;
+			p += usglen;
+			num_xfer -= usglen;
+			if (num_xfer <= 0)
+				return 0;
+		}
+	} else {		/* kernel using scatter gather list */
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		ksglen = (int) sclp->length;
+		p = sg_scatg2virt(sclp);
+		for (j = 0, k = 0; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
+			if (res)
+				return res;
+
+			for (; k < schp->k_use_sg; ++k, ++sclp) {
+				ksglen = (int) sclp->length;
+				p = sg_scatg2virt(sclp);
+				if (NULL == p)
+					break;
+				if (usglen <= 0)
+					break;
+				if (ksglen > usglen) {
+					if (usglen >= num_xfer) {
+						if (__copy_from_user
+						    (p, up, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_from_user(p, up, usglen))
+						return -EFAULT;
+					p += usglen;
+					ksglen -= usglen;
+					break;
+				} else {
+					if (ksglen >= num_xfer) {
+						if (__copy_from_user
+						    (p, up, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_from_user(p, up, ksglen))
+						return -EFAULT;
+					up += ksglen;
+					usglen -= ksglen;
+				}
 			}
-			return 0;
-		    }
-		    if (ok) {
-			if (__copy_from_user(p, up, ksglen))
-			    return -EFAULT;
-		    }
-		    up += ksglen;
-		    usglen -= ksglen;
 		}
-            }
-        }
-    }
-    return 0;
+	}
+	return 0;
 }
 
-static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
-		      int wr_xf, int * countp, unsigned char ** up)
-{
-    int num_xfer = (int)hp->dxfer_len;
-    unsigned char * p;
-    int count, k;
-    sg_iovec_t u_iovec;
-
-    if (0 == sg_num) {
-	p = (unsigned char *)hp->dxferp;
-	if (wr_xf && ('\0' == hp->interface_id))
-	    count = (int)hp->flags; /* holds "old" input_size */
-	else
-	    count = num_xfer;
-    }
-    else {
-	if (__copy_from_user(&u_iovec,
-			 (unsigned char *)hp->dxferp + (ind * SZ_SG_IOVEC),
-			 SZ_SG_IOVEC))
-	    return -EFAULT;
-	p = (unsigned char *)u_iovec.iov_base;
-	count = (int)u_iovec.iov_len;
-    }
-    if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count)))
-	return k;
-    if (up) *up = p;
-    if (countp) *countp = count;
-    return 0;
-}
-
-static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
-{
-    int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = schp->sglist_len / elem_sz;
-    return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
-}
-
-static void sg_remove_scat(Sg_scatter_hold * schp)
-{
-    SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n",
-			       schp->k_use_sg));
-    if (schp->buffer && schp->sglist_len) {
-        int k, mem_src;
-        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
-	char * mem_src_arr = sg_get_sgat_msa(schp);
-
-	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
-	    mem_src = mem_src_arr[k];
-	    SCSI_LOG_TIMEOUT(5,
-		printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
-                       k, sg_scatg2virt(sclp), sclp->length, mem_src));
-            sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
-	    sclp->page = NULL;
-            sclp->offset = 0;
-            sclp->length = 0;
-        }
-	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
-    }
-    else if (schp->buffer)
-	sg_free(schp->buffer, schp->b_malloc_len, schp->buffer_mem_src);
-    memset(schp, 0, sizeof(*schp));
-}
-
-static int sg_read_xfer(Sg_request * srp)
-{
-    sg_io_hdr_t * hp = &srp->header;
-    Sg_scatter_hold * schp = &srp->data;
-    int num_xfer = 0;
-    int j, k, onum, usglen, ksglen, res, ok;
-    int iovec_count = (int)hp->iovec_count;
-    int dxfer_dir = hp->dxfer_direction;
-    unsigned char * p;
-    unsigned char * up;
-    int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
-
-    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir) ||
-	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
-	num_xfer =  hp->dxfer_len;
-	if (schp->bufflen < num_xfer)
-	    num_xfer = schp->bufflen;
-    }
-    if ((num_xfer <= 0) || 
-    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+static int
+sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
+	   int wr_xf, int *countp, unsigned char **up)
+{
+	int num_xfer = (int) hp->dxfer_len;
+	unsigned char *p;
+	int count, k;
+	sg_iovec_t u_iovec;
+
+	if (0 == sg_num) {
+		p = (unsigned char *) hp->dxferp;
+		if (wr_xf && ('\0' == hp->interface_id))
+			count = (int) hp->flags;	/* holds "old" input_size */
+		else
+			count = num_xfer;
+	} else {
+		if (__copy_from_user(&u_iovec,
+				     (unsigned char *) hp->dxferp +
+				     (ind * SZ_SG_IOVEC), SZ_SG_IOVEC))
+			return -EFAULT;
+		p = (unsigned char *) u_iovec.iov_base;
+		count = (int) u_iovec.iov_len;
+	}
+	if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count)))
+		return k;
+	if (up)
+		*up = p;
+	if (countp)
+		*countp = count;
 	return 0;
+}
 
-    SCSI_LOG_TIMEOUT(4,
-	 printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
-		num_xfer, iovec_count, schp->k_use_sg));
-    if (iovec_count) {
-	onum = iovec_count;
-	if ((k = verify_area(VERIFY_READ, hp->dxferp,
-			     SZ_SG_IOVEC * onum)))
-	    return k;
-    }
-    else
-	onum = 1;
-
-    if (0 == schp->k_use_sg) {  /* kernel has single buffer */
-	if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */
-	    for (j = 0, p = schp->buffer; j < onum; ++j) {
-		res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
-		if (res) return res;
-		usglen = (num_xfer > usglen) ? usglen : num_xfer;
-		if (__copy_to_user(up, p, usglen))
-		    return -EFAULT;
-		p += usglen;
-		num_xfer -= usglen;
-		if (num_xfer <= 0)
-		    return 0;
-	    }
-	}
-    }
-    else {      /* kernel using scatter gather list */
-	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
-	char * mem_src_arr = sg_get_sgat_msa(schp);
-
-	ksglen = (int)sclp->length;
-	p = sg_scatg2virt(sclp);
-	for (j = 0, k = 0; j < onum; ++j) {
-	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
-	    if (res) return res;
+static void
+sg_remove_scat(Sg_scatter_hold * schp)
+{
+	SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg));
+	if (schp->buffer && (schp->sglist_len > 0)) {
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
 
-	    for (; k < schp->k_use_sg; ++k, ++sclp) {
-		ksglen = (int)sclp->length; 
-		p = sg_scatg2virt(sclp);
-		if (NULL == p)
-		    break;
-		ok = (SG_USER_MEM != mem_src_arr[k]);
-		if (usglen <= 0)
-		    break;
-		if (ksglen > usglen) {
-		    if (usglen >= num_xfer) {
-			if (ok) {
-			    if (__copy_to_user(up, p, num_xfer))
-				return -EFAULT;
+		if (schp->dio_in_use) {
+#ifdef SG_ALLOW_DIO_CODE
+			st_unmap_user_pages(sclp, schp->k_use_sg, TRUE);
+#endif
+		} else {
+			int k;
+
+			for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp);
+			     ++k, ++sclp) {
+				SCSI_LOG_TIMEOUT(5, printk(
+				    "sg_remove_scat: k=%d, a=0x%p, len=%d\n",
+				    k, sg_scatg2virt(sclp), sclp->length));
+				sg_page_free(sg_scatg2virt(sclp), sclp->length);
+				sclp->page = NULL;
+				sclp->offset = 0;
+				sclp->length = 0;
 			}
-			return 0;
-		    }
-		    if (ok) {
-			if (__copy_to_user(up, p, usglen))
-			    return -EFAULT;
-		    }
-		    p += usglen;
-		    ksglen -= usglen;
-		    break;
 		}
-		else {
-		    if (ksglen >= num_xfer) {
-			if (ok) {
-			    if (__copy_to_user(up, p, num_xfer))
+		sg_page_free(schp->buffer, schp->sglist_len);
+	} else if (schp->buffer)
+		sg_page_free(schp->buffer, schp->b_malloc_len);
+	memset(schp, 0, sizeof (*schp));
+}
+
+static int
+sg_read_xfer(Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int num_xfer = 0;
+	int j, k, onum, usglen, ksglen, res;
+	int iovec_count = (int) hp->iovec_count;
+	int dxfer_dir = hp->dxfer_direction;
+	unsigned char *p;
+	unsigned char *up;
+	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
+
+	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir)
+	    || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
+		num_xfer = hp->dxfer_len;
+		if (schp->bufflen < num_xfer)
+			num_xfer = schp->bufflen;
+	}
+	if ((num_xfer <= 0) || (schp->dio_in_use) ||
+	    (new_interface
+	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+		return 0;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
+			  num_xfer, iovec_count, schp->k_use_sg));
+	if (iovec_count) {
+		onum = iovec_count;
+		if ((k = verify_area(VERIFY_READ, hp->dxferp,
+				     SZ_SG_IOVEC * onum)))
+			return k;
+	} else
+		onum = 1;
+
+	if (0 == schp->k_use_sg) {	/* kernel has single buffer */
+		for (j = 0, p = schp->buffer; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
+			if (res)
+				return res;
+			usglen = (num_xfer > usglen) ? usglen : num_xfer;
+			if (__copy_to_user(up, p, usglen))
 				return -EFAULT;
+			p += usglen;
+			num_xfer -= usglen;
+			if (num_xfer <= 0)
+				return 0;
+		}
+	} else {		/* kernel using scatter gather list */
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		ksglen = (int) sclp->length;
+		p = sg_scatg2virt(sclp);
+		for (j = 0, k = 0; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
+			if (res)
+				return res;
+
+			for (; k < schp->k_use_sg; ++k, ++sclp) {
+				ksglen = (int) sclp->length;
+				p = sg_scatg2virt(sclp);
+				if (NULL == p)
+					break;
+				if (usglen <= 0)
+					break;
+				if (ksglen > usglen) {
+					if (usglen >= num_xfer) {
+						if (__copy_to_user
+						    (up, p, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_to_user(up, p, usglen))
+						return -EFAULT;
+					p += usglen;
+					ksglen -= usglen;
+					break;
+				} else {
+					if (ksglen >= num_xfer) {
+						if (__copy_to_user
+						    (up, p, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_to_user(up, p, ksglen))
+						return -EFAULT;
+					up += ksglen;
+					usglen -= ksglen;
+				}
 			}
-			return 0;
-		    }
-		    if (ok) {
-			if (__copy_to_user(up, p, ksglen))
-			    return -EFAULT;
-		    }
-		    up += ksglen;
-		    usglen -= ksglen;
-		}
-	    }
-	}
-    }
-    return 0;
-}
-
-static int sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer)
-{
-    Sg_scatter_hold * schp = &srp->data;
-
-    SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
-			       num_read_xfer));
-    if ((! outp) || (num_read_xfer <= 0))
-        return 0;
-    if(schp->k_use_sg > 0) {
-        int k, num;
-        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
-
-	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
-            num = (int)sclp->length;
-            if (num > num_read_xfer) {
-                if (__copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer))
-		    return -EFAULT;
-                break;
-            }
-            else {
-                if (__copy_to_user(outp, sg_scatg2virt(sclp), num))
-		    return -EFAULT;
-                num_read_xfer -= num;
-                if (num_read_xfer <= 0)
-                    break;
-                outp += num;
-            }
-        }
-    }
-    else {
-        if (__copy_to_user(outp, schp->buffer, num_read_xfer))
-	    return -EFAULT;
-    }
-    return 0;
-}
-
-static void sg_build_reserve(Sg_fd * sfp, int req_size)
-{
-    Sg_scatter_hold * schp = &sfp->reserve;
-
-    SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));
-    do {
-        if (req_size < PAGE_SIZE)
-            req_size = PAGE_SIZE;
-	if (0 == sg_build_indi(schp, sfp, req_size))
-            return;
-        else
-            sg_remove_scat(schp);
-        req_size >>= 1; /* divide by 2 */
-    } while (req_size >  (PAGE_SIZE / 2));
-}
-
-static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
-{
-    Sg_scatter_hold * req_schp = &srp->data;
-    Sg_scatter_hold * rsv_schp = &sfp->reserve;
-
-    srp->res_used = 1;
-    SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
-    size = (size + 1) & (~1);    /* round to even for aha1542 */
-    if (rsv_schp->k_use_sg > 0) {
-        int k, num;
-        int rem = size;
-        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
-
-	for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
-            num = (int)sclp->length;
-            if (rem <= num) {
-		if (0 == k) {
-		    req_schp->k_use_sg = 0;
-		    req_schp->buffer = sg_scatg2virt(sclp);
 		}
-		else {
-    		    sfp->save_scat_len = num;
-    		    sclp->length = (unsigned)rem;
-    		    req_schp->k_use_sg = k + 1;
-    		    req_schp->sglist_len = rsv_schp->sglist_len;
-    		    req_schp->buffer = rsv_schp->buffer;
+	}
+	return 0;
+}
+
+static int
+sg_read_oxfer(Sg_request * srp, char *outp, int num_read_xfer)
+{
+	Sg_scatter_hold *schp = &srp->data;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
+				   num_read_xfer));
+	if ((!outp) || (num_read_xfer <= 0))
+		return 0;
+	if (schp->k_use_sg > 0) {
+		int k, num;
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp);
+		     ++k, ++sclp) {
+			num = (int) sclp->length;
+			if (num > num_read_xfer) {
+				if (__copy_to_user
+				    (outp, sg_scatg2virt(sclp), num_read_xfer))
+					return -EFAULT;
+				break;
+			} else {
+				if (__copy_to_user
+				    (outp, sg_scatg2virt(sclp), num))
+					return -EFAULT;
+				num_read_xfer -= num;
+				if (num_read_xfer <= 0)
+					break;
+				outp += num;
+			}
 		}
+	} else {
+		if (__copy_to_user(outp, schp->buffer, num_read_xfer))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static void
+sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+	Sg_scatter_hold *schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));
+	do {
+		if (req_size < PAGE_SIZE)
+			req_size = PAGE_SIZE;
+		if (0 == sg_build_indirect(schp, sfp, req_size))
+			return;
+		else
+			sg_remove_scat(schp);
+		req_size >>= 1;	/* divide by 2 */
+	} while (req_size > (PAGE_SIZE / 2));
+}
+
+static void
+sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	srp->res_used = 1;
+	SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+	size = (size + 1) & (~1);	/* round to even for aha1542 */
+	if (rsv_schp->k_use_sg > 0) {
+		int k, num;
+		int rem = size;
+		struct scatterlist *sclp =
+		    (struct scatterlist *) rsv_schp->buffer;
+
+		for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+			num = (int) sclp->length;
+			if (rem <= num) {
+				if (0 == k) {
+					req_schp->k_use_sg = 0;
+					req_schp->buffer = sg_scatg2virt(sclp);
+				} else {
+					sfp->save_scat_len = num;
+					sclp->length = (unsigned) rem;
+					req_schp->k_use_sg = k + 1;
+					req_schp->sglist_len =
+					    rsv_schp->sglist_len;
+					req_schp->buffer = rsv_schp->buffer;
+				}
+				req_schp->bufflen = size;
+				req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+				break;
+			} else
+				rem -= num;
+		}
+		if (k >= rsv_schp->k_use_sg)
+			SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
+	} else {
+		req_schp->k_use_sg = 0;
 		req_schp->bufflen = size;
-		req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;
+		req_schp->buffer = rsv_schp->buffer;
 		req_schp->b_malloc_len = rsv_schp->b_malloc_len;
-		break;
-            }
-            else
-                rem -= num;
-        }
-	if (k >= rsv_schp->k_use_sg)
-	    SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
-    }
-    else {
+	}
+}
+
+static void
+sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
+				   (int) req_schp->k_use_sg));
+	if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
+		struct scatterlist *sclp =
+		    (struct scatterlist *) rsv_schp->buffer;
+
+		if (sfp->save_scat_len > 0)
+			(sclp + (req_schp->k_use_sg - 1))->length =
+			    (unsigned) sfp->save_scat_len;
+		else
+			SCSI_LOG_TIMEOUT(1, printk ("sg_unlink_reserve: BAD save_scat_len\n"));
+	}
 	req_schp->k_use_sg = 0;
-        req_schp->bufflen = size;
-        req_schp->buffer = rsv_schp->buffer;
-	req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;
-        req_schp->b_malloc_len = rsv_schp->b_malloc_len;
-    }
-}
-
-static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
-{
-    Sg_scatter_hold * req_schp = &srp->data;
-    Sg_scatter_hold * rsv_schp = &sfp->reserve;
-
-    SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
-			       (int)req_schp->k_use_sg));
-    if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
-        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
-
-	if (sfp->save_scat_len > 0)
-	    (sclp + (req_schp->k_use_sg - 1))->length =
-                                        (unsigned)sfp->save_scat_len;
-        else
-            SCSI_LOG_TIMEOUT(1, printk(
-			"sg_unlink_reserve: BAD save_scat_len\n"));
-    }
-    req_schp->k_use_sg = 0;
-    req_schp->bufflen = 0;
-    req_schp->buffer = NULL;
-    req_schp->sglist_len = 0;
-    sfp->save_scat_len = 0;
-    srp->res_used = 0;
-}
-
-static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id)
-{
-    Sg_request * resp;
-    unsigned long iflags;
-
-    write_lock_irqsave(&sfp->rq_list_lock, iflags);
-    for (resp = sfp->headrp; resp; resp = resp->nextrp) { 
-	/* look for requests that are ready + not SG_IO owned */
-	if ((1 == resp->done) && (! resp->sg_io_owned) &&
-            ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
-	    resp->done = 2;   /* guard against other readers */
-            break;
-	}
-    }
-    write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return resp;
+	req_schp->bufflen = 0;
+	req_schp->buffer = NULL;
+	req_schp->sglist_len = 0;
+	sfp->save_scat_len = 0;
+	srp->res_used = 0;
+}
+
+static Sg_request *
+sg_get_rq_mark(Sg_fd * sfp, int pack_id)
+{
+	Sg_request *resp;
+	unsigned long iflags;
+
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (resp = sfp->headrp; resp; resp = resp->nextrp) {
+		/* look for requests that are ready + not SG_IO owned */
+		if ((1 == resp->done) && (!resp->sg_io_owned) &&
+		    ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+			resp->done = 2;	/* guard against other readers */
+			break;
+		}
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
 }
 
 #ifdef CONFIG_PROC_FS
-static Sg_request * sg_get_nth_request(Sg_fd * sfp, int nth)
+static Sg_request *
+sg_get_nth_request(Sg_fd * sfp, int nth)
 {
-    Sg_request * resp;
-    unsigned long iflags;
-    int k;
-
-    read_lock_irqsave(&sfp->rq_list_lock, iflags);
-    for (k = 0, resp = sfp->headrp; resp && (k < nth); 
-	 ++k, resp = resp->nextrp)
-	;
-    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return resp;
+	Sg_request *resp;
+	unsigned long iflags;
+	int k;
+
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (k = 0, resp = sfp->headrp; resp && (k < nth);
+	     ++k, resp = resp->nextrp) ;
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
 }
 #endif
 
 /* always adds to end of list */
-static Sg_request * sg_add_request(Sg_fd * sfp)
+static Sg_request *
+sg_add_request(Sg_fd * sfp)
 {
-    int k;
-    unsigned long iflags;
-    Sg_request * resp;
-    Sg_request * rp =  sfp->req_arr;
-
-    write_lock_irqsave(&sfp->rq_list_lock, iflags);
-    resp = sfp->headrp;
-    if (! resp) {
-	memset(rp, 0, sizeof(Sg_request));
-	rp->parentfp = sfp;
-	resp = rp;
-	sfp->headrp = resp;
-    }
-    else {
-        if (0 == sfp->cmd_q)
-            resp = NULL;   /* command queuing disallowed */
-        else {
-            for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
-                if (! rp->parentfp)
-                    break;
-            }
-            if (k < SG_MAX_QUEUE) {
-		memset(rp, 0, sizeof(Sg_request));
+	int k;
+	unsigned long iflags;
+	Sg_request *resp;
+	Sg_request *rp = sfp->req_arr;
+
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	resp = sfp->headrp;
+	if (!resp) {
+		memset(rp, 0, sizeof (Sg_request));
 		rp->parentfp = sfp;
-		while (resp->nextrp) 
-		    resp = resp->nextrp;
-		resp->nextrp = rp;
 		resp = rp;
-            }
-            else
-                resp = NULL;
-        }
-    }
-    if (resp) {
-        resp->nextrp = NULL;
-	resp->header.duration = jiffies;
-        resp->my_cmdp = NULL;
-#ifdef SG_ALLOW_DIO_CODE
-	resp->data.kiobp = NULL;
-#endif
-    }
-    write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return resp;
+		sfp->headrp = resp;
+	} else {
+		if (0 == sfp->cmd_q)
+			resp = NULL;	/* command queuing disallowed */
+		else {
+			for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+				if (!rp->parentfp)
+					break;
+			}
+			if (k < SG_MAX_QUEUE) {
+				memset(rp, 0, sizeof (Sg_request));
+				rp->parentfp = sfp;
+				while (resp->nextrp)
+					resp = resp->nextrp;
+				resp->nextrp = rp;
+				resp = rp;
+			} else
+				resp = NULL;
+		}
+	}
+	if (resp) {
+		resp->nextrp = NULL;
+		resp->header.duration = jiffies;
+		resp->my_cmdp = NULL;
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
 }
 
 /* Return of 1 for found; 0 for not found */
-static int sg_remove_request(Sg_fd * sfp, Sg_request * srp)
+static int
+sg_remove_request(Sg_fd * sfp, Sg_request * srp)
 {
-    Sg_request * prev_rp;
-    Sg_request * rp;
-    unsigned long iflags;
-    int res = 0;
-
-    if ((! sfp) || (! srp) || (! sfp->headrp))
-        return res;
-    write_lock_irqsave(&sfp->rq_list_lock, iflags);
-    prev_rp = sfp->headrp;
-    if (srp == prev_rp) {
-        sfp->headrp = prev_rp->nextrp;
-        prev_rp->parentfp = NULL;
-        res = 1;
-    }
-    else {
-	while ((rp = prev_rp->nextrp)) {
-	    if (srp == rp) {
-		prev_rp->nextrp = rp->nextrp;
-		rp->parentfp = NULL;
+	Sg_request *prev_rp;
+	Sg_request *rp;
+	unsigned long iflags;
+	int res = 0;
+
+	if ((!sfp) || (!srp) || (!sfp->headrp))
+		return res;
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	prev_rp = sfp->headrp;
+	if (srp == prev_rp) {
+		sfp->headrp = prev_rp->nextrp;
+		prev_rp->parentfp = NULL;
 		res = 1;
-		break;
-	    }
-	    prev_rp = rp;
+	} else {
+		while ((rp = prev_rp->nextrp)) {
+			if (srp == rp) {
+				prev_rp->nextrp = rp->nextrp;
+				rp->parentfp = NULL;
+				res = 1;
+				break;
+			}
+			prev_rp = rp;
+		}
 	}
-    }
-    write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return res;
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return res;
 }
 
 #ifdef CONFIG_PROC_FS
-static Sg_fd * sg_get_nth_sfp(Sg_device * sdp, int nth)
+static Sg_fd *
+sg_get_nth_sfp(Sg_device * sdp, int nth)
 {
-    Sg_fd * resp;
-    unsigned long iflags;
-    int k;
-
-    read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    for (k = 0, resp = sdp->headfp; resp && (k < nth); 
-	 ++k, resp = resp->nextfp)
-	;
-    read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    return resp;
+	Sg_fd *resp;
+	unsigned long iflags;
+	int k;
+
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = 0, resp = sdp->headfp; resp && (k < nth);
+	     ++k, resp = resp->nextfp) ;
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	return resp;
 }
 #endif
 
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev)
+static Sg_fd *
+sg_add_sfp(Sg_device * sdp, int dev)
 {
-    Sg_fd * sfp;
-    unsigned long iflags;
+	Sg_fd *sfp;
+	unsigned long iflags;
 
-    sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0);
-    if (! sfp)
-        return NULL;
-    memset(sfp, 0, sizeof(Sg_fd));
-    sfp->fd_mem_src = SG_HEAP_KMAL;
-    init_waitqueue_head(&sfp->read_wait);
-    sfp->rq_list_lock = RW_LOCK_UNLOCKED;
-
-    sfp->timeout = SG_DEFAULT_TIMEOUT;
-    sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-    sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-                   sdp->device->host->unchecked_isa_dma : 1;
-    sfp->cmd_q = SG_DEF_COMMAND_Q;
-    sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
-    sfp->parentdp = sdp;
-    write_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (! sdp->headfp)
-        sdp->headfp = sfp;
-    else {    /* add to tail of existing list */
-	Sg_fd * pfp = sdp->headfp;
-	while (pfp->nextfp)
-	    pfp = pfp->nextfp;
-	pfp->nextfp = sfp;
-    }
-    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
-			       sfp, (int)sfp->fd_mem_src));
-    sg_build_reserve(sfp, sg_big_buff);
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
+	sfp = (Sg_fd *) sg_page_malloc(sizeof (Sg_fd), 0, 0);
+	if (!sfp)
+		return NULL;
+	memset(sfp, 0, sizeof (Sg_fd));
+	init_waitqueue_head(&sfp->read_wait);
+	sfp->rq_list_lock = RW_LOCK_UNLOCKED;
+
+	sfp->timeout = SG_DEFAULT_TIMEOUT;
+	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
+	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
+	    sdp->device->host->unchecked_isa_dma : 1;
+	sfp->cmd_q = SG_DEF_COMMAND_Q;
+	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
+	sfp->parentdp = sdp;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	if (!sdp->headfp)
+		sdp->headfp = sfp;
+	else {			/* add to tail of existing list */
+		Sg_fd *pfp = sdp->headfp;
+		while (pfp->nextfp)
+			pfp = pfp->nextfp;
+		pfp->nextfp = sfp;
+	}
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
+	sg_build_reserve(sfp, sg_big_buff);
+	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
 			   sfp->reserve.bufflen, sfp->reserve.k_use_sg));
-    return sfp;
+	return sfp;
 }
 
-static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+static void
+__sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
 {
-    Sg_fd * fp;
-    Sg_fd * prev_fp;
+	Sg_fd *fp;
+	Sg_fd *prev_fp;
 
-    prev_fp =  sdp->headfp;
-    if (sfp == prev_fp)
-	sdp->headfp = prev_fp->nextfp;
-    else {
-	while ((fp = prev_fp->nextfp)) {
-	    if (sfp == fp) {
-		prev_fp->nextfp = fp->nextfp;
-		break;
-	    }
-	    prev_fp = fp;
+	prev_fp = sdp->headfp;
+	if (sfp == prev_fp)
+		sdp->headfp = prev_fp->nextfp;
+	else {
+		while ((fp = prev_fp->nextfp)) {
+			if (sfp == fp) {
+				prev_fp->nextfp = fp->nextfp;
+				break;
+			}
+			prev_fp = fp;
+		}
 	}
-    }
-    if (sfp->reserve.bufflen > 0) {
-    SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
-	     (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
-	if (sfp->mmap_called)
-	    sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
-	sg_remove_scat(&sfp->reserve);
-    }
-    sfp->parentdp = NULL;
-    SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    sfp=0x%p\n", sfp));
-    sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+	if (sfp->reserve.bufflen > 0) {
+		SCSI_LOG_TIMEOUT(6, 
+			printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
+			(int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg));
+		if (sfp->mmap_called)
+			sg_rb_correct4mmap(&sfp->reserve, 0);	/* undo correction */
+		sg_remove_scat(&sfp->reserve);
+	}
+	sfp->parentdp = NULL;
+	SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    sfp=0x%p\n", sfp));
+	sg_page_free((char *) sfp, sizeof (Sg_fd));
 }
 
 /* Returns 0 in normal case, 1 when detached and sdp object removed */
-static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+static int
+sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
 {
-    Sg_request * srp;
-    Sg_request * tsrp;
-    int dirty = 0;
-    int res = 0;
-
-    for (srp = sfp->headrp; srp; srp = tsrp) {
-	tsrp = srp->nextrp;
-	if (srp->done)
-	    sg_finish_rem_req(srp);
-	else
-	    ++dirty;
-    }
-    if (0 == dirty) {
-	unsigned long iflags;
+	Sg_request *srp;
+	Sg_request *tsrp;
+	int dirty = 0;
+	int res = 0;
+
+	for (srp = sfp->headrp; srp; srp = tsrp) {
+		tsrp = srp->nextrp;
+		if (srp->done)
+			sg_finish_rem_req(srp);
+		else
+			++dirty;
+	}
+	if (0 == dirty) {
+		unsigned long iflags;
 
-	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	__sg_remove_sfp(sdp, sfp);
-	if (sdp->detached && (NULL == sdp->headfp)) {
-	    int k, maxd;
-
-	    maxd = sg_template.dev_max;
-	    for (k = 0; k < maxd; ++k) {
-	    	if (sdp == sg_dev_arr[k])
-		    break;
-	    }
-	    if (k < maxd)
-		sg_dev_arr[k] = NULL;
-	    kfree((char *)sdp);
-	    res = 1;
+		write_lock_irqsave(&sg_dev_arr_lock, iflags);
+		__sg_remove_sfp(sdp, sfp);
+		if (sdp->detached && (NULL == sdp->headfp)) {
+			int k, maxd;
+
+			maxd = sg_template.dev_max;
+			for (k = 0; k < maxd; ++k) {
+				if (sdp == sg_dev_arr[k])
+					break;
+			}
+			if (k < maxd)
+				sg_dev_arr[k] = NULL;
+			vfree((char *) sdp);
+			res = 1;
+		}
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	} else {
+		sfp->closed = 1;	/* flag dirty state on this fd */
+		sdp->device->access_count++;
+		/* MOD_INC's to inhibit unloading sg and associated adapter driver */
+		if (sg_template.module)
+			__MOD_INC_USE_COUNT(sg_template.module);
+		if (sdp->device->host->hostt->module)
+			__MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
+		SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n",
+				  dirty));
 	}
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    }
-    else {
-        sfp->closed = 1; /* flag dirty state on this fd */
-	sdp->device->access_count++;
-	/* MOD_INC's to inhibit unloading sg and associated adapter driver */
-	if (sg_template.module)
-	    __MOD_INC_USE_COUNT(sg_template.module);
-	if (sdp->device->host->hostt->module)
-	    __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
-        SCSI_LOG_TIMEOUT(1, printk(
-          "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
-    }
-    return res;
-}
-
-static int sg_res_in_use(Sg_fd * sfp)
-{
-    const Sg_request * srp;
-    unsigned long iflags;
-
-    read_lock_irqsave(&sfp->rq_list_lock, iflags);
-    for (srp = sfp->headrp; srp; srp = srp->nextrp)
-        if (srp->res_used) break;
-    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return srp ? 1 : 0;
+	return res;
 }
 
-/* If retSzp==NULL want exact size or fail */
-static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
+static int
+sg_res_in_use(Sg_fd * sfp)
 {
-    char * resp = NULL;
-    int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
+	const Sg_request *srp;
+	unsigned long iflags;
 
-    if (rqSz <= 0)
-        return resp;
-    if (SG_HEAP_KMAL == mem_src) {
-        resp = kmalloc(rqSz, page_mask);
-        if (resp) {
-	    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-	    	memset(resp, 0, rqSz);
-	    if (retSzp) *retSzp = rqSz;
-	}
-        return resp;
-    }
-    else if (SG_HEAP_PAGE == mem_src) {
-        int order, a_size;
-        int resSz = rqSz;
-
-        for (order = 0, a_size = PAGE_SIZE;
-             a_size < rqSz; order++, a_size <<= 1)
-            ;
-        resp = (char *)__get_free_pages(page_mask, order);
-        while ((! resp) && order && retSzp) {
-            --order;
-            a_size >>= 1;   /* divide by 2, until PAGE_SIZE */
-            resp = (char *)__get_free_pages(page_mask, order); /* try half */
-            resSz = a_size;
-        }
-	if (resp) {
-	    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-	    	memset(resp, 0, resSz);
-	    if (retSzp) *retSzp = resSz;
-	}
-    }
-    else
-        printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", 
-	       mem_src, rqSz);
-    return resp;
-}
-
-static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
-                        int * mem_srcp)
-{
-    char * resp = NULL;
-
-    if (retSzp) *retSzp = size;
-    if (size <= 0)
-        ;
-    else {
-        int low_dma = sfp->low_dma;
-        int l_ms = -1;  /* invalid value */
-
-	switch (*mem_srcp)
-        {
-        case SG_HEAP_PAGE:
-            l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
-            resp = sg_low_malloc(size, low_dma, l_ms, 0);
-            if (resp)
-                break;
-            resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            if (! resp) {
-                l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
-                resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            }
-            if (resp && retSzp) *retSzp = size;
-            break;
-        case SG_HEAP_KMAL:
-            l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
-            resp = sg_low_malloc(size, low_dma, l_ms, 0);
-            break;
-        default:
-            SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
-            break;
-        }
-        if (resp) *mem_srcp = l_ms;
-    }
-    SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n",
-                               size, *mem_srcp, resp));
-    return resp;
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (srp = sfp->headrp; srp; srp = srp->nextrp)
+		if (srp->res_used)
+			break;
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return srp ? 1 : 0;
 }
 
-#ifdef SG_ALLOW_DIO_CODE
-static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+/* If retSzp==NULL want exact size or fail */
+static char *
+sg_page_malloc(int rqSz, int lowDma, int *retSzp)
 {
-#if SG_NEW_KIOVEC
-    return alloc_kiovec_sz(nr, bufp, szp);
-#else
-    return alloc_kiovec(nr, bufp);
-#endif
+	char *resp = NULL;
+	int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
+	int order, a_size;
+	int resSz = rqSz;
+
+	if (rqSz <= 0)
+		return resp;
+
+	for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
+	     order++, a_size <<= 1) ;
+	resp = (char *) __get_free_pages(page_mask, order);
+	while ((!resp) && order && retSzp) {
+		--order;
+		a_size >>= 1;	/* divide by 2, until PAGE_SIZE */
+		resp = (char *) __get_free_pages(page_mask, order);	/* try half */
+		resSz = a_size;
+	}
+	if (resp) {
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			memset(resp, 0, resSz);
+		if (retSzp)
+			*retSzp = resSz;
+	}
+	return resp;
 }
-#endif
 
-static void sg_low_free(char * buff, int size, int mem_src)
+static void
+sg_page_free(char *buff, int size)
 {
-    if (! buff) return;
-    switch (mem_src) {
-    case SG_HEAP_KMAL:
-	kfree(buff);    /* size not used */
-	break;
-    case SG_HEAP_PAGE:
-	{
-	    int order, a_size;
-	    for (order = 0, a_size = PAGE_SIZE;
-		 a_size < size; order++, a_size <<= 1)
-		;
-	    free_pages((unsigned long)buff, order);
-	}
-	break;
-    case SG_USER_MEM:
-	break; /* nothing to do */
-    default:
-	printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
-               mem_src, buff, size);
-	break;
-    }
-}
-
-static void sg_free(char * buff, int size, int mem_src)
-{
-    SCSI_LOG_TIMEOUT(6,
-        printk("sg_free: buff=0x%p, size=%d\n", buff, size));
-    if ((! buff) || (size <= 0))
-        ;
-    else
-        sg_low_free(buff, size, mem_src);
-}
+	int order, a_size;
 
-#ifdef SG_ALLOW_DIO_CODE
-static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
-{
-#if SG_NEW_KIOVEC
-    free_kiovec_sz(nr, bufp, szp);
-#else
-    free_kiovec(nr, bufp);
-#endif
+	if (!buff)
+		return;
+	for (order = 0, a_size = PAGE_SIZE; a_size < size;
+	     order++, a_size <<= 1) ;
+	free_pages((unsigned long) buff, order);
 }
-#endif
 
-static int sg_ms_to_jif(unsigned int msecs)
+static int
+sg_ms_to_jif(unsigned int msecs)
 {
-    if ((UINT_MAX / 2U) < msecs)
-	return INT_MAX;      /* special case, set largest possible */
-    else
-	return ((int)msecs < (INT_MAX / 1000)) ? (((int)msecs * HZ) / 1000)
-					       : (((int)msecs / 1000) * HZ);
+	if ((UINT_MAX / 2U) < msecs)
+		return INT_MAX;	/* special case, set largest possible */
+	else
+		return ((int) msecs <
+			(INT_MAX / 1000)) ? (((int) msecs * HZ) / 1000)
+		    : (((int) msecs / 1000) * HZ);
 }
 
-static inline unsigned sg_jif_to_ms(int jifs)
+static inline unsigned
+sg_jif_to_ms(int jifs)
 {
-    if (jifs <= 0)
-	return 0U;
-    else {
-	unsigned int j = (unsigned int)jifs;
-	return (j < (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * 1000);
-    }
+	if (jifs <= 0)
+		return 0U;
+	else {
+		unsigned int j = (unsigned int) jifs;
+		return (j <
+			(UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) *
+								  1000);
+	}
 }
 
-static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE,
-INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
-MODE_SENSE, MODE_SENSE_10, LOG_SENSE};
+static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
+	INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
+	MODE_SENSE, MODE_SENSE_10, LOG_SENSE
+};
 
-static int sg_allow_access(unsigned char opcode, char dev_type)
+static int
+sg_allow_access(unsigned char opcode, char dev_type)
 {
-    int k;
+	int k;
 
-    if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */
-	return 1;
-    for (k = 0; k < sizeof(allow_ops); ++k) {
-	if (opcode == allow_ops[k])
-	    return 1;
-    }
-    return 0;
+	if (TYPE_SCANNER == dev_type)	/* TYPE_ROM maybe burner */
+		return 1;
+	for (k = 0; k < sizeof (allow_ops); ++k) {
+		if (opcode == allow_ops[k])
+			return 1;
+	}
+	return 0;
 }
 
-
 #ifdef CONFIG_PROC_FS
-static int sg_last_dev()
+static int
+sg_last_dev()
 {
-    int k;
-    unsigned long iflags;
+	int k;
+	unsigned long iflags;
 
-    read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    for (k = sg_template.dev_max - 1; k >= 0; --k)
-	if (sg_dev_arr[k] && sg_dev_arr[k]->device) break;
-    read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    return k + 1;   /* origin 1 */
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = sg_template.dev_max - 1; k >= 0; --k)
+		if (sg_dev_arr[k] && sg_dev_arr[k]->device)
+			break;
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	return k + 1;		/* origin 1 */
 }
 #endif
 
-static Sg_device * sg_get_dev(int dev)
+static Sg_device *
+sg_get_dev(int dev)
 {
-    Sg_device * sdp = NULL;
-    unsigned long iflags;
+	Sg_device *sdp = NULL;
+	unsigned long iflags;
 
-    if (sg_dev_arr && (dev >= 0))
-    {
-	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-	if (dev < sg_template.dev_max)
-	    sdp = sg_dev_arr[dev];
-	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    }
-    return sdp;
+	if (sg_dev_arr && (dev >= 0)) {
+		read_lock_irqsave(&sg_dev_arr_lock, iflags);
+		if (dev < sg_template.dev_max)
+			sdp = sg_dev_arr[dev];
+		read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	}
+	return sdp;
 }
 
 #ifdef CONFIG_PROC_FS
 
-static struct proc_dir_entry * sg_proc_sgp = NULL;
+static struct proc_dir_entry *sg_proc_sgp = NULL;
 
 static char sg_proc_sg_dirname[] = "sg";
-static const char * sg_proc_leaf_names[] = {"allow_dio", "def_reserved_size",
-		"debug", "devices", "device_hdr", "device_strs",
-		"hosts", "host_hdr", "host_strs", "version"};
-
-static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
-			     int size, int * eof, void * data);
-static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
+static const char *sg_proc_leaf_names[] = { "allow_dio", "def_reserved_size",
+	"debug", "devices", "device_hdr", "device_strs",
+	"hosts", "host_hdr", "host_strs", "version"
+};
+
+static int sg_proc_adio_read(char *buffer, char **start, off_t offset,
+			     int size, int *eof, void *data);
+static int sg_proc_adio_info(char *buffer, int *len, off_t * begin,
 			     off_t offset, int size);
-static int sg_proc_adio_write(struct file * filp, const char * buffer,
-			      unsigned long count, void * data);
-static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
-			       int size, int * eof, void * data);
-static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_adio_write(struct file *filp, const char *buffer,
+			      unsigned long count, void *data);
+static int sg_proc_dressz_read(char *buffer, char **start, off_t offset,
+			       int size, int *eof, void *data);
+static int sg_proc_dressz_info(char *buffer, int *len, off_t * begin,
 			       off_t offset, int size);
-static int sg_proc_dressz_write(struct file * filp, const char * buffer,
-				unsigned long count, void * data);
-static int sg_proc_debug_read(char * buffer, char ** start, off_t offset,
-			      int size, int * eof, void * data);
-static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_dressz_write(struct file *filp, const char *buffer,
+				unsigned long count, void *data);
+static int sg_proc_debug_read(char *buffer, char **start, off_t offset,
+			      int size, int *eof, void *data);
+static int sg_proc_debug_info(char *buffer, int *len, off_t * begin,
 			      off_t offset, int size);
-static int sg_proc_dev_read(char * buffer, char ** start, off_t offset,
-			    int size, int * eof, void * data);
-static int sg_proc_dev_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_dev_read(char *buffer, char **start, off_t offset,
+			    int size, int *eof, void *data);
+static int sg_proc_dev_info(char *buffer, int *len, off_t * begin,
 			    off_t offset, int size);
-static int sg_proc_devhdr_read(char * buffer, char ** start, off_t offset,
-			       int size, int * eof, void * data);
-static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_devhdr_read(char *buffer, char **start, off_t offset,
+			       int size, int *eof, void *data);
+static int sg_proc_devhdr_info(char *buffer, int *len, off_t * begin,
 			       off_t offset, int size);
-static int sg_proc_devstrs_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data);
-static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_devstrs_read(char *buffer, char **start, off_t offset,
+				int size, int *eof, void *data);
+static int sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
 				off_t offset, int size);
-static int sg_proc_host_read(char * buffer, char ** start, off_t offset,
-			     int size, int * eof, void * data);
-static int sg_proc_host_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_host_read(char *buffer, char **start, off_t offset,
+			     int size, int *eof, void *data);
+static int sg_proc_host_info(char *buffer, int *len, off_t * begin,
 			     off_t offset, int size);
-static int sg_proc_hosthdr_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data);
-static int sg_proc_hosthdr_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_hosthdr_read(char *buffer, char **start, off_t offset,
+				int size, int *eof, void *data);
+static int sg_proc_hosthdr_info(char *buffer, int *len, off_t * begin,
 				off_t offset, int size);
-static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset,
-				 int size, int * eof, void * data);
-static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_hoststrs_read(char *buffer, char **start, off_t offset,
+				 int size, int *eof, void *data);
+static int sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin,
 				 off_t offset, int size);
-static int sg_proc_version_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data);
-static int sg_proc_version_info(char * buffer, int * len, off_t * begin,
+static int sg_proc_version_read(char *buffer, char **start, off_t offset,
+				int size, int *eof, void *data);
+static int sg_proc_version_info(char *buffer, int *len, off_t * begin,
 				off_t offset, int size);
-static read_proc_t * sg_proc_leaf_reads[] = {
-	     sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read,
-	     sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read,
-	     sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read,
-	     sg_proc_version_read};
-static write_proc_t * sg_proc_leaf_writes[] = {
-	     sg_proc_adio_write, sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0};
+static read_proc_t *sg_proc_leaf_reads[] = {
+	sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read,
+	sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read,
+	sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read,
+	sg_proc_version_read
+};
+static write_proc_t *sg_proc_leaf_writes[] = {
+	sg_proc_adio_write, sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0
+};
 
 #define PRINT_PROC(fmt,args...)                                 \
     do {                                                        \
@@ -2816,317 +2750,391 @@
 				size : begin + len - offset;    \
     } while(0)
 
-
-static int sg_proc_init()
+static int
+sg_proc_init()
 {
-    int k, mask;
-    int leaves = sizeof(sg_proc_leaf_names) / sizeof(sg_proc_leaf_names[0]);
-    struct proc_dir_entry * pdep;
-
-    if (! proc_scsi)
-	return 1;
-    sg_proc_sgp = create_proc_entry(sg_proc_sg_dirname,
-				    S_IFDIR | S_IRUGO | S_IXUGO, proc_scsi);
-    if (! sg_proc_sgp)
-	return 1;
-    for (k = 0; k < leaves; ++k) {
-	mask = sg_proc_leaf_writes[k] ? S_IRUGO | S_IWUSR : S_IRUGO;
-	pdep = create_proc_entry(sg_proc_leaf_names[k], mask, sg_proc_sgp);
-	if (pdep) {
-	    pdep->read_proc = sg_proc_leaf_reads[k];
-	    if (sg_proc_leaf_writes[k])
-		pdep->write_proc = sg_proc_leaf_writes[k];
+	int k, mask;
+	int leaves =
+	    sizeof (sg_proc_leaf_names) / sizeof (sg_proc_leaf_names[0]);
+	struct proc_dir_entry *pdep;
+
+	if (!proc_scsi)
+		return 1;
+	sg_proc_sgp = create_proc_entry(sg_proc_sg_dirname,
+					S_IFDIR | S_IRUGO | S_IXUGO, proc_scsi);
+	if (!sg_proc_sgp)
+		return 1;
+	for (k = 0; k < leaves; ++k) {
+		mask = sg_proc_leaf_writes[k] ? S_IRUGO | S_IWUSR : S_IRUGO;
+		pdep =
+		    create_proc_entry(sg_proc_leaf_names[k], mask, sg_proc_sgp);
+		if (pdep) {
+			pdep->read_proc = sg_proc_leaf_reads[k];
+			if (sg_proc_leaf_writes[k])
+				pdep->write_proc = sg_proc_leaf_writes[k];
+		}
 	}
-    }
-    return 0;
+	return 0;
 }
 
-static void sg_proc_cleanup()
+static void
+sg_proc_cleanup()
 {
-    int k;
-    int leaves = sizeof(sg_proc_leaf_names) / sizeof(sg_proc_leaf_names[0]);
+	int k;
+	int leaves =
+	    sizeof (sg_proc_leaf_names) / sizeof (sg_proc_leaf_names[0]);
 
-    if ((! proc_scsi) || (! sg_proc_sgp))
-	return;
-    for (k = 0; k < leaves; ++k)
-	remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp);
-    remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
+	if ((!proc_scsi) || (!sg_proc_sgp))
+		return;
+	for (k = 0; k < leaves; ++k)
+		remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp);
+	remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
 }
 
-static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
-			       int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_adio_info); }
+static int
+sg_proc_adio_read(char *buffer, char **start, off_t offset,
+		  int size, int *eof, void *data)
+{
+	SG_PROC_READ_FN(sg_proc_adio_info);
+}
 
-static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
-			     off_t offset, int size)
+static int
+sg_proc_adio_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
 {
-    PRINT_PROC("%d\n", sg_allow_dio);
-    return 1;
+	PRINT_PROC("%d\n", sg_allow_dio);
+	return 1;
 }
 
-static int sg_proc_adio_write(struct file * filp, const char * buffer,
-			      unsigned long count, void * data)
+static int
+sg_proc_adio_write(struct file *filp, const char *buffer,
+		   unsigned long count, void *data)
 {
-    int num;
-    char buff[11];
+	int num;
+	char buff[11];
 
-    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-	return -EACCES;
-    num = (count < 10) ? count : 10;
-    if (copy_from_user(buff, buffer, num))
-	return -EFAULT;
-    buff[num] = '\0';
-    sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0;
-    return count;
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		return -EACCES;
+	num = (count < 10) ? count : 10;
+	if (copy_from_user(buff, buffer, num))
+		return -EFAULT;
+	buff[num] = '\0';
+	sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0;
+	return count;
 }
 
-static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
-			       int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_dressz_info); }
-
-static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin,
-			       off_t offset, int size)
+static int
+sg_proc_dressz_read(char *buffer, char **start, off_t offset,
+		    int size, int *eof, void *data)
 {
-    PRINT_PROC("%d\n", sg_big_buff);
-    return 1;
+	SG_PROC_READ_FN(sg_proc_dressz_info);
 }
 
-static int sg_proc_dressz_write(struct file * filp, const char * buffer,
-				unsigned long count, void * data)
+static int
+sg_proc_dressz_info(char *buffer, int *len, off_t * begin,
+		    off_t offset, int size)
 {
-    int num;
-    unsigned long k = ULONG_MAX;
-    char buff[11];
-
-    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-	return -EACCES;
-    num = (count < 10) ? count : 10;
-    if (copy_from_user(buff, buffer, num))
-	return -EFAULT;
-    buff[num] = '\0';
-    k = simple_strtoul(buff, 0, 10);
-    if (k <= 1048576) {		/* limit "big buff" to 1 MB */
-	sg_big_buff = k;
-	return count;
-    }
-    return -ERANGE;
+	PRINT_PROC("%d\n", sg_big_buff);
+	return 1;
 }
 
-static int sg_proc_debug_read(char * buffer, char ** start, off_t offset,
-			      int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_debug_info); }
+static int
+sg_proc_dressz_write(struct file *filp, const char *buffer,
+		     unsigned long count, void *data)
+{
+	int num;
+	unsigned long k = ULONG_MAX;
+	char buff[11];
 
-static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
-			      off_t offset, int size)
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		return -EACCES;
+	num = (count < 10) ? count : 10;
+	if (copy_from_user(buff, buffer, num))
+		return -EFAULT;
+	buff[num] = '\0';
+	k = simple_strtoul(buff, 0, 10);
+	if (k <= 1048576) {	/* limit "big buff" to 1 MB */
+		sg_big_buff = k;
+		return count;
+	}
+	return -ERANGE;
+}
+
+static int
+sg_proc_debug_read(char *buffer, char **start, off_t offset,
+		   int size, int *eof, void *data)
 {
-    Sg_device * sdp;
-    const sg_io_hdr_t * hp;
-    int j, max_dev, new_interface;
+	SG_PROC_READ_FN(sg_proc_debug_info);
+}
 
-    if (NULL == sg_dev_arr) {
-	PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
-	return 1;
-    }
-    max_dev = sg_last_dev();
-    PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
-	       sg_template.dev_max, max_dev);
-    PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
-    for (j = 0; j < max_dev; ++j) {
-	if ((sdp = sg_get_dev(j))) {
-	    Sg_fd * fp;
-	    Sg_request * srp;
-	    struct scsi_device * scsidp;
-	    int dev, k, m, blen, usg;
- 
-	    scsidp = sdp->device;
-	    if (NULL == scsidp) {
-		PRINT_PROC("device %d detached ??\n", j);
-		continue;
-	    }
-	    dev = minor(sdp->i_rdev);
+static int sg_proc_debug_helper(char *buffer, int *len, off_t * begin,
+				off_t offset, int size, Sg_device * sdp)
+{
+	int k, m, new_interface, blen, usg;
+	Sg_request *srp;
+	Sg_fd *fp;
+	const sg_io_hdr_t *hp;
+	const char * cp;
 
-	    if (sg_get_nth_sfp(sdp, 0)) {
-		PRINT_PROC(" >>> device=sg%d ", dev);
-		if (sdp->detached)
-		    PRINT_PROC("detached pending close ");
-		else
-		    PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d",
-		       scsidp->host->host_no, scsidp->channel,
-		       scsidp->id, scsidp->lun, scsidp->host->hostt->emulated);
-		PRINT_PROC(" sg_tablesize=%d excl=%d\n", sdp->sg_tablesize, 
-			   sdp->exclude);
-	    }
-	    for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
+	for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
 		PRINT_PROC("   FD(%d): timeout=%dms bufflen=%d "
 			   "(res)sgat=%d low_dma=%d\n", k + 1,
-			   sg_jif_to_ms(fp->timeout), fp->reserve.bufflen,
-			   (int)fp->reserve.k_use_sg, (int)fp->low_dma);
+			   sg_jif_to_ms(fp->timeout),
+			   fp->reserve.bufflen,
+			   (int) fp->reserve.k_use_sg,
+			   (int) fp->low_dma);
 		PRINT_PROC("   cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
-			   (int)fp->cmd_q, (int)fp->force_packid,
-			   (int)fp->keep_orphan, (int)fp->closed);
+			   (int) fp->cmd_q, (int) fp->force_packid,
+			   (int) fp->keep_orphan, (int) fp->closed);
 		for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
-		    hp = &srp->header;
-		    new_interface = (hp->interface_id == '\0') ? 0 : 1;
-/* stop indenting so far ... */
-	PRINT_PROC(srp->res_used ? ((new_interface && 
-	    (SG_FLAG_MMAP_IO & hp->flags)) ? "     mmap>> " : "     rb>> ") :
-	    ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
-	blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
-	usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
-	PRINT_PROC(srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") 
-			     : (srp->my_cmdp ? "act:" : "prior:"));
-	PRINT_PROC(" id=%d blen=%d", srp->header.pack_id, blen);
-	if (srp->done)
-	    PRINT_PROC(" dur=%d", hp->duration);
-	else
-	    PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
-			sg_jif_to_ms(fp->timeout),
-		  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
-	PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
-/* reset indenting */
+			hp = &srp->header;
+			new_interface = (hp->interface_id == '\0') ? 0 : 1;
+			if (srp->res_used) {
+				if (new_interface && 
+				    (SG_FLAG_MMAP_IO & hp->flags))
+					cp = "     mmap>> ";
+				else
+					cp = "     rb>> ";
+			} else {
+				if (SG_INFO_DIRECT_IO_MASK & hp->info)
+					cp = "     dio>> ";
+				else
+					cp = "     ";
+			}
+			PRINT_PROC(cp);
+			blen = srp->my_cmdp ? 
+				srp->my_cmdp->sr_bufflen : srp->data.bufflen;
+			usg = srp->my_cmdp ? 
+				srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
+			PRINT_PROC(srp->done ? 
+				   ((1 == srp->done) ?  "rcv:" : "fin:")
+				   : (srp->my_cmdp ? "act:" : "prior:"));
+			PRINT_PROC(" id=%d blen=%d",
+				   srp->header.pack_id, blen);
+			if (srp->done)
+				PRINT_PROC(" dur=%d", hp->duration);
+			else
+				PRINT_PROC(" t_o/elap=%d/%d",
+				  new_interface ? hp->timeout : sg_jif_to_ms(fp->timeout),
+				  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
+			PRINT_PROC("ms sgat=%d op=0x%02x\n", usg,
+				   (int) srp->data.cmd_opcode);
 		}
 		if (0 == m)
-		    PRINT_PROC("     No requests active\n");
-	    }
+			PRINT_PROC("     No requests active\n");
 	}
-    }
-    return 1;
+	return 1;
 }
 
-static int sg_proc_dev_read(char * buffer, char ** start, off_t offset,
-			    int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_dev_info); }
-
-static int sg_proc_dev_info(char * buffer, int * len, off_t * begin,
-			    off_t offset, int size)
-{
-    Sg_device * sdp;
-    int j, max_dev;
-    struct scsi_device * scsidp;
-
-    max_dev = sg_last_dev();
-    for (j = 0; j < max_dev; ++j) {
-	sdp = sg_get_dev(j);
-	if (sdp && (scsidp = sdp->device) && (! sdp->detached))
-	    PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
-	       scsidp->host->host_no, scsidp->channel, scsidp->id,
-	       scsidp->lun, (int)scsidp->type, (int)scsidp->access_count,
-	       (int)scsidp->queue_depth, (int)scsidp->device_busy,
-	       (int)scsidp->online);
-	else
-	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
-    }
-    return 1;
+static int
+sg_proc_debug_info(char *buffer, int *len, off_t * begin,
+		   off_t offset, int size)
+{
+	Sg_device *sdp;
+	int j, max_dev;
+
+	if (NULL == sg_dev_arr) {
+		PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
+		return 1;
+	}
+	max_dev = sg_last_dev();
+	PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
+		   sg_template.dev_max, max_dev);
+	PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
+	for (j = 0; j < max_dev; ++j) {
+		if ((sdp = sg_get_dev(j))) {
+			struct scsi_device *scsidp;
+			int dev;
+
+			scsidp = sdp->device;
+			if (NULL == scsidp) {
+				PRINT_PROC("device %d detached ??\n", j);
+				continue;
+			}
+			dev = minor(sdp->i_rdev);
+
+			if (sg_get_nth_sfp(sdp, 0)) {
+				PRINT_PROC(" >>> device=sg%d ", dev);
+				if (sdp->detached)
+					PRINT_PROC("detached pending close ");
+				else
+					PRINT_PROC
+					    ("scsi%d chan=%d id=%d lun=%d   em=%d",
+					     scsidp->host->host_no,
+					     scsidp->channel, scsidp->id,
+					     scsidp->lun,
+					     scsidp->host->hostt->emulated);
+				PRINT_PROC(" sg_tablesize=%d excl=%d\n",
+					   sdp->sg_tablesize, sdp->exclude);
+			}
+			if (0 == sg_proc_debug_helper(buffer, len, begin,
+						      offset, size, sdp))
+				return 0;
+		}
+	}
+	return 1;
 }
 
-static int sg_proc_devhdr_read(char * buffer, char ** start, off_t offset,
-			       int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_devhdr_info); }
+static int
+sg_proc_dev_read(char *buffer, char **start, off_t offset,
+		 int size, int *eof, void *data)
+{
+	SG_PROC_READ_FN(sg_proc_dev_info);
+}
+
+static int
+sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
+{
+	Sg_device *sdp;
+	int j, max_dev;
+	struct scsi_device *scsidp;
+
+	max_dev = sg_last_dev();
+	for (j = 0; j < max_dev; ++j) {
+		sdp = sg_get_dev(j);
+		if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+			PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+				   scsidp->host->host_no, scsidp->channel,
+				   scsidp->id, scsidp->lun, (int) scsidp->type,
+				   (int) scsidp->access_count,
+				   (int) scsidp->queue_depth,
+				   (int) scsidp->device_busy,
+				   (int) scsidp->online);
+		else
+			PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
+	}
+	return 1;
+}
 
-static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin,
-			       off_t offset, int size)
+static int
+sg_proc_devhdr_read(char *buffer, char **start, off_t offset,
+		    int size, int *eof, void *data)
 {
-    PRINT_PROC("host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n");
-    return 1;
+	SG_PROC_READ_FN(sg_proc_devhdr_info);
 }
 
-static int sg_proc_devstrs_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_devstrs_info); }
-
-static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin,
-				off_t offset, int size)
+static int
+sg_proc_devhdr_info(char *buffer, int *len, off_t * begin,
+		    off_t offset, int size)
 {
-    Sg_device * sdp;
-    int j, max_dev;
-    struct scsi_device * scsidp;
+	PRINT_PROC("host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n");
+	return 1;
+}
 
-    max_dev = sg_last_dev();
-    for (j = 0; j < max_dev; ++j) {
-	sdp = sg_get_dev(j);
-	if (sdp && (scsidp = sdp->device) && (! sdp->detached))
-	    PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
-		       scsidp->vendor, scsidp->model, scsidp->rev);
-	else
-	    PRINT_PROC("<no active device>\n");
-    }
-    return 1;
+static int
+sg_proc_devstrs_read(char *buffer, char **start, off_t offset,
+		     int size, int *eof, void *data)
+{
+	SG_PROC_READ_FN(sg_proc_devstrs_info);
+}
+
+static int
+sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
+		     off_t offset, int size)
+{
+	Sg_device *sdp;
+	int j, max_dev;
+	struct scsi_device *scsidp;
+
+	max_dev = sg_last_dev();
+	for (j = 0; j < max_dev; ++j) {
+		sdp = sg_get_dev(j);
+		if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+			PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
+				   scsidp->vendor, scsidp->model, scsidp->rev);
+		else
+			PRINT_PROC("<no active device>\n");
+	}
+	return 1;
 }
 
-static int sg_proc_host_read(char * buffer, char ** start, off_t offset,
-			     int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_host_info); }
+static int
+sg_proc_host_read(char *buffer, char **start, off_t offset,
+		  int size, int *eof, void *data)
+{
+	SG_PROC_READ_FN(sg_proc_host_info);
+}
+
+static int
+sg_proc_host_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
+{
+	struct Scsi_Host *shp;
+	int k;
+
+	for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
+		for (; k < shp->host_no; ++k)
+			PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n");
+		PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n",
+			   shp->unique_id, shp->host_busy, shp->cmd_per_lun,
+			   shp->sg_tablesize, (int) shp->unchecked_isa_dma,
+			   (int) shp->hostt->emulated);
+	}
+	return 1;
+}
 
-static int sg_proc_host_info(char * buffer, int * len, off_t * begin,
-			     off_t offset, int size)
+static int
+sg_proc_hosthdr_read(char *buffer, char **start, off_t offset,
+		     int size, int *eof, void *data)
 {
-    struct Scsi_Host * shp;
-    int k;
-
-    for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
-    	for ( ; k < shp->host_no; ++k)
-	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n");
-	PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n",
-		   shp->unique_id, shp->host_busy, shp->cmd_per_lun,
-		   shp->sg_tablesize, (int)shp->unchecked_isa_dma,
-		   (int)shp->hostt->emulated);
-    }
-    return 1;
+	SG_PROC_READ_FN(sg_proc_hosthdr_info);
 }
 
-static int sg_proc_hosthdr_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_hosthdr_info); }
-
-static int sg_proc_hosthdr_info(char * buffer, int * len, off_t * begin,
-				off_t offset, int size)
+static int
+sg_proc_hosthdr_info(char *buffer, int *len, off_t * begin,
+		     off_t offset, int size)
 {
-    PRINT_PROC("uid\tbusy\tcpl\tscatg\tisa\temul\n");
-    return 1;
+	PRINT_PROC("uid\tbusy\tcpl\tscatg\tisa\temul\n");
+	return 1;
 }
 
-static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset,
-				 int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_hoststrs_info); }
+static int
+sg_proc_hoststrs_read(char *buffer, char **start, off_t offset,
+		      int size, int *eof, void *data)
+{
+	SG_PROC_READ_FN(sg_proc_hoststrs_info);
+}
 
 #define SG_MAX_HOST_STR_LEN 256
 
-static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin,
-				 off_t offset, int size)
-{
-    struct Scsi_Host * shp;
-    int k;
-    char buff[SG_MAX_HOST_STR_LEN];
-    char * cp;
-
-    for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
-        for ( ; k < shp->host_no; ++k)
-            PRINT_PROC("<no active host>\n");
-        strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
-                    (shp->hostt->name ? shp->hostt->name : "<no name>"),
-                SG_MAX_HOST_STR_LEN);
-        buff[SG_MAX_HOST_STR_LEN - 1] = '\0';
-        for (cp = buff; *cp; ++cp) {
-            if ('\n' == *cp)
-                *cp = ' '; /* suppress imbedded newlines */
-        }
-        PRINT_PROC("%s\n", buff);
-    }
-    return 1;
+static int
+sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin,
+		      off_t offset, int size)
+{
+	struct Scsi_Host *shp;
+	int k;
+	char buff[SG_MAX_HOST_STR_LEN];
+	char *cp;
+
+	for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
+		for (; k < shp->host_no; ++k)
+			PRINT_PROC("<no active host>\n");
+		strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
+			(shp->hostt->name ? shp->hostt->name : "<no name>"),
+			SG_MAX_HOST_STR_LEN);
+		buff[SG_MAX_HOST_STR_LEN - 1] = '\0';
+		for (cp = buff; *cp; ++cp) {
+			if ('\n' == *cp)
+				*cp = ' ';	/* suppress imbedded newlines */
+		}
+		PRINT_PROC("%s\n", buff);
+	}
+	return 1;
 }
 
-static int sg_proc_version_read(char * buffer, char ** start, off_t offset,
-				int size, int * eof, void * data)
-{ SG_PROC_READ_FN(sg_proc_version_info); }
-
-static int sg_proc_version_info(char * buffer, int * len, off_t * begin,
-				off_t offset, int size)
+static int
+sg_proc_version_read(char *buffer, char **start, off_t offset,
+		     int size, int *eof, void *data)
 {
-    PRINT_PROC("%d\t%s\n", sg_version_num, sg_version_str);
-    return 1;
+	SG_PROC_READ_FN(sg_proc_version_info);
 }
-#endif  /* CONFIG_PROC_FS */
 
+static int
+sg_proc_version_info(char *buffer, int *len, off_t * begin,
+		     off_t offset, int size)
+{
+	PRINT_PROC("%d\t%s\n", sg_version_num, sg_version_str);
+	return 1;
+}
+#endif				/* CONFIG_PROC_FS */
 
 module_init(init_sg);
 module_exit(exit_sg);
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/scsi/sr.c	Tue Aug 27 12:28:02 2002
@@ -734,17 +734,17 @@
 				   char *page, size_t count, loff_t off)
 {
 	kdev_t kdev; 
-	kdev.value=(int)driverfs_dev->driver_data;
+	kdev.value=(int)(long)driverfs_dev->driver_data;
 	return off ? 0 : sprintf(page, "%x\n",kdev.value);
 }
-static DEVICE_ATTR(kdev,"kdev",S_IRUGO,sr_device_kdev_read,NULL);
+static DEVICE_ATTR(kdev,S_IRUGO,sr_device_kdev_read,NULL);
 
 static ssize_t sr_device_type_read(struct device *driverfs_dev, 
 				   char *page, size_t count, loff_t off) 
 {
 	return off ? 0 : sprintf (page, "CHR\n");
 }
-static DEVICE_ATTR(type,"type",S_IRUGO,sr_device_type_read,NULL);
+static DEVICE_ATTR(type,S_IRUGO,sr_device_type_read,NULL);
 
 
 void sr_finish()
@@ -800,7 +800,7 @@
 			&SCp->device->sdev_driverfs_dev;
 		SCp->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
 		SCp->cdi.cdrom_driverfs_dev.driver_data = 
-			(void *)__mkdev(MAJOR_NR, i);
+			(void *)(long)__mkdev(MAJOR_NR, i);
 		device_register(&SCp->cdi.cdrom_driverfs_dev);
 		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
 				   &dev_attr_type);
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/scsi/st.c	Tue Aug 27 12:28:07 2002
@@ -12,13 +12,13 @@
    Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Mon Jul 22 13:27:21 2002 by makisara
+   Last modified: Thu Aug 22 21:57:07 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20020722";
+static char *verstr = "20020822";
 
 #include <linux/module.h>
 
@@ -70,6 +70,9 @@
 static int buffer_kbs;
 static int write_threshold_kbs;
 static int max_sg_segs;
+static int try_direct_io = TRY_DIRECT_IO;
+static int try_rdio = TRUE;
+static int try_wdio = TRUE;
 
 MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI Tape Driver");
@@ -80,7 +83,15 @@
 MODULE_PARM(write_threshold_kbs, "i");
 MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 30)");
 MODULE_PARM(max_sg_segs, "i");
-MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (64)");
+MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
+MODULE_PARM(try_direct_io, "i");
+MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
+
+/* Extra parameters for testing */
+MODULE_PARM(try_rdio, "i");
+MODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible");
+MODULE_PARM(try_wdio, "i");
+MODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible");
 
 #ifndef MODULE
 static struct st_dev_parm {
@@ -95,7 +106,9 @@
 	},
 	{
 		"max_sg_segs", &max_sg_segs
-	}
+	},
+	{
+		"try_direct_io", &try_direct_io
 };
 #endif
 
@@ -146,6 +159,12 @@
 static int from_buffer(ST_buffer *, char *, int);
 static void buf_to_sg(ST_buffer *, unsigned int);
 
+static int st_map_user_pages(struct scatterlist *, const unsigned int, 
+			     unsigned long, size_t, int, unsigned long);
+static int sgl_map_user_pages(struct scatterlist *, const unsigned int, 
+			      unsigned long, size_t, int);
+static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
+
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
@@ -362,9 +381,10 @@
 	if (SRpnt->sr_device->scsi_level <= SCSI_2)
 		cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 	init_completion(&STp->wait);
-	SRpnt->sr_use_sg = (bytes > (STp->buffer)->frp[0].length);
+	SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length);
 	if (SRpnt->sr_use_sg) {
-		buf_to_sg(STp->buffer, bytes);
+		if (!STp->buffer->do_dio)
+			buf_to_sg(STp->buffer, bytes);
 		SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
 		bp = (char *) &((STp->buffer)->sg[0]);
 	} else
@@ -952,7 +972,8 @@
 		STps->rw = ST_IDLE;
 	}
 	STp->recover_count = 0;
-	DEB( STp->nbr_waits = STp->nbr_finished = 0; )
+	DEB( STp->nbr_waits = STp->nbr_finished = 0;
+	     STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
 
 	retval = check_tape(STp, filp);
 	if (retval < 0)
@@ -1014,6 +1035,10 @@
 		goto out;
 	}
 
+	DEBC( if (STp->nbr_requests)
+		printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
+		       dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
+
 	if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
 
                 DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
@@ -1126,7 +1151,6 @@
 /* The checks common to both reading and writing */
 static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t *ppos)
 {
-	int bufsize;
 	ssize_t retval = 0;
 
 	/*
@@ -1184,28 +1208,10 @@
 	    (retval = update_partition(STp)) < 0)
 		goto out;
 
-	if (STp->block_size == 0) {
-		if (STp->max_block > 0 &&
-		    (count < STp->min_block || count > STp->max_block)) {
-			retval = (-EINVAL);
-			goto out;
-		}
-		if (count > (STp->buffer)->buffer_size &&
-		    !enlarge_buffer(STp->buffer, count, STp->restr_dma)) {
-			retval = (-EOVERFLOW);
-			goto out;
-		}
-	}
-	else {
-		/* Fixed block mode with too small buffer? */
-		bufsize = STp->block_size > st_fixed_buffer_size ?
-			STp->block_size : st_fixed_buffer_size;
-		if ((STp->buffer)->buffer_size < bufsize &&
-		    !enlarge_buffer(STp->buffer, bufsize, STp->restr_dma)) {
-			retval = (-EOVERFLOW);
-			goto out;
-		}
-		(STp->buffer)->buffer_blocks = bufsize / STp->block_size;
+	if (STp->block_size == 0 && STp->max_block > 0 &&
+	    (count < STp->min_block || count > STp->max_block)) {
+		retval = (-EINVAL);
+		goto out;
 	}
 
 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
@@ -1217,6 +1223,60 @@
 }
 
 
+static int setup_buffering(Scsi_Tape *STp, const char *buf, size_t count, int is_read)
+{
+	int i, bufsize, retval = 0;
+	ST_buffer *STbp = STp->buffer;
+
+	if (is_read)
+		i = STp->try_dio && try_rdio;
+	else
+		i = STp->try_dio && try_wdio;
+	if (i) {
+		i = st_map_user_pages(&(STbp->sg[0]), STbp->use_sg,
+				      (unsigned long)buf, count, (is_read ? READ : WRITE),
+				      STp->max_pfn);
+		if (i > 0) {
+			STbp->do_dio = i;
+			STbp->buffer_bytes = 0;   /* can be used as transfer counter */
+		}
+		else
+			STbp->do_dio = FALSE;  /* fall back to buffering with any error */
+		STbp->sg_segs = STbp->do_dio;
+		STbp->frp_sg_current = 0;
+		DEB(
+		     if (STbp->do_dio) {
+			STp->nbr_dio++;
+			STp->nbr_pages += STbp->do_dio;
+			for (i=1; i < STbp->do_dio; i++)
+				if (page_to_pfn(STbp->sg[i].page) == page_to_pfn(STbp->sg[i-1].page) + 1)
+					STp->nbr_combinable++;
+		     }
+		)
+	} else
+		STbp->do_dio = FALSE;
+	DEB( STp->nbr_requests++; )
+
+	if (!STbp->do_dio) {
+		if (STp->block_size)
+			bufsize = STp->block_size > st_fixed_buffer_size ?
+				STp->block_size : st_fixed_buffer_size;
+		else
+			bufsize = count;
+		if (bufsize > STbp->buffer_size &&
+		    !enlarge_buffer(STbp, bufsize, STp->restr_dma)) {
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+		if (STp->block_size)
+			STbp->buffer_blocks = bufsize / STp->block_size;
+	}
+
+ out:
+	return retval;
+}
+
+
 /* Write command */
 static ssize_t
  st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
@@ -1312,12 +1372,17 @@
 	/* Check the buffer readability in cases where copy_user might catch
 	   the problems after some tape movement. */
 	if (STp->block_size != 0 &&
+	    !STbp->do_dio &&
 	    (copy_from_user(&i, buf, 1) != 0 ||
 	     copy_from_user(&i, buf + count - 1, 1) != 0)) {
 		retval = (-EFAULT);
 		goto out;
 	}
 
+	retval = setup_buffering(STp, buf, count, FALSE);
+	if (retval)
+		goto out;
+
 	total = count;
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -1329,31 +1394,38 @@
 	b_point = buf;
 	while (count > 0) {
 
-		if (STp->block_size == 0)
+		if (STbp->do_dio) {
 			do_count = count;
+		}
 		else {
-			do_count = STbp->buffer_blocks * STp->block_size -
-			    STbp->buffer_bytes;
-			if (do_count > count)
+			if (STp->block_size == 0)
 				do_count = count;
-		}
+			else {
+				do_count = STbp->buffer_blocks * STp->block_size -
+					STbp->buffer_bytes;
+				if (do_count > count)
+					do_count = count;
+			}
 
-		i = append_to_buffer(b_point, STbp, do_count);
-		if (i) {
-			retval = i;
-			goto out;
+			i = append_to_buffer(b_point, STbp, do_count);
+			if (i) {
+				retval = i;
+				goto out;
+			}
 		}
 		count -= do_count;
 		filp->f_pos += do_count;
 		b_point += do_count;
 
-		async_write = STm->do_async_writes && STps->eof < ST_EOM_OK;
+		async_write = !STbp->do_dio &&
+			STm->do_async_writes && STps->eof < ST_EOM_OK;
 		if (STp->block_size != 0)
 			async_write &= count == 0 &&
 				(!STm->do_buffer_writes ||
 				 STbp->buffer_bytes >= STp->write_threshold);
 
-		if (STp->block_size != 0 && STm->do_buffer_writes && STps->eof < ST_EOM_OK &&
+		if (STp->block_size != 0 && STm->do_buffer_writes &&
+		    !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK &&
 		    STbp->buffer_bytes < STbp->buffer_size) {
 			STp->dirty = TRUE;
 			/* Don't write a buffer that is not full enough. */
@@ -1364,8 +1436,9 @@
 		if (STp->block_size == 0)
 			blks = transfer = do_count;
 		else {
-			blks = STbp->buffer_bytes /
-			    STp->block_size;
+			if (!STbp->do_dio)
+				do_count = STbp->buffer_bytes;
+			blks = do_count / STp->block_size;
 			transfer = blks * STp->block_size;
 		}
 		cmd[2] = blks >> 16;
@@ -1467,6 +1540,11 @@
  out:
 	if (SRpnt != NULL)
 		scsi_release_request(SRpnt);
+	STbp = STp->buffer;
+	if (STbp->do_dio) {
+		sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, FALSE);
+		STbp->do_dio = 0;
+	}
 	up(&STp->lock);
 
 	return retval;
@@ -1482,6 +1560,7 @@
 	Scsi_Request *SRpnt;
 	ST_mode *STm;
 	ST_partstat *STps;
+	ST_buffer *STbp;
 	int dev = TAPE_NR(STp->devt);
 	int retval = 0;
 
@@ -1492,24 +1571,26 @@
 	STps = &(STp->ps[STp->partition]);
 	if (STps->eof == ST_FM_HIT)
 		return 1;
+	STbp = STp->buffer;
 
-	memset(cmd, 0, MAX_COMMAND_SIZE);
-	cmd[0] = READ_6;
-	cmd[1] = (STp->block_size != 0);
 	if (STp->block_size == 0)
 		blks = bytes = count;
 	else {
-		if (STm->do_read_ahead) {
+		if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) {
 			blks = (STp->buffer)->buffer_blocks;
 			bytes = blks * STp->block_size;
 		} else {
 			bytes = count;
-			if (bytes > (STp->buffer)->buffer_size)
+			if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size)
 				bytes = (STp->buffer)->buffer_size;
 			blks = bytes / STp->block_size;
 			bytes = blks * STp->block_size;
 		}
 	}
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = READ_6;
+	cmd[1] = (STp->block_size != 0);
 	cmd[2] = blks >> 16;
 	cmd[3] = blks >> 8;
 	cmd[4] = blks;
@@ -1519,13 +1600,13 @@
 			   STp->timeout, MAX_RETRIES, TRUE);
 	*aSRpnt = SRpnt;
 	if (!SRpnt)
-		return (STp->buffer)->syscall_result;
+		return STbp->syscall_result;
 
-	(STp->buffer)->read_pointer = 0;
+	STbp->read_pointer = 0;
 	STps->at_sm = 0;
 
 	/* Something to check */
-	if ((STp->buffer)->syscall_result) {
+	if (STbp->syscall_result) {
 		retval = 1;
 		DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
                             dev,
@@ -1558,7 +1639,7 @@
 								STps->drv_block += 1;
 							return (-ENOMEM);
 						}
-						(STp->buffer)->buffer_bytes = bytes - transfer;
+						STbp->buffer_bytes = bytes - transfer;
 					} else {
 						scsi_release_request(SRpnt);
 						SRpnt = *aSRpnt = NULL;
@@ -1570,11 +1651,11 @@
 							return (-EIO);
 						}
 						/* We have some data, deliver it */
-						(STp->buffer)->buffer_bytes = (blks - transfer) *
+						STbp->buffer_bytes = (blks - transfer) *
 						    STp->block_size;
                                                 DEBC(printk(ST_DEB_MSG
                                                             "st%d: ILI but enough data received %ld %d.\n",
-                                                            dev, count, (STp->buffer)->buffer_bytes));
+                                                            dev, count, STbp->buffer_bytes));
 						if (STps->drv_block >= 0)
 							STps->drv_block += 1;
 						if (st_int_ioctl(STp, MTBSR, 1))
@@ -1586,26 +1667,26 @@
 					else
 						STps->eof = ST_EOD_2;
 					if (STp->block_size == 0)
-						(STp->buffer)->buffer_bytes = 0;
+						STbp->buffer_bytes = 0;
 					else
-						(STp->buffer)->buffer_bytes =
+						STbp->buffer_bytes =
 						    bytes - transfer * STp->block_size;
                                         DEBC(printk(ST_DEB_MSG
                                                     "st%d: EOF detected (%d bytes read).\n",
-                                                    dev, (STp->buffer)->buffer_bytes));
+                                                    dev, STbp->buffer_bytes));
 				} else if (SRpnt->sr_sense_buffer[2] & 0x40) {
 					if (STps->eof == ST_FM)
 						STps->eof = ST_EOD_1;
 					else
 						STps->eof = ST_EOM_OK;
 					if (STp->block_size == 0)
-						(STp->buffer)->buffer_bytes = bytes - transfer;
+						STbp->buffer_bytes = bytes - transfer;
 					else
-						(STp->buffer)->buffer_bytes =
+						STbp->buffer_bytes =
 						    bytes - transfer * STp->block_size;
 
                                         DEBC(printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n",
-                                                    dev, (STp->buffer)->buffer_bytes));
+                                                    dev, STbp->buffer_bytes));
 				}
 			}
 			/* end of EOF, EOM, ILI test */ 
@@ -1625,19 +1706,19 @@
 		}
 		/* End of extended sense test */ 
 		else {		/* Non-extended sense */
-			retval = (STp->buffer)->syscall_result;
+			retval = STbp->syscall_result;
 		}
 
 	}
 	/* End of error handling */ 
 	else			/* Read successful */
-		(STp->buffer)->buffer_bytes = bytes;
+		STbp->buffer_bytes = bytes;
 
 	if (STps->drv_block >= 0) {
 		if (STp->block_size == 0)
 			STps->drv_block++;
 		else
-			STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size;
+			STps->drv_block += STbp->buffer_bytes / STp->block_size;
 	}
 	return retval;
 }
@@ -1656,11 +1737,13 @@
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
+	ST_buffer *STbp;
 	int dev = TAPE_NR(inode->i_rdev);
 
 	read_lock(&st_dev_arr_lock);
 	STp = scsi_tapes[dev];
 	read_unlock(&st_dev_arr_lock);
+	STbp = STp->buffer;
 
 	if (down_interruptible(&STp->lock))
 		return -ERESTARTSYS;
@@ -1686,10 +1769,14 @@
         DEB(
 	if (debugging && STps->eof != ST_NOEOF)
 		printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
-		       STps->eof, (STp->buffer)->buffer_bytes);
+		       STps->eof, STbp->buffer_bytes);
         ) /* end DEB */
 
-	if ((STp->buffer)->buffer_bytes == 0 &&
+	retval = setup_buffering(STp, buf, count, TRUE);
+	if (retval)
+		goto out;
+
+	if (STbp->buffer_bytes == 0 &&
 	    STps->eof >= ST_EOD_1) {
 		if (STps->eof < ST_EOD) {
 			STps->eof += 1;
@@ -1700,14 +1787,16 @@
 		goto out;
 	}
 
-	/* Check the buffer writability before any tape movement. Don't alter
-	   buffer data. */
-	if (copy_from_user(&i, buf, 1) != 0 ||
-	    copy_to_user(buf, &i, 1) != 0 ||
-	    copy_from_user(&i, buf + count - 1, 1) != 0 ||
-	    copy_to_user(buf + count - 1, &i, 1) != 0) {
-		retval = (-EFAULT);
-		goto out;
+	if (!STbp->do_dio) {
+		/* Check the buffer writability before any tape movement. Don't alter
+		   buffer data. */
+		if (copy_from_user(&i, buf, 1) != 0 ||
+		    copy_to_user(buf, &i, 1) != 0 ||
+		    copy_from_user(&i, buf + count - 1, 1) != 0 ||
+		    copy_to_user(buf + count - 1, &i, 1) != 0) {
+			retval = (-EFAULT);
+			goto out;
+		}
 	}
 
 	STps->rw = ST_READING;
@@ -1717,7 +1806,7 @@
 	for (total = 0, special = 0; total < count && !special;) {
 
 		/* Get new data if the buffer is empty */
-		if ((STp->buffer)->buffer_bytes == 0) {
+		if (STbp->buffer_bytes == 0) {
 			special = read_tape(STp, count - total, &SRpnt);
 			if (special < 0) {	/* No need to continue read */
 				retval = special;
@@ -1726,20 +1815,22 @@
 		}
 
 		/* Move the data from driver buffer to user buffer */
-		if ((STp->buffer)->buffer_bytes > 0) {
+		if (STbp->buffer_bytes > 0) {
                         DEB(
 			if (debugging && STps->eof != ST_NOEOF)
 				printk(ST_DEB_MSG
                                        "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
-				       STps->eof, (STp->buffer)->buffer_bytes,
+				       STps->eof, STbp->buffer_bytes,
                                        count - total);
                         ) /* end DEB */
-			transfer = (STp->buffer)->buffer_bytes < count - total ?
-			    (STp->buffer)->buffer_bytes : count - total;
-			i = from_buffer(STp->buffer, buf, transfer);
-			if (i) {
-				retval = i;
-				goto out;
+			transfer = STbp->buffer_bytes < count - total ?
+			    STbp->buffer_bytes : count - total;
+			if (!STbp->do_dio) {
+				i = from_buffer(STbp, buf, transfer);
+				if (i) {
+					retval = i;
+					goto out;
+				}
 			}
 			filp->f_pos += transfer;
 			buf += transfer;
@@ -1775,6 +1866,11 @@
 		scsi_release_request(SRpnt);
 		SRpnt = NULL;
 	}
+	if (STbp->do_dio) {
+		sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, TRUE);
+		STbp->do_dio = 0;
+		STbp->buffer_bytes = 0;
+	}
 	up(&STp->lock);
 
 	return retval;
@@ -3530,17 +3626,17 @@
 				   char *page, size_t count, loff_t off)
 {
 	kdev_t kdev; 
-	kdev.value=(int)driverfs_dev->driver_data;
+	kdev.value=(int)(long)driverfs_dev->driver_data;
 	return off ? 0 : sprintf(page, "%x\n",kdev.value);
 }
-static DEVICE_ATTR(kdev,"kdev",S_IRUGO,st_device_kdev_read,NULL);
+static DEVICE_ATTR(kdev,S_IRUGO,st_device_kdev_read,NULL);
 
 static ssize_t st_device_type_read(struct device *driverfs_dev, 
 				   char *page, size_t count, loff_t off) 
 {
 	return off ? 0 : sprintf (page, "CHR\n");
 }
-static DEVICE_ATTR(type,"type",S_IRUGO,st_device_type_read,NULL);
+static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL);
 
 
 static struct file_operations st_fops =
@@ -3562,6 +3658,7 @@
 	ST_buffer *buffer;
 	int i, mode, dev_num;
 	char *stp;
+	u64 bounce_limit;
 
 	if (SDp->type != TYPE_TAPE)
 		return 1;
@@ -3647,13 +3744,13 @@
 	    /*  Rewind entry  */
 	    sprintf (name, "mt%s", formats[mode]);
 	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
-		    SDp->sdev_driverfs_dev.name, name);
+		    SDp->sdev_driverfs_dev.bus_id, name);
 	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
 		    SDp->sdev_driverfs_dev.name, name);
 	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
 	    tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
 	    tpnt->driverfs_dev_r[mode].driver_data =
-			(void *)__mkdev(MAJOR_NR, i + (mode << 5));
+			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5));
 	    device_register(&tpnt->driverfs_dev_r[mode]);
 	    device_create_file(&tpnt->driverfs_dev_r[mode], 
 			       &dev_attr_type);
@@ -3666,13 +3763,13 @@
 	    /*  No-rewind entry  */
 	    sprintf (name, "mt%sn", formats[mode]);
 	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
-		    SDp->sdev_driverfs_dev.name, name);
+		    SDp->sdev_driverfs_dev.bus_id, name);
 	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
 		    SDp->sdev_driverfs_dev.name, name);
 	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
 	    tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
 	    tpnt->driverfs_dev_n[mode].driver_data =
-			(void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
+			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
 	    device_register(&tpnt->driverfs_dev_n[mode]);
 	    device_create_file(&tpnt->driverfs_dev_n[mode], 
 			       &dev_attr_type);
@@ -3716,6 +3813,23 @@
 	tpnt->timeout = ST_TIMEOUT;
 	tpnt->long_timeout = ST_LONG_TIMEOUT;
 
+	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) {
+		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 (SDp->host->unchecked_isa_dma)
+		bounce_limit = BLK_BOUNCE_ISA;
+	bounce_limit >>= PAGE_SHIFT;
+	if (bounce_limit > ULONG_MAX)
+		bounce_limit = ULONG_MAX;
+	tpnt->max_pfn = bounce_limit;
+
 	for (i = 0; i < ST_NBR_MODES; i++) {
 		STm = &(tpnt->modes[i]);
 		STm->defined = FALSE;
@@ -3751,6 +3865,8 @@
 	printk(KERN_WARNING
 	"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	       dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	printk(KERN_WARNING "st%d: try direct i/o: %s, max page reachable by HBA %lu\n",
+	       dev_num, tpnt->try_dio ? "yes" : "no", tpnt->max_pfn);
 
 	return 0;
 };
@@ -3779,7 +3895,7 @@
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
-						   &dev_attr_type);
+						   &dev_attr_kdev);
 				put_device(&tpnt->driverfs_dev_r[mode]);
 				devfs_unregister (tpnt->de_n[mode]);
 				tpnt->de_n[mode] = NULL;
@@ -3852,3 +3968,129 @@
 
 module_init(init_st);
 module_exit(exit_st);
+
+
+/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
+   - mapping of all pages not successful
+   - any page is above max_pfn
+   (i.e., either completely successful or fails)
+*/
+static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+			     unsigned long uaddr, size_t count, int rw,
+			     unsigned long max_pfn)
+{
+	int i, nr_pages;
+
+	nr_pages = sgl_map_user_pages(sgl, max_pages, uaddr, count, rw);
+	if (nr_pages <= 0)
+		return nr_pages;
+
+	for (i=0; i < nr_pages; i++) {
+		if (page_to_pfn(sgl[i].page) > max_pfn)
+			goto out_unmap;
+	}
+	return nr_pages;
+
+ out_unmap:
+	sgl_unmap_user_pages(sgl, nr_pages, FALSE);
+	return 0;
+}
+
+
+/* The following functions may be useful for a larger audience. */
+static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+			      unsigned long uaddr, size_t count, int rw)
+{
+	int res, i, j;
+	unsigned int nr_pages;
+	struct page **pages;
+
+	nr_pages = ((uaddr & ~PAGE_MASK) + count - 1 + ~PAGE_MASK) >> PAGE_SHIFT;
+
+	/* User attempted Overflow! */
+	if ((uaddr + count) < uaddr)
+		return -EINVAL;
+
+	/* Too big */
+        if (nr_pages > max_pages)
+		return -ENOMEM;
+
+	/* Hmm? */
+	if (count == 0)
+		return 0;
+
+	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+        /* Try to fault in all of the necessary pages */
+	down_read(&current->mm->mmap_sem);
+        /* rw==READ means read from drive, write into memory area */
+	res = get_user_pages(
+		current,
+		current->mm,
+		uaddr,
+		nr_pages,
+		rw == READ,
+		0, /* don't force */
+		pages,
+		NULL);
+	up_read(&current->mm->mmap_sem);
+
+	/* Errors and no page mapped should return here */
+	if (res < nr_pages)
+		goto out_unmap;
+
+        for (i=0; i < nr_pages; i++) {
+                /* FIXME: flush superflous for rw==READ,
+                 * probably wrong function for rw==WRITE
+                 */
+		flush_dcache_page(pages[i]);
+        }
+
+	/* Populate the scatter/gather list */
+	sgl[0].page = pages[0]; 
+	sgl[0].offset = uaddr & ~PAGE_MASK;
+	if (nr_pages > 1) {
+		sgl[0].length = PAGE_SIZE - sgl[0].offset;
+		count -= sgl[0].length;
+		for (i=1; i < nr_pages ; i++) {
+			sgl[i].offset = 0;
+			sgl[i].page = pages[i]; 
+			sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+			count -= PAGE_SIZE;
+		}
+	}
+	else {
+		sgl[0].length = count;
+	}
+
+	kfree(pages);
+	return nr_pages;
+
+ out_unmap:
+	if (res > 0) {
+		for (j=0; j < res; j++)
+			page_cache_release(pages[j]);
+	}
+	kfree(pages);
+	return res;
+}
+
+
+/* And unmap them... */
+static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
+				int dirtied)
+{
+	int i;
+
+	for (i=0; i < nr_pages; i++) {
+		if (dirtied && !PageReserved(sgl[i].page))
+			SetPageDirty(sgl[i].page);
+		/* FIXME: cache flush missing for rw==READ
+		 * FIXME: call the correct reference counting function
+		 */
+		page_cache_release(sgl[i].page);
+	}
+
+	return 0;
+}
diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h
--- a/drivers/scsi/st.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/scsi/st.h	Tue Aug 27 12:28:02 2002
@@ -12,6 +12,7 @@
 typedef struct {
 	unsigned char in_use;
 	unsigned char dma;	/* DMA-able buffer */
+	unsigned char do_dio;
 	int buffer_size;
 	int buffer_blocks;
 	int buffer_bytes;
@@ -21,7 +22,7 @@
 	int syscall_result;
 	Scsi_Request *last_SRpnt;
 	unsigned char *b_data;
-	unsigned short use_sg;	/* zero or maximum number of s/g segments for this adapter */
+	unsigned short use_sg;	/* zero or max number of s/g segments for this adapter */
 	unsigned short sg_segs;		/* number of segments in s/g list */
 	unsigned short orig_frp_segs;	/* number of segments allocated at first try */
 	unsigned short frp_segs;	/* number of buffer segments */
@@ -91,12 +92,15 @@
 	unsigned char cln_sense_value;
 	unsigned char cln_sense_mask;
 	unsigned char use_pf;			/* Set Page Format bit in all mode selects? */
+	unsigned char try_dio;			/* try direct i/o? */
 	unsigned char c_algo;			/* compression algorithm */
 	int tape_type;
 	int write_threshold;
 	int timeout;		/* timeout for normal commands */
 	int long_timeout;	/* timeout for commands known to take long time */
 
+	unsigned long max_pfn;	/* the maximum page number reachable by the HBA */
+
 	/* Mode characteristics */
 	ST_mode modes[ST_NBR_MODES];
 	int current_mode;
@@ -135,6 +139,10 @@
 	unsigned char write_pending;
 	int nbr_finished;
 	int nbr_waits;
+	int nbr_requests;
+	int nbr_dio;
+	int nbr_pages;
+	int nbr_combinable;
 	unsigned char last_cmnd[6];
 	unsigned char last_sense[16];
 #endif
diff -Nru a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h
--- a/drivers/scsi/st_options.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/scsi/st_options.h	Tue Aug 27 12:28:07 2002
@@ -1,14 +1,19 @@
 /*
    The compile-time configurable defaults for the Linux SCSI tape driver.
 
-   Copyright 1995-2000 Kai Makisara.
+   Copyright 1995-2002 Kai Makisara.
 
-   Last modified: Sun May  5 15:09:56 2002 by makisara
+   Last modified: Fri Jul 26 15:54:31 2002 by makisara
 */
 
 #ifndef _ST_OPTIONS_H
 #define _ST_OPTIONS_H
 
+/* If TRY_DIRECT_IO is non-zero, the driver tries to transfer data directly
+   between the user buffer and tape drive. If this is not possible, driver
+   buffer is used. If TRY_DIRECT_IO is zero, driver buffer is always used. */
+#define TRY_DIRECT_IO 1
+
 /* The driver does not wait for some operations to finish before returning
    to the user program if ST_NOWAIT is non-zero. This helps if the SCSI
    adapter does not support multiple outstanding commands. However, the user
@@ -40,7 +45,7 @@
 #define ST_WRITE_THRESHOLD_BLOCKS 30
 
 /* Maximum number of scatter/gather segments */
-#define ST_MAX_SG      64
+#define ST_MAX_SG      256
 
 /* The number of scatter/gather segments to allocate at first try (must be
    smaller or equal to the maximum). */
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Tue Aug 27 12:28:07 2002
@@ -1107,7 +1107,6 @@
 static int sym_eh_handler(int op, char *opname, Scsi_Cmnd *cmd)
 {
 	hcb_p np = SYM_SOFTC_PTR(cmd);
-	unsigned long flags;
 	SYM_QUEHEAD *qp;
 	int to_do = SYM_EH_DO_IGNORE;
 	int sts = -1;
@@ -1118,8 +1117,6 @@
 
 	printf_warning("%s: %s operation started.\n", devname, opname);
 
-	SYM_LOCK_HCB(np, flags);
-
 #if 0
 	/* This one should be the result of some race, thus to ignore */
 	if (cmd->serial_number != cmd->serial_number_at_timeout)
@@ -1197,8 +1194,6 @@
 	/* Complete the command with locks held as required by the driver */
 	if (to_do == SYM_EH_DO_COMPLETE)
 		sym_xpt_done2(np, cmd, CAM_REQ_ABORTED);
-
-	SYM_UNLOCK_HCB(np, flags);
 
 	/* Wait for completion with locks released, as required by kernel */
 	if (to_do == SYM_EH_DO_WAIT) {
diff -Nru a/drivers/usb/Config.in b/drivers/usb/Config.in
--- a/drivers/usb/Config.in	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/Config.in	Tue Aug 27 12:28:08 2002
@@ -33,12 +33,6 @@
 
    source drivers/usb/serial/Config.in
 
-   comment 'USB Miscellaneous drivers'
-   dep_tristate '  EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
-   dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
-   dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
-
+   source drivers/usb/misc/Config.in
 fi
 endmenu
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/Makefile	Tue Aug 27 12:28:08 2002
@@ -57,7 +57,9 @@
 obj-$(CONFIG_USB_AUERSWALD)	+= misc/
 obj-$(CONFIG_USB_BRLVGER)	+= misc/
 obj-$(CONFIG_USB_EMI26)		+= misc/
+obj-$(CONFIG_USB_LCD)		+= misc/
 obj-$(CONFIG_USB_RIO500)	+= misc/
+obj-$(CONFIG_USB_SPEEDTOUCH)	+= misc/
 obj-$(CONFIG_USB_TIGL)		+= misc/
 obj-$(CONFIG_USB_USS720)	+= misc/
 
diff -Nru a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
--- a/drivers/usb/class/Makefile	Tue Aug 27 12:28:05 2002
+++ b/drivers/usb/class/Makefile	Tue Aug 27 12:28:05 2002
@@ -7,7 +7,7 @@
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
-obj-$(CONFIG_USB_PRINTER)	+= printer.o
+obj-$(CONFIG_USB_PRINTER)	+= usblp.o
 
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
--- a/drivers/usb/class/printer.c	Tue Aug 27 12:28:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1130 +0,0 @@
-/*
- * printer.c  Version 0.12
- *
- * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
- * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
- * Copyright (c) 2000 Randy Dunlap	<randy.dunlap@intel.com>
- * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
- # Copyright (c) 2001 Pete Zaitcev	<zaitcev@redhat.com>
- # Copyright (c) 2001 David Paschal	<paschal@rcsis.com>
- *
- * USB Printer Device Class driver for USB printers and printer cables
- *
- * Sponsored by SuSE
- *
- * ChangeLog:
- *	v0.1 - thorough cleaning, URBification, almost a rewrite
- *	v0.2 - some more cleanups
- *	v0.3 - cleaner again, waitqueue fixes
- *	v0.4 - fixes in unidirectional mode
- *	v0.5 - add DEVICE_ID string support
- *	v0.6 - never time out
- *	v0.7 - fixed bulk-IN read and poll (David Paschal)
- *	v0.8 - add devfs support
- *	v0.9 - fix unplug-while-open paths
- *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
- *	v0.11 - add proto_bias option (Pete Zaitcev)
- *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/signal.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/lp.h>
-#include <linux/devfs_fs_kernel.h>
-#undef DEBUG
-#include <linux/usb.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.12"
-#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
-#define DRIVER_DESC "USB Printer Device Class driver"
-
-#define USBLP_BUF_SIZE		8192
-#define USBLP_DEVICE_ID_SIZE	1024
-
-/* ioctls: */
-#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
-#define IOCNR_GET_DEVICE_ID		1
-#define IOCNR_GET_PROTOCOLS		2
-#define IOCNR_SET_PROTOCOL		3
-#define IOCNR_HP_SET_CHANNEL		4
-#define IOCNR_GET_BUS_ADDRESS		5
-#define IOCNR_GET_VID_PID		6
-/* Get device_id string: */
-#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
-/* The following ioctls were added for http://hpoj.sourceforge.net: */
-/* Get two-int array:
- * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3),
- * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */
-#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
-/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */
-#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
-/* Set channel number (HP Vendor-specific command): */
-#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
-/* Get two-int array: [0]=bus number, [1]=device address: */
-#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
-/* Get two-int array: [0]=vendor ID, [1]=product ID: */
-#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
-
-/*
- * A DEVICE_ID string may include the printer's serial number.
- * It should end with a semi-colon (';').
- * An example from an HP 970C DeskJet printer is (this is one long string,
- * with the serial number changed):
-MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ:                    ;
- */
-
-/*
- * USB Printer Requests
- */
-
-#define USBLP_REQ_GET_ID			0x00
-#define USBLP_REQ_GET_STATUS			0x01
-#define USBLP_REQ_RESET				0x02
-#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define USBLP_MINORS		256
-#else
-#define USBLP_MINORS		16
-#endif
-#define USBLP_MINOR_BASE	0
-
-#define USBLP_WRITE_TIMEOUT	(5*HZ)			/* 5 seconds */
-
-#define USBLP_FIRST_PROTOCOL	1
-#define USBLP_LAST_PROTOCOL	3
-#define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
-
-struct usblp {
-	struct usb_device 	*dev;			/* USB device */
-	devfs_handle_t		devfs;			/* devfs device */
-	struct semaphore	sem;			/* locks this struct, especially "dev" */
-	char			*buf;		/* writeurb->transfer_buffer */
-	struct urb		*readurb, *writeurb;	/* The urbs */
-	wait_queue_head_t	wait;			/* Zzzzz ... */
-	int			readcount;		/* Counter for reads */
-	int			ifnum;			/* Interface number */
-	/* Alternate-setting numbers and endpoints for each protocol
-	 * (7/1/{index=1,2,3}) that the device supports: */
-	struct {
-		int				alt_setting;
-		struct usb_endpoint_descriptor	*epwrite;
-		struct usb_endpoint_descriptor	*epread;
-	}			protocol[USBLP_MAX_PROTOCOLS];
-	int			current_protocol;
-	int			minor;			/* minor number of device */
-	int			wcomplete;		/* writing is completed */
-	int			rcomplete;		/* reading is completed */
-	unsigned int		quirks;			/* quirks flags */
-	unsigned char		used;			/* True if open */
-	unsigned char		bidir;			/* interface is bidirectional */
-	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
-							/* first 2 bytes are (big-endian) length */
-};
-
-#ifdef DEBUG
-static void usblp_dump(struct usblp *usblp) {
-	int p;
-
-	dbg("usblp=0x%p", usblp);
-	dbg("dev=0x%p", usblp->dev);
-	dbg("devfs=0x%p", usblp->devfs);
-	dbg("buf=0x%p", usblp->buf);
-	dbg("readcount=%d", usblp->readcount);
-	dbg("ifnum=%d", usblp->ifnum);
-    for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
-	dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
-	dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
-	dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
-    }
-	dbg("current_protocol=%d", usblp->current_protocol);
-	dbg("minor=%d", usblp->minor);
-	dbg("wcomplete=%d", usblp->wcomplete);
-	dbg("rcomplete=%d", usblp->rcomplete);
-	dbg("quirks=%d", usblp->quirks);
-	dbg("used=%d", usblp->used);
-	dbg("bidir=%d", usblp->bidir);
-	dbg("device_id_string=\"%s\"",
-		usblp->device_id_string ?
-			usblp->device_id_string + 2 :
-			(unsigned char *)"(null)");
-}
-#endif
-
-extern devfs_handle_t usb_devfs_handle;			/* /dev/usb dir. */
-
-static struct usblp *usblp_table[USBLP_MINORS];
-
-/* Quirks: various printer quirks are handled by this table & its flags. */
-
-struct quirk_printer_struct {
-	__u16 vendorId;
-	__u16 productId;
-	unsigned int quirks;
-};
-
-#define USBLP_QUIRK_BIDIR	0x1	/* reports bidir but requires unidirectional mode (no INs/reads) */
-#define USBLP_QUIRK_USB_INIT	0x2	/* needs vendor USB init string */
-
-static struct quirk_printer_struct quirk_printers[] = {
-	{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
-	{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
-	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
-	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
-	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
-	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
-	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */   
-	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */   
-	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
-	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
-	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
-	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
-	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
-	{ 0, 0 }
-};
-
-static int usblp_select_alts(struct usblp *usblp);
-static int usblp_set_protocol(struct usblp *usblp, int protocol);
-static int usblp_cache_device_id_string(struct usblp *usblp);
-
-/* forward reference to make our lives easier */
-extern struct usb_driver usblp_driver;
-
-/*
- * Functions for usblp control messages.
- */
-
-static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
-{
-	int retval = usb_control_msg(usblp->dev,
-		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT);
-	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
-		request, !!dir, recip, value, len, retval);
-	return retval < 0 ? retval : 0;
-}
-
-#define usblp_read_status(usblp, status)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
-#define usblp_get_id(usblp, config, id, maxlen)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
-#define usblp_reset(usblp)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
-
-#define usblp_hp_channel_change_request(usblp, channel, buffer) \
-	usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1)
-
-/*
- * See the description for usblp_select_alts() below for the usage
- * explanation.  Look into your /proc/bus/usb/devices and dmesg in
- * case of any trouble.
- */
-static int proto_bias = -1;
-
-/*
- * URB callback.
- */
-
-static void usblp_bulk_read(struct urb *urb)
-{
-	struct usblp *usblp = urb->context;
-
-	if (!usblp || !usblp->dev || !usblp->used)
-		return;
-
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
-	usblp->rcomplete = 1;
-	wake_up_interruptible(&usblp->wait);
-}
-
-static void usblp_bulk_write(struct urb *urb)
-{
-	struct usblp *usblp = urb->context;
-
-	if (!usblp || !usblp->dev || !usblp->used)
-		return;
-
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
-	usblp->wcomplete = 1;
-	wake_up_interruptible(&usblp->wait);
-}
-
-/*
- * Get and print printer errors.
- */
-
-static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
-
-static int usblp_check_status(struct usblp *usblp, int err)
-{
-	unsigned char status, newerr = 0;
-	int error;
-
-	error = usblp_read_status (usblp, &status);
-	if (error < 0) {
-		err("usblp%d: error %d reading printer status",
-			usblp->minor, error);
-		return 0;
-	}
-
-	if (~status & LP_PERRORP) {
-		newerr = 3;
-		if (status & LP_POUTPA) newerr = 1;
-		if (~status & LP_PSELECD) newerr = 2;
-	}
-
-	if (newerr != err)
-		info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
-
-	return newerr;
-}
-
-/*
- * File op functions.
- */
-
-static int usblp_open(struct inode *inode, struct file *file)
-{
-	int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE;
-	struct usblp *usblp;
-	int retval;
-
-	if (minor < 0 || minor >= USBLP_MINORS)
-		return -ENODEV;
-
-	lock_kernel();
-	usblp  = usblp_table[minor];
-
-	retval = -ENODEV;
-	if (!usblp || !usblp->dev)
-		goto out;
-
-	retval = -EBUSY;
-	if (usblp->used)
-		goto out;
-
-	/*
-	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-	 * This is #if 0-ed because we *don't* want to fail an open
-	 * just because the printer is off-line.
-	 */
-#if 0
-	if ((retval = usblp_check_status(usblp, 0))) {
-		retval = retval > 1 ? -EIO : -ENOSPC;
-		goto out;
-	}
-#else
-	retval = 0;
-#endif
-
-	usblp->used = 1;
-	file->private_data = usblp;
-
-	usblp->writeurb->transfer_buffer_length = 0;
-	usblp->writeurb->status = 0;
-	usblp->wcomplete = 1; /* we begin writeable */
-	usblp->rcomplete = 0;
-
-	if (usblp->bidir) {
-		usblp->readcount = 0;
-		usblp->readurb->dev = usblp->dev;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
-			retval = -EIO;
-			usblp->used = 0;
-			file->private_data = NULL;
-		}
-	}
-out:
-	unlock_kernel();
-	return retval;
-}
-
-static void usblp_cleanup (struct usblp *usblp)
-{
-	devfs_unregister (usblp->devfs);
-	usblp_table [usblp->minor] = NULL;
-	usb_deregister_dev (1, usblp->minor);
-	info("usblp%d: removed", usblp->minor);
-
-	kfree (usblp->writeurb->transfer_buffer);
-	kfree (usblp->device_id_string);
-	usb_free_urb(usblp->writeurb);
-	usb_free_urb(usblp->readurb);
-	kfree (usblp);
-}
-
-static void usblp_unlink_urbs(struct usblp *usblp)
-{
-	usb_unlink_urb(usblp->writeurb);
-	if (usblp->bidir)
-		usb_unlink_urb(usblp->readurb);
-}
-
-static int usblp_release(struct inode *inode, struct file *file)
-{
-	struct usblp *usblp = file->private_data;
-
-	down (&usblp->sem);
-	lock_kernel();
-	usblp->used = 0;
-	if (usblp->dev) {
-		usblp_unlink_urbs(usblp);
-		up(&usblp->sem);
-	} else 		/* finish cleanup from disconnect */
-		usblp_cleanup (usblp);
-	unlock_kernel();
-	return 0;
-}
-
-/* No kernel lock - fine */
-static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct usblp *usblp = file->private_data;
-	poll_wait(file, &usblp->wait, wait);
- 	return ((!usblp->bidir || usblp->readurb->status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
- 			       | (usblp->writeurb->status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
-}
-
-static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct usblp *usblp = file->private_data;
-	int length, err, i;
-	unsigned char lpstatus, newChannel;
-	int status;
-	int twoints[2];
-	int retval = 0;
-
-	down (&usblp->sem);
-	if (!usblp->dev) {
-		retval = -ENODEV;
-		goto done;
-	}
-
-	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
-
-		switch (_IOC_NR(cmd)) {
-
-			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
-				if (_IOC_DIR(cmd) != _IOC_READ) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-				length = usblp_cache_device_id_string(usblp);
-				if (length < 0) {
-					retval = length;
-					goto done;
-				}
-				if (length > _IOC_SIZE(cmd))
-					length = _IOC_SIZE(cmd); /* truncate */
-
-				if (copy_to_user((unsigned char *) arg,
-						usblp->device_id_string,
-						(unsigned long) length)) {
-					retval = -EFAULT;
-					goto done;
-				}
-
-				break;
-
-			case IOCNR_GET_PROTOCOLS:
-				if (_IOC_DIR(cmd) != _IOC_READ ||
-				    _IOC_SIZE(cmd) < sizeof(twoints)) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-				twoints[0] = usblp->current_protocol;
-				twoints[1] = 0;
-				for (i = USBLP_FIRST_PROTOCOL;
-				     i <= USBLP_LAST_PROTOCOL; i++) {
-					if (usblp->protocol[i].alt_setting >= 0)
-						twoints[1] |= (1<<i);
-				}
-
-				if (copy_to_user((unsigned char *)arg,
-						(unsigned char *)twoints,
-						sizeof(twoints))) {
-					retval = -EFAULT;
-					goto done;
-				}
-
-				break;
-
-			case IOCNR_SET_PROTOCOL:
-				if (_IOC_DIR(cmd) != _IOC_WRITE) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-#ifdef DEBUG
-				if (arg == -10) {
-					usblp_dump(usblp);
-					break;
-				}
-#endif
-
-				usblp_unlink_urbs(usblp);
-				retval = usblp_set_protocol(usblp, arg);
-				if (retval < 0) {
-					usblp_set_protocol(usblp,
-						usblp->current_protocol);
-				}
-				break;
-
-			case IOCNR_HP_SET_CHANNEL:
-				if (_IOC_DIR(cmd) != _IOC_WRITE ||
-				    usblp->dev->descriptor.idVendor != 0x03F0 ||
-				    usblp->quirks & USBLP_QUIRK_BIDIR) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-				err = usblp_hp_channel_change_request(usblp,
-					arg, &newChannel);
-				if (err < 0) {
-					err("usblp%d: error = %d setting "
-						"HP channel",
-						usblp->minor, err);
-					retval = -EIO;
-					goto done;
-				}
-
-				dbg("usblp%d requested/got HP channel %ld/%d",
-					usblp->minor, arg, newChannel);
-				break;
-
-			case IOCNR_GET_BUS_ADDRESS:
-				if (_IOC_DIR(cmd) != _IOC_READ ||
-				    _IOC_SIZE(cmd) < sizeof(twoints)) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-				twoints[0] = usblp->dev->bus->busnum;
-				twoints[1] = usblp->dev->devnum;
-				if (copy_to_user((unsigned char *)arg,
-						(unsigned char *)twoints,
-						sizeof(twoints))) {
-					retval = -EFAULT;
-					goto done;
-				}
-
-				dbg("usblp%d is bus=%d, device=%d",
-					usblp->minor, twoints[0], twoints[1]);
-				break;
-
-			case IOCNR_GET_VID_PID:
-				if (_IOC_DIR(cmd) != _IOC_READ ||
-				    _IOC_SIZE(cmd) < sizeof(twoints)) {
-					retval = -EINVAL;
-					goto done;
-				}
-
-				twoints[0] = usblp->dev->descriptor.idVendor;
-				twoints[1] = usblp->dev->descriptor.idProduct;
-				if (copy_to_user((unsigned char *)arg,
-						(unsigned char *)twoints,
-						sizeof(twoints))) {
-					retval = -EFAULT;
-					goto done;
-				}
-
-				dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
-					usblp->minor, twoints[0], twoints[1]);
-				break;
-
-			default:
-				retval = -EINVAL;
-		}
-	else	/* old-style ioctl value */
-		switch (cmd) {
-
-			case LPGETSTATUS:
-				if (usblp_read_status(usblp, &lpstatus)) {
-					err("usblp%d: failed reading printer status", usblp->minor);
-					retval = -EIO;
-					goto done;
-				}
-				status = lpstatus;
-				if (copy_to_user ((int *)arg, &status, sizeof(int)))
-					retval = -EFAULT;
-				break;
-
-			default:
-				retval = -EINVAL;
-		}
-
-done:
-	up (&usblp->sem);
-	return retval;
-}
-
-static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	struct usblp *usblp = file->private_data;
-	int timeout, err = 0, writecount = 0;
-
-	while (writecount < count) {
-		if (!usblp->wcomplete) {
-			barrier();
-			if (file->f_flags & O_NONBLOCK)
-				return -EAGAIN;
-
-			timeout = USBLP_WRITE_TIMEOUT;
-			add_wait_queue(&usblp->wait, &wait);
-			while ( 1==1 ) {
-
-				if (signal_pending(current)) {
-					remove_wait_queue(&usblp->wait, &wait);
-					return writecount ? writecount : -EINTR;
-				}
-				set_current_state(TASK_INTERRUPTIBLE);
-				if (timeout && !usblp->wcomplete) {
-					timeout = schedule_timeout(timeout);
-				} else {
-					set_current_state(TASK_RUNNING);
-					break;
-				}
-			}
-			remove_wait_queue(&usblp->wait, &wait);
-		}
-
-		down (&usblp->sem);
-		if (!usblp->dev) {
-			up (&usblp->sem);
-			return -ENODEV;
-		}
-
-		if (usblp->writeurb->status != 0) {
-			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-				if (!usblp->wcomplete)
-					err("usblp%d: error %d writing to printer",
-						usblp->minor, usblp->writeurb->status);
-				err = usblp->writeurb->status;
-			} else
-				err = usblp_check_status(usblp, err);
-			up (&usblp->sem);
-
-			/* if the fault was due to disconnect, let khubd's
-			 * call to usblp_disconnect() grab usblp->sem ...
-			 */
-			schedule ();
-			continue;
-		}
-
-		writecount += usblp->writeurb->transfer_buffer_length;
-		usblp->writeurb->transfer_buffer_length = 0;
-
-		if (writecount == count) {
-			up (&usblp->sem);
-			break;
-		}
-
-		usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
-							  (count - writecount) : USBLP_BUF_SIZE;
-
-		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
-				usblp->writeurb->transfer_buffer_length)) {
-			up(&usblp->sem);
-			return writecount ? writecount : -EFAULT;
-		}
-
-		usblp->writeurb->dev = usblp->dev;
-		usblp->wcomplete = 0;
-		if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
-			count = -EIO;
-			up (&usblp->sem);
-			break;
-		}
-		up (&usblp->sem);
-	}
-
-	return count;
-}
-
-static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
-	struct usblp *usblp = file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-
-	if (!usblp->bidir)
-		return -EINVAL;
-
-	down (&usblp->sem);
-	if (!usblp->dev) {
-		count = -ENODEV;
-		goto done;
-	}
-
-	if (!usblp->rcomplete) {
-		barrier();
-
-		if (file->f_flags & O_NONBLOCK) {
-			count = -EAGAIN;
-			goto done;
-		}
-
-		// FIXME:  only use urb->status inside completion
-		// callbacks; this way is racey...
-		add_wait_queue(&usblp->wait, &wait);
-		while (1==1) {
-			if (signal_pending(current)) {
-				count = -EINTR;
-				remove_wait_queue(&usblp->wait, &wait);
-				goto done;
-			}
-			up (&usblp->sem);
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (!usblp->rcomplete) {
-				schedule();
-			} else {
-				set_current_state(TASK_RUNNING);
-				break;
-			}
-			down (&usblp->sem);
-		}
-		remove_wait_queue(&usblp->wait, &wait);
-	}
-
-	if (!usblp->dev) {
-		count = -ENODEV;
-		goto done;
-	}
-
-	if (usblp->readurb->status) {
-		err("usblp%d: error %d reading from printer",
-			usblp->minor, usblp->readurb->status);
-		usblp->readurb->dev = usblp->dev;
- 		usblp->readcount = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
-			dbg("error submitting urb"); 
-		count = -EIO;
-		goto done;
-	}
-
-	count = count < usblp->readurb->actual_length - usblp->readcount ?
-		count :	usblp->readurb->actual_length - usblp->readcount;
-
-	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
-		count = -EFAULT;
-		goto done;
-	}
-
-	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
-		usblp->readcount = 0;
-		usblp->readurb->dev = usblp->dev;
-		usblp->rcomplete = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
-			count = -EIO;
-			goto done;
-		}
-	}
-
-done:
-	up (&usblp->sem);
-	return count;
-}
-
-/*
- * Checks for printers that have quirks, such as requiring unidirectional
- * communication but reporting bidirectional; currently some HP printers
- * have this flaw (HP 810, 880, 895, etc.), or needing an init string
- * sent at each open (like some Epsons).
- * Returns 1 if found, 0 if not found.
- *
- * HP recommended that we use the bidirectional interface but
- * don't attempt any bulk IN transfers from the IN endpoint.
- * Here's some more detail on the problem:
- * The problem is not that it isn't bidirectional though. The problem
- * is that if you request a device ID, or status information, while
- * the buffers are full, the return data will end up in the print data
- * buffer. For example if you make sure you never request the device ID
- * while you are sending print data, and you don't try to query the
- * printer status every couple of milliseconds, you will probably be OK.
- */
-static unsigned int usblp_quirks (__u16 vendor, __u16 product)
-{
-	int i;
-
-	for (i = 0; quirk_printers[i].vendorId; i++) {
-		if (vendor == quirk_printers[i].vendorId &&
-		    product == quirk_printers[i].productId)
-			return quirk_printers[i].quirks;
- 	}
-	return 0;
-}
-
-static struct file_operations usblp_fops = {
-	.owner =	THIS_MODULE,
-	.read =		usblp_read,
-	.write =	usblp_write,
-	.poll =		usblp_poll,
-	.ioctl =	usblp_ioctl,
-	.open =		usblp_open,
-	.release =	usblp_release,
-};
-
-static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
-			 const struct usb_device_id *id)
-{
-	struct usblp *usblp = 0;
-	int protocol;
-	int retval;
-	char name[6];
-
-	/* Malloc and start initializing usblp structure so we can use it
-	 * directly. */
-	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
-		err("out of memory for usblp");
-		goto abort;
-	}
-	memset(usblp, 0, sizeof(struct usblp));
-	usblp->dev = dev;
-	init_MUTEX (&usblp->sem);
-	init_waitqueue_head(&usblp->wait);
-	usblp->ifnum = ifnum;
-
-	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
-	if (retval) {
-		err("Not able to get a minor for this device.");
-		goto abort;
-	}
-
-	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usblp->writeurb) {
-		err("out of memory");
-		goto abort_minor;
-	}
-	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usblp->readurb) {
-		err("out of memory");
-		goto abort_minor;
-	}
-
-	/* Malloc device ID string buffer to the largest expected length,
-	 * since we can re-query it on an ioctl and a dynamic string
-	 * could change in length. */
-	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
-		err("out of memory for device_id_string");
-		goto abort_minor;
-	}
-
-	/* Malloc write/read buffers in one chunk.  We somewhat wastefully
-	 * malloc both regardless of bidirectionality, because the
-	 * alternate setting can be changed later via an ioctl. */
-	if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
-		err("out of memory for buf");
-		goto abort_minor;
-	}
-
-	/* Lookup quirks for this printer. */
-	usblp->quirks = usblp_quirks(
-		dev->descriptor.idVendor,
-		dev->descriptor.idProduct);
-
-	/* Analyze and pick initial alternate settings and endpoints. */
-	protocol = usblp_select_alts(usblp);
-	if (protocol < 0) {
-		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
-			dev->descriptor.idVendor,
-			dev->descriptor.idProduct);
-		goto abort_minor;
-	}
-
-	/* Setup the selected alternate setting and endpoints. */
-	if (usblp_set_protocol(usblp, protocol) < 0)
-		goto abort_minor;
-
-	/* Retrieve and store the device ID string. */
-	usblp_cache_device_id_string(usblp);
-
-#ifdef DEBUG
-	usblp_check_status(usblp, 0);
-#endif
-
-	/* add a table entry so the device works when advertised */
-	usblp_table[usblp->minor] = usblp;
-
-	/* If we have devfs, create with perms=660. */
-	sprintf(name, "lp%d", usblp->minor);
-	usblp->devfs = devfs_register(usb_devfs_handle, name,
-				      DEVFS_FL_DEFAULT, USB_MAJOR,
-				      USBLP_MINOR_BASE + usblp->minor,
-				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-				      S_IWGRP, &usblp_fops, NULL);
-
-	info("usblp%d: USB %sdirectional printer dev %d "
-		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
-		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum,
-		usblp->protocol[usblp->current_protocol].alt_setting,
-		usblp->current_protocol, usblp->dev->descriptor.idVendor,
-		usblp->dev->descriptor.idProduct);
-
-	return usblp;
-
-abort_minor:
-	usb_deregister_dev (1, usblp->minor);
-abort:
-	if (usblp) {
-		usb_free_urb(usblp->writeurb);
-		usb_free_urb(usblp->readurb);
-		if (usblp->buf) kfree(usblp->buf);
-		if (usblp->device_id_string) kfree(usblp->device_id_string);
-		kfree(usblp);
-	}
-	return NULL;
-}
-
-/*
- * We are a "new" style driver with usb_device_id table,
- * but our requirements are too intricate for simple match to handle.
- *
- * The "proto_bias" option may be used to specify the preferred protocol
- * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3).  If the device
- * supports the preferred protocol, then we bind to it.
- *
- * The best interface for us is 7/1/2, because it is compatible
- * with a stream of characters. If we find it, we bind to it.
- *
- * Note that the people from hpoj.sourceforge.net need to be able to
- * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose.
- *
- * Failing 7/1/2, we look for 7/1/3, even though it's probably not
- * stream-compatible, because this matches the behaviour of the old code.
- *
- * If nothing else, we bind to 7/1/1 - the unidirectional interface.
- */
-static int usblp_select_alts(struct usblp *usblp)
-{
-	struct usb_interface *if_alt;
-	struct usb_interface_descriptor *ifd;
-	struct usb_endpoint_descriptor *epd, *epwrite, *epread;
-	int p, i, e;
-
-	if_alt = &usblp->dev->actconfig->interface[usblp->ifnum];
-
-	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
-		usblp->protocol[p].alt_setting = -1;
-
-	/* Find out what we have. */
-	for (i = 0; i < if_alt->num_altsetting; i++) {
-		ifd = &if_alt->altsetting[i];
-
-		if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1)
-			continue;
-
-		if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL ||
-		    ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL)
-			continue;
-
-		/* Look for bulk OUT and IN endpoints. */
-		epwrite = epread = 0;
-		for (e = 0; e < ifd->bNumEndpoints; e++) {
-			epd = &ifd->endpoint[e];
-
-			if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
-			    USB_ENDPOINT_XFER_BULK)
-				continue;
-
-			if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
-				if (!epwrite) epwrite=epd;
-
-			} else {
-				if (!epread) epread=epd;
-			}
-		}
-
-		/* Ignore buggy hardware without the right endpoints. */
-		if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread))
-			continue;
-
-		/* Turn off reads for 7/1/1 (unidirectional) interfaces
-		 * and buggy bidirectional printers. */
-		if (ifd->bInterfaceProtocol == 1) {
-			epread = NULL;
-		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-			info("Disabling reads from problem bidirectional "
-				"printer on usblp%d", usblp->minor);
-			epread = NULL;
-		}
-
-		usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i;
-		usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite;
-		usblp->protocol[ifd->bInterfaceProtocol].epread = epread;
-	}
-
-	/* If our requested protocol is supported, then use it. */
-	if (proto_bias >= USBLP_FIRST_PROTOCOL &&
-	    proto_bias <= USBLP_LAST_PROTOCOL &&
-	    usblp->protocol[proto_bias].alt_setting != -1)
-		return proto_bias;
-
-	/* Ordering is important here. */
-	if (usblp->protocol[2].alt_setting != -1) return 2;
-	if (usblp->protocol[1].alt_setting != -1) return 1;
-	if (usblp->protocol[3].alt_setting != -1) return 3;
-
-	/* If nothing is available, then don't bind to this device. */
-	return -1;
-}
-
-static int usblp_set_protocol(struct usblp *usblp, int protocol)
-{
-	int r, alts;
-
-	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
-		return -EINVAL;
-
-	alts = usblp->protocol[protocol].alt_setting;
-	if (alts < 0) return -EINVAL;
-	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
-	if (r < 0) {
-		err("can't set desired altsetting %d on interface %d",
-			alts, usblp->ifnum);
-		return r;
-	}
-
-	FILL_BULK_URB(usblp->writeurb, usblp->dev,
-		usb_sndbulkpipe(usblp->dev,
-		 usblp->protocol[protocol].epwrite->bEndpointAddress),
-		usblp->buf, 0,
-		usblp_bulk_write, usblp);
-
-	usblp->bidir = (usblp->protocol[protocol].epread != 0);
-	if (usblp->bidir)
-		FILL_BULK_URB(usblp->readurb, usblp->dev,
-			usb_rcvbulkpipe(usblp->dev,
-			 usblp->protocol[protocol].epread->bEndpointAddress),
-			usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE,
-			usblp_bulk_read, usblp);
-
-	usblp->current_protocol = protocol;
-	dbg("usblp%d set protocol %d", usblp->minor, protocol);
-	return 0;
-}
-
-/* Retrieves and caches device ID string.
- * Returns length, including length bytes but not null terminator.
- * On error, returns a negative errno value. */
-static int usblp_cache_device_id_string(struct usblp *usblp)
-{
-	int err, length;
-
-	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
-	if (err < 0) {
-		dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
-			usblp->minor, err);
-		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
-		return -EIO;
-	}
-
-	/* First two bytes are length in big-endian.
-	 * They count themselves, and we copy them into
-	 * the user's buffer. */
-	length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1];
-	if (length < 2)
-		length = 2;
-	else if (length >= USBLP_DEVICE_ID_SIZE)
-		length = USBLP_DEVICE_ID_SIZE - 1;
-	usblp->device_id_string[length] = '\0';
-
-	dbg("usblp%d Device ID string [len=%d]=\"%s\"",
-		usblp->minor, length, &usblp->device_id_string[2]);
-
-	return length;
-}
-
-static void usblp_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct usblp *usblp = ptr;
-
-	if (!usblp || !usblp->dev) {
-		err("bogus disconnect");
-		BUG ();
-	}
-
-	down (&usblp->sem);
-	lock_kernel();
-	usblp->dev = NULL;
-
-	usblp_unlink_urbs(usblp);
-
-	if (!usblp->used)
-		usblp_cleanup (usblp);
-	else 	/* cleanup later, on close */
-		up (&usblp->sem);
-	unlock_kernel();
-}
-
-static struct usb_device_id usblp_ids [] = {
-	{ USB_DEVICE_INFO(7, 1, 1) },
-	{ USB_DEVICE_INFO(7, 1, 2) },
-	{ USB_DEVICE_INFO(7, 1, 3) },
-	{ USB_INTERFACE_INFO(7, 1, 1) },
-	{ USB_INTERFACE_INFO(7, 1, 2) },
-	{ USB_INTERFACE_INFO(7, 1, 3) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usblp_ids);
-
-static struct usb_driver usblp_driver = {
-	.owner =	THIS_MODULE,
-	.name =		"usblp",
-	.probe =	usblp_probe,
-	.disconnect =	usblp_disconnect,
-	.id_table =	usblp_ids,
-};
-
-static int __init usblp_init(void)
-{
-	if (usb_register(&usblp_driver))
-		return -1;
-	info(DRIVER_VERSION ": " DRIVER_DESC);
-	return 0;
-}
-
-static void __exit usblp_exit(void)
-{
-	usb_deregister(&usblp_driver);
-}
-
-module_init(usblp_init);
-module_exit(usblp_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_PARM(proto_bias, "i");
-MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/class/usblp.c	Tue Aug 27 12:28:01 2002
@@ -0,0 +1,1130 @@
+/*
+ * usblp.c  Version 0.12
+ *
+ * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
+ * Copyright (c) 2000 Randy Dunlap	<randy.dunlap@intel.com>
+ * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ # Copyright (c) 2001 Pete Zaitcev	<zaitcev@redhat.com>
+ # Copyright (c) 2001 David Paschal	<paschal@rcsis.com>
+ *
+ * USB Printer Device Class driver for USB printers and printer cables
+ *
+ * Sponsored by SuSE
+ *
+ * ChangeLog:
+ *	v0.1 - thorough cleaning, URBification, almost a rewrite
+ *	v0.2 - some more cleanups
+ *	v0.3 - cleaner again, waitqueue fixes
+ *	v0.4 - fixes in unidirectional mode
+ *	v0.5 - add DEVICE_ID string support
+ *	v0.6 - never time out
+ *	v0.7 - fixed bulk-IN read and poll (David Paschal)
+ *	v0.8 - add devfs support
+ *	v0.9 - fix unplug-while-open paths
+ *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
+ *	v0.11 - add proto_bias option (Pete Zaitcev)
+ *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/lp.h>
+#include <linux/devfs_fs_kernel.h>
+#undef DEBUG
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.12"
+#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
+#define DRIVER_DESC "USB Printer Device Class driver"
+
+#define USBLP_BUF_SIZE		8192
+#define USBLP_DEVICE_ID_SIZE	1024
+
+/* ioctls: */
+#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
+#define IOCNR_GET_DEVICE_ID		1
+#define IOCNR_GET_PROTOCOLS		2
+#define IOCNR_SET_PROTOCOL		3
+#define IOCNR_HP_SET_CHANNEL		4
+#define IOCNR_GET_BUS_ADDRESS		5
+#define IOCNR_GET_VID_PID		6
+/* Get device_id string: */
+#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
+/* The following ioctls were added for http://hpoj.sourceforge.net: */
+/* Get two-int array:
+ * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3),
+ * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */
+#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
+/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */
+#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
+/* Set channel number (HP Vendor-specific command): */
+#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
+/* Get two-int array: [0]=bus number, [1]=device address: */
+#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
+/* Get two-int array: [0]=vendor ID, [1]=product ID: */
+#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
+
+/*
+ * A DEVICE_ID string may include the printer's serial number.
+ * It should end with a semi-colon (';').
+ * An example from an HP 970C DeskJet printer is (this is one long string,
+ * with the serial number changed):
+MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ:                    ;
+ */
+
+/*
+ * USB Printer Requests
+ */
+
+#define USBLP_REQ_GET_ID			0x00
+#define USBLP_REQ_GET_STATUS			0x01
+#define USBLP_REQ_RESET				0x02
+#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define USBLP_MINORS		256
+#else
+#define USBLP_MINORS		16
+#endif
+#define USBLP_MINOR_BASE	0
+
+#define USBLP_WRITE_TIMEOUT	(5*HZ)			/* 5 seconds */
+
+#define USBLP_FIRST_PROTOCOL	1
+#define USBLP_LAST_PROTOCOL	3
+#define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
+
+struct usblp {
+	struct usb_device 	*dev;			/* USB device */
+	devfs_handle_t		devfs;			/* devfs device */
+	struct semaphore	sem;			/* locks this struct, especially "dev" */
+	char			*buf;		/* writeurb->transfer_buffer */
+	struct urb		*readurb, *writeurb;	/* The urbs */
+	wait_queue_head_t	wait;			/* Zzzzz ... */
+	int			readcount;		/* Counter for reads */
+	int			ifnum;			/* Interface number */
+	/* Alternate-setting numbers and endpoints for each protocol
+	 * (7/1/{index=1,2,3}) that the device supports: */
+	struct {
+		int				alt_setting;
+		struct usb_endpoint_descriptor	*epwrite;
+		struct usb_endpoint_descriptor	*epread;
+	}			protocol[USBLP_MAX_PROTOCOLS];
+	int			current_protocol;
+	int			minor;			/* minor number of device */
+	int			wcomplete;		/* writing is completed */
+	int			rcomplete;		/* reading is completed */
+	unsigned int		quirks;			/* quirks flags */
+	unsigned char		used;			/* True if open */
+	unsigned char		bidir;			/* interface is bidirectional */
+	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
+							/* first 2 bytes are (big-endian) length */
+};
+
+#ifdef DEBUG
+static void usblp_dump(struct usblp *usblp) {
+	int p;
+
+	dbg("usblp=0x%p", usblp);
+	dbg("dev=0x%p", usblp->dev);
+	dbg("devfs=0x%p", usblp->devfs);
+	dbg("buf=0x%p", usblp->buf);
+	dbg("readcount=%d", usblp->readcount);
+	dbg("ifnum=%d", usblp->ifnum);
+    for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
+	dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
+	dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
+	dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
+    }
+	dbg("current_protocol=%d", usblp->current_protocol);
+	dbg("minor=%d", usblp->minor);
+	dbg("wcomplete=%d", usblp->wcomplete);
+	dbg("rcomplete=%d", usblp->rcomplete);
+	dbg("quirks=%d", usblp->quirks);
+	dbg("used=%d", usblp->used);
+	dbg("bidir=%d", usblp->bidir);
+	dbg("device_id_string=\"%s\"",
+		usblp->device_id_string ?
+			usblp->device_id_string + 2 :
+			(unsigned char *)"(null)");
+}
+#endif
+
+extern devfs_handle_t usb_devfs_handle;			/* /dev/usb dir. */
+
+static struct usblp *usblp_table[USBLP_MINORS];
+
+/* Quirks: various printer quirks are handled by this table & its flags. */
+
+struct quirk_printer_struct {
+	__u16 vendorId;
+	__u16 productId;
+	unsigned int quirks;
+};
+
+#define USBLP_QUIRK_BIDIR	0x1	/* reports bidir but requires unidirectional mode (no INs/reads) */
+#define USBLP_QUIRK_USB_INIT	0x2	/* needs vendor USB init string */
+
+static struct quirk_printer_struct quirk_printers[] = {
+	{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
+	{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
+	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
+	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
+	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
+	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */   
+	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */   
+	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
+	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
+	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
+	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
+	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
+	{ 0, 0 }
+};
+
+static int usblp_select_alts(struct usblp *usblp);
+static int usblp_set_protocol(struct usblp *usblp, int protocol);
+static int usblp_cache_device_id_string(struct usblp *usblp);
+
+/* forward reference to make our lives easier */
+extern struct usb_driver usblp_driver;
+
+/*
+ * Functions for usblp control messages.
+ */
+
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
+{
+	int retval = usb_control_msg(usblp->dev,
+		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
+		request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT);
+	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
+		request, !!dir, recip, value, len, retval);
+	return retval < 0 ? retval : 0;
+}
+
+#define usblp_read_status(usblp, status)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
+#define usblp_get_id(usblp, config, id, maxlen)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
+#define usblp_reset(usblp)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
+
+#define usblp_hp_channel_change_request(usblp, channel, buffer) \
+	usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1)
+
+/*
+ * See the description for usblp_select_alts() below for the usage
+ * explanation.  Look into your /proc/bus/usb/devices and dmesg in
+ * case of any trouble.
+ */
+static int proto_bias = -1;
+
+/*
+ * URB callback.
+ */
+
+static void usblp_bulk_read(struct urb *urb)
+{
+	struct usblp *usblp = urb->context;
+
+	if (!usblp || !usblp->dev || !usblp->used)
+		return;
+
+	if (unlikely(urb->status))
+		warn("usblp%d: nonzero read/write bulk status received: %d",
+			usblp->minor, urb->status);
+	usblp->rcomplete = 1;
+	wake_up_interruptible(&usblp->wait);
+}
+
+static void usblp_bulk_write(struct urb *urb)
+{
+	struct usblp *usblp = urb->context;
+
+	if (!usblp || !usblp->dev || !usblp->used)
+		return;
+
+	if (unlikely(urb->status))
+		warn("usblp%d: nonzero read/write bulk status received: %d",
+			usblp->minor, urb->status);
+	usblp->wcomplete = 1;
+	wake_up_interruptible(&usblp->wait);
+}
+
+/*
+ * Get and print printer errors.
+ */
+
+static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
+
+static int usblp_check_status(struct usblp *usblp, int err)
+{
+	unsigned char status, newerr = 0;
+	int error;
+
+	error = usblp_read_status (usblp, &status);
+	if (error < 0) {
+		err("usblp%d: error %d reading printer status",
+			usblp->minor, error);
+		return 0;
+	}
+
+	if (~status & LP_PERRORP) {
+		newerr = 3;
+		if (status & LP_POUTPA) newerr = 1;
+		if (~status & LP_PSELECD) newerr = 2;
+	}
+
+	if (newerr != err)
+		info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
+
+	return newerr;
+}
+
+/*
+ * File op functions.
+ */
+
+static int usblp_open(struct inode *inode, struct file *file)
+{
+	int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE;
+	struct usblp *usblp;
+	int retval;
+
+	if (minor < 0 || minor >= USBLP_MINORS)
+		return -ENODEV;
+
+	lock_kernel();
+	usblp  = usblp_table[minor];
+
+	retval = -ENODEV;
+	if (!usblp || !usblp->dev)
+		goto out;
+
+	retval = -EBUSY;
+	if (usblp->used)
+		goto out;
+
+	/*
+	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
+	 * This is #if 0-ed because we *don't* want to fail an open
+	 * just because the printer is off-line.
+	 */
+#if 0
+	if ((retval = usblp_check_status(usblp, 0))) {
+		retval = retval > 1 ? -EIO : -ENOSPC;
+		goto out;
+	}
+#else
+	retval = 0;
+#endif
+
+	usblp->used = 1;
+	file->private_data = usblp;
+
+	usblp->writeurb->transfer_buffer_length = 0;
+	usblp->writeurb->status = 0;
+	usblp->wcomplete = 1; /* we begin writeable */
+	usblp->rcomplete = 0;
+
+	if (usblp->bidir) {
+		usblp->readcount = 0;
+		usblp->readurb->dev = usblp->dev;
+		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
+			retval = -EIO;
+			usblp->used = 0;
+			file->private_data = NULL;
+		}
+	}
+out:
+	unlock_kernel();
+	return retval;
+}
+
+static void usblp_cleanup (struct usblp *usblp)
+{
+	devfs_unregister (usblp->devfs);
+	usblp_table [usblp->minor] = NULL;
+	usb_deregister_dev (1, usblp->minor);
+	info("usblp%d: removed", usblp->minor);
+
+	kfree (usblp->writeurb->transfer_buffer);
+	kfree (usblp->device_id_string);
+	usb_free_urb(usblp->writeurb);
+	usb_free_urb(usblp->readurb);
+	kfree (usblp);
+}
+
+static void usblp_unlink_urbs(struct usblp *usblp)
+{
+	usb_unlink_urb(usblp->writeurb);
+	if (usblp->bidir)
+		usb_unlink_urb(usblp->readurb);
+}
+
+static int usblp_release(struct inode *inode, struct file *file)
+{
+	struct usblp *usblp = file->private_data;
+
+	down (&usblp->sem);
+	lock_kernel();
+	usblp->used = 0;
+	if (usblp->dev) {
+		usblp_unlink_urbs(usblp);
+		up(&usblp->sem);
+	} else 		/* finish cleanup from disconnect */
+		usblp_cleanup (usblp);
+	unlock_kernel();
+	return 0;
+}
+
+/* No kernel lock - fine */
+static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usblp *usblp = file->private_data;
+	poll_wait(file, &usblp->wait, wait);
+ 	return ((!usblp->bidir || usblp->readurb->status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
+ 			       | (usblp->writeurb->status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
+}
+
+static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usblp *usblp = file->private_data;
+	int length, err, i;
+	unsigned char lpstatus, newChannel;
+	int status;
+	int twoints[2];
+	int retval = 0;
+
+	down (&usblp->sem);
+	if (!usblp->dev) {
+		retval = -ENODEV;
+		goto done;
+	}
+
+	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
+
+		switch (_IOC_NR(cmd)) {
+
+			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
+				if (_IOC_DIR(cmd) != _IOC_READ) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				length = usblp_cache_device_id_string(usblp);
+				if (length < 0) {
+					retval = length;
+					goto done;
+				}
+				if (length > _IOC_SIZE(cmd))
+					length = _IOC_SIZE(cmd); /* truncate */
+
+				if (copy_to_user((unsigned char *) arg,
+						usblp->device_id_string,
+						(unsigned long) length)) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				break;
+
+			case IOCNR_GET_PROTOCOLS:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				twoints[0] = usblp->current_protocol;
+				twoints[1] = 0;
+				for (i = USBLP_FIRST_PROTOCOL;
+				     i <= USBLP_LAST_PROTOCOL; i++) {
+					if (usblp->protocol[i].alt_setting >= 0)
+						twoints[1] |= (1<<i);
+				}
+
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				break;
+
+			case IOCNR_SET_PROTOCOL:
+				if (_IOC_DIR(cmd) != _IOC_WRITE) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+#ifdef DEBUG
+				if (arg == -10) {
+					usblp_dump(usblp);
+					break;
+				}
+#endif
+
+				usblp_unlink_urbs(usblp);
+				retval = usblp_set_protocol(usblp, arg);
+				if (retval < 0) {
+					usblp_set_protocol(usblp,
+						usblp->current_protocol);
+				}
+				break;
+
+			case IOCNR_HP_SET_CHANNEL:
+				if (_IOC_DIR(cmd) != _IOC_WRITE ||
+				    usblp->dev->descriptor.idVendor != 0x03F0 ||
+				    usblp->quirks & USBLP_QUIRK_BIDIR) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				err = usblp_hp_channel_change_request(usblp,
+					arg, &newChannel);
+				if (err < 0) {
+					err("usblp%d: error = %d setting "
+						"HP channel",
+						usblp->minor, err);
+					retval = -EIO;
+					goto done;
+				}
+
+				dbg("usblp%d requested/got HP channel %ld/%d",
+					usblp->minor, arg, newChannel);
+				break;
+
+			case IOCNR_GET_BUS_ADDRESS:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				twoints[0] = usblp->dev->bus->busnum;
+				twoints[1] = usblp->dev->devnum;
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				dbg("usblp%d is bus=%d, device=%d",
+					usblp->minor, twoints[0], twoints[1]);
+				break;
+
+			case IOCNR_GET_VID_PID:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				twoints[0] = usblp->dev->descriptor.idVendor;
+				twoints[1] = usblp->dev->descriptor.idProduct;
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
+					usblp->minor, twoints[0], twoints[1]);
+				break;
+
+			default:
+				retval = -EINVAL;
+		}
+	else	/* old-style ioctl value */
+		switch (cmd) {
+
+			case LPGETSTATUS:
+				if (usblp_read_status(usblp, &lpstatus)) {
+					err("usblp%d: failed reading printer status", usblp->minor);
+					retval = -EIO;
+					goto done;
+				}
+				status = lpstatus;
+				if (copy_to_user ((int *)arg, &status, sizeof(int)))
+					retval = -EFAULT;
+				break;
+
+			default:
+				retval = -EINVAL;
+		}
+
+done:
+	up (&usblp->sem);
+	return retval;
+}
+
+static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct usblp *usblp = file->private_data;
+	int timeout, err = 0, writecount = 0;
+
+	while (writecount < count) {
+		if (!usblp->wcomplete) {
+			barrier();
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+
+			timeout = USBLP_WRITE_TIMEOUT;
+			add_wait_queue(&usblp->wait, &wait);
+			while ( 1==1 ) {
+
+				if (signal_pending(current)) {
+					remove_wait_queue(&usblp->wait, &wait);
+					return writecount ? writecount : -EINTR;
+				}
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (timeout && !usblp->wcomplete) {
+					timeout = schedule_timeout(timeout);
+				} else {
+					set_current_state(TASK_RUNNING);
+					break;
+				}
+			}
+			remove_wait_queue(&usblp->wait, &wait);
+		}
+
+		down (&usblp->sem);
+		if (!usblp->dev) {
+			up (&usblp->sem);
+			return -ENODEV;
+		}
+
+		if (usblp->writeurb->status != 0) {
+			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
+				if (!usblp->wcomplete)
+					err("usblp%d: error %d writing to printer",
+						usblp->minor, usblp->writeurb->status);
+				err = usblp->writeurb->status;
+			} else
+				err = usblp_check_status(usblp, err);
+			up (&usblp->sem);
+
+			/* if the fault was due to disconnect, let khubd's
+			 * call to usblp_disconnect() grab usblp->sem ...
+			 */
+			schedule ();
+			continue;
+		}
+
+		writecount += usblp->writeurb->transfer_buffer_length;
+		usblp->writeurb->transfer_buffer_length = 0;
+
+		if (writecount == count) {
+			up (&usblp->sem);
+			break;
+		}
+
+		usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+							  (count - writecount) : USBLP_BUF_SIZE;
+
+		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
+				usblp->writeurb->transfer_buffer_length)) {
+			up(&usblp->sem);
+			return writecount ? writecount : -EFAULT;
+		}
+
+		usblp->writeurb->dev = usblp->dev;
+		usblp->wcomplete = 0;
+		if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
+			count = -EIO;
+			up (&usblp->sem);
+			break;
+		}
+		up (&usblp->sem);
+	}
+
+	return count;
+}
+
+static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usblp *usblp = file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (!usblp->bidir)
+		return -EINVAL;
+
+	down (&usblp->sem);
+	if (!usblp->dev) {
+		count = -ENODEV;
+		goto done;
+	}
+
+	if (!usblp->rcomplete) {
+		barrier();
+
+		if (file->f_flags & O_NONBLOCK) {
+			count = -EAGAIN;
+			goto done;
+		}
+
+		// FIXME:  only use urb->status inside completion
+		// callbacks; this way is racey...
+		add_wait_queue(&usblp->wait, &wait);
+		while (1==1) {
+			if (signal_pending(current)) {
+				count = -EINTR;
+				remove_wait_queue(&usblp->wait, &wait);
+				goto done;
+			}
+			up (&usblp->sem);
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!usblp->rcomplete) {
+				schedule();
+			} else {
+				set_current_state(TASK_RUNNING);
+				break;
+			}
+			down (&usblp->sem);
+		}
+		remove_wait_queue(&usblp->wait, &wait);
+	}
+
+	if (!usblp->dev) {
+		count = -ENODEV;
+		goto done;
+	}
+
+	if (usblp->readurb->status) {
+		err("usblp%d: error %d reading from printer",
+			usblp->minor, usblp->readurb->status);
+		usblp->readurb->dev = usblp->dev;
+ 		usblp->readcount = 0;
+		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
+			dbg("error submitting urb"); 
+		count = -EIO;
+		goto done;
+	}
+
+	count = count < usblp->readurb->actual_length - usblp->readcount ?
+		count :	usblp->readurb->actual_length - usblp->readcount;
+
+	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
+		count = -EFAULT;
+		goto done;
+	}
+
+	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
+		usblp->readcount = 0;
+		usblp->readurb->dev = usblp->dev;
+		usblp->rcomplete = 0;
+		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
+			count = -EIO;
+			goto done;
+		}
+	}
+
+done:
+	up (&usblp->sem);
+	return count;
+}
+
+/*
+ * Checks for printers that have quirks, such as requiring unidirectional
+ * communication but reporting bidirectional; currently some HP printers
+ * have this flaw (HP 810, 880, 895, etc.), or needing an init string
+ * sent at each open (like some Epsons).
+ * Returns 1 if found, 0 if not found.
+ *
+ * HP recommended that we use the bidirectional interface but
+ * don't attempt any bulk IN transfers from the IN endpoint.
+ * Here's some more detail on the problem:
+ * The problem is not that it isn't bidirectional though. The problem
+ * is that if you request a device ID, or status information, while
+ * the buffers are full, the return data will end up in the print data
+ * buffer. For example if you make sure you never request the device ID
+ * while you are sending print data, and you don't try to query the
+ * printer status every couple of milliseconds, you will probably be OK.
+ */
+static unsigned int usblp_quirks (__u16 vendor, __u16 product)
+{
+	int i;
+
+	for (i = 0; quirk_printers[i].vendorId; i++) {
+		if (vendor == quirk_printers[i].vendorId &&
+		    product == quirk_printers[i].productId)
+			return quirk_printers[i].quirks;
+ 	}
+	return 0;
+}
+
+static struct file_operations usblp_fops = {
+	.owner =	THIS_MODULE,
+	.read =		usblp_read,
+	.write =	usblp_write,
+	.poll =		usblp_poll,
+	.ioctl =	usblp_ioctl,
+	.open =		usblp_open,
+	.release =	usblp_release,
+};
+
+static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
+			 const struct usb_device_id *id)
+{
+	struct usblp *usblp = 0;
+	int protocol;
+	int retval;
+	char name[6];
+
+	/* Malloc and start initializing usblp structure so we can use it
+	 * directly. */
+	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
+		err("out of memory for usblp");
+		goto abort;
+	}
+	memset(usblp, 0, sizeof(struct usblp));
+	usblp->dev = dev;
+	init_MUTEX (&usblp->sem);
+	init_waitqueue_head(&usblp->wait);
+	usblp->ifnum = ifnum;
+
+	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
+	if (retval) {
+		err("Not able to get a minor for this device.");
+		goto abort;
+	}
+
+	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usblp->writeurb) {
+		err("out of memory");
+		goto abort_minor;
+	}
+	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usblp->readurb) {
+		err("out of memory");
+		goto abort_minor;
+	}
+
+	/* Malloc device ID string buffer to the largest expected length,
+	 * since we can re-query it on an ioctl and a dynamic string
+	 * could change in length. */
+	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
+		err("out of memory for device_id_string");
+		goto abort_minor;
+	}
+
+	/* Malloc write/read buffers in one chunk.  We somewhat wastefully
+	 * malloc both regardless of bidirectionality, because the
+	 * alternate setting can be changed later via an ioctl. */
+	if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
+		err("out of memory for buf");
+		goto abort_minor;
+	}
+
+	/* Lookup quirks for this printer. */
+	usblp->quirks = usblp_quirks(
+		dev->descriptor.idVendor,
+		dev->descriptor.idProduct);
+
+	/* Analyze and pick initial alternate settings and endpoints. */
+	protocol = usblp_select_alts(usblp);
+	if (protocol < 0) {
+		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
+			dev->descriptor.idVendor,
+			dev->descriptor.idProduct);
+		goto abort_minor;
+	}
+
+	/* Setup the selected alternate setting and endpoints. */
+	if (usblp_set_protocol(usblp, protocol) < 0)
+		goto abort_minor;
+
+	/* Retrieve and store the device ID string. */
+	usblp_cache_device_id_string(usblp);
+
+#ifdef DEBUG
+	usblp_check_status(usblp, 0);
+#endif
+
+	/* add a table entry so the device works when advertised */
+	usblp_table[usblp->minor] = usblp;
+
+	/* If we have devfs, create with perms=660. */
+	sprintf(name, "lp%d", usblp->minor);
+	usblp->devfs = devfs_register(usb_devfs_handle, name,
+				      DEVFS_FL_DEFAULT, USB_MAJOR,
+				      USBLP_MINOR_BASE + usblp->minor,
+				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+				      S_IWGRP, &usblp_fops, NULL);
+
+	info("usblp%d: USB %sdirectional printer dev %d "
+		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
+		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum,
+		usblp->protocol[usblp->current_protocol].alt_setting,
+		usblp->current_protocol, usblp->dev->descriptor.idVendor,
+		usblp->dev->descriptor.idProduct);
+
+	return usblp;
+
+abort_minor:
+	usb_deregister_dev (1, usblp->minor);
+abort:
+	if (usblp) {
+		usb_free_urb(usblp->writeurb);
+		usb_free_urb(usblp->readurb);
+		if (usblp->buf) kfree(usblp->buf);
+		if (usblp->device_id_string) kfree(usblp->device_id_string);
+		kfree(usblp);
+	}
+	return NULL;
+}
+
+/*
+ * We are a "new" style driver with usb_device_id table,
+ * but our requirements are too intricate for simple match to handle.
+ *
+ * The "proto_bias" option may be used to specify the preferred protocol
+ * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3).  If the device
+ * supports the preferred protocol, then we bind to it.
+ *
+ * The best interface for us is 7/1/2, because it is compatible
+ * with a stream of characters. If we find it, we bind to it.
+ *
+ * Note that the people from hpoj.sourceforge.net need to be able to
+ * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose.
+ *
+ * Failing 7/1/2, we look for 7/1/3, even though it's probably not
+ * stream-compatible, because this matches the behaviour of the old code.
+ *
+ * If nothing else, we bind to 7/1/1 - the unidirectional interface.
+ */
+static int usblp_select_alts(struct usblp *usblp)
+{
+	struct usb_interface *if_alt;
+	struct usb_interface_descriptor *ifd;
+	struct usb_endpoint_descriptor *epd, *epwrite, *epread;
+	int p, i, e;
+
+	if_alt = &usblp->dev->actconfig->interface[usblp->ifnum];
+
+	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
+		usblp->protocol[p].alt_setting = -1;
+
+	/* Find out what we have. */
+	for (i = 0; i < if_alt->num_altsetting; i++) {
+		ifd = &if_alt->altsetting[i];
+
+		if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1)
+			continue;
+
+		if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL ||
+		    ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL)
+			continue;
+
+		/* Look for bulk OUT and IN endpoints. */
+		epwrite = epread = 0;
+		for (e = 0; e < ifd->bNumEndpoints; e++) {
+			epd = &ifd->endpoint[e];
+
+			if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
+			    USB_ENDPOINT_XFER_BULK)
+				continue;
+
+			if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+				if (!epwrite) epwrite=epd;
+
+			} else {
+				if (!epread) epread=epd;
+			}
+		}
+
+		/* Ignore buggy hardware without the right endpoints. */
+		if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread))
+			continue;
+
+		/* Turn off reads for 7/1/1 (unidirectional) interfaces
+		 * and buggy bidirectional printers. */
+		if (ifd->bInterfaceProtocol == 1) {
+			epread = NULL;
+		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
+			info("Disabling reads from problem bidirectional "
+				"printer on usblp%d", usblp->minor);
+			epread = NULL;
+		}
+
+		usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i;
+		usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite;
+		usblp->protocol[ifd->bInterfaceProtocol].epread = epread;
+	}
+
+	/* If our requested protocol is supported, then use it. */
+	if (proto_bias >= USBLP_FIRST_PROTOCOL &&
+	    proto_bias <= USBLP_LAST_PROTOCOL &&
+	    usblp->protocol[proto_bias].alt_setting != -1)
+		return proto_bias;
+
+	/* Ordering is important here. */
+	if (usblp->protocol[2].alt_setting != -1) return 2;
+	if (usblp->protocol[1].alt_setting != -1) return 1;
+	if (usblp->protocol[3].alt_setting != -1) return 3;
+
+	/* If nothing is available, then don't bind to this device. */
+	return -1;
+}
+
+static int usblp_set_protocol(struct usblp *usblp, int protocol)
+{
+	int r, alts;
+
+	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
+		return -EINVAL;
+
+	alts = usblp->protocol[protocol].alt_setting;
+	if (alts < 0) return -EINVAL;
+	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
+	if (r < 0) {
+		err("can't set desired altsetting %d on interface %d",
+			alts, usblp->ifnum);
+		return r;
+	}
+
+	FILL_BULK_URB(usblp->writeurb, usblp->dev,
+		usb_sndbulkpipe(usblp->dev,
+		 usblp->protocol[protocol].epwrite->bEndpointAddress),
+		usblp->buf, 0,
+		usblp_bulk_write, usblp);
+
+	usblp->bidir = (usblp->protocol[protocol].epread != 0);
+	if (usblp->bidir)
+		FILL_BULK_URB(usblp->readurb, usblp->dev,
+			usb_rcvbulkpipe(usblp->dev,
+			 usblp->protocol[protocol].epread->bEndpointAddress),
+			usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE,
+			usblp_bulk_read, usblp);
+
+	usblp->current_protocol = protocol;
+	dbg("usblp%d set protocol %d", usblp->minor, protocol);
+	return 0;
+}
+
+/* Retrieves and caches device ID string.
+ * Returns length, including length bytes but not null terminator.
+ * On error, returns a negative errno value. */
+static int usblp_cache_device_id_string(struct usblp *usblp)
+{
+	int err, length;
+
+	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
+	if (err < 0) {
+		dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
+			usblp->minor, err);
+		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
+		return -EIO;
+	}
+
+	/* First two bytes are length in big-endian.
+	 * They count themselves, and we copy them into
+	 * the user's buffer. */
+	length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1];
+	if (length < 2)
+		length = 2;
+	else if (length >= USBLP_DEVICE_ID_SIZE)
+		length = USBLP_DEVICE_ID_SIZE - 1;
+	usblp->device_id_string[length] = '\0';
+
+	dbg("usblp%d Device ID string [len=%d]=\"%s\"",
+		usblp->minor, length, &usblp->device_id_string[2]);
+
+	return length;
+}
+
+static void usblp_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usblp *usblp = ptr;
+
+	if (!usblp || !usblp->dev) {
+		err("bogus disconnect");
+		BUG ();
+	}
+
+	down (&usblp->sem);
+	lock_kernel();
+	usblp->dev = NULL;
+
+	usblp_unlink_urbs(usblp);
+
+	if (!usblp->used)
+		usblp_cleanup (usblp);
+	else 	/* cleanup later, on close */
+		up (&usblp->sem);
+	unlock_kernel();
+}
+
+static struct usb_device_id usblp_ids [] = {
+	{ USB_DEVICE_INFO(7, 1, 1) },
+	{ USB_DEVICE_INFO(7, 1, 2) },
+	{ USB_DEVICE_INFO(7, 1, 3) },
+	{ USB_INTERFACE_INFO(7, 1, 1) },
+	{ USB_INTERFACE_INFO(7, 1, 2) },
+	{ USB_INTERFACE_INFO(7, 1, 3) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usblp_ids);
+
+static struct usb_driver usblp_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"usblp",
+	.probe =	usblp_probe,
+	.disconnect =	usblp_disconnect,
+	.id_table =	usblp_ids,
+};
+
+static int __init usblp_init(void)
+{
+	if (usb_register(&usblp_driver))
+		return -1;
+	info(DRIVER_VERSION ": " DRIVER_DESC);
+	return 0;
+}
+
+static void __exit usblp_exit(void)
+{
+	usb_deregister(&usblp_driver);
+}
+
+module_init(usblp_init);
+module_exit(usblp_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_PARM(proto_bias, "i");
+MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/core/Makefile	Tue Aug 27 12:28:08 2002
@@ -2,10 +2,10 @@
 # Makefile for USB Core files and filesystem
 #
 
-export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o file.o
+export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o file.o buffer.o
 
 usbcore-objs	:= usb.o usb-debug.o hub.o hcd.o urb.o message.o \
-			config.o file.o
+			config.o file.o buffer.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
diff -Nru a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/buffer.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,186 @@
+/*
+ * DMA memory management for framework level HCD code (hc_driver)
+ *
+ * This implementation plugs in through generic "usb_bus" level methods,
+ * and works with real PCI, or when "pci device == null" makes sense.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+
+/*
+ * DMA-Consistent Buffers
+ */
+
+/* FIXME tune these based on pool statistics ... */
+static const size_t	pool_max [HCD_BUFFER_POOLS] = {
+	32,
+	128,
+	512,
+	PAGE_SIZE / 2
+	/* bigger --> allocate pages */
+};
+
+
+/* SETUP primitives */
+
+/**
+ * hcd_buffer_create - initialize buffer pools
+ * @hcd: the bus whose buffer pools are to be initialized
+ *
+ * Call this as part of initializing a host controller that uses the pci dma
+ * memory allocators.  It initializes some pools of dma-consistent memory that
+ * will be shared by all drivers using that controller, or returns a negative
+ * errno value on error.
+ *
+ * Call hcd_buffer_destroy() to clean up after using those pools.
+ */
+int hcd_buffer_create (struct usb_hcd *hcd)
+{
+	char		name [16];
+	int 		i, size;
+
+	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
+		if (!(size = pool_max [i]))
+			continue;
+		snprintf (name, sizeof name, "buffer-%d", size);
+		hcd->pool [i] = pci_pool_create (name, hcd->pdev,
+				size, size, 0, SLAB_KERNEL);
+		if (!hcd->pool [i]) {
+			hcd_buffer_destroy (hcd);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL (hcd_buffer_create);
+
+
+/**
+ * hcd_buffer_destroy - deallocate buffer pools
+ * @hcd: the bus whose buffer pools are to be destroyed
+ *
+ * This frees the buffer pools created by hcd_buffer_create().
+ */
+void hcd_buffer_destroy (struct usb_hcd *hcd)
+{
+	int		i;
+
+	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
+		struct pci_pool		*pool = hcd->pool [i];
+		if (pool) {
+			pci_pool_destroy (pool);
+			hcd->pool [i] = 0;
+		}
+	}
+}
+EXPORT_SYMBOL (hcd_buffer_destroy);
+
+
+/* sometimes alloc/free could use kmalloc with SLAB_DMA, for
+ * better sharing and to leverage mm/slab.c intelligence.
+ */
+
+void *hcd_buffer_alloc (
+	struct usb_bus 		*bus,
+	size_t			size,
+	int			mem_flags,
+	dma_addr_t		*dma
+)
+{
+	struct usb_hcd		*hcd = bus->hcpriv;
+	int 			i;
+
+	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+		if (size <= pool_max [i])
+			return pci_pool_alloc (hcd->pool [i], mem_flags, dma);
+	}
+	return pci_alloc_consistent (hcd->pdev, size, dma);
+}
+
+void hcd_buffer_free (
+	struct usb_bus 		*bus,
+	size_t			size,
+	void 			*addr,
+	dma_addr_t		dma
+)
+{
+	struct usb_hcd		*hcd = bus->hcpriv;
+	int 			i;
+
+	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+		if (size <= pool_max [i]) {
+			pci_pool_free (hcd->pool [i], addr, dma);
+			return;
+		}
+	}
+	pci_free_consistent (hcd->pdev, size, addr, dma);
+}
+
+
+/*
+ * DMA-Mappings for arbitrary memory buffers
+ */
+
+int hcd_buffer_map (
+	struct usb_bus	*bus,
+	void		*addr,
+	dma_addr_t	*dma,
+	size_t		size,
+	int		direction
+) {
+	struct usb_hcd	*hcd = bus->hcpriv;
+
+	// FIXME pci_map_single() has no standard failure mode!
+	*dma = pci_map_single (hcd->pdev, addr, size,
+			(direction == USB_DIR_IN)
+				? PCI_DMA_FROMDEVICE
+				: PCI_DMA_TODEVICE);
+	return 0;
+}
+
+void hcd_buffer_dmasync (
+	struct usb_bus	*bus,
+	dma_addr_t	dma,
+	size_t		size,
+	int		direction
+) {
+	struct usb_hcd *hcd = bus->hcpriv;
+
+	pci_dma_sync_single (hcd->pdev, dma, size,
+			(direction == USB_DIR_IN)
+				? PCI_DMA_FROMDEVICE
+				: PCI_DMA_TODEVICE);
+}
+
+void hcd_buffer_unmap (
+	struct usb_bus	*bus,
+	dma_addr_t	dma,
+	size_t		size,
+	int		direction
+) {
+	struct usb_hcd *hcd = bus->hcpriv;
+
+	pci_unmap_single (hcd->pdev, dma, size,
+			(direction == USB_DIR_IN)
+				? PCI_DMA_FROMDEVICE
+				: PCI_DMA_TODEVICE);
+}
+
+
+// FIXME DMA-Mappings for struct scatterlist
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/usb/core/devio.c	Tue Aug 27 12:28:06 2002
@@ -46,6 +46,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
+#include "hcd.h"	/* for usbcore internals */
 
 struct async {
         struct list_head asynclist;
@@ -724,7 +725,7 @@
 
 		lock_kernel();
 		if (intf->driver && ps->dev) {
-			usb_bind_driver(intf->driver,ps->dev, i);
+			usb_bind_driver (intf->driver, intf);
 		}
 		unlock_kernel();
 	}
@@ -1062,8 +1063,8 @@
 	int			size;
 	void			*buf = 0;
 	int			retval = 0;
-       struct usb_interface    *ifp = 0;
-       struct usb_driver       *driver = 0;
+	struct usb_interface    *ifp = 0;
+	struct usb_driver       *driver = 0;
 
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
@@ -1102,10 +1103,10 @@
 		unlock_kernel();
                break;
 
-       /* let kernel drivers try to (re)bind to the interface */
-       case USBDEVFS_CONNECT:
-               usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno);
-               break;
+	/* let kernel drivers try to (re)bind to the interface */
+	case USBDEVFS_CONNECT:
+		usb_find_interface_driver (ps->dev, ifp);
+		break;
 
        /* talk directly to the interface's driver */
        default:
@@ -1144,6 +1145,11 @@
 	return retval;
 }
 
+/*
+ * NOTE:  All requests here that have interface numbers as parameters
+ * are assuming that somehow the configuration has been prevented from
+ * changing.  But there's no mechanism to ensure that...
+ */
 static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct dev_state *ps = (struct dev_state *)file->private_data;
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/usb/core/hcd-pci.c	Tue Aug 27 12:28:05 2002
@@ -130,10 +130,19 @@
 			return retval;
 		}
 	}
-	pci_set_drvdata(dev, hcd);
+	pci_set_drvdata (dev, hcd);
 	hcd->driver = driver;
 	hcd->description = driver->description;
 	hcd->pdev = dev;
+	hcd->self.bus_name = dev->slot_name;
+	hcd->product_desc = dev->name;
+
+	if ((retval = hcd_buffer_create (hcd)) != 0) {
+clean_3:
+		driver->hcd_free (hcd);
+		goto clean_2;
+	}
+
 	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
 
 	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
@@ -154,8 +163,7 @@
 			!= 0) {
 		err ("request interrupt %s failed", bufp);
 		retval = -EBUSY;
-		driver->hcd_free (hcd);
-		goto clean_2;
+		goto clean_3;
 	}
 	hcd->irq = dev->irq;
 
@@ -168,8 +176,6 @@
 	usb_bus_init (&hcd->self);
 	hcd->self.op = &usb_hcd_operations;
 	hcd->self.hcpriv = (void *) hcd;
-	hcd->self.bus_name = dev->slot_name;
-	hcd->product_desc = dev->name;
 
 	INIT_LIST_HEAD (&hcd->dev_list);
 
@@ -216,6 +222,7 @@
 	usb_disconnect (&hub);
 
 	hcd->driver->stop (hcd);
+	hcd_buffer_destroy (hcd);
 	hcd->state = USB_STATE_HALT;
 
 	free_irq (hcd->irq, hcd);
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/core/hcd.c	Tue Aug 27 12:28:07 2002
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/uts.h>			/* for UTS_SYSNAME */
+#include <linux/pci.h>			/* for hcd->pdev and dma addressing */
 #include <asm/byteorder.h>
 
 
@@ -288,7 +289,7 @@
 	// language ids
 	if (id == 0) {
 		*data++ = 4; *data++ = 3;	/* 4 bytes string data */
-		*data++ = 0; *data++ = 0;	/* some language id */
+		*data++ = 0x09; *data++ = 0x04;	/* MSFT-speak for "en-us" */
 		return 4;
 
 	// serial number
@@ -454,7 +455,6 @@
 	/* rh_timer protected by hcd_data_lock */
 	if (timer_pending (&hcd->rh_timer)
 			|| urb->status != -EINPROGRESS
-			|| !HCD_IS_RUNNING (hcd->state)
 			|| urb->transfer_buffer_length < len) {
 		dbg ("not queuing status urb, stat %d", urb->status);
 		return -EINVAL;
@@ -508,8 +508,12 @@
 				BUG ();
 			}
 			spin_unlock_irqrestore (&hcd_data_lock, flags);
-		} else
+		} else {
 			spin_unlock_irqrestore (&urb->lock, flags);
+			spin_lock_irqsave (&hcd_data_lock, flags);
+			rh_status_urb (hcd, urb);
+			spin_unlock_irqrestore (&hcd_data_lock, flags);
+		}
 	} else {
 		/* this urb's been unlinked */
 		urb->hcpriv = 0;
@@ -581,9 +585,7 @@
 {
 	memset (&bus->devmap, 0, sizeof(struct usb_devmap));
 
-#ifdef DEVNUM_ROUND_ROBIN
 	bus->devnum_next = 1;
-#endif /* DEVNUM_ROUND_ROBIN */
 
 	bus->root_hub = NULL;
 	bus->hcpriv = NULL;
@@ -734,10 +736,10 @@
 /*-------------------------------------------------------------------------*/
 
 /**
- * usb_calc_bus_time: approximate periodic transaction time in nanoseconds
+ * usb_calc_bus_time - approximate periodic transaction time in nanoseconds
  * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
  * @is_input: true iff the transaction sends data to the host
- * @is_isoc: true for isochronous transactions, false for interrupt ones
+ * @isoc: true for isochronous transactions, false for interrupt ones
  * @bytecount: how many bytes in the transaction.
  *
  * Returns approximate bus time in nanoseconds for a periodic transaction.
@@ -1018,6 +1020,24 @@
 	if (status)
 		return status;
 
+	/* lower level hcd code should use *_dma exclusively */
+	if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
+		if (usb_pipecontrol (urb->pipe))
+			urb->setup_dma = pci_map_single (
+					hcd->pdev,
+					urb->setup_packet,
+					sizeof (struct usb_ctrlrequest),
+					PCI_DMA_TODEVICE);
+		if (urb->transfer_buffer_length != 0)
+			urb->transfer_dma = pci_map_single (
+					hcd->pdev,
+					urb->transfer_buffer,
+					urb->transfer_buffer_length,
+					usb_pipein (urb->pipe)
+					    ? PCI_DMA_FROMDEVICE
+					    : PCI_DMA_TODEVICE);
+	}
+
 	/* increment urb's reference count as part of giving it to the HCD
 	 * (which now controls it).  HCD guarantees that it either returns
 	 * an error or calls giveback(), but not both.
@@ -1245,6 +1265,11 @@
 	.submit_urb =		hcd_submit_urb,
 	.unlink_urb =		hcd_unlink_urb,
 	.deallocate =		hcd_free_dev,
+	.buffer_alloc =		hcd_buffer_alloc,
+	.buffer_free =		hcd_buffer_free,
+	.buffer_map =		hcd_buffer_map,
+	.buffer_dmasync =	hcd_buffer_dmasync,
+	.buffer_unmap =		hcd_buffer_unmap,
 };
 EXPORT_SYMBOL (usb_hcd_operations);
 
@@ -1259,8 +1284,8 @@
  * This hands the URB from HCD to its USB device driver, using its
  * completion function.  The HCD has freed all per-urb resources
  * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause deadlocks if it resubmits this URB,
- * and won't confuse things by modifying and resubmitting this one.
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
  * Bandwidth and other resources will be deallocated.
  *
  * HCDs must not use this for periodic URBs that are still scheduled
@@ -1280,6 +1305,20 @@
 	if (urb->status)
 		dbg ("giveback urb %p status %d len %d",
 			urb, urb->status, urb->actual_length);
+
+	/* lower level hcd code should use *_dma exclusively */
+	if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
+		if (usb_pipecontrol (urb->pipe))
+			pci_unmap_single (hcd->pdev, urb->setup_dma,
+					sizeof (struct usb_ctrlrequest),
+					PCI_DMA_TODEVICE);
+		if (urb->transfer_buffer_length != 0)
+			pci_unmap_single (hcd->pdev, urb->transfer_dma,
+					urb->transfer_buffer_length,
+					usb_pipein (urb->pipe)
+					    ? PCI_DMA_FROMDEVICE
+					    : PCI_DMA_TODEVICE);
+	}
 
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/core/hcd.h	Tue Aug 27 12:28:02 2002
@@ -19,6 +19,31 @@
 
 #ifdef __KERNEL__
 
+/* This file contains declarations of usbcore internals that are mostly
+ * used or exposed by Host Controller Drivers.
+ */
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_UNDEF_0			0xf0
+#define USB_PID_OUT			0xe1
+#define USB_PID_ACK			0xd2
+#define USB_PID_DATA0			0xc3
+#define USB_PID_PING			0xb4	/* USB 2.0 */
+#define USB_PID_SOF			0xa5
+#define USB_PID_NYET			0x96	/* USB 2.0 */
+#define USB_PID_DATA2			0x87	/* USB 2.0 */
+#define USB_PID_SPLIT			0x78	/* USB 2.0 */
+#define USB_PID_IN			0x69
+#define USB_PID_NAK			0x5a
+#define USB_PID_DATA1			0x4b
+#define USB_PID_PREAMBLE		0x3c	/* Token mode */
+#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
+#define USB_PID_SETUP			0x2d
+#define USB_PID_STALL			0x1e
+#define USB_PID_MDATA			0x0f	/* USB 2.0 */
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -58,6 +83,9 @@
 	atomic_t		resume_count;	/* multiple resumes issue */
 #endif
 
+#define HCD_BUFFER_POOLS	4
+	struct pci_pool		*pool [HCD_BUFFER_POOLS];
+
 	int			state;
 #	define	__ACTIVE		0x01
 #	define	__SLEEPY		0x02
@@ -109,6 +137,25 @@
 	int (*get_frame_number) (struct usb_device *usb_dev);
 	int (*submit_urb) (struct urb *urb, int mem_flags);
 	int (*unlink_urb) (struct urb *urb);
+
+	/* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
+	void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
+			int mem_flags,
+			dma_addr_t *dma);
+	void (*buffer_free)(struct usb_bus *bus, size_t size,
+			void *addr, dma_addr_t dma);
+
+	int (*buffer_map) (struct usb_bus *bus,
+		void *addr, dma_addr_t *dma,
+		size_t size, int direction);
+	void (*buffer_dmasync) (struct usb_bus *bus,
+		dma_addr_t dma,
+		size_t size, int direction);
+	void (*buffer_unmap) (struct usb_bus *bus,
+		dma_addr_t dma,
+		size_t size, int direction);
+
+	// FIXME  also: buffer_sg_map (), buffer_sg_unmap ()
 };
 
 /* each driver provides one of these, and hardware init support */
@@ -181,6 +228,25 @@
 
 #endif /* CONFIG_PCI */
 
+/* pci-ish (pdev null is ok) buffer alloc/mapping support */
+int hcd_buffer_create (struct usb_hcd *hcd);
+void hcd_buffer_destroy (struct usb_hcd *hcd);
+
+void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
+	int mem_flags, dma_addr_t *dma);
+void hcd_buffer_free (struct usb_bus *bus, size_t size,
+	void *addr, dma_addr_t dma);
+
+int hcd_buffer_map (struct usb_bus *bus,
+	void *addr, dma_addr_t *dma,
+	size_t size, int direction);
+void hcd_buffer_dmasync (struct usb_bus *bus,
+	dma_addr_t dma,
+	size_t size, int direction);
+void hcd_buffer_unmap (struct usb_bus *bus,
+	dma_addr_t dma,
+	size_t size, int direction);
+
 /* generic bus glue, needed for host controllers that don't use PCI */
 extern struct usb_operations usb_hcd_operations;
 extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
@@ -193,13 +259,11 @@
 extern void usb_connect(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
 
-#ifndef _LINUX_HUB_H
 /* exported to hub driver ONLY to support usb_reset_device () */
 extern int usb_get_configuration(struct usb_device *dev);
 extern void usb_set_maxpacket(struct usb_device *dev);
 extern void usb_destroy_configuration(struct usb_device *dev);
 extern int usb_set_address(struct usb_device *dev);
-#endif /* _LINUX_HUB_H */
 
 /*-------------------------------------------------------------------------*/
 
@@ -306,6 +370,54 @@
 
 extern void usb_bus_get (struct usb_bus *bus);
 extern void usb_bus_put (struct usb_bus *bus);
+
+extern struct usb_interface *usb_ifnum_to_if (struct usb_device *dev,
+	unsigned ifnum);
+
+extern int usb_find_interface_driver (struct usb_device *dev,
+	struct usb_interface *interface);
+
+#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
+
+#define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
+
+/* for probe/disconnect with correct module usage counting */
+void *usb_bind_driver(struct usb_driver *driver, struct usb_interface *intf);
+void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf);
+
+extern struct list_head usb_driver_list;
+
+/*
+ * USB device fs stuff
+ */
+
+#ifdef CONFIG_USB_DEVICEFS
+
+/*
+ * these are expected to be called from the USB core/hub thread
+ * with the kernel lock held
+ */
+extern void usbfs_add_bus(struct usb_bus *bus);
+extern void usbfs_remove_bus(struct usb_bus *bus);
+extern void usbfs_add_device(struct usb_device *dev);
+extern void usbfs_remove_device(struct usb_device *dev);
+extern void usbfs_update_special (void);
+
+extern int usbfs_init(void);
+extern void usbfs_cleanup(void);
+
+#else /* CONFIG_USB_DEVICEFS */
+
+static inline void usbfs_add_bus(struct usb_bus *bus) {}
+static inline void usbfs_remove_bus(struct usb_bus *bus) {}
+static inline void usbfs_add_device(struct usb_device *dev) {}
+static inline void usbfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_update_special (void) {}
+
+static inline int usbfs_init(void) { return 0; }
+static inline void usbfs_cleanup(void) { }
+
+#endif /* CONFIG_USB_DEVICEFS */
 
 /*-------------------------------------------------------------------------*/
 
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/usb/core/hub.c	Tue Aug 27 12:28:05 2002
@@ -261,9 +261,8 @@
 {
 	struct usb_device *dev = hub->dev;
 	struct usb_hub_status hubstatus;
-	char portstr[USB_MAXCHILDREN + 1];
 	unsigned int pipe;
-	int i, maxp, ret;
+	int maxp, ret;
 
 	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
@@ -294,9 +293,17 @@
 
 	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
-	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
-		dbg("part of a compound device");
-	else
+	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) {
+		int	i;
+		char	portstr [USB_MAXCHILDREN + 1];
+
+		for (i = 0; i < dev->maxchild; i++)
+			portstr[i] = hub->descriptor->DeviceRemovable
+				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+				? 'F' : 'R';
+		portstr[dev->maxchild] = 0;
+		dbg("compound device; port removable status: %s", portstr);
+	} else
 		dbg("standalone hub");
 
 	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
@@ -370,14 +377,6 @@
 		hub->descriptor->bPwrOn2PwrGood * 2);
 	dbg("hub controller current requirement: %dmA",
 		hub->descriptor->bHubContrCurrent);
-
-	for (i = 0; i < dev->maxchild; i++)
-		portstr[i] = hub->descriptor->DeviceRemovable
-			    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
-			? 'F' : 'R';
-	portstr[dev->maxchild] = 0;
-
-	dbg("port removable status: %s", portstr);
 
 	ret = usb_get_hub_status(dev, &hubstatus);
 	if (ret < 0) {
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h	Tue Aug 27 12:27:59 2002
+++ b/drivers/usb/core/hub.h	Tue Aug 27 12:27:59 2002
@@ -123,6 +123,10 @@
  * Hub descriptor 
  * See USB 2.0 spec Table 11-13
  */
+
+#define USB_DT_HUB			(USB_TYPE_CLASS | 0x09)
+#define USB_DT_HUB_NONVAR_SIZE		7
+
 struct usb_hub_descriptor {
 	__u8  bDescLength;
 	__u8  bDescriptorType;
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/core/message.c	Tue Aug 27 12:28:02 2002
@@ -8,6 +8,8 @@
 #include <linux/init.h>
 #include <asm/byteorder.h>
 
+#include "hcd.h"	/* for usbcore internals */
+
 struct usb_api_data {
 	wait_queue_head_t wqh;
 	int done;
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/core/urb.c	Tue Aug 27 12:28:07 2002
@@ -88,15 +88,17 @@
 /*-------------------------------------------------------------------*/
 
 /**
- * usb_submit_urb - asynchronously issue a transfer request for an endpoint
+ * usb_submit_urb - issue an asynchronous transfer request for an endpoint
  * @urb: pointer to the urb describing the request
  * @mem_flags: the type of memory to allocate, see kmalloc() for a list
  *	of valid options for this.
  *
  * This submits a transfer request, and transfers control of the URB
  * describing that request to the USB subsystem.  Request completion will
- * indicated later, asynchronously, by calling the completion handler.
- * This call may be issued in interrupt context.
+ * be indicated later, asynchronously, by calling the completion handler.
+ * The three types of completion are success, error, and unlink
+ * (also called "request cancellation").
+ * URBs may be submitted in interrupt context.
  *
  * The caller must have correctly initialized the URB before submitting
  * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
@@ -148,20 +150,19 @@
  *
  * Memory Flags:
  *
- * General rules for how to decide which mem_flags to use:
- * 
- * Basically the rules are the same as for kmalloc.  There are four
+ * The general rules for how to decide which mem_flags to use
+ * are the same as for kmalloc.  There are four
  * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
  * GFP_ATOMIC.
  *
  * GFP_NOFS is not ever used, as it has not been implemented yet.
  *
- * There are three situations you must use GFP_ATOMIC.
- *    a) you are inside a completion handler, an interrupt, bottom half,
- *       tasklet or timer.
- *    b) you are holding a spinlock or rwlock (does not apply to
- *       semaphores)
- *    c) current->state != TASK_RUNNING, this is the case only after
+ * GFP_ATOMIC is used when
+ *   (a) you are inside a completion handler, an interrupt, bottom half,
+ *       tasklet or timer, or
+ *   (b) you are holding a spinlock or rwlock (does not apply to
+ *       semaphores), or
+ *   (c) current->state != TASK_RUNNING, this is the case only after
  *       you've changed it.
  * 
  * GFP_NOIO is used in the block io path and error handling of storage
@@ -169,17 +170,17 @@
  *
  * All other situations use GFP_KERNEL.
  *
- * Specfic rules for how to decide which mem_flags to use:
- *
- *    - start_xmit, timeout, and receive methods of network drivers must
- *      use GFP_ATOMIC (spinlock)
- *    - queuecommand methods of scsi drivers must use GFP_ATOMIC (spinlock)
- *    - If you use a kernel thread with a network driver you must use
- *      GFP_NOIO, unless b) or c) apply
- *    - After you have done a down() you use GFP_KERNEL, unless b) or c)
- *      apply or your are in a storage driver's block io path
- *    - probe and disconnect use GFP_KERNEL unless b) or c) apply
- *    - Changing firmware on a running storage or net device uses
+ * Some more specific rules for mem_flags can be inferred, such as
+ *  (1) start_xmit, timeout, and receive methods of network drivers must
+ *      use GFP_ATOMIC (they are called with a spinlock held);
+ *  (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
+ *      called with a spinlock held);
+ *  (3) If you use a kernel thread with a network driver you must use
+ *      GFP_NOIO, unless (b) or (c) apply;
+ *  (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
+ *      apply or your are in a storage driver's block io path;
+ *  (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
+ *  (6) changing firmware on a running storage or net device uses
  *      GFP_NOIO, unless b) or c) apply
  *
  */
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/usb/core/usb.c	Tue Aug 27 12:28:06 2002
@@ -52,7 +52,6 @@
  * Prototypes for the device driver probing/loading functions
  */
 static void usb_find_drivers(struct usb_device *);
-static int  usb_find_interface_driver(struct usb_device *, unsigned int);
 static void usb_check_support(struct usb_device *);
 
 /*
@@ -119,7 +118,7 @@
 }
 
 /**
- *	usb_unbind_driver - disconnects a driver from a device
+ *	usb_unbind_driver - disconnects a driver from a device (usbcore-internal)
  *	@device: usb device to be disconnected
  *	@intf: interface of the device to be disconnected
  *	Context: BKL held
@@ -137,7 +136,7 @@
 	driver = intf->driver;
 	priv = intf->private_data;
 	
-	if (!driver)
+	if (!driver || !driver->disconnect)
 		return;
 
 	/* as soon as we increase the module use count we drop the BKL
@@ -164,21 +163,27 @@
 }
 
 /**
- *	usb_bind_driver - connect a driver to a device's interface
- *	@driver: device driver to be bound to a devices interface
- *	@dev: device to be bound
- *	@ifnum: index number of the interface to be used
+ *	usb_bind_driver - connect a driver to a device's interface (usbcore-internal)
+ *	@driver: device driver to be bound to interface
+ *	@interface: interface that the driver will be using
+ *	Context: BKL held
  *
- *	Does a save binding of a driver to a device's interface
- *	Returns a pointer to the drivers private description of the binding
+ *	Does a safe binding of a driver to one of a device's interfaces.
+ *	Returns the driver's data for the binding, or null indicating
+ *	that the driver did not bind to this interface.
+ *
+ *	This differs from usb_driver_claim_interface(), which is called from
+ *	drivers and neither calls the driver's probe() entry nor does any
+ *	locking to guard against removing driver modules.
  */
-
-void *usb_bind_driver(struct usb_driver *driver, struct usb_device *dev, unsigned int ifnum)
+void *
+usb_bind_driver (struct usb_driver *driver, struct usb_interface *interface)
 {
 	int i,m;
 	void *private = NULL;
 	const struct usb_device_id *id;
-	struct usb_interface *interface;
+	struct usb_device *dev = interface_to_usbdev (interface);
+	int ifnum;
 
 	if (driver->owner) {
 		m = try_inc_mod_count(driver->owner);
@@ -187,14 +192,21 @@
 		unlock_kernel();
 	}
 
-	interface = &dev->actconfig->interface[ifnum];
+	// START TEMPORARY
+	// driver->probe() hasn't yet changed to take interface not dev+ifnum,
+	// so we still need ifnum here.
+	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++)
+		if (&dev->actconfig->interface [ifnum] == interface)
+			break;
+	BUG_ON (ifnum == dev->actconfig->bNumInterfaces);
+	// END TEMPORARY
 
 	id = driver->id_table;
 	/* new style driver? */
 	if (id) {
 		for (i = 0; i < interface->num_altsetting; i++) {
 		  	interface->act_altsetting = i;
-			id = usb_match_id(dev, interface, id);
+			id = usb_match_id(interface, id);
 			if (id) {
 				down(&driver->serialize);
 				private = driver->probe(dev,ifnum,id);
@@ -252,7 +264,7 @@
 			 * This will go through the list looking for another
 			 * driver that can handle the device
 			 */
-			usb_find_interface_driver(dev, i);
+			usb_find_interface_driver(dev, interface);
 		}
 	}
 }
@@ -294,29 +306,7 @@
 }
 
 /**
- * usb_ifnum_to_ifpos - convert the interface number to the interface position
- * @dev: the device to use
- * @ifnum: the interface number (bInterfaceNumber); not interface position
- *
- * This is used to convert the interface _number_ (as in
- * interface.bInterfaceNumber) to the interface _position_ (as in
- * dev->actconfig->interface + position).  Note that the number is the same as
- * the position for all interfaces _except_ devices with interfaces not
- * sequentially numbered (e.g., 0, 2, 3, etc).
- */
-int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum)
-{
-	int i;
-
-	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
-		if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
-			return i;
-
-	return -EINVAL;
-}
-
-/**
- * usb_ifnum_to_if - get the interface object with a given interface number
+ * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
  * @dev: the device whose current configuration is considered
  * @ifnum: the desired interface
  *
@@ -392,7 +382,8 @@
 	/* now we check this device */
 	if (dev->devnum > 0)
 		for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
-			usb_find_interface_driver(dev, i);
+			usb_find_interface_driver (dev,
+				dev->actconfig->interface + i);
 }
 
 
@@ -475,7 +466,6 @@
 
 /**
  * usb_match_id - find first usb_device_id matching device or interface
- * @dev: the device whose descriptors are considered when matching
  * @interface: the interface of interest
  * @id: array of usb_device_id structures, terminated by zero entry
  *
@@ -537,15 +527,18 @@
  * its associated class and subclass.
  */   
 const struct usb_device_id *
-usb_match_id(struct usb_device *dev, struct usb_interface *interface,
-	     const struct usb_device_id *id)
+usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
 {
-	struct usb_interface_descriptor	*intf = 0;
+	struct usb_interface_descriptor *intf;
+	struct usb_device *dev;
 
 	/* proc_connectinfo in devio.c may call us with id == NULL. */
 	if (id == NULL)
 		return NULL;
 
+	intf = &interface->altsetting [interface->act_altsetting];
+	dev = interface_to_usbdev(interface);
+
 	/* It is important to check that id->driver_info is nonzero,
 	   since an entry that is all zeroes except for a nonzero
 	   id->driver_info is the way to create an entry that
@@ -584,19 +577,17 @@
 		    (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
 			continue;
 
-		intf = &interface->altsetting [interface->act_altsetting];
-
 		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
 		    (id->bInterfaceClass != intf->bInterfaceClass))
 			continue;
 
 		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
 		    (id->bInterfaceSubClass != intf->bInterfaceSubClass))
-		    continue;
+			continue;
 
 		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
 		    (id->bInterfaceProtocol != intf->bInterfaceProtocol))
-		    continue;
+			continue;
 
 		return id;
 	}
@@ -605,7 +596,7 @@
 }
 
 /*
- * This entrypoint gets called for each new device.
+ * This entrypoint gets called for unclaimed interfaces.
  *
  * We now walk the list of registered USB drivers,
  * looking for one that will accept this interface.
@@ -620,21 +611,27 @@
  *
  * Returns: 0 if a driver accepted the interface, -1 otherwise
  */
-static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
+int usb_find_interface_driver (
+	struct usb_device *dev,
+	struct usb_interface *interface
+)
 {
 	struct list_head *tmp;
-	struct usb_interface *interface;
 	void *private;
 	struct usb_driver *driver;
+	int ifnum;
 	
-	if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
-		err("bad find_interface_driver params");
-		return -1;
-	}
-
 	down(&dev->serialize);
 
-	interface = dev->actconfig->interface + ifnum;
+	/* FIXME It's just luck that for some devices with drivers that set
+	 * configuration in probe(), the interface numbers still make sense.
+	 * That's one of several unsafe assumptions involved in configuring
+	 * devices, and in binding drivers to their interfaces.
+	 */
+	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++)
+		if (&dev->actconfig->interface [ifnum] == interface)
+			break;
+	BUG_ON (ifnum == dev->actconfig->bNumInterfaces);
 
 	if (usb_interface_claimed(interface))
 		goto out_err;
@@ -645,7 +642,7 @@
 		driver = list_entry(tmp, struct usb_driver, driver_list);
 		tmp = tmp->next;
 
-		private = usb_bind_driver(driver, dev, ifnum);
+		private = usb_bind_driver(driver, interface);
 
 		/* probe() may have changed the config on us */
 		interface = dev->actconfig->interface + ifnum;
@@ -664,25 +661,6 @@
 	return -1;
 }
 
-/**
- * usb_find_interface_driver_for_ifnum - finds a usb interface driver for the specified ifnum
- * @dev: the device to use
- * @ifnum: the interface number (bInterfaceNumber); not interface position!
- *
- * This converts a ifnum to ifpos via a call to usb_ifnum_to_ifpos and then
- * calls usb_find_interface_driver() with the found ifpos.  Note
- * usb_find_interface_driver's ifnum parameter is actually interface position.
- */
-int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum)
-{
-	int ifpos = usb_ifnum_to_ifpos(dev, ifnum);
-
-	if (0 > ifpos)
-		return -EINVAL;
-
-	return usb_find_interface_driver(dev, ifpos);
-}
-
 #ifdef	CONFIG_HOTPLUG
 
 /*
@@ -836,7 +814,7 @@
 	return sprintf (buf, "%u\n", udev->actconfig->bConfigurationValue);
 }
 
-static DEVICE_ATTR(config,"configuration",S_IRUGO,show_config,NULL);
+static DEVICE_ATTR(configuration,S_IRUGO,show_config,NULL);
 
 /* interfaces have one current setting; alternates
  * can have different endpoints and class info.
@@ -851,7 +829,7 @@
 	interface = to_usb_interface (dev);
 	return sprintf (buf, "%u\n", interface->altsetting->bAlternateSetting);
 }
-static DEVICE_ATTR(altsetting,"altsetting",S_IRUGO,show_altsetting,NULL);
+static DEVICE_ATTR(altsetting,S_IRUGO,show_altsetting,NULL);
 
 /* product driverfs file */
 static ssize_t show_product (struct device *dev, char *buf, size_t count, loff_t off)
@@ -863,12 +841,14 @@
 		return 0;
 	udev = to_usb_device (dev);
 
-	len = usb_string(udev, udev->descriptor.iProduct, buf, PAGE_SIZE); 
+	len = usb_string(udev, udev->descriptor.iProduct, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
 	buf[len] = '\n';
-	buf[len+1] = 0x00;
+	buf[len+1] = 0;
 	return len+1;
 }
-static DEVICE_ATTR(product,"product",S_IRUGO,show_product,NULL);
+static DEVICE_ATTR(product,S_IRUGO,show_product,NULL);
 
 /* manufacturer driverfs file */
 static ssize_t
@@ -881,12 +861,14 @@
 		return 0;
 	udev = to_usb_device (dev);
 
-	len = usb_string(udev, udev->descriptor.iManufacturer, buf, PAGE_SIZE); 
+	len = usb_string(udev, udev->descriptor.iManufacturer, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
 	buf[len] = '\n';
-	buf[len+1] = 0x00;
+	buf[len+1] = 0;
 	return len+1;
 }
-static DEVICE_ATTR(manufacturer,"manufacturer",S_IRUGO,show_manufacturer,NULL);
+static DEVICE_ATTR(manufacturer,S_IRUGO,show_manufacturer,NULL);
 
 /* serial number driverfs file */
 static ssize_t
@@ -899,12 +881,14 @@
 		return 0;
 	udev = to_usb_device (dev);
 
-	len = usb_string(udev, udev->descriptor.iSerialNumber, buf, PAGE_SIZE); 
+	len = usb_string(udev, udev->descriptor.iSerialNumber, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
 	buf[len] = '\n';
-	buf[len+1] = 0x00;
+	buf[len+1] = 0;
 	return len+1;
 }
-static DEVICE_ATTR(serial,"serial",S_IRUGO,show_serial,NULL);
+static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL);
 
 /*
  * This entrypoint gets called for each new device.
@@ -918,13 +902,13 @@
 	unsigned claimed = 0;
 
 	/* FIXME should get called for each new configuration not just the
-	 * first one for a device. switching configs (or altesettings) should
+	 * first one for a device. switching configs (or altsettings) should
 	 * undo driverfs and HCD state for the previous interfaces.
 	 */
 	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
 		struct usb_interface *interface = &dev->actconfig->interface[ifnum];
 		struct usb_interface_descriptor *desc = interface->altsetting;
-		
+
 		/* register this interface with driverfs */
 		interface->dev.parent = &dev->dev;
 		interface->dev.bus = &usb_bus_type;
@@ -950,7 +934,7 @@
 
 		/* if this interface hasn't already been claimed */
 		if (!usb_interface_claimed(interface)) {
-			if (usb_find_interface_driver(dev, ifnum))
+			if (usb_find_interface_driver(dev, interface))
 				rejected++;
 			else
 				claimed++;
@@ -1073,56 +1057,6 @@
 }
 
 /*-------------------------------------------------------------------*/
-
-
-/* for returning string descriptors in UTF-16LE */
-static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
-{
-	int retval;
-
-	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
-		*utf++ = *ascii++ & 0x7f;
-		*utf++ = 0;
-	}
-	return retval;
-}
-
-/*
- * root_hub_string is used by each host controller's root hub code,
- * so that they're identified consistently throughout the system.
- */
-int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
-{
-	char buf [30];
-
-	// assert (len > (2 * (sizeof (buf) + 1)));
-	// assert (strlen (type) <= 8);
-
-	// language ids
-	if (id == 0) {
-		*data++ = 4; *data++ = 3;	/* 4 bytes data */
-		*data++ = 0; *data++ = 0;	/* some language id */
-		return 4;
-
-	// serial number
-	} else if (id == 1) {
-		sprintf (buf, "%x", serial);
-
-	// product description
-	} else if (id == 2) {
-		sprintf (buf, "USB %s Root Hub", type);
-
-	// id 3 == vendor description
-
-	// unsupported IDs --> "stall"
-	} else
-	    return 0;
-
-	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
-	data [1] = 3;
-	return data [0];
-}
-
 /*
  * __usb_get_extra_descriptor() finds a descriptor of specific type in the
  * extra field of the interface and endpoint descriptor structs.
@@ -1237,16 +1171,13 @@
 	 * won't have seen this, but not so for reinit ... 
 	 */
 	dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
-#ifndef DEVNUM_ROUND_ROBIN
-	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
-#else	/* round_robin alloc of devnums */
+
 	/* Try to allocate the next devnum beginning at bus->devnum_next. */
 	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
 	if (devnum >= 128)
 		devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 
 	dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
-#endif	/* round_robin alloc of devnums */
 
 	if (devnum < 128) {
 		set_bit(devnum, dev->bus->devmap.devicemap);
@@ -1434,7 +1365,7 @@
 	err = device_register (&dev->dev);
 	if (err)
 		return err;
-	device_create_file (&dev->dev, &dev_attr_config);
+	device_create_file (&dev->dev, &dev_attr_configuration);
 	if (dev->descriptor.iManufacturer)
 		device_create_file (&dev->dev, &dev_attr_manufacturer);
 	if (dev->descriptor.iProduct)
@@ -1455,6 +1386,152 @@
 }
 
 
+/**
+ * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP
+ * @dev: device the buffer will be used with
+ * @size: requested buffer size
+ * @mem_flags: affect whether allocation may block
+ * @dma: used to return DMA address of buffer
+ *
+ * Return value is either null (indicating no buffer could be allocated), or
+ * the cpu-space pointer to a buffer that may be used to perform DMA to the
+ * specified device.  Such cpu-space buffers are returned along with the DMA
+ * address (through the pointer provided).
+ *
+ * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to
+ * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
+ * hardware for long idle periods.  The implementation varies between
+ * platforms, depending on details of how DMA will work to this device.
+ *
+ * When the buffer is no longer used, free it with usb_buffer_free().
+ */
+void *usb_buffer_alloc (
+	struct usb_device *dev,
+	size_t size,
+	int mem_flags,
+	dma_addr_t *dma
+)
+{
+	if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
+		return 0;
+	return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
+}
+
+/**
+ * usb_buffer_free - free memory allocated with usb_buffer_alloc()
+ * @dev: device the buffer was used with
+ * @size: requested buffer size
+ * @addr: CPU address of buffer
+ * @dma: DMA address of buffer
+ *
+ * This reclaims an I/O buffer, letting it be reused.  The memory must have
+ * been allocated using usb_buffer_alloc(), and the parameters must match
+ * those provided in that allocation request. 
+ */
+void usb_buffer_free (
+	struct usb_device *dev,
+	size_t size,
+	void *addr,
+	dma_addr_t dma
+)
+{
+	if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
+	    	return;
+	dev->bus->op->buffer_free (dev->bus, size, addr, dma);
+}
+
+/**
+ * usb_buffer_map - create DMA mapping(s) for an urb
+ * @urb: urb whose transfer_buffer will be mapped
+ *
+ * Return value is either null (indicating no buffer could be mapped), or
+ * the parameter.  URB_NO_DMA_MAP is added to urb->transfer_flags if the
+ * operation succeeds.
+ *
+ * This call would normally be used for an urb which is reused, perhaps
+ * as the target of a large periodic transfer, with usb_buffer_dmasync()
+ * calls to synchronize memory and dma state.  It may not be used for
+ * control requests.
+ *
+ * Reverse the effect of this call with usb_buffer_unmap().
+ */
+struct urb *usb_buffer_map (struct urb *urb)
+{
+	struct usb_bus		*bus;
+	struct usb_operations	*op;
+
+	if (!urb
+			|| usb_pipecontrol (urb->pipe)
+			|| !urb->dev
+			|| !(bus = urb->dev->bus)
+			|| !(op = bus->op)
+			|| !op->buffer_map)
+		return 0;
+
+	if (op->buffer_map (bus,
+			urb->transfer_buffer,
+			&urb->transfer_dma,
+			urb->transfer_buffer_length,
+			usb_pipein (urb->pipe)
+				? USB_DIR_IN
+				: USB_DIR_OUT))
+		return 0;
+	urb->transfer_flags |= URB_NO_DMA_MAP;
+	return urb;
+}
+
+/**
+ * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
+ * @urb: urb whose transfer_buffer will be synchronized
+ */
+void usb_buffer_dmasync (struct urb *urb)
+{
+	struct usb_bus		*bus;
+	struct usb_operations	*op;
+
+	if (!urb
+			|| !(urb->transfer_flags & URB_NO_DMA_MAP)
+			|| !urb->dev
+			|| !(bus = urb->dev->bus)
+			|| !(op = bus->op)
+			|| !op->buffer_dmasync)
+		return;
+
+	op->buffer_dmasync (bus,
+			urb->transfer_dma,
+			urb->transfer_buffer_length,
+			usb_pipein (urb->pipe)
+				? USB_DIR_IN
+				: USB_DIR_OUT);
+}
+
+/**
+ * usb_buffer_unmap - free DMA mapping(s) for an urb
+ * @urb: urb whose transfer_buffer will be unmapped
+ *
+ * Reverses the effect of usb_buffer_map().
+ */
+void usb_buffer_unmap (struct urb *urb)
+{
+	struct usb_bus		*bus;
+	struct usb_operations	*op;
+
+	if (!urb
+			|| !(urb->transfer_flags & URB_NO_DMA_MAP)
+			|| !urb->dev
+			|| !(bus = urb->dev->bus)
+			|| !(op = bus->op)
+			|| !op->buffer_unmap)
+		return;
+
+	op->buffer_unmap (bus,
+			urb->transfer_dma,
+			urb->transfer_buffer_length,
+			usb_pipein (urb->pipe)
+				? USB_DIR_IN
+				: USB_DIR_OUT);
+}
+
 #ifdef CONFIG_PROC_FS
 struct list_head *usb_driver_get_list(void)
 {
@@ -1489,10 +1566,10 @@
  */
 static void __exit usb_exit(void)
 {
-	put_bus(&usb_bus_type);
 	usb_major_cleanup();
 	usbfs_cleanup();
 	usb_hub_cleanup();
+	put_bus(&usb_bus_type);
 }
 
 subsys_initcall(usb_init);
@@ -1503,8 +1580,6 @@
  * These symbols are exported for device (or host controller)
  * driver modules to use.
  */
-EXPORT_SYMBOL(usb_ifnum_to_ifpos);
-EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
 EXPORT_SYMBOL(usb_register);
@@ -1516,22 +1591,25 @@
 EXPORT_SYMBOL(usb_get_dev);
 EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
-EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
 EXPORT_SYMBOL(usb_match_id);
 
-EXPORT_SYMBOL(usb_root_hub_string);
 EXPORT_SYMBOL(usb_new_device);
 EXPORT_SYMBOL(usb_reset_device);
 EXPORT_SYMBOL(usb_connect);
 EXPORT_SYMBOL(usb_disconnect);
-EXPORT_SYMBOL(usb_bind_driver);
-EXPORT_SYMBOL(usb_unbind_driver);
 
 EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
 EXPORT_SYMBOL(usb_get_current_frame_number);
+
+EXPORT_SYMBOL (usb_buffer_alloc);
+EXPORT_SYMBOL (usb_buffer_free);
+
+EXPORT_SYMBOL (usb_buffer_map);
+EXPORT_SYMBOL (usb_buffer_dmasync);
+EXPORT_SYMBOL (usb_buffer_unmap);
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/host/ehci-dbg.c	Tue Aug 27 12:28:02 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -175,3 +175,215 @@
 		(status & PORT_CONNECT) ? " CONNECT" : "" \
 	    )
 
+#ifdef DEBUG
+
+#define speed_char(info1) ({ char tmp; \
+		switch (info1 & (3 << 12)) { \
+		case 0 << 12: tmp = 'f'; break; \
+		case 1 << 12: tmp = 'l'; break; \
+		case 2 << 12: tmp = 'h'; break; \
+		default: tmp = '?'; break; \
+		}; tmp; })
+
+static ssize_t
+show_async (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct ehci_qh		*qh;
+
+	if (off != 0)
+		return 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	if (ehci->async) {
+		qh = ehci->async;
+		do {
+			u32			scratch;
+			struct list_head	*entry;
+			struct ehci_qtd		*td;
+
+			scratch = cpu_to_le32p (&qh->hw_info1);
+			temp = snprintf (next, size, "qh %p dev%d %cs ep%d",
+					qh, scratch & 0x007f,
+					speed_char (scratch),
+					(scratch >> 8) & 0x000f);
+			size -= temp;
+			next += temp;
+
+			list_for_each (entry, &qh->qtd_list) {
+				td = list_entry (entry, struct ehci_qtd,
+						qtd_list);
+				scratch = cpu_to_le32p (&td->hw_token);
+				temp = snprintf (next, size,
+						", td %p len=%d %s",
+						td, scratch >> 16,
+						({ char *tmp;
+						 switch ((scratch>>8)&0x03) {
+						 case 0: tmp = "out"; break;
+						 case 1: tmp = "in"; break;
+						 case 2: tmp = "setup"; break;
+						 default: tmp = "?"; break;
+						 } tmp;})
+						);
+				size -= temp;
+				next += temp;
+			}
+
+			temp = snprintf (next, size, "\n");
+			size -= temp;
+			next += temp;
+
+		} while ((qh = qh->qh_next.qh) != ehci->async);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return count - size;
+}
+static DEVICE_ATTR (async, S_IRUSR, show_async, NULL);
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	union ehci_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i, tag;
+
+	if (off != 0)
+		return 0;
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	temp = snprintf (next, size, "size = %d\n", ehci->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ehci->periodic_size; i++) {
+		p = ehci->pshadow [i];
+		if (!p.ptr)
+			continue;
+		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+
+		temp = snprintf (next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			switch (tag) {
+			case Q_TYPE_QH:
+				temp = snprintf (next, size, " intr-%d %p",
+						p.qh->period, p.qh);
+				size -= temp;
+				next += temp;
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen [temp].ptr == p.ptr)
+						break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count) {
+					u32	scratch = cpu_to_le32p (
+							&p.qh->hw_info1);
+
+					temp = snprintf (next, size,
+						" (%cs dev%d ep%d)",
+						speed_char (scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f);
+
+					/* FIXME TDs too */
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen [seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				tag = Q_NEXT_TYPE (p.qh->hw_next);
+				p = p.qh->qh_next;
+				break;
+			case Q_TYPE_FSTN:
+				temp = snprintf (next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = snprintf (next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				temp = snprintf (next, size,
+					" sitd/%p", p.sitd);
+				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				p = p.sitd->sitd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	kfree (seen);
+
+	return count - size;
+}
+static DEVICE_ATTR (periodic, S_IRUSR, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static inline void create_debug_files (struct ehci_hcd *bus)
+{
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+}
+
+static inline void remove_debug_files (struct ehci_hcd *bus)
+{
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+}
+
+#else /* DEBUG */
+
+static inline void create_debug_files (struct ehci_hcd *bus)
+{
+}
+
+static inline void remove_debug_files (struct ehci_hcd *bus)
+{
+}
+
+#endif /* DEBUG */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/host/ehci-hcd.c	Tue Aug 27 12:28:07 2002
@@ -65,6 +65,8 @@
  *
  * HISTORY:
  *
+ * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
+ *	only scheduling is different, no arbitrary limitations.
  * 2002-07-25	Sanity check PCI reads, mostly for better cardbus support,
  * 	clean up HC run state handshaking.
  * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
@@ -85,7 +87,7 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-Jul-25"
+#define DRIVER_VERSION "2002-Aug-06"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -93,6 +95,8 @@
 // #define EHCI_VERBOSE_DEBUG
 // #define have_split_iso
 
+#define INTR_AUTOMAGIC		/* to be removed later in 2.5 */
+
 /* magic numbers that can affect system performance */
 #define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
 #define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
@@ -376,6 +380,8 @@
 		return -ENOMEM;
 	}
 
+	create_debug_files (ehci);
+
 	/*
 	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
 	 * are explicitly handed to companion controller(s), so no TT is
@@ -429,6 +435,8 @@
 		ehci_ready (ehci);
 	ehci_reset (ehci);
 
+	remove_debug_files (ehci);
+
 	/* root hub is shut down separately (first, when possible) */
 	tasklet_disable (&ehci->tasklet);
 	ehci_tasklet ((unsigned long) ehci);
@@ -614,7 +622,8 @@
  *
  * hcd-specific init for hcpriv hasn't been done yet
  *
- * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
@@ -626,10 +635,11 @@
 
 	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
 	INIT_LIST_HEAD (&qtd_list);
-	switch (usb_pipetype (urb->pipe)) {
 
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 		return submit_async (ehci, urb, &qtd_list, mem_flags);
@@ -649,9 +659,6 @@
 		dbg ("no split iso support yet");
 		return -ENOSYS;
 #endif /* have_split_iso */
-
-	default:	/* can't happen */
-		return -ENOSYS;
 	}
 }
 
@@ -665,15 +672,16 @@
 	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
 	unsigned long		flags;
 
-	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->self.bus_name, urb, qh->qh_state);
+	dbg ("%s urb_dequeue %p qh %p state %d",
+		hcd->self.bus_name, urb, qh, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		spin_lock_irqsave (&ehci->lock, flags);
 		if (ehci->reclaim) {
-dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
 			if (in_interrupt ()) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
 				return -EAGAIN;
@@ -683,28 +691,43 @@
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
-// yeech ... this could spin for up to two frames!
-dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
-    qh->qh_state, ehci->reclaim, ehci->hcd.state
-);
-				udelay (100);
+				/* let pending unlinks complete */
+				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
 		}
 		if (qh->qh_state == QH_STATE_LINKED)
 			start_unlink_async (ehci, qh);
 		spin_unlock_irqrestore (&ehci->lock, flags);
-		return 0;
+		break;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh,
-			(urb->dev->speed == USB_SPEED_HIGH)
-			    ? urb->interval
-			    : (urb->interval << 3));
-		if (ehci->hcd.state == USB_STATE_HALT)
-			urb->status = -ESHUTDOWN;
-		qh_completions (ehci, qh, 1);
-		return 0;
+		if (qh->qh_state == QH_STATE_LINKED) {
+			/* messy, can spin or block a microframe ... */
+			intr_deschedule (ehci, qh, 1);
+			/* qh_state == IDLE */
+		}
+		qh_completions (ehci, qh);
+
+		/* reschedule QH iff another request is queued */
+		if (!list_empty (&qh->qtd_list)
+				&& HCD_IS_RUNNING (ehci->hcd.state)) {
+			int status;
+
+			spin_lock_irqsave (&ehci->lock, flags);
+			status = qh_schedule (ehci, qh);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+
+			if (status != 0) {
+				// shouldn't happen often, but ...
+				// FIXME kill those tds' urbs
+				err ("can't reschedule qh %p, err %d",
+					qh, status);
+			}
+			return status;
+		}
+
+		break;
 
 	case PIPE_ISOCHRONOUS:
 		// itd or sitd ...
@@ -712,9 +735,9 @@
 		// wait till next completion, do it then.
 		// completion irqs can wait up to 1024 msec,
 		urb->transfer_flags |= EHCI_STATE_UNLINK;
-		return 0;
+		break;
 	}
-	return -EINVAL;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -728,6 +751,7 @@
 	int			i;
 	unsigned long		flags;
 
+	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
 	dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
@@ -736,34 +760,57 @@
 	for (i = 0; i < 32; i++) {
 		if (dev->ep [i]) {
 			struct ehci_qh		*qh;
+			char			*why;
 
 			/* dev->ep never has ITDs or SITDs */
 			qh = (struct ehci_qh *) dev->ep [i];
-			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
-			if (!list_empty (&qh->qtd_list)) {
-				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+
+			/* detect/report non-recoverable errors */
+			if (in_interrupt ()) 
+				why = "disconnect() didn't";
+			else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0
+					&& qh->qh_state != QH_STATE_IDLE)
+				why = "(active periodic)";
+			else
+				why = 0;
+			if (why) {
+				err ("dev %s-%s ep %d-%s error: %s",
+					hcd->self.bus_name, udev->devpath,
+					i & 0xf, (i & 0x10) ? "IN" : "OUT",
+					why);
 				BUG ();
 			}
-			dev->ep [i] = 0;
 
-			/* wait_ms() won't spin here -- we're a thread */
+			dev->ep [i] = 0;
+			if (qh->qh_state == QH_STATE_IDLE)
+				goto idle;
+			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+
+			/* scan_async() empties the ring as it does its work,
+			 * using IAA, but doesn't (yet?) turn it off.  if it
+			 * doesn't empty this qh, likely it's the last entry.
+			 */
 			while (qh->qh_state == QH_STATE_LINKED
 					&& ehci->reclaim
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
+				/* wait_ms() won't spin, we're a thread;
+				 * and we know IRQ+tasklet can progress
+				 */
 				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
-			if (qh->qh_state == QH_STATE_LINKED) {
+			if (qh->qh_state == QH_STATE_LINKED)
 				start_unlink_async (ehci, qh);
-				while (qh->qh_state != QH_STATE_IDLE) {
-					spin_unlock_irqrestore (&ehci->lock,
-						flags);
-					wait_ms (1);
-					spin_lock_irqsave (&ehci->lock, flags);
-				}
+			while (qh->qh_state != QH_STATE_IDLE
+					&& ehci->hcd.state != USB_STATE_HALT) {
+				spin_unlock_irqrestore (&ehci->lock,
+					flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
 			}
+idle:
 			qh_put (ehci, qh);
 		}
 	}
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/host/ehci-q.c	Tue Aug 27 12:28:02 2002
@@ -47,9 +47,11 @@
 qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
 {
 	int	i, count;
+	u64	addr = buf;
 
 	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	if (likely (len < count))		/* ... iff needed */
 		count = len;
@@ -59,7 +61,7 @@
 
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		for (i = 1; count < len && i < 5; i++) {
-			u64	addr = buf;
+			addr = buf;
 			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
 			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
 			buf += 0x1000;
@@ -157,46 +159,35 @@
 	}
 }
 
-static void ehci_urb_complete (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
-		pci_dma_sync_single (ehci->hcd.pdev, addr,
-			urb->transfer_buffer_length,
-			PCI_DMA_FROMDEVICE);
-
-	/* cleanse status if we saw no error */
-	if (likely (urb->status == -EINPROGRESS)) {
-		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & URB_SHORT_NOT_OK))
-			urb->status = -EREMOTEIO;
-		else
-			urb->status = 0;
-	}
-
-	/* only report unlinks once */
-	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
-		urb->complete (urb);
-}
-
 /* urb->lock ignored from here on (hcd is done with urb) */
 
 static void ehci_urb_done (
 	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
 	struct urb		*urb
 ) {
-	if (urb->transfer_buffer_length)
-		pci_unmap_single (ehci->hcd.pdev,
-			addr,
-			urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
+#ifdef	INTR_AUTOMAGIC
+	struct urb		*resubmit = 0;
+	struct usb_device	*dev = 0;
+#endif
+
 	if (likely (urb->hcpriv != 0)) {
-		qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
+		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
+
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
+
+			/* ... update hc-wide periodic stats (for usbfs) */
+			ehci->hcd.self.bandwidth_int_reqs--;
+
+#ifdef	INTR_AUTOMAGIC
+			if (!((urb->status == -ENOENT)
+					|| (urb->status == -ECONNRESET))) {
+				resubmit = usb_get_urb (urb);
+				dev = urb->dev;
+			}
+#endif
+		}
+		qh_put (ehci, qh);
 		urb->hcpriv = 0;
 	}
 
@@ -208,33 +199,46 @@
 			urb->status = 0;
 	}
 
-	/* hand off urb ownership */
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
+
+#ifdef	INTR_AUTOMAGIC
+	if (resubmit && ((urb->status == -ENOENT)
+				|| (urb->status == -ECONNRESET))) {
+		usb_put_urb (resubmit);
+		resubmit = 0;
+	}
+	// device drivers will soon be doing something like this
+	if (resubmit) {
+		int	status;
+
+		resubmit->dev = dev;
+		status = usb_submit_urb (resubmit, SLAB_KERNEL);
+		if (status != 0)
+			err ("can't resubmit interrupt urb %p: status %d",
+					resubmit, status);
+		usb_put_urb (resubmit);
+	}
+#endif
 }
 
 
 /*
  * Process completed qtds for a qh, issuing completions if needed.
- * When freeing:  frees qtds, unmaps buf, returns URB to driver.
- * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
+ * Frees qtds, unmaps buf, returns URB to driver.
  * Races up to qh->hw_current; returns number of urb completions.
  */
-static int
-qh_completions (
-	struct ehci_hcd		*ehci,
-	struct ehci_qh		*qh,
-	int			freeing
-) {
+static void
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
 	struct ehci_qtd		*qtd, *last;
 	struct list_head	*next, *qtd_list = &qh->qtd_list;
 	int			unlink = 0, halted = 0;
 	unsigned long		flags;
-	int			retval = 0;
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely (list_empty (qtd_list))) {
 		spin_unlock_irqrestore (&ehci->lock, flags);
-		return retval;
+		return;
 	}
 
 	/* scan QTDs till end of list, or we reach an active one */
@@ -251,14 +255,8 @@
 			if (likely (last->urb != urb)) {
 				/* complete() can reenter this HCD */
 				spin_unlock_irqrestore (&ehci->lock, flags);
-				if (likely (freeing != 0))
-					ehci_urb_done (ehci, last->buf_dma,
-						last->urb);
-				else
-					ehci_urb_complete (ehci, last->buf_dma,
-						last->urb);
+				ehci_urb_done (ehci, last->urb);
 				spin_lock_irqsave (&ehci->lock, flags);
-				retval++;
 			}
 
 			/* qh overlays can have HC's old cached copies of
@@ -270,8 +268,7 @@
 				qh->hw_qtd_next = last->hw_next;
 			}
 
-			if (likely (freeing != 0))
-				ehci_qtd_free (ehci, last);
+			ehci_qtd_free (ehci, last);
 			last = 0;
 		}
 		next = qtd->qtd_list.next;
@@ -288,7 +285,7 @@
 
 		/* fault: unlink the rest, since this qtd saw an error? */
 		if (unlikely ((token & QTD_STS_HALT) != 0)) {
-			freeing = unlink = 1;
+			unlink = 1;
 			/* status copied below */
 
 		/* QH halts only because of fault (above) or unlink (here). */
@@ -296,13 +293,14 @@
 
 			/* unlinking everything because of HC shutdown? */
 			if (ehci->hcd.state == USB_STATE_HALT) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* explicit unlink, maybe starting here? */
 			} else if (qh->qh_state == QH_STATE_IDLE
 					&& (urb->status == -ECONNRESET
+						|| urb->status == -ESHUTDOWN
 						|| urb->status == -ENOENT)) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* QH halted to unlink urbs _after_ this?  */
 			} else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
@@ -312,7 +310,7 @@
 
 			/* unlink the rest?  once we start unlinking, after
 			 * a fault or explicit unlink, we unlink all later
-			 * urbs.  usb spec requires that.
+			 * urbs.  usb spec requires that for faults...
 			 */
 			if (unlink && urb->status == -EINPROGRESS)
 				urb->status = -ECONNRESET;
@@ -330,31 +328,7 @@
 		qtd_copy_status (urb, qtd->length, token);
 		spin_unlock (&urb->lock);
 
-		/*
-		 * NOTE:  this won't work right with interrupt urbs that
-		 * need multiple qtds ... only the first scan of qh->qtd_list
-		 * starts at the right qtd, yet multiple scans could happen
-		 * for transfers that are scheduled across multiple uframes. 
-		 * (Such schedules are not currently allowed!)
-		 */
-		if (likely (freeing != 0))
-			list_del (&qtd->qtd_list);
-		else {
-			/* restore everything the HC could change
-			 * from an interrupt QTD
-			 */
-			qtd->hw_token = (qtd->hw_token
-					& __constant_cpu_to_le32 (0x8300))
-				| cpu_to_le32 (qtd->length << 16)
-				| __constant_cpu_to_le32 (QTD_STS_ACTIVE
-					| (EHCI_TUNE_CERR << 10));
-			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
-
-			/* this offset, and the length above,
-			 * are likely wrong on QTDs #2..N
-			 */
-			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
-		}
+		list_del (&qtd->qtd_list);
 
 #if 0
 		if (urb->status == -EINPROGRESS)
@@ -365,12 +339,6 @@
 				urb, urb->status, qtd, token,
 				urb->actual_length);
 #endif
-
-		/* SETUP for control urb? */
-		if (unlikely (QTD_PID (token) == 2))
-			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
 	}
 
 	/* patch up list head? */
@@ -382,14 +350,9 @@
 
 	/* last urb's completion might still need calling */
 	if (likely (last != 0)) {
-		if (likely (freeing != 0)) {
-			ehci_urb_done (ehci, last->buf_dma, last->urb);
-			ehci_qtd_free (ehci, last);
-		} else
-			ehci_urb_complete (ehci, last->buf_dma, last->urb);
-		retval++;
+		ehci_urb_done (ehci, last->urb);
+		ehci_qtd_free (ehci, last);
 	}
-	return retval;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -428,10 +391,6 @@
 				size = qtd->urb->transfer_buffer_length;
 				unmapped++;
 			}
-			if (qtd->buf_dma)
-				pci_unmap_single (ehci->hcd.pdev,
-					qtd->buf_dma,
-					size, direction);
 		}
 		ehci_qtd_free (ehci, qtd);
 	}
@@ -448,8 +407,9 @@
 	int			flags
 ) {
 	struct ehci_qtd		*qtd, *qtd_prev;
-	dma_addr_t		buf, map_buf;
+	dma_addr_t		buf;
 	int			len, maxpacket;
+	int			is_input;
 	u32			token;
 
 	/*
@@ -467,17 +427,8 @@
 	/* for split transactions, SplitXState initialized to zero */
 
 	if (usb_pipecontrol (urb->pipe)) {
-		/* control request data is passed in the "setup" pid */
-		qtd->buf_dma = pci_map_single (
-					ehci->hcd.pdev,
-					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
-					PCI_DMA_TODEVICE);
-		if (unlikely (!qtd->buf_dma))
-			goto cleanup;
-
 		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
+		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
 			token | (2 /* "setup" */ << 8));
 
 		/* ... and always at least one more pid */
@@ -495,23 +446,17 @@
 	 * data transfer stage:  buffer setup
 	 */
 	len = urb->transfer_buffer_length;
-	if (likely (len > 0)) {
-		buf = map_buf = pci_map_single (ehci->hcd.pdev,
-			urb->transfer_buffer, len,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-		if (unlikely (!buf))
-			goto cleanup;
-	} else
-		buf = map_buf = 0;
+	is_input = usb_pipein (urb->pipe);
+	if (likely (len > 0))
+		buf = urb->transfer_dma;
+	else
+		buf = 0;
 
-	if (!buf || usb_pipein (urb->pipe))
+	if (!buf || is_input)
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
-			usb_pipeout (urb->pipe));
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -522,7 +467,6 @@
 		int this_qtd_len;
 
 		qtd->urb = urb;
-		qtd->buf_dma = map_buf;
 		this_qtd_len = qtd_fill (qtd, buf, len, token);
 		len -= this_qtd_len;
 		buf += this_qtd_len;
@@ -607,6 +551,11 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
+
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -624,6 +573,8 @@
 ) {
 	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
 	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
 
 	if (!qh)
 		return qh;
@@ -634,6 +585,53 @@
 	info1 |= usb_pipeendpoint (urb->pipe) << 8;
 	info1 |= usb_pipedevice (urb->pipe) << 0;
 
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			/* FIXME handle HS periods of less than 1 frame. */
+			qh->period = urb->interval >> 3;
+			if (qh->period < 1) {
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				qh = 0;
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
 	/* using TT? */
 	switch (urb->dev->speed) {
 	case USB_SPEED_LOW:
@@ -643,67 +641,63 @@
 	case USB_SPEED_FULL:
 		/* EPS 0 means "full" */
 		info1 |= (EHCI_TUNE_RL_TT << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= (1 << 27);	/* for TT */
 			info1 |= 1 << 14;	/* toggle from qtd */
 		}
-		info1 |= usb_maxpacket (urb->dev, urb->pipe,
-					usb_pipeout (urb->pipe)) << 16;
+		info1 |= maxp << 16;
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
 		info2 |= urb->dev->tt->hub->devnum << 16;
 
-		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
-		 * ... and a 0.96 scheduler might use FSTN nodes too
-		 */
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
 		break;
 
 	case USB_SPEED_HIGH:		/* no TT involved */
 		info1 |= (2 << 12);	/* EPS "high" */
 		info1 |= (EHCI_TUNE_RL_HS << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else if (usb_pipebulk (urb->pipe)) {
+		} else if (type == PIPE_BULK) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else {
-			u32	temp;
-			temp = usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe));
-			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
-			/* HS intr can be "high bandwidth" */
-			temp = 1 + ((temp >> 11) & 0x03);
-			info2 |= temp << 30;		/* mult */
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
 		}
 		break;
-	default:
 #ifdef DEBUG
+	default:
 		BUG ();
 #endif
 	}
 
-	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
 
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
 	qh->hw_info2 = cpu_to_le32 (info2);
 
 	/* initialize sw and hw queues with these qtds */
-	list_splice (qtd_list, &qh->qtd_list);
-	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	if (!list_empty (qtd_list)) {
+		list_splice (qtd_list, &qh->qtd_list);
+		qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	} else {
+		qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END;
+	}
 
 	/* initialize data toggle state */
-	if (!usb_pipecontrol (urb->pipe))
-		clear_toggle (urb->dev,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe),
-			qh);
+	clear_toggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, qh);
 
+done:
 	return qh;
 }
+#undef hb_mult
+#undef hb_packet
 
 /*-------------------------------------------------------------------------*/
 
@@ -745,50 +739,48 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int
-submit_async (
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	struct ehci_qtd		*qtd;
-	struct hcd_dev		*dev;
-	int			epnum;
-	unsigned long		flags;
+	int			epnum,
+	void			**ptr
+)
+{
 	struct ehci_qh		*qh = 0;
 
-	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
-		qtd, dev ? dev->ep [epnum] : (void *)~0);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	qh = (struct ehci_qh *) dev->ep [epnum];
+	qh = (struct ehci_qh *) *ptr;
 	if (likely (qh != 0)) {
-		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+		struct ehci_qtd	*qtd;
+
+		if (unlikely (list_empty (qtd_list)))
+			qtd = 0;
+		else
+			qtd = list_entry (qtd_list->next, struct ehci_qtd,
+					qtd_list);
 
 		/* maybe patch the qh used for set_address */
 		if (unlikely (epnum == 0
 				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
 			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
 
-		/* is an URB is queued to this qh already? */
-		if (unlikely (!list_empty (&qh->qtd_list))) {
+		/* append to tds already queued to this qh? */
+		if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
 			struct ehci_qtd		*last_qtd;
 			int			short_rx = 0;
+			u32			hw_next;
 
 			/* update the last qtd's "next" pointer */
 			// dbg_qh ("non-empty qh", ehci, qh);
 			last_qtd = list_entry (qh->qtd_list.prev,
 					struct ehci_qtd, qtd_list);
+			hw_next = QTD_NEXT (qtd->qtd_dma);
 			last_qtd->hw_next = hw_next;
 
 			/* previous urb allows short rx? maybe optimize. */
@@ -803,6 +795,7 @@
 			 * Interrupt code must cope with case of HC having it
 			 * cached, and clobbering these updates.
 			 * ... complicates getting rid of extra interrupts!
+			 * (Or:  use dummy td, so cache always stays valid.)
 			 */
 			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
 				wmb ();
@@ -822,31 +815,61 @@
 			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
-			if (usb_pipebulk (urb->pipe)
-					&& unlikely (!usb_gettoggle (urb->dev,
+			if (unlikely (!usb_gettoggle (urb->dev,
 						(epnum & 0x0f),
 						!(epnum & 0x10)))) {
 				clear_toggle (urb->dev,
 					epnum & 0x0f, !(epnum & 0x10), qh);
 			}
-			qh_update (qh, qtd);
+			if (qtd)
+				qh_update (qh, qtd);
 		}
 		list_splice (qtd_list, qh->qtd_list.prev);
 
 	} else {
 		/* can't sleep here, we have ehci->lock... */
 		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg_qh ("new qh", ehci, qh);
-			dev->ep [epnum] = qh;
-		}
+		// if (qh) dbg_qh ("new qh", ehci, qh);
+		*ptr = qh;
 	}
+	if (qh)
+		urb->hcpriv = qh_get (qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
 
 	/* Control/bulk operations through TTs don't need scheduling,
 	 * the HC and TT handle it when the TT has a buffer ready.
 	 */
 	if (likely (qh != 0)) {
-		urb->hcpriv = qh_get (qh);
 		if (likely (qh->qh_state == QH_STATE_IDLE))
 			qh_link_async (ehci, qh_get (qh));
 	}
@@ -873,7 +896,7 @@
 	ehci->reclaim = 0;
 	ehci->reclaim_ready = 0;
 
-	qh_completions (ehci, qh, 1);
+	qh_completions (ehci, qh);
 
 	// unlink any urb should now unlink all following urbs, so that
 	// relinking only happens for urbs before the unlinked ones.
@@ -973,13 +996,15 @@
 				spin_unlock_irqrestore (&ehci->lock, flags);
 
 				/* concurrent unlink could happen here */
-				qh_completions (ehci, qh, 1);
+				qh_completions (ehci, qh);
 
 				spin_lock_irqsave (&ehci->lock, flags);
 				qh_put (ehci, qh);
 			}
 
-			/* unlink idle entries (reduces PCI usage) */
+			/* unlink idle entries, reducing HC PCI usage as
+			 * well as HCD schedule-scanning costs
+			 */
 			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
 				if (qh->qh_next.qh != qh) {
 					// dbg ("irq/empty");
@@ -987,6 +1012,7 @@
 				} else {
 					// FIXME:  arrange to stop
 					// after it's been idle a while.
+					// stop/restart isn't free...
 				}
 			}
 			qh = qh->qh_next.qh;
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/host/ehci-sched.c	Tue Aug 27 12:28:02 2002
@@ -220,31 +220,31 @@
 
 /*-------------------------------------------------------------------------*/
 
+// FIXME microframe periods not yet handled
+
 static void intr_deschedule (
 	struct ehci_hcd	*ehci,
-	unsigned	frame,
 	struct ehci_qh	*qh,
-	unsigned	period
+	int		wait
 ) {
 	unsigned long	flags;
 	int		status;
-
-	period >>= 3;		// FIXME microframe periods not handled yet
+	unsigned	frame = qh->start;
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	do {
 		periodic_unlink (ehci, frame, qh);
 		qh_put (ehci, qh);
-		frame += period;
+		frame += qh->period;
 	} while (frame < ehci->periodic_size);
 
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_next.ptr = 0;
-	ehci->periodic_urbs--;
+	ehci->periodic_sched--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		status = disable_periodic (ehci);
 	else {
 		status = 0;
@@ -258,21 +258,35 @@
 	 * (yeech!) to be sure it's done.
 	 * No other threads may be mucking with this qh.
 	 */
-	if (!status && ((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
-		udelay (125);
+	if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
+		if (wait) {
+			udelay (125);
+			qh->hw_next = EHCI_LIST_END;
+		} else {
+			/* we may not be IDLE yet, but if the qh is empty
+			 * the race is very short.  then if qh also isn't
+			 * rescheduled soon, it won't matter.  otherwise...
+			 */
+			vdbg ("intr_deschedule...");
+		}
+	} else
+		qh->hw_next = EHCI_LIST_END;
 
 	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_next = EHCI_LIST_END;
+
+	/* update per-qh bandwidth utilization (for usbfs) */
+	ehci->hcd.self.bandwidth_allocated -= 
+		(qh->usecs + qh->c_usecs) / qh->period;
 
 	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
-		qh, period, frame,
-		atomic_read (&qh->refcount), ehci->periodic_urbs);
+		qh, qh->period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_sched);
 }
 
 static int check_period (
 	struct ehci_hcd *ehci, 
 	unsigned	frame,
-	int		uframe,
+	unsigned	uframe,
 	unsigned	period,
 	unsigned	usecs
 ) {
@@ -309,19 +323,142 @@
 	return 1;
 }
 
+static int check_intr_schedule (
+	struct ehci_hcd		*ehci, 
+	unsigned		frame,
+	unsigned		uframe,
+	const struct ehci_qh	*qh,
+	u32			*c_maskp
+)
+{
+    	int		retval = -ENOSPC;
+
+	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = cpu_to_le32 (0);
+		goto done;
+	}
+
+	/* This is a split transaction; check the bandwidth available for
+	 * the completion too.  Check both worst and best case gaps: worst
+	 * case is SPLIT near uframe end, and CSPLIT near start ... best is
+	 * vice versa.  Difference can be almost two uframe times, but we
+	 * reserve unnecessary bandwidth (waste it) this way.  (Actually
+	 * even better cases exist, like immediate device NAK.)
+	 *
+	 * FIXME don't even bother unless we know this TT is idle in that
+	 * range of uframes ... for now, check_period() allows only one
+	 * interrupt transfer per frame, so needn't check "TT busy" status
+	 * when scheduling a split (QH, SITD, or FSTN).
+	 *
+	 * FIXME ehci 0.96 and above can use FSTNs
+	 */
+	if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
+				qh->period, qh->c_usecs))
+		goto done;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf,
+				qh->period, qh->c_usecs))
+		goto done;
+
+	*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf));
+	retval = 0;
+done:
+	return retval;
+}
+
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int 		status;
+	unsigned	uframe;
+	u32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
+
+	qh->hw_next = EHCI_LIST_END;
+	frame = qh->start;
+
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+		status = check_intr_schedule (ehci, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
+		status = -ENOSPC;
+	}
+
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		frame = qh->period - 1;
+		do {
+			for (uframe = 0; uframe < 8; uframe++) {
+				status = check_intr_schedule (ehci,
+						frame, uframe, qh,
+						&c_mask);
+				if (status == 0)
+					break;
+			}
+		} while (status && --frame);
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		qh->hw_info2 &= ~0xffff;
+		qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
+	} else
+		dbg ("reused previous qh %p schedule", qh);
+
+	/* stuff into the periodic schedule */
+	qh->qh_state = QH_STATE_LINKED;
+	dbg ("qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
+		qh, qh->usecs, qh->c_usecs,
+		qh->period, frame, uframe, qh->gap_uf);
+	do {
+		if (unlikely (ehci->pshadow [frame].ptr != 0)) {
+
+// FIXME -- just link toward the end, before any qh with a shorter period,
+// AND accomodate it already having been linked here (after some other qh)
+// AS WELL AS updating the schedule checking logic
+
+			BUG ();
+		} else {
+			ehci->pshadow [frame].qh = qh_get (qh);
+			ehci->periodic [frame] =
+				QH_NEXT (qh->qh_dma);
+		}
+		wmb ();
+		frame += qh->period;
+	} while (frame < ehci->periodic_size);
+
+	/* update per-qh bandwidth for usbfs */
+	ehci->hcd.self.bandwidth_allocated += 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	/* maybe enable periodic schedule processing */
+	if (!ehci->periodic_sched++)
+		status = enable_periodic (ehci);
+done:
+	return status;
+}
+
 static int intr_submit (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	int			mem_flags
 ) {
-	unsigned		epnum, period;
-	unsigned short		usecs, c_usecs, gap_uf;
+	unsigned		epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
 	struct hcd_dev		*dev;
 	int			is_input;
 	int			status = 0;
+	struct list_head	empty;
 
 	/* get endpoint and transfer/schedule data */
 	epnum = usb_pipeendpoint (urb->pipe);
@@ -329,198 +466,30 @@
 	if (is_input)
 		epnum |= 0x10;
 
-	/*
-	 * HS interrupt transfers are simple -- only one microframe.  FS/LS
-	 * interrupt transfers involve a SPLIT in one microframe and CSPLIT
-	 * sometime later.  We need to know how much time each will be
-	 * needed in each microframe and, for FS/LS, how many microframes
-	 * separate the two in the best case.
-	 */
-	usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
-			urb->transfer_buffer_length);
-	if (urb->dev->speed == USB_SPEED_HIGH) {
-		gap_uf = 0;
-		c_usecs = 0;
-
-		/* FIXME handle HS periods of less than 1 frame. */
-		period = urb->interval >> 3;
-		if (period < 1) {
-			dbg ("intr period %d uframes, NYET!", urb->interval);
-			status = -EINVAL;
-			goto done;
-		}
-	} else {
-		/* gap is a function of full/low speed transfer times */
-		gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, is_input, 0,
-				urb->transfer_buffer_length) / (125 * 1000);
-
-		/* FIXME this just approximates SPLIT/CSPLIT times */
-		if (is_input) {		// SPLIT, gap, CSPLIT+DATA
-			c_usecs = usecs + HS_USECS (0);
-			usecs = HS_USECS (1);
-		} else {		// SPLIT+DATA, gap, CSPLIT
-			usecs = usecs + HS_USECS (1);
-			c_usecs = HS_USECS (0);
-		}
-
-		period = urb->interval;
-	}
+	spin_lock_irqsave (&ehci->lock, flags);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
 
-	/*
-	 * NOTE: current completion/restart logic doesn't handle more than
-	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
-	 * such big requests need many periods to transfer.
-	 *
-	 * FIXME want to change hcd core submit model to expect queuing
-	 * for all transfer types ... not just ISO and (with flag) BULK.
-	 * that means: getting rid of this check; handling the "interrupt
-	 * urb already queued" case below like bulk queuing is handled (no
-	 * errors possible!); and completly getting rid of that annoying
-	 * qh restart logic.  simpler/smaller overall, and more flexible.
-	 */
-	if (unlikely (qtd_list->next != qtd_list->prev)) {
-		dbg ("only one intr qtd per urb allowed"); 
-		status = -EINVAL;
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD (&empty);
+	qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]);
+	if (qh == 0) {
+		status = -ENOMEM;
 		goto done;
 	}
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* get the qh (must be empty and idle) */
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	qh = (struct ehci_qh *) dev->ep [epnum];
-	if (qh) {
-		/* only allow one queued interrupt urb per EP */
-		if (unlikely (qh->qh_state != QH_STATE_IDLE
-				|| !list_empty (&qh->qtd_list))) {
-			dbg ("interrupt urb already queued");
-			status = -EBUSY;
-		} else {
-			/* maybe reset hardware's data toggle in the qh */
-			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10)))) {
-				qh->hw_token |=
-					__constant_cpu_to_le32 (QTD_TOGGLE);
-				usb_settoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10), 1);
-			}
-			/* trust the QH was set up as interrupt ... */
-			list_splice (qtd_list, &qh->qtd_list);
-			qh_update (qh, list_entry (qtd_list->next,
-						struct ehci_qtd, qtd_list));
-			qtd_list = &qh->qtd_list;
-		}
-	} else {
-		/* can't sleep here, we have ehci->lock... */
-		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg ("new INTR qh %p", qh);
-			dev->ep [epnum] = qh;
-			qtd_list = &qh->qtd_list;
-		} else
-			status = -ENOMEM;
+	if (qh->qh_state == QH_STATE_IDLE) {
+		if ((status = qh_schedule (ehci, qh)) != 0)
+			goto done;
 	}
 
-	/* Schedule this periodic QH. */
-	if (likely (status == 0)) {
-		unsigned	frame = period;
-
-		qh->hw_next = EHCI_LIST_END;
-		qh->usecs = usecs;
-		qh->c_usecs = c_usecs;
-
-		urb->hcpriv = qh_get (qh);
-		status = -ENOSPC;
-
-		/* pick a set of schedule slots, link the QH into them */
-		do {
-			int	uframe;
-			u32	c_mask = 0;
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+	BUG_ON (qh == 0);
 
-			/* pick a set of slots such that all uframes have
-			 * enough periodic bandwidth available.
-			 */
-			frame--;
-			for (uframe = 0; uframe < 8; uframe++) {
-				if (check_period (ehci, frame, uframe,
-						period, usecs) == 0)
-					continue;
-
-				/* If this is a split transaction, check the
-				 * bandwidth available for the completion
-				 * too.  check both best and worst case gaps:
-				 * worst case is SPLIT near uframe end, and
-				 * CSPLIT near start ... best is vice versa.
-				 * Difference can be almost two uframe times.
-				 *
-				 * FIXME don't even bother unless we know
-				 * this TT is idle in that uframe ... right
-				 * now we know only one interrupt transfer
-				 * will be scheduled per frame, so we don't
-				 * need to update/check TT state when we
-				 * schedule a split (QH, SITD, or FSTN).
-				 *
-				 * FIXME ehci 0.96 and above can use FSTNs
-				 */
-				if (!c_usecs)
-				    	break;
-				if (check_period (ehci, frame,
-						uframe + gap_uf,
-						period, c_usecs) == 0)
-					continue;
-				if (check_period (ehci, frame,
-						uframe + gap_uf + 1,
-						period, c_usecs) == 0)
-					continue;
+	/* ... update usbfs periodic stats */
+	ehci->hcd.self.bandwidth_int_reqs++;
 
-				c_mask = 0x03 << (8 + uframe + gap_uf);
-				c_mask = cpu_to_le32 (c_mask);
-				break;
-			}
-			if (uframe == 8)
-				continue;
-
-			/* QH will run once each period, starting there  */
-			urb->start_frame = frame;
-			status = 0;
-
-			/* reset S-frame and (maybe) C-frame masks */
-			qh->hw_info2 &= ~0xffff;
-			qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
-			// dbg_qh ("Schedule INTR qh", ehci, qh);
-
-			/* stuff into the periodic schedule */
-			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d.0 starting %d.%d",
-				qh, qh->usecs, period, frame, uframe);
-			do {
-				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
-// FIXME -- just link toward the end, before any qh with a shorter period,
-// AND handle it already being (implicitly) linked into this frame
-// AS WELL AS updating the check_period() logic
-					BUG ();
-				} else {
-					ehci->pshadow [frame].qh = qh_get (qh);
-					ehci->periodic [frame] =
-						QH_NEXT (qh->qh_dma);
-				}
-				wmb ();
-				frame += period;
-			} while (frame < ehci->periodic_size);
-
-			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb,
-				(usecs + c_usecs) / period, 0);
-
-			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++)
-				status = enable_periodic (ehci);
-			break;
-
-		} while (frame);
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
 done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
 
@@ -534,10 +503,6 @@
 	struct ehci_qh	*qh,
 	unsigned long	flags		/* caller owns ehci->lock ... */
 ) {
-	struct ehci_qtd	*qtd;
-	struct urb	*urb;
-	int		unlinking;
-
 	/* nothing to report? */
 	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
 			!= 0))
@@ -547,43 +512,14 @@
 		return flags;
 	}
 	
-	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
-	urb = qtd->urb;
-	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
-
-	/* call any completions, after patching for reactivation */
+	/* handle any completions */
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	/* NOTE:  currently restricted to one qtd per qh! */
-	if (qh_completions (ehci, qh, 0) == 0)
-		urb = 0;
+	qh_completions (ehci, qh);
 	spin_lock_irqsave (&ehci->lock, flags);
 
-	/* never reactivate requests that were unlinked ... */
-	if (likely (urb != 0)) {
-		if (unlinking
-				|| urb->status == -ECONNRESET
-				|| urb->status == -ENOENT
-				// || (urb->dev == null)
-				|| ehci->hcd.state == USB_STATE_HALT)
-			urb = 0;
-		// FIXME look at all those unlink cases ... we always
-		// need exactly one completion that reports unlink.
-		// the one above might not have been it!
-	}
-
-	/* normally reactivate */
-	if (likely (urb != 0)) {
-		if (usb_pipeout (urb->pipe))
-			pci_dma_sync_single (ehci->hcd.pdev,
-				qtd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_TODEVICE);
-		urb->status = -EINPROGRESS;
-		urb->actual_length = 0;
+	if (unlikely (list_empty (&qh->qtd_list)))
+		intr_deschedule (ehci, qh, 0);
 
-		/* patch qh and restart */
-		qh_update (qh, qtd);
-	}
 	return flags;
 }
 
@@ -594,11 +530,6 @@
 {
 	struct ehci_itd *first_itd = urb->hcpriv;
 
-	pci_unmap_single (ehci->hcd.pdev,
-		first_itd->buf_dma, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
 	while (!list_empty (&first_itd->itd_list)) {
 		struct ehci_itd	*itd;
 
@@ -694,16 +625,7 @@
 	int			frame_index;
 	struct ehci_itd		*first_itd, *itd;
 	int			status;
-	dma_addr_t		buf_dma, itd_dma;
-
-	/* set up one dma mapping for this urb */
-	buf_dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (buf_dma == 0)
-		return -ENOMEM;
+	dma_addr_t		itd_dma;
 
 	/* allocate/init ITDs */
 	for (frame_index = 0, first_itd = 0;
@@ -717,7 +639,8 @@
 		memset (itd, 0, sizeof *itd);
 		itd->itd_dma = itd_dma;
 
-		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+		status = itd_fill (ehci, itd, urb, frame_index,
+				urb->transfer_dma);
 		if (status != 0)
 			goto fail;
 
@@ -806,7 +729,7 @@
 
 	/* calculate the legal range [start,max) */
 	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		now += 8;				/* startup delay */
 	now %= mod;
 	end = now + mod;
@@ -926,7 +849,7 @@
 		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
 
 		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_urbs++) {
+		if (!ehci->periodic_sched++) {
 			if ((status =  enable_periodic (ehci)) != 0) {
 				// FIXME deschedule right away
 				err ("itd_schedule, enable = %d", status);
@@ -1009,8 +932,8 @@
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/* defer stopping schedule; completion can submit */
-	ehci->periodic_urbs--;
-	if (!ehci->periodic_urbs)
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
 		(void) disable_periodic (ehci);
 
 	return flags;
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/host/ehci.h	Tue Aug 27 12:28:08 2002
@@ -50,7 +50,7 @@
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+	unsigned		periodic_sched;	/* periodic activity count */
 
 	/* deferred work from IRQ, etc */
 	struct tasklet_struct	tasklet;
@@ -72,7 +72,7 @@
 };
 
 /* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
-#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
 
 /* NOTE:  urb->transfer_flags expected to not use this bit !!! */
 #define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
@@ -219,7 +219,6 @@
 
 	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
 	struct urb		*urb;			/* qtd's urb */
-	dma_addr_t		buf_dma;		/* buffer address */
 	size_t			length;			/* length of buffer */
 } __attribute__ ((aligned (32)));
 
@@ -287,12 +286,20 @@
 	struct list_head	qtd_list;	/* sw qtd list */
 
 	atomic_t		refcount;
-	unsigned short		usecs;		/* intr bandwidth */
-	unsigned short		c_usecs;	/* ... split completion bw */
-	short			qh_state;
+
+	u8			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
+
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/hc_sl811_rh.c b/drivers/usb/host/hc_sl811_rh.c
--- a/drivers/usb/host/hc_sl811_rh.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/host/hc_sl811_rh.c	Tue Aug 27 12:28:07 2002
@@ -21,6 +21,8 @@
  *
  *-------------------------------------------------------------------------*/
 
+/* FIXME:  reuse the root hub framework in usbcore, shrinking this code.  */
+
 #ifdef DEBUG
 #undef DEBUG
 #endif
@@ -229,6 +231,52 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+static int root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+	char buf [30];
+
+	// assert (len > (2 * (sizeof (buf) + 1)));
+	// assert (strlen (type) <= 8);
+
+	// language ids
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	// serial number
+	} else if (id == 1) {
+		sprintf (buf, "%x", serial);
+
+	// product description
+	} else if (id == 2) {
+		sprintf (buf, "USB %s Root Hub", type);
+
+	// id 3 == vendor description
+
+	// unsupported IDs --> "stall"
+	} else
+	    return 0;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;
+	return data [0];
+}
+
+/*-------------------------------------------------------------------------*/
+
 /* helper macro */
 #define OK(x) 			len = (x); break
 
@@ -409,7 +457,7 @@
 			OK (len);
 
 		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
+			len = root_hub_string (wValue & 0xff, (int) (long) 0,
 						   "SL811HS", data, wLength);
 			if (len > 0) {
 				data_buf = data;
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/host/ohci-q.c	Tue Aug 27 12:28:08 2002
@@ -14,27 +14,8 @@
 
 	if (last >= 0) {
 		int		i;
-		struct td	*td = urb_priv->td [0];
-		int		len = td->urb->transfer_buffer_length;
-		int		dir = usb_pipeout (td->urb->pipe)
-					? PCI_DMA_TODEVICE
-					: PCI_DMA_FROMDEVICE;
-
-		/* unmap CTRL URB setup buffer (always td 0) */
-		if (usb_pipecontrol (td->urb->pipe)) {
-			pci_unmap_single (hc->hcd.pdev, 
-					td->data_dma, 8, PCI_DMA_TODEVICE);
-			
-			/* CTRL data buffer starts at td 1 if len > 0 */
-			if (len && last > 0)
-				td = urb_priv->td [1]; 		
-		}
-		/* else:  ISOC, BULK, INTR data buffer starts at td 0 */
-
-		/* unmap data buffer */
-		if (len && td->data_dma)
-			pci_unmap_single (hc->hcd.pdev,
-					td->data_dma, len, dir);
+		struct td	*td;
+
 		for (i = 0; i <= last; i++) {
 			td = urb_priv->td [i];
 			if (td)
@@ -85,15 +66,8 @@
 	struct urb_priv	*urb_priv = urb->hcpriv;
 	unsigned long	flags;
 
-// FIXME rewrite this resubmit path.  use pci_dma_sync_single()
-// and requeue more cheaply, and only if needed.
-// Better yet ... abolish the notion of automagic resubmission.
-	pci_unmap_single (hc->hcd.pdev,
-		urb_priv->td [0]->data_dma,
-		urb->transfer_buffer_length,
-		usb_pipeout (urb->pipe)
-			? PCI_DMA_TODEVICE
-			: PCI_DMA_FROMDEVICE);
+// FIXME going away along with the rest of interrrupt automagic...
+
 	/* FIXME: MP race.  If another CPU partially unlinks
 	 * this URB (urb->status was updated, hasn't yet told
 	 * us to dequeue) before we call complete() here, an
@@ -612,13 +586,9 @@
 
 	urb_priv->td_cnt = 0;
 
-	if (data_len) {
-		data = pci_map_single (ohci->hcd.pdev,
-				       urb->transfer_buffer, data_len,
-				       is_out
-					       ? PCI_DMA_TODEVICE
-					       : PCI_DMA_FROMDEVICE);
-	} else
+	if (data_len)
+		data = urb->transfer_dma;
+	else
 		data = 0;
 
 	/* NOTE:  TD_CC is set so we can tell which TDs the HC processed by
@@ -665,11 +635,7 @@
 	 */
 	case PIPE_CONTROL:
 		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-		td_fill (info,
-			pci_map_single (ohci->hcd.pdev,
-					urb->setup_packet, 8,
-					PCI_DMA_TODEVICE),
-			 8, urb, cnt++);
+		td_fill (info, urb->setup_dma, 8, urb, cnt++);
 		if (data_len > 0) {
 			info = TD_CC | TD_R | TD_T_DATA1;
 			info |= is_out ? TD_DP_OUT : TD_DP_IN;
@@ -938,7 +904,7 @@
 		/* ED's now officially unlinked, hc doesn't see */
 		ed->state = ED_IDLE;
 		ed->hwINFO &= ~ED_SKIP;
-		ed->hwHeadP &= ~cpu_to_le32 (ED_H);
+		ed->hwHeadP &= ~ED_H;
 		ed->hwNextED = 0;
 
 		/* but if there's work queued, reschedule */
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/host/ohci-sa1111.c	Tue Aug 27 12:28:07 2002
@@ -161,6 +161,12 @@
 	hcd->regs = (void *) &USB_OHCI_OP_BASE;
 	hcd->pdev = SA1111_FAKE_PCIDEV;
 
+	retval = hcd_buffer_create (hcd);
+	if (retval != 0) {
+		dbg ("pool alloc fail");
+		goto err1;
+	}
+
 	set_irq_type(NIRQHCIM, IRQT_RISING);
 	retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
 			      hcd->description, hcd);
@@ -193,6 +199,7 @@
 	return 0;
 
  err2:
+	hcd_buffer_destroy (hcd);
 	if (hcd) driver->hcd_free(hcd);
  err1:
 	sa1111_stop_hc();
@@ -233,6 +240,7 @@
 	hcd->state = USB_STATE_HALT;
 
 	free_irq (hcd->irq, hcd);
+	hcd_buffer_destroy (hcd);
 
 	usb_deregister_bus (&hcd->self);
 	if (atomic_read (&hcd->self.refcnt) != 1)
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/host/uhci-hcd.c	Tue Aug 27 12:28:08 2002
@@ -646,23 +646,6 @@
 
 	urb->hcpriv = urbp;
 
-	if (urb->transfer_buffer_length) {
-		urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
-			urb->transfer_buffer, urb->transfer_buffer_length,
-			usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
-			PCI_DMA_TODEVICE);
-		if (!urbp->transfer_buffer_dma_handle)
-			return NULL;
-	}
-
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
-		urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-			urb->setup_packet, sizeof(struct usb_ctrlrequest),
-			PCI_DMA_TODEVICE);
-		if (!urbp->setup_packet_dma_handle)
-			return NULL;
-	}
-
 	return urbp;
 }
 
@@ -721,19 +704,6 @@
 		uhci_free_td(uhci, td);
 	}
 
-	if (urbp->setup_packet_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urbp->setup_packet_dma_handle = 0;
-	}
-
-	if (urbp->transfer_buffer_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-		urbp->transfer_buffer_dma_handle = 0;
-	}
-
 	urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
@@ -813,7 +783,7 @@
 	unsigned long destination, status;
 	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	int len = urb->transfer_buffer_length;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
+	dma_addr_t data = urb->transfer_dma;
 
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -832,7 +802,7 @@
 
 	uhci_add_td_to_urb(urb, td);
 	uhci_fill_td(td, status, destination | uhci_explen(7),
-		urbp->setup_packet_dma_handle);
+		urb->setup_dma);
 
 	/*
 	 * If direction is "send", change the frame from SETUP (0x2D)
@@ -1072,7 +1042,6 @@
 {
 	struct uhci_td *td;
 	unsigned long destination, status;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
 		return -EINVAL;
@@ -1094,7 +1063,7 @@
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
 	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
+	uhci_fill_td(td, status, destination, urb->transfer_dma);
 
 	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
 
@@ -1196,7 +1165,7 @@
 	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	int len = urb->transfer_buffer_length;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
+	dma_addr_t data = urb->transfer_dma;
 
 	if (len < 0)
 		return -EINVAL;
@@ -1358,7 +1327,6 @@
 	struct uhci_td *td;
 	int i, ret, frame;
 	int status, destination;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@@ -1378,7 +1346,7 @@
 
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
-			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
+			urb->transfer_dma + urb->iso_frame_desc[i].offset);
 
 		if (i + 1 >= urb->number_of_packets)
 			td->status |= cpu_to_le32(TD_CTRL_IOC);
@@ -1831,15 +1799,6 @@
 			urb->status == -ECONNRESET);
 	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
 			urb->interval);
-
-	if (urbp->transfer_buffer_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-
-	if (urbp->setup_packet_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	status = urbp->status;
 	if (!resubmit_interrupt || killed)
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/host/uhci-hcd.h	Tue Aug 27 12:28:08 2002
@@ -4,6 +4,9 @@
 #include <linux/list.h>
 #include <linux/usb.h>
 
+#define usb_packetid(pipe)	(usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
+#define PIPE_DEVEP_MASK		0x0007ff00
+
 /*
  * Universal Host Controller Interface data structures and defines
  */
@@ -337,9 +340,6 @@
 
 	struct urb *urb;
 	struct usb_device *dev;
-
-	dma_addr_t setup_packet_dma_handle;
-	dma_addr_t transfer_buffer_dma_handle;
 
 	struct uhci_qh *qh;		/* QH for this URB */
 	struct list_head td_list;	/* P: urb->lock */
diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
--- a/drivers/usb/image/scanner.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/image/scanner.h	Tue Aug 27 12:28:02 2002
@@ -115,6 +115,7 @@
 	{ USB_DEVICE(0x03f0, 0x0101) },	/* 4100C */
 	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
 	{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
+	{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
 	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
@@ -187,8 +188,12 @@
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
 	{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+	{ USB_DEVICE(0x04a9, 0x2204) }, /* FB630U */
 	{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
 	{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
+	{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
+	{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
+	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/input/hid-core.c	Tue Aug 27 12:28:07 2002
@@ -879,7 +879,7 @@
 	{
 		int i;
 		printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
-		for (i = 0; i < n; i++)
+		for (i = 0; i < len; i++)
 			printk(" %02x", data[i]);
 		printk("\n");
 	}
@@ -1073,7 +1073,7 @@
 
 	hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
 	hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
-	hid->cr.wValue = ((report->type + 1) << 8) | report->id;
+	hid->cr.wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
 	hid->cr.wIndex = cpu_to_le16(hid->ifnum);
 	hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length);
 
@@ -1384,7 +1384,7 @@
 #ifdef DEBUG_DATA
 	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
 	for (n = 0; n < rsize; n++)
-		printk(" %02x", (unsigned) rdesc[n]);
+		printk(" %02x", (unsigned char) rdesc[n]);
 	printk("\n");
 #endif
 
@@ -1432,7 +1432,7 @@
 	hid->outlock = SPIN_LOCK_UNLOCKED;
 	hid->ctrllock = SPIN_LOCK_UNLOCKED;
 
-	hid->version = hdesc->bcdHID;
+	hid->version = le16_to_cpu(hdesc->bcdHID);
 	hid->country = hdesc->bCountryCode;
 	hid->dev = dev;
 	hid->ifnum = interface->bInterfaceNumber;
diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
--- a/drivers/usb/media/ibmcam.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/media/ibmcam.c	Tue Aug 27 12:28:02 2002
@@ -78,7 +78,7 @@
 };
 
 /*
- * This structure lives in uvd_t->user field.
+ * This structure lives in uvd->user field.
  */
 typedef struct {
 	int initialized;	/* Had we already sent init sequence? */
@@ -249,7 +249,7 @@
  * History:
  * 1/21/00  Created.
  */
-static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */
+static ParseState_t ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
 {
 	usbvideo_frame_t *frame;
 	ibmcam_t *icam;
@@ -398,7 +398,7 @@
  * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
  */
 static ParseState_t ibmcam_parse_lines(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	usbvideo_frame_t *frame,
 	long *pcopylen)
 {
@@ -663,7 +663,7 @@
  * lost resolution.
  */
 static ParseState_t ibmcam_model2_320x240_parse_lines(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	usbvideo_frame_t *frame,
 	long *pcopylen)
 {
@@ -817,7 +817,7 @@
 }
 
 static ParseState_t ibmcam_model3_parse_lines(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	usbvideo_frame_t *frame,
 	long *pcopylen)
 {
@@ -962,7 +962,7 @@
  * 10-Feb-2001 Created.
  */
 static ParseState_t ibmcam_model4_128x96_parse_lines(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	usbvideo_frame_t *frame,
 	long *pcopylen)
 {
@@ -1049,7 +1049,7 @@
  * History:
  * 1/21/00  Created.
  */
-void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+void ibmcam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame)
 {
 	ParseState_t newstate;
 	long copylen = 0;
@@ -1128,7 +1128,7 @@
  * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
  */
 static int ibmcam_veio(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	unsigned char req,
 	unsigned short value,
 	unsigned short index)
@@ -1195,7 +1195,7 @@
  * History:
  * 1/18/00  Created.
  */
-static int ibmcam_calculate_fps(uvd_t *uvd)
+static int ibmcam_calculate_fps(struct uvd *uvd)
 {
 	return 3 + framerate*4 + framerate/2;
 }
@@ -1209,33 +1209,33 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_send_FF_04_02(uvd_t *uvd)
+static void ibmcam_send_FF_04_02(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
 	ibmcam_veio(uvd, 0, 0x0004, 0x0124);
 	ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void ibmcam_send_00_04_06(uvd_t *uvd)
+static void ibmcam_send_00_04_06(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x0000, 0x0127);
 	ibmcam_veio(uvd, 0, 0x0004, 0x0124);
 	ibmcam_veio(uvd, 0, 0x0006, 0x0124);
 }
 
-static void ibmcam_send_x_00(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
 }
 
-static void ibmcam_send_x_00_05(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_send_x_00(uvd, x);
 	ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1243,7 +1243,7 @@
 	ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
@@ -1251,7 +1251,7 @@
 	ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1260,7 +1260,7 @@
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1270,7 +1270,7 @@
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char val)
+static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
 {
 	ibmcam_send_x_01_00_05(uvd, unknown_88);
 	ibmcam_send_x_00_05(uvd, fkey);
@@ -1284,20 +1284,20 @@
 	ibmcam_send_FF_04_02(uvd);
 }
 
-static void ibmcam_PacketFormat2(uvd_t *uvd, unsigned char fkey, unsigned char val)
+static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
 {
 	ibmcam_send_x_01_00_05	(uvd, unknown_88);
 	ibmcam_send_x_00_05	(uvd, fkey);
 	ibmcam_send_x_00_05_02	(uvd, val);
 }
 
-static void ibmcam_model2_Packet2(uvd_t *uvd)
+static void ibmcam_model2_Packet2(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
 	ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
 }
 
-static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
+static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
 {
 	ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
 	ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
@@ -1318,7 +1318,7 @@
  * 00_0096_0127
  * 00_fea8_0124	
 */
-static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
+static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
 {
 	ibmcam_veio(uvd, 0, 0x0078, 0x012d);
 	ibmcam_veio(uvd, 0, v1,     0x012f);
@@ -1327,7 +1327,7 @@
 	ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
 }
 
-static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i)
+static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
 {
 	ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
 	ibmcam_veio(uvd, 0, 0x0026, 0x012f);
@@ -1353,7 +1353,7 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_adjust_contrast(uvd_t *uvd)
+static void ibmcam_adjust_contrast(struct uvd *uvd)
 {
 	unsigned char a_contrast = uvd->vpic.contrast >> 12;
 	unsigned char new_contrast;
@@ -1428,7 +1428,7 @@
  * 1/5/00   Created.
  * 2/20/00  Added support for Model 2 cameras.
  */
-static void ibmcam_change_lighting_conditions(uvd_t *uvd)
+static void ibmcam_change_lighting_conditions(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_change_lighting_conditions";
 
@@ -1474,7 +1474,7 @@
  * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
  * Recommended value is 4. Cameras model 2 do not have this feature at all.
  */
-static void ibmcam_set_sharpness(uvd_t *uvd)
+static void ibmcam_set_sharpness(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_set_sharpness";
 
@@ -1543,7 +1543,7 @@
  *
  * This procedure changes brightness of the picture.
  */
-static void ibmcam_set_brightness(uvd_t *uvd)
+static void ibmcam_set_brightness(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_set_brightness";
 	static const unsigned short n = 1;
@@ -1608,7 +1608,7 @@
 	}
 }
 
-static void ibmcam_set_hue(uvd_t *uvd)
+static void ibmcam_set_hue(struct uvd *uvd)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_2:
@@ -1704,14 +1704,14 @@
  * This procedure gets called from V4L interface to update picture settings.
  * Here we change brightness and contrast.
  */
-static void ibmcam_adjust_picture(uvd_t *uvd)
+static void ibmcam_adjust_picture(struct uvd *uvd)
 {
 	ibmcam_adjust_contrast(uvd);
 	ibmcam_set_brightness(uvd);
 	ibmcam_set_hue(uvd);
 }
 
-static int ibmcam_model1_setup(uvd_t *uvd)
+static int ibmcam_model1_setup(struct uvd *uvd)
 {
 	const int ntries = 5;
 	int i;
@@ -1908,7 +1908,7 @@
 	return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
 }
 
-static int ibmcam_model2_setup(uvd_t *uvd)
+static int ibmcam_model2_setup(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x0000, 0x0100);	/* LED on */
 	ibmcam_veio(uvd, 1, 0x0000, 0x0116);
@@ -1966,7 +1966,7 @@
  * This code adds finishing touches to the video data interface.
  * Here we configure the frame rate and turn on the LED.
  */
-static void ibmcam_model1_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
 {
 	unsigned short internal_frame_rate;
 
@@ -1978,7 +1978,7 @@
 	ibmcam_veio(uvd, 0, 0xc0, 0x010c);
 }
 
-static void ibmcam_model2_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
 {
 	unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
 
@@ -2154,7 +2154,7 @@
 	usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-static void ibmcam_model4_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
 {
 	switch (uvd->videosize) {
 	case VIDEOSIZE_128x96:
@@ -2704,7 +2704,7 @@
 	usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-static void ibmcam_model3_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
 {
 	int i;
 	/*
@@ -3485,7 +3485,7 @@
  * This code tells camera to stop streaming. The interface remains
  * configured and bandwidth - claimed.
  */
-static void ibmcam_video_stop(uvd_t *uvd)
+static void ibmcam_video_stop(struct uvd *uvd)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -3546,7 +3546,7 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop)
+static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -3570,7 +3570,7 @@
 	}
 }
 
-static void ibmcam_video_start(uvd_t *uvd)
+static void ibmcam_video_start(struct uvd *uvd)
 {
 	ibmcam_change_lighting_conditions(uvd);
 	ibmcam_set_sharpness(uvd);
@@ -3580,7 +3580,7 @@
 /*
  * Return negative code on failure, 0 on success.
  */
-static int ibmcam_setup_on_open(uvd_t *uvd)
+static int ibmcam_setup_on_open(struct uvd *uvd)
 {
 	int setup_ok = 0; /* Success by default */
 	/* Send init sequence only once, it's large! */
@@ -3602,7 +3602,7 @@
 	return setup_ok;
 }
 
-static void ibmcam_configure_video(uvd_t *uvd)
+static void ibmcam_configure_video(struct uvd *uvd)
 {
 	if (uvd == NULL)
 		return;
@@ -3658,7 +3658,7 @@
  */
 static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
 {
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 	int i, nas, model=0, canvasX=0, canvasY=0;
 	int actInterface=-1, inactInterface=-1, maxPS=0;
 	unsigned char video_ep = 0;
@@ -3868,7 +3868,7 @@
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		/* Here uvd is a fully allocated uvd_t object */
+		/* Here uvd is a fully allocated uvd object */
 		uvd->flags = flags;
 		uvd->debug = debug;
 		uvd->dev = dev;
diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
--- a/drivers/usb/media/konicawc.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/usb/media/konicawc.c	Tue Aug 27 12:27:45 2002
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * konicawc.c - konica webcam driver
  *
  * Author: Simon Evans <spse@secret.org.uk>
@@ -8,7 +6,7 @@
  * Copyright (C) 2002 Simon Evans
  *
  * Licence: GPL
- * 
+ *
  * Driver for USB webcams based on Konica chipset. This
  * chipset is used in Intel YC76 camera.
  *
@@ -17,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/input.h>
 
 #include "usbvideo.h"
 
@@ -26,9 +25,11 @@
 #define MAX_SHARPNESS	108
 #define MAX_WHITEBAL	372
 #define MAX_SPEED	6
+
+
 #define MAX_CAMERAS	1
 
-#define DRIVER_VERSION	"v1.1"
+#define DRIVER_VERSION	"v1.4"
 #define DRIVER_DESC	"Konica Webcam driver"
 
 enum ctrl_req {
@@ -41,18 +42,32 @@
 
 
 enum frame_sizes {
-	SIZE_160X136	= 0,
-	SIZE_176X144	= 1,
-	SIZE_320X240	= 2,
+	SIZE_160X120	= 0,
+	SIZE_160X136	= 1,
+	SIZE_176X144	= 2,
+	SIZE_320X240	= 3,
+	
 };
 
+#define MAX_FRAME_SIZE	SIZE_320X240
 
 static usbvideo_t *cams;
 
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+
 /* Some default values for inital camera settings,
    can be set by modprobe */
 
-static int debug;
 static enum frame_sizes size;	
 static int speed = 6;		/* Speed (fps) 0 (slowest) to 6 (fastest) */
 static int brightness =	MAX_BRIGHTNESS/2;
@@ -61,31 +76,36 @@
 static int sharpness =	MAX_SHARPNESS/2;
 static int whitebal =	3*(MAX_WHITEBAL/4);
 
-static int speed_to_interface[] = { 1, 0, 3, 2, 4, 5, 6 };
+static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
 
 /* These FPS speeds are from the windows config box. They are
  * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
  * real fps.
  */
 
-static int speed_to_fps[3][7] = { { 24, 40, 48, 60, 72, 80, 100 },
-				  { 18, 30, 36, 45, 54, 60, 75  },
-				  { 6,  10, 12, 15, 18, 20, 25  } };
-
-
-static int camera_sizes[][2] = { { 160, 136 },
-				 { 176, 144 },
-				 { 320, 240 },
-				 { } /* List terminator */
+static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+			       { 24, 40, 48, 60, 72, 80, 100 },
+			       { 18, 30, 36, 45, 54, 60, 75  },
+			       { 6,  10, 12, 15, 18, 21, 25  } };
+
+struct cam_size {
+	u16	width;
+	u16	height;
+	u8	cmd;
 };
 
+static struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
+					  { 160, 136, 0xa },
+					  { 176, 144, 0x4 },
+					  { 320, 240, 0x5 } };
+
 struct konicawc {
 	u8 brightness;		/* camera uses 0 - 9, x11 for real value */
 	u8 contrast;		/* as above */
 	u8 saturation;		/* as above */
 	u8 sharpness;		/* as above */
 	u8 white_bal;		/* 0 - 33, x11 for real value */
-	u8 speed;		/* Stored as 0 - 6, used as index in speed_to_* (above) */
+	u8 speed;		/* Stored as 0 - 6, used as index in spd_to_* (above) */
 	u8 size;		/* Frame Size */
 	int height;
 	int width;
@@ -93,6 +113,14 @@
 	u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
 	struct urb *last_data_urb;
 	int lastframe;
+	int cur_frame_size;	/* number of bytes in current frame size */
+	int maxline;		/* number of lines per frame */
+	int yplanesz;		/* Number of bytes in the Y plane */
+	unsigned int buttonsts:1;
+#ifdef CONFIG_INPUT
+	struct input_dev input;
+	char input_physname[64];
+#endif
 };
 
 
@@ -101,7 +129,7 @@
 #define konicawc_set_value(uvd, value, index)			konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
 
 
-static int konicawc_ctrl_msg(uvd_t *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
+static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
 {
         int retval = usb_control_msg(uvd->dev,
 		dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
@@ -110,91 +138,106 @@
 }
 
 
-static int konicawc_setup_on_open(uvd_t *uvd)
+static inline void konicawc_camera_on(struct uvd *uvd)
+{
+        DEBUG(0, "camera on");
+        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
+}
+
+
+static inline void konicawc_camera_off(struct uvd *uvd)
+{
+        DEBUG(0, "camera off");
+        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
+}
+
+
+static void konicawc_set_camera_size(struct uvd *uvd)
 {
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
-	konicawc_set_misc(uvd, 0x2, 0, 0x0b);
-	dbg("setting brightness to %d (%d)", cam->brightness,
+	konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
+	cam->width = camera_sizes[cam->size].width;
+	cam->height = camera_sizes[cam->size].height;
+	cam->yplanesz = cam->height * cam->width;
+	cam->cur_frame_size = (cam->yplanesz * 3) / 2;
+	cam->maxline = cam->yplanesz / 256;
+	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+}
+
+
+static int konicawc_setup_on_open(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
 	    cam->brightness * 11);
 	konicawc_set_value(uvd, cam->brightness, SetBrightness);
-	dbg("setting white balance to %d (%d)", cam->white_bal,
+	DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
 	    cam->white_bal * 11);
 	konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
-	dbg("setting contrast to %d (%d)", cam->contrast,
+	DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
 	    cam->contrast * 11);
 	konicawc_set_value(uvd, cam->contrast, SetContrast);
-	dbg("setting saturation to %d (%d)", cam->saturation,
+	DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
 	    cam->saturation * 11);
 	konicawc_set_value(uvd, cam->saturation, SetSaturation);
-	dbg("setting sharpness to %d (%d)", cam->sharpness,
+	DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
 	    cam->sharpness * 11);
 	konicawc_set_value(uvd, cam->sharpness, SetSharpness);
-	dbg("setting size %d", cam->size);
-	switch(cam->size) {
-	case 0:
-		konicawc_set_misc(uvd, 0x2, 0xa, 0x08);
-		break;
-
-	case 1:
-		konicawc_set_misc(uvd, 0x2, 4, 0x08);
-		break;
-
-	case 2:
-		konicawc_set_misc(uvd, 0x2, 5, 0x08);
-		break;
-	}
-	konicawc_set_misc(uvd, 0x2, 1, 0x0b);
-	cam->lastframe = -1;
+	konicawc_set_camera_size(uvd);
+	cam->lastframe = -2;
+	cam->buttonsts = 0;
 	return 0;
 }
 
 
-static void konicawc_adjust_picture(uvd_t *uvd)
+static void konicawc_adjust_picture(struct uvd *uvd)
 {
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
-	dbg("new brightness: %d", uvd->vpic.brightness);
+	konicawc_camera_off(uvd);
+	DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
 	uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
 	if(cam->brightness != uvd->vpic.brightness / 11) {
 	   cam->brightness = uvd->vpic.brightness / 11;
-	   dbg("setting brightness to %d (%d)", cam->brightness,
+	   DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
 	       cam->brightness * 11);
 	   konicawc_set_value(uvd, cam->brightness, SetBrightness);
 	}
 
-	dbg("new contrast: %d", uvd->vpic.contrast);
+	DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
 	uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
 	if(cam->contrast != uvd->vpic.contrast / 11) {
 		cam->contrast = uvd->vpic.contrast / 11;
-		dbg("setting contrast to %d (%d)", cam->contrast,
+		DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
 		    cam->contrast * 11);
 		konicawc_set_value(uvd, cam->contrast, SetContrast);
 	}
+	konicawc_camera_on(uvd);
 }
 
 
-static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb)
+static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
 {
 	char *cdata;
 	int i, totlen = 0;
 	unsigned char *status = stsurb->transfer_buffer;
 	int keep = 0, discard = 0, bad = 0;
-	static int buttonsts = 0;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
 	for (i = 0; i < dataurb->number_of_packets; i++) {
-		int button = buttonsts;
+		int button = cam->buttonsts;
 		unsigned char sts;
 		int n = dataurb->iso_frame_desc[i].actual_length;
 		int st = dataurb->iso_frame_desc[i].status;
-		cdata = dataurb->transfer_buffer + 
+		cdata = dataurb->transfer_buffer +
 			dataurb->iso_frame_desc[i].offset;
 
 		/* Detect and ignore errored packets */
 		if (st < 0) {
-			if (debug >= 1)
-				err("Data error: packet=%d. len=%d. status=%d.",
-				    i, n, st);
+			DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
+			      i, n, st);
 			uvd->stats.iso_err_count++;
 			continue;
 		}
@@ -210,8 +253,8 @@
 
 		/* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
 		 * otherwise:
-		 * bit 0 0:drop packet (padding data)
-		 *	 1 keep packet
+		 * bit 0 0: keep packet
+		 *	 1: drop packet (padding data)
 		 *
 		 * bit 4 0 button not clicked
 		 *       1 button clicked
@@ -219,16 +262,20 @@
 		 */
 
 		if(sts < 0x80) {
-			button = sts & 0x40;
+			button = !!(sts & 0x40);
 			sts &= ~0x40;
 		}
 		
 		/* work out the button status, but dont do
 		   anything with it for now */
-		   
-		if(button != buttonsts) {
-			dbg("button: %sclicked", button ? "" : "un");
-			buttonsts = button;
+
+		if(button != cam->buttonsts) {
+			DEBUG(2, "button: %sclicked", button ? "" : "un");
+			cam->buttonsts = button;
+#ifdef CONFIG_INPUT
+			input_report_key(&cam->input, BTN_0, cam->buttonsts);
+			input_sync(&cam->input);
+#endif
 		}
 
 		if(sts == 0x01) { /* drop frame */
@@ -241,35 +288,53 @@
 			bad++;
 			continue;
 		}
+		if(!sts && cam->lastframe == -2) {
+			DEBUG(2, "dropping frame looking for image start");
+			continue;
+		}
 
 		keep++;
-		if(*(status+i) & 0x80) { /* frame start */
+		if(sts & 0x80) { /* frame start */
 			unsigned char marker[] = { 0, 0xff, 0, 0x00 };
-			if(debug > 1)
-				dbg("Adding Marker packet = %d, frame = %2.2x",
-				    i, *(status+i));
-			marker[3] = *(status+i) - 0x80;
-			RingQueue_Enqueue(&uvd->dp, marker, 4);			
+
+			if(cam->lastframe == -2) {
+				DEBUG(2, "found initial image");
+				cam->lastframe = -1;
+			}
+				
+			marker[3] = sts & 0x7F;
+			RingQueue_Enqueue(&uvd->dp, marker, 4);
 			totlen += 4;
 		}
+
 		totlen += n;	/* Little local accounting */
-		if(debug > 5)
-			dbg("Adding packet %d, bytes = %d", i, n);
 		RingQueue_Enqueue(&uvd->dp, cdata, n);
-
 	}
-	if(debug > 8) {
-		dbg("finished: keep = %d discard = %d bad = %d added %d bytes",
+	DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
 		    keep, discard, bad, totlen);
-	}
 	return totlen;
 }
 
 
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+        int i, ret;
+        for (i = 0; i < FRAMES_PER_DESC; i++) {
+                urb->iso_frame_desc[i].status = 0;
+        }
+        urb->dev = uvd->dev;
+        urb->status = 0;
+        ret = usb_submit_urb(urb, GFP_KERNEL);
+	DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
+        if(ret)
+                err("usb_submit_urb error (%d)", ret);
+
+}
+
+
 static void konicawc_isoc_irq(struct urb *urb)
 {
-	int i, ret, len = 0;
-	uvd_t *uvd = urb->context;
+	struct uvd *uvd = urb->context;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
 	/* We don't want to do anything if we are about to be removed! */
@@ -277,58 +342,56 @@
 		return;
 
 	if (!uvd->streaming) {
-		if (debug >= 1)
-			info("Not streaming, but interrupt!");
+		DEBUG(1, "Not streaming, but interrupt!");
 		return;
 	}
 
-	if (urb->actual_length > 32) {
-		cam->last_data_urb = urb;
-		goto urb_done_with;
-	}
+	DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
 
 	uvd->stats.urb_count++;
-	if (urb->actual_length <= 0)
-		goto urb_done_with;
 
+	if (urb->transfer_buffer_length > 32) {
+		cam->last_data_urb = urb;
+		return;
+	}
 	/* Copy the data received into ring queue */
 	if(cam->last_data_urb) {
-		len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
-		for (i = 0; i < FRAMES_PER_DESC; i++) {
-			cam->last_data_urb->iso_frame_desc[i].status = 0;
-		}
+		int len = 0;
+		if(urb->start_frame != cam->last_data_urb->start_frame)
+			err("Lost sync on frames");
+		else if (!urb->status && !cam->last_data_urb->status)
+			len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
+
+		resubmit_urb(uvd, urb);
+		resubmit_urb(uvd, cam->last_data_urb);
 		cam->last_data_urb = NULL;
+		uvd->stats.urb_length = len;
+		uvd->stats.data_count += len;
+		if(len)
+			RingQueue_WakeUpInterruptible(&uvd->dp);
+		return;
 	}
-	uvd->stats.urb_length = len;
-	uvd->stats.data_count += len;
-	if(len)
-		RingQueue_WakeUpInterruptible(&uvd->dp);
-
-urb_done_with:
-	for (i = 0; i < FRAMES_PER_DESC; i++) {
-		urb->iso_frame_desc[i].status = 0;
-	}
-	urb->dev = uvd->dev;
-	urb->status = 0;
-	ret = usb_submit_urb(urb, GFP_KERNEL);
-	if(ret)
-		err("usb_submit_urb error (%d)", ret);
 	return;
 }
 
 
-static int konicawc_start_data(uvd_t *uvd)
+static int konicawc_start_data(struct uvd *uvd)
 {
 	struct usb_device *dev = uvd->dev;
 	int i, errFlag;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int pktsz;
+	struct usb_interface_descriptor *interface;
 
+	interface = &dev->actconfig->interface[uvd->iface].altsetting[spd_to_iface[cam->speed]];
+	pktsz = interface->endpoint[1].wMaxPacketSize;
+	DEBUG(1, "pktsz = %d", pktsz);
 	if (!CAMERA_IS_OPERATIONAL(uvd)) {
 		err("Camera is not operational");
 		return -EFAULT;
 	}
 	uvd->curframe = -1;
-
+	konicawc_camera_on(uvd);
 	/* Alternate interface 1 is is the biggest frame size */
 	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
 	if (i < 0) {
@@ -349,10 +412,10 @@
 		urb->transfer_buffer = uvd->sbuf[i].data;
 		urb->complete = konicawc_isoc_irq;
 		urb->number_of_packets = FRAMES_PER_DESC;
-		urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
-		for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
+		urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+		for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
 			urb->iso_frame_desc[j].offset = k;
-			urb->iso_frame_desc[j].length = uvd->iso_packet_len;
+			urb->iso_frame_desc[j].length = pktsz;
 		}
 
 		urb = cam->sts_urb[i];
@@ -375,23 +438,22 @@
 	
 	/* Submit all URBs */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-		if (errFlag)
-			err ("usb_submit_isoc(%d) ret %d", i, errFlag);
-
 		errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
 		if (errFlag)
 			err("usb_submit_isoc(%d) ret %d", i, errFlag);
+
+		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+		if (errFlag)
+			err ("usb_submit_isoc(%d) ret %d", i, errFlag);
 	}
 
 	uvd->streaming = 1;
-	if (debug > 1)
-		dbg("streaming=1 video_endp=$%02x", uvd->video_endp);
+	DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
 	return 0;
 }
 
 
-static void konicawc_stop_data(uvd_t *uvd)
+static void konicawc_stop_data(struct uvd *uvd)
 {
 	int i, j;
 	struct konicawc *cam;
@@ -399,6 +461,8 @@
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
 
+	konicawc_camera_off(uvd);
+	uvd->streaming = 0;
 	cam = (struct konicawc *)uvd->user_data;
 	cam->last_data_urb = NULL;
 
@@ -413,8 +477,6 @@
 			err("usb_unlink_urb() error %d.", j);
 	}
 
-	uvd->streaming = 0;
-
 	if (!uvd->remove_pending) {
 		/* Set packet size to 0 */
 		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
@@ -426,44 +488,35 @@
 }
 
 
-static void konicawc_process_isoc(uvd_t *uvd, usbvideo_frame_t *frame)
+static void konicawc_process_isoc(struct uvd *uvd, usbvideo_frame_t *frame)
 {	
-	int n;
-	int maxline, yplanesz;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
-	assert(uvd != NULL);
+	int maxline = cam->maxline;
+	int yplanesz = cam->yplanesz;
+
 	assert(frame != NULL);
 
-	maxline = (cam->height * cam->width * 3) / (2 * 384);
-	yplanesz = cam->height * cam->width;
-	if(debug > 5)
-		dbg("maxline = %d yplanesz = %d", maxline, yplanesz);
-	
-	if(debug > 3)
-		dbg("Frame state = %d", frame->scanstate);
+	DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
+	DEBUG(3, "Frame state = %d", frame->scanstate);
 
 	if(frame->scanstate == ScanState_Scanning) {
 		int drop = 0;
 		int curframe;
 		int fdrops = 0;
-		if(debug > 3)
-			dbg("Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
+		DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
 		while(RingQueue_GetLength(&uvd->dp) >= 4) {
 			if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
 			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
 			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
 			    (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
 				curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
-				if(cam->lastframe != -1) {
-					if(curframe < cam->lastframe) {
-						fdrops = (curframe + 0x80) - cam->lastframe;
-					} else {
-						fdrops = curframe - cam->lastframe;
-					}
+				if(cam->lastframe >= 0) {
+					fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
 					fdrops--;
-					if(fdrops)
+					if(fdrops) {
 						info("Dropped %d frames (%d -> %d)", fdrops,
 						     cam->lastframe, curframe);
+					}
 				}
 				cam->lastframe = curframe;
 				frame->curline = 0;
@@ -474,18 +527,20 @@
 			RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
 			drop++;
 		}
+		if(drop)
+			DEBUG(2, "dropped %d bytes looking for new frame", drop);
 	}
 
 	if(frame->scanstate == ScanState_Scanning)
 		return;
 		
-	/* Try to move data from queue into frame buffer 
+	/* Try to move data from queue into frame buffer
 	 * We get data in blocks of 384 bytes made up of:
 	 * 256 Y, 64 U, 64 V.
 	 * This needs to be written out as a Y plane, a U plane and a V plane.
 	 */
 		
-	while ( frame->curline < maxline && (n = RingQueue_GetLength(&uvd->dp)) >= 384) {
+	while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
 		/* Y */
 		RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
 		/* U */
@@ -497,8 +552,7 @@
 	}
 	/* See if we filled the frame */
 	if (frame->curline == maxline) {
-		if(debug > 5)
-			dbg("got whole frame");
+		DEBUG(5, "got whole frame");
 
 		frame->frameState = FrameState_Done_Hold;
 		frame->curline = 0;
@@ -508,16 +562,105 @@
 }
 
 
-static int konicawc_calculate_fps(uvd_t *uvd)
+static int konicawc_find_fps(int size, int fps)
+{
+	int i;
+
+	fps *= 3;
+	DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
+	if(fps <= spd_to_fps[size][0])
+		return 0;
+
+	if(fps >= spd_to_fps[size][MAX_SPEED])
+		return MAX_SPEED;
+
+	for(i = 0; i < MAX_SPEED; i++) {
+		if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
+			DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
+			if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
+				return i;
+			else
+				return i+1;
+		}
+	}
+	return MAX_SPEED+1;
+}
+
+
+static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
 {
-	struct konicawc *t = uvd->user_data;
-	dbg("fps = %d", speed_to_fps[t->size][t->speed]/3);
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int newspeed = cam->speed;
+	int newsize;
+	int x = vw->width;
+	int y = vw->height;
+	int fps = vw->flags;
+
+	if(x > 0 && y > 0) {
+		DEBUG(2, "trying to find size %d,%d", x, y);
+		for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+			if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
+				break;
+		}
+	} else {
+		newsize = cam->size;
+	}
 
-	return speed_to_fps[t->size][t->speed]/3;
+	if(newsize > MAX_FRAME_SIZE) {
+		DEBUG(1, "couldnt find size %d,%d", x, y);
+		return -EINVAL;
+	}
+
+	if(fps > 0) {
+		DEBUG(1, "trying to set fps to %d", fps);
+		newspeed = konicawc_find_fps(newsize, fps);
+		DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
+	}
+
+	if(newspeed > MAX_SPEED)
+		return -EINVAL;
+
+	DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
+	if((newsize == cam->size) && (newspeed == cam->speed)) {
+		DEBUG(1, "Nothing to do");
+		return 0;
+	}
+	DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
+	     camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
+
+	konicawc_stop_data(uvd);
+	uvd->ifaceAltActive = spd_to_iface[newspeed];
+	DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
+	cam->speed = newspeed;
+
+	if(cam->size != newsize) {
+		cam->size = newsize;
+		konicawc_set_camera_size(uvd);
+	}
+
+	/* Flush the input queue and clear any current frame in progress */
+
+	RingQueue_Flush(&uvd->dp);
+	cam->lastframe = -2;
+	if(uvd->curframe != -1) {
+	  uvd->frame[uvd->curframe].curline = 0;
+	  uvd->frame[uvd->curframe].seqRead_Length = 0;
+	  uvd->frame[uvd->curframe].seqRead_Index = 0;
+	}
+
+	konicawc_start_data(uvd);
+	return 0;
 }
 
 
-static void konicawc_configure_video(uvd_t *uvd)
+static int konicawc_calculate_fps(struct uvd *uvd)
+{
+	struct konicawc *cam = uvd->user_data;
+	return spd_to_fps[cam->size][cam->speed]/3;
+}
+
+
+static void konicawc_configure_video(struct uvd *uvd)
 {
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 	u8 buf[2];
@@ -550,10 +693,10 @@
 	uvd->vcap.type = VID_TYPE_CAPTURE;
 	uvd->vcap.channels = 1;
 	uvd->vcap.audios = 0;
-	uvd->vcap.minwidth = camera_sizes[cam->size][0];
-	uvd->vcap.minheight = camera_sizes[cam->size][1];
-	uvd->vcap.maxwidth = camera_sizes[cam->size][0];
-	uvd->vcap.maxheight = camera_sizes[cam->size][1];
+	uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+	uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+	uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+	uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
 
 	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
 	uvd->vchan.flags = 0 ;
@@ -563,27 +706,25 @@
 	strcpy(uvd->vchan.name, "Camera");
 
 	/* Talk to device */
-	dbg("device init");
+	DEBUG(1, "device init");
 	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-		dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
 	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-		dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
 	if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
-		dbg("2,0,d failed");
-	dbg("setting initial values");
-
+		DEBUG(2, "2,0,d failed");
+	DEBUG(1, "setting initial values");
 }
 
 
 static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
 {
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 	int i, nas;
 	int actInterface=-1, inactInterface=-1, maxPS=0;
 	unsigned char video_ep = 0;
-	
-	if (debug >= 1)
-		dbg("konicawc_probe(%p,%u.)", dev, ifnum);
+
+	DEBUG(1, "konicawc_probe(%p,%u.)", dev, ifnum);
 
 	/* We don't handle multi-config cameras */
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -594,10 +735,8 @@
 
 	/* Validate found interface: must have one ISO endpoint */
 	nas = dev->actconfig->interface[ifnum].num_altsetting;
-	if (debug > 0)
-		info("Number of alternate settings=%d.", nas);
-	if (nas < 8) {
-		err("Too few alternate settings for this camera!");
+	if (nas != 8) {
+		err("Incorrect number of alternate settings (%d) for this camera!", nas);
 		return NULL;
 	}
 	/* Validate all alternate settings */
@@ -612,7 +751,7 @@
 			return NULL;
 		}
 		endpoint = &interface->endpoint[1];
-		dbg("found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
+		DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
 		    endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
 		if (video_ep == 0)
 			video_ep = endpoint->bEndpointAddress;
@@ -636,29 +775,27 @@
 				return NULL;
 			}
 		} else {
-			if (i == speed_to_interface[speed]) {
+			if (i == spd_to_iface[speed]) {
 				/* This one is the requested one */
 				actInterface = i;
-				maxPS = endpoint->wMaxPacketSize;
-				if (debug > 0) {
-					info("Selecting requested active setting=%d. maxPS=%d.",
-					     i, maxPS);
-				}
 			}
 		}
+		if(endpoint->wMaxPacketSize > maxPS)
+			maxPS = endpoint->wMaxPacketSize;
 	}
 	if(actInterface == -1) {
 		err("Cant find required endpoint");
 		return NULL;
 	}
 
+	DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
 
 	/* Code below may sleep, need to lock module while we are here */
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
 		struct konicawc *cam = (struct konicawc *)(uvd->user_data);
-		/* Here uvd is a fully allocated uvd_t object */
+		/* Here uvd is a fully allocated uvd object */
 		for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
 			cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 			if(cam->sts_urb[i] == NULL) {
@@ -670,26 +807,10 @@
 			}
 		}
 		cam->speed = speed;
-		switch(size) {
-		case SIZE_160X136:
-		default:
-			cam->height = 136;
-			cam->width = 160;
-			cam->size = SIZE_160X136;
-			break;
-
-		case SIZE_176X144:
-			cam->height = 144;
-			cam->width = 176;
-			cam->size = SIZE_176X144;
-			break;
-
-		case SIZE_320X240:
-			cam->height = 240;
-			cam->width = 320;
-			cam->size = SIZE_320X240;
-			break;
-		}
+		RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+		cam->width = camera_sizes[size].width;
+		cam->height = camera_sizes[size].height;
+		cam->size = size;
 
 		uvd->flags = 0;
 		uvd->debug = debug;
@@ -701,29 +822,50 @@
 		uvd->iso_packet_len = maxPS;
 		uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
 		uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
-		uvd->canvas = VIDEOSIZE(cam->width, cam->height);
-		uvd->videosize = uvd->canvas;
+		uvd->canvas = VIDEOSIZE(320, 240);
+		uvd->videosize = VIDEOSIZE(cam->width, cam->height);
 
 		/* Initialize konicawc specific data */
 		konicawc_configure_video(uvd);
 
 		i = usbvideo_RegisterVideoDevice(uvd);
-		uvd->max_frame_size = (cam->width * cam->height * 3)/2;
+		uvd->max_frame_size = (320 * 240 * 3)/2;
 		if (i != 0) {
 			err("usbvideo_RegisterVideoDevice() failed.");
 			uvd = NULL;
 		}
+#ifdef CONFIG_INPUT
+		/* Register input device for button */
+		memset(&cam->input, 0, sizeof(struct input_dev));
+		cam->input.name = "Konicawc snapshot button";
+		cam->input.private = cam;
+		cam->input.evbit[0] = BIT(EV_KEY);
+		cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+		cam->input.id.bustype = BUS_USB;
+		cam->input.id.vendor = dev->descriptor.idVendor;
+		cam->input.id.product = dev->descriptor.idProduct;
+		cam->input.id.version = dev->descriptor.bcdDevice;
+		input_register_device(&cam->input);
+		
+		usb_make_path(dev, cam->input_physname, 56);
+		strcat(cam->input_physname, "/input0");
+		cam->input.phys = cam->input_physname;
+		info("konicawc: %s on %s\n", cam->input.name, cam->input.phys);
+#endif
 	}
 	MOD_DEC_USE_COUNT;
 	return uvd;
 }
 
 
-static void konicawc_free_uvd(uvd_t *uvd)
+static void konicawc_free_uvd(struct uvd *uvd)
 {
 	int i;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
+#ifdef CONFIG_INPUT
+	input_unregister_device(&cam->input);
+#endif
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		usb_free_urb(cam->sts_urb[i]);
 		cam->sts_urb[i] = NULL;
@@ -746,6 +888,7 @@
 	cbTbl.setupOnOpen = konicawc_setup_on_open;
 	cbTbl.processData = konicawc_process_isoc;
 	cbTbl.getFPS = konicawc_calculate_fps;
+	cbTbl.setVideoMode = konicawc_set_video_mode;
 	cbTbl.startDataPump = konicawc_start_data;
 	cbTbl.stopDataPump = konicawc_stop_data;
 	cbTbl.adjustPicture = konicawc_adjust_picture;
@@ -773,9 +916,9 @@
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_PARM(speed, "i");
-MODULE_PARM_DESC(speed, "FPS speed: 0 (slowest) - 6 (fastest)");
+MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
 MODULE_PARM(size, "i");
-MODULE_PARM_DESC(size, "Frame Size 0: 160x136 1: 176x144 2: 320x240");
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
 MODULE_PARM(brightness, "i");
 MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
 MODULE_PARM(contrast, "i");
@@ -786,7 +929,11 @@
 MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
 MODULE_PARM(whitebal, "i");
 MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
+
+#ifdef CONFIG_USB_DEBUG
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
 module_init(konicawc_init);
 module_exit(konicawc_cleanup);
diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
--- a/drivers/usb/media/ultracam.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/usb/media/ultracam.c	Tue Aug 27 12:28:01 2002
@@ -103,7 +103,7 @@
  * 02-Nov-2000 First (mostly dummy) version.
  * 06-Nov-2000 Rewrote to dump all data into frame.
  */
-void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+void ultracam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame)
 {
 	int n;
 
@@ -140,7 +140,7 @@
  * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
  */
 static int ultracam_veio(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	unsigned char req,
 	unsigned short value,
 	unsigned short index,
@@ -193,7 +193,7 @@
 /*
  * ultracam_calculate_fps()
  */
-static int ultracam_calculate_fps(uvd_t *uvd)
+static int ultracam_calculate_fps(struct uvd *uvd)
 {
 	return 3 + framerate*4 + framerate/2;
 }
@@ -201,14 +201,14 @@
 /*
  * ultracam_adjust_contrast()
  */
-static void ultracam_adjust_contrast(uvd_t *uvd)
+static void ultracam_adjust_contrast(struct uvd *uvd)
 {
 }
 
 /*
  * ultracam_change_lighting_conditions()
  */
-static void ultracam_change_lighting_conditions(uvd_t *uvd)
+static void ultracam_change_lighting_conditions(struct uvd *uvd)
 {
 }
 
@@ -219,7 +219,7 @@
  * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
  * Recommended value is 4. Cameras model 2 do not have this feature at all.
  */
-static void ultracam_set_sharpness(uvd_t *uvd)
+static void ultracam_set_sharpness(struct uvd *uvd)
 {
 }
 
@@ -228,11 +228,11 @@
  *
  * This procedure changes brightness of the picture.
  */
-static void ultracam_set_brightness(uvd_t *uvd)
+static void ultracam_set_brightness(struct uvd *uvd)
 {
 }
 
-static void ultracam_set_hue(uvd_t *uvd)
+static void ultracam_set_hue(struct uvd *uvd)
 {
 }
 
@@ -242,7 +242,7 @@
  * This procedure gets called from V4L interface to update picture settings.
  * Here we change brightness and contrast.
  */
-static void ultracam_adjust_picture(uvd_t *uvd)
+static void ultracam_adjust_picture(struct uvd *uvd)
 {
 	ultracam_adjust_contrast(uvd);
 	ultracam_set_brightness(uvd);
@@ -255,7 +255,7 @@
  * This code tells camera to stop streaming. The interface remains
  * configured and bandwidth - claimed.
  */
-static void ultracam_video_stop(uvd_t *uvd)
+static void ultracam_video_stop(struct uvd *uvd)
 {
 }
 
@@ -266,24 +266,24 @@
  * resets the video pipe. This sequence was observed to reinit the
  * camera or, at least, to initiate ISO data stream.
  */
-static void ultracam_reinit_iso(uvd_t *uvd, int do_stop)
+static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
 {
 }
 
-static void ultracam_video_start(uvd_t *uvd)
+static void ultracam_video_start(struct uvd *uvd)
 {
 	ultracam_change_lighting_conditions(uvd);
 	ultracam_set_sharpness(uvd);
 	ultracam_reinit_iso(uvd, 0);
 }
 
-static int ultracam_resetPipe(uvd_t *uvd)
+static int ultracam_resetPipe(struct uvd *uvd)
 {
 	usb_clear_halt(uvd->dev, uvd->video_endp);
 	return 0;
 }
 
-static int ultracam_alternateSetting(uvd_t *uvd, int setting)
+static int ultracam_alternateSetting(struct uvd *uvd, int setting)
 {
 	static const char proc[] = "ultracam_alternateSetting";
 	int i;
@@ -299,7 +299,7 @@
 /*
  * Return negative code on failure, 0 on success.
  */
-static int ultracam_setup_on_open(uvd_t *uvd)
+static int ultracam_setup_on_open(struct uvd *uvd)
 {
 	int setup_ok = 0; /* Success by default */
 	/* Send init sequence only once, it's large! */
@@ -487,7 +487,7 @@
 	return setup_ok;
 }
 
-static void ultracam_configure_video(uvd_t *uvd)
+static void ultracam_configure_video(struct uvd *uvd)
 {
 	if (uvd == NULL)
 		return;
@@ -539,7 +539,7 @@
  */
 static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
 {
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 	int i, nas;
 	int actInterface=-1, inactInterface=-1, maxPS=0;
 	unsigned char video_ep = 0;
@@ -628,7 +628,7 @@
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		/* Here uvd is a fully allocated uvd_t object */
+		/* Here uvd is a fully allocated uvd object */
 		uvd->flags = flags;
 		uvd->debug = debug;
 		uvd->dev = dev;
diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
--- a/drivers/usb/media/usbvideo.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/usb/media/usbvideo.c	Tue Aug 27 12:28:06 2002
@@ -44,8 +44,8 @@
 #if USES_PROC_FS
 static void usbvideo_procfs_level1_create(usbvideo_t *ut);
 static void usbvideo_procfs_level1_destroy(usbvideo_t *ut);
-static void usbvideo_procfs_level2_create(uvd_t *uvd);
-static void usbvideo_procfs_level2_destroy(uvd_t *uvd);
+static void usbvideo_procfs_level2_create(struct uvd *uvd);
+static void usbvideo_procfs_level2_destroy(struct uvd *uvd);
 static int usbvideo_default_procfs_read_proc(
 	char *page, char **start, off_t off, int count,
 	int *eof, void *data);
@@ -55,7 +55,7 @@
 #endif
 
 static void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
-static void usbvideo_CameraRelease(uvd_t *uvd);
+static void usbvideo_CameraRelease(struct uvd *uvd);
 
 static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
 			      unsigned int cmd, unsigned long arg);
@@ -65,11 +65,11 @@
 			     size_t count, loff_t *ppos);
 static int usbvideo_v4l_close(struct inode *inode, struct file *file);
 
-static int usbvideo_StartDataPump(uvd_t *uvd);
-static void usbvideo_StopDataPump(uvd_t *uvd);
-static int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
-static int usbvideo_NewFrame(uvd_t *uvd, int framenum);
-static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd,
+static int usbvideo_StartDataPump(struct uvd *uvd);
+static void usbvideo_StopDataPump(struct uvd *uvd);
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
 						usbvideo_frame_t *frame);
 
 /*******************************/
@@ -135,9 +135,21 @@
 
 static void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
 {
+	/* Make sure the requested size is a power of 2 and
+	   round up if necessary. This allows index wrapping
+	   using masks rather than modulo */
+
+	int i = 1;
 	assert(rq != NULL);
 	assert(rqLen > 0);
+
+	while(rqLen >> i)
+		i++;
+	if(rqLen != 1 << (i-1))
+		rqLen = 1 << i;
+
 	rq->length = rqLen;
+	rq->ri = rq->wi = 0;
 	rq->queue = usbvideo_rvmalloc(rq->length);
 	assert(rq->queue != NULL);
 }
@@ -161,12 +173,32 @@
 
 int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len)
 {
-	int i;
+	int rql, toread;
+
 	assert(rq != NULL);
 	assert(dst != NULL);
-	for (i=0; i < len; i++) {
-		dst[i] = rq->queue[rq->ri];
-		RING_QUEUE_DEQUEUE_BYTES(rq,1);
+
+	rql = RingQueue_GetLength(rq);
+	if(!rql)
+		return 0;
+
+	/* Clip requested length to available data */
+	if(len > rql)
+		len = rql;
+
+	toread = len;
+	if(rq->ri > rq->wi) {
+		/* Read data from tail */
+		int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
+		memcpy(dst, rq->queue + rq->ri, read);
+		toread -= read;
+		dst += read;
+		rq->ri = (rq->ri + read) & (rq->length-1);
+	}
+	if(toread) {
+		/* Read data from head */
+		memcpy(dst, rq->queue + rq->ri, toread);
+		rq->ri = (rq->ri + toread) & (rq->length-1);
 	}
 	return len;
 }
@@ -194,7 +226,7 @@
 		if (m > q_avail)
 			m = q_avail;
 
-		memmove(rq->queue + rq->wi, cdata, m);
+		memcpy(rq->queue + rq->wi, cdata, m);
 		RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
 		cdata += m;
 		enqueued += m;
@@ -205,24 +237,6 @@
 
 EXPORT_SYMBOL(RingQueue_Enqueue);
 
-int RingQueue_GetLength(const RingQueue_t *rq)
-{
-	int ri, wi;
-
-	assert(rq != NULL);
-
-	ri = rq->ri;
-	wi = rq->wi;
-	if (ri == wi)
-		return 0;
-	else if (ri < wi)
-		return wi - ri;
-	else
-		return wi + (rq->length - ri);
-}
-
-EXPORT_SYMBOL(RingQueue_GetLength);
-
 static void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
 {
 	assert(rq != NULL);
@@ -238,6 +252,16 @@
 
 EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
 
+void RingQueue_Flush(RingQueue_t *rq)
+{
+	assert(rq != NULL);
+	rq->ri = 0;
+	rq->wi = 0;
+}
+
+EXPORT_SYMBOL(RingQueue_Flush);
+
+
 /*
  * usbvideo_VideosizeToString()
  *
@@ -266,7 +290,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-static void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
+static void usbvideo_OverlayChar(struct uvd *uvd, usbvideo_frame_t *frame,
 				 int x, int y, int ch)
 {
 	static const unsigned short digits[16] = {
@@ -321,7 +345,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-static void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
+static void usbvideo_OverlayString(struct uvd *uvd, usbvideo_frame_t *frame,
 				   int x, int y, const char *str)
 {
 	while (*str) {
@@ -339,7 +363,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-static void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
+static void usbvideo_OverlayStats(struct uvd *uvd, usbvideo_frame_t *frame)
 {
 	const int y_diff = 8;
 	char tmp[16];
@@ -374,7 +398,7 @@
 		q_used = RingQueue_GetLength(&uvd->dp);
 		if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
 			u_hi = uvd->dp.length;
-			u_lo = (q_used + uvd->dp.ri) % uvd->dp.length;
+			u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
 		} else {
 			u_hi = (q_used + uvd->dp.ri);
 			u_lo = -1;
@@ -462,7 +486,7 @@
  * History:
  * 14-Jan-2000 Corrected default multiplier.
  */
-static void usbvideo_ReportStatistics(const uvd_t *uvd)
+static void usbvideo_ReportStatistics(const struct uvd *uvd)
 {
 	if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
 		unsigned long allPackets, badPackets, goodPackets, percent;
@@ -590,20 +614,19 @@
  * History:
  * 01-Feb-2000 Created.
  */
-void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode)
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
 {
-	static const char proc[] = "usbvideo_TestPattern";
 	usbvideo_frame_t *frame;
 	int num_cell = 0;
 	int scan_length = 0;
 	static int num_pass = 0;
 
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-		err("%s: uvd->curframe=%d.", proc, uvd->curframe);
+		err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
 		return;
 	}
 
@@ -707,37 +730,35 @@
 
 /* ******************************************************************** */
 
-static void usbvideo_ClientIncModCount(uvd_t *uvd)
+static void usbvideo_ClientIncModCount(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_ClientIncModCount";
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", proc);
+		err("%s: uvd->handle == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", proc);
+		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
 		return;
 	}
 	__MOD_INC_USE_COUNT(uvd->handle->md_module);
 }
 
-static void usbvideo_ClientDecModCount(uvd_t *uvd)
+static void usbvideo_ClientDecModCount(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_ClientDecModCount";
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", proc);
+		err("%s: uvd->handle == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", proc);
+		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
 		return;
 	}
 	__MOD_DEC_USE_COUNT(uvd->handle->md_module);
@@ -752,30 +773,29 @@
 	struct module *md,
 	const struct usb_device_id *id_table)
 {
-	static const char proc[] = "usbvideo_register";
 	usbvideo_t *cams;
 	int i, base_size;
 
 	/* Check parameters for sanity */
 	if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-		err("%s: Illegal call", proc);
+		err("%s: Illegal call", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	/* Check registration callback - must be set! */
 	if (cbTbl->probe == NULL) {
-		err("%s: probe() is required!", proc);
+		err("%s: probe() is required!", __FUNCTION__);
 		return -EINVAL;
 	}
 
-	base_size = num_cams * sizeof(uvd_t) + sizeof(usbvideo_t);
+	base_size = num_cams * sizeof(struct uvd) + sizeof(usbvideo_t);
 	cams = (usbvideo_t *) kmalloc(base_size, GFP_KERNEL);
 	if (cams == NULL) {
 		err("Failed to allocate %d. bytes for usbvideo_t", base_size);
 		return -ENOMEM;
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-	    proc, cams, base_size, num_cams);
+	    __FUNCTION__, cams, base_size, num_cams);
 	memset(cams, 0, base_size);
 
 	/* Copy callbacks, apply defaults for those that are not set */
@@ -807,14 +827,14 @@
 	}
 #endif
 	cams->num_cameras = num_cams;
-	cams->cam = (uvd_t *) &cams[1];
+	cams->cam = (struct uvd *) &cams[1];
 	cams->md_module = md;
 	if (cams->md_module == NULL)
-		warn("%s: module == NULL!", proc);
+		warn("%s: module == NULL!", __FUNCTION__);
 	init_MUTEX(&cams->lock);	/* to 1 == available */
 
 	for (i = 0; i < num_cams; i++) {
-		uvd_t *up = &cams->cam[i];
+		struct uvd *up = &cams->cam[i];
 
 		up->handle = cams;
 
@@ -825,11 +845,11 @@
 			if (up->user_data == NULL) {
 				up->user_size = 0;
 				err("%s: Failed to allocate user_data (%d. bytes)",
-				    proc, up->user_size);
+				    __FUNCTION__, up->user_size);
 				return -ENOMEM;
 			}
 			dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-			     proc, i, up->user_data, up->user_size);
+			     __FUNCTION__, i, up->user_data, up->user_size);
 		}
 	}
 
@@ -844,7 +864,7 @@
 
 #if USES_PROC_FS
 	if (cams->uses_procfs) {
-		dbg("%s: Creating /proc filesystem entries.", proc);
+		dbg("%s: Creating /proc filesystem entries.", __FUNCTION__);
 		usbvideo_procfs_level1_create(cams);
 	}
 #endif
@@ -871,33 +891,32 @@
  */
 void usbvideo_Deregister(usbvideo_t **pCams)
 {
-	static const char proc[] = "usbvideo_deregister";
 	usbvideo_t *cams;
 	int i;
 
 	if (pCams == NULL) {
-		err("%s: pCams == NULL", proc);
+		err("%s: pCams == NULL", __FUNCTION__);
 		return;
 	}
 	cams = *pCams;
 	if (cams == NULL) {
-		err("%s: cams == NULL", proc);
+		err("%s: cams == NULL", __FUNCTION__);
 		return;
 	}
 
 #if USES_PROC_FS
 	if (cams->uses_procfs) {
-		dbg("%s: Deregistering filesystem entries.", proc);
+		dbg("%s: Deregistering filesystem entries.", __FUNCTION__);
 		usbvideo_procfs_level1_destroy(cams);
 	}
 #endif
 
-	dbg("%s: Deregistering %s driver.", proc, cams->drvName);
+	dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
 	usb_deregister(&cams->usbdrv);
 
-	dbg("%s: Deallocating cams=$%p (%d. cameras)", proc, cams, cams->num_cameras);
+	dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
 	for (i=0; i < cams->num_cameras; i++) {
-		uvd_t *up = &cams->cam[i];
+		struct uvd *up = &cams->cam[i];
 		int warning = 0;
 
 		if (up->user_data != NULL) {
@@ -909,16 +928,16 @@
 		}
 		if (warning) {
 			err("%s: Warning: user_data=$%p user_size=%d.",
-			    proc, up->user_data, up->user_size);
+			    __FUNCTION__, up->user_data, up->user_size);
 		} else {
 			dbg("%s: Freeing %d. $%p->user_data=$%p",
-			    proc, i, up, up->user_data);
+			    __FUNCTION__, i, up, up->user_data);
 			kfree(up->user_data);
 		}
 	}
 	/* Whole array was allocated in one chunk */
-	dbg("%s: Freed %d uvd_t structures",
-	    proc, cams->num_cameras);
+	dbg("%s: Freed %d uvd structures",
+	    __FUNCTION__, cams->num_cameras);
 	kfree(cams);
 	*pCams = NULL;
 }
@@ -949,17 +968,16 @@
  */
 static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
 {
-	static const char proc[] = "usbvideo_Disconnect";
-	uvd_t *uvd = (uvd_t *) ptr;
+	struct uvd *uvd = (struct uvd *) ptr;
 	int i;
 
 	if ((dev == NULL) || (uvd == NULL)) {
-		err("%s($%p,$%p): Illegal call.", proc, dev, ptr);
+		err("%s($%p,$%p): Illegal call.", __FUNCTION__, dev, ptr);
 		return;
 	}
 	usbvideo_ClientIncModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s(%p,%p.)", proc, dev, ptr);
+		info("%s(%p,%p.)", __FUNCTION__, dev, ptr);
 
 	down(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -975,10 +993,10 @@
 
 	video_unregister_device(&uvd->vdev);
 	if (uvd->debug > 0)
-		info("%s: Video unregistered.", proc);
+		info("%s: Video unregistered.", __FUNCTION__);
 
 	if (uvd->user)
-		info("%s: In use, disconnect pending.", proc);
+		info("%s: In use, disconnect pending.", __FUNCTION__);
 	else
 		usbvideo_CameraRelease(uvd);
 	up(&uvd->lock);
@@ -990,25 +1008,24 @@
 /*
  * usbvideo_CameraRelease()
  *
- * This code does final release of uvd_t. This happens
+ * This code does final release of uvd. This happens
  * after the device is disconnected -and- all clients
  * closed their files.
  *
  * History:
  * 27-Jan-2000 Created.
  */
-static void usbvideo_CameraRelease(uvd_t *uvd)
+static void usbvideo_CameraRelease(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_CameraRelease";
 	if (uvd == NULL) {
-		err("%s: Illegal call", proc);
+		err("%s: Illegal call", __FUNCTION__);
 		return;
 	}
 
 #if USES_PROC_FS
 	assert(uvd->handle != NULL);
 	if (uvd->handle->uses_procfs) {
-		dbg("%s: Removing /proc/%s/ filesystem entries.", proc, uvd->handle->drvName);
+		dbg("%s: Removing /proc/%s/ filesystem entries.", __FUNCTION__, uvd->handle->drvName);
 		usbvideo_procfs_level2_destroy(uvd);
 	}
 #endif
@@ -1039,7 +1056,7 @@
 	}
 	down(&cams->lock);
 	for (u = 0; u < cams->num_cameras; u++) {
-		uvd_t *uvd = &cams->cam[u];
+		struct uvd *uvd = &cams->cam[u];
 		if (!uvd->uvd_used) /* This one is free */
 		{
 			uvd->uvd_used = 1;	/* In use now */
@@ -1069,10 +1086,10 @@
 	.fops =       &usbvideo_fops,
 };
 
-uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
+struct uvd *usbvideo_AllocateDevice(usbvideo_t *cams)
 {
 	int i, devnum;
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 
 	if (cams == NULL) {
 		err("No usbvideo_t handle?");
@@ -1120,24 +1137,23 @@
 
 EXPORT_SYMBOL(usbvideo_AllocateDevice);
 
-int usbvideo_RegisterVideoDevice(uvd_t *uvd)
+int usbvideo_RegisterVideoDevice(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_RegisterVideoDevice";
 	char tmp1[20], tmp2[20];	/* Buffers for printing */
 
 	if (uvd == NULL) {
-		err("%s: Illegal call.", proc);
+		err("%s: Illegal call.", __FUNCTION__);
 		return -EINVAL;
 	}
 	if (uvd->video_endp == 0) {
-		info("%s: No video endpoint specified; data pump disabled.", proc);
+		info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
 	}
 	if (uvd->paletteBits == 0) {
-		err("%s: No palettes specified!", proc);
+		err("%s: No palettes specified!", __FUNCTION__);
 		return -EINVAL;
 	}
 	if (uvd->defaultPalette == 0) {
-		info("%s: No default palette!", proc);
+		info("%s: No default palette!", __FUNCTION__);
 	}
 
 	uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1147,17 +1163,17 @@
 
 	if (uvd->debug > 0) {
 		info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-		     proc, uvd->iface, uvd->video_endp, uvd->paletteBits);
+		     __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
 	}
 	if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("%s: video_register_device failed", proc);
+		err("%s: video_register_device failed", __FUNCTION__);
 		return -EPIPE;
 	}
 	if (uvd->debug > 1) {
-		info("%s: video_register_device() successful", proc);
+		info("%s: video_register_device() successful", __FUNCTION__);
 	}
 	if (uvd->dev == NULL) {
-		err("%s: uvd->dev == NULL", proc);
+		err("%s: uvd->dev == NULL", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -1170,7 +1186,7 @@
 	if (uvd->handle->uses_procfs) {
 		if (uvd->debug > 0) {
 			info("%s: Creating /proc/video/%s/ filesystem entries.",
-			     proc, uvd->handle->drvName);
+			     __FUNCTION__, uvd->handle->drvName);
 		}
 		usbvideo_procfs_level2_create(uvd);
 	}
@@ -1186,7 +1202,7 @@
 
 static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	uvd_t *uvd = file->private_data;
+	struct uvd *uvd = file->private_data;
 	unsigned long start = vma->vm_start;
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long page, pos;
@@ -1230,20 +1246,19 @@
  */
 static int usbvideo_v4l_open(struct inode *inode, struct file *file)
 {
-	static const char proc[] = "usbvideo_v4l_open";
 	struct video_device *dev = video_devdata(file);
-	uvd_t *uvd = (uvd_t *) dev;
+	struct uvd *uvd = (struct uvd *) dev;
 	const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
 	int i, errCode = 0;
 
 	if (uvd->debug > 1)
-		info("%s($%p", proc, dev);
+		info("%s($%p)", __FUNCTION__, dev);
 
 	usbvideo_ClientIncModCount(uvd);
 	down(&uvd->lock);
 
 	if (uvd->user) {
-		err("%s: Someone tried to open an already opened device!", proc);
+		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
 		errCode = -EBUSY;
 	} else {
 		/* Clear statistics */
@@ -1256,10 +1271,10 @@
 		/* Allocate memory for the frame buffers */
 		uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
 		uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
-		RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */
+		RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
 		if ((uvd->fbuf == NULL) ||
 		    (!RingQueue_IsAllocated(&uvd->dp))) {
-			err("%s: Failed to allocate fbuf or dp", proc);
+			err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
 			errCode = -ENOMEM;
 		} else {
 			/* Allocate all buffers */
@@ -1305,19 +1320,19 @@
 		if (errCode == 0) {
 			if (VALID_CALLBACK(uvd, setupOnOpen)) {
 				if (uvd->debug > 1)
-					info("%s: setupOnOpen callback", proc);
+					info("%s: setupOnOpen callback", __FUNCTION__);
 				errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
 				if (errCode < 0) {
 					err("%s: setupOnOpen callback failed (%d.).",
-					    proc, errCode);
+					    __FUNCTION__, errCode);
 				} else if (uvd->debug > 1) {
-					info("%s: setupOnOpen callback successful", proc);
+					info("%s: setupOnOpen callback successful", __FUNCTION__);
 				}
 			}
 			if (errCode == 0) {
 				uvd->settingsAdjusted = 0;
 				if (uvd->debug > 1)
-					info("%s: Open succeeded.", proc);
+					info("%s: Open succeeded.", __FUNCTION__);
 				uvd->user++;
 				file->private_data = uvd;
 			}
@@ -1327,7 +1342,7 @@
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s: Returning %d.", proc, errCode);
+		info("%s: Returning %d.", __FUNCTION__, errCode);
 	return errCode;
 }
 
@@ -1345,13 +1360,12 @@
  */
 static int usbvideo_v4l_close(struct inode *inode, struct file *file)
 {
-	static const char proc[] = "usbvideo_v4l_close";
 	struct video_device *dev = file->private_data;
-	uvd_t *uvd = (uvd_t *) dev;
+	struct uvd *uvd = (struct uvd *) dev;
 	int i;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, dev);
+		info("%s($%p)", __FUNCTION__, dev);
 
 	down(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1378,7 +1392,7 @@
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
-		info("%s: Completed.", proc);
+		info("%s: Completed.", __FUNCTION__);
 	file->private_data = NULL;
 	return 0;
 }
@@ -1394,7 +1408,7 @@
 static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
 				 unsigned int cmd, void *arg)
 {
-	uvd_t *uvd = file->private_data;
+	struct uvd *uvd = file->private_data;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return -EIO;
@@ -1444,6 +1458,10 @@
 		{
 			struct video_window *vw = arg;
 
+			if(VALID_CALLBACK(uvd, setVideoMode)) {
+				return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
+			}
+
 			if (vw->flags)
 				return -EINVAL;
 			if (vw->clipcount)
@@ -1461,8 +1479,8 @@
 
 			vw->x = 0;
 			vw->y = 0;
-			vw->width = VIDEOSIZE_X(uvd->canvas);
-			vw->height = VIDEOSIZE_Y(uvd->canvas);
+			vw->width = VIDEOSIZE_X(uvd->videosize);
+			vw->height = VIDEOSIZE_Y(uvd->videosize);
 			vw->chromakey = 0;
 			if (VALID_CALLBACK(uvd, getFPS))
 				vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
@@ -1619,8 +1637,7 @@
 static int usbvideo_v4l_read(struct file *file, char *buf,
 		      size_t count, loff_t *ppos)
 {
-	static const char proc[] = "usbvideo_v4l_read";
-	uvd_t *uvd = file->private_data;
+	struct uvd *uvd = file->private_data;
 	int noblock = file->f_flags & O_NONBLOCK;
 	int frmx = -1, i;
 	usbvideo_frame_t *frame;
@@ -1629,7 +1646,7 @@
 		return -EFAULT;
 
 	if (uvd->debug >= 1)
-		info("%s: %d. bytes, noblock=%d.", proc, count, noblock);
+		info("%s: %d. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 
 	down(&uvd->lock);	
 
@@ -1676,7 +1693,7 @@
 	 */
 	if (frmx == -1) {
 		if (uvd->defaultPalette == 0) {
-			err("%s: No default palette; don't know what to do!", proc);
+			err("%s: No default palette; don't know what to do!", __FUNCTION__);
 			count = -EFAULT;
 			goto read_done;
 		}
@@ -1748,7 +1765,7 @@
 	frame->seqRead_Index += count;
 	if (uvd->debug >= 1) {
 		err("%s: {copy} count used=%d, new seqRead_Index=%ld",
-			proc, count, frame->seqRead_Index);
+			__FUNCTION__, count, frame->seqRead_Index);
 	}
 
 	/* Finally check if the frame is done with and "release" it */
@@ -1759,7 +1776,7 @@
 		/* Mark it as available to be used again. */
 		uvd->frame[frmx].frameState = FrameState_Unused;
 		if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
-			err("%s: usbvideo_NewFrame failed.", proc);
+			err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
 		}
 	}
 read_done:
@@ -1770,7 +1787,7 @@
 /*
  * Make all of the blocks of data contiguous
  */
-static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
+static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
 {
 	char *cdata;
 	int i, totlen = 0;
@@ -1803,7 +1820,7 @@
 static void usbvideo_IsocIrq(struct urb *urb)
 {
 	int i, ret, len;
-	uvd_t *uvd = urb->context;
+	struct uvd *uvd = urb->context;
 
 	/* We don't want to do anything if we are about to be removed! */
 	if (!CAMERA_IS_OPERATIONAL(uvd))
@@ -1860,17 +1877,16 @@
  *             of hardcoded values. Simplified by using for loop,
  *             allowed any number of URBs.
  */
-static int usbvideo_StartDataPump(uvd_t *uvd)
+static int usbvideo_StartDataPump(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_StartDataPump";
 	struct usb_device *dev = uvd->dev;
 	int i, errFlag;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, uvd);
+		info("%s($%p)", __FUNCTION__, uvd);
 
 	if (!CAMERA_IS_OPERATIONAL(uvd)) {
-		err("%s: Camera is not operational",proc);
+		err("%s: Camera is not operational", __FUNCTION__);
 		return -EFAULT;
 	}
 	uvd->curframe = -1;
@@ -1878,14 +1894,14 @@
 	/* Alternate interface 1 is is the biggest frame size */
 	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
 	if (i < 0) {
-		err("%s: usb_set_interface error", proc);
+		err("%s: usb_set_interface error", __FUNCTION__);
 		uvd->last_error = i;
 		return -EBUSY;
 	}
 	if (VALID_CALLBACK(uvd, videoStart))
 		GET_CALLBACK(uvd, videoStart)(uvd);
 	else 
-		err("%s: videoStart not set", proc);
+		err("%s: videoStart not set", __FUNCTION__);
 
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
@@ -1910,12 +1926,12 @@
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
 		if (errFlag)
-			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
+			err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
 	}
 
 	uvd->streaming = 1;
 	if (uvd->debug > 1)
-		info("%s: streaming=1 video_endp=$%02x", proc, uvd->video_endp);
+		info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
 	return 0;
 }
 
@@ -1929,13 +1945,12 @@
  * 22-Jan-2000 Corrected order of actions to work after surprise removal.
  * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
  */
-static void usbvideo_StopDataPump(uvd_t *uvd)
+static void usbvideo_StopDataPump(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_StopDataPump";
 	int i, j;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, uvd);
+		info("%s($%p)", __FUNCTION__, uvd);
 
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
@@ -1944,10 +1959,10 @@
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		j = usb_unlink_urb(uvd->sbuf[i].urb);
 		if (j < 0)
-			err("%s: usb_unlink_urb() error %d.", proc, j);
+			err("%s: usb_unlink_urb() error %d.", __FUNCTION__, j);
 	}
 	if (uvd->debug > 1)
-		info("%s: streaming=0", proc);
+		info("%s: streaming=0", __FUNCTION__);
 	uvd->streaming = 0;
 
 	if (!uvd->remove_pending) {
@@ -1955,12 +1970,12 @@
 		if (VALID_CALLBACK(uvd, videoStop))
 			GET_CALLBACK(uvd, videoStop)(uvd);
 		else 
-			err("%s: videoStop not set" ,proc);
+			err("%s: videoStop not set", __FUNCTION__);
 
 		/* Set packet size to 0 */
 		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
 		if (j < 0) {
-			err("%s: usb_set_interface() error %d.", proc, j);
+			err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
 			uvd->last_error = j;
 		}
 	}
@@ -1973,7 +1988,7 @@
  * 29-Mar-00 Added copying of previous frame into the current one.
  * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
  */
-static int usbvideo_NewFrame(uvd_t *uvd, int framenum)
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
 {
 	usbvideo_frame_t *frame;
 	int n;
@@ -2049,7 +2064,7 @@
  * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
  * based on usbvideo can use this feature at any time.
  */
-static void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
+static void usbvideo_CollectRawData(struct uvd *uvd, usbvideo_frame_t *frame)
 {
 	int n;
 
@@ -2079,18 +2094,17 @@
 	}
 }
 
-static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
 {
-	static const char proc[] = "usbvideo_GetFrame";
 	usbvideo_frame_t *frame = &uvd->frame[frameNum];
 
 	if (uvd->debug >= 2)
-		info("%s($%p,%d.)", proc, uvd, frameNum);
+		info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
 
 	switch (frame->frameState) {
         case FrameState_Unused:
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Unused", proc);
+			info("%s: FrameState_Unused", __FUNCTION__);
 		return -EINVAL;
         case FrameState_Ready:
         case FrameState_Grabbing:
@@ -2100,7 +2114,7 @@
 	redo:
 		if (!CAMERA_IS_OPERATIONAL(uvd)) {
 			if (uvd->debug >= 2)
-				info("%s: Camera is not operational (1)", proc);
+				info("%s: Camera is not operational (1)", __FUNCTION__);
 			return -EIO;
 		}
 		ntries = 0; 
@@ -2109,24 +2123,24 @@
 			signalPending = signal_pending(current);
 			if (!CAMERA_IS_OPERATIONAL(uvd)) {
 				if (uvd->debug >= 2)
-					info("%s: Camera is not operational (2)", proc);
+					info("%s: Camera is not operational (2)", __FUNCTION__);
 				return -EIO;
 			}
 			assert(uvd->fbuf != NULL);
 			if (signalPending) {
 				if (uvd->debug >= 2)
-					info("%s: Signal=$%08x", proc, signalPending);
+					info("%s: Signal=$%08x", __FUNCTION__, signalPending);
 				if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
 					usbvideo_TestPattern(uvd, 1, 0);
 					uvd->curframe = -1;
 					uvd->stats.frame_num++;
 					if (uvd->debug >= 2)
-						info("%s: Forced test pattern screen", proc);
+						info("%s: Forced test pattern screen", __FUNCTION__);
 					return 0;
 				} else {
 					/* Standard answer: Interrupted! */
 					if (uvd->debug >= 2)
-						info("%s: Interrupted!", proc);
+						info("%s: Interrupted!", __FUNCTION__);
 					return -EINTR;
 				}
 			} else {
@@ -2136,17 +2150,17 @@
 				else if (VALID_CALLBACK(uvd, processData))
 					GET_CALLBACK(uvd, processData)(uvd, frame);
 				else 
-					err("%s: processData not set", proc);
+					err("%s: processData not set", __FUNCTION__);
 			}
 		} while (frame->frameState == FrameState_Grabbing);
 		if (uvd->debug >= 2) {
 			info("%s: Grabbing done; state=%d. (%lu. bytes)",
-			     proc, frame->frameState, frame->seqRead_Length);
+			     __FUNCTION__, frame->frameState, frame->seqRead_Length);
 		}
 		if (frame->frameState == FrameState_Error) {
 			int ret = usbvideo_NewFrame(uvd, frameNum);
 			if (ret < 0) {
-				err("%s: usbvideo_NewFrame() failed (%d.)", proc, ret);
+				err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
 				return ret;
 			}
 			goto redo;
@@ -2178,7 +2192,7 @@
 		}
 		frame->frameState = FrameState_Done_Hold;
 		if (uvd->debug >= 2)
-			info("%s: Entered FrameState_Done_Hold state.", proc);
+			info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
 		return 0;
 
 	case FrameState_Done_Hold:
@@ -2189,12 +2203,12 @@
 		 * it will be released back into the wild to roam freely.
 		 */
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Done_Hold state.", proc);
+			info("%s: FrameState_Done_Hold state.", __FUNCTION__);
 		return 0;
 	}
 
 	/* Catch-all for other cases. We shall not be here. */
-	err("%s: Invalid state %d.", proc, frame->frameState);
+	err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
 	frame->frameState = FrameState_Unused;
 	return 0;
 }
@@ -2212,7 +2226,7 @@
  * line above then we just copy next line. Similarly, if we need to
  * create a last line then preceding line is used.
  */
-void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame)
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame)
 {
 	if ((uvd == NULL) || (frame == NULL))
 		return;
@@ -2282,16 +2296,15 @@
  * History:
  * 09-Feb-2001  Created.
  */
-static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, 
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, 
 						usbvideo_frame_t *frame)
 {
-	static const char proc[] = "usbvideo_SoftwareContrastAdjustment";
 	int i, j, v4l_linesize;
 	signed long adj;
 	const int ccm = 128; /* Color correction median - see below */
 
 	if ((uvd == NULL) || (frame == NULL)) {
-		err("%s: Illegal call.", proc);
+		err("%s: Illegal call.", __FUNCTION__);
 		return;
 	}
 	adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
@@ -2343,14 +2356,12 @@
 
 static void usbvideo_procfs_level1_create(usbvideo_t *ut)
 {
-	static const char proc[] = "usbvideo_procfs_level1_create";
-
 	if (ut == NULL) {
-		err("%s: ut == NULL", proc);
+		err("%s: ut == NULL", __FUNCTION__);
 		return;
 	}
 	if (video_proc_entry == NULL) {
-		err("%s: /proc/video/ doesn't exist.", proc);
+		err("%s: /proc/video/ doesn't exist.", __FUNCTION__);
 		return;
 	}
 	ut->procfs_dEntry = create_proc_entry(ut->drvName, S_IFDIR, video_proc_entry);
@@ -2358,16 +2369,14 @@
 		if (ut->md_module != NULL)
 			ut->procfs_dEntry->owner = ut->md_module;
 	} else {
-		err("%s: Unable to initialize /proc/video/%s", proc, ut->drvName);
+		err("%s: Unable to initialize /proc/video/%s", __FUNCTION__, ut->drvName);
 	}
 }
 
 static void usbvideo_procfs_level1_destroy(usbvideo_t *ut)
 {
-	static const char proc[] = "usbvideo_procfs_level1_destroy";
-
 	if (ut == NULL) {
-		err("%s: ut == NULL", proc);
+		err("%s: ut == NULL", __FUNCTION__);
 		return;
 	}
 	if (ut->procfs_dEntry != NULL) {
@@ -2376,17 +2385,15 @@
 	}
 }
 
-static void usbvideo_procfs_level2_create(uvd_t *uvd)
+static void usbvideo_procfs_level2_create(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_procfs_level2_create";
-
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	assert(uvd->handle != NULL);
 	if (uvd->handle->procfs_dEntry == NULL) {
-		err("%s: uvd->handle->procfs_dEntry == NULL", proc);
+		err("%s: uvd->handle->procfs_dEntry == NULL", __FUNCTION__);
 		return;
 	}
 
@@ -2400,16 +2407,14 @@
 		uvd->procfs_vEntry->read_proc = uvd->handle->cb.procfs_read;
 		uvd->procfs_vEntry->write_proc = uvd->handle->cb.procfs_write;
 	} else {
-		err("%s: Failed to create entry \"%s\"", proc, uvd->videoName);
+		err("%s: Failed to create entry \"%s\"", __FUNCTION__, uvd->videoName);
 	}
 }
 
-static void usbvideo_procfs_level2_destroy(uvd_t *uvd)
+static void usbvideo_procfs_level2_destroy(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_procfs_level2_destroy";
-
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->procfs_vEntry != NULL) {
diff -Nru a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
--- a/drivers/usb/media/usbvideo.h	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/media/usbvideo.h	Tue Aug 27 12:28:02 2002
@@ -113,9 +113,10 @@
     mr = LIMIT_RGB(mm_r); \
 }
 
-#define	RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length
+#define	RING_QUEUE_SIZE		(128*1024)	/* Must be a power of 2 */
+#define	RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
 #define	RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define	RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length])
+#define	RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
 
 typedef struct {
 	unsigned char *queue;	/* Data from the Isoc data pump */
@@ -202,7 +203,7 @@
 
 struct s_usbvideo_t;
 
-typedef struct {
+struct uvd {
 	struct video_device vdev;	/* Must be the first field! */
 	struct usb_device *dev;
 	struct s_usbvideo_t *handle;	/* Points back to the usbvideo_t */
@@ -247,7 +248,7 @@
 	usbvideo_statistics_t stats;
 	struct proc_dir_entry *procfs_vEntry;	/* /proc/video/MYDRIVER/video2 */
 	char videoName[32];		/* Holds name like "video7" */
-} uvd_t;
+};
 
 /*
  * usbvideo callbacks (virtual methods). They are set when usbvideo
@@ -256,21 +257,22 @@
  */
 typedef struct {
 	void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *);
-	void (*userFree)(uvd_t *);
+	void (*userFree)(struct uvd *);
 	void (*disconnect)(struct usb_device *, void *);
-	int (*setupOnOpen)(uvd_t *);
-	void (*videoStart)(uvd_t *);
-	void (*videoStop)(uvd_t *);
-	void (*processData)(uvd_t *, usbvideo_frame_t *);
-	void (*postProcess)(uvd_t *, usbvideo_frame_t *);
-	void (*adjustPicture)(uvd_t *);
-	int (*getFPS)(uvd_t *);
-	int (*overlayHook)(uvd_t *, usbvideo_frame_t *);
-	int (*getFrame)(uvd_t *, int);
+	int (*setupOnOpen)(struct uvd *);
+	void (*videoStart)(struct uvd *);
+	void (*videoStop)(struct uvd *);
+	void (*processData)(struct uvd *, usbvideo_frame_t *);
+	void (*postProcess)(struct uvd *, usbvideo_frame_t *);
+	void (*adjustPicture)(struct uvd *);
+	int (*getFPS)(struct uvd *);
+	int (*overlayHook)(struct uvd *, usbvideo_frame_t *);
+	int (*getFrame)(struct uvd *, int);
 	int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data);
 	int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data);
-	int (*startDataPump)(uvd_t *uvd);
-	void (*stopDataPump)(uvd_t *uvd);
+	int (*startDataPump)(struct uvd *uvd);
+	void (*stopDataPump)(struct uvd *uvd);
+	int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
 } usbvideo_cb_t;
 
 struct s_usbvideo_t {
@@ -280,7 +282,7 @@
 	struct semaphore lock;		/* Mutex protecting camera structures */
 	usbvideo_cb_t cb;		/* Table of callbacks (virtual methods) */
 	struct video_device vdt;	/* Video device template */
-	uvd_t *cam;			/* Array of camera structures */
+	struct uvd *cam;			/* Array of camera structures */
 	int uses_procfs;		/* Non-zero if we create /proc entries */
 	struct proc_dir_entry *procfs_dEntry;	/* /proc/video/MYDRIVER */
 	struct module *md_module;	/* Minidriver module */
@@ -288,7 +290,7 @@
 typedef struct s_usbvideo_t usbvideo_t;
 
 /*
- * This macro retrieves callback address from the uvd_t object.
+ * This macro retrieves callback address from the struct uvd object.
  * No validity checks are done here, so be sure to check the
  * callback beforehand with VALID_CALLBACK.
  */
@@ -306,8 +308,18 @@
 
 int  RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
 int  RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
-int  RingQueue_GetLength(const RingQueue_t *rq);
 void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
+void RingQueue_Flush(RingQueue_t *rq);
+
+static inline int RingQueue_GetLength(const RingQueue_t *rq)
+{
+	return (rq->wi - rq->ri + rq->length) & (rq->length-1);
+}
+
+static inline int RingQueue_GetFreeSpace(const RingQueue_t *rq)
+{
+	return rq->length - RingQueue_GetLength(rq);
+}
 
 void usbvideo_DrawLine(
 	usbvideo_frame_t *frame,
@@ -316,7 +328,7 @@
 	unsigned char cr, unsigned char cg, unsigned char cb);
 void usbvideo_HexDump(const unsigned char *data, int len);
 void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode);
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
 
 /* Memory allocation routines */
 unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
@@ -329,13 +341,13 @@
 	const usbvideo_cb_t *cbTable,
 	struct module *md,
 	const struct usb_device_id *id_table);
-uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
-int usbvideo_RegisterVideoDevice(uvd_t *uvd);
+struct uvd *usbvideo_AllocateDevice(usbvideo_t *cams);
+int usbvideo_RegisterVideoDevice(struct uvd *uvd);
 void usbvideo_Deregister(usbvideo_t **uvt);
 
 int usbvideo_v4l_initialize(struct video_device *dev);
 
-void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame);
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame);
 
 /*
  * This code performs bounds checking - use it when working with
diff -Nru a/drivers/usb/misc/Config.help b/drivers/usb/misc/Config.help
--- a/drivers/usb/misc/Config.help	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/misc/Config.help	Tue Aug 27 12:28:07 2002
@@ -84,3 +84,31 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called uss720.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SPEEDTCH
+
+  This driver provides support for the Alcatel SpeedTouch ADSL USB 
+  modem.
+
+  The driver requires the ATM interface and ATM SAR so you need to 
+  enable ATM (under Networking options) and the ATM SAR option. You 
+  will also need PPP over ATM (under Network device support).
+
+  This driver is a slightly revised version of Johan Verrept's 1.5 
+  SpeedTouch Driver which has been altered to work on the 2.5 series 
+  kernels.
+
+  To use the device you also need a user-mode daemon that downloads
+  the firmware and (re)initializes the modem. The offical version is 
+  a closed source one from Alcatel that you can get at
+  <http://www.alcateldsl.com/support.htm>.
+
+  A piece of code has recently been sent to linux-usb-devel which 
+  allows the open source user space driver's firmware program 
+  modem_run to be used with this driver instead. You will still 
+  need the Alcatel daemon package to extract the modem firmware from 
+  it (or the windows drivers instead).
+
+  For more information, see Johan Verrept's webpages at
+  <http://linux-usb.sourceforge.net/SpeedTouch/>.
+
diff -Nru a/drivers/usb/misc/Config.in b/drivers/usb/misc/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/Config.in	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,11 @@
+#
+# USB Miscellaneous driver configuration
+#
+comment 'USB Miscellaneous drivers'
+dep_tristate '  EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
+dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
+dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB LCD driver support' CONFIG_USB_LCD $CONFIG_USB
+dep_tristate '  Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB    
diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
--- a/drivers/usb/misc/Makefile	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/misc/Makefile	Tue Aug 27 12:28:07 2002
@@ -3,10 +3,14 @@
 # (the ones that don't fit into any other categories)
 #
 
+export-objs	:= atmsar.o
+
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
 obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
+obj-$(CONFIG_USB_LCD)		+= usblcd.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
+obj-$(CONFIG_USB_SPEEDTOUCH)	+= speedtouch.o atmsar.o
 obj-$(CONFIG_USB_TIGL)		+= tiglusb.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
 
diff -Nru a/drivers/usb/misc/atmsar.c b/drivers/usb/misc/atmsar.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/atmsar.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,720 @@
+/*
+ *  General SAR library for ATM devices. 
+ * 
+ *  Written By Johan Verrept ( Johan.Verrept@advalvas.be )
+ *
+ *  Copyright (c) 2000, Johan Verrept
+ *
+ *  This code falls under the GNU General Public License, see COPYING for details
+ *
+ *  This package 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.
+ *  
+ *  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
+
+Version 0.2.4A:
+       - Version for inclusion in 2.5 series kernel
+       - Modifcations by Richard Purdie (rpurdie@rpsys.net)
+ 	- replaced "sarlib" with "atmsar"
+       - adaptations for inclusion in kernel tree
+
+Version 0.2.4:
+	- Fixed wrong buffer overrun check in atmsar_decode_rawcell()
+	  reported by Stephen Robinson <stephen.robinson@zen.co.uk>
+	- Fixed bug when input skb did not contain a multple of 52/53 bytes.
+	  (would happen when the speedtouch device resynced)
+	  also reported by Stephen Robinson <stephen.robinson@zen.co.uk>
+
+Version 0.2.3:
+	- Fixed wrong allocation size. caused memory corruption in some
+	  cases. Reported by Vladimir Dergachev <volodya@mindspring.com>
+	- Added some comments
+
+Version 0.2.2:
+	- Fixed CRCASM (patch from Linus Flannagan <linusf@netservices.eng.net>)
+	- Fixed problem when user did NOT use the ATMSAR_USE_53BYTE_CELL flag.
+          (reported by  Piers Scannell <email@lot105.com> )
+	- No more in-buffer rewriting for cloned buffers.
+	- Removed the PII specific CFLAGS in the Makefile.
+
+Version 0.2.1:
+	- removed dependancy on alloc_tx. tis presented problems when using
+		this with the  br2684 code.
+
+Version 0.2:
+        - added AAL0 reassembly
+        - added alloc_tx support                  
+        - replaced alloc_skb in decode functions to dev_alloc_skb to allow
+                 calling from interrupt
+        - fixed embarassing AAL5 bug. I was setting the pti bit in the wrong
+                byte...
+        - fixed another emabrassing bug.. picked up the wrong crc type and
+                forgot to invert the crc result...
+        - fixed AAL5 length calculations.
+        - removed automatic skb freeing from encode functions.
+                This caused problems because i did kfree_skb it, while it
+                needed to be popped. I cannot determine though whether it
+                needs to be popped or not. Figu'e it out ye'self ;-)
+        - added mru field. This is the buffersize. atmsar_decode_aal0 will
+                use when it allocates a receive buffer. A stop gap for real
+		buffer management.
+
+Version 0.1:
+	- library created.
+	- only contains AAL5, AAL0 can be easily added. ( actually, only
+		AAL0 reassembly is missing)
+*/
+
+#include "atmsar.h"
+#include <linux/module.h>
+#include <linux/init.h>
+
+#define DRIVER_AUTHOR "Johan Verrept, Johan.Verrept@advalvas.be"
+#define DRIVER_DESC "General SAR library for ATM devices"
+#define DRIVER_VERSION "0.2.4A"
+
+/***********************
+ **
+ **  things to remember
+ **
+ ***********************/
+
+/*
+  1. the atmsar_vcc_data list pointer MUST be initialized to NULL
+  2. atmsar_encode_rawcell will drop incomplete cells.
+  3. ownership of the skb goes to the library !
+*/
+
+#define ATM_HDR_VPVC_MASK  (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
+
+/***********************
+ **
+ **  LOCAL STRUCTURES
+ **
+ ***********************/
+
+/***********************
+ **
+ **  LOCAL MACROS
+ **
+ ***********************/
+/*
+#define DEBUG 1
+*/
+#ifdef DEBUG
+#define PDEBUG(arg...)  printk(KERN_DEBUG "atmsar: " arg)
+#else
+#define PDEBUG(arg...)
+#endif
+
+#define ADD_HEADER(dest, header) \
+  *dest++ = (unsigned char) (header >> 24); \
+  *dest++ = (unsigned char) (header >> 16); \
+  *dest++ = (unsigned char) (header >> 8); \
+  *dest++ = (unsigned char) (header & 0xff);
+
+/*
+ * CRC Routines from  net/wan/sbni.c)
+ * table generated by Rocksoft^tm Model CRC Algorithm Table Generation Program V1.0
+ */
+#define CRC32_REMAINDER CBF43926
+#define CRC32_INITIAL 0xffffffff
+#define CRC32(c,crc) (crc32tab[((size_t)(crc>>24) ^ (c)) & 0xff] ^ (((crc) << 8)))
+unsigned long crc32tab[256] = {
+	0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
+	0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
+	0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
+	0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
+	0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
+	0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
+	0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
+	0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
+	0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
+	0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
+	0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
+	0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
+	0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
+	0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
+	0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
+	0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
+	0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
+	0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
+	0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
+	0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
+	0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
+	0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
+	0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
+	0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
+	0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
+	0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
+	0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
+	0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
+	0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
+	0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
+	0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
+	0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
+	0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
+	0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
+	0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
+	0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
+	0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
+	0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
+	0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
+	0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
+	0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
+	0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
+	0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
+	0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
+	0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
+	0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
+	0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
+	0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
+	0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
+	0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
+	0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
+	0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
+	0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
+	0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
+	0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
+	0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
+	0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
+	0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
+	0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
+	0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
+	0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
+	0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
+	0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
+	0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
+};
+
+#ifdef CRCASM
+
+unsigned long calc_crc (char *mem, int len, unsigned initial)
+{
+	unsigned crc, dummy_len;
+      __asm__ ("xorl %%eax,%%eax\n\t" "1:\n\t" "movl %%edx,%%eax\n\t" "shrl $16,%%eax\n\t" "lodsb\n\t" "xorb %%ah,%%al\n\t" "andl $255,%%eax\n\t" "shll $8,%%edx\n\t" "xorl (%%edi,%%eax,4),%%edx\n\t" "loop 1b":"=d" (crc),
+		 "=c"
+		 (dummy_len)
+      :	 "S" (mem), "D" (&crc32tab[0]), "1" (len), "0" (initial)
+      :	 "eax");
+	return crc;
+}
+
+#else
+
+unsigned long calc_crc (char *mem, int len, unsigned initial)
+{
+	unsigned crc;
+	crc = initial;
+
+	for (; len; mem++, len--) {
+		crc = CRC32 (*mem, crc);
+	}
+	return (crc);
+}
+#endif
+
+#define crc32( crc, mem, len) calc_crc(mem, len, crc);
+
+/* initialiation routines. not used at the moment 
+ * I will avoid these as long as possible !!
+ */
+
+int open_atmsar (void)
+{
+	return 0;
+}
+
+int remove_atmsar (void)
+{
+	return 0;
+}
+
+/* ATOMIC version of alloc_tx */
+struct sk_buff *atmsar_alloc_skb_wrapper (struct atm_vcc *vcc, unsigned int size)
+{
+	struct sk_buff *skb;
+
+	if (atomic_read (&vcc->tx_inuse) && !atm_may_send (vcc, size)) {
+		PDEBUG ("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n",
+			atomic_read (&vcc->tx_inuse), size, vcc->sk->sndbuf);
+		return NULL;
+	}
+	skb = alloc_skb (size, GFP_ATOMIC);
+	if (!skb)
+		return NULL;
+	atomic_add (skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+	return skb;
+}
+
+struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size)
+{
+	struct sk_buff *tmp = NULL;
+	int bufsize = 0;
+
+	switch (vcc->type) {
+	case ATMSAR_TYPE_AAL0:
+		/* reserving adequate headroom */
+		bufsize =
+		    size + (((size / 48) + 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+		break;
+	case ATMSAR_TYPE_AAL1:
+		/* reserving adequate headroom */
+		bufsize =
+		    size + (((size / 47) + 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+		break;
+	case ATMSAR_TYPE_AAL2:
+	case ATMSAR_TYPE_AAL34:
+		/* not supported */
+		break;
+	case ATMSAR_TYPE_AAL5:
+		/* reserving adequate tailroom */
+		bufsize = size + (((size + 8 + 47) / 48) * 48);
+		break;
+	}
+
+	PDEBUG ("Requested size %d, Allocating size %d\n", size, bufsize);
+	tmp = vcc->alloc_tx (vcc->vcc, bufsize);
+	skb_put (tmp, bufsize);
+
+	return tmp;
+}
+
+struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
+				     ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
+{
+	struct atmsar_vcc_data *new;
+
+	new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
+
+	if (!new)
+		return NULL;
+
+	if (!vcc)
+		return NULL;
+
+	memset (new, 0, sizeof (struct atmsar_vcc_data));
+	new->vcc = vcc;
+/*
+ * This gives problems with the ATM layer alloc_tx().
+ * It is not usable from interrupt context and for
+ * some reason this is used in interurpt context 
+ * with br2684.c
+ *
+  if (vcc->alloc_tx)
+    new->alloc_tx  = vcc->alloc_tx;
+  else
+*/
+	new->alloc_tx = atmsar_alloc_skb_wrapper;
+
+	new->stats = vcc->stats;
+	new->type = type;
+	new->next = NULL;
+	new->gfc = gfc;
+	new->vp = vpi;
+	new->vc = vci;
+	new->pti = pti;
+
+	switch (type) {
+	case ATMSAR_TYPE_AAL0:
+		new->mtu = ATMSAR_DEF_MTU_AAL0;
+		break;
+	case ATMSAR_TYPE_AAL1:
+		new->mtu = ATMSAR_DEF_MTU_AAL1;
+		break;
+	case ATMSAR_TYPE_AAL2:
+		new->mtu = ATMSAR_DEF_MTU_AAL2;
+		break;
+	case ATMSAR_TYPE_AAL34:
+		/* not supported */
+		new->mtu = ATMSAR_DEF_MTU_AAL34;
+		break;
+	case ATMSAR_TYPE_AAL5:
+		new->mtu = ATMSAR_DEF_MTU_AAL5;
+		break;
+	}
+
+	new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
+	    | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
+	    | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
+	    | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
+	new->flags = flags;
+	new->next = NULL;
+	new->reasBuffer = NULL;
+
+	new->next = *list;
+	*list = new;
+
+	PDEBUG ("Allocated new SARLib vcc 0x%p with vp %d vc %d\n", new, vpi, vci);
+
+	return new;
+}
+
+void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
+{
+	struct atmsar_vcc_data *work;
+
+	if (*list == vcc) {
+		*list = (*list)->next;
+	} else {
+		for (work = *list; work && work->next && (work->next != vcc); work = work->next);
+
+		/* return if not found */
+		if (work->next != vcc)
+			return;
+
+		work->next = work->next->next;
+	}
+
+	if (vcc->reasBuffer) {
+		dev_kfree_skb (vcc->reasBuffer);
+	}
+
+	PDEBUG ("Allocated SARLib vcc 0x%p with vp %d vc %d\n", vcc, vcc->vp, vcc->vc);
+
+	kfree (vcc);
+}
+
+/***********************
+ **
+ **    ENCODE FUNCTIONS
+ **
+ ***********************/
+
+struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+	int number_of_cells = (skb->len) / 48;
+	int total_length = number_of_cells * (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52);
+	unsigned char *source;
+	unsigned char *target;
+	struct sk_buff *out = NULL;
+	int i;
+
+	PDEBUG ("atmsar_encode_rawcell (0x%p, 0x%p) called\n", ctx, skb);
+
+	if (skb_cloned (skb)
+	    || (skb_headroom (skb) <
+		(number_of_cells * (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4)))) {
+		PDEBUG
+		    ("atmsar_encode_rawcell allocating new skb. ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p\n",
+		     ctx->alloc_tx, ctx->vcc);
+		/* get new skb */
+		out = ctx->alloc_tx (ctx->vcc, total_length);
+		if (!out)
+			return NULL;
+
+		skb_put (out, total_length);
+		source = skb->data;
+		target = out->data;
+	} else {
+		PDEBUG ("atmsar_encode_rawcell: sufficient headroom\n");
+		source = skb->data;
+		skb_push (skb, number_of_cells * ((ctx->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+		target = skb->data;
+		out = skb;
+	}
+
+	PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
+
+	if (ctx->flags & ATMSAR_USE_53BYTE_CELL) {
+		for (i = 0; i < number_of_cells; i++) {
+			ADD_HEADER (target, ctx->atmHeader);
+			*target++ = (char) 0xEC;
+			memcpy (target, source, 48);
+			target += 48;
+			source += 48;
+			PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
+		}
+	} else {
+		for (i = 0; i < number_of_cells; i++) {
+			ADD_HEADER (target, ctx->atmHeader);
+			memcpy (target, source, 48);
+			target += 48;
+			source += 48;
+			PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
+		};
+	}
+
+	if (ctx->flags & ATMSAR_SET_PTI) {
+		/* setting pti bit in last cell */
+		*(target - (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 50 : 49)) |= 0x2;
+	}
+
+	/* update stats */
+	if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
+		atomic_add (number_of_cells, &(ctx->stats->tx));
+
+	PDEBUG ("atmsar_encode_rawcell return 0x%p (length %d)\n", out, out->len);
+	return out;
+}
+
+struct sk_buff *atmsar_encode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+	int length, pdu_length;
+	unsigned char *trailer;
+	unsigned char *pad;
+	uint crc = 0xffffffff;
+
+	PDEBUG ("atmsar_encode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
+
+	/* determine aal5 length */
+	pdu_length = skb->len;
+	length = ((pdu_length + 8 + 47) / 48) * 48;
+
+	if (skb_tailroom (skb) < (length - pdu_length)) {
+		struct sk_buff *out;
+		PDEBUG
+		    ("atmsar_encode_aal5 allocating new skb. ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p\n",
+		     ctx->alloc_tx, ctx->vcc);
+		/* get new skb */
+		out = ctx->alloc_tx (ctx->vcc, length);
+		if (!out)
+			return NULL;
+
+		PDEBUG ("out->data = 0x%p\n", out->data);
+		PDEBUG ("atmsar_encode_aal5 pdu length %d, allocated length %d\n", skb->len,
+			length);
+		memcpy (out->data, skb->data, skb->len);
+		skb_put (out, skb->len);
+
+		skb = out;
+	}
+
+	PDEBUG ("skb->data = 0x%p\n", skb->data);
+	/* note end of pdu and add length */
+	pad = skb_put (skb, length - pdu_length);
+	trailer = skb->tail - 8;
+
+	PDEBUG ("trailer = 0x%p\n", trailer);
+
+	/* zero padding space */
+	memset (pad, 0, length - pdu_length - 8);
+
+	/* add trailer */
+	*trailer++ = (unsigned char) 0;	/* UU  = 0 */
+	*trailer++ = (unsigned char) 0;	/* CPI = 0 */
+	*trailer++ = (unsigned char) (pdu_length >> 8);
+	*trailer++ = (unsigned char) (pdu_length & 0xff);
+	crc = ~crc32 (crc, skb->data, length - 4);
+	*trailer++ = (unsigned char) (crc >> 24);
+	*trailer++ = (unsigned char) (crc >> 16);
+	*trailer++ = (unsigned char) (crc >> 8);
+	*trailer++ = (unsigned char) (crc & 0xff);
+
+	/* update stats */
+	if (ctx->stats)
+		atomic_inc (&ctx->stats->tx);
+
+	PDEBUG ("atmsar_encode_aal5 return 0x%p (length %d)\n", skb, skb->len);
+	return skb;
+}
+
+/***********************
+ **
+ **  DECODE FUNCTIONS
+ **
+ ***********************/
+
+struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
+				       struct atmsar_vcc_data **ctx)
+{
+	while (skb->len) {
+		unsigned char *cell = skb->data;
+		unsigned char *cell_payload;
+		struct atmsar_vcc_data *vcc = list;
+		unsigned long atmHeader =
+		    ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
+		    ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
+
+		PDEBUG ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called\n", list, skb, ctx);
+		PDEBUG ("atmsar_decode_rawcell skb->data %p, skb->tail %p\n", skb->data, skb->tail);
+
+		if (!list || !skb || !ctx)
+			return NULL;
+		if (!skb->data || !skb->tail)
+			return NULL;
+
+		/* here should the header CRC check be... */
+
+		/* look up correct vcc */
+		for (;
+		     vcc
+		     && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
+		     vcc = vcc->next);
+
+		PDEBUG ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d\n", vcc,
+			(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
+			(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
+
+		if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
+			cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
+
+			switch (vcc->type) {
+			case ATMSAR_TYPE_AAL0:
+				/* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */
+				{
+					struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
+
+					if (tmp) {
+						memcpy (tmp->tail, cell_payload, 48);
+						skb_put (tmp, 48);
+
+						if (vcc->stats)
+							atomic_inc (&vcc->stats->rx);
+
+						skb_pull (skb,
+							  (vcc->
+							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+							   52));
+						PDEBUG
+						    ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d\n",
+						     tmp, tmp->len);
+						return tmp;
+					};
+				}
+				break;
+			case ATMSAR_TYPE_AAL1:
+			case ATMSAR_TYPE_AAL2:
+			case ATMSAR_TYPE_AAL34:
+				/* not supported */
+				break;
+			case ATMSAR_TYPE_AAL5:
+				if (!vcc->reasBuffer)
+					vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
+
+				/* if alloc fails, we just drop the cell. it is possible that we can still
+				 * receive cells on other vcc's 
+				 */
+				if (vcc->reasBuffer) {
+					/* if (buffer overrun) discard received cells until now */
+					if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
+						skb_trim (vcc->reasBuffer, 0);
+
+					/* copy data */
+					memcpy (vcc->reasBuffer->tail, cell_payload, 48);
+					skb_put (vcc->reasBuffer, 48);
+
+					/* check for end of buffer */
+					if (cell[3] & 0x2) {
+						struct sk_buff *tmp;
+
+						/* the aal5 buffer ends here, cut the buffer. */
+						/* buffer will always have at least one whole cell, so */
+						/* don't need to check return from skb_pull */
+						skb_pull (skb,
+							  (vcc->
+							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+							   52));
+						*ctx = vcc;
+						tmp = vcc->reasBuffer;
+						vcc->reasBuffer = NULL;
+
+						PDEBUG
+						    ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d\n",
+						     tmp, tmp->len);
+						return tmp;
+					}
+				}
+				break;
+			};
+			/* flush the cell */
+			/* buffer will always contain at least one whole cell, so don't */
+			/* need to check return value from skb_pull */
+			skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
+		} else {
+			/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+			if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
+			    NULL) {
+				skb_trim (skb, 0);
+			}
+		}
+	}
+
+	return NULL;
+};
+
+struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+	uint crc = 0xffffffff;
+	uint length, pdu_crc, pdu_length;
+
+	PDEBUG ("atmsar_decode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
+
+	if (skb->len && (skb->len % 48))
+		return NULL;
+
+	length = (skb->tail[-6] << 8) + skb->tail[-5];
+	pdu_crc =
+	    (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
+	pdu_length = ((length + 47 + 8) / 48) * 48;
+
+	PDEBUG ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d\n",
+		skb->len, length, pdu_crc, pdu_length);
+
+	/* is skb long enough ? */
+	if (skb->len < pdu_length) {
+		if (ctx->stats)
+			atomic_inc (&ctx->stats->rx_err);
+		return NULL;
+	}
+
+	/* is skb too long ? */
+	if (skb->len > pdu_length) {
+		PDEBUG ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d\n",
+			skb->len, pdu_length);
+		/* buffer is too long. we can try to recover
+		 * if we discard the first part of the skb.
+		 * the crc will decide whether this was ok
+		 */
+		skb_pull (skb, skb->len - pdu_length);
+	}
+
+	crc = ~crc32 (crc, skb->data, pdu_length - 4);
+
+	/* check crc */
+	if (pdu_crc != crc) {
+		PDEBUG ("atmsar_decode_aal5: crc check failed!\n");
+		if (ctx->stats)
+			atomic_inc (&ctx->stats->rx_err);
+		return NULL;
+	}
+
+	/* pdu is ok */
+	skb_trim (skb, length);
+
+	/* update stats */
+	if (ctx->stats)
+		atomic_inc (&ctx->stats->rx);
+
+	PDEBUG ("atmsar_decode_aal5 returns pdu 0x%p with length %d\n", skb, skb->len);
+	return skb;
+};
+
+
+static int start (void)
+{
+	return 0;
+}
+
+static void cleanup (void)
+{
+}
+
+module_init (start);
+module_exit (cleanup);
+
+EXPORT_SYMBOL (atmsar_open);
+EXPORT_SYMBOL (atmsar_close);
+EXPORT_SYMBOL (atmsar_encode_rawcell);
+EXPORT_SYMBOL (atmsar_encode_aal5);
+EXPORT_SYMBOL (atmsar_decode_rawcell);
+EXPORT_SYMBOL (atmsar_decode_aal5);
+EXPORT_SYMBOL (atmsar_alloc_tx);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
diff -Nru a/drivers/usb/misc/atmsar.h b/drivers/usb/misc/atmsar.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/atmsar.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,81 @@
+/*
+ *
+ *  General SAR library for ATM devices.
+ *
+ *  Copyright (c) 2000, Johan Verrept
+ *
+ *  This code falls under the GNU General Public License, see COPYING for details.
+ *
+ */
+
+#ifndef _ATMSAR_H_
+#define _ATMSAR_H_
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/atmdev.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/atm.h>
+
+#define ATMSAR_USE_53BYTE_CELL  0x1L
+#define ATMSAR_SET_PTI          0x2L
+
+
+/* types */
+#define ATMSAR_TYPE_AAL0        ATM_AAL0
+#define ATMSAR_TYPE_AAL1        ATM_AAL1
+#define ATMSAR_TYPE_AAL2        ATM_AAL2
+#define ATMSAR_TYPE_AAL34       ATM_AAL34
+#define ATMSAR_TYPE_AAL5        ATM_AAL5
+
+
+/* default MTU's */
+#define ATMSAR_DEF_MTU_AAL0         48
+#define ATMSAR_DEF_MTU_AAL1         47
+#define ATMSAR_DEF_MTU_AAL2          0	/* not supported */
+#define ATMSAR_DEF_MTU_AAL34         0	/* not supported */
+#define ATMSAR_DEF_MTU_AAL5      65535	/* max mtu ..    */
+
+struct atmsar_vcc_data {
+	struct atmsar_vcc_data *next;
+
+	/* general atmsar flags, per connection */
+	int flags;
+	int type;
+
+	/* connection specific non-atmsar data */
+	struct sk_buff *(*alloc_tx) (struct atm_vcc * vcc, unsigned int size);
+	struct atm_vcc *vcc;
+	struct k_atm_aal_stats *stats;
+	unsigned short mtu;	/* max is actually  65k for AAL5... */
+
+	/* cell data */
+	unsigned int vp;
+	unsigned int vc;
+	unsigned char gfc;
+	unsigned char pti;
+	unsigned int headerFlags;
+	unsigned long atmHeader;
+
+	/* raw cell reassembly */
+	struct sk_buff *reasBuffer;
+};
+
+
+extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc,
+					    uint type, ushort vpi, ushort vci, unchar pti,
+					    unchar gfc, uint flags);
+extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc);
+
+extern struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+extern struct sk_buff *atmsar_encode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+
+struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
+				       struct atmsar_vcc_data **ctx);
+struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+
+struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size);
+
+#endif				/* _ATMSAR_H_ */
diff -Nru a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtouch.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/speedtouch.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,1068 @@
+/*
+ *  Driver Module for Alcatel SpeedTouch USB xDSL modem
+ *  Copyright 2001, Alcatel
+ *  Written by Johan Verrept (Johan.Verrept@advalvas.be)
+ *
+
+1.5A:   - Version for inclusion in 2.5 series kernel
+        - Modifcations by Richard Purdie (rpurdie@rpsys.net)
+        - made compatible with kernel 2.5.6 onwards by changing
+	  udsl_usb_send_data_context->urb changed to a pointer 
+	  and adding code to alloc and free it
+        - remove_wait_queue() added to udsl_atm_processqueue_thread() 
+
+1.5:	- fixed memory leak when atmsar_decode_aal5 returned NULL.
+	 (reported by stephen.robinson@zen.co.uk)
+
+1.4:	- changed the spin_lock() under interrupt to spin_lock_irqsave()
+	- unlink all active send urbs of a vcc that is being closed.
+
+1.3.1:	- added the version number
+
+1.3:	- Added multiple send urb support
+	- fixed memory leak and vcc->tx_inuse starvation bug
+	  when not enough memory left in vcc.
+
+1.2:	- Fixed race condition in udsl_usb_send_data()
+1.1:	- Turned off packet debugging
+ 
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include "atmsar.h"
+
+const char *udsl_version = "1.5A";
+
+/*
+#define DEBUG 1
+#define DEBUG_PACKET 1
+*/
+
+#ifdef DEBUG
+#define PDEBUG(arg...)  printk(KERN_DEBUG "SpeedTouch USB: " arg)
+#else
+#define PDEBUG(arg...)
+#endif
+
+
+#ifdef DEBUG_PACKET
+#define PACKETDEBUG(arg...) udsl_print_packet ( arg )
+#else
+#define PACKETDEBUG(arg...)
+#endif
+
+#define DRIVER_AUTHOR	"Johan Verrept, Johan.Verrept@advalvas.be"
+#define DRIVER_DESC	"Driver for the Alcatel Speed Touch USB ADSL modem"
+#define DRIVER_VERSION	"1.5A"
+
+#define SPEEDTOUCH_VENDORID		0x06b9
+#define SPEEDTOUCH_PRODUCTID		0x4061
+
+#define MAX_UDSL			1
+#define UDSL_OBUF_SIZE			32768
+#define UDSL_MINOR			48
+#define UDSL_NUMBER_RCV_URBS		1
+#define UDSL_NUMBER_SND_URBS		1
+#define UDSL_RECEIVE_BUFFER_SIZE	64*53
+/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
+ * PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
+#define UDSL_MAX_AAL5_MRU		2048
+#define UDSL_SEND_CONTEXTS		8
+
+#define UDSL_IOCTL_START		1
+#define UDSL_IOCTL_STOP			2
+
+/* endpoint declarations */
+
+#define UDSL_ENDPOINT_DATA_OUT		0x07
+#define UDSL_ENDPOINT_DATA_IN		0x87
+
+/* usb_device_id struct */
+
+static struct usb_device_id udsl_usb_ids[] = {
+	{USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
+	{}			/* list terminator */
+};
+
+/* not exporting this prevents the depmod from generating the map that causes the modules to be isnserted as driver.
+ * we do not want this, we want the script run.
+MODULE_DEVICE_TABLE ( usb, udsl_usb_ids);
+*/
+/* context declarations */
+
+struct udsl_data_ctx {
+	struct sk_buff *skb;
+	struct urb *urb;
+	struct udsl_instance_data *instance;
+};
+
+struct udsl_usb_send_data_context {
+	struct urb *urb;
+	struct sk_buff *skb;
+	struct atm_vcc *vcc;
+	struct udsl_instance_data *instance;
+};
+
+/*
+ * UDSL main driver data
+ */
+
+struct udsl_instance_data {
+	int minor;
+
+	/* usb device part */
+	struct usb_device *usb_dev;
+	struct udsl_data_ctx *rcvbufs;
+	struct sk_buff_head sndqueue;
+	spinlock_t sndqlock;
+	struct udsl_usb_send_data_context send_ctx[UDSL_NUMBER_SND_URBS];
+	int data_started;
+
+	/* atm device part */
+	struct atm_dev *atm_dev;
+	struct sk_buff_head recvqueue;
+	spinlock_t recvqlock;
+
+	struct atmsar_vcc_data *atmsar_vcc_list;
+};
+
+struct udsl_instance_data *minor_data[MAX_UDSL];
+
+static const char udsl_driver_name[] = "Alcatel SpeedTouch USB";
+
+/* data thread */
+static int datapid = 0;
+DECLARE_WAIT_QUEUE_HEAD (udsl_wqh);
+
+#ifdef DEBUG_PACKET
+int udsl_print_packet (const unsigned char *data, int len);
+#endif
+
+/*
+ * atm driver prototypes and stuctures
+ */
+
+static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
+static void udsl_atm_close (struct atm_vcc *vcc);
+static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
+static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
+int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page);
+void udsl_atm_processqueue (struct udsl_instance_data *instance);
+
+static struct atmdev_ops udsl_atm_devops = {
+	open:udsl_atm_open,
+	close:udsl_atm_close,
+	ioctl:udsl_atm_ioctl,
+	send:udsl_atm_send,
+	proc_read:udsl_atm_proc_read,
+};
+
+struct udsl_atm_dev_data {
+	struct atmsar_vcc_data *atmsar_vcc;
+};
+
+/*
+ * usb driver prototypes and structures
+ */
+static void *udsl_usb_probe (struct usb_device *dev, unsigned int ifnum,
+			     const struct usb_device_id *id);
+static void udsl_usb_disconnect (struct usb_device *dev, void *ptr);
+int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_vcc *vcc,
+			struct sk_buff *skb);
+static int udsl_usb_ioctl (struct usb_device *hub, unsigned int code, void *user_data);
+static int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc);
+
+static struct usb_driver udsl_usb_driver = {
+	name:udsl_driver_name,
+	probe:udsl_usb_probe,
+	disconnect:udsl_usb_disconnect,
+	ioctl:udsl_usb_ioctl,
+	id_table:udsl_usb_ids,
+};
+
+/************
+**   ATM   **
+************/
+
+/***************************************************************************
+*
+* init functions
+*
+****************************************************************************/
+
+struct atm_dev *udsl_atm_startdevice (struct udsl_instance_data *instance,
+				      struct atmdev_ops *devops)
+{
+	MOD_INC_USE_COUNT;
+	instance->atm_dev = atm_dev_register (udsl_driver_name, devops, -1, 0);
+	instance->atm_dev->dev_data = instance;
+	instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
+	instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
+	instance->atm_dev->signal = ATM_PHY_SIG_LOST;
+
+	skb_queue_head_init (&instance->recvqueue);
+
+	/* tmp init atm device, set to 128kbit */
+	instance->atm_dev->link_rate = 128 * 1000 / 424;
+
+	return instance->atm_dev;
+}
+
+void udsl_atm_stopdevice (struct udsl_instance_data *instance)
+{
+	struct atm_vcc *walk;
+	struct sk_buff *skb;
+	struct atm_dev *atm_dev;
+	unsigned long iflags;
+	if (!instance->atm_dev)
+		return;
+
+	atm_dev = instance->atm_dev;
+
+	/* clean queue */
+	spin_lock_irqsave (&instance->recvqlock, iflags);
+	while (!skb_queue_empty (&instance->recvqueue)) {
+		skb = skb_dequeue (&instance->recvqueue);
+		dev_kfree_skb (skb);
+	};
+	spin_unlock_irqrestore (&instance->recvqlock, iflags);
+
+	atm_dev->signal = ATM_PHY_SIG_LOST;
+	walk = atm_dev->vccs;
+	shutdown_atm_dev (atm_dev);
+
+	for (; walk; walk = walk->next)
+		wake_up (&walk->sleep);
+
+	instance->atm_dev = NULL;
+	MOD_DEC_USE_COUNT;
+}
+
+void udsl_atm_set_mac (struct udsl_instance_data *instance, const char mac[6])
+{
+	if (!instance->atm_dev)
+		return;
+
+	memcpy (instance->atm_dev->esi, mac, 6);
+}
+
+/***************************************************************************
+*
+* ATM helper functions
+*
+****************************************************************************/
+struct sk_buff *udsl_atm_alloc_tx (struct atm_vcc *vcc, unsigned int size)
+{
+	struct atmsar_vcc_data *atmsar_vcc =
+	    ((struct udsl_atm_dev_data *) vcc->dev_data)->atmsar_vcc;
+	if (atmsar_vcc)
+		return atmsar_alloc_tx (atmsar_vcc, size);
+
+	printk (KERN_INFO
+		"SpeedTouch USB: udsl_atm_alloc_tx could not find correct alloc_tx function !\n");
+	return NULL;
+}
+
+int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page)
+{
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) atm_dev->dev_data;
+	int left = *pos;
+
+	if (!left--)
+		return sprintf (page, "Speed Touch USB:%d (%02x:%02x:%02x:%02x:%02x:%02x)\n",
+				instance->minor, atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
+				atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
+
+	if (!left--)
+		return sprintf (page, "AAL0: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+				atomic_read (&atm_dev->stats.aal0.tx),
+				atomic_read (&atm_dev->stats.aal0.tx_err),
+				atomic_read (&atm_dev->stats.aal0.rx),
+				atomic_read (&atm_dev->stats.aal0.rx_err),
+				atomic_read (&atm_dev->stats.aal0.rx_drop));
+
+	if (!left--)
+		return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+				atomic_read (&atm_dev->stats.aal5.tx),
+				atomic_read (&atm_dev->stats.aal5.tx_err),
+				atomic_read (&atm_dev->stats.aal5.rx),
+				atomic_read (&atm_dev->stats.aal5.rx_err),
+				atomic_read (&atm_dev->stats.aal5.rx_drop));
+
+	return 0;
+}
+
+/***************************************************************************
+*
+* ATM DATA functions
+*
+****************************************************************************/
+int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	struct udsl_atm_dev_data *dev_data = (struct udsl_atm_dev_data *) vcc->dev_data;
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
+	struct sk_buff *new = NULL;
+	int err;
+
+	PDEBUG ("udsl_atm_send called\n");
+
+	if (!dev_data)
+		return -EINVAL;
+
+	switch (vcc->qos.aal) {
+	case ATM_AAL5:
+		new = atmsar_encode_aal5 (dev_data->atmsar_vcc, skb);
+		if (!new)
+			goto nomem;
+		if (new != skb) {
+			vcc->pop (vcc, skb);
+			skb = new;
+		}
+		new = atmsar_encode_rawcell (dev_data->atmsar_vcc, skb);
+		if (!new)
+			goto nomem;
+		if (new != skb) {
+			vcc->pop (vcc, skb);
+			skb = new;
+		}
+		err = udsl_usb_send_data (instance, vcc, skb);
+		PDEBUG ("udsl_atm_send successfull (%d)\n", err);
+		return err;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	PDEBUG ("udsl_atm_send unsuccessfull\n");
+	return 0;
+      nomem:
+	vcc->pop (vcc, skb);
+	return -ENOMEM;
+};
+
+
+void udsl_atm_processqueue (struct udsl_instance_data *instance)
+{
+	struct atmsar_vcc_data *atmsar_vcc = NULL;
+	struct sk_buff *new = NULL, *skb = NULL, *tmp = NULL;
+	unsigned long iflags;
+
+	/* quick check */
+	spin_lock_irqsave (&instance->recvqlock, iflags);
+	if (skb_queue_empty (&instance->recvqueue)) {
+		spin_unlock_irqrestore (&instance->recvqlock, iflags);
+		return;
+	}
+	PDEBUG ("udsl_atm_processqueue entered\n");
+
+	while (!skb_queue_empty (&instance->recvqueue)) {
+		skb = skb_dequeue (&instance->recvqueue);
+
+		spin_unlock_irqrestore (&instance->recvqlock, iflags);
+
+		PDEBUG ("skb = %p, skb->len = %d\n", skb, skb->len);
+		PACKETDEBUG (skb->data, skb->len);
+
+		while ((new =
+			atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
+					       &atmsar_vcc)) != NULL) {
+			PDEBUG ("(after cell processing)skb->len = %d\n", new->len);
+			switch (atmsar_vcc->type) {
+			case ATMSAR_TYPE_AAL5:
+				tmp = new;
+				new = atmsar_decode_aal5 (atmsar_vcc, new);
+
+				/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
+				if (new) {
+					PDEBUG ("(after aal5 decap) skb->len = %d\n", new->len);
+					if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
+						PACKETDEBUG (new->data, new->len);
+						atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
+					} else {
+						PDEBUG
+						    ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
+						     atomic_read (&atmsar_vcc->vcc->rx_inuse),
+						     atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
+						dev_kfree_skb (new);
+					}
+				} else {
+					PDEBUG ("atmsar_decode_aal5 returned NULL!\n");
+					dev_kfree_skb (tmp);
+				}
+				break;
+			default:
+				/* not supported. we delete the skb. */
+				printk (KERN_INFO
+					"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
+				dev_kfree_skb (new);
+				break;
+			}
+		};
+		dev_kfree_skb (skb);
+		spin_lock_irqsave (&instance->recvqlock, iflags);
+	};
+
+	spin_unlock_irqrestore (&instance->recvqlock, iflags);
+	PDEBUG ("udsl_atm_processqueue successfull\n");
+}
+
+int udsl_atm_processqueue_thread (void *data)
+{
+	int i = 0;
+	DECLARE_WAITQUEUE (wait, current);
+
+	lock_kernel ();
+	daemonize ();
+
+	/* Setup a nice name */
+	strcpy (current->comm, "kSpeedSARd");
+
+	add_wait_queue (&udsl_wqh, &wait);
+
+	for (;;) {
+		interruptible_sleep_on (&udsl_wqh);
+		if (signal_pending (current))
+			break;
+		PDEBUG ("SpeedSARd awoke\n");
+		for (i = 0; i < MAX_UDSL; i++)
+			if (minor_data[i])
+				udsl_atm_processqueue (minor_data[i]);
+	};
+
+	remove_wait_queue (&udsl_wqh, &wait);
+	datapid = 0;
+	PDEBUG ("SpeedSARd is exiting\n");
+	return 0;
+}
+
+
+void udsl_atm_sar_start (void)
+{
+	datapid = kernel_thread (udsl_atm_processqueue_thread, (void *) NULL,
+				 CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+}
+
+void udsl_atm_sar_stop (void)
+{
+	int ret;
+	/* Kill the thread */
+	ret = kill_proc (datapid, SIGTERM, 1);
+	if (!ret) {
+		/* Wait 10 seconds */
+		int count = 10 * 100;
+
+		while (datapid && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout (1);
+		}
+
+		if (!count)
+			err ("giving up on killing SpeedSAR thread.");
+	}
+}
+
+/***************************************************************************
+*
+* SAR driver entries
+*
+****************************************************************************/
+int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
+{
+	struct udsl_atm_dev_data *dev_data;
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
+
+	PDEBUG ("udsl_atm_open called\n");
+
+	/* at the moment only AAL5 support */
+	if (vcc->qos.aal != ATM_AAL5)
+		return -EINVAL;
+
+	MOD_INC_USE_COUNT;
+	dev_data =
+	    (struct udsl_atm_dev_data *) kmalloc (sizeof (struct udsl_atm_dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	dev_data->atmsar_vcc =
+	    atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0,
+			 ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
+	if (!dev_data->atmsar_vcc) {
+		kfree (dev_data);
+		return -ENOMEM;	/* this is the only reason atmsar_open can fail... */
+	}
+
+	vcc->vpi = vpi;
+	vcc->vci = vci;
+	set_bit (ATM_VF_ADDR, &vcc->flags);
+	set_bit (ATM_VF_PARTIAL, &vcc->flags);
+	set_bit (ATM_VF_READY, &vcc->flags);
+	vcc->dev_data = dev_data;
+	vcc->alloc_tx = udsl_atm_alloc_tx;
+
+	dev_data->atmsar_vcc->mtu = UDSL_MAX_AAL5_MRU;
+
+	PDEBUG ("udsl_atm_open successfull\n");
+	return 0;
+}
+
+void udsl_atm_close (struct atm_vcc *vcc)
+{
+	struct udsl_atm_dev_data *dev_data = (struct udsl_atm_dev_data *) vcc->dev_data;
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
+
+	PDEBUG ("udsl_atm_close called\n");
+
+	/* freeing resources */
+	/* cancel all sends on this vcc */
+	udsl_usb_cancelsends (instance, vcc);
+
+	atmsar_close (&(instance->atmsar_vcc_list), dev_data->atmsar_vcc);
+	kfree (dev_data);
+	vcc->dev_data = NULL;
+	clear_bit (ATM_VF_PARTIAL, &vcc->flags);
+
+	/* freeing address */
+	vcc->vpi = ATM_VPI_UNSPEC;
+	vcc->vci = ATM_VCI_UNSPEC;
+	clear_bit (ATM_VF_ADDR, &vcc->flags);
+
+	MOD_DEC_USE_COUNT;
+
+	PDEBUG ("udsl_atm_close successfull\n");
+	return;
+};
+
+int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
+{
+	switch (cmd) {
+	case ATM_QUERYLOOP:
+		return put_user (ATM_LM_NONE, (int *) arg) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+};
+
+
+/************
+**   USB   **
+************/
+
+/***************************************************************************
+*
+* usb data functions
+*
+****************************************************************************/
+
+struct udsl_cb {
+	struct atm_vcc *vcc;
+};
+
+static void udsl_usb_send_data_complete (struct urb *urb)
+{
+	struct udsl_usb_send_data_context *ctx = (struct udsl_usb_send_data_context *) urb->context;
+	struct udsl_instance_data *instance = ctx->instance;
+	int err;
+	unsigned long flags;
+
+	PDEBUG ("udsl_usb_send_data_completion (vcc = %p, skb = %p, status %d)\n", ctx->vcc,
+		ctx->skb, urb->status);
+
+	ctx->vcc->pop (ctx->vcc, ctx->skb);
+	ctx->skb = NULL;
+
+	spin_lock_irqsave (&instance->sndqlock, flags);
+	if (skb_queue_empty (&instance->sndqueue)) {
+		spin_unlock_irqrestore (&instance->sndqlock, flags);
+		return;
+	}
+	/* submit next skb */
+	ctx->skb = skb_dequeue (&(instance->sndqueue));
+	ctx->vcc = ((struct udsl_cb *) (ctx->skb->cb))->vcc;
+	spin_unlock_irqrestore (&instance->sndqlock, flags);
+	FILL_BULK_URB (urb,
+		       instance->usb_dev,
+		       usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
+		       (unsigned char *) ctx->skb->data,
+		       ctx->skb->len, (usb_complete_t) udsl_usb_send_data_complete, ctx);
+
+	err = usb_submit_urb (urb, GFP_KERNEL);
+
+	PDEBUG ("udsl_usb_send_data_completion (send packet %p with length %d), retval = %d\n",
+		ctx->skb, ctx->skb->len, err);
+}
+
+int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc)
+{
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave (&instance->sndqlock, flags);
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
+		if (!instance->send_ctx[i].skb)
+			continue;
+		if (instance->send_ctx[i].vcc == vcc) {
+			usb_unlink_urb (instance->send_ctx[i].urb);
+			usb_free_urb (instance->send_ctx[i].urb);
+			instance->send_ctx[i].vcc->pop (instance->send_ctx[i].vcc,
+							instance->send_ctx[i].skb);
+			instance->send_ctx[i].skb = NULL;
+		}
+	}
+	spin_unlock_irqrestore (&instance->sndqlock, flags);
+
+	return 0;
+}
+
+/**** send ******/
+int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_vcc *vcc,
+			struct sk_buff *skb)
+{
+	int err, i;
+	struct urb *urb;
+	unsigned long flags;
+
+	PDEBUG ("udsl_usb_send_data entered, sending packet %p with length %d\n", skb, skb->len);
+
+	if (!instance->data_started)
+		return -EAGAIN;
+
+	PACKETDEBUG (skb->data, skb->len);
+
+	spin_lock_irqsave (&instance->sndqlock, flags);
+	((struct udsl_cb *) skb->cb)->vcc = vcc;
+
+	/* we are already queueing */
+	if (!skb_queue_empty (&instance->sndqueue)) {
+		skb_queue_tail (&instance->sndqueue, skb);
+		spin_unlock_irqrestore (&instance->sndqlock, flags);
+		PDEBUG ("udsl_usb_send_data: already queing, skb (0x%p) queued\n", skb);
+		return 0;
+	}
+
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+		if (instance->send_ctx[i].skb == NULL)
+			break;
+
+	/* we must start queueing */
+	if (i == UDSL_NUMBER_SND_URBS) {
+		skb_queue_tail (&instance->sndqueue, skb);
+		spin_unlock_irqrestore (&instance->sndqlock, flags);
+		PDEBUG ("udsl_usb_send_data: skb (0x%p) queued\n", skb);
+		return 0;
+	};
+
+	/* init context */
+	urb = instance->send_ctx[i].urb;
+	instance->send_ctx[i].skb = skb;
+	instance->send_ctx[i].vcc = vcc;
+	instance->send_ctx[i].instance = instance;
+
+	spin_unlock_irqrestore (&instance->sndqlock, flags);
+
+	/* submit packet */
+	FILL_BULK_URB (urb,
+		       instance->usb_dev,
+		       usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
+		       (unsigned char *) skb->data,
+		       skb->len,
+		       (usb_complete_t) udsl_usb_send_data_complete, &(instance->send_ctx[i])
+	    );
+
+	err = usb_submit_urb (urb, GFP_KERNEL);
+
+	if (err != 0)
+		skb_unlink (skb);
+
+	PDEBUG ("udsl_usb_send_data done (retval = %d)\n", err);
+	return err;
+}
+
+/********* receive *******/
+void udsl_usb_data_receive (struct urb *urb)
+{
+	struct udsl_data_ctx *ctx;
+	struct udsl_instance_data *instance;
+	unsigned long flags;
+
+	if (!urb)
+		return;
+
+	PDEBUG ("udsl_usb_receive_data entered, got packet %p with length %d an status %d\n", urb,
+		urb->actual_length, urb->status);
+
+	ctx = (struct udsl_data_ctx *) urb->context;
+	if (!ctx || !ctx->skb)
+		return;
+
+	instance = ctx->instance;
+
+	switch (urb->status) {
+	case 0:
+		PDEBUG ("udsl_usb_data_receive: processing urb with ctx %p, urb %p (%p), skb %p\n",
+			ctx, ctx ? ctx->urb : NULL, urb, ctx ? ctx->skb : NULL);
+		/* update the skb structure */
+		skb_put (ctx->skb, urb->actual_length);
+
+		/* queue the skb for processing and wake the SAR */
+		spin_lock_irqsave (&instance->recvqlock, flags);
+		skb_queue_tail (&instance->recvqueue, ctx->skb);
+		spin_unlock_irqrestore (&instance->recvqlock, flags);
+		wake_up (&udsl_wqh);
+		/* get a new skb */
+		ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
+		if (!ctx->skb) {
+			PDEBUG ("No skb, loosing urb.\n");
+			usb_free_urb (ctx->urb);
+			ctx->urb = NULL;
+			return;
+		}
+		break;
+	case -EPIPE:		/* stall or babble */
+		usb_clear_halt (urb->dev, usb_rcvbulkpipe (urb->dev, UDSL_ENDPOINT_DATA_IN));
+		break;
+	case -ENOENT:		/* buffer was unlinked */
+	case -EILSEQ:		/* unplug or timeout */
+	case -ETIMEDOUT:	/* unplug or timeout */
+		/* 
+		 * we don't do anything here and we don't resubmit
+		 */
+		return;
+	}
+
+	FILL_BULK_URB (urb,
+		       instance->usb_dev,
+		       usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
+		       (unsigned char *) ctx->skb->data,
+		       UDSL_RECEIVE_BUFFER_SIZE, (usb_complete_t) udsl_usb_data_receive, ctx);
+	usb_submit_urb (urb, GFP_KERNEL);
+	return;
+};
+
+int udsl_usb_data_init (struct udsl_instance_data *instance)
+{
+	int i, succes;
+
+	if (instance->data_started)
+		return 1;
+
+	/* set alternate setting 1 on interface 1 */
+	usb_set_interface (instance->usb_dev, 1, 2);
+
+	PDEBUG ("max packet size on endpoint %d is %d\n", UDSL_ENDPOINT_DATA_OUT,
+		usb_maxpacket (instance->usb_dev,
+			       usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), 0));
+
+	instance->rcvbufs =
+	    (struct udsl_data_ctx *) kmalloc (sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS,
+					      GFP_KERNEL);
+	if (!instance->rcvbufs)
+		return -ENOMEM;
+
+	memset (instance->rcvbufs, 0, sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS);
+
+	skb_queue_head_init (&instance->sndqueue);
+
+	for (i = 0, succes = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
+		struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
+
+		ctx->urb = NULL;
+		ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
+		if (!ctx->skb)
+			continue;
+
+		ctx->urb = usb_alloc_urb (0, GFP_KERNEL);
+		if (!ctx->urb) {
+			kfree_skb (ctx->skb);
+			ctx->skb = NULL;
+			break;
+		};
+
+		FILL_BULK_URB (ctx->urb,
+			       instance->usb_dev,
+			       usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
+			       (unsigned char *) ctx->skb->data,
+			       UDSL_RECEIVE_BUFFER_SIZE,
+			       (usb_complete_t) udsl_usb_data_receive, ctx);
+
+
+		ctx->instance = instance;
+
+		PDEBUG ("udsl_usb_data_init: usb with skb->truesize = %d (Asked for %d)\n",
+			ctx->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE);
+
+		if (usb_submit_urb (ctx->urb, GFP_KERNEL) < 0)
+			PDEBUG ("udsl_usb_data_init: Submit failed, loosing urb.\n");
+		else
+			succes++;
+	}
+
+	PDEBUG ("udsl_usb_data_init %d urb%s queued for receive\n", succes,
+		(succes != 1) ? "s" : "");
+
+	for (i = 0, succes = 0; i < UDSL_NUMBER_SND_URBS; i++) {
+		instance->send_ctx[i].urb = usb_alloc_urb (0, GFP_KERNEL);
+		PDEBUG ("udsl_usb_data_init: send urb allocted address %p\n",
+			instance->send_ctx[i].urb);
+		if (instance->send_ctx[i].urb)
+			succes++;
+	}
+
+	PDEBUG ("udsl_usb_data_init %d urb%s queued for send\n", succes, (succes != 1) ? "s" : "");
+
+	instance->data_started = 1;
+	instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+	return 0;
+}
+
+int udsl_usb_data_exit (struct udsl_instance_data *instance)
+{
+	int i;
+
+	if (!instance->data_started)
+		return 0;
+
+	if (!instance->rcvbufs)
+		return 0;
+
+	/* destroy urbs */
+	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
+		struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
+
+		if ((!ctx->urb) || (!ctx->skb))
+			continue;
+
+		if (ctx->urb->status == -EINPROGRESS)
+			usb_unlink_urb (ctx->urb);
+
+		usb_free_urb (ctx->urb);
+		kfree_skb (ctx->skb);
+		ctx->skb = NULL;
+	}
+
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
+		struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
+
+		if (ctx->urb->status == -EINPROGRESS)
+			usb_unlink_urb (ctx->urb);
+
+		if (ctx->skb)
+			ctx->vcc->pop (ctx->vcc, ctx->skb);
+		ctx->skb = NULL;
+
+		usb_free_urb (ctx->urb);
+
+	}
+
+	/* free receive contexts */
+	kfree (instance->rcvbufs);
+	instance->rcvbufs = NULL;
+
+	instance->data_started = 0;
+	instance->atm_dev->signal = ATM_PHY_SIG_LOST;
+
+	return 0;
+};
+
+
+/***************************************************************************
+*
+* usb driver entries
+*
+****************************************************************************/
+#define hex2int(c) ( (c >= '0')&&(c <= '9') ?  (c - '0') : ((c & 0xf)+9) )
+
+
+static int udsl_usb_ioctl (struct usb_device *dev, unsigned int code, void *user_data)
+{
+	struct udsl_instance_data *instance;
+	int i;
+
+	for (i = 0; i < MAX_UDSL; i++)
+		if (minor_data[i] && (minor_data[i]->usb_dev == dev))
+			break;
+
+	if (i == MAX_UDSL)
+		return -EINVAL;
+
+	instance = minor_data[i];
+
+	switch (code) {
+	case UDSL_IOCTL_START:
+		return udsl_usb_data_init (instance);
+		break;
+	case UDSL_IOCTL_STOP:
+		return udsl_usb_data_exit (instance);
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+void *udsl_usb_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	int i;
+	unsigned char mac[6];
+	unsigned char mac_str[13];
+	struct udsl_instance_data *instance = NULL;
+
+	PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
+		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
+	    (dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
+	    (dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
+		return NULL;
+
+	MOD_INC_USE_COUNT;
+
+	for (i = 0; i < MAX_UDSL; i++)
+		if (minor_data[i] == NULL)
+			break;
+
+	if (i >= MAX_UDSL) {
+		printk (KERN_INFO "No minor table space available for SpeedTouch USB\n");
+		return NULL;
+	};
+
+	PDEBUG ("Device Accepted, assigning minor %d\n", i);
+
+	/* device init */
+	instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL);
+	if (!instance) {
+		PDEBUG ("No memory for Instance data!\n");
+		return NULL;
+	}
+
+	/* initialize structure */
+	memset (instance, 0, sizeof (struct udsl_instance_data));
+	instance->minor = i;
+	instance->usb_dev = dev;
+	instance->rcvbufs = NULL;
+	spin_lock_init (&instance->sndqlock);
+	spin_lock_init (&instance->recvqlock);
+
+	udsl_atm_startdevice (instance, &udsl_atm_devops);
+
+	/* set MAC address, it is stored in the serial number */
+	usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13);
+	for (i = 0; i < 6; i++)
+		mac[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
+
+	PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4],
+		mac[5]);
+	udsl_atm_set_mac (instance, mac);
+
+	minor_data[instance->minor] = instance;
+
+	return instance;
+}
+
+void udsl_usb_disconnect (struct usb_device *dev, void *ptr)
+{
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) ptr;
+	int i = instance->minor;
+
+	/* unlinking receive buffers */
+	udsl_usb_data_exit (instance);
+
+	/* removing atm device */
+	if (instance->atm_dev)
+		udsl_atm_stopdevice (instance);
+
+	PDEBUG ("disconnecting minor %d\n", i);
+
+	while (MOD_IN_USE > 1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout (1);
+	}
+
+	kfree (instance);
+	minor_data[i] = NULL;
+
+	MOD_DEC_USE_COUNT;
+}
+
+/***************************************************************************
+*
+* Driver Init
+*
+****************************************************************************/
+
+int udsl_usb_init (void)
+{
+	int i;
+
+	PDEBUG ("Initializing SpeedTouch Driver Version %s\n", udsl_version);
+
+	for (i = 0; i < MAX_UDSL; i++)
+		minor_data[i] = NULL;
+
+	init_waitqueue_head (&udsl_wqh);
+	udsl_atm_sar_start ();
+
+	return usb_register (&udsl_usb_driver);
+}
+
+int udsl_usb_cleanup (void)
+{
+	/* killing threads */
+	udsl_atm_sar_stop ();
+	usb_deregister (&udsl_usb_driver);
+	return 0;
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+	return udsl_usb_init ();
+}
+
+int cleanup_module (void)
+{
+	return udsl_usb_cleanup ();
+}
+#endif
+
+#ifdef DEBUG_PACKET
+/*******************************************************************************
+*
+* Debug 
+*
+*******************************************************************************/
+
+int udsl_print_packet (const unsigned char *data, int len)
+{
+	unsigned char buffer[256];
+	int i = 0, j = 0;
+
+	for (i = 0; i < len;) {
+		buffer[0] = '\0';
+		sprintf (buffer, "%.3d :", i);
+		for (j = 0; (j < 16) && (i < len); j++, i++) {
+			sprintf (buffer, "%s %2.2x", buffer, data[i]);
+		}
+		PDEBUG ("%s\n", buffer);
+	}
+	return i;
+};
+
+#endif				/* PACKETDEBUG */
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
--- a/drivers/usb/misc/tiglusb.c	Tue Aug 27 12:27:47 2002
+++ b/drivers/usb/misc/tiglusb.c	Tue Aug 27 12:27:47 2002
@@ -41,10 +41,6 @@
 #include <linux/ticable.h>
 #include "tiglusb.h"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-# define minor(x) MINOR(x)
-#endif
-
 /*
  * Version Information
  */
diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/usblcd.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,354 @@
+/***************************************************************************** 
+ *                          USBLCD Kernel Driver                             *
+ *        See http://www.usblcd.de for Hardware and Documentation.           *
+ *                            Version 1.01                                   *
+ *             (C) 2002 Adams IT Services <info@usblcd.de>                   *
+ *                                                                           *
+ *     This file is licensed under the GPL. See COPYING in the package.      *
+ * Based on rio500.c by Cesar Miquel (miquel@df.uba.ar) which is based on    *
+ * hp_scanner.c by David E. Nelson (dnelson@jump.net)                        *
+ *                                                                           *
+ * 23.7.02 RA changed minor device number to the official assigned one       *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#define DRIVER_VERSION "USBLCD Driver Version 1.01"
+
+#define USBLCD_MINOR		144
+
+#define IOCTL_GET_HARD_VERSION	1
+#define IOCTL_GET_DRV_VERSION	2
+
+/* stall/wait timeout for USBLCD */
+#define NAK_TIMEOUT	(HZ)
+
+#define IBUF_SIZE	0x1000
+#define OBUF_SIZE	0x10000
+
+struct lcd_usb_data {
+	struct usb_device *lcd_dev;	/* init: probe_lcd */
+	unsigned int ifnum;		/* Interface number of the USB device */
+	int minor;			/* minor number for this device */
+	int isopen;			/* nz if open */
+	int present;			/* Device is present on the bus */
+	char *obuf, *ibuf;		/* transfer buffers */
+	char bulk_in_ep, bulk_out_ep;	/* Endpoint assignments */
+	wait_queue_head_t wait_q;	/* for timeouts */
+};
+
+static struct lcd_usb_data lcd_instance;
+
+static int open_lcd(struct inode *inode, struct file *file)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	if (lcd->isopen || !lcd->present) {
+		return -EBUSY;
+	}
+	lcd->isopen = 1;
+
+	init_waitqueue_head(&lcd->wait_q);
+
+	info("USBLCD opened.");
+
+	return 0;
+}
+
+static int close_lcd(struct inode *inode, struct file *file)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	lcd->isopen = 0;
+
+	info("USBLCD closed.");
+	return 0;
+}
+
+static int
+ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	int i;
+	char buf[30];
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	switch (cmd) {
+	case IOCTL_GET_HARD_VERSION:
+		i = (lcd->lcd_dev)->descriptor.bcdDevice;
+		sprintf(buf,"%1d%1d.%1d%1d",(i & 0xF000)>>12,(i & 0xF00)>>8,
+			(i & 0xF0)>>4,(i & 0xF));
+		if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
+			return -EFAULT;
+		break;
+	case IOCTL_GET_DRV_VERSION:
+		sprintf(buf,DRIVER_VERSION);
+		if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
+			return -EFAULT;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t
+write_lcd(struct file *file, const char *buffer,
+	  size_t count, loff_t * ppos)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	unsigned long copy_size;
+	unsigned long bytes_written = 0;
+	unsigned int partial;
+
+	int result = 0;
+	int maxretry;
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	do {
+		unsigned long thistime;
+		char *obuf = lcd->obuf;
+
+		thistime = copy_size =
+		    (count >= OBUF_SIZE) ? OBUF_SIZE : count;
+		if (copy_from_user(lcd->obuf, buffer, copy_size))
+			return -EFAULT;
+		maxretry = 5;
+		while (thistime) {
+			if (!lcd->lcd_dev)
+				return -ENODEV;
+			if (signal_pending(current)) {
+				return bytes_written ? bytes_written : -EINTR;
+			}
+
+			result = usb_bulk_msg(lcd->lcd_dev,
+					 usb_sndbulkpipe(lcd->lcd_dev, 1),
+					 obuf, thistime, &partial, 10 * HZ);
+
+			dbg("write stats: result:%d thistime:%lu partial:%u",
+			     result, thistime, partial);
+
+			if (result == -ETIMEDOUT) {	/* NAK - so hold for a while */
+				if (!maxretry--) {
+					return -ETIME;
+				}
+				interruptible_sleep_on_timeout(&lcd-> wait_q, NAK_TIMEOUT);
+				continue;
+			} else if (!result & partial) {
+				obuf += partial;
+				thistime -= partial;
+			} else
+				break;
+		};
+		if (result) {
+			err("Write Whoops - %x", result);
+			return -EIO;
+		}
+		bytes_written += copy_size;
+		count -= copy_size;
+		buffer += copy_size;
+	} while (count > 0);
+
+	return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_lcd(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	ssize_t read_count;
+	unsigned int partial;
+	int this_read;
+	int result;
+	int maxretry = 10;
+	char *ibuf = lcd->ibuf;
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	read_count = 0;
+
+	while (count > 0) {
+		if (signal_pending(current)) {
+			return read_count ? read_count : -EINTR;
+		}
+		if (!lcd->lcd_dev)
+			return -ENODEV;
+		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+
+		result = usb_bulk_msg(lcd->lcd_dev,
+				      usb_rcvbulkpipe(lcd->lcd_dev, 0),
+				      ibuf, this_read, &partial,
+				      (int) (HZ * 8));
+
+		dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
+		       result, this_read, partial);
+
+		if (partial) {
+			count = this_read = partial;
+		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
+			if (!maxretry--) {
+				err("read_lcd: maxretry timeout");
+				return -ETIME;
+			}
+			interruptible_sleep_on_timeout(&lcd->wait_q,
+						       NAK_TIMEOUT);
+			continue;
+		} else if (result != -EREMOTEIO) {
+			err("Read Whoops - result:%u partial:%u this_read:%u",
+			     result, partial, this_read);
+			return -EIO;
+		} else {
+			return (0);
+		}
+
+		if (this_read) {
+			if (copy_to_user(buffer, ibuf, this_read))
+				return -EFAULT;
+			count -= this_read;
+			read_count += this_read;
+			buffer += this_read;
+		}
+	}
+	return read_count;
+}
+
+static struct
+file_operations usb_lcd_fops = {
+	.owner =	THIS_MODULE,
+	.read =		read_lcd,
+	.write =	write_lcd,
+	.ioctl =	ioctl_lcd,
+	.open =		open_lcd,
+	.release =	close_lcd,
+};
+
+static void *probe_lcd(struct usb_device *dev, unsigned int ifnum)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	int i;
+	int retval;
+	
+	if (dev->descriptor.idProduct != 0x0001  ) {
+		warn(KERN_INFO "USBLCD model not supported.");
+		return NULL;
+	}
+
+	if (lcd->present == 1) {
+		warn(KERN_INFO "Multiple USBLCDs are not supported!");
+		return NULL;
+	}
+
+	i = dev->descriptor.bcdDevice;
+
+	info("USBLCD Version %1d%1d.%1d%1d found at address %d",
+		(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
+		dev->devnum);
+
+	retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, 1, &lcd->minor);
+	if (retval) {
+		err("Not able to get a minor for this device.");
+		return NULL;
+	}
+	
+	lcd->present = 1;
+	lcd->lcd_dev = dev;
+
+	if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+		err("probe_lcd: Not enough memory for the output buffer");
+		return NULL;
+	}
+	dbg("probe_lcd: obuf address:%p", lcd->obuf);
+
+	if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+		err("probe_lcd: Not enough memory for the input buffer");
+		kfree(lcd->obuf);
+		return NULL;
+	}
+	dbg("probe_lcd: ibuf address:%p", lcd->ibuf);
+
+	return lcd;
+}
+
+static void disconnect_lcd(struct usb_device *dev, void *ptr)
+{
+	struct lcd_usb_data *lcd = (struct lcd_usb_data *) ptr;
+
+	usb_deregister_dev(1, lcd->minor);
+
+	if (lcd->isopen) {
+		lcd->isopen = 0;
+		/* better let it finish - the release will do whats needed */
+		lcd->lcd_dev = NULL;
+		return;
+	}
+	kfree(lcd->ibuf);
+	kfree(lcd->obuf);
+
+	info("USBLCD disconnected.");
+
+	lcd->present = 0;
+}
+
+static struct usb_device_id id_table [] = {
+	{ .idVendor = 0x1212, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
+	{},
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+static struct
+usb_driver lcd_driver = {
+	.name =		"usblcd",
+	.probe =	(void *)probe_lcd,
+	.disconnect =	disconnect_lcd,
+	.id_table =	id_table,
+};
+
+int usb_lcd_init(void)
+{
+	if (usb_register(&lcd_driver) < 0)
+		return -1;
+
+	info("%s (C) Adams IT Services http://www.usblcd.de", DRIVER_VERSION);
+	info("USBLCD support registered.");
+	return 0;
+}
+
+
+void usb_lcd_cleanup(void)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	lcd->present = 0;
+	usb_deregister(&lcd_driver);
+}
+
+module_init(usb_lcd_init);
+module_exit(usb_lcd_cleanup);
+
+MODULE_AUTHOR("Adams IT Services <info@usblcd.de>");
+MODULE_DESCRIPTION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c
--- a/drivers/usb/net/cdc-ether.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/usb/net/cdc-ether.c	Tue Aug 27 12:27:57 2002
@@ -1,4 +1,4 @@
-// Portions of this file taken from 
+// Portions of this file taken from
 // Petko Manolov - Petkan (petkan@dce.bg)
 // from his driver pegasus.c
 
@@ -436,7 +436,10 @@
 
 	// Tell the kernel to stop sending us frames while we get this
 	// all set up.
-	netif_stop_queue(net);
+//	netif_stop_queue(net);
+
+// FIXME: We hold xmit_lock. If you want to do the queue stuff you need
+//	  to enable it from a completion handler
 
       /* Note: do not reorder, GCC is clever about common statements. */
         if (net->flags & IFF_PROMISC) {
@@ -469,7 +472,7 @@
 			MODE_FLAG_DIRECTED |
 			MODE_FLAG_BROADCAST |
 			MODE_FLAG_MULTICAST;
-		buff = kmalloc(6 * net->mc_count, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+		buff = kmalloc(6 * net->mc_count, GFP_ATOMIC);
                 for (i = 0, mclist = net->mc_list;
 		     mclist && i < net->mc_count;
                      i++, mclist = mclist->next) {
@@ -477,6 +480,7 @@
 		}
 #if 0
 		usb_control_msg(ether_dev->usb,
+// FIXME: We hold a spinlock. You must not use a synchronous API
 				usb_sndctrlpipe(ether_dev->usb, 0),
 				SET_ETHERNET_MULTICAST_FILTER, /* request */
 				USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */
@@ -493,7 +497,7 @@
 	CDC_SetEthernetPacketFilter(ether_dev);
 #endif	
         // Tell the kernel to start giving frames to us again.
-	netif_wake_queue(net);
+//	netif_wake_queue(net);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1170,23 +1174,20 @@
 	if (rc)	{
 		// Nope we couldn't find one we liked.
 		// This device was not meant for us to control.
-		kfree( ether_dev );
-		return	NULL;
+		goto error_all;
 	}
 
-	// Now that we FOUND a configuration. let's try to make the 
+	// Now that we FOUND a configuration. let's try to make the
 	// device go into it.
 	if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) {
 		err("usb_set_configuration() failed");
-		kfree( ether_dev );
-		return NULL;
+		goto error_all;
 	}
 
 	// Now set the communication interface up as required.
 	if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) {
 		err("usb_set_interface() failed");
-		kfree( ether_dev );
-		return NULL;
+		goto error_all;
 	}
 
 	// Only turn traffic on right now if we must...
@@ -1194,23 +1195,21 @@
 		// We found an alternate setting for the data
 		// interface that allows us to turn off traffic.
 		// We should use it.
-		if (usb_set_interface( usb, 
-		                       ether_dev->data_bInterfaceNumber, 
+		if (usb_set_interface( usb,
+		                       ether_dev->data_bInterfaceNumber,
 		                       ether_dev->data_bAlternateSetting_without_traffic)) {
 			err("usb_set_interface() failed");
-			kfree( ether_dev );
-			return NULL;
+			goto error_all;
 		}
 	} else	{
 		// We didn't find an alternate setting for the data
 		// interface that would let us turn off traffic.
 		// Oh well, let's go ahead and do what we must...
-		if (usb_set_interface( usb, 
-		                       ether_dev->data_bInterfaceNumber, 
+		if (usb_set_interface( usb,
+		                       ether_dev->data_bInterfaceNumber,
 		                       ether_dev->data_bAlternateSetting_with_traffic)) {
 			err("usb_set_interface() failed");
-			kfree( ether_dev );
-			return NULL;
+			goto error_all;
 		}
 	}
 
@@ -1220,8 +1219,7 @@
 		// Hmm...  The kernel is not sharing today...
 		// Fine, we didn't want it anyway...
 		err( "Unable to initialize ethernet device" );
-		kfree( ether_dev );
-		return	NULL;
+		goto error_all;
 	}
 
 	// Now that we have an ethernet device, let's set it up
@@ -1241,7 +1239,7 @@
 	// We'll keep track of this information for later...
 	ether_dev->usb = usb;
 	ether_dev->net = net;
-	
+
 	// and don't forget the MAC address.
 	set_ethernet_addr( ether_dev );
 
@@ -1249,12 +1247,12 @@
 	log_device_info( ether_dev );
 
 	// I claim this interface to be a CDC Ethernet Networking device
-	usb_driver_claim_interface( &CDCEther_driver, 
-	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]), 
+	usb_driver_claim_interface( &CDCEther_driver,
+	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]),
 	                            ether_dev );
 	// I claim this interface to be a CDC Ethernet Networking device
-	usb_driver_claim_interface( &CDCEther_driver, 
-	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]), 
+	usb_driver_claim_interface( &CDCEther_driver,
+	                            &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]),
 	                            ether_dev );
 
 	// Does this REALLY do anything???
@@ -1265,6 +1263,14 @@
 
 	// Okay, we are finally done...
 	return NULL;
+
+	// bailing out with our tail between our knees
+error_all:
+	usb_free_urb(ether_dev->tx_urb);
+	usb_free_urb(ether_dev->rx_urb);
+	usb_free_urb(ether_dev->intr_urb);
+	kfree( ether_dev );
+	return	NULL;
 }
 
 
diff -Nru a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in
--- a/drivers/usb/serial/Config.in	Tue Aug 27 12:27:45 2002
+++ b/drivers/usb/serial/Config.in	Tue Aug 27 12:27:45 2002
@@ -36,7 +36,7 @@
 dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
 dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
 dep_tristate '  USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-   dep_mbool '  USB Secure Encapsulated Driver - Padded (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE_PADDED $CONFIG_USB_SERIAL_SAFE
+   dep_mbool '  USB Secure Encapsulated Driver - Padded' CONFIG_USB_SERIAL_SAFE_PADDED $CONFIG_USB_SERIAL_SAFE
 dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Xircom / Entregra Single Port Serial Driver' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL
 dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h
--- a/drivers/usb/serial/ipaq.h	Tue Aug 27 12:27:51 2002
+++ b/drivers/usb/serial/ipaq.h	Tue Aug 27 12:27:51 2002
@@ -19,7 +19,7 @@
 #define COMPAQ_VENDOR_ID	0x049f
 #define COMPAQ_IPAQ_ID		0x0003
 
-#define HP_VENDOR_ID		0x003f
+#define HP_VENDOR_ID		0x03f0
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
 
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/serial/usbserial.c	Tue Aug 27 12:28:02 2002
@@ -1193,7 +1193,7 @@
 	interface = &dev->actconfig->interface[ifnum];
 	list_for_each (tmp, &usb_serial_driver_list) {
 		type = list_entry(tmp, struct usb_serial_device_type, driver_list);
-		id_pattern = usb_match_id(dev, interface, type->id_table);
+		id_pattern = usb_match_id(interface, type->id_table);
 		if (id_pattern != NULL) {
 			dbg("descriptor matches");
 			found = 1;
diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
--- a/drivers/usb/storage/isd200.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/usb/storage/isd200.c	Tue Aug 27 12:28:06 2002
@@ -434,6 +434,12 @@
                 return ISD200_TRANSPORT_GOOD;
         }
 
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+                US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
+		return ISD200_TRANSPORT_ABORTED;
+	}
+
         /* uh oh... we have an error code, so something went wrong. */
         if (result) {
                 /* NAK - that means we've retried a few times already */
@@ -442,12 +448,6 @@
                         return ISD200_TRANSPORT_FAILED;
                 }
 
-                /* -ENOENT -- we canceled this transfer */
-                if (result == -ENOENT) {
-                        US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
-                        return ISD200_TRANSPORT_ABORTED;
-                }
-
                 /* the catch-all case */
                 US_DEBUGP("isd200_transfer_partial(): unknown error\n");
                 return ISD200_TRANSPORT_FAILED;
@@ -581,8 +581,11 @@
 				   &partial);
         US_DEBUGP("Bulk command transfer result=%d\n", result);
     
-	if (result == -ENOENT)
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 		return ISD200_TRANSPORT_ABORTED;
+	}
+
 	else if (result == -EPIPE) {
 		/* if we stall, we need to clear it before we go on */
                 US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
@@ -610,8 +613,10 @@
         US_DEBUGP("Attempting to get CSW...\n");
         result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
 				   &partial);
-        if (result == -ENOENT)
-                return ISD200_TRANSPORT_ABORTED;
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		return ISD200_TRANSPORT_ABORTED;
+	}
 
         /* did the attempt to read the CSW fail? */
         if (result == -EPIPE) {
@@ -624,8 +629,9 @@
                                            US_BULK_CS_WRAP_LEN, &partial);
 
                 /* if the command was aborted, indicate that */
-                if (result == -ENOENT)
-                        return ISD200_TRANSPORT_ABORTED;
+		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+			return ISD200_TRANSPORT_ABORTED;
+		}
         
                 /* if it fails again, we need a reset and return an error*/
                 if (result == -EPIPE) {
diff -Nru a/drivers/usb/storage/raw_bulk.c b/drivers/usb/storage/raw_bulk.c
--- a/drivers/usb/storage/raw_bulk.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/usb/storage/raw_bulk.c	Tue Aug 27 12:28:01 2002
@@ -3,7 +3,7 @@
  * Unrelated to CF/SM - just USB stuff.
  *
  * This is mostly a thin layer on top of transport.c.
- * It converts routines that return values like -ENOENT and -EPIPE
+ * It converts routines that return values like -EPIPE
  * into routines that return USB_STOR_TRANSPORT_ABORTED etc.
  *
  * There is also some debug printing here.
@@ -58,13 +58,14 @@
 			request, requesttype, value, index,
 			xfer_data, xfer_len);
 
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		US_DEBUGP("usb_stor_send_control(): transfer aborted\n");
+		return US_BULK_TRANSFER_ABORTED;
+	}
 
 	// Check the return code for the command.
-
 	if (result < 0) {
-		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
-			return USB_STOR_TRANSPORT_ABORTED;
 
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
@@ -105,13 +106,13 @@
 		/* return US_BULK_TRANSFER_SHORT; */
 	}
 
-	if (result) {
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
-			US_DEBUGP("raw_bulk(): transfer aborted\n");
-			return US_BULK_TRANSFER_ABORTED;
-		}
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n");
+		return US_BULK_TRANSFER_ABORTED;
+	}
 
+	if (result) {
 		/* NAK - that means we've retried a few times already */
        		if (result == -ETIMEDOUT)
 			US_DEBUGP("raw_bulk(): device NAKed\n");
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/usb/storage/scsiglue.c	Tue Aug 27 12:28:06 2002
@@ -147,7 +147,8 @@
 	srb->host_scribble = (unsigned char *)us;
 
 	/* enqueue the command */
-	BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE || us->srb != NULL);
+	BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
+	BUG_ON(us->srb != NULL);
 	srb->scsi_done = done;
 	us->srb = srb;
 
@@ -264,7 +265,7 @@
 		US_DEBUGPX("simulating disconnect/reconnect.\n");
 		down(&intf->driver->serialize);
 		intf->driver->disconnect(pusb_dev_save, intf->private_data);
-		id = usb_match_id(pusb_dev_save, intf, intf->driver->id_table);
+		id = usb_match_id(intf, intf->driver->id_table);
 		intf->driver->probe(pusb_dev_save, i, id);
 		up(&intf->driver->serialize);
 	}
@@ -379,12 +380,21 @@
 	.emulated =		TRUE
 };
 
+/* For a device that is "Not Ready" */
 unsigned char usb_stor_sense_notready[18] = {
 	[0]	= 0x70,			    /* current error */
 	[2]	= 0x02,			    /* not ready */
 	[7]	= 0x0a,			    /* additional length */
 	[12]	= 0x04,			    /* not ready */
 	[13]	= 0x03			    /* manual intervention */
+};
+
+/* To Report "Illegal Request: Invalid Field in CDB */
+unsigned char usb_stor_sense_invalidCDB[18] = {
+	[0]	= 0x70,			    /* current error */
+	[2]	= ILLEGAL_REQUEST,	    /* Illegal Request = 0x05 */
+	[7]	= 0x0a,			    /* additional length */
+	[12]	= 0x24			    /* Invalid Field in CDB */
 };
 
 #define USB_STOR_SCSI_SENSE_HDRSZ 4
diff -Nru a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
--- a/drivers/usb/storage/scsiglue.h	Tue Aug 27 12:27:45 2002
+++ b/drivers/usb/storage/scsiglue.h	Tue Aug 27 12:27:45 2002
@@ -46,6 +46,7 @@
 #include "hosts.h"
 
 extern unsigned char usb_stor_sense_notready[18];
+extern unsigned char usb_stor_sense_invalidCDB[18];
 extern Scsi_Host_Template usb_stor_host_template;
 extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
 extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/storage/transport.c	Tue Aug 27 12:28:02 2002
@@ -348,7 +348,10 @@
 	 * violates this invariant is a bug.  In the hopes of removing
 	 * all the complex logic above, let's find them and eliminate them.
 	 */
-	BUG_ON(len != srb->request_bufflen);
+	if (len != srb->request_bufflen) {
+		printk("USB len=%d, request_bufflen=%d\n", len, srb->request_bufflen);
+		show_trace(NULL);
+	}
 
 	return len;
 }
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/usb/storage/unusual_devs.h	Tue Aug 27 12:28:08 2002
@@ -65,6 +65,17 @@
 		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
 #endif
 
+/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
+ * always fails and confuses drive; without US_FL_START_STOP, drive accesses
+ * (read or write) all fail.
+ */
+UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
+		"Buffalo",
+		"DUB-P40G HDD",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY | US_FL_START_STOP),
+
 #ifdef CONFIG_USB_STORAGE_DPCM
 UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
 		"Microtech",
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/usb/storage/usb.c	Tue Aug 27 12:28:02 2002
@@ -385,11 +385,15 @@
 			us->srb->result = DID_BAD_TARGET << 16;
 		}
 
-		/* handle those devices which can't do a START_STOP */
-		else if ((us->srb->cmnd[0] == START_STOP) &&
-		    (us->flags & US_FL_START_STOP)) {
-			US_DEBUGP("Skipping START_STOP command\n");
-			us->srb->result = GOOD << 1;
+		/* handle requests for EVPD, which most USB devices do
+		 * not support */
+		else if((us->srb->cmnd[0] == INQUIRY) &&
+				(us->srb->cmnd[1] & 0x1)) {
+				US_DEBUGP("Faking INQUIRY command for EVPD\n");
+				memcpy(us->srb->sense_buffer, 
+				       usb_stor_sense_invalidCDB, 
+				       sizeof(usb_stor_sense_invalidCDB));
+				us->srb->result = CHECK_CONDITION << 1;
 		}
 
 		/* our device has gone - pretend not ready */
@@ -405,6 +409,7 @@
 				       sizeof(usb_stor_sense_notready));
 				us->srb->result = GOOD << 1;
 			} else if(us->srb->cmnd[0] == INQUIRY) {
+				/* INQUIRY should always work, per spec... */
 				unsigned char data_ptr[36] = {
 				    0x20, 0x80, 0x02, 0x02,
 				    0x1F, 0x00, 0x00, 0x00};
@@ -412,6 +417,7 @@
 				fill_inquiry_response(us, data_ptr, 36);
 				us->srb->result = GOOD << 1;
 			} else {
+				/* not ready */
 				memcpy(us->srb->sense_buffer, 
 				       usb_stor_sense_notready, 
 				       sizeof(usb_stor_sense_notready));
@@ -430,6 +436,35 @@
 			US_DEBUGP("Faking INQUIRY command\n");
 			fill_inquiry_response(us, data_ptr, 36);
 			us->srb->result = GOOD << 1;
+		}
+
+		/* Most USB devices can't handle START_STOP.  But we
+		 * need something for media-change, so we'll use TUR
+		 * instead.
+		 */
+		else if (us->srb->cmnd[0] == START_STOP) {
+			unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
+			__u8 old_cmd_len;
+
+			US_DEBUGP("Converting START_STOP to TUR\n");
+
+			/* save old command */
+			memcpy(saved_cdb, us->srb->cmnd, us->srb->cmd_len);
+			old_cmd_len = us->srb->cmd_len;
+
+			/* set up new command -- preserve LUN */
+			us->srb->cmd_len = 6;
+			memset(us->srb->cmnd, 0, us->srb->cmd_len);
+			us->srb->cmnd[0] = TEST_UNIT_READY;
+			us->srb->cmnd[1] = saved_cdb[1] & 0xE0;
+
+			/* do command */
+			US_DEBUG(usb_stor_show_command(us->srb));
+			us->proto_handler(us->srb, us);
+
+			/* restore original command */
+			us->srb->cmd_len = old_cmd_len;
+			memcpy(us->srb->cmnd, saved_cdb, us->srb->cmd_len);
 		}
 
 		/* we've got a command, let's do it! */
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/usb/storage/usb.h	Tue Aug 27 12:28:07 2002
@@ -203,16 +203,9 @@
 
 /* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
  * single queue element srb for write access */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
 #define scsi_unlock(host)	spin_unlock_irq(host->host_lock)
 #define scsi_lock(host)		spin_lock_irq(host->host_lock)
 
 #define sg_address(psg)		(page_address((psg)->page) + (psg)->offset)
-#else
-#define scsi_unlock(host)	spin_unlock_irq(&io_request_lock)
-#define scsi_lock(host)		spin_lock_irq(&io_request_lock)
-
-#define sg_address(psg)		((psg)->address)
-#endif
 
 #endif
diff -Nru a/drivers/video/Config.help b/drivers/video/Config.help
--- a/drivers/video/Config.help	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/Config.help	Tue Aug 27 12:28:02 2002
@@ -387,8 +387,7 @@
   Say Y here if you have a Matrox Millennium, Matrox Millennium II,
   Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
   Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
-  Matrox G400, G450 or G550 card in your box. At this time, support for 
-  the G-series digital output is almost non-existant.
+  Matrox G400, G450 or G550 card in your box.
 
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -413,7 +412,7 @@
   packed pixel and 32 bpp packed pixel. You can also use font widths
   different from 8.
 
-CONFIG_FB_MATROX_G100
+CONFIG_FB_MATROX_G450
   Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based
   video card. If you select "Advanced lowlevel driver options", you
   should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
@@ -423,11 +422,35 @@
   If you need support for G400 secondary head, you must first say Y to
   "I2C support" and "I2C bit-banging support" in the character devices
   section, and then to "Matrox I2C support" and "G400 second head
-  support" here in the framebuffer section.
+  support" here in the framebuffer section. G450/G550 secondary head
+  and digital output are supported without additional modules.
+  
+  The driver starts in monitor mode. You must use the matroxset tool 
+  (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to 
+  swap primary and secondary head outputs, or to change output mode.  
+  Secondary head driver always start in 640x480 resolution and you 
+  must use fbset to change it.
+
+  Do not forget that second head supports only 16 and 32 bpp
+  packed pixels, so it is a good idea to compile them into the kernel
+  too. You can use only some font widths, as the driver uses generic
+  painting procedures (the secondary head does not use acceleration
+  engine).
   
-  If you have G550, you must also compile support for G450/G550 secondary
-  head into kernel, otherwise picture will be shown only on output you
-  are probably not using...
+  G450/G550 hardware can display TV picture only from secondary CRTC,
+  and it performs no scaling, so picture must have 525 or 625 lines.
+
+CONFIG_FB_MATROX_G100A
+  Say Y here if you have a Matrox G100, G200 or G400 based
+  video card. If you select "Advanced lowlevel driver options", you
+  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
+  pixel and 32 bpp packed pixel. You can also use font widths
+  different from 8.
+
+  If you need support for G400 secondary head, you must first say Y to
+  "I2C support" and "I2C bit-banging support" in the character devices
+  section, and then to "Matrox I2C support" and "G400 second head
+  support" here in the framebuffer section.
 
 CONFIG_FB_MATROX_I2C
   This drivers creates I2C buses which are needed for accessing the
@@ -467,27 +490,6 @@
   Also do not forget that second head supports only 16 and 32 bpp
   packed pixels, so it is a good idea to compile them into the kernel
   too.  You can use only some font widths, as the driver uses generic
-  painting procedures (the secondary head does not use acceleration
-  engine).
-
-CONFIG_FB_MATROX_G450
-  Say Y or M here if you want to use a secondary head (meaning two
-  monitors in parallel) on G450, or if you are using analog output
-  of G550.
-
-  If you compile it as module, two modules are created,
-  matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you
-  want two independent display devices.
-
-  The driver starts in monitor mode and currently does not support
-  output in TV modes.  You must use the matroxset tool (available
-  at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to swap
-  primary and secondary head outputs.  Secondary head driver always
-  start in 640x480 resolution and you must use fbset to change it.
-
-  Also do not forget that second head supports only 16 and 32 bpp
-  packed pixels, so it is a good idea to compile them into the kernel
-  too. You can use only some font widths, as the driver uses generic
   painting procedures (the secondary head does not use acceleration
   engine).
 
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/Config.in	Tue Aug 27 12:28:07 2002
@@ -130,14 +130,19 @@
 	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
 	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
 	    bool '    Mystique support' CONFIG_FB_MATROX_MYSTIQUE
-	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G100
+	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G450
+	    if [ "$CONFIG_FB_MATROX_G450" = "n" ]; then
+	       bool '    G100/G200/G400 support' CONFIG_FB_MATROX_G100A
+	    fi
+	    if [ "$CONFIG_FB_MATROX_G450" = "y" -o "$CONFIG_FB_MATROX_G100A" = "y" ]; then
+	       define_bool CONFIG_FB_MATROX_G100 y
+	    fi
             if [ "$CONFIG_I2C" != "n" ]; then
 	       dep_tristate '      Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
 	       if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
 	          dep_tristate '      G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
 	       fi
             fi
-            dep_tristate '      G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
@@ -265,7 +270,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
            "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then 
+	   "$CONFIG_FB_SA1100" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -278,7 +283,7 @@
 	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
-	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m"-o \
+	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
@@ -292,7 +297,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
-	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then 
+	   "$CONFIG_FB_SA1100" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
@@ -331,7 +336,7 @@
 	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
 	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_ATY" = "y" ]; then 
+	   "$CONFIG_FB_SIS" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
@@ -352,7 +357,7 @@
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_APOLLO" = "y" -o \
-	   "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_OF" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" ]; then
 	 define_tristate CONFIG_FBCON_ACCEL y
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/Makefile	Tue Aug 27 12:27:59 2002
@@ -60,7 +60,7 @@
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
 obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
 obj-$(CONFIG_FB_HP300)            += hpfb.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_OF)               += offb.o
+obj-$(CONFIG_FB_OF)               += offb.o cfbfillrect.o cfbimgblit.o cfbcopyarea.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
 obj-$(CONFIG_FB_CLGEN)            += clgenfb.o
@@ -89,7 +89,7 @@
 obj-$(CONFIG_FB_MATROX)		  += matrox/
 obj-$(CONFIG_FB_RIVA)		  += riva/
 obj-$(CONFIG_FB_SIS)		  += sis/
-obj-$(CONFIG_FB_ATY)		  += aty/
+obj-$(CONFIG_FB_ATY)		  += aty/ cfbimgblt.o
 
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
 obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
@@ -119,12 +119,10 @@
 obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
 obj-$(CONFIG_FBCON_ACCEL)	  += fbcon-accel.o
 
-host-progs := ../char/conmakehash
-
 include $(TOPDIR)/Rules.make
 
-$(obj)/promcon_tbl.c: $(src)/prom.uni $(obj)/../char/conmakehash
-	$(obj)/../char/conmakehash $< | \
+$(obj)/promcon_tbl.c: $(src)/prom.uni
+	$(objtree)/scripts/conmakehash $< | \
 	sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
 	    -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@
 
diff -Nru a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
--- a/drivers/video/S3triofb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/S3triofb.c	Tue Aug 27 12:28:05 2002
@@ -124,15 +124,15 @@
                          u_int *transp, struct fb_info *info);
 
 static struct fb_ops s3trio_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	s3trio_get_fix,
-	fb_get_var:	s3trio_get_var,
-	fb_set_var:	s3trio_set_var,
-	fb_get_cmap:	s3trio_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	s3trio_setcolreg,
-	fb_pan_display:	s3trio_pan_display,
-	fb_blank:	s3triofb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	s3trio_get_fix,
+	.fb_get_var =	s3trio_get_var,
+	.fb_set_var =	s3trio_set_var,
+	.fb_get_cmap =	s3trio_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	s3trio_setcolreg,
+	.fb_pan_display =s3trio_pan_display,
+	.fb_blank =	s3triofb_blank,
 };
 
     /*
@@ -776,14 +776,14 @@
 }
 
 static struct display_switch fbcon_trio8 = {
-   setup:		fbcon_cfb8_setup,
-   bmove:		fbcon_trio8_bmove,
-   clear:		fbcon_trio8_clear,
-   putc:		fbcon_trio8_putc,
-   putcs:		fbcon_trio8_putcs,
-   revc:		fbcon_trio8_revc,
-   clear_margins:	fbcon_cfb8_clear_margins,
-   fontwidthmask:	FONTWIDTH(8)
+   .setup =		fbcon_cfb8_setup,
+   .bmove =		fbcon_trio8_bmove,
+   .clear =		fbcon_trio8_clear,
+   .putc =		fbcon_trio8_putc,
+   .putcs =		fbcon_trio8_putcs,
+   .revc =		fbcon_trio8_revc,
+   .clear_margins =	fbcon_cfb8_clear_margins,
+   .fontwidthmask =	FONTWIDTH(8)
 };
 #endif
 
diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c
--- a/drivers/video/acornfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/acornfb.c	Tue Aug 27 12:28:02 2002
@@ -1176,16 +1176,16 @@
 }
 
 static struct fb_ops acornfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	acornfb_get_fix,
-	fb_get_var:	acornfb_get_var,
-	fb_set_var:	acornfb_set_var,
-	fb_get_cmap:	acornfb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	acornfb_setcolreg,
-	fb_pan_display:	acornfb_pan_display,
-	fb_blank:	acornfb_blank,
-	fb_mmap:	acornfb_mmap,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	acornfb_get_fix,
+	.fb_get_var =	acornfb_get_var,
+	.fb_set_var =	acornfb_set_var,
+	.fb_get_cmap =	acornfb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	acornfb_setcolreg,
+	.fb_pan_display =acornfb_pan_display,
+	.fb_blank =	acornfb_blank,
+	.fb_mmap =	acornfb_mmap,
 };
 
 static int
@@ -1275,19 +1275,19 @@
 
 static struct fb_videomode __initdata
 acornfb_default_mode = {
-	name:		NULL,
-	refresh:	60,
-	xres:		640,
-	yres:		480,
-	pixclock:	39722,
-	left_margin:	56,
-	right_margin:	16,
-	upper_margin:	34,
-	lower_margin:	9,
-	hsync_len:	88,
-	vsync_len:	2,
-	sync:		0,
-	vmode:		FB_VMODE_NONINTERLACED
+	.name =		NULL,
+	.refresh =	60,
+	.xres =		640,
+	.yres =		480,
+	.pixclock =	39722,
+	.left_margin =	56,
+	.right_margin =	16,
+	.upper_margin =	34,
+	.lower_margin =	9,
+	.hsync_len =	88,
+	.vsync_len =	2,
+	.sync =		0,
+	.vmode =	FB_VMODE_NONINTERLACED
 };
 
 static void __init
diff -Nru a/drivers/video/amifb.c b/drivers/video/amifb.c
--- a/drivers/video/amifb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/amifb.c	Tue Aug 27 12:28:08 2002
@@ -1164,16 +1164,16 @@
 
 
 static struct fb_ops amifb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	amifb_get_fix,
-	fb_get_var:	amifb_get_var,
-	fb_set_var:	amifb_set_var,
-	fb_get_cmap:	amifb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	amifb_setcolreg,
-	fb_pan_display:	amifb_pan_display,
-	fb_blank:	amifb_blank,
-	fb_ioctl:	amifb_ioctl,
+	.owner		= THIS_MODULE,
+	.fb_get_fix	= amifb_get_fix,
+	.fb_get_var	= amifb_get_var,
+	.fb_set_var	= amifb_set_var,
+	.fb_get_cmap	= amifb_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= amifb_setcolreg,
+	.fb_pan_display	= amifb_pan_display,
+	.fb_blank	= amifb_blank,
+	.fb_ioctl	= amifb_ioctl,
 };
 
 static void __init amifb_setup_mcap(char *spec)
diff -Nru a/drivers/video/anakinfb.c b/drivers/video/anakinfb.c
--- a/drivers/video/anakinfb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/anakinfb.c	Tue Aug 27 12:28:07 2002
@@ -27,28 +27,28 @@
 static struct display display;
 
 static struct fb_var_screeninfo anakinfb_var = {
-	xres:		400,
-	yres:		234,
-	xres_virtual:	400,
-	yres_virtual:	234,
-	bits_per_pixel:	16,
-	red:		{ 11, 5, 0 },
-	green:		{  5, 6, 0 }, 
-	blue:		{  0, 5, 0 },
-        activate:       FB_ACTIVATE_NOW,
-        height:         -1,
-        width:          -1,
-        vmode:          FB_VMODE_NONINTERLACED,
+	.xres =		400,
+	.yres =		234,
+	.xres_virtual =	400,
+	.yres_virtual =	234,
+	.bits_per_pixel =16,
+	.red =		{ 11, 5, 0 },
+	.green =	{  5, 6, 0 }, 
+	.blue =		{  0, 5, 0 },
+	.activate	FB_ACTIVATE_NOW,
+	.height		-1,
+	.width		-1,
+	.vmode		FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo anakinfb_fix = {
-	id:		"AnakinFB",
-	smem_start:	VGA_START,
-	smem_len:	VGA_SIZE,
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_TRUECOLOR,
-	line_length:	400*2,
-	accel:		FB_ACCEL_NONE,
+	.id =		"AnakinFB",
+	.smem_start =	VGA_START,
+	.smem_len =	VGA_SIZE,
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.line_length =	400*2,
+	.accel =	FB_ACCEL_NONE,
 };
 
 static int
@@ -64,16 +64,14 @@
 }
 
 static struct fb_ops anakinfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	anakinfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= anakinfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 int __init
diff -Nru a/drivers/video/atafb.c b/drivers/video/atafb.c
--- a/drivers/video/atafb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/atafb.c	Tue Aug 27 12:27:59 2002
@@ -2623,15 +2623,15 @@
 }
 
 static struct fb_ops atafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	atafb_get_fix,
-	fb_get_var:	atafb_get_var,
-	fb_set_var:	atafb_set_var,
-	fb_get_cmap:	atafb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_pan_display:	atafb_pan_display,
-	fb_blank:	atafb_blank,
-	fb_ioctl:	atafb_ioctl,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	atafb_get_fix,
+	.fb_get_var =	atafb_get_var,
+	.fb_set_var =	atafb_set_var,
+	.fb_get_cmap =	atafb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_pan_display =atafb_pan_display,
+	.fb_blank =	atafb_blank,
+	.fb_ioctl =	atafb_ioctl,
 };
 
 static void
diff -Nru a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
--- a/drivers/video/aty/Makefile	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/aty/Makefile	Tue Aug 27 12:28:02 2002
@@ -1,6 +1,6 @@
 obj-$(CONFIG_FB_ATY) += atyfb.o
 
-atyfb-y				:= atyfb_base.o mach64_accel.o ../cfbimgblt.o
+atyfb-y				:= atyfb_base.o mach64_accel.o
 atyfb-$(CONFIG_FB_ATY_GX)	+= mach64_gx.o
 atyfb-$(CONFIG_FB_ATY_CT)	+= mach64_ct.o mach64_cursor.o
 atyfb-objs			:= $(atyfb-y)
diff -Nru a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
--- a/drivers/video/aty/atyfb.h	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/aty/atyfb.h	Tue Aug 27 12:28:07 2002
@@ -3,7 +3,7 @@
  */
 
 #include <linux/config.h>
-
+#include <video/fbcon.h>
 
     /*
      *  Elements of the hardware specific atyfb_par structure
@@ -12,9 +12,6 @@
 struct crtc {
 	u32 vxres;
 	u32 vyres;
-	u32 xoffset;
-	u32 yoffset;
-	u32 bpp;
 	u32 h_tot_disp;
 	u32 h_sync_strt_wid;
 	u32 v_tot_disp;
@@ -94,7 +91,6 @@
 	u8 ram_type;
 	u8 mem_refresh_rate;
 	u8 blitter_may_be_busy;
-	u32 accel_flags;
 #ifdef __sparc__
 	struct pci_mmap_map *mmap_map;
 	int consolecnt;
@@ -103,6 +99,7 @@
 	int open;
 #endif
 #ifdef CONFIG_PMAC_PBOOK
+	struct fb_info *next;
 	unsigned char *save_framebuffer;
 	unsigned long save_pll[64];
 #endif
@@ -161,7 +158,7 @@
 		regindex -= 0x800;
 
 #ifdef CONFIG_ATARI
-	out_le32((volatile u32 *)(par->ati_regbase + regindex));
+	out_le32((volatile u32 *)(par->ati_regbase + regindex), val);
 #else
 	writel(val, par->ati_regbase + regindex);
 #endif
@@ -280,13 +277,4 @@
 extern void aty_reset_engine(const struct atyfb_par *par);
 extern void aty_init_engine(struct atyfb_par *par,
 			    struct fb_info *info);
-extern void atyfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
-
-    /*
-     *  Text console acceleration
-     */
 
-extern const struct display_switch fbcon_aty8;
-extern const struct display_switch fbcon_aty16;
-extern const struct display_switch fbcon_aty24;
-extern const struct display_switch fbcon_aty32;
diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
--- a/drivers/video/aty/atyfb_base.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/aty/atyfb_base.c	Tue Aug 27 12:28:01 2002
@@ -66,10 +66,7 @@
 #include <asm/uaccess.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
+#include "../fbcon-accel.h"
 
 #include <video/mach64.h>
 #include "atyfb.h"
@@ -134,11 +131,11 @@
 };
 
 static struct fb_fix_screeninfo atyfb_fix __initdata = {
-	id:		"ATY Mach64",
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	xpanstep:	8,
-	ypanstep:	1,
+	.id		= "ATY Mach64",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 8,
+	.ypanstep	= 1,
 };
 
     /*
@@ -147,12 +144,9 @@
 
 static int atyfb_open(struct fb_info *info, int user);
 static int atyfb_release(struct fb_info *info, int user);
-static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
+static int atyfb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int atyfb_set_par(struct fb_info *info); 
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			   u_int transp, struct fb_info *info);
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
@@ -160,19 +154,15 @@
 static int atyfb_blank(int blank, struct fb_info *info);
 static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg, int con, struct fb_info *info);
+extern void atyfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+extern void atyfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
+extern void atyfb_imageblit(struct fb_info *info, struct fb_image *image);
 #ifdef __sparc__
 static int atyfb_mmap(struct fb_info *info, struct file *file,
 		      struct vm_area_struct *vma);
 #endif
 static int atyfb_rasterimg(struct fb_info *info, int start);
 
-
-    /*
-     *  Interface to the low level console driver
-     */
-
-static int atyfbcon_updatevar(int con, struct fb_info *info);
-
     /*
      *  Internal routines
      */
@@ -189,24 +179,13 @@
 			   struct crtc *crtc);
 static int aty_crtc_to_var(const struct crtc *crtc,
 			   struct fb_var_screeninfo *var);
-
-static void atyfb_set_par(struct atyfb_par *par,
-			  struct fb_info *info);
-static int atyfb_decode_var(const struct fb_var_screeninfo *var,
-			    struct atyfb_par *par,
-			    const struct fb_info *info);
 static int atyfb_encode_var(struct fb_var_screeninfo *var,
 			    const struct atyfb_par *par,
 			    const struct fb_info *info);
 static void set_off_pitch(struct atyfb_par *par,
 			  const struct fb_info *info);
-static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par,
-		      const struct fb_info *info);
-static void atyfb_set_dispsw(struct display *disp,
-			     struct fb_info *info);
 #ifdef CONFIG_PPC
-static int read_aty_sense(const struct fb_info *info);
+static int read_aty_sense(const struct atyfb_par *par);
 #endif
 
 
@@ -219,26 +198,34 @@
 int atyfb_setup(char *);
 #endif
 
+int gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+        *var = info->var;
+        return 0;
+}
+
 static struct fb_ops atyfb_ops = {
-	owner:THIS_MODULE,
-	fb_open:atyfb_open,
-	fb_release:atyfb_release,
-	fb_get_fix:atyfb_get_fix,
-	fb_get_var:atyfb_get_var,
-	fb_set_var:atyfb_set_var,
-	fb_get_cmap:gen_get_cmap,
-	fb_set_cmap:gen_set_cmap,
-	fb_setcolreg:atyfb_setcolreg,
-	fb_pan_display:atyfb_pan_display,
-	fb_blank:atyfb_blank,
-	fb_ioctl:atyfb_ioctl,
+	.owner		= THIS_MODULE,
+	.fb_open	= atyfb_open,
+	.fb_release	= atyfb_release,
+	.fb_set_var	= gen_set_var,
+	.fb_check_var	= atyfb_check_var,
+	.fb_set_par	= atyfb_set_par,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= atyfb_setcolreg,
+	.fb_pan_display	= atyfb_pan_display,
+	.fb_blank	= atyfb_blank,
+	.fb_ioctl	= atyfb_ioctl,
+	.fb_fillrect	= atyfb_fillrect,
+	.fb_copyarea	= atyfb_copyarea,
+	.fb_imageblit	= atyfb_imageblit,
 #ifdef __sparc__
-	fb_mmap:atyfb_mmap,
+	.fb_mmap	= atyfb_mmap,
 #endif
-	fb_rasterimg:atyfb_rasterimg,
+	.fb_rasterimg	= atyfb_rasterimg,
 };
 
-static char atyfb_name[16] = "ATY Mach64";
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
 static char noaccel __initdata = 0;
@@ -462,63 +449,62 @@
      *  Apple monitor sense
      */
 
-static int __init read_aty_sense(const struct fb_info *info)
+static int __init read_aty_sense(const struct atyfb_par *par)
 {
 	int sense, i;
 
-	aty_st_le32(GP_IO, 0x31003100, info);	/* drive outputs high */
+	aty_st_le32(GP_IO, 0x31003100, par);	/* drive outputs high */
 	__delay(200);
-	aty_st_le32(GP_IO, 0, info);	/* turn off outputs */
+	aty_st_le32(GP_IO, 0, par);	/* turn off outputs */
 	__delay(2000);
-	i = aty_ld_le32(GP_IO, info);	/* get primary sense value */
+	i = aty_ld_le32(GP_IO, par);	/* get primary sense value */
 	sense = ((i & 0x3000) >> 3) | (i & 0x100);
 
 	/* drive each sense line low in turn and collect the other 2 */
-	aty_st_le32(GP_IO, 0x20000000, info);	/* drive A low */
+	aty_st_le32(GP_IO, 0x20000000, par);	/* drive A low */
 	__delay(2000);
-	i = aty_ld_le32(GP_IO, info);
+	i = aty_ld_le32(GP_IO, par);
 	sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
-	aty_st_le32(GP_IO, 0x20002000, info);	/* drive A high again */
+	aty_st_le32(GP_IO, 0x20002000, par);	/* drive A high again */
 	__delay(200);
 
-	aty_st_le32(GP_IO, 0x10000000, info);	/* drive B low */
+	aty_st_le32(GP_IO, 0x10000000, par);	/* drive B low */
 	__delay(2000);
-	i = aty_ld_le32(GP_IO, info);
+	i = aty_ld_le32(GP_IO, par);
 	sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
-	aty_st_le32(GP_IO, 0x10001000, info);	/* drive B high again */
+	aty_st_le32(GP_IO, 0x10001000, par);	/* drive B high again */
 	__delay(200);
 
-	aty_st_le32(GP_IO, 0x01000000, info);	/* drive C low */
+	aty_st_le32(GP_IO, 0x01000000, par);	/* drive C low */
 	__delay(2000);
-	sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12;
-	aty_st_le32(GP_IO, 0, info);	/* turn off outputs */
-
+	sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;
+	aty_st_le32(GP_IO, 0, par);	/* turn off outputs */
 	return sense;
 }
 
 #endif				/* defined(CONFIG_PPC) */
 
 #if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT)
-static void aty_st_lcd(int index, u32 val, const struct fb_info *info)
+static void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
 {
 	unsigned long temp;
 
 	/* write addr byte */
-	temp = aty_ld_le32(LCD_INDEX, info);
-	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+	temp = aty_ld_le32(LCD_INDEX, par);
+	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
 	/* write the register value */
-	aty_st_le32(LCD_DATA, val, info);
+	aty_st_le32(LCD_DATA, val, par);
 }
 
-static u32 aty_ld_lcd(int index, const struct fb_info *info)
+static u32 aty_ld_lcd(int index, const struct atyfb_par *par)
 {
 	unsigned long temp;
 
 	/* write addr byte */
-	temp = aty_ld_le32(LCD_INDEX, info);
-	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+	temp = aty_ld_le32(LCD_INDEX, par);
+	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
 	/* read the register value */
-	return aty_ld_le32(LCD_DATA, info);
+	return aty_ld_le32(LCD_DATA, par);
 }
 #endif				/* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */
 
@@ -646,9 +632,6 @@
 	/* output */
 	crtc->vxres = vxres;
 	crtc->vyres = vyres;
-	crtc->xoffset = xoffset;
-	crtc->yoffset = yoffset;
-	crtc->bpp = bpp;
 	crtc->h_tot_disp = h_total | (h_disp << 16);
 	crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly << 8) |
 	    ((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) |
@@ -792,8 +775,6 @@
 	var->xres_virtual = crtc->vxres;
 	var->yres_virtual = crtc->vyres;
 	var->bits_per_pixel = bpp;
-	var->xoffset = crtc->xoffset;
-	var->yoffset = crtc->yoffset;
 	var->left_margin = left;
 	var->right_margin = right;
 	var->upper_margin = upper;
@@ -808,14 +789,14 @@
 
 /* ------------------------------------------------------------------------- */
 
-static void atyfb_set_par(struct atyfb_par *par,
-			  struct fb_info *info)
+static int atyfb_set_par(struct fb_info *info)
 {
-	u32 i;
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	int accelmode;
 	u8 tmp;
+	u32 i;
 
-	accelmode = par->accel_flags;	/* hack */
+	accelmode = info->var.accel_flags;	/* hack */
 
 	if (par->blitter_may_be_busy)
 		wait_for_idle(par);
@@ -825,13 +806,13 @@
 	/* better call aty_StrobeClock ?? */
 	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, CLOCK_STROBE, par);
 
-	par->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode);
+	par->dac_ops->set_dac(info, &par->pll, info->var.bits_per_pixel, accelmode);
 	par->pll_ops->set_pll(info, &par->pll);
 
 	if (!M64_HAS(INTEGRATED)) {
 		/* Don't forget MEM_CNTL */
 		i = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;
-		switch (par->crtc.bpp) {
+		switch (info->var.bits_per_pixel) {
 		case 8:
 			i |= 0x02000000;
 			break;
@@ -847,7 +828,7 @@
 		i = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;
 		if (!M64_HAS(MAGIC_POSTDIV))
 			i |= par->mem_refresh_rate << 20;
-		switch (par->crtc.bpp) {
+		switch (info->var.bits_per_pixel) {
 		case 8:
 		case 24:
 			i |= 0x00000000;
@@ -880,8 +861,11 @@
 	}
 	aty_st_8(DAC_MASK, 0xff, par);
 
+	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel/8;
+	info->fix.visual = info->var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
 	/* Initialize the graphics engine */
-	if (par->accel_flags & FB_ACCELF_TEXT)
+	if (info->var.accel_flags & FB_ACCELF_TEXT)
 		aty_init_engine(par, info);
 
 #ifdef CONFIG_BOOTX_TEXT
@@ -889,33 +873,29 @@
 			     (((par->crtc.h_tot_disp >> 16) & 0xff) +
 			      1) * 8,
 			     ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,
-			     par->crtc.bpp,
-			     par->crtc.vxres * par->crtc.bpp / 8);
+			     info->var.bits_per_pixel,
+			     par->crtc.vxres * info->var.bits_per_pixel / 8);
 #endif				/* CONFIG_BOOTX_TEXT */
+	return 0;
 }
 
-static int atyfb_decode_var(const struct fb_var_screeninfo *var,
-			    struct atyfb_par *par,
-			    const struct fb_info *info)
+static int atyfb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
 {
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	int err;
 
 	if ((err = aty_var_to_crtc(info, var, &par->crtc)) ||
 	    (err =
-	     par->pll_ops->var_to_pll(info, var->pixclock, par->crtc.bpp,
+	     par->pll_ops->var_to_pll(info, var->pixclock, var->bits_per_pixel,
 				       &par->pll)))
 		return err;
 
-	if (var->accel_flags & FB_ACCELF_TEXT)
-		par->accel_flags = FB_ACCELF_TEXT;
-	else
-		par->accel_flags = 0;
-
 #if 0				/* fbmon is not done. uncomment for 2.5.x -brad */
 	if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
 		return -EINVAL;
 #endif
-
+	atyfb_encode_var(var, par, info);
 	return 0;
 }
 
@@ -933,8 +913,6 @@
 
 	var->height = -1;
 	var->width = -1;
-	var->accel_flags = par->accel_flags;
-
 	return 0;
 }
 
@@ -943,10 +921,10 @@
 static void set_off_pitch(struct atyfb_par *par,
 			  const struct fb_info *info)
 {
-	u32 xoffset = par->crtc.xoffset;
-	u32 yoffset = par->crtc.yoffset;
+	u32 xoffset = info->var.xoffset;
+	u32 yoffset = info->var.yoffset;
 	u32 vxres = par->crtc.vxres;
-	u32 bpp = par->crtc.bpp;
+	u32 bpp = info->var.bits_per_pixel;
 
 	par->crtc.off_pitch =
 	    ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
@@ -1024,7 +1002,7 @@
 						var.yres_virtual =
 						    var.yres;
 				}
-				atyfb_set_var(&var, -1, info);
+				gen_set_var(&var, -1, info);
 			}
 		}
 	} else {
@@ -1034,167 +1012,6 @@
 	return (0);
 }
 
-
-static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par,
-		      const struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-	strcpy(fix->id, atyfb_name);
-	fix->smem_start = info->fix.smem_start;
-	fix->smem_len = info->fix.smem_len;
-	fix->mmio_start = info->fix.mmio_start;
-	fix->mmio_len = info->fix.mmio_len;
-	fix->accel = info->fix.accel;
-	fix->type = info->fix.type;
-	fix->type_aux = info->fix.type_aux;
-	fix->line_length = par->crtc.vxres * par->crtc.bpp / 8;
-	fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
-	    : FB_VISUAL_DIRECTCOLOR;
-	fix->ywrapstep = info->fix.ywrapstep;
-	fix->xpanstep = info->fix.xpanstep;
-	fix->ypanstep = info->fix.ypanstep;
-	return 0;
-}
-
-    /*
-     *  Get the Fixed Part of the Display
-     */
-
-static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
-{
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
-
-	atyfb_decode_var(&fb_display[con].var, par, info);
-	encode_fix(fix, par, info);
-	return 0;
-}
-
-
-    /*
-     *  Get the User Defined Part of the Display
-     */
-
-static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
-
-	if (con == -1)
-		atyfb_encode_var(var, par, info);
-	else
-		*var = fb_display[con].var;
-	return 0;
-}
-
-
-static void atyfb_set_dispsw(struct display *disp,
-			     struct fb_info *info)
-{
-	switch (info->var.bits_per_pixel) {
-	case 8:
-		disp->dispsw = &fbcon_aty8;
-		break;
-	case 16:
-		disp->dispsw = &fbcon_aty16;
-		disp->dispsw_data = info->pseudo_palette;
-		break;
-	case 24:
-		disp->dispsw = &fbcon_aty24;
-		disp->dispsw_data = info->pseudo_palette;
-		break;
-	case 32:
-		disp->dispsw = &fbcon_aty32;
-		disp->dispsw_data = info->pseudo_palette;
-		break;
-	default:
-		disp->dispsw = &fbcon_dummy;
-	}
-#ifdef CONFIG_FB_ATY_CT
-/*
-	if (info->cursor) {
-		&disp->dispsw.cursor = atyfb_cursor;
-		&disp->dispsw.set_font = atyfb_set_font;
-	}
-*/
-#endif			/* CONFIG_FB_ATY_CT */
-}
-
-
-    /*
-     *  Set the User Defined Part of the Display
-     */
-
-static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
-	struct display *display;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel,
-	    err;
-	int activate = var->activate;
-
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = info->disp;	/* used during initialization */
-
-	if ((err = atyfb_decode_var(var, par, info)))
-		return err;
-
-	atyfb_encode_var(var, par, info);
-
-	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = display->var.xres;
-		oldyres = display->var.yres;
-		oldvxres = display->var.xres_virtual;
-		oldvyres = display->var.yres_virtual;
-		oldbpp = display->var.bits_per_pixel;
-		oldaccel = display->var.accel_flags;
-		display->var = *var;
-		accel = var->accel_flags & FB_ACCELF_TEXT;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual
-		    || oldvyres != var->yres_virtual
-		    || oldbpp != var->bits_per_pixel
-		    || oldaccel != var->accel_flags) {
-			struct fb_fix_screeninfo fix;
-
-			encode_fix(&fix, par, info);
-			display->visual = fix.visual;
-			display->type = fix.type;
-			display->type_aux = fix.type_aux;
-			display->ypanstep = fix.ypanstep;
-			display->ywrapstep = fix.ywrapstep;
-			display->line_length = fix.line_length;
-			display->can_soft_blank = 1;
-			display->inverse = 0;
-			if (accel)
-				display->scrollmode =
-				    (par->bus_type ==
-				     PCI) ? SCROLL_YNOMOVE : 0;
-			else
-				display->scrollmode = SCROLL_YREDRAW;
-			if (info->changevar)
-				(*info->changevar) (con);
-		}
-		if (!info->display_fg ||
-		    info->display_fg->vc_num == con) {
-			atyfb_set_par(par, info);
-			atyfb_set_dispsw(display, info);
-		}
-		if (oldbpp != var->bits_per_pixel) {
-			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-				return err;
-			do_install_cmap(con, info);
-		}
-	}
-	return 0;
-}
-
-
     /*
      *  Pan or Wrap the Display
      *
@@ -1214,8 +1031,8 @@
 	if (xoffset + xres > par->crtc.vxres
 	    || yoffset + yres > par->crtc.vyres)
 		return -EINVAL;
-	par->crtc.xoffset = xoffset;
-	par->crtc.yoffset = yoffset;
+	info->var.xoffset = xoffset;
+	info->var.yoffset = yoffset;
 	set_off_pitch(par, info);
 	return 0;
 }
@@ -1250,12 +1067,6 @@
 #endif				/* __sparc__ || DEBUG */
 #ifdef __sparc__
 	struct fbtype fbtyp;
-	struct display *disp;
-
-	if (con >= 0)
-		disp = &fb_display[con];
-	else
-		disp = info2->disp;
 #endif
 
 	switch (cmd) {
@@ -1264,8 +1075,8 @@
 		fbtyp.fb_type = FBTYPE_PCI_GENERIC;
 		fbtyp.fb_width = par->crtc.vxres;
 		fbtyp.fb_height = par->crtc.vyres;
-		fbtyp.fb_depth = par->crtc.bpp;
-		fbtyp.fb_cmsize = disp->cmap.len;
+		fbtyp.fb_depth = info->var.bits_per_pixel;
+		fbtyp.fb_cmsize = info->cmap.len;
 		fbtyp.fb_size = info->fix.smem_len;
 		if (copy_to_user
 		    ((struct fbtype *) arg, &fbtyp, sizeof(fbtyp)))
@@ -1439,16 +1250,16 @@
 	u8 b[2][256];
 } atyfb_save;
 
-static void atyfb_save_palette(struct fb_info *info, int enter)
+static void atyfb_save_palette(struct atyfb_par *par, int enter)
 {
 	int i, tmp;
 
 	for (i = 0; i < 256; i++) {
-		tmp = aty_ld_8(DAC_CNTL, info) & 0xfc;
+		tmp = aty_ld_8(DAC_CNTL, par) & 0xfc;
 		if (M64_HAS(EXTRA_BRIGHT))
 			tmp |= 0x2;
-		aty_st_8(DAC_CNTL, tmp, info);
-		aty_st_8(DAC_MASK, 0xff, info);
+		aty_st_8(DAC_CNTL, tmp, par);
+		aty_st_8(DAC_MASK, 0xff, par);
 
 		writeb(i, &par->aty_cmap_regs->rindex);
 		atyfb_save.r[enter][i] = readb(&par->aty_cmap_regs->lut);
@@ -1477,15 +1288,16 @@
 		    d->fb_info->fbops == &atyfb_ops &&
 		    d->fb_info->display_fg &&
 		    d->fb_info->display_fg->vc_num == i) {
-			atyfb_save_palette(d->fb_info, enter);
 			info = d->fb_info;
 			par = (struct atyfb_par *) info->par;
+			
+			atyfb_save_palette(par, enter);
 			if (enter) {
-				atyfb_save.yoffset = par->crtc.yoffset;
-				par->crtc.yoffset = 0;
+				atyfb_save.yoffset = info->var.yoffset;
+				info->var.yoffset = 0;
 				set_off_pitch(par, info);
 			} else {
-				par->crtc.yoffset = atyfb_save.yoffset;
+				info->var.yoffset = atyfb_save.yoffset;
 				set_off_pitch(par, info);
 			}
 			break;
@@ -1506,32 +1318,32 @@
  * management registers. There's is some confusion about which
  * chipID is a Rage LT or LT pro :(
  */
-static int aty_power_mgmt_LT(int sleep, struct fb_info *info)
+static int aty_power_mgmt_LT(int sleep, struct atyfb_par *par)
 {
 	unsigned int pm;
 	int timeout;
 
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
-	aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 
 	timeout = 200000;
 	if (sleep) {
 		/* Sleep */
 		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 		udelay(10);
 		pm &= ~(PWR_BLON | AUTO_PWR_UP);
 		pm |= SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 		udelay(10);
 		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
 		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 			udelay(10);
 			if ((--timeout) == 0)
 				break;
@@ -1540,18 +1352,18 @@
 	} else {
 		/* Wakeup */
 		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 		udelay(10);
 		pm |= (PWR_BLON | AUTO_PWR_UP);
 		pm &= ~SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 		udelay(10);
 		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
 		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
 			udelay(10);
 			if ((--timeout) == 0)
 				break;
@@ -1562,32 +1374,32 @@
 	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
 }
 
-static int aty_power_mgmt_LTPro(int sleep, struct fb_info *info)
+static int aty_power_mgmt_LTPro(int sleep, struct atyfb_par *par)
 {
 	unsigned int pm;
 	int timeout;
 
-	pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
-	aty_st_lcd(POWER_MANAGEMENT, pm, info);
-	pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+	aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 
 	timeout = 200;
 	if (sleep) {
 		/* Sleep */
 		pm &= ~PWR_MGT_ON;
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 		udelay(10);
 		pm &= ~(PWR_BLON | AUTO_PWR_UP);
 		pm |= SUSPEND_NOW;
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 		udelay(10);
 		pm |= PWR_MGT_ON;
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
 		do {
-			pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+			pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 			mdelay(1);
 			if ((--timeout) == 0)
 				break;
@@ -1596,18 +1408,18 @@
 	} else {
 		/* Wakeup */
 		pm &= ~PWR_MGT_ON;
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 		udelay(10);
 		pm &= ~SUSPEND_NOW;
 		pm |= (PWR_BLON | AUTO_PWR_UP);
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 		udelay(10);
 		pm |= PWR_MGT_ON;
-		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
 		do {
-			pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+			pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 			mdelay(1);
 			if ((--timeout) == 0)
 				break;
@@ -1617,10 +1429,10 @@
 	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
 }
 
-static int aty_power_mgmt(int sleep, struct fb_info *info)
+static int aty_power_mgmt(int sleep, struct atyfb_par *par)
 {
-	return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, info)
-	    : aty_power_mgmt_LTPro(sleep, info);
+	return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, par)
+	    : aty_power_mgmt_LTPro(sleep, par);
 }
 
 /*
@@ -1635,12 +1447,11 @@
 
 	result = PBOOK_SLEEP_OK;
 
-	for (info = first_display; info != NULL; info = info->next) {
+	for (info = first_display; info != NULL; info = par->next) {
 		struct fb_fix_screeninfo fix;
 		int nb;
 
-		atyfb_get_fix(&fix, fg_console, info);
-		nb = fb_display[fg_console].var.yres * fix.line_length;
+		nb = fb_display[fg_console].var.yres * info->fix.line_length;
 
 		switch (when) {
 		case PBOOK_SLEEP_REQUEST:
@@ -1659,7 +1470,7 @@
 				wait_for_idle(par);
 			/* Stop accel engine (stop bus mastering) */
 			if (par->accel_flags & FB_ACCELF_TEXT)
-				aty_reset_engine(info);
+				aty_reset_engine(par);
 
 			/* Backup fb content */
 			if (par->save_framebuffer)
@@ -1670,11 +1481,11 @@
 			atyfb_blank(VESA_POWERDOWN + 1, info);
 
 			/* Set chip to "suspend" mode */
-			result = aty_power_mgmt(1, info);
+			result = aty_power_mgmt(1, par);
 			break;
 		case PBOOK_WAKE:
 			/* Wakeup chip */
-			result = aty_power_mgmt(0, info);
+			result = aty_power_mgmt(0, par);
 
 			/* Restore fb content */
 			if (par->save_framebuffer) {
@@ -1684,7 +1495,7 @@
 				par->save_framebuffer = 0;
 			}
 			/* Restore display */
-			atyfb_set_par(par->par, info);
+			atyfb_set_par(info);
 			atyfb_blank(0, info);
 			break;
 		}
@@ -1711,7 +1522,8 @@
 static int aty_set_backlight_enable(int on, int level, void *data)
 {
 	struct fb_info *info = (struct fb_info *) data;
-	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info);
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
 
 	reg |= (BLMOD_EN | BIASMOD_EN);
 	if (on && level > BACKLIGHT_OFF) {
@@ -1721,8 +1533,7 @@
 		reg &= ~BIAS_MOD_LEVEL_MASK;
 		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
 	}
-	aty_st_lcd(LCD_MISC_CNTL, reg, info);
-
+	aty_st_lcd(LCD_MISC_CNTL, reg, par);
 	return 0;
 }
 
@@ -1784,7 +1595,7 @@
 	if (!M64_HAS(INTEGRATED)) {
 		u32 stat0;
 		u8 dac_type, dac_subtype, clk_type;
-		stat0 = aty_ld_le32(CONFIG_STAT0, info);
+		stat0 = aty_ld_le32(CONFIG_STAT0, par);
 		par->bus_type = (stat0 >> 0) & 0x07;
 		par->ram_type = (stat0 >> 3) & 0x07;
 		ramname = aty_gx_ram[par->ram_type];
@@ -2034,7 +1845,7 @@
 
 	disp = info->disp;
 
-	strcpy(info->modename, atyfb_name);
+	strcpy(info->modename, info->fix.id);
 	info->node = NODEV;
 	info->fbops = &atyfb_ops;
 	info->disp = disp;
@@ -2043,7 +1854,7 @@
 	strcpy(info->fontname, fontname);
 	info->changevar = NULL;
 	info->switch_con = gen_switch;
-	info->updatevar = &atyfbcon_updatevar;
+	info->updatevar = gen_update_var;
 	info->flags = FBINFO_FLAG_DEFAULT;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
@@ -2093,7 +1904,7 @@
 					default_vmode = VMODE_800_600_60;
 				else
 					default_vmode = VMODE_640_480_67;
-				sense = read_aty_sense(info);
+				sense = read_aty_sense(par);
 				printk(KERN_INFO
 				       "atyfb: monitor sense=%x, mode %d\n",
 				       sense,
@@ -2145,12 +1956,12 @@
 			var.yres_virtual = var.yres;
 	}
 
-	if (atyfb_decode_var(&var, par, info)) {
+	if (atyfb_check_var(&var, info)) {
 		printk("atyfb: can't set default video mode\n");
 		return 0;
 	}
 #ifdef __sparc__
-	atyfb_save_palette(info, 0);
+	atyfb_save_palette(par, 0);
 #endif
 
 #ifdef CONFIG_FB_ATY_CT
@@ -2168,7 +1979,7 @@
 
 	fb_alloc_cmap(&info->cmap, 256, 0);
 
-	atyfb_set_var(&var, -1, info);
+	gen_set_var(&var, -1, info);
 
 	if (register_framebuffer(info) < 0)
 		return 0;
@@ -2176,16 +1987,17 @@
 	fb_list = info;
 
 	printk("fb%d: %s frame buffer device on %s\n",
-	       GET_FB_IDX(info->node), atyfb_name, name);
+	       GET_FB_IDX(info->node), info->fix.id, name);
 	return 1;
 }
 
 int __init atyfb_init(void)
 {
 #if defined(CONFIG_PCI)
+	unsigned long addr, res_start, res_size;
+	struct atyfb_par *default_par;
 	struct pci_dev *pdev = NULL;
 	struct fb_info *info;
-	unsigned long addr, res_start, res_size;
 	int i;
 #ifdef __sparc__
 	extern void (*prom_palette) (int);
@@ -2201,7 +2013,6 @@
 #else
 	u16 tmp;
 #endif
-	struct atyfb_par *default_par;
 
 	while ((pdev =
 		pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
@@ -2239,6 +2050,7 @@
 			memset(default_par, 0, sizeof(struct atyfb_par));
 
 			info->disp = (struct display *) (info + 1);
+			info->fix = atyfb_fix;
 			info->par = default_par;
 
 			rp = &pdev->resource[0];
@@ -2258,14 +2070,13 @@
 			/*
 			 * Map memory-mapped registers.
 			 */
-			par->ati_regbase = addr + 0x7ffc00UL;
+			default_par->ati_regbase = addr + 0x7ffc00UL;
 			info->fix.mmio_start = addr + 0x7ffc00UL;
 
 			/*
 			 * Map in big-endian aperture.
 			 */
-			info->screen_base =
-			    (unsigned long) addr + 0x800000UL;
+			info->screen_base = (char *) (addr + 0x800000UL);
 			info->fix.smem_start = addr + 0x800000UL;
 
 			/*
@@ -2361,11 +2172,9 @@
 				/*
 				 * Fix PROMs idea of MEM_CNTL settings...
 				 */
-				mem = aty_ld_le32(MEM_CNTL, info);
-				chip_id =
-				    aty_ld_le32(CONFIG_CHIP_ID, info);
-				if (((chip_id & CFG_CHIP_TYPE) ==
-				     VT_CHIP_ID)
+				mem = aty_ld_le32(MEM_CNTL, default_par);
+				chip_id = aty_ld_le32(CONFIG_CHIP_ID, default_par);
+				if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID)
 				    && !((chip_id >> 24) & 1)) {
 					switch (mem & 0x0f) {
 					case 3:
@@ -2383,13 +2192,11 @@
 					default:
 						break;
 					}
-					if ((aty_ld_le32
-					     (CONFIG_STAT0,
-					      info) & 7) >= SDRAM)
+					if ((aty_ld_le32(CONFIG_STAT0, default_par) & 7) >= SDRAM)
 						mem &= ~(0x00700000);
 				}
 				mem &= ~(0xcf80e000);	/* Turn off all undocumented bits. */
-				aty_st_le32(MEM_CNTL, mem, info);
+				aty_st_le32(MEM_CNTL, mem, default_par);
 			}
 
 			/*
@@ -2427,21 +2234,21 @@
 				crtc.vyres =
 				    prom_getintdefault(node, "height",
 						       768);
-				crtc.bpp =
+				var->bits_per_pixel =
 				    prom_getintdefault(node, "depth", 8);
-				crtc.xoffset = crtc.yoffset = 0;
+				var->xoffset = var->yoffset = 0;
 				crtc.h_tot_disp =
-				    aty_ld_le32(CRTC_H_TOTAL_DISP, info);
+				    aty_ld_le32(CRTC_H_TOTAL_DISP, default_par);
 				crtc.h_sync_strt_wid =
 				    aty_ld_le32(CRTC_H_SYNC_STRT_WID,
-						info);
+						default_par);
 				crtc.v_tot_disp =
-				    aty_ld_le32(CRTC_V_TOTAL_DISP, info);
+				    aty_ld_le32(CRTC_V_TOTAL_DISP, default_par);
 				crtc.v_sync_strt_wid =
 				    aty_ld_le32(CRTC_V_SYNC_STRT_WID,
-						info);
+						default_par);
 				crtc.gen_cntl =
-				    aty_ld_le32(CRTC_GEN_CNTL, info);
+				    aty_ld_le32(CRTC_GEN_CNTL, default_par);
 				aty_crtc_to_var(&crtc, var);
 
 				h_total = var->xres + var->right_margin +
@@ -2452,10 +2259,10 @@
 				/*
 				 * Read the PLL to figure actual Refresh Rate.
 				 */
-				clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+				clock_cntl = aty_ld_8(CLOCK_CNTL, default_par);
 				/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
 				for (i = 0; i < 16; i++)
-					pll_regs[i] = aty_ld_pll(i, info);
+					pll_regs[i] = aty_ld_pll(i, default_par);
 
 				/*
 				 * PLL Reference Divider M:
@@ -2555,21 +2362,21 @@
 			/*
 			 * Add /dev/fb mmap values.
 			 */
-			par->mmap_map[0].voff = 0x8000000000000000UL;
-			par->mmap_map[0].poff =
-			    info->screen_base & PAGE_MASK;
-			par->mmap_map[0].size =
+			default_par->mmap_map[0].voff = 0x8000000000000000UL;
+			default_par->mmap_map[0].poff =
+			    (unsigned long) info->screen_base & PAGE_MASK;
+			default_par->mmap_map[0].size =
 			    info->fix.smem_len;
-			par->mmap_map[0].prot_mask = _PAGE_CACHE;
-			par->mmap_map[0].prot_flag = _PAGE_E;
-			par->mmap_map[1].voff =
-			    par->mmap_map[0].voff +
+			default_par->mmap_map[0].prot_mask = _PAGE_CACHE;
+			default_par->mmap_map[0].prot_flag = _PAGE_E;
+			default_par->mmap_map[1].voff =
+			    default_par->mmap_map[0].voff +
 			    info->fix.smem_len;
-			par->mmap_map[1].poff =
-			    par->ati_regbase & PAGE_MASK;
-			par->mmap_map[1].size = PAGE_SIZE;
-			par->mmap_map[1].prot_mask = _PAGE_CACHE;
-			par->mmap_map[1].prot_flag = _PAGE_E;
+			default_par->mmap_map[1].poff =
+			    default_par->ati_regbase & PAGE_MASK;
+			default_par->mmap_map[1].size = PAGE_SIZE;
+			default_par->mmap_map[1].prot_mask = _PAGE_CACHE;
+			default_par->mmap_map[1].prot_flag = _PAGE_E;
 #endif				/* __sparc__ */
 
 #ifdef CONFIG_PMAC_PBOOK
@@ -2577,15 +2384,16 @@
 				pmu_register_sleep_notifier
 				    (&aty_sleep_notifier);
 			/* FIXME info->next = first_display; */
-			first_display = info;
+			default_par->next = first_display;
 #endif
 		}
 	}
 
 #elif defined(CONFIG_ATARI)
-	u32 clock_r;
-	int m64_num;
+	struct atyfb_par *default_par;
 	struct fb_info *info;
+	int m64_num;
+	u32 clock_r;
 
 	for (m64_num = 0; m64_num < mach64_count; m64_num++) {
 		if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
@@ -2602,6 +2410,7 @@
 			return -ENOMEM;
 		}
 		memset(info, 0, sizeof(struct fb_info));
+		info->fix = atyfb_fix;		
 
 		/*
 		 *  Map the video memory (physical address given) to somewhere in the
@@ -2610,25 +2419,25 @@
 		info->screen_base = (unsigned long)ioremap(phys_vmembase[m64_num],
 					 		   phys_size[m64_num]);	
 		info->fix.smem_start = info->screen_base;	/* Fake! */
-		par->ati_regbase = (unsigned long)ioremap(phys_guiregbase[m64_num],
+		default_par->ati_regbase = (unsigned long)ioremap(phys_guiregbase[m64_num],
 							  0x10000) + 0xFC00ul;
 		info->fix.mmio_start = par->ati_regbase; /* Fake! */
 
-		aty_st_le32(CLOCK_CNTL, 0x12345678, info);
-		clock_r = aty_ld_le32(CLOCK_CNTL, info);
+		aty_st_le32(CLOCK_CNTL, 0x12345678, default_par);
+		clock_r = aty_ld_le32(CLOCK_CNTL, default_par);
 
 		switch (clock_r & 0x003F) {
 		case 0x12:
-			par->clk_wr_offset = 3;	/*  */
+			default_par->clk_wr_offset = 3;	/*  */
 			break;
 		case 0x34:
-			par->clk_wr_offset = 2;	/* Medusa ST-IO ISA Adapter etc. */
+			default_par->clk_wr_offset = 2;	/* Medusa ST-IO ISA Adapter etc. */
 			break;
 		case 0x16:
-			par->clk_wr_offset = 1;	/*  */
+			default_par->clk_wr_offset = 1;	/*  */
 			break;
 		case 0x38:
-			par->clk_wr_offset = 0;	/* Panther 1 ISA Adapter (Gerald) */
+			default_par->clk_wr_offset = 0;	/* Panther 1 ISA Adapter (Gerald) */
 			break;
 		}
 
@@ -2831,7 +2640,7 @@
 		i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt */
 	aty_st_8(DAC_CNTL, i, par);
 	aty_st_8(DAC_MASK, 0xff, par);
-	scale = (M64_HAS(INTEGRATED) && par->crtc.bpp == 16) ? 3 : 0;
+	scale = (M64_HAS(INTEGRATED) && info->var.bits_per_pixel == 16) ? 3 : 0;
 #ifdef CONFIG_ATARI
 	out_8(&par->aty_cmap_regs->windex, regno << scale);
 	out_8(&par->aty_cmap_regs->lut, red);
@@ -2844,7 +2653,7 @@
 	writeb(blue, &par->aty_cmap_regs->lut);
 #endif
 	if (regno < 16)
-		switch (par->crtc.bpp) {
+		switch (info->var.bits_per_pixel) {
 		case 16:
 			((u16 *) (info->pseudo_palette))[regno] =
 			    (regno << 10) | (regno << 5) | regno;
@@ -2861,52 +2670,6 @@
 		}
 	return 0;
 }
-
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
-
-static int atyfbcon_updatevar(int con, struct fb_info *info)
-{
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
-	struct display *p = &fb_display[con];
-	struct vc_data *conp = p->conp;
-	u32 yres, yoffset, sy, height;
-
-	yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
-	yoffset = fb_display[con].var.yoffset;
-
-	sy = (conp->vc_rows + p->yscroll) * fontheight(p);
-	height = yres - conp->vc_rows * fontheight(p);
-
-	if (height && (yoffset + yres > sy)) {
-		struct fb_fillrect area;
-
-		area.dx = fb_display[con].var.xoffset;
-		area.dy = sy;
-		area.height = height;
-		area.width = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
-		area.color = attr_bgcol_ec(p, conp);
-		area.rop = ROP_COPY;
-
-		if (sy + height > par->crtc.vyres) {
-			wait_for_fifo(1, par);
-			aty_st_le32(SC_BOTTOM, sy + height - 1, par);
-		}
-		atyfb_fillrect(info, &area);
-	}
-#ifdef CONFIG_FB_ATY_CT
-	if (par->cursor && (yoffset + yres <= sy))
-		atyfb_cursor(p, CM_ERASE, par->cursor->pos.x,
-			     par->cursor->pos.y);
-#endif				/* CONFIG_FB_ATY_CT */
-
-	par->crtc.yoffset = yoffset;
-	set_off_pitch(par, info);
-	return 0;
-}
-
-
 
 #ifdef MODULE
 int __init init_module(void)
diff -Nru a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
--- a/drivers/video/aty/mach64_accel.c	Tue Aug 27 12:27:45 2002
+++ b/drivers/video/aty/mach64_accel.c	Tue Aug 27 12:27:45 2002
@@ -6,27 +6,10 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
 #include <video/mach64.h>
 #include "atyfb.h"
 
     /*
-     *  Text console acceleration
-     */
-
-static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy,
-			    int dx, int height, int width);
-static void fbcon_aty_clear(struct vc_data *conp, struct display *p,
-			    int sy, int sx, int height, int width);
-
-
-    /*
      *  Generic Mach64 routines
      */
 
@@ -63,9 +46,9 @@
 	u32 pitch_value;
 
 	/* determine modal information from global mode structure */
-	pitch_value = par->crtc.vxres;
+	pitch_value = info->var.xres_virtual;
 
-	if (par->crtc.bpp == 24) {
+	if (info->var.bits_per_pixel == 24) {
 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
 		/* horizontal coordinates and widths must be adjusted */
 		pitch_value = pitch_value * 3;
@@ -187,7 +170,7 @@
 	par->blitter_may_be_busy = 1;
 }
 
-static void atyfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
+void atyfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	
@@ -197,8 +180,8 @@
 	if (!area->width || !area->height)
 		return;
 
-	pitch_value = par->crtc.vxres;
-	if (par->crtc.bpp == 24) {
+	pitch_value = info->var.xres_virtual;
+	if (info->var.bits_per_pixel == 24) {
 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
 		/* horizontal coordinates and widths must be adjusted */
 		pitch_value *= 3;
@@ -237,7 +220,7 @@
 	rect->color |= (rect->color << 8);
 	rect->color |= (rect->color << 16);
 
-	if (par->crtc.bpp == 24) {
+	if (info->var.bits_per_pixel == 24) {
 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
 		/* horizontal coordinates and widths must be adjusted */
 		rect->dx *= 3;
@@ -255,111 +238,11 @@
 	draw_rect(rect->dx, rect->dy, rect->width, rect->height, par);
 }
 
-    /*
-     *  Text console acceleration
-     */
-
-static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy,
-			    int dx, int height, int width)
-{
-	struct fb_info *info = p->fb_info;
-	struct fb_copyarea area;
-#ifdef __sparc__
-	struct atyfb_par *par = (struct atyfb_par *) (info->par);
-
-	if (par->mmaped && (!info->display_fg
-			   || info->display_fg->vc_num ==
-			   par->vtconsole))
-		return;
-#endif
-
-	area.sx = sx * fontwidth(p);
-	area.sy = sy * fontheight(p);
-	area.dx = dx * fontwidth(p);
-	area.dy = dy * fontheight(p);
-	area.width  = width * fontwidth(p);
-	area.height = height * fontheight(p);
-
-	atyfb_copyarea(info, &area); 
-}
-
-static void fbcon_aty_clear(struct vc_data *conp, struct display *p,
-			    int sy, int sx, int height, int width)
+void atyfb_imageblit(struct fb_info *info, struct fb_image *image)
 {
-	struct fb_info *info = p->fb_info;
-	struct fb_fillrect region;
-#ifdef __sparc__
-	struct atyfb_par *par = (struct atyfb_par *) (info->par);
-
-	if (par->mmaped && (!info->display_fg
-			   || info->display_fg->vc_num ==
-			   par->vtconsole))
-		return;
-#endif
-	region.color = attr_bgcol_ec(p, conp);
-	region.color |= (region.color << 8);
-	region.color |= (region.color << 16);
-
-	region.dx = sx * fontwidth(p);
-	region.dy = sy * fontheight(p);
-	region.width = width * fontwidth(p);
-	region.height = height * fontheight(p);
-	region.rop = ROP_COPY;
-
-	atyfb_fillrect(info, &region);
-}
-
-#ifdef __sparc__
-#define check_access \
-    if (par->mmaped && (!info->display_fg \
-	|| info->display_fg->vc_num == par->vtconsole)) \
-	return;
-#else
-#define check_access do { } while (0)
-#endif
-
-#define DEF_FBCON_ATY_OP(name, call, args...) \
-static void name(struct vc_data *conp, struct display *p, args) \
-{ \
-    struct fb_info *info = p->fb_info; \
-    struct atyfb_par *par = (struct atyfb_par *) info->par; \
-    check_access; \
-    if (par->blitter_may_be_busy) \
-	wait_for_idle(par); \
-    call; \
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+    
+	if (par->blitter_may_be_busy)
+		wait_for_idle(par);
+	cfb_imageblit(info, image);
 }
-
-#define DEF_FBCON_ATY(width) \
-    DEF_FBCON_ATY_OP(fbcon_aty##width##_putc, \
-		     fbcon_cfb##width##_putc(conp, p, c, yy, xx), \
-		     int c, int yy, int xx) \
-    DEF_FBCON_ATY_OP(fbcon_aty##width##_putcs, \
-		     fbcon_cfb##width##_putcs(conp, p, s, count, yy, xx), \
-		     const unsigned short *s, int count, int yy, int xx) \
-    DEF_FBCON_ATY_OP(fbcon_aty##width##_clear_margins, \
-		     fbcon_cfb##width##_clear_margins(conp, p, bottom_only), \
-		     int bottom_only) \
- \
-const struct display_switch fbcon_aty##width = { \
-    setup:		fbcon_cfb##width##_setup, \
-    bmove:		fbcon_aty_bmove, \
-    clear:		fbcon_aty_clear, \
-    putc:		fbcon_aty##width##_putc, \
-    putcs:		fbcon_aty##width##_putcs, \
-    revc:		fbcon_cfb##width##_revc, \
-    clear_margins:	fbcon_aty##width##_clear_margins, \
-    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) \
-};
-
-#ifdef FBCON_HAS_CFB8
-DEF_FBCON_ATY(8)
-#endif
-#ifdef FBCON_HAS_CFB16
-    DEF_FBCON_ATY(16)
-#endif
-#ifdef FBCON_HAS_CFB24
-    DEF_FBCON_ATY(24)
-#endif
-#ifdef FBCON_HAS_CFB32
-    DEF_FBCON_ATY(32)
-#endif
diff -Nru a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
--- a/drivers/video/aty/mach64_ct.c	Tue Aug 27 12:27:42 2002
+++ b/drivers/video/aty/mach64_ct.c	Tue Aug 27 12:27:42 2002
@@ -271,11 +271,11 @@
 }
 
 const struct aty_dac_ops aty_dac_ct = {
-	set_dac:(void *) dummy,
+	.set_dac	= (void *) dummy,
 };
 
 const struct aty_pll_ops aty_pll_ct = {
-	var_to_pll:aty_var_to_pll_ct,
-	pll_to_var:aty_pll_ct_to_var,
-	set_pll:aty_set_pll_ct,
+	.var_to_pll	= aty_var_to_pll_ct,
+	.pll_to_var	= aty_pll_ct_to_var,
+	.set_pll	= aty_set_pll_ct,
 };
diff -Nru a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
--- a/drivers/video/aty/mach64_cursor.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/aty/mach64_cursor.c	Tue Aug 27 12:28:08 2002
@@ -129,7 +129,7 @@
 #endif
 
 	if (on) {
-		x = c->pos.x - c->hot.x - par->crtc.xoffset;
+		x = c->pos.x - c->hot.x - info->var.xoffset;
 		if (x < 0) {
 			xoff = -x;
 			x = 0;
@@ -137,7 +137,7 @@
 			xoff = 0;
 		}
 
-		y = c->pos.y - c->hot.y - par->crtc.yoffset;
+		y = c->pos.y - c->hot.y - info->var.yoffset;
 		if (y < 0) {
 			yoff = -y;
 			y = 0;
@@ -252,7 +252,7 @@
 	cursor->offset = info->fix.smem_len;
 
 #ifdef __sparc__
-	addr = info->screen_base - 0x800000 + cursor->offset;
+	addr = (unsigned long) info->screen_base - 0x800000 + cursor->offset;
 	cursor->ram = (u8 *) addr;
 #else
 #ifdef __BIG_ENDIAN
diff -Nru a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c
--- a/drivers/video/aty/mach64_gx.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/aty/mach64_gx.c	Tue Aug 27 12:28:01 2002
@@ -191,13 +191,13 @@
 }
 
 const struct aty_dac_ops aty_dac_ibm514 = {
-	set_dac:aty_set_dac_514,
+	.set_dac	= aty_set_dac_514,
 };
 
 const struct aty_pll_ops aty_pll_ibm514 = {
-	var_to_pll:aty_var_to_pll_514,
-	pll_to_var:aty_pll_514_to_var,
-	set_pll:aty_set_pll_514,
+	.var_to_pll	= aty_var_to_pll_514,
+	.pll_to_var	= aty_pll_514_to_var,
+	.set_pll	= aty_set_pll_514,
 };
 
 
@@ -280,7 +280,7 @@
 }
 
 const struct aty_dac_ops aty_dac_ati68860b = {
-	set_dac:aty_set_dac_ATI68860_B,
+	.set_dac	= aty_set_dac_ATI68860_B,
 };
 
 
@@ -333,7 +333,7 @@
 }
 
 const struct aty_dac_ops aty_dac_att21c498 = {
-	set_dac:	aty_set_dac_ATT21C498,
+	.set_dac	= aty_set_dac_ATT21C498,
 };
 
 
@@ -487,9 +487,9 @@
 }
 
 const struct aty_pll_ops aty_pll_ati18818_1 = {
-	var_to_pll:aty_var_to_pll_18818,
-	pll_to_var:aty_pll_18818_to_var,
-	set_pll:aty_set_pll18818,
+	.var_to_pll	= aty_var_to_pll_18818,
+	.pll_to_var	= aty_pll_18818_to_var,
+	.set_pll	= aty_set_pll18818,
 };
 
 
@@ -603,9 +603,9 @@
 }
 
 const struct aty_pll_ops aty_pll_stg1703 = {
-	var_to_pll:aty_var_to_pll_1703,
-	pll_to_var:aty_pll_1703_to_var,
-	set_pll:aty_set_pll_1703,
+	.var_to_pll	= aty_var_to_pll_1703,
+	.pll_to_var	= aty_pll_1703_to_var,
+	.set_pll	= aty_set_pll_1703,
 };
 
 
@@ -727,9 +727,9 @@
 }
 
 const struct aty_pll_ops aty_pll_ch8398 = {
-	var_to_pll:aty_var_to_pll_8398,
-	pll_to_var:aty_pll_8398_to_var,
-	set_pll:aty_set_pll_8398,
+	.var_to_pll	= aty_var_to_pll_8398,
+	.pll_to_var	= aty_pll_8398_to_var,
+	.set_pll	= aty_set_pll_8398,
 };
 
 
@@ -874,9 +874,9 @@
 }
 
 const struct aty_pll_ops aty_pll_att20c408 = {
-	var_to_pll:aty_var_to_pll_408,
-	pll_to_var:aty_pll_408_to_var,
-	set_pll:aty_set_pll_408,
+	.var_to_pll	= aty_var_to_pll_408,
+	.pll_to_var	= aty_pll_408_to_var,
+	.set_pll	= aty_set_pll_408,
 };
 
 
@@ -904,11 +904,11 @@
 }
 
 const struct aty_dac_ops aty_dac_unsupported = {
-	set_dac:aty_set_dac_unsupported,
+	.set_dac	= aty_set_dac_unsupported,
 };
 
 const struct aty_pll_ops aty_pll_unsupported = {
-	var_to_pll:(void *) dummy,
-	pll_to_var:(void *) dummy,
-	set_pll:(void *) dummy,
+	.var_to_pll	= (void *) dummy,
+	.pll_to_var	= (void *) dummy,
+	.set_pll	= (void *) dummy,
 };
diff -Nru a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
--- a/drivers/video/aty128fb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/aty128fb.c	Tue Aug 27 12:28:05 2002
@@ -117,18 +117,18 @@
 /* default modedb mode */
 /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
 static struct fb_videomode defaultmode __initdata = {
-	refresh:	60,
-	xres:		640,
-	yres:		480,
-	pixclock:	39722,
-	left_margin:	48,
-	right_margin:	16,
-	upper_margin:	33,
-	lower_margin:	10,
-	hsync_len:	96,
-	vsync_len:	2,
-	sync:		0,
-	vmode:		FB_VMODE_NONINTERLACED
+	.refresh =	60,
+	.xres =		640,
+	.yres =		480,
+	.pixclock =	39722,
+	.left_margin =	48,
+	.right_margin =	16,
+	.upper_margin =	33,
+	.lower_margin =	10,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.sync =		0,
+	.vmode =	FB_VMODE_NONINTERLACED
 };
 
 /* struct to hold chip description information */
@@ -415,16 +415,16 @@
 #endif
 
 static struct fb_ops aty128fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	aty128fb_get_fix,
-	fb_get_var:	aty128fb_get_var,
-	fb_set_var:	aty128fb_set_var,
-	fb_get_cmap:	aty128fb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	aty128fb_setcolreg,
-	fb_pan_display:	aty128fb_pan_display,
-	fb_blank:	aty128fb_blank,
-	fb_rasterimg:	aty128fb_rasterimg,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	aty128fb_get_fix,
+	.fb_get_var =	aty128fb_get_var,
+	.fb_set_var =	aty128fb_set_var,
+	.fb_get_cmap =	aty128fb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	aty128fb_setcolreg,
+	.fb_pan_display =aty128fb_pan_display,
+	.fb_blank =	aty128fb_blank,
+	.fb_rasterimg =	aty128fb_rasterimg,
 };
 
 #ifdef CONFIG_PMAC_BACKLIGHT
@@ -1749,7 +1749,7 @@
     board_list = aty128_board_list_add(board_list, info);
 
     size = (var.bits_per_pixel <= 8) ? 256 : 32;
-    fb_alloc_cmap(info->fb_info.cmap, size, 0);	
+    fb_alloc_cmap(&info->fb_info.cmap, size, 0);	
 
     if (register_framebuffer(&info->fb_info) < 0)
 	return 0;
diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
--- a/drivers/video/cfbcopyarea.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/cfbcopyarea.c	Tue Aug 27 12:28:02 2002
@@ -28,6 +28,14 @@
 #include <asm/io.h>
 #include <video/fbcon.h>
 
+#if BITS_PER_LONG == 32
+#define FB_READ		fb_readl
+#define FB_WRITE	fb_writel
+#else
+#define FB_READ		fb_readq
+#define FB_WRITE	fb_writeq
+#endif
+
 void cfb_copyarea(struct fb_info *p, struct fb_copyarea *area)
 {
 	int x2, y2, lineincr, shift, shift_right, shift_left, old_dx, old_dy;
@@ -137,19 +145,19 @@
 					dst = (unsigned long *) dst1;
 					src = (unsigned long *) src1;
 
-					last = (fb_readl(src) & start_mask);
+					last = (FB_READ(src) & start_mask);
 
 					if (shift > 0)
-						fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+						FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
 					for (j = 0; j < n; j++) {
 						dst++;
-						tmp = fb_readl(src);
+						tmp = FB_READ(src);
 						src++;
-						fb_writel((last << shift_left) | (tmp >> shift_right), dst);
+						FB_WRITE((last << shift_left) | (tmp >> shift_right), dst);
 						last = tmp;
 						src++;
 					}
-					fb_writel(fb_readl(dst) | (last << shift_left), dst);
+					FB_WRITE(FB_READ(dst) | (last << shift_left), dst);
 					src1 += lineincr;
 					dst1 += lineincr;
 				} while (--height);
@@ -161,19 +169,19 @@
 					dst = (unsigned long *) dst1;
 					src = (unsigned long *) src1;
 
-					last = (fb_readl(src) & end_mask);
+					last = (FB_READ(src) & end_mask);
 
 					if (shift < 0)
-						fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+						FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
 					for (j = 0; j < n; j++) {
 						dst--;
-						tmp = fb_readl(src);
+						tmp = FB_READ(src);
 						src--;
-						fb_writel((tmp << shift_left) | (last >> shift_right), dst);
+						FB_WRITE((tmp << shift_left) | (last >> shift_right), dst);
 						last = tmp;
 						src--;
 					}
-					fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+					FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
 					src1 += lineincr;
 					dst1 += lineincr;
 				} while (--height);
@@ -187,16 +195,16 @@
 					src = (unsigned long *) (src1 - start_index);
 
 					if (start_mask)
-						fb_writel(fb_readl(src) | start_mask, dst);
+						FB_WRITE(FB_READ(src) | start_mask, dst);
 
 					for (j = 0; j < n; j++) {
-						fb_writel(fb_readl(src), dst);
+						FB_WRITE(FB_READ(src), dst);
 						dst++;
 						src++;
 					}
 
 					if (end_mask)
-						fb_writel(fb_readl(src) | end_mask, dst);
+						FB_WRITE(FB_READ(src) | end_mask, dst);
 					src1 += lineincr;
 					dst1 += lineincr;
 				} while (--height);
@@ -207,9 +215,9 @@
 					src = (unsigned long *) src1;
 
 					if (start_mask)
-						fb_writel(fb_readl(src) | start_mask, dst);
+						FB_WRITE(FB_READ(src) | start_mask, dst);
 					for (j = 0; j < n; j++) {
-						fb_writel(fb_readl(src), dst);
+						FB_WRITE(FB_READ(src), dst);
 						dst--;
 						src--;
 					}
diff -Nru a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
--- a/drivers/video/cfbfillrect.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/cfbfillrect.c	Tue Aug 27 12:28:07 2002
@@ -22,6 +22,14 @@
 #include <asm/types.h>
 #include <video/fbcon.h>
 
+#if BITS_PER_LONG == 32
+#define FB_READ		fb_readl
+#define FB_WRITE	fb_writel
+#else
+#define FB_READ		fb_readq
+#define FB_WRITE	fb_writeq
+#endif
+
 void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect)
 {
 	unsigned long start_index, end_index, start_mask = 0, end_mask = 0;
@@ -93,33 +101,19 @@
 				dst = (unsigned long *) (dst1 - start_index);
 
 				if (start_mask) {
-#if BITS_PER_LONG == 32
-					fb_writel(fb_readl(dst) |
-						  start_mask, dst);
-#else
-					fb_writeq(fb_readq(dst) |
+					FB_WRITE(FB_READ(dst) |
 						  start_mask, dst);
-#endif
 					dst++;
 				}
 
 				for (i = 0; i < n; i++) {
-#if BITS_PER_LONG == 32
-					fb_writel(fg, dst);
-#else
-					fb_writeq(fg, dst);
-#endif
+					FB_WRITE(fg, dst);
 					dst++;
 				}
 
 				if (end_mask)
-#if BITS_PER_LONG == 32
-					fb_writel(fb_readl(dst) | end_mask,
-						  dst);
-#else
-					fb_writeq(fb_readq(dst) | end_mask,
+					FB_WRITE(FB_READ(dst) | end_mask,
 						  dst);
-#endif
 				dst1 += linesize;
 			} while (--height);
 			break;
@@ -128,33 +122,19 @@
 				dst = (unsigned long *) (dst1 - start_index);
 
 				if (start_mask) {
-#if BITS_PER_LONG == 32
-					fb_writel(fb_readl(dst) ^
+					FB_WRITE(FB_READ(dst) ^
 						  start_mask, dst);
-#else
-					fb_writeq(fb_readq(dst) ^
-						  start_mask, dst);
-#endif
 					dst++;
 				}
 
 				for (i = 0; i < n; i++) {
-#if BITS_PER_LONG == 32
-					fb_writel(fb_readl(dst) ^ fg, dst);
-#else
-					fb_writeq(fb_readq(dst) ^ fg, dst);
-#endif
+					FB_WRITE(FB_READ(dst) ^ fg, dst);
 					dst++;
 				}
 
 				if (end_mask) {
-#if BITS_PER_LONG == 32
-					fb_writel(fb_readl(dst) ^ end_mask,
+					FB_WRITE(FB_READ(dst) ^ end_mask,
 						  dst);
-#else
-					fb_writeq(fb_readq(dst) ^ end_mask,
-						  dst);
-#endif
 				}
 				dst1 += linesize;
 			} while (--height);
diff -Nru a/drivers/video/cgfourteenfb.c b/drivers/video/cgfourteenfb.c
--- a/drivers/video/cgfourteenfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/cgfourteenfb.c	Tue Aug 27 12:28:02 2002
@@ -203,7 +203,7 @@
 			  int x_margin, int y_margin)
 {
 	fb->info.screen_base += (y_margin - fb->y_margin) *
-		p->line_length + (x_margin - fb->x_margin);
+		fb->info.fix.line_length + (x_margin - fb->x_margin);
 }
 
 static void cg14_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
diff -Nru a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c
--- a/drivers/video/cgsixfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/cgsixfb.c	Tue Aug 27 12:28:02 2002
@@ -521,13 +521,13 @@
 }
 
 static struct display_switch cg6_dispsw __initdata = {
-	setup:		cg6_setup,
-	bmove:		fbcon_redraw_bmove,
-	clear:		cg6_clear,
-	putc:		cg6_putc,
-	putcs:		cg6_putcs,
-	revc:		cg6_revc, 
-	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
+	.setup =	cg6_setup,
+	.bmove =	fbcon_redraw_bmove,
+	.clear =	cg6_clear,
+	.putc =		cg6_putc,
+	.putcs =	cg6_putcs,
+	.revc =		cg6_revc, 
+	.fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
 };
 
 static void cg6_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
@@ -673,7 +673,7 @@
 static void cg6_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
 {
 	fb->info.screen_base += (y_margin - fb->y_margin) *
-		p->line_length + (x_margin - fb->x_margin);
+		fb->info.fix.line_length + (x_margin - fb->x_margin);
 }
 
 static int __init cg6_rasterimg (struct fb_info *info, int start)
diff -Nru a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c
--- a/drivers/video/cgthreefb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/cgthreefb.c	Tue Aug 27 12:28:08 2002
@@ -140,7 +140,7 @@
 			 int x_margin, int y_margin)
 {
 	fb->info.screen_base += (y_margin - fb->y_margin) *
-		p->line_length + (x_margin - fb->x_margin);
+		fb->info.fix.line_length + (x_margin - fb->x_margin);
 }
 
 static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
diff -Nru a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
--- a/drivers/video/chipsfb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/chipsfb.c	Tue Aug 27 12:28:05 2002
@@ -126,14 +126,14 @@
 static int chipsfb_blank(int blank, struct fb_info *info);
 
 static struct fb_ops chipsfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	chips_get_fix,
-	fb_get_var:	chips_get_var,
-	fb_set_var:	chips_set_var,
-	fb_get_cmap:	chips_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	chipsfb_setcolreg,
-	fb_blank:	chipsfb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	chips_get_fix,
+	.fb_get_var =	chips_get_var,
+	.fb_set_var =	chips_set_var,
+	.fb_get_cmap =	chips_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	chipsfb_setcolreg,
+	.fb_blank =	chipsfb_blank,
 };
 
 static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green,
diff -Nru a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c
--- a/drivers/video/clgenfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/clgenfb.c	Tue Aug 27 12:28:02 2002
@@ -498,17 +498,17 @@
 
 /* function table of the above functions */
 static struct fb_ops clgenfb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	clgenfb_open,
-	fb_release:	clgenfb_release,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	clgenfb_setcolreg,
-	fb_pan_display:	fbgen_pan_display,
-	fb_blank:	fbgen_blank,
+	.owner =	THIS_MODULE,
+	.fb_open =	clgenfb_open,
+	.fb_release =	clgenfb_release,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	clgenfb_setcolreg,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_blank =	fbgen_blank,
 };
 
 /*--- Hardware Specific Routines -------------------------------------------*/
@@ -555,14 +555,14 @@
 				int sy, int sx, int height, int width);
 
 static struct display_switch fbcon_clgen_8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		fbcon_clgen8_bmove,
-	clear:		fbcon_clgen8_clear,
-	putc:		fbcon_cfb8_putc,
-	putcs:		fbcon_cfb8_putcs,
-	revc:		fbcon_cfb8_revc,
-	clear_margins:	fbcon_cfb8_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	fbcon_clgen8_bmove,
+	.clear =	fbcon_clgen8_clear,
+	.putc =		fbcon_cfb8_putc,
+	.putcs =	fbcon_cfb8_putcs,
+	.revc =		fbcon_cfb8_revc,
+	.clear_margins =fbcon_cfb8_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
@@ -571,14 +571,14 @@
 static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
 				 int sy, int sx, int height, int width);
 static struct display_switch fbcon_clgen_16 = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		fbcon_clgen16_bmove,
-	clear:		fbcon_clgen16_clear,
-	putc:		fbcon_cfb16_putc,
-	putcs:		fbcon_cfb16_putcs,
-	revc:		fbcon_cfb16_revc,
-	clear_margins:	fbcon_cfb16_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb16_setup,
+	.bmove =	fbcon_clgen16_bmove,
+	.clear =	fbcon_clgen16_clear,
+	.putc =		fbcon_cfb16_putc,
+	.putcs =	fbcon_cfb16_putcs,
+	.revc =		fbcon_cfb16_revc,
+	.clear_margins =fbcon_cfb16_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -587,14 +587,14 @@
 static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
 				 int sy, int sx, int height, int width);
 static struct display_switch fbcon_clgen_32 = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		fbcon_clgen32_bmove,
-	clear:		fbcon_clgen32_clear,
-	putc:		fbcon_cfb32_putc,
-	putcs:		fbcon_cfb32_putcs,
-	revc:		fbcon_cfb32_revc,
-	clear_margins:	fbcon_cfb32_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb32_setup,
+	.bmove =	fbcon_clgen32_bmove,
+	.clear =	fbcon_clgen32_clear,
+	.putc =		fbcon_cfb32_putc,
+	.putcs =	fbcon_cfb32_putcs,
+	.revc =		fbcon_cfb32_revc,
+	.clear_margins =fbcon_cfb32_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 
diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
--- a/drivers/video/clps711xfb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/clps711xfb.c	Tue Aug 27 12:28:01 2002
@@ -193,19 +193,17 @@
 }
 
 static struct fb_ops clps7111fb_ops = {
-	owner:		THIS_MODULE,
-	fb_check_var:	clps7111fb_check_var,
-	fb_set_par:	clps7111fb_set_par,
-	fb_set_var:	gen_set_var,
-	fb_set_cmap:	gen_set_cmap,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_setcolreg:	clps7111fb_setcolreg,
-	fb_blank:	clps7111fb_blank,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_check_var	= clps7111fb_check_var,
+	.fb_set_par	= clps7111fb_set_par,
+	.fb_set_var	= gen_set_var,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_setcolreg	= clps7111fb_setcolreg,
+	.fb_blank	= clps7111fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 static int 
diff -Nru a/drivers/video/controlfb.c b/drivers/video/controlfb.c
--- a/drivers/video/controlfb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/controlfb.c	Tue Aug 27 12:28:01 2002
@@ -216,16 +216,16 @@
 
 
 static struct fb_ops controlfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	control_get_fix,
-	fb_get_var:	control_get_var,
-	fb_set_var:	control_set_var,
-	fb_get_cmap:	control_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	controlfb_setcolreg,
-	fb_pan_display:	control_pan_display,
-	fb_blank:	controlfb_blank,
-	fb_mmap:	control_mmap,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	control_get_fix,
+	.fb_get_var =	control_get_var,
+	.fb_set_var =	control_set_var,
+	.fb_get_cmap =	control_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	controlfb_setcolreg,
+	.fb_pan_display =control_pan_display,
+	.fb_blank =	controlfb_blank,
+	.fb_mmap =	control_mmap,
 };
 
 
diff -Nru a/drivers/video/creatorfb.c b/drivers/video/creatorfb.c
--- a/drivers/video/creatorfb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/creatorfb.c	Tue Aug 27 12:27:59 2002
@@ -648,13 +648,13 @@
 }
 
 static struct display_switch ffb_dispsw __initdata = {
-	setup:		ffb_setup,
-	bmove:		fbcon_redraw_bmove,
-	clear:		ffb_clear,
-	putc:		ffb_putc,
-	putcs:		ffb_putcs,
-	revc:		ffb_revc, 
-	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
+	.setup =	ffb_setup,
+	.bmove =	fbcon_redraw_bmove,
+	.clear =	ffb_clear,
+	.putc =		ffb_putc,
+	.putcs =	ffb_putcs,
+	.revc =		ffb_revc, 
+	.fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
 };
 
 static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/cyber2000fb.c	Tue Aug 27 12:28:01 2002
@@ -292,14 +292,14 @@
 }
 
 static struct display_switch fbcon_cyber_accel = {
-	setup:		cyber2000_accel_setup,
-	bmove:		cyber2000_accel_bmove,
-	clear:		cyber2000_accel_clear,
-	putc:		cyber2000_accel_putc,
-	putcs:		cyber2000_accel_putcs,
-	revc:		cyber2000_accel_revc,
-	clear_margins:	cyber2000_accel_clear_margins,
-	fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
+	.setup =	cyber2000_accel_setup,
+	.bmove =	cyber2000_accel_bmove,
+	.clear =	cyber2000_accel_clear,
+	.putc =		cyber2000_accel_putc,
+	.putcs =	cyber2000_accel_putcs,
+	.revc =		cyber2000_accel_revc,
+	.clear_margins =cyber2000_accel_clear_margins,
+	.fontwidthmask =FONTWIDTH(8)|FONTWIDTH(16)
 };
 
 /*
@@ -1109,15 +1109,13 @@
 }
 
 static struct fb_ops cyber2000fb_ops = {
-	owner:		THIS_MODULE,
-	fb_set_var:	cyber2000fb_set_var,
-	fb_setcolreg:	cyber2000fb_setcolreg,
-	fb_pan_display:	cyber2000fb_pan_display,
-	fb_blank:	cyber2000fb_blank,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= cyber2000fb_set_var,
+	.fb_setcolreg	= cyber2000fb_setcolreg,
+	.fb_pan_display	= cyber2000fb_pan_display,
+	.fb_blank	= cyber2000fb_blank,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
 };
 
 /*
@@ -1208,18 +1206,18 @@
  * 640x480, hsync 31.5kHz, vsync 60Hz
  */
 static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
-	refresh:	60,
-	xres:		640,
-	yres:		480,
-	pixclock:	39722,
-	left_margin:	56,
-	right_margin:	16,
-	upper_margin:	34,
-	lower_margin:	9,
-	hsync_len:	88,
-	vsync_len:	2,
-	sync:		FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-	vmode:		FB_VMODE_NONINTERLACED
+	.refresh =	60,
+	.xres =		640,
+	.yres =		480,
+	.pixclock =	39722,
+	.left_margin =	56,
+	.right_margin =	16,
+	.upper_margin =	34,
+	.lower_margin =	9,
+	.hsync_len =	88,
+	.vsync_len =	2,
+	.sync =		FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode =	FB_VMODE_NONINTERLACED
 };
 
 static char igs_regs[] __devinitdata = {
@@ -1744,12 +1742,12 @@
 MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
 
 static struct pci_driver cyberpro_driver = {
-	name:		"CyberPro",
-	probe:		cyberpro_pci_probe,
-	remove:		__devexit_p(cyberpro_pci_remove),
-	suspend:	cyberpro_pci_suspend,
-	resume:		cyberpro_pci_resume,
-	id_table:	cyberpro_pci_table
+	.name =		"CyberPro",
+	.probe =	cyberpro_pci_probe,
+	.remove =	__devexit_p(cyberpro_pci_remove),
+	.suspend =	cyberpro_pci_suspend,
+	.resume =	cyberpro_pci_resume,
+	.id_table =	cyberpro_pci_table
 };
 #endif
 
diff -Nru a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
--- a/drivers/video/cyberfb.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/video/cyberfb.c	Tue Aug 27 12:27:57 2002
@@ -948,14 +948,14 @@
 }
 
 static struct fb_ops cyberfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	cyberfb_get_fix,
-	fb_get_var:	cyberfb_get_var,
-	fb_set_var:	cyberfb_set_var,
-	fb_get_cmap:	cyberfb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	cyberfb_setcolreg,
-	fb_blank:	cyberfb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	cyberfb_get_fix,
+	.fb_get_var =	cyberfb_get_var,
+	.fb_set_var =	cyberfb_set_var,
+	.fb_get_cmap =	cyberfb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	cyberfb_setcolreg,
+	.fb_blank =	cyberfb_blank,
 };
 
 int __init cyberfb_setup(char *options)
@@ -1188,14 +1188,14 @@
 }
 
 static struct display_switch fbcon_cyber8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		fbcon_cyber8_bmove,
-	clear:		fbcon_cyber8_clear,
-	putc:		fbcon_cyber8_putc,
-	putcs:		fbcon_cyber8_putcs,
-	revc:		fbcon_cyber8_revc,
-	clear_margins:	fbcon_cfb8_clear_margins,
-	fontwidthmask:	FONTWIDTH(8)
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	fbcon_cyber8_bmove,
+	.clear =	fbcon_cyber8_clear,
+	.putc =		fbcon_cyber8_putc,
+	.putcs =	fbcon_cyber8_putcs,
+	.revc =		fbcon_cyber8_revc,
+	.clear_margins =fbcon_cfb8_clear_margins,
+	.fontwidthmask =FONTWIDTH(8)
 };
 #endif
 
diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c
--- a/drivers/video/dnfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/dnfb.c	Tue Aug 27 12:28:02 2002
@@ -119,36 +119,34 @@
 static void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
 
 static struct fb_ops dn_fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_blank:	dnfb_blank,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	dnfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_blank	= dnfb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= dnfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 struct fb_var_screeninfo dnfb_var __initdata = {
-	xres:		1280,
-	yres:		1024,
-	xres_virtual:	2048,
-	yres_virtual:	1024,
-	bits_per_pixel:	1,
-	height:		-1,
-	width:		-1,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres		1280,
+	.yres		1024,
+	.xres_virtual	2048,
+	.yres_virtual	1024,
+	.bits_per_pixel	1,
+	.height		-1,
+	.width		-1,
+	.vmode		FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo dnfb_fix __initdata = {
-	id:		"Apollo Mono",
-	smem_start:	(FRAME_BUFFER_START + IO_BASE),
-	smem_len:	FRAME_BUFFER_LEN,
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_MONO10,
-	line_length:	256,
+	.id		"Apollo Mono",
+	.smem_start	(FRAME_BUFFER_START + IO_BASE),
+	.smem_len	FRAME_BUFFER_LEN,
+	.type		FB_TYPE_PACKED_PIXELS,
+	.visual		FB_VISUAL_MONO10,
+	.line_length	256,
 };
 
 static int dnfb_blank(int blank, struct fb_info *info)
diff -Nru a/drivers/video/dummycon.c b/drivers/video/dummycon.c
--- a/drivers/video/dummycon.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/dummycon.c	Tue Aug 27 12:28:08 2002
@@ -57,18 +57,18 @@
  */
 
 const struct consw dummy_con = {
-    con_startup:	dummycon_startup,
-    con_init:		dummycon_init,
-    con_deinit:		DUMMY,
-    con_clear:		DUMMY,
-    con_putc:		DUMMY,
-    con_putcs:		DUMMY,
-    con_cursor:		DUMMY,
-    con_scroll:		DUMMY,
-    con_bmove:		DUMMY,
-    con_switch:		DUMMY,
-    con_blank:		DUMMY,
-    con_font_op:	DUMMY,
-    con_set_palette:	DUMMY,
-    con_scrolldelta:	DUMMY,
+    .con_startup =	dummycon_startup,
+    .con_init =		dummycon_init,
+    .con_deinit =	DUMMY,
+    .con_clear =	DUMMY,
+    .con_putc =		DUMMY,
+    .con_putcs =	DUMMY,
+    .con_cursor =	DUMMY,
+    .con_scroll =	DUMMY,
+    .con_bmove =	DUMMY,
+    .con_switch =	DUMMY,
+    .con_blank =	DUMMY,
+    .con_font_op =	DUMMY,
+    .con_set_palette =	DUMMY,
+    .con_scrolldelta =	DUMMY,
 };
diff -Nru a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
--- a/drivers/video/epson1355fb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/epson1355fb.c	Tue Aug 27 12:27:59 2002
@@ -459,16 +459,16 @@
 
 
 struct fbgen_hwswitch e1355_switch = {
-	detect:		e1355_detect,
-	encode_fix:	e1355_encode_fix,
-	decode_var:	e1355_decode_var,
-	encode_var:	e1355_encode_var,
-	get_par:	e1355_get_par,
-	set_par:	e1355_set_par,
-	getcolreg:	e1355_getcolreg,
-	pan_display:	e1355_pan_display,
-	blank:		e1355_blank,
-	set_disp:	e1355_set_disp,
+	.detect =	e1355_detect,
+	.encode_fix =	e1355_encode_fix,
+	.decode_var =	e1355_decode_var,
+	.encode_var =	e1355_encode_var,
+	.get_par =	e1355_get_par,
+	.set_par =	e1355_set_par,
+	.getcolreg =	e1355_getcolreg,
+	.pan_display =	e1355_pan_display,
+	.blank =	e1355_blank,
+	.set_disp =	e1355_set_disp,
 };
 
 
@@ -476,15 +476,15 @@
 
 
 static struct fb_ops e1355fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	e1355fb_setcolreg,
-	fb_pan_display:	fbgen_pan_display,
-	fb_blank:	fbgen_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	e1355fb_setcolreg,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_blank =	fbgen_blank,
 };
 
 static struct e1355fb_info fb_info;
diff -Nru a/drivers/video/fbcon-accel.c b/drivers/video/fbcon-accel.c
--- a/drivers/video/fbcon-accel.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/fbcon-accel.c	Tue Aug 27 12:28:01 2002
@@ -151,14 +151,14 @@
      */
 
 struct display_switch fbcon_accel = {
-	setup:		fbcon_accel_setup,
-	bmove:		fbcon_accel_bmove,
-	clear:		fbcon_accel_clear,
-	putc:		fbcon_accel_putc,
-	putcs:		fbcon_accel_putcs,
-	revc:		fbcon_accel_revc,
-	clear_margins:	fbcon_accel_clear_margins,
-	fontwidthmask:	FONTWIDTHRANGE(1, 16)	
+	.setup =	fbcon_accel_setup,
+	.bmove =	fbcon_accel_bmove,
+	.clear =	fbcon_accel_clear,
+	.putc =		fbcon_accel_putc,
+	.putcs =	fbcon_accel_putcs,
+	.revc =		fbcon_accel_revc,
+	.clear_margins =fbcon_accel_clear_margins,
+	.fontwidthmask =FONTWIDTHRANGE(1, 16)	
 };
 
 #ifdef MODULE
diff -Nru a/drivers/video/fbcon-afb.c b/drivers/video/fbcon-afb.c
--- a/drivers/video/fbcon-afb.c	Tue Aug 27 12:27:56 2002
+++ b/drivers/video/fbcon-afb.c	Tue Aug 27 12:27:56 2002
@@ -160,8 +160,8 @@
 
 void fbcon_afb_setup(struct display *p)
 {
-    if (p->line_length)
-	p->next_line = p->line_length;
+    if (p->fb_info->fix.line_length)
+	p->next_line = p->fb_info->fix.line_length;
     else
 	p->next_line = p->var.xres_virtual>>3;
     p->next_plane = p->var.yres_virtual*p->next_line;
diff -Nru a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c
--- a/drivers/video/fbcon-cfb16.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/fbcon-cfb16.c	Tue Aug 27 12:28:06 2002
@@ -36,7 +36,7 @@
 
 void fbcon_cfb16_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1;
+    p->next_line = p->fb_info->fix.line_length ? p->fb_info->fix.line_length : p->var.xres_virtual<<1;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c
--- a/drivers/video/fbcon-cfb2.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/fbcon-cfb2.c	Tue Aug 27 12:28:01 2002
@@ -50,7 +50,7 @@
 
 void fbcon_cfb2_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual>>2;
+    p->next_line = p->fb_info->fix.line_length ? p->fb_info->fix.line_length : p->var.xres_virtual>>2;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c
--- a/drivers/video/fbcon-cfb24.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/fbcon-cfb24.c	Tue Aug 27 12:28:02 2002
@@ -25,7 +25,9 @@
 
 void fbcon_cfb24_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual*3;
+    struct fb_info *info = p->fb_info;	
+
+    p->next_line = info->fix.line_length ? info->fix.line_length : p->var.xres_virtual*3;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c
--- a/drivers/video/fbcon-cfb32.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/fbcon-cfb32.c	Tue Aug 27 12:28:01 2002
@@ -25,7 +25,7 @@
 
 void fbcon_cfb32_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2;
+    p->next_line = p->fb_info->fix.line_length ? p->fb_info->fix.line_length : p->var.xres_virtual<<2;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c
--- a/drivers/video/fbcon-cfb4.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/fbcon-cfb4.c	Tue Aug 27 12:28:02 2002
@@ -50,7 +50,7 @@
 
 void fbcon_cfb4_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual>>1;
+    p->next_line = p->fb_info->fix.line_length ? p->fb_info->fix.line_length : p->var.xres_virtual>>1;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c
--- a/drivers/video/fbcon-cfb8.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/fbcon-cfb8.c	Tue Aug 27 12:28:06 2002
@@ -41,7 +41,7 @@
 
 void fbcon_cfb8_setup(struct display *p)
 {
-    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual;
+    p->next_line = p->fb_info->fix.line_length ? p->fb_info->fix.line_length : p->var.xres_virtual;
     p->next_plane = 0;
 }
 
diff -Nru a/drivers/video/fbcon-hga.c b/drivers/video/fbcon-hga.c
--- a/drivers/video/fbcon-hga.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/fbcon-hga.c	Tue Aug 27 12:28:02 2002
@@ -45,7 +45,7 @@
 {
 	DPRINTK("fbcon_hga_setup: ll:%d\n", (int)p->line_length);
 
-	p->next_line = p->line_length;
+	p->next_line = p->fb_info->fix.line_length;
 	p->next_plane = 0;
 }
 
@@ -214,14 +214,14 @@
 	 */
 
 struct display_switch fbcon_hga = {
-	setup:		fbcon_hga_setup,
-	bmove:		fbcon_hga_bmove,
-	clear:		fbcon_hga_clear,
-	putc:		fbcon_hga_putc,
-	putcs:		fbcon_hga_putcs,
-	revc:		fbcon_hga_revc,
-	clear_margins:	fbcon_hga_clear_margins,
-	fontwidthmask:	FONTWIDTH(8)
+	.setup =	fbcon_hga_setup,
+	.bmove =	fbcon_hga_bmove,
+	.clear =	fbcon_hga_clear,
+	.putc =		fbcon_hga_putc,
+	.putcs =	fbcon_hga_putcs,
+	.revc =		fbcon_hga_revc,
+	.clear_margins =fbcon_hga_clear_margins,
+	.fontwidthmask =FONTWIDTH(8)
 };
 
 
diff -Nru a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c
--- a/drivers/video/fbcon-ilbm.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/fbcon-ilbm.c	Tue Aug 27 12:28:02 2002
@@ -32,12 +32,12 @@
 
 void fbcon_ilbm_setup(struct display *p)
 {
-    if (p->line_length) {
-	p->next_line = p->line_length*p->var.bits_per_pixel;
-	p->next_plane = p->line_length;
+    if (p->fb_info->fix.line_length) {
+	p->next_line = p->fb_info->fix.line_length*p->var.bits_per_pixel;
+	p->next_plane = p->fb_info->fix.line_length;
     } else {
-	p->next_line = p->type_aux;
-	p->next_plane = p->type_aux/p->var.bits_per_pixel;
+	p->next_line = p->fb_info->fix.type_aux;
+	p->next_plane = p->fb_info->fix.type_aux/p->var.bits_per_pixel;
     }
 }
 
diff -Nru a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c
--- a/drivers/video/fbcon-mfb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/fbcon-mfb.c	Tue Aug 27 12:28:07 2002
@@ -25,8 +25,8 @@
 
 void fbcon_mfb_setup(struct display *p)
 {
-    if (p->line_length)
-	p->next_line = p->line_length;
+    if (p->fb_info->fix.line_length)
+	p->next_line = p->fb_info->fix.line_length;
     else
 	p->next_line = p->var.xres_virtual>>3;
     p->next_plane = 0;
diff -Nru a/drivers/video/fbcon-sti.c b/drivers/video/fbcon-sti.c
--- a/drivers/video/fbcon-sti.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/fbcon-sti.c	Tue Aug 27 12:28:07 2002
@@ -324,14 +324,14 @@
      */
 
 struct display_switch fbcon_sti = {
-	setup:		fbcon_sti_setup, 
-	bmove:		fbcon_sti_bmove, 
-	clear:		fbcon_sti_clear,
-	putc:		fbcon_sti_putc, 
-	putcs:		fbcon_sti_putcs, 
-	revc:		fbcon_sti_revc,
-	clear_margins:	fbcon_sti_clear_margins,
-	fontwidthmask:	FONTWIDTH(8)
+	.setup =	fbcon_sti_setup, 
+	.bmove =	fbcon_sti_bmove, 
+	.clear =	fbcon_sti_clear,
+	.putc =		fbcon_sti_putc, 
+	.putcs =	fbcon_sti_putcs, 
+	.revc =		fbcon_sti_revc,
+	.clear_margins =fbcon_sti_clear_margins,
+	.fontwidthmask =FONTWIDTH(8)
 };
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/fbcon-vga-planes.c b/drivers/video/fbcon-vga-planes.c
--- a/drivers/video/fbcon-vga-planes.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/fbcon-vga-planes.c	Tue Aug 27 12:28:06 2002
@@ -119,9 +119,9 @@
 	height *= fontheight(p);
 
 	if (dy < sy || (dy == sy && dx < sx)) {
-		line_ofs = p->line_length - width;
-		dest = p->fb_info->screen_base + dx + dy * p->line_length;
-		src = p->fb_info->screen_base + sx + sy * p->line_length;
+		line_ofs = p->fb_info->fix.line_length - width;
+		dest = p->fb_info->screen_base + dx + dy * p->fb_info->fix.line_length;
+		src = p->fb_info->screen_base + sx + sy * p->fb_info->fix.line_length;
 		while (height--) {
 			for (x = 0; x < width; x++) {
 				readb(src);
@@ -133,9 +133,9 @@
 			dest += line_ofs;
 		}
 	} else {
-		line_ofs = p->line_length - width;
-		dest = p->fb_info->screen_base + dx + width + (dy + height - 1) * p->line_length;
-		src = p->fb_info->screen_base + sx + width + (sy + height - 1) * p->line_length;
+		line_ofs = p->fb_info->fix.line_length - width;
+		dest = p->fb_info->screen_base + dx + width + (dy + height - 1) * p->fb_info->fix.line_length;
+		src = p->fb_info->screen_base + sx + width + (sy + height - 1) * p->fb_info->fix.line_length;
 		while (height--) {
 			for (x = 0; x < width; x++) {
 				dest--;
@@ -152,7 +152,7 @@
 void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		   int height, int width)
 {
-	int line_ofs = p->line_length - width;
+	int line_ofs = p->fb_info->fix.line_length - width;
 	char *where;
 	int x;
 	
@@ -167,7 +167,7 @@
 	sy *= fontheight(p);
 	height *= fontheight(p);
 
-	where = p->fb_info->screen_base + sx + sy * p->line_length;
+	where = p->fb_info->screen_base + sx + sy * p->fb_info->fix.line_length;
 	while (height--) {
 		for (x = 0; x < width; x++) {
 			writeb(0, where);
@@ -184,7 +184,7 @@
 
 	int y;
 	u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->fb_info->fix.line_length * fontheight(p);
 
 	setmode(0);
 	setop(0);
@@ -193,13 +193,13 @@
 	selectmask();
 
 	setmask(0xff);
-	for (y = 0; y < fontheight(p); y++, where += p->line_length) 
+	for (y = 0; y < fontheight(p); y++, where += p->fb_info->fix.line_length) 
 		rmw(where);
 
-	where -= p->line_length * y;
+	where -= p->fb_info->fix.line_length * y;
 	setcolor(fg);
 	selectmask();
-	for (y = 0; y < fontheight(p); y++, where += p->line_length) 
+	for (y = 0; y < fontheight(p); y++, where += p->fb_info->fix.line_length) 
 		if (cdat[y]) {
 			setmask(cdat[y]);
 			rmw(where);
@@ -213,7 +213,7 @@
 
 	int y;
 	u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->fb_info->fix.line_length * fontheight(p);
 
 	setmode(2);
 	setop(0);
@@ -227,7 +227,7 @@
 	readb(where); /* fill latches */
 	setmode(3);
 	wmb();
-	for (y = 0; y < fontheight(p); y++, where += p->line_length) 
+	for (y = 0; y < fontheight(p); y++, where += p->fb_info->fix.line_length) 
 		writeb(cdat[y], where);
 	wmb();
 }
@@ -248,7 +248,7 @@
 	selectmask();
 
 	setmask(0xff);
-	where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
+	where = p->fb_info->screen_base + xx + yy * p->fb_info->fix.line_length * fontheight(p);
 	writeb(bg, where);
 	rmb();
 	readb(where); /* fill latches */
@@ -263,9 +263,9 @@
 			outb(*cdat++, GRAPHICS_DATA_REG);	
 			wmb();
 			writeb(fg, where);
-			where += p->line_length;
+			where += p->fb_info->fix.line_length;
 		}
-		where += 1 - p->line_length * fontheight(p);
+		where += 1 - p->fb_info->fix.line_length * fontheight(p);
 	}
 	
 	wmb();
@@ -289,7 +289,7 @@
 	selectmask();
 
 	setmask(0xff);
-	where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
+	where = p->fb_info->screen_base + xx + yy * p->fb_info->fix.line_length * fontheight(p);
 	writeb(bg, where);
 	rmb();
 	readb(where); /* fill latches */
@@ -302,9 +302,9 @@
 
 		for (y = 0; y < fontheight(p); y++, cdat++) {
 			writeb (*cdat, where);
-			where += p->line_length;
+			where += p->fb_info->fix.line_length;
 		}
-		where += 1 - p->line_length * fontheight(p);
+		where += 1 - p->fb_info->fix.line_length * fontheight(p);
 	}
 	
 	wmb();
@@ -312,7 +312,7 @@
 
 void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
 {
-	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->fb_info->fix.line_length * fontheight(p);
 	int y;
 	
 	setmode(0);
@@ -324,7 +324,7 @@
 	setmask(0xff);
 	for (y = 0; y < fontheight(p); y++) {
 		rmw(where);
-		where += p->line_length;
+		where += p->fb_info->fix.line_length;
 	}
 }
 
diff -Nru a/drivers/video/fbcon.c b/drivers/video/fbcon.c
--- a/drivers/video/fbcon.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/fbcon.c	Tue Aug 27 12:28:01 2002
@@ -518,13 +518,15 @@
 
 static __inline__ void updatescrollmode(struct display *p)
 {
+    struct fb_info *info = p->fb_info;	
+
     int m;
     if (p->scrollmode & __SCROLL_YFIXED)
     	return;
-    if (divides(p->ywrapstep, fontheight(p)) &&
-	divides(fontheight(p), p->var.yres_virtual))
+    if (divides(info->fix.ywrapstep, fontheight(p)) &&
+	divides(fontheight(p), info->var.yres_virtual))
 	m = __SCROLL_YWRAP;
-    else if (divides(p->ypanstep, fontheight(p)) &&
+    else if (divides(info->fix.ypanstep, fontheight(p)) &&
 	     p->var.yres_virtual >= p->var.yres+fontheight(p))
 	m = __SCROLL_YPAN;
     else if (p->scrollmode & __SCROLL_YNOMOVE)
@@ -553,6 +555,7 @@
 static void fbcon_setup(int con, int init, int logo)
 {
     struct display *p = &fb_display[con];
+    struct fb_info *info = p->fb_info;
     struct vc_data *conp = p->conp;
     int nr_rows, nr_cols;
     int old_rows, old_cols;
@@ -560,13 +563,13 @@
     int i, charcnt = 256;
     struct fbcon_font_desc *font;
     
-    if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) ||
-        p->type == FB_TYPE_TEXT)
+    if (con != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
+        info->fix.type == FB_TYPE_TEXT)
     	logo = 0;
 
     p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
 
-    if (con == fg_console && p->type != FB_TYPE_TEXT) {   
+    if (con == fg_console && info->fix.type != FB_TYPE_TEXT) {   
 	if (fbcon_softback_size) {
 	    if (!softback_buf) {
 		softback_buf = (unsigned long)kmalloc(fbcon_softback_size, GFP_KERNEL);
@@ -716,7 +719,8 @@
 
     if (p->dispsw == &fbcon_dummy)
 	printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
-	       "supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
+	       "supported\n", info->fix.type, info->fix.type_aux, 
+		p->var.bits_per_pixel);
     p->dispsw->setup(p);
 
     p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
@@ -1563,9 +1567,9 @@
 
     if (!p->can_soft_blank) {
 	if (blank) {
-	    if (p->visual == FB_VISUAL_MONO01) {
-		if (p->fb_info->screen_base)
-		    fb_memset255(p->fb_info->screen_base,
+	    if (info->fix.visual == FB_VISUAL_MONO01) {
+		if (info->screen_base)
+		    fb_memset255(info->screen_base,
 				 p->var.xres_virtual*p->var.yres_virtual*
 				 p->var.bits_per_pixel>>3);
 	    } else {
@@ -2122,9 +2126,10 @@
 static int __init fbcon_show_logo( void )
 {
     struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
+    struct fb_info *info = p->fb_info;
     int depth = p->var.bits_per_pixel;
     int line = p->next_line;
-    unsigned char *fb = p->fb_info->screen_base;
+    unsigned char *fb = info->screen_base;
     unsigned char *logo;
     unsigned char *dst, *src;
     int i, j, n, x1, y1, x;
@@ -2140,8 +2145,8 @@
      * We don't have to set the colors for the 16-color logo, since that logo
      * uses the standard VGA text console palette
      */
-    if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) ||
-	(p->visual == FB_VISUAL_DIRECTCOLOR && depth >= 24))
+    if ((info->fix.visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) ||
+	(info->fix.visual == FB_VISUAL_DIRECTCOLOR && depth >= 24))
 	for (i = 0; i < LINUX_LOGO_COLORS; i += n) {
 	    n = LINUX_LOGO_COLORS - i;
 	    if (n > 16)
@@ -2157,8 +2162,7 @@
 		palette_cmap.blue[j]  = (linux_logo_blue[i+j] << 8) |
 					linux_logo_blue[i+j];
 	    }
-	    p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
-					   p->fb_info);
+	    info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console, info);
 	}
 	
     if (depth >= 8) {
@@ -2174,15 +2178,15 @@
 	logo_depth = 1;
     }
     
-    if (p->fb_info->fbops->fb_rasterimg)
-    	p->fb_info->fbops->fb_rasterimg(p->fb_info, 1);
+    if (info->fbops->fb_rasterimg)
+    	info->fbops->fb_rasterimg(info, 1);
 
     for (x = 0; x < num_online_cpus() * (LOGO_W + 8) &&
     	 x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
     	 
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
-        if (p->visual == FB_VISUAL_DIRECTCOLOR) {
+        if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 	    unsigned int val;		/* max. depth 32! */
 	    int bdepth;
 	    int redshift, greenshift, blueshift;
@@ -2257,7 +2261,7 @@
 #endif
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
-	if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR)) {
+	if ((depth % 8 == 0) && (info->fix.visual == FB_VISUAL_TRUECOLOR)) {
 	    /* Modes without color mapping, needs special data transformation... */
 	    unsigned int val;		/* max. depth 32! */
 	    int bdepth = depth/8;
@@ -2302,7 +2306,7 @@
 	}
 #endif
 #if defined(CONFIG_FBCON_CFB4)
-	if (depth == 4 && p->type == FB_TYPE_PACKED_PIXELS) {
+	if (depth == 4 && info->fix.type == FB_TYPE_PACKED_PIXELS) {
 		src = logo;
 		for( y1 = 0; y1 < LOGO_H; y1++) {
 			dst = fb + y1*line + x/2;
@@ -2316,7 +2320,7 @@
 	}
 #endif
 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS)
-	if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
+	if (depth == 8 && info->fix.type == FB_TYPE_PACKED_PIXELS) {
 	    /* depth 8 or more, packed, with color registers */
 		
 	    src = logo;
@@ -2331,8 +2335,8 @@
 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
     defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
     defined(CONFIG_FBCON_IPLAN2P8)
-	if (depth >= 2 && (p->type == FB_TYPE_PLANES ||
-			   p->type == FB_TYPE_INTERLEAVED_PLANES)) {
+	if (depth >= 2 && (info->fix.type == FB_TYPE_PLANES ||
+			   info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) {
 	    /* planes (normal or interleaved), with color registers */
 	    int bit;
 	    unsigned char val, mask;
@@ -2340,7 +2344,7 @@
 
 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
     defined(CONFIG_FBCON_IPLAN2P8)
-	    int line_length = p->line_length;
+	    int line_length = info->fix.line_length;
 
 	    /* for support of Atari interleaved planes */
 #define MAP_X(x)	(line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))
@@ -2384,12 +2388,12 @@
 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
     defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_HGA)
 
-	if (depth == 1 && (p->type == FB_TYPE_PACKED_PIXELS ||
-			   p->type == FB_TYPE_PLANES ||
-			   p->type == FB_TYPE_INTERLEAVED_PLANES)) {
+	if (depth == 1 && (info->fix.type == FB_TYPE_PACKED_PIXELS ||
+			   info->fix.type == FB_TYPE_PLANES ||
+			   info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) {
 
 	    /* monochrome */
-	    unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
+	    unsigned char inverse = p->inverse || info->fix.visual == FB_VISUAL_MONO01
 		? 0x00 : 0xff;
 
 	    int is_hga = !strncmp(p->fb_info->modename, "HGA", 3);
@@ -2407,7 +2411,7 @@
 	}
 #endif
 #if defined(CONFIG_FBCON_VGA_PLANES)
-	if (depth == 4 && p->type == FB_TYPE_VGA_PLANES) {
+	if (depth == 4 && info->fix.type == FB_TYPE_VGA_PLANES) {
 		outb_p(1,0x3ce); outb_p(0xf,0x3cf);
 		outb_p(3,0x3ce); outb_p(0,0x3cf);
 		outb_p(5,0x3ce); outb_p(0,0x3cf);
@@ -2453,24 +2457,24 @@
  */
  
 const struct consw fb_con = {
-    con_startup: 	fbcon_startup, 
-    con_init: 		fbcon_init,
-    con_deinit: 	fbcon_deinit,
-    con_clear: 		fbcon_clear,
-    con_putc: 		fbcon_putc,
-    con_putcs: 		fbcon_putcs,
-    con_cursor: 	fbcon_cursor,
-    con_scroll: 	fbcon_scroll,
-    con_bmove: 		fbcon_bmove,
-    con_switch: 	fbcon_switch,
-    con_blank: 		fbcon_blank,
-    con_font_op:	fbcon_font_op,
-    con_set_palette: 	fbcon_set_palette,
-    con_scrolldelta: 	fbcon_scrolldelta,
-    con_set_origin: 	fbcon_set_origin,
-    con_invert_region:	fbcon_invert_region,
-    con_screen_pos:	fbcon_screen_pos,
-    con_getxy:		fbcon_getxy,
+    .con_startup = 	fbcon_startup, 
+    .con_init = 	fbcon_init,
+    .con_deinit = 	fbcon_deinit,
+    .con_clear = 	fbcon_clear,
+    .con_putc = 	fbcon_putc,
+    .con_putcs = 	fbcon_putcs,
+    .con_cursor = 	fbcon_cursor,
+    .con_scroll = 	fbcon_scroll,
+    .con_bmove = 	fbcon_bmove,
+    .con_switch = 	fbcon_switch,
+    .con_blank = 	fbcon_blank,
+    .con_font_op =	fbcon_font_op,
+    .con_set_palette = 	fbcon_set_palette,
+    .con_scrolldelta = 	fbcon_scrolldelta,
+    .con_set_origin = 	fbcon_set_origin,
+    .con_invert_region = fbcon_invert_region,
+    .con_screen_pos =	fbcon_screen_pos,
+    .con_getxy =	fbcon_getxy,
 };
 
 
@@ -2483,12 +2487,12 @@
 #define DUMMY	(void *)fbcon_dummy_op
 
 struct display_switch fbcon_dummy = {
-    setup:	DUMMY,
-    bmove:	DUMMY,
-    clear:	DUMMY,
-    putc:	DUMMY,
-    putcs:	DUMMY,
-    revc:	DUMMY,
+    .setup =	DUMMY,
+    .bmove =	DUMMY,
+    .clear =	DUMMY,
+    .putc =	DUMMY,
+    .putcs =	DUMMY,
+    .revc =	DUMMY,
 };
 
 
diff -Nru a/drivers/video/fbgen.c b/drivers/video/fbgen.c
--- a/drivers/video/fbgen.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/fbgen.c	Tue Aug 27 12:28:07 2002
@@ -30,18 +30,6 @@
 #include <video/fbcon-cfb32.h>
 #include "fbcon-accel.h"
 
-int gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	*fix = info->fix;
-	return 0;	
-}
-
-int gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	*var = info->var;
-	return 0;	
-}
-
 int gen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
 	int err;
@@ -141,12 +129,6 @@
 {
 	struct display *display = (con < 0) ? info->disp : (fb_display + con);
 
-	display->visual = info->fix.visual;
-	display->type	= info->fix.type;
-	display->type_aux = info->fix.type_aux;
-	display->ypanstep = info->fix.ypanstep;
-    	display->ywrapstep = info->fix.ywrapstep;
-    	display->line_length = info->fix.line_length;
 	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR ||
 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 		display->can_soft_blank = info->fbops->fb_blank ? 1 : 0;
@@ -175,6 +157,8 @@
 #ifdef FBCON_HAS_ACCEL
 	display->scrollmode = SCROLL_YNOMOVE;
 	display->dispsw = &fbcon_accel;
+#else
+	display->dispsw = &fbcon_dummy;
 #endif
 	return;
 }
@@ -289,8 +273,6 @@
 }
 
 /* generic frame buffer operations */
-EXPORT_SYMBOL(gen_get_fix);
-EXPORT_SYMBOL(gen_get_var);
 EXPORT_SYMBOL(gen_set_var);
 EXPORT_SYMBOL(gen_get_cmap);
 EXPORT_SYMBOL(gen_set_cmap);
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Tue Aug 27 12:27:39 2002
+++ b/drivers/video/fbmem.c	Tue Aug 27 12:27:39 2002
@@ -393,19 +393,16 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	int fbidx = GET_FB_IDX(inode->i_rdev);
 	struct fb_info *info = registered_fb[fbidx];
-	struct fb_ops *fb = info->fbops;
-	struct fb_fix_screeninfo fix;
 
-	if (! fb || ! info->disp)
+	if (!info || ! info->screen_base)
 		return -ENODEV;
 
-	fb->fb_get_fix(&fix,PROC_CONSOLE(info), info);
-	if (p >= fix.smem_len)
+	if (p >= info->fix.smem_len)
 	    return 0;
-	if (count >= fix.smem_len)
-	    count = fix.smem_len;
-	if (count + p > fix.smem_len)
-		count = fix.smem_len - p;
+	if (count >= info->fix.smem_len)
+	    count = info->fix.smem_len;
+	if (count + p > info->fix.smem_len)
+		count = info->fix.smem_len - p;
 	if (count) {
 	    char *base_addr;
 
@@ -425,21 +422,18 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	int fbidx = GET_FB_IDX(inode->i_rdev);
 	struct fb_info *info = registered_fb[fbidx];
-	struct fb_ops *fb = info->fbops;
-	struct fb_fix_screeninfo fix;
 	int err;
 
-	if (! fb || ! info->disp)
+	if (!info || !info->screen_base)
 		return -ENODEV;
 
-	fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
-	if (p > fix.smem_len)
+	if (p > info->fix.smem_len)
 	    return -ENOSPC;
-	if (count >= fix.smem_len)
-	    count = fix.smem_len;
+	if (count >= info->fix.smem_len)
+	    count = info->fix.smem_len;
 	err = 0;
-	if (count + p > fix.smem_len) {
-	    count = fix.smem_len - p;
+	if (count + p > info->fix.smem_len) {
+	    count = info->fix.smem_len - p;
 	    err = -ENOSPC;
 	}
 	if (count) {
@@ -482,9 +476,7 @@
 		return -ENODEV;
 	switch (cmd) {
 	case FBIOGET_VSCREENINFO:
-		if ((i = fb->fb_get_var(&var, PROC_CONSOLE(info), info)))
-			return i;
-		return copy_to_user((void *) arg, &var,
+		return copy_to_user((void *) arg, &info->var,
 				    sizeof(var)) ? -EFAULT : 0;
 	case FBIOPUT_VSCREENINFO:
 		if (copy_from_user(&var, (void *) arg, sizeof(var)))
@@ -498,10 +490,7 @@
 			return -EFAULT;
 		return 0;
 	case FBIOGET_FSCREENINFO:
-		if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(info), info)))
-			return i;
-		return copy_to_user((void *) arg, &fix, sizeof(fix)) ?
-			-EFAULT : 0;
+		return copy_to_user((void *) arg, &info->fix, sizeof(fix)) ? -EFAULT : 0;
 	case FBIOPUTCMAP:
 		if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
 			return -EFAULT;
@@ -568,8 +557,6 @@
 	struct fb_ops *fb = info->fbops;
 	unsigned long off;
 #if !defined(__sparc__) || defined(__sparc_v9__)
-	struct fb_fix_screeninfo fix;
-	struct fb_var_screeninfo var;
 	unsigned long start;
 	u32 len;
 #endif
@@ -593,23 +580,20 @@
 	return -EINVAL;
 #else
 	/* !sparc32... */
-
 	lock_kernel();
-	fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
 
 	/* frame buffer memory */
-	start = fix.smem_start;
-	len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len);
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
 	if (off >= len) {
 		/* memory mapped io */
 		off -= len;
-		fb->fb_get_var(&var, PROC_CONSOLE(info), info);
-		if (var.accel_flags) {
+		if (info->var.accel_flags) {
 			unlock_kernel();
 			return -EINVAL;
 		}
-		start = fix.mmio_start;
-		len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len);
+		start = info->fix.mmio_start;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
 	}
 	unlock_kernel();
 	start &= PAGE_MASK;
@@ -722,15 +706,15 @@
 }
 
 static struct file_operations fb_fops = {
-	owner:		THIS_MODULE,
-	read:		fb_read,
-	write:		fb_write,
-	ioctl:		fb_ioctl,
-	mmap:		fb_mmap,
-	open:		fb_open,
-	release:	fb_release,
+	.owner =	THIS_MODULE,
+	.read =		fb_read,
+	.write =	fb_write,
+	.ioctl =	fb_ioctl,
+	.mmap =		fb_mmap,
+	.open =		fb_open,
+	.release =	fb_release,
 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
-	get_unmapped_area: get_fb_unmapped_area,
+	.get_unmapped_area = get_fb_unmapped_area,
 #endif
 };
 
diff -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
--- a/drivers/video/fm2fb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/fm2fb.c	Tue Aug 27 12:28:02 2002
@@ -136,12 +136,12 @@
 static struct display display;
 
 static struct fb_fix_screeninfo fb_fix __initdata = {
-	smem_len:	FRAMEMASTER_REG,
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_TRUECOLOR,
-	line_length:	(768 << 2),
-	mmio_len:	(8),
-	accel:		FB_ACCEL_NONE,
+	.smem_len =	FRAMEMASTER_REG,
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.line_length =	(768 << 2),
+	.mmio_len =	(8),
+	.accel =	FB_ACCEL_NONE,
 };
 
 static int fm2fb_mode __initdata = -1;
@@ -175,17 +175,15 @@
 static int fm2fb_blank(int blank, struct fb_info *info);
 
 static struct fb_ops fm2fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	fm2fb_setcolreg,
-	fb_blank:	fm2fb_blank,	
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= fm2fb_setcolreg,
+	.fb_blank	= fm2fb_blank,	
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
     /*
diff -Nru a/drivers/video/g364fb.c b/drivers/video/g364fb.c
--- a/drivers/video/g364fb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/g364fb.c	Tue Aug 27 12:27:59 2002
@@ -78,23 +78,23 @@
 static struct fb_info fb_info;
 
 static struct fb_fix_screeninfo fb_fix __initdata = {
-	id:		"G364 8plane",
-	smem_start:	0x40000000,	/* physical address */
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	ypanstep:	1,
-	accel:		FB_ACCEL_NONE,
+	.id =		"G364 8plane",
+	.smem_start =	0x40000000,	/* physical address */
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.ypanstep =	1,
+	.accel =	FB_ACCEL_NONE,
 };
 
 static struct fb_var_screeninfo fb_var __initdata = {
-	bits_per_pixel:	8,
-	red:		{ 0, 8, 0 },
+	.bits_per_pixel =8,
+	.red =		{ 0, 8, 0 },
       	green:		{ 0, 8, 0 },
       	blue:		{ 0, 8, 0 },
-      	activate:	FB_ACTIVATE_NOW,
+      	activate:FB_ACTIVATE_NOW,
       	height:		-1,
       	width:		-1,
-      	pixclock:	39722,
+      	pixclock:39722,
       	left_margin:	40,
       	right_margin:	24,
       	upper_margin:	32,
@@ -117,18 +117,16 @@
 static int g364fb_blank(int blank, struct fb_info *info);
 
 static struct fb_ops g364fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	g364fb_setcolreg,
-	fb_pan_display:	g364fb_pan_display,
-	fb_blank:	g364fb_blank,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= g364fb_setcolreg,
+	.fb_pan_display	= g364fb_pan_display,
+	.fb_blank	= g364fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 void fbcon_g364fb_cursor(struct display *p, int mode, int x, int y)
diff -Nru a/drivers/video/hgafb.c b/drivers/video/hgafb.c
--- a/drivers/video/hgafb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/hgafb.c	Tue Aug 27 12:28:08 2002
@@ -111,23 +111,23 @@
 /* Framebuffer driver structures */
 
 static struct fb_var_screeninfo hga_default_var = {
-	xres:		720,
-	yres:		348,
-	xres_virtual:	720,
-	yres_virtual:	348,
-	xoffset:	0,
-	yoffset:	0,
-	bits_per_pixel:	1,
-	grayscale:	0,
-	red:		{0, 1, 0},
-	green:		{0, 1, 0},
-	blue:		{0, 1, 0},
-	transp:		{0, 0, 0},
-	nonstd:		0,			/* (FB_NONSTD_HGA ?) */
-	activate:	0,
-	height:		-1,
-	width:		-1,
-	accel_flags:	0,
+	.xres =		720,
+	.yres =		348,
+	.xres_virtual =	720,
+	.yres_virtual =	348,
+	.xoffset =	0,
+	.yoffset =	0,
+	.bits_per_pixel =1,
+	.grayscale =	0,
+	.red =		{0, 1, 0},
+	.green =	{0, 1, 0},
+	.blue =		{0, 1, 0},
+	.transp =	{0, 0, 0},
+	.nonstd =	0,			/* (FB_NONSTD_HGA ?) */
+	.activate =	0,
+	.height =	-1,
+	.width =	-1,
+	.accel_flags =	0,
 	/* pixclock */
 	/* left_margin, right_margin */
 	/* upper_margin, lower_margin */
@@ -137,19 +137,19 @@
 };
 
 static struct fb_fix_screeninfo hga_fix = {
-	id:		"HGA",
-	smem_start:	(unsigned long) NULL,
-	smem_len:	0,
-	type:		FB_TYPE_PACKED_PIXELS,	/* (not sure) */
-	type_aux:	0,			/* (not sure) */
-	visual:		FB_VISUAL_MONO10,
-	xpanstep:	8,
-	ypanstep:	8,
-	ywrapstep:	0,
-	line_length:	90,
-	mmio_start:	0,
-	mmio_len:	0,
-	accel:		FB_ACCEL_NONE
+	.id =		"HGA",
+	.smem_start =	(unsigned long) NULL,
+	.smem_len =	0,
+	.type =		FB_TYPE_PACKED_PIXELS,	/* (not sure) */
+	.type_aux =	0,			/* (not sure) */
+	.visual =	FB_VISUAL_MONO10,
+	.xpanstep =	8,
+	.ypanstep =	8,
+	.ywrapstep =	0,
+	.line_length =	90,
+	.mmio_start =	0,
+	.mmio_len =	0,
+	.accel =	FB_ACCEL_NONE
 };
 
 static struct fb_info fb_info;
@@ -557,15 +557,13 @@
 }
 
 static struct fb_ops hgafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	hga_set_var,
-	fb_get_cmap:	hga_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	hgafb_setcolreg,
-	fb_pan_display:	hga_pan_display,
-	fb_blank:	hgafb_blank,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= hga_set_var,
+	.fb_get_cmap	= hga_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= hgafb_setcolreg,
+	.fb_pan_display	= hga_pan_display,
+	.fb_blank	= hgafb_blank,
 };
 		
 
diff -Nru a/drivers/video/hitfb.c b/drivers/video/hitfb.c
--- a/drivers/video/hitfb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/hitfb.c	Tue Aug 27 12:27:59 2002
@@ -32,17 +32,17 @@
 #include <video/fbcon.h>
 
 static struct fb_var_screeninfo hitfb_var __initdata = {
-	activate:	FB_ACTIVATE_NOW,
-	height:		-1,
-	width:		-1,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.vmode =	FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo hitfb_fix __initdata = {
-	id:		"Hitachi HD64461",
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_TRUECOLOR,
-	accel_flags:	FB_ACCEL_NONE,
+	.id =		"Hitachi HD64461",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.accel_flags =	FB_ACCEL_NONE,
 };
 
 static u16 pseudo_palette[17];
@@ -124,18 +124,16 @@
 }
 
 static struct fb_ops hitfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_check_var:	hitfb_check_var,
-	fb_set_par:	hitfb_set_par,
-	fb_setcolreg:	hitfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= hitfb_check_var,
+	.fb_set_par	= hitfb_set_par,
+	.fb_setcolreg	= hitfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 int __init hitfb_init(void)
diff -Nru a/drivers/video/hpfb.c b/drivers/video/hpfb.c
--- a/drivers/video/hpfb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/hpfb.c	Tue Aug 27 12:28:07 2002
@@ -43,28 +43,28 @@
 #define WMOVE		0x409c
 
 static struct fb_fix_screeninfo hpfb_fix __initdata = {
-	id:		"HP300 Topcat",
-	smem_len:	1024*768,
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	line_length:	1024,
-	accel:		FB_ACCEL_NONE,
+	.id		= "HP300 Topcat",
+	.smem_len	= 1024*768,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.line_length	= 1024,
+	.accel		= FB_ACCEL_NONE,
 };
 
 static struct fb_var_screeninfo hpfb_defined = {
-	xres:		1024,
-	yres:		768,
-	xres_virtual:	1024,
-	yres_virtual:	786,
-	bits_per_pixel:	1,
-	red:		{0,2,0},	/* R */
-	green:		{0,2,0},	/* G */
-	blue:		{0,2,0},	/* B */
-	activate:	FB_ACTIVATE_NOW,
-	height:		274,
-	width:		195,	/* 14" monitor */
-	accel_flags:	FB_ACCEL_NONE,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres		= 1024,
+	.yres		= 768,
+	.xres_virtual	= 1024,
+	.yres_virtual	= 786,
+	.bits_per_pixel	= 1,
+	.red		= {0,2,0},	/* R */
+	.green		= {0,2,0},	/* G */
+	.blue		= {0,2,0},	/* B */
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= 274,
+	.width		= 195,	/* 14" monitor */
+	.accel_flags	= FB_ACCEL_NONE,
+	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
 static struct display display;
@@ -104,16 +104,14 @@
 }
 
 static struct fb_ops hpfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	hpfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	hpfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= hpfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= hpfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 #define TOPCAT_FBOMSB	0x5d
diff -Nru a/drivers/video/igafb.c b/drivers/video/igafb.c
--- a/drivers/video/igafb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/igafb.c	Tue Aug 27 12:28:07 2002
@@ -401,15 +401,15 @@
  * Framebuffer option structure
  */
 static struct fb_ops igafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	igafb_get_fix,
-	fb_get_var:	igafb_get_var,
-	fb_set_var:	igafb_set_var,
-	fb_get_cmap:	igafb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	igafb_setcolreg,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	igafb_get_fix,
+	.fb_get_var =	igafb_get_var,
+	.fb_set_var =	igafb_set_var,
+	.fb_get_cmap =	igafb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	igafb_setcolreg,
 #ifdef __sparc__
-	fb_mmap:	igafb_mmap,
+	.fb_mmap =	igafb_mmap,
 #endif
 };
 
diff -Nru a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
--- a/drivers/video/imsttfb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/imsttfb.c	Tue Aug 27 12:28:05 2002
@@ -1122,58 +1122,58 @@
 
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_imstt8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		imsttfbcon_bmove,
-	clear:		imsttfbcon_clear,
-	putc:		fbcon_cfb8_putc,
-	putcs:		fbcon_cfb8_putcs,
-	revc:		imsttfbcon_revc,
-	cursor:		imsttfbcon_cursor,
-	set_font:	imsttfbcon_set_font,
-	clear_margins:	fbcon_cfb8_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	imsttfbcon_bmove,
+	.clear =	imsttfbcon_clear,
+	.putc =		fbcon_cfb8_putc,
+	.putcs =	fbcon_cfb8_putcs,
+	.revc =		imsttfbcon_revc,
+	.cursor =	imsttfbcon_cursor,
+	.set_font =	imsttfbcon_set_font,
+	.clear_margins =fbcon_cfb8_clear_margins,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
 static struct display_switch fbcon_imstt16 = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		imsttfbcon_bmove,
-	clear:		imsttfbcon_clear,
-	putc:		fbcon_cfb16_putc,
-	putcs:		fbcon_cfb16_putcs,
-	revc:		imsttfbcon_revc,
-	cursor:		imsttfbcon_cursor,
-	set_font:	imsttfbcon_set_font,
-	clear_margins:	fbcon_cfb16_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb16_setup,
+	.bmove =	imsttfbcon_bmove,
+	.clear =	imsttfbcon_clear,
+	.putc =		fbcon_cfb16_putc,
+	.putcs =	fbcon_cfb16_putcs,
+	.revc =		imsttfbcon_revc,
+	.cursor =	imsttfbcon_cursor,
+	.set_font =	imsttfbcon_set_font,
+	.clear_margins =fbcon_cfb16_clear_margins,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 #ifdef FBCON_HAS_CFB24
 static struct display_switch fbcon_imstt24 = {
-	setup:		fbcon_cfb24_setup,
-	bmove:		imsttfbcon_bmove,
-	clear:		imsttfbcon_clear,
-	putc:		fbcon_cfb24_putc,
-	putcs:		fbcon_cfb24_putcs,
-	revc:		imsttfbcon_revc,
-	cursor:		imsttfbcon_cursor,
-	set_font:	imsttfbcon_set_font,
-	clear_margins:	fbcon_cfb24_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb24_setup,
+	.bmove =	imsttfbcon_bmove,
+	.clear =	imsttfbcon_clear,
+	.putc =		fbcon_cfb24_putc,
+	.putcs =	fbcon_cfb24_putcs,
+	.revc =		imsttfbcon_revc,
+	.cursor =	imsttfbcon_cursor,
+	.set_font =	imsttfbcon_set_font,
+	.clear_margins =fbcon_cfb24_clear_margins,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
 static struct display_switch fbcon_imstt32 = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		imsttfbcon_bmove,
-	clear:		imsttfbcon_clear,
-	putc:		fbcon_cfb32_putc,
-	putcs:		fbcon_cfb32_putcs,
-	revc:		imsttfbcon_revc,
-	cursor:		imsttfbcon_cursor,
-	set_font:	imsttfbcon_set_font,
-	clear_margins:	fbcon_cfb32_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb32_setup,
+	.bmove =	imsttfbcon_bmove,
+	.clear =	imsttfbcon_clear,
+	.putc =		fbcon_cfb32_putc,
+	.putcs =	fbcon_cfb32_putcs,
+	.revc =		imsttfbcon_revc,
+	.cursor =	imsttfbcon_cursor,
+	.set_font =	imsttfbcon_set_font,
+	.clear_margins =fbcon_cfb32_clear_margins,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -1617,23 +1617,23 @@
 MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl);
 
 static struct pci_driver imsttfb_pci_driver = {
-	name:		"imsttfb",
-	id_table:	imsttfb_pci_tbl,
-	probe:		imsttfb_probe,
-	remove:		__devexit_p(imsttfb_remove),
+	.name =		"imsttfb",
+	.id_table =	imsttfb_pci_tbl,
+	.probe =	imsttfb_probe,
+	.remove =	__devexit_p(imsttfb_remove),
 };
 
 static struct fb_ops imsttfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	imsttfb_get_fix,
-	fb_get_var:	imsttfb_get_var,
-	fb_set_var:	imsttfb_set_var,
-	fb_get_cmap:	imsttfb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	imsttfb_setcolreg,
-	fb_pan_display:	imsttfb_pan_display,
-	fb_blank:	imsttfb_blank,
-	fb_ioctl:	imsttfb_ioctl,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	imsttfb_get_fix,
+	.fb_get_var =	imsttfb_get_var,
+	.fb_set_var =	imsttfb_set_var,
+	.fb_get_cmap =	imsttfb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	imsttfb_setcolreg,
+	.fb_pan_display =imsttfb_pan_display,
+	.fb_blank =	imsttfb_blank,
+	.fb_ioctl =	imsttfb_ioctl,
 };
 
 static int
diff -Nru a/drivers/video/leofb.c b/drivers/video/leofb.c
--- a/drivers/video/leofb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/leofb.c	Tue Aug 27 12:28:08 2002
@@ -451,13 +451,13 @@
 }
 
 static struct display_switch leo_dispsw __initdata = {
-	setup:		leo_setup,
-	bmove:		fbcon_redraw_bmove,
-	clear:		leo_clear,
-	putc:		leo_putc,
-	putcs:		leo_putcs,
-	revc:		leo_revc, 
-	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
+	.setup =	leo_setup,
+	.bmove =	fbcon_redraw_bmove,
+	.clear =	leo_clear,
+	.putc =		leo_putc,
+	.putcs =	leo_putcs,
+	.revc =		leo_revc, 
+	.fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
 };
 
 static void leo_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
diff -Nru a/drivers/video/macfb.c b/drivers/video/macfb.c
--- a/drivers/video/macfb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/macfb.c	Tue Aug 27 12:27:59 2002
@@ -58,21 +58,29 @@
 #define CSC_BASE 0x50F20000
 
 static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
-				unsigned int green, unsigned int blue) = NULL;
+				unsigned int green, unsigned int blue,
+				struct fb_info *info) = NULL;
 static int valkyrie_setpalette (unsigned int regno, unsigned int red,
-				unsigned int green, unsigned int blue);
+				unsigned int green, unsigned int blue,
+				struct fb_info *info);
 static int dafb_setpalette (unsigned int regno, unsigned int red,
-			    unsigned int green, unsigned int blue);
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *fb_info);
 static int rbv_setpalette (unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue);
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
 static int mdc_setpalette (unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue);
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
 static int toby_setpalette (unsigned int regno, unsigned int red,
-			    unsigned int green, unsigned int blue);
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *fb_info);
 static int civic_setpalette (unsigned int regno, unsigned int red,
-			     unsigned int green, unsigned int blue);
+			     unsigned int green, unsigned int blue,
+			     struct fb_info *fb_info);
 static int csc_setpalette (unsigned int regno, unsigned int red,
-			     unsigned int green, unsigned int blue);
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
 
 static volatile struct {
 	unsigned char addr;
@@ -148,31 +156,32 @@
 static int  video_slot = 0;
 
 static struct fb_var_screeninfo macfb_defined = {
-	bits_per_pixel:	8,	
-	activae:	FB_ACTIVATE_NOW,
-	width:		-1,
-	height:		-1,
-	right_margin:	32,
-	upper_margin:	16,
-	lower_margin:	4,
-	vsync_len:	4,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.bits_per_pixel	= 8,	
+	.activate	= FB_ACTIVATE_NOW,
+	.width		= -1,
+	.height		= -1,
+	.right_margin	= 32,
+	.upper_margin	= 16,
+	.lower_margin	= 4,
+	.vsync_len	= 4,
+	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vesafb_fix = {
-	id:	"Macintosh ",
-	type:	FB_TYPE_PACKED_PIXELS,
-	accel:	FB_ACCEL_NONE,
+static struct fb_fix_screeninfo macfb_fix = {
+	.id	= "Macintosh ",
+	.type	= FB_TYPE_PACKED_PIXELS,
+	.accel	= FB_ACCEL_NONE,
 };
 
 static struct display disp;
 static struct fb_info fb_info;
 static u32 pseudo_palette[17];
-static int             inverse   = 0;
-static int             vidtest   = 0;
+static int inverse   = 0;
+static int vidtest   = 0;
 
 static int valkyrie_setpalette (unsigned int regno, unsigned int red,
-				unsigned int green, unsigned int blue)
+				unsigned int green, unsigned int blue,
+				struct fb_info *info)
 {
 	unsigned long flags;
 	
@@ -180,8 +189,7 @@
 	green >>= 8;
 	blue >>= 8;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	/* tell clut which address to fill */
 	nubus_writeb(regno, &valkyrie_cmap_regs->addr);
@@ -194,8 +202,7 @@
 	nop();
 	nubus_writeb(blue, &valkyrie_cmap_regs->lut);
 
-	restore_flags(flags);
-
+	local_irq_restore(flags);
 	return 0;
 }
 
@@ -204,7 +211,8 @@
    kidding!) and simply set them one by one until we hit the one we
    want. */
 static int dafb_setpalette (unsigned int regno, unsigned int red,
-			    unsigned int green, unsigned int blue)
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *info)
 {
 	/* FIXME: really, really need to use ioremap() here,
            phys_to_virt() doesn't work anymore */
@@ -215,8 +223,7 @@
 	green >>= 8;
 	blue >>= 8;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	/* fbcon will set an entire colourmap, but X won't.  Hopefully
 	   this should accomodate both of them */
@@ -229,11 +236,11 @@
 		
 		/* Loop until we get to the register we want */
 		for (i = 0; i < regno; i++) {
-			nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(info->cmap[i].red >> 8, &dafb_cmap_regs->lut);
 			nop();
-			nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(info->cmap[i].green >> 8, &dafb_cmap_regs->lut);
 			nop();
-			nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(info->cmap[i].blue >> 8, &dafb_cmap_regs->lut);
 			nop();
 		}
 	}
@@ -244,26 +251,26 @@
 	nop();
 	nubus_writeb(blue, &dafb_cmap_regs->lut);
 	
-	restore_flags(flags);
-	
+	local_irq_restore(flags);
 	lastreg = regno;
 	return 0;
 }
 
 /* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
 static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
-				 unsigned int green, unsigned int blue)
+				 unsigned int green, unsigned int blue,
+				 struct fb_info *info)	
 {
+	unsigned int bpp = info->var.bits_per_pixel;
 	unsigned char _red  =red>>8;
 	unsigned char _green=green>>8;
 	unsigned char _blue =blue>>8;
 	unsigned char _regno;
 	unsigned long flags;
 
-	if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
+	if (bpp > 8) return 1; /* failsafe */
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 
 	/* On these chips, the CLUT register numbers are spread out
 	   across the register space.  Thus:
@@ -273,7 +280,7 @@
 	   In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
 	   
 	   In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
-  	_regno = (regno<<(8 - info->var.bits_per_pixel)) | (0xFF >> info->var.vits_per_pixel);
+  	_regno = (regno << (8 - bpp)) | (0xFF >> bpp);
 	nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
 
 	/* send one color channel at a time */
@@ -281,13 +288,13 @@
 	nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
 	nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
 
-	restore_flags(flags);
-	
+	local_irq_restore(flags);	
 	return 0;
 }
 
 static int rbv_setpalette (unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue)
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info)
 {
 	/* use MSBs */
 	unsigned char _red  =red>>8;
@@ -298,8 +305,7 @@
 
 	if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	/* From the VideoToolbox driver.  Seems to be saying that
 	 * regno #254 and #255 are the important ones for 1-bit color,
@@ -318,14 +324,14 @@
 	nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
 	nubus_writeb(_blue,  &rbv_cmap_regs->lut);
 	
-	restore_flags(flags);
-	/* done. */
+	local_irq_restore(flags); /* done. */
 	return 0;
 }
 
 /* Macintosh Display Card (8x24) */
 static int mdc_setpalette(unsigned int regno, unsigned int red,
-			  unsigned int green, unsigned int blue)
+			  unsigned int green, unsigned int blue,
+			  struct fb_info *info)
 {
 	volatile struct mdc_cmap_regs *cmap_regs =
 		nubus_slot_addr(video_slot);
@@ -336,8 +342,7 @@
 	unsigned char _regno=regno;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	/* the nop's are there to order writes. */
 	nubus_writeb(_regno, &cmap_regs->addr); nop();
@@ -345,38 +350,40 @@
 	nubus_writeb(_green, &cmap_regs->lut);  nop();
 	nubus_writeb(_blue, &cmap_regs->lut);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 	return 0;
 }
 
 /* Toby frame buffer */
 static int toby_setpalette(unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue)
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info) 
 {
 	volatile struct toby_cmap_regs *cmap_regs =
 		nubus_slot_addr(video_slot);
+	unsigned int bpp = info->var.bits_per_pixel;
 	/* use MSBs */
 	unsigned char _red  =~(red>>8);
 	unsigned char _green=~(green>>8);
 	unsigned char _blue =~(blue>>8);
-	unsigned char _regno = (regno << (8 - info->var.bits_per_pixel)) | (0xFF >> info->var.bits_per_pixel);
+	unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	
+	local_irq_save(flags);
+		
 	nubus_writeb(_regno, &cmap_regs->addr); nop();
 	nubus_writeb(_red, &cmap_regs->lut);    nop();
 	nubus_writeb(_green, &cmap_regs->lut);  nop();
 	nubus_writeb(_blue, &cmap_regs->lut);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 	return 0;
 }
 
 /* Jet frame buffer */
 static int jet_setpalette(unsigned int regno, unsigned int red,
-			  unsigned int green, unsigned int blue)
+			  unsigned int green, unsigned int blue,
+			  struct fb_info *info)
 {
 	volatile struct jet_cmap_regs *cmap_regs =
 		nubus_slot_addr(video_slot);
@@ -386,15 +393,14 @@
 	unsigned char _blue  = (blue>>8);
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	nubus_writeb(regno, &cmap_regs->addr); nop();
 	nubus_writeb(_red, &cmap_regs->lut); nop();
 	nubus_writeb(_green, &cmap_regs->lut); nop();
 	nubus_writeb(_blue, &cmap_regs->lut);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 	return 0;
 }
 
@@ -410,7 +416,8 @@
  * FIXME: this doesn't seem to work anymore.
  */
 static int civic_setpalette (unsigned int regno, unsigned int red,
-			     unsigned int green, unsigned int blue)
+			     unsigned int green, unsigned int blue,
+			     struct fb_info *info)
 {
 	static int lastreg = -1;
 	unsigned long flags;
@@ -422,8 +429,7 @@
 	green >>= 8;
 	blue  >>= 8;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	
 	/*
 	 * Set the register address
@@ -437,7 +443,7 @@
 #if 0
 	{
 #define CIVIC_VBL_OFFSET	0x120
-		volatile unsigned long *vbl = readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
+		volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
 		/* do interrupt setup stuff here? */
 		*vbl = 0L; nop();	/* clear */
 		*vbl = 1L; nop();	/* set */
@@ -491,8 +497,7 @@
 		nubus_writeb( junk, &civic_cmap_regs->lut); nop();
 	}
 
-	restore_flags(flags);
-
+	local_irq_restore(flags);
 	lastreg = regno;
 	return 0;
 }
@@ -504,7 +509,8 @@
  */
 
 static int csc_setpalette (unsigned int regno, unsigned int red,
-			     unsigned int green, unsigned int blue)
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info)
 {
 	mdelay(1);
 	csc_cmap_regs->clut_waddr = regno;
@@ -533,20 +539,10 @@
 		/* We shouldn't get here */
 		break;
 	case 2:
-		if (macfb_setpalette)
-			macfb_setpalette(regno, red, green, blue);
-		else
-			return 1;
-		break;
 	case 4:
-		if (macfb_setpalette)
-			macfb_setpalette(regno, red, green, blue);
-		else
-			return 1;
-		break;
 	case 8:
 		if (macfb_setpalette)
-			macfb_setpalette(regno, red, green, blue);
+			macfb_setpalette(regno, red, green, blue, info);
 		else
 			return 1;
 		break;
@@ -591,16 +587,14 @@
 }
 
 static struct fb_ops macfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	macfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= macfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 void __init macfb_setup(char *options, int *ints)
@@ -652,7 +646,7 @@
 	printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
 	       macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024);
 	printk("macfb: mode is %dx%dx%d, linelength=%d\n",
-	       macfb_defined.xres, macfb_defined.yres/, macfb_defined.bits_per_pixel, macfb_fix.line_length);
+	       macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length);
 	
 	/*
 	 *	Fill in the available video resolution
@@ -968,11 +962,11 @@
 	fb_info.disp		= &disp;
 	fb_info.switch_con	= gen_switch;
 	fb_info.updatevar	= gen_update_var;
-	fb_info.pseudo_palatte	= pseudo_palette;
+	fb_info.pseudo_palette	= pseudo_palette;
 	fb_info.flags		= FBINFO_FLAG_DEFAULT;
 
 	fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
-	gen_set_disp(-1, info);
+	gen_set_disp(-1, &fb_info);
 	
 	if (register_framebuffer(&fb_info) < 0)
 		return;
diff -Nru a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile
--- a/drivers/video/matrox/Makefile	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/matrox/Makefile	Tue Aug 27 12:28:02 2002
@@ -5,16 +5,16 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o
+export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o matroxfb_g450.o
 
 # Each configuration option enables a list of files.
 
-my-obj-$(CONFIG_FB_MATROX_G100)	  := g450_pll.o
+my-obj-$(CONFIG_FB_MATROX_G100)	  += g450_pll.o
+my-obj-$(CONFIG_FB_MATROX_G450)   += matroxfb_g450.o matroxfb_crtc2.o
 
 obj-$(CONFIG_FB_MATROX)           += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
 obj-$(CONFIG_FB_MATROX_I2C)       += i2c-matroxfb.o
 obj-$(CONFIG_FB_MATROX_MAVEN)     += matroxfb_maven.o matroxfb_crtc2.o
-obj-$(CONFIG_FB_MATROX_G450)	  += matroxfb_g450.o matroxfb_crtc2.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
--- a/drivers/video/matrox/g450_pll.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/matrox/g450_pll.c	Tue Aug 27 12:28:08 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
  *
- * (c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file COPYING in the main directory of this archive for
@@ -33,6 +33,10 @@
 	return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
 }
 
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
+	return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
+}
+
 static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
 	if (f2 < f1) {
     		f2 = f1 - f2;
@@ -52,40 +56,42 @@
 	m = (mnp >> 16) & 0xFF;
 	p = mnp & 0xFF;
 
-	if (m == 0 || m == 0xFF) {
-		if (m == 0) {
-			if (p & 0x40) {
-				return NO_MORE_MNP;
+	do {
+		if (m == 0 || m == 0xFF) {
+			if (m == 0) {
+				if (p & 0x40) {
+					return NO_MORE_MNP;
+				}
+			        if (p & 3) {
+					p--;
+				} else {
+					p = 0x40;
+				}
+				tvco >>= 1;
+				if (tvco < pi->vcomin) {
+					return NO_MORE_MNP;
+				}
+				*fvco = tvco;
 			}
-		        if (p & 3) {
-				p--;
+
+			p &= 0x43;
+			if (tvco < 550000) {
+/*				p |= 0x00; */
+			} else if (tvco < 700000) {
+				p |= 0x08;
+			} else if (tvco < 1000000) {
+				p |= 0x10;
+			} else if (tvco < 1150000) {
+				p |= 0x18;
 			} else {
-				p = 0x40;
+				p |= 0x20;
 			}
-			tvco >>= 1;
-			if (tvco < pi->vcomin) {
-				return NO_MORE_MNP;
-			}
-			*fvco = tvco;
-		}
-
-		p &= 0x43;
-		if (tvco < 550000) {
-/*			p |= 0x00; */
-		} else if (tvco < 700000) {
-			p |= 0x08;
-		} else if (tvco < 1000000) {
-			p |= 0x10;
-		} else if (tvco < 1150000) {
-			p |= 0x18;
+			m = 9;
 		} else {
-			p |= 0x20;
+			m--;
 		}
-		m = 9;
-	} else {
-		m--;
-	}
-        n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+        	n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+	} while (n < 0x03 || n > 0x7A);
 	return (m << 16) | (n << 8) | p;
 }
 
@@ -219,7 +225,7 @@
 	}
 }
 
-static inline void g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
 	if (g450_cmppll(PMINFO mnp, pll)) {
 		g450_setpll(PMINFO mnp, pll);
 	}
@@ -385,10 +391,8 @@
 			unsigned int vco;
 			unsigned int delta;
 
-			if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
-				continue;
-			}
 			vco = g450_mnp2vco(PMINFO mnp);
+#if 0			
 			if (pll == M_VIDEO_PLL) {
 				unsigned int big, small;
 
@@ -406,6 +410,7 @@
 					continue;
 				}
 			}
+#endif			
 			delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
 			for (idx = mnpcount; idx > 0; idx--) {
 				/* == is important; due to nextpll algorithm we get
@@ -426,7 +431,7 @@
 	}
 	/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
 	if (!mnpcount) {
-		return 1;
+		return -EBUSY;
 	}
 	{
 		unsigned long flags;
@@ -435,15 +440,15 @@
 		matroxfb_DAC_lock_irqsave(flags);
 		mnp = g450_checkcache(PMINFO ci, mnparray[0]);
 		if (mnp != NO_MORE_MNP) {
-			g450_setpll_cond(PMINFO mnp, pll);
+			matroxfb_g450_setpll_cond(PMINFO mnp, pll);
 		} else {
 			mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
 			g450_addcache(ci, mnparray[0], mnp);
 		}
 		updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
 		matroxfb_DAC_unlock_irqrestore(flags);
+		return mnp;
 	}
-	return 0;
 }
 
 /* It must be greater than number of possible PLL values.
@@ -465,8 +470,10 @@
 }
 
 EXPORT_SYMBOL(matroxfb_g450_setclk);
+EXPORT_SYMBOL(g450_mnp2f);
+EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
 
-MODULE_AUTHOR("(c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/matrox/g450_pll.h b/drivers/video/matrox/g450_pll.h
--- a/drivers/video/matrox/g450_pll.h	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/matrox/g450_pll.h	Tue Aug 27 12:28:06 2002
@@ -4,5 +4,7 @@
 #include "matroxfb_base.h"
 
 int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
 
 #endif	/* __G450_PLL_H__ */
diff -Nru a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
--- a/drivers/video/matrox/i2c-matroxfb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/matrox/i2c-matroxfb.c	Tue Aug 27 12:28:05 2002
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.51 2001/01/19
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -30,6 +30,12 @@
 
 /******************************************************/
 
+struct matroxfb_dh_maven_info {
+	struct i2c_bit_adapter	maven;
+	struct i2c_bit_adapter	ddc1;
+	struct i2c_bit_adapter	ddc2;
+};
+
 static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
 	unsigned long flags;
 	int v;
@@ -40,7 +46,7 @@
 	return v;
 }
 
-static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
 	unsigned long flags;
 	int v;
 
@@ -53,7 +59,7 @@
 }
 
 /* software I2C functions */
-static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
 	if (state)
 		state = 0;
 	else
@@ -61,68 +67,24 @@
 	matroxfb_set_gpio(minfo, ~mask, state);
 }
 
-static void matroxfb_maven_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_DATA, state);
-}
-
-static void matroxfb_maven_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_CLK, state);
-}
-
-static int matroxfb_maven_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0;
+static void matroxfb_gpio_setsda(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.data, state);
 }
 
-static int matroxfb_maven_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0;
+static void matroxfb_gpio_setscl(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
 }
 
-static void matroxfb_ddc1_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_DATA, state);
+static int matroxfb_gpio_getsda(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
 }
 
-static void matroxfb_ddc1_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_CLK, state);
-}
-
-static int matroxfb_ddc1_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc1b_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_DATA, state);
-}
-
-static void matroxfb_ddc1b_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_CLK, state);
-}
-
-static int matroxfb_ddc1b_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1b_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc2_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_DATA, state);
-}
-
-static void matroxfb_ddc2_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_CLK, state);
-}
-
-static int matroxfb_ddc2_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc2_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
+static int matroxfb_gpio_getscl(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
 }
 
 static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
@@ -133,97 +95,36 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static struct i2c_adapter matroxmaven_i2c_adapter_template =
+static struct i2c_adapter matrox_i2c_adapter_template =
 {
-	"",
-	I2C_HW_B_G400,
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
+	.id =		I2C_HW_B_G400,
+	.inc_use =	matroxfb_dh_inc_use,
+	.dec_use =	matroxfb_dh_dec_use,
 };
 
-static struct i2c_algo_bit_data matroxmaven_i2c_algo_template =
+static struct i2c_algo_bit_data matrox_i2c_algo_template =
 {
 	NULL,
-	matroxfb_maven_setsda,
-	matroxfb_maven_setscl,
-	matroxfb_maven_getsda,
-	matroxfb_maven_getscl,
+	matroxfb_gpio_setsda,
+	matroxfb_gpio_setscl,
+	matroxfb_gpio_getsda,
+	matroxfb_gpio_getscl,
 	10, 10, 100,
 };
 
-static struct i2c_adapter matrox_ddc1_adapter_template =
-{
-	"",
-	I2C_HW_B_G400, /* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1_algo_template =
-{
-	NULL,
-	matroxfb_ddc1_setsda,
-	matroxfb_ddc1_setscl,
-	matroxfb_ddc1_getsda,
-	matroxfb_ddc1_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1b_algo_template =
-{
-	NULL,
-	matroxfb_ddc1b_setsda,
-	matroxfb_ddc1b_setscl,
-	matroxfb_ddc1b_getsda,
-	matroxfb_ddc1b_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_adapter matrox_ddc2_adapter_template =
-{
-	"",
-	I2C_HW_B_G400,	/* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */
-	matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc2_algo_template =
-{
-	NULL,
-	matroxfb_ddc2_setsda,
-	matroxfb_ddc2_setscl,
-	matroxfb_ddc2_getsda,
-	matroxfb_ddc2_getscl,
-	10, 10, 100,
-};
-
-static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) {
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
+		unsigned int data, unsigned int clock, const char* name) {
 	int err;
 
-	b->adapter.data = minfo;
+	b->minfo = minfo;
+	b->mask.data = data;
+	b->mask.clock = clock;
+	b->adapter = matrox_i2c_adapter_template;
+	sprintf(b->adapter.name, name, GET_FB_IDX(minfo->fbcon.node));
+	b->adapter.data = b;
 	b->adapter.algo_data = &b->bac;
-	b->bac.data = minfo;
+	b->bac = matrox_i2c_algo_template;
+	b->bac.data = b;
 	err = i2c_bit_add_bus(&b->adapter);
 	b->initialized = !err;
 	return err;
@@ -236,50 +137,14 @@
 	}
 }
 
-static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->maven;
-
-	b->adapter = matroxmaven_i2c_adapter_template;
-	b->bac = matroxmaven_i2c_algo_template;
-	sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->maven);
 }
 
-static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
-static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1b_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc1);
 }
 
-static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc2;
-
-	b->adapter = matrox_ddc2_adapter_template;
-	b->bac = matrox_ddc2_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc2);
 }
@@ -299,24 +164,26 @@
 	matroxfb_DAC_unlock_irqrestore(flags);
 
 	memset(m2info, 0, sizeof(*m2info));
-	m2info->maven.minfo = m2info;
-	m2info->ddc1.minfo = m2info;
-	m2info->ddc2.minfo = m2info;
-	m2info->primary_dev = minfo;
-
-	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP)
-		err = i2c_ddc1b_init(m2info);
-	else
-		err = i2c_ddc1_init(m2info);
+
+	switch (ACCESS_FBINFO(chip)) {
+		case MGA_2064:
+		case MGA_2164:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+		default:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+	}
 	if (err)
 		goto fail_ddc1;
-	if (ACCESS_FBINFO(devflags.maven_capable)) {
-		err = i2c_ddc2_init(m2info);
-		if (err)
+	if (ACCESS_FBINFO(devflags.dualhead)) {
+		err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1 on i2c-matroxfb");
+		if (err == -ENODEV) {
+			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
+		} else if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
-		err = i2c_maven_init(m2info);
+		/* Register maven bus even on G450/G550 */
+		err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u on i2c-matroxfb");
 		if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
 	}
@@ -337,10 +204,10 @@
 }
 
 static struct matroxfb_driver i2c_matroxfb = {
-	LIST_HEAD_INIT(i2c_matroxfb.node),
-	"i2c-matroxfb",
-	i2c_matroxfb_probe,
-	i2c_matroxfb_remove,
+	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
+	.name =		"i2c-matroxfb",
+	.probe = 	i2c_matroxfb_probe,
+	.remove =	i2c_matroxfb_remove,
 };
 
 static int __init i2c_matroxfb_init(void) {
@@ -355,7 +222,7 @@
 	matroxfb_unregister_driver(&i2c_matroxfb);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
 
 module_init(i2c_matroxfb_init);
diff -Nru a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
--- a/drivers/video/matrox/matroxfb_DAC1064.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/matrox/matroxfb_DAC1064.c	Tue Aug 27 12:28:05 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.65 2002/08/14
  *
  * See matroxfb_base.c for contributors.
  *
@@ -150,7 +150,7 @@
 	return 0;
 }
 
-static int DAC1064_selhwcursor(WPMINFO struct display* p) {
+static int DAC1064_selhwcursor(WPMINFO2) {
 	ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor;
 	ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont;
 	return 0;
@@ -161,37 +161,20 @@
 	unsigned int p;
 
 	DBG("DAC1064_calcclock")
+	
+	/* only for devices older than G450 */
 
 	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
 	
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		if (fvco <= 300000)		/* 276-324 */
-			;
-		else if (fvco <= 400000)	/* 378-438 */
-			p |= 0x08;
-		else if (fvco <= 550000)	/* 540-567 */
-			p |= 0x10;
-		else if (fvco <= 690000)	/* 675-695 */
-			p |= 0x18;
-		else if (fvco <= 800000)	/* 776-803 */
-			p |= 0x20;
-		else if (fvco <= 891000)	/* 891-891 */
-			p |= 0x28;
-		else if (fvco <= 940000)	/* 931-945 */
-			p |= 0x30;
-		else				/* <959 */
-			p |= 0x38;
-	} else {
-		p = (1 << p) - 1;
-		if (fvco <= 100000)
-			;
-		else if (fvco <= 140000)
-			p |= 0x08;
-		else if (fvco <= 180000)
-			p |= 0x10;
-		else
-			p |= 0x18;
-	}
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
 	*post = p;
 }
 
@@ -293,31 +276,164 @@
 	hw->MXoptionReg = mx;
 }
 
+static void g450_set_plls(WPMINFO2) {
+	u_int32_t c2_ctl;
+	unsigned int pxc;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+	int pixelmnp;
+	int videomnp;
+	
+	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
+	c2_ctl |= 0x0001;			/* Enable CRTC2 */
+	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
+	pixelmnp = ACCESS_FBINFO(crtc1).mnp;
+	videomnp = ACCESS_FBINFO(crtc2).mnp;
+	if (videomnp < 0) {
+		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
+		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
+	} else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
+		c2_ctl |=  0x4002;	/* Use reference directly */
+	} else if (videomnp == pixelmnp) {
+		c2_ctl |=  0x0004;	/* Use pixel PLL */
+	} else {
+		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
+			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
+			   of PIXEL PLL in such case because of VIDEO PLL may be source
+			   of TVO clocks, and chroma subcarrier is derived from its
+			   pixel clocks */
+			pixelmnp += 0x000100;
+		}
+		c2_ctl |=  0x0006;	/* Use video PLL */
+		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
+		
+		outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
+	}
+
+	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
+	if (pixelmnp >= 0) {
+		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
+		
+		outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
+	}
+	if (c2_ctl != hw->crtc2.ctl) {
+		hw->crtc2.ctl = c2_ctl;
+		mga_outl(0x3C10, c2_ctl);
+	}
+
+	pxc = ACCESS_FBINFO(crtc1).pixclock;
+	if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
+		pxc = ACCESS_FBINFO(crtc2).pixclock;
+	}
+	if (ACCESS_FBINFO(chip) == MGA_G550) {
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
+		} else if (pxc < 55000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
+		} else if (pxc < 70000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
+		} else if (pxc < 100000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
+		} else if (pxc < 115000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
+		} else if (pxc < 125000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
+		}
+	} else {
+		/* G450 */
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
+		} else if (pxc < 65000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
+		} else if (pxc < 105000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
+		} else if (pxc < 135000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
+		} else if (pxc < 160000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
+		} else if (pxc < 175000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
+		}
+	}
+}
+
 void DAC1064_global_init(WPMINFO2) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
 
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
-	hw->DACreg[POS1064_XOUTPUTCONN] = 0x01;	/* output #1 enabled */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		if (ACCESS_FBINFO(devflags.g450dac)) {
-			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2;
-			hw->DACreg[POS1064_XOUTPUTCONN] = 0x05;	/* output #1 enabled; CRTC1 connected to output #2 */
-		} else {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
+		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
+		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		switch (ACCESS_FBINFO(outputs[0]).src) {
+			case MATROXFB_SRC_CRTC1:
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[1]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
+				} else {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
+				}
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[2]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
+				break;
+			case MATROXFB_SRC_NONE:
+#if 0
+				/* HELP! If we boot without DFP connected to DVI, we can
+				   poweroff TMDS. But if we boot with DFP connected,
+				   TMDS generated clocks are used instead of ALL pixclocks
+				   available... If someone knows which register
+				   handles it, please reveal this secret to me... */			
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
+#endif				
+				break;
+		}
+		/* Now set timming related variables... */
+		g450_set_plls(PMINFO2);
+	} else {
+		if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
-		}
-	} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
-		hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */
-	} else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
-	else
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+		} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+		} else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
+		else
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
 
-	if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
-		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
+			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+	}
 }
 
 void DAC1064_global_restore(WPMINFO2) {
@@ -329,31 +445,32 @@
 		outDAC1064(PMINFO 0x20, 0x04);
 		outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
 		if (ACCESS_FBINFO(devflags.g450dac)) {
-			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);	/* only matrox know... */
-			outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F);	/* powerup everything */
+			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
+			outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+			outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
 			outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
 		}
 	}
 }
 
-static int DAC1064_init_1(WPMINFO struct my_timming* m, struct display *p) {
+static int DAC1064_init_1(WPMINFO struct my_timming* m) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
 
 	DBG("DAC1064_init_1")
 
 	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
-	if (p->type == FB_TYPE_TEXT) {
+	if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 		hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT;
 		hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
 					     | M1064_XMULCTRL_GRAPHICS_PALETIZED;
 	} else {
-		switch (p->var.bits_per_pixel) {
+		switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 		/* case 4: not supported by MGA1064 DAC */
 		case 8:
 			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
 			break;
 		case 16:
-			if (p->var.green.length == 5)
+			if (ACCESS_FBINFO(fbcon).var.green.length == 5)
 				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
 			else
 				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
@@ -368,22 +485,22 @@
 			return 1;	/* unsupported depth */
 		}
 	}
-
-	DAC1064_global_init(PMINFO2);
 	hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
 	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
 	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
 	hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
 	hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
+
+	DAC1064_global_init(PMINFO2);
 	return 0;
 }
 
-static int DAC1064_init_2(WPMINFO struct my_timming* m, struct display* p) {
+static int DAC1064_init_2(WPMINFO struct my_timming* m) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
 
 	DBG("DAC1064_init_2")
 
-	if (p->var.bits_per_pixel > 16) {	/* 256 entries */
+	if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) {	/* 256 entries */
 		int i;
 
 		for (i = 0; i < 256; i++) {
@@ -391,8 +508,8 @@
 			hw->DACpal[i * 3 + 1] = i;
 			hw->DACpal[i * 3 + 2] = i;
 		}
-	} else if (p->var.bits_per_pixel > 8) {
-		if (p->var.green.length == 5) {	/* 0..31, 128..159 */
+	} else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) {
+		if (ACCESS_FBINFO(fbcon).var.green.length == 5) {	/* 0..31, 128..159 */
 			int i;
 
 			for (i = 0; i < 32; i++) {
@@ -471,13 +588,8 @@
 #endif
 }
 
-static int m1064_compute(void* outdev, struct my_timming* m) {
-#define minfo ((struct matrox_fb_info*)outdev)
-#ifdef CONFIG_FB_MATROX_G450
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
-	} else 
-#endif
+static int m1064_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
 	{
 		int i;
 		int tmout;
@@ -504,37 +616,26 @@
 	return 0;
 }
 
-static int m1064_program(void* outdev) {
-	/* nothing, hardware is set in m1064_compute */
-	return 0;
-}
-
-static int m1064_start(void* outdev) {
-	/* nothing */
-	return 0;
-}
-
-static void m1064_incuse(void* outdev) {
-	/* nothing yet; MODULE_INC_USE in future... */
-}
-
-static void m1064_decuse(void* outdev) {
-	/* nothing yet; MODULE_DEC_USE in future... */
-}
+static struct matrox_altout m1064 = {
+	.name	 = "Primary output",
+	.compute = m1064_compute,
+};
 
-static int m1064_setmode(void* outdev, u_int32_t mode) {
-	if (mode != MATROXFB_OUTPUT_MODE_MONITOR)
-		return -EINVAL;
+static int g450_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	if (m->mnp < 0) {
+		m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		if (m->mnp >= 0) {
+			m->pixclock = g450_mnp2f(PMINFO m->mnp);
+		}
+	}
+#undef minfo
 	return 0;
 }
 
-static struct matrox_altout m1064 = {
-	m1064_compute,
-	m1064_program,
-	m1064_start,
-	m1064_incuse,
-	m1064_decuse,
-	m1064_setmode
+static struct matrox_altout g450out = {
+	.name	 = "Primary output",
+	.compute = g450_compute,
 };
 
 #endif /* NEED_DAC1064 */
@@ -545,7 +646,7 @@
 
 	DBG("MGA1064_init")
 
-	if (DAC1064_init_1(PMINFO m, p)) return 1;
+	if (DAC1064_init_1(PMINFO m)) return 1;
 	if (matroxfb_vgaHWinit(PMINFO m, p)) return 1;
 
 	hw->MiscOutReg = 0xCB;
@@ -556,7 +657,7 @@
 	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
 		hw->CRTCEXT[3] |= 0x40;
 
-	if (DAC1064_init_2(PMINFO m, p)) return 1;
+	if (DAC1064_init_2(PMINFO m)) return 1;
 	return 0;
 }
 #endif
@@ -567,7 +668,7 @@
 
 	DBG("MGAG100_init")
 
-	if (DAC1064_init_1(PMINFO m, p)) return 1;
+	if (DAC1064_init_1(PMINFO m)) return 1;
 	hw->MXoptionReg &= ~0x2000;
 	if (matroxfb_vgaHWinit(PMINFO m, p)) return 1;
 
@@ -579,7 +680,7 @@
 	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
 		hw->CRTCEXT[3] |= 0x40;
 
-	if (DAC1064_init_2(PMINFO m, p)) return 1;
+	if (DAC1064_init_2(PMINFO m)) return 1;
 	return 0;
 }
 #endif	/* G100 */
@@ -680,7 +781,10 @@
 	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
 
-	ACCESS_FBINFO(primout) = &m1064;
+	ACCESS_FBINFO(outputs[0]).output = &m1064;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;	/* do not modify settings */
@@ -726,8 +830,13 @@
 	    ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
 		matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
 	} else {
-		/* slow down video clocks... */
-		matroxfb_g450_setclk(PMINFO 0, M_VIDEO_PLL);
+		unsigned long flags;
+		unsigned int pwr;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
+		outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
+		matroxfb_DAC_unlock_irqrestore(flags);
 	}
 	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
 	
@@ -864,7 +973,14 @@
 	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
 			? ACCESS_FBINFO(devflags.sgram) : 1;
 
-	ACCESS_FBINFO(primout) = &m1064;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[0]).output = &g450out;
+	} else {
+		ACCESS_FBINFO(outputs[0]).output = &m1064;
+	}
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		/* we must do this always, BIOS does not do it for us
@@ -895,8 +1011,7 @@
 
 		hw->MXoptionReg |= 0x1080;
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-		mga_outl(M_CTLWTST, 0x00000300);
-		/* mga_outl(M_CTLWTST, 0x03258A31); */
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
 		udelay(100);
 		mga_outb(0x1C05, 0x00);
 		mga_outb(0x1C05, 0x80);
@@ -947,17 +1062,18 @@
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
 
 		if (ACCESS_FBINFO(devflags.memtype) == -1)
-			ACCESS_FBINFO(devflags.memtype) = 0;
-		hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
+			hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
 		if (ACCESS_FBINFO(devflags.sgram))
 			hw->MXoptionReg |= 0x4000;
-		mga_outl(M_CTLWTST, 0x042450A1);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		udelay(200);
 		mga_outl(M_MACCESS, 0x00000000);
 		mga_outl(M_MACCESS, 0x00008000);
 		udelay(100);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		hw->MXoptionReg |= 0x00040020;
 	}
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
diff -Nru a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
--- a/drivers/video/matrox/matroxfb_DAC1064.h	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/matrox/matroxfb_DAC1064.h	Tue Aug 27 12:28:05 2002
@@ -146,6 +146,8 @@
 
 #define M1064_XPWRCTRL		0xA0
 
+#define M1064_XPANMODE		0xA2
+
 enum POS1064 {
 	POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
 	POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
@@ -156,7 +158,7 @@
 	POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
 	POS1064_XCRCBITSEL,
 	POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
-	POS1064_XOUTPUTCONN };
+	POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
 
 
 #endif	/* __MATROXFB_DAC1064_H__ */
diff -Nru a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
--- a/drivers/video/matrox/matroxfb_Ti3026.c	Tue Aug 27 12:27:51 2002
+++ b/drivers/video/matrox/matroxfb_Ti3026.c	Tue Aug 27 12:27:51 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2000/11/29
+ * Version: 1.65 2002/08/14
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -84,6 +84,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define outTi3026 matroxfb_DAC_out
@@ -401,7 +402,7 @@
 	return 0;
 }
 
-static int matroxfb_ti3026_selhwcursor(WPMINFO struct display* p) {
+static int matroxfb_ti3026_selhwcursor(WPMINFO2) {
 	ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
 	ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
 	return 0;
@@ -433,7 +434,7 @@
 	hw->DACclk[1] = pixfeed;
 	hw->DACclk[2] = pixpost | 0xB0;
 
-	if (p->type == FB_TYPE_TEXT) {
+	if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 		hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL;
 		hw->DACclk[3] = 0xFD;
 		hw->DACclk[4] = 0x3D;
@@ -501,7 +502,7 @@
 	DBG("Ti3026_init")
 
 	memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
-	if (p->type == FB_TYPE_TEXT) {
+	if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 		hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;
 		hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
 		hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
@@ -568,7 +569,7 @@
 
 	/* set interleaving */
 	hw->MXoptionReg &= ~0x00001000;
-	if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+	if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
 
 	/* set DAC */
 	Ti3026_setpclk(PMINFO m->pixclock, p);
@@ -811,6 +812,10 @@
 	ti3026_ramdac_init(PMINFO2);
 }
 
+static struct matrox_altout ti3026_output = {
+	.name	 = "Primary output",
+};
+
 static int Ti3026_preinit(WPMINFO2) {
 	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
 					  1024, 1152, 1280,      1600, 1664, 1920,
@@ -828,6 +833,11 @@
 	ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
 	ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
+
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;
diff -Nru a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
--- a/drivers/video/matrox/matroxfb_accel.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/matrox/matroxfb_accel.c	Tue Aug 27 12:28:07 2002
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.51 2001/06/18
+ * Version: 1.65 2002/08/14
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -85,21 +85,21 @@
 
 #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
 
-void matrox_cfbX_init(WPMINFO struct display* p) {
+void matrox_cfbX_init(WPMINFO2) {
 	u_int32_t maccess;
 	u_int32_t mpitch;
 	u_int32_t mopmode;
 
 	DBG("matrox_cfbX_init")
 
-	mpitch = p->var.xres_virtual;
+	mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
 
-	if (p->type == FB_TYPE_TEXT) {
+	if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 		maccess = 0x00000000;
 		mpitch = (mpitch >> 4) | 0x8000; /* set something */
 		mopmode = M_OPMODE_8BPP;
 	} else {
-		switch (p->var.bits_per_pixel) {
+		switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 		case 4:		maccess = 0x00000000;	/* accelerate as 8bpp video */
 				mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
 				mopmode = M_OPMODE_4BPP;
@@ -107,7 +107,7 @@
 		case 8:		maccess = 0x00000000;
 				mopmode = M_OPMODE_8BPP;
 				break;
-		case 16:	if (p->var.green.length == 5)
+		case 16:	if (ACCESS_FBINFO(fbcon).var.green.length == 5)
 					maccess = 0xC0000001;
 				else
 					maccess = 0x40000001;
@@ -816,7 +816,7 @@
 static void matrox_text_setup(struct display* p) {
 	MINFO_FROM_DISP(p);
 
-	p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
+	p->next_line = ACCESS_FBINFO(fbcon).fix.line_length ? ACCESS_FBINFO(fbcon).fix.line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
 	p->next_plane = 0;
 }
 
@@ -1040,7 +1040,7 @@
 		MINFO_FROM_DISP(p);
 
 		matrox_text_round(PMINFO &p->var, p);
-		p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
+		p->next_line = ACCESS_FBINFO(fbcon).fix.line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
 
 		if (p->conp)
 			matrox_text_createcursor(PMINFO p);
@@ -1058,79 +1058,79 @@
 
 #ifdef FBCON_HAS_VGATEXT
 static struct display_switch matroxfb_text = {
-	setup:		matrox_text_setup,
-	bmove:		matrox_text_bmove,
-	clear:		matrox_text_clear,
-	putc:		matrox_text_putc,
-	putcs:		matrox_text_putcs,
-	revc:		matrox_text_revc,
-	cursor:		matrox_text_cursor,
-	set_font:	matrox_text_setfont,
-	fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(9)
+	.setup =	matrox_text_setup,
+	.bmove =	matrox_text_bmove,
+	.clear =	matrox_text_clear,
+	.putc =		matrox_text_putc,
+	.putcs =	matrox_text_putcs,
+	.revc =		matrox_text_revc,
+	.cursor =	matrox_text_cursor,
+	.set_font =	matrox_text_setfont,
+	.fontwidthmask =FONTWIDTH(8)|FONTWIDTH(9)
 };
 #endif
 
 #ifdef FBCON_HAS_CFB4
 static struct display_switch matroxfb_cfb4 = {
-	setup:		fbcon_cfb4_setup,
-	bmove:		matrox_cfb4_bmove,
-	clear:		matrox_cfb4_clear,
-	putc:		fbcon_cfb4_putc,
-	putcs:		fbcon_cfb4_putcs,
-	revc:		matrox_cfb4_revc,
-	fontwidthmask:	FONTWIDTH(8) /* fix, fix, fix it */
+	.setup =	fbcon_cfb4_setup,
+	.bmove =	matrox_cfb4_bmove,
+	.clear =	matrox_cfb4_clear,
+	.putc =		fbcon_cfb4_putc,
+	.putcs =	fbcon_cfb4_putcs,
+	.revc =		matrox_cfb4_revc,
+	.fontwidthmask =FONTWIDTH(8) /* fix, fix, fix it */
 };
 #endif
 
 #ifdef FBCON_HAS_CFB8
 static struct display_switch matroxfb_cfb8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		matrox_cfbX_bmove,
-	clear:		matrox_cfb8_clear,
-	putc:		matrox_cfb8_putc,
-	putcs:		matrox_cfb8_putcs,
-	revc:		matrox_cfb8_revc,
-	clear_margins:	matrox_cfbX_clear_margins,
-	fontwidthmask:	~1 /* FONTWIDTHS */
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	matrox_cfbX_bmove,
+	.clear =	matrox_cfb8_clear,
+	.putc =		matrox_cfb8_putc,
+	.putcs =	matrox_cfb8_putcs,
+	.revc =		matrox_cfb8_revc,
+	.clear_margins =matrox_cfbX_clear_margins,
+	.fontwidthmask =~1 /* FONTWIDTHS */
 };
 #endif
 
 #ifdef FBCON_HAS_CFB16
 static struct display_switch matroxfb_cfb16 = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		matrox_cfbX_bmove,
-	clear:		matrox_cfb16_clear,
-	putc:		matrox_cfb16_putc,
-	putcs:		matrox_cfb16_putcs,
-	revc:		matrox_cfb16_revc,
-	clear_margins:	matrox_cfbX_clear_margins,
-	fontwidthmask:	~1 /* FONTWIDTHS */
+	.setup =	fbcon_cfb16_setup,
+	.bmove =	matrox_cfbX_bmove,
+	.clear =	matrox_cfb16_clear,
+	.putc =		matrox_cfb16_putc,
+	.putcs =	matrox_cfb16_putcs,
+	.revc =		matrox_cfb16_revc,
+	.clear_margins =matrox_cfbX_clear_margins,
+	.fontwidthmask =~1 /* FONTWIDTHS */
 };
 #endif
 
 #ifdef FBCON_HAS_CFB24
 static struct display_switch matroxfb_cfb24 = {
-	setup:		fbcon_cfb24_setup,
-	bmove:		matrox_cfbX_bmove,
-	clear:		matrox_cfb24_clear,
-	putc:		matrox_cfb24_putc,
-	putcs:		matrox_cfb24_putcs,
-	revc:		matrox_cfb24_revc,
-	clear_margins:	matrox_cfbX_clear_margins,
-	fontwidthmask:	~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
+	.setup =	fbcon_cfb24_setup,
+	.bmove =	matrox_cfbX_bmove,
+	.clear =	matrox_cfb24_clear,
+	.putc =		matrox_cfb24_putc,
+	.putcs =	matrox_cfb24_putcs,
+	.revc =		matrox_cfb24_revc,
+	.clear_margins =matrox_cfbX_clear_margins,
+	.fontwidthmask =~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
 };
 #endif
 
 #ifdef FBCON_HAS_CFB32
 static struct display_switch matroxfb_cfb32 = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		matrox_cfbX_bmove,
-	clear:		matrox_cfb32_clear,
-	putc:		matrox_cfb32_putc,
-	putcs:		matrox_cfb32_putcs,
-	revc:		matrox_cfb32_revc,
-	clear_margins:	matrox_cfbX_clear_margins,
-	fontwidthmask:	~1 /* FONTWIDTHS */
+	.setup =	fbcon_cfb32_setup,
+	.bmove =	matrox_cfbX_bmove,
+	.clear =	matrox_cfb32_clear,
+	.putc =		matrox_cfb32_putc,
+	.putcs =	matrox_cfb32_putcs,
+	.revc =		matrox_cfb32_revc,
+	.clear_margins =matrox_cfbX_clear_margins,
+	.fontwidthmask =~1 /* FONTWIDTHS */
 };
 #endif
 
@@ -1144,11 +1144,11 @@
 	if (p->dispsw && p->conp)
 		fb_con.con_cursor(p->conp, CM_ERASE);
 	p->dispsw_data = NULL;
-	if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
-		if (p->type == FB_TYPE_TEXT) {
+	if ((ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
+		if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 			swtmp = &matroxfb_text;
 		} else {
-			switch (p->var.bits_per_pixel) {
+			switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB4
 			case 4:
 				swtmp = &fbcon_cfb4;
@@ -1183,10 +1183,10 @@
 			}
 		}
 		dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
-	} else if (p->type == FB_TYPE_TEXT) {
+	} else if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 		swtmp = &matroxfb_text;
 	} else {
-		switch (p->var.bits_per_pixel) {
+		switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB4
 		case 4:
 			swtmp = &matroxfb_cfb4;
@@ -1222,8 +1222,8 @@
 	}
 	memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
 	p->dispsw = &ACCESS_FBINFO(dispsw);
-	if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
-		ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO p);
+	if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
+		ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO2);
 	}
 }
 
@@ -1233,7 +1233,7 @@
 	int i;
 
 	if (p && p->conp) {
-		if (p->type == FB_TYPE_TEXT) {
+		if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 			matrox_text_createcursor(PMINFO p);
 			matrox_text_loadfont(PMINFO p);
 			i = 0;
diff -Nru a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h
--- a/drivers/video/matrox/matroxfb_accel.h	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/matrox/matroxfb_accel.h	Tue Aug 27 12:28:01 2002
@@ -4,7 +4,7 @@
 #include "matroxfb_base.h"
 
 void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
-void matrox_cfbX_init(WPMINFO struct display* p);
+void matrox_cfbX_init(WPMINFO2);
 void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
 void initMatrox(WPMINFO struct display* p);
 
diff -Nru a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
--- a/drivers/video/matrox/matroxfb_base.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/matrox/matroxfb_base.c	Tue Aug 27 12:28:08 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.65 2002/08/14
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -77,6 +77,15 @@
  *               "Uns Lider" <unslider@miranda.org>
  *                     G100 PLNWT fixes
  *
+ *               "Denis Zaitsev" <zzz@cd-club.ru>
+ *                     Fixes
+ *
+ *               "Mike Pieper" <mike@pieper-family.de>
+ *                     TVOut enhandcements, V4L2 control interface.
+ *
+ *               "Diego Biurrun" <diego@biurrun.de>
+ *                     DFP testing
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -100,6 +109,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_maven.h"
 #include "matroxfb_crtc2.h"
+#include "matroxfb_g450.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
 
@@ -169,11 +179,13 @@
 	if (ACCESS_FBINFO(dead))
 		return;
 
+	ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset;
+	ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset;
 	disp = ACCESS_FBINFO(currcon_display);
-	if (disp->type == FB_TYPE_TEXT) {
-		pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8);
+	if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
+		pos = ACCESS_FBINFO(fbcon).var.yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + ACCESS_FBINFO(fbcon).var.xoffset / (fontwidth(disp)?fontwidth(disp):8);
 	} else {
-		pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+		pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
 		pos += ACCESS_FBINFO(curr.ydstorg.chunks);
 	}
 	p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
@@ -212,6 +224,7 @@
 	}
 	matroxfb_unregister_device(MINFO);
 	unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+	matroxfb_g450_shutdown(PMINFO2);
 	del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 #ifdef CONFIG_MTRR
 	if (ACCESS_FBINFO(mtrr.vram_valid))
@@ -233,7 +246,7 @@
 
 static int matroxfb_open(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_open")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -246,7 +259,7 @@
 
 static int matroxfb_release(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_release")
 
 	if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
@@ -258,7 +271,7 @@
 
 static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
 		struct fb_info* info) {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_pan_display")
 
@@ -284,7 +297,7 @@
 
 static int matroxfb_updatevar(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_updatevar");
 
 	matrox_pan_var(PMINFO &fb_display[con].var);
@@ -404,12 +417,43 @@
 }
 
 static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
+	struct RGBT {
+		unsigned char bpp;
+		struct {
+			unsigned char offset,
+				      length;
+		} red,
+		  green,
+		  blue,
+		  transp;
+		signed char visual;
+	};
+	static const struct RGBT table[]= {
+#if defined FBCON_HAS_VGATEXT
+		{ 0,{ 0,6},{0,6},{0,6},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB4 || defined FBCON_HAS_CFB8
+		{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB16
+		{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
+		{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB24
+		{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB32
+		{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
+#endif
+	};
+	struct RGBT const *rgbt;
+	unsigned int bpp = var->bits_per_pixel;
 	unsigned int vramlen;
 	unsigned int memlen;
 
 	DBG("matroxfb_decode_var")
 
-	switch (var->bits_per_pixel) {
+	switch (bpp) {
 #ifdef FBCON_HAS_VGATEXT
 		case 0:	 if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
 			 break;
@@ -438,22 +482,22 @@
 		var->yres_virtual = var->yres;
 	if (var->xres_virtual < var->xres)
 		var->xres_virtual = var->xres;
-	if (var->bits_per_pixel) {
-		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
-		memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+	if (bpp) {
+		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
+		memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		if (memlen > vramlen) {
-			var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
-			memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+			var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
+			memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		}
 		/* There is hardware bug that no line can cross 4MB boundary */
 		/* give up for CFB24, it is impossible to easy workaround it */
 		/* for other try to do something */
 		if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
-			if (var->bits_per_pixel == 24) {
+			if (bpp == 24) {
 				/* sorry */
 			} else {
 				unsigned int linelen;
-				unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
+				unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
 				unsigned int m2 = PAGE_SIZE;	/* or 128 if you do not need PAGE ALIGNED address */
 				unsigned int max_yres;
 
@@ -497,88 +541,27 @@
 	if (var->yoffset + var->yres > var->yres_virtual)
 		var->yoffset = var->yres_virtual - var->yres;
 
-	if (var->bits_per_pixel == 0) {
-		var->red.offset = 0;
-		var->red.length = 6;
-		var->green.offset = 0;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 6;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel == 4) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel <= 8) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else {
-		if (var->bits_per_pixel <= 16) {
-			if (var->green.length == 5) {
-				var->red.offset    = 10;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 5;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 15;
-				var->transp.length = 1;
-			} else {
-				var->red.offset    = 11;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 6;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 0;
-				var->transp.length = 0;
-			}
-		} else if (var->bits_per_pixel <= 24) {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 0;
-			var->transp.length = 0;
-		} else {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 24;
-			var->transp.length = 8;
-		}
-		dprintk("matroxfb: truecolor: "
-		       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-		       var->transp.length,
-		       var->red.length,
-		       var->green.length,
-		       var->blue.length,
-		       var->transp.offset,
-		       var->red.offset,
-		       var->green.offset,
-		       var->blue.offset);
-		*visual = MX_VISUAL_DIRECTCOLOR;
+	if (bpp == 16 && var->green.length == 5) {
+		bpp--; /* an artifical value - 15 */
 	}
+
+	for (rgbt = table; rgbt->bpp < bpp; rgbt++);
+#define	SETCLR(clr)\
+	var->clr.offset = rgbt->clr.offset;\
+	var->clr.length = rgbt->clr.length
+	SETCLR(red);
+	SETCLR(green);
+	SETCLR(blue);
+	SETCLR(transp);
+#undef	SETCLR
+	*visual = rgbt->visual;
+
+	if (bpp > 8)
+		dprintk("matroxfb: truecolor: "
+			"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+			var->transp.length, var->red.length, var->green.length, var->blue.length,
+			var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
+
 	*video_cmap_len = matroxfb_get_cmap_len(var);
 	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
 				var->xres_virtual, var->yres_virtual);
@@ -589,9 +572,8 @@
 			      unsigned blue, unsigned transp,
 			      struct fb_info *fb_info)
 {
-	struct display* p;
 #ifdef CONFIG_FB_MATROX_MULTIHEAD
-	struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+	struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
 #endif
 
 	DBG("matroxfb_setcolreg")
@@ -611,18 +593,17 @@
 	ACCESS_FBINFO(palette[regno].blue)  = blue;
 	ACCESS_FBINFO(palette[regno].transp) = transp;
 
-	p = ACCESS_FBINFO(currcon_display);
-	if (p->var.grayscale) {
+	if (ACCESS_FBINFO(fbcon).var.grayscale) {
 		/* gray = 0.30*R + 0.59*G + 0.11*B */
 		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
 	}
 
-	red = CNVT_TOHW(red, p->var.red.length);
-	green = CNVT_TOHW(green, p->var.green.length);
-	blue = CNVT_TOHW(blue, p->var.blue.length);
-	transp = CNVT_TOHW(transp, p->var.transp.length);
+	red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length);
+	green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length);
+	blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length);
+	transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length);
 
-	switch (p->var.bits_per_pixel) {
+	switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT)
 #ifdef FBCON_HAS_VGATEXT
 	case 0:
@@ -642,87 +623,54 @@
 #ifdef FBCON_HAS_CFB16
 	case 16:
 		ACCESS_FBINFO(cmap.cfb16[regno]) =
-			(red << p->var.red.offset)     |
-			(green << p->var.green.offset) |
-			(blue << p->var.blue.offset)   |
-			(transp << p->var.transp.offset); /* for 1:5:5:5 */
+			(red << ACCESS_FBINFO(fbcon).var.red.offset)     |
+			(green << ACCESS_FBINFO(fbcon).var.green.offset) |
+			(blue << ACCESS_FBINFO(fbcon).var.blue.offset)   |
+			(transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
 	case 24:
 		ACCESS_FBINFO(cmap.cfb24[regno]) =
-			(red   << p->var.red.offset)   |
-			(green << p->var.green.offset) |
-			(blue  << p->var.blue.offset);
+			(red   << ACCESS_FBINFO(fbcon).var.red.offset)   |
+			(green << ACCESS_FBINFO(fbcon).var.green.offset) |
+			(blue  << ACCESS_FBINFO(fbcon).var.blue.offset);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
 	case 32:
 		ACCESS_FBINFO(cmap.cfb32[regno]) =
-			(red   << p->var.red.offset)   |
-			(green << p->var.green.offset) |
-			(blue  << p->var.blue.offset)  |
-			(transp << p->var.transp.offset);	/* 8:8:8:8 */
+			(red   << ACCESS_FBINFO(fbcon).var.red.offset)   |
+			(green << ACCESS_FBINFO(fbcon).var.green.offset) |
+			(blue  << ACCESS_FBINFO(fbcon).var.blue.offset)  |
+			(transp << ACCESS_FBINFO(fbcon).var.transp.offset);	/* 8:8:8:8 */
 		break;
 #endif
 	}
 	return 0;
 }
 
-static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static void matroxfb_update_fix(WPMINFO2)
 {
-	struct display* p;
+	struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
 	DBG("matroxfb_get_fix")
 
-#define minfo ((struct matrox_fb_info*)info)
-
-	if (ACCESS_FBINFO(dead)) {
-		return -ENXIO;
-	}
-
-	if (con >= 0)
-		p = fb_display + con;
-	else
-		p = ACCESS_FBINFO(fbcon.disp);
-
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
 	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
-	fix->type = p->type;
-	fix->type_aux = p->type_aux;
-	fix->visual = p->visual;
-	fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+	fix->xpanstep = 8;	/* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
 	fix->ypanstep = 1;
 	fix->ywrapstep = 0;
-	fix->line_length = p->line_length;
 	fix->mmio_start = ACCESS_FBINFO(mmio.base);
 	fix->mmio_len = ACCESS_FBINFO(mmio.len);
 	fix->accel = ACCESS_FBINFO(devflags.accelerator);
-	return 0;
-#undef minfo
-}
-
-static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
-	DBG("matroxfb_get_var")
-
-	if(con < 0)
-		*var=ACCESS_FBINFO(fbcon.disp)->var;
-	else
-		*var=fb_display[con].var;
-	return 0;
-#undef minfo
 }
 
 static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	int err;
 	int visual;
 	int cmap_len;
@@ -763,17 +711,19 @@
 	display->var = *var;
 	/* cmap */
 	ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
-	display->visual = visual;
-	display->ypanstep = 1;
-	display->ywrapstep = 0;
-	if (var->bits_per_pixel) {
-		display->type = FB_TYPE_PACKED_PIXELS;
-		display->type_aux = 0;
-		display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
-	} else {
-		display->type = FB_TYPE_TEXT;
-		display->type_aux = ACCESS_FBINFO(devflags.text_type_aux);
-		display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
+	if (display == ACCESS_FBINFO(currcon_display)) {
+		ACCESS_FBINFO(fbcon).var = *var;
+		matroxfb_update_fix(PMINFO2);
+		ACCESS_FBINFO(fbcon).fix.visual = visual;
+		if (var->bits_per_pixel) {
+			ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS;
+			ACCESS_FBINFO(fbcon).fix.type_aux = 0;
+			display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+		} else {
+			ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_TEXT;
+			ACCESS_FBINFO(fbcon).fix.type_aux = ACCESS_FBINFO(devflags.text_type_aux);
+			display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
+		}
 	}
 	display->can_soft_blank = 1;
 	display->inverse = ACCESS_FBINFO(devflags.inverse);
@@ -788,7 +738,7 @@
 		unsigned int pos;
 
 		ACCESS_FBINFO(curr.cmap_len) = cmap_len;
-		if (display->type == FB_TYPE_TEXT) {
+		if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 			/* textmode must be in first megabyte, so no ydstorg allowed */
 			ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
 			ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
@@ -818,8 +768,10 @@
 
 		{	struct my_timming mt;
 			struct matrox_hw_state* hw;
+			int out;
 
 			matroxfb_var2my(var, &mt);
+			mt.crtc = MATROXFB_SRC_CRTC1;
 			/* CRTC1 delays */
 			switch (var->bits_per_pixel) {
 				case  0:	mt.delay = 31 + 0; break;
@@ -834,8 +786,18 @@
 			del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+			up_read(&ACCESS_FBINFO(altout).lock);
+			ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
+			ACCESS_FBINFO(crtc1).mnp = mt.mnp;
 			ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display));
-			if (display->type == FB_TYPE_TEXT) {
+			if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) {
 				if (fontheight(display))
 					pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
 				else
@@ -849,39 +811,23 @@
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
 			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
 			hw->CRTCEXT[8] = pos >> 21;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->compute(MINFO, &mt);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-				up_read(&ACCESS_FBINFO(altout.lock));
-			}
 			ACCESS_FBINFO(hw_switch->restore(PMINFO display));
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->program(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->program) {
+					ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
 			ACCESS_FBINFO(cursor.redraw) = 1;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->start(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->start) {
+					ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
-			matrox_cfbX_init(PMINFO display);
+			up_read(&ACCESS_FBINFO(altout).lock);
+			matrox_cfbX_init(PMINFO2);
 			my_install_cmap(PMINFO2);
 		}
 	}
@@ -896,7 +842,7 @@
 
 	DBG("matrox_getcolreg")
 
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	/*
 	 *  Read a single color register and split it into colors/transparent.
 	 *  Return != 0 for invalid regno.
@@ -916,7 +862,7 @@
 static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			     struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
 					: fb_display + con;
 
@@ -942,7 +888,7 @@
 {
 	unsigned int cmap_len;
 	struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_set_cmap")
 
@@ -982,18 +928,22 @@
 		vblank->flags |= FB_VBLANK_HBLANKING;
 	if (sts1 & 8)
 		vblank->flags |= FB_VBLANK_VSYNCING;
-	if (vblank->vcount >= ACCESS_FBINFO(currcon_display)->var.yres)
+	if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres)
 		vblank->flags |= FB_VBLANK_VBLANKING;
 	vblank->hcount = 0;
 	vblank->count = 0;
 	return 0;
 }
 
+static struct matrox_altout panellink_output = {
+	.name	 = "Panellink output",
+};
+
 static int matroxfb_ioctl(struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg, int con,
 			  struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_ioctl")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -1016,80 +966,74 @@
 		case MATROXFB_SET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					case MATROXFB_OUTPUT_SECONDARY:
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else if (!oproc->verifymode) {
+					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+						val = 0;
+					} else {
 						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val != 1)
-							return val;
-						if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-							matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
-						if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+					}
+				} else {
+					val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
+				}
+				if (!val) {
+					if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
+						ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
+						val = 1;
+					}
+				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val != 1)
+					return val;
+				switch (ACCESS_FBINFO(outputs[mom.output]).src) {
+					case MATROXFB_SRC_CRTC1:
+						matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
+						break;
+					case MATROXFB_SRC_CRTC2:
+						{
 							struct matroxfb_dh_fb_info* crtc2;
 
 							down_read(&ACCESS_FBINFO(crtc2.lock));
-							crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info));
+							crtc2 = ACCESS_FBINFO(crtc2.info);
 							if (crtc2)
-								crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon);
+								crtc2->fbcon.switch_con(crtc2->fbcon.currcon, &crtc2->fbcon);
 							up_read(&ACCESS_FBINFO(crtc2.lock));
 						}
-						return 0;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					default:
-						return -EINVAL;
+						break;
 				}
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					case MATROXFB_OUTPUT_SECONDARY:
-						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val)
-							return val;
-						break;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					default:
-						return -EINVAL;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else {
+					mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
+					val = 0;
 				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val)
+					return val;
 				if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
 					return -EFAULT;
 				return 0;
@@ -1097,52 +1041,109 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int i;
+				int changes;
 
 				if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.sh))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
-					if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
-						return -EINVAL;
-					if (ACCESS_FBINFO(output.sh))
-						return -EINVAL;
+				for (i = 0; i < 32; i++) {
+					if (tmp & (1 << i)) {
+						if (i >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[i]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
 				}
-				if (tmp == ACCESS_FBINFO(output.ph))
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+							return -EINVAL;
+						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+							if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
+								return -EBUSY;
+							}
+						}
+					}
+				}
+				changes = 0;
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (tmp & (1 << i)) {
+						if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
+						}
+					} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.ph) = tmp;
 				matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t conn = 0;
+				int i;
 
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
-				if (put_user(tmp, (u_int32_t*)arg))
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								conn |= 1 << i;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (conn & MATROXFB_OUTPUT_CONN_DFP)
+						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
+						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_ALL_OUTPUTS:
 			{
-				if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 	}
-	return -EINVAL;
+	return -ENOTTY;
 #undef minfo
 }
 
@@ -1150,7 +1151,7 @@
 
 static int matroxfb_blank(int blank, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	int seq;
 	int crtc;
 	CRITFLAGS
@@ -1181,23 +1182,21 @@
 }
 
 static struct fb_ops matroxfb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	matroxfb_open,
-	fb_release:	matroxfb_release,
-	fb_get_fix:	matroxfb_get_fix,
-	fb_get_var:	matroxfb_get_var,
-	fb_set_var:	matroxfb_set_var,
-	fb_get_cmap:	matroxfb_get_cmap,
-	fb_set_cmap:	matroxfb_set_cmap,
-	fb_setcolreg:	matroxfb_setcolreg,
-	fb_pan_display:	matroxfb_pan_display,
-	fb_blank:	matroxfb_blank,
-	fb_ioctl:	matroxfb_ioctl,
+	.owner =	THIS_MODULE,
+	.fb_open =	matroxfb_open,
+	.fb_release =	matroxfb_release,
+	.fb_set_var =	matroxfb_set_var,
+	.fb_get_cmap =	matroxfb_get_cmap,
+	.fb_set_cmap =	matroxfb_set_cmap,
+	.fb_setcolreg =	matroxfb_setcolreg,
+	.fb_pan_display =matroxfb_pan_display,
+	.fb_blank =	matroxfb_blank,
+	.fb_ioctl =	matroxfb_ioctl,
 };
 
 int matroxfb_switch(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (container_of(info, struct matrox_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display *p;
 
@@ -1392,10 +1391,10 @@
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
 #define DEVF_SRCORG		0x0004
-#define DEVF_BOTHDACS		0x0008	/* put CRTC1 on both outputs by default */
+#define DEVF_DUALHEAD		0x0008
 #define DEVF_CROSS4MB		0x0010
 #define DEVF_TEXT4B		0x0020
-#define DEVF_DDC_8_2		0x0040
+/* #define DEVF_recycled	0x0040	*/
 /* #define DEVF_recycled	0x0080	*/
 #define DEVF_SUPPORT32MB	0x0100
 #define DEVF_ANY_VXRES		0x0200
@@ -1405,14 +1404,14 @@
 #define DEVF_PANELLINK_CAPABLE	0x2000
 #define DEVF_G450DAC		0x4000
 
-#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
+#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
 #define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
 #define DEVF_G200	(DEVF_G2CORE)
 #define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
 /* if you'll find how to drive DFP... */
-#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
-#define DEVF_G550	(DEVF_G450 | DEVF_BOTHDACS)
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G550	(DEVF_G450)
 
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
@@ -1606,27 +1605,24 @@
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
 #ifdef CONFIG_FB_MATROX_32MB
-	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+	ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
 #endif
 	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
-	ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
-	ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
+	ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
+	ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
+	ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
 	if (b->flags & DEVF_PANELLINK_CAPABLE) {
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &panellink_output;
 		if (dfp)
-			ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP;
-	}
-	if (b->flags & DEVF_BOTHDACS) {
-#ifdef CONFIG_FB_MATROX_G450	
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-#else
-		printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n");
-		printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n");
-#endif
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		else
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(devflags.panellink) = 1;
 	}
 	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
-	ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC;
+	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
@@ -1732,6 +1728,7 @@
 
 	if (!ACCESS_FBINFO(devflags.novga))
 		request_region(0x3C0, 32, "matrox");
+	matroxfb_g450_connect(PMINFO2);
 	ACCESS_FBINFO(hw_switch->reset(PMINFO2));
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
@@ -1885,6 +1882,7 @@
 	}
 	return 0;
 failVideoIO:;
+	matroxfb_g450_shutdown(PMINFO2);
 	mga_iounmap(ACCESS_FBINFO(video.vbase));
 failCtrlIO:;
 	mga_iounmap(ACCESS_FBINFO(mmio.vbase));
@@ -2072,10 +2070,6 @@
 	init_rwsem(&ACCESS_FBINFO(crtc2.lock));
 	init_rwsem(&ACCESS_FBINFO(altout.lock));
 
-	ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.sh) = 0;
-
 	err = initMatrox2(PMINFO d, b);
 	if (!err) {
 #ifndef CONFIG_FB_MATROX_MULTIHEAD
@@ -2133,10 +2127,10 @@
 
 
 static struct pci_driver matroxfb_driver = {
-	name:		"matroxfb",
-	id_table:	matroxfb_devices,
-	probe:		matroxfb_probe,
-	remove:		pci_remove_matrox,
+	.name =		"matroxfb",
+	.id_table =	matroxfb_devices,
+	.probe =	matroxfb_probe,
+	.remove =	pci_remove_matrox,
 };
 
 /* **************************** init-time only **************************** */
@@ -2489,8 +2483,8 @@
 
 /* *************************** init module code **************************** */
 
-MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450");
+MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(mem, "i");
diff -Nru a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
--- a/drivers/video/matrox/matroxfb_base.h	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/matrox/matroxfb_base.h	Tue Aug 27 12:28:06 2002
@@ -2,7 +2,7 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450
  *
- * (c) 1998,1999,2000,2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  */
 #ifndef __MATROXFB_H__
@@ -288,6 +288,8 @@
 
 struct my_timming {
 	unsigned int pixclock;
+	int mnp;
+	unsigned int crtc;
 	unsigned int HDisplay;
 	unsigned int HSyncStart;
 	unsigned int HSyncEnd;
@@ -364,6 +366,10 @@
 	u_int16_t hcorr;
 };
 
+struct matrox_crtc2 {
+	u_int32_t ctl;
+};
+
 struct matrox_hw_state {
 	u_int32_t	MXoptionReg;
 	unsigned char	DACclk[6];
@@ -381,10 +387,7 @@
 	/* TVOut only */
 	struct mavenregs	maven;
 
-	/* CRTC2 only */
-	/* u_int32_t	TBD */
-
-	unsigned int	vidclk;
+	struct matrox_crtc2	crtc2;
 };
 
 struct matrox_accel_data {
@@ -396,15 +399,17 @@
 };
 
 struct matrox_altout {
+	const char	*name;
 	int		(*compute)(void* altout_dev, struct my_timming* input);
 	int		(*program)(void* altout_dev);
 	int		(*start)(void* altout_dev);
-	void		(*incuse)(void* altout_dev);
-	void		(*decuse)(void* altout_dev);
-	int		(*setmode)(void* altout_dev, u_int32_t mode);
-	int		(*getmode)(void* altout_dev, u_int32_t* mode);
+	int		(*verifymode)(void* altout_dev, u_int32_t mode);
 };
 
+#define MATROXFB_SRC_NONE	0
+#define MATROXFB_SRC_CRTC1	1
+#define MATROXFB_SRC_CRTC2	2
+
 enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
 
 struct matrox_bios {
@@ -421,9 +426,9 @@
 
 struct matrox_switch;
 struct matroxfb_driver;
+struct matroxfb_dh_fb_info;
 
 struct matrox_fb_info {
-	/* fb_info must be first */
 	struct fb_info		fbcon;
 
 	struct list_head	next_fb;
@@ -439,20 +444,25 @@
 	struct pci_dev*		pcidev;
 
 	struct {
-		u_int32_t	all;
-		u_int32_t	ph;
-		u_int32_t	sh;
-			      } output;
-	struct matrox_altout*	primout;
-	struct {
-	struct fb_info*		info;
+		unsigned int	pixclock;
+		int		mnp;
+			      } crtc1;
+	struct {
+		unsigned int 	pixclock;
+		int		mnp;
+	struct matroxfb_dh_fb_info*	info;
 	struct rw_semaphore	lock;
 			      } crtc2;
 	struct {
-	struct matrox_altout*	output;
-	void*			device;
-	struct rw_semaphore	lock;
+ 	struct rw_semaphore	lock;
 			      } altout;
+#define MATROXFB_MAX_OUTPUTS		3
+	struct {
+	unsigned int		src;
+	struct matrox_altout*	output;
+	void*			data;
+	unsigned int		mode;
+			      } outputs[MATROXFB_MAX_OUTPUTS];
 
 #define MATROXFB_MAX_FB_DRIVERS		5
 	struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
@@ -541,6 +551,8 @@
 		int		memtype;
 		int		g450dac;
 		int		dfp_type;
+		int		panellink;	/* G400 DFP possible (not G450/G550) */
+		int		dualhead;
 		unsigned int	fbResource;
 			      } devflags;
 	struct display_switch	dispsw;
@@ -618,7 +630,7 @@
 #define PMINFO   PMINFO2 ,
 
 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
-	return (struct matrox_fb_info*)p->fb_info;
+	return container_of(p->fb_info, struct matrox_fb_info, fbcon);
 }
 
 #define PMXINFO(p)	   mxinfo(p),
@@ -658,7 +670,7 @@
 	void	(*reset)(WPMINFO2);
 	int	(*init)(WPMINFO struct my_timming*, struct display*);
 	void	(*restore)(WPMINFO struct display*);
-	int	(*selhwcursor)(WPMINFO struct display*);
+	int	(*selhwcursor)(WPMINFO2);
 };
 
 struct matroxfb_driver {
diff -Nru a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
--- a/drivers/video/matrox/matroxfb_crtc2.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/matrox/matroxfb_crtc2.c	Tue Aug 27 12:28:02 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.65 2002/08/14
  *
  */
 
@@ -28,7 +28,7 @@
 
 static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
 		unsigned *blue, unsigned *transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	if (regno >= 16)
 		return 1;
 	*red = m2info->palette[regno].red;
@@ -41,8 +41,7 @@
 
 static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
 		unsigned blue, unsigned transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	struct display* p;
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 
 	if (regno >= 16)
 		return 1;
@@ -50,33 +49,32 @@
 	m2info->palette[regno].blue = blue;
 	m2info->palette[regno].green = green;
 	m2info->palette[regno].transp = transp;
-	p = m2info->currcon_display;
-	if (p->var.grayscale) {
+	if (m2info->fbcon.var.grayscale) {
 		/* gray = 0.30*R + 0.59*G + 0.11*B */
 		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
 	}
-	red = CNVT_TOHW(red, p->var.red.length);
-	green = CNVT_TOHW(green, p->var.green.length);
-	blue = CNVT_TOHW(blue, p->var.blue.length);
-	transp = CNVT_TOHW(transp, p->var.transp.length);
+	red = CNVT_TOHW(red, m2info->fbcon.var.red.length);
+	green = CNVT_TOHW(green, m2info->fbcon.var.green.length);
+	blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length);
+	transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length);
 
-	switch (p->var.bits_per_pixel) {
+	switch (m2info->fbcon.var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB16
 		case 16:
 			m2info->cmap.cfb16[regno] =
-				(red << p->var.red.offset)     |
-				(green << p->var.green.offset) |
-				(blue << p->var.blue.offset)   |
-				(transp << p->var.transp.offset);
+				(red << m2info->fbcon.var.red.offset)     |
+				(green << m2info->fbcon.var.green.offset) |
+				(blue << m2info->fbcon.var.blue.offset)   |
+				(transp << m2info->fbcon.var.transp.offset);
 			break;
 #endif
 #ifdef FBCON_HAS_CFB32
 		case 32:
 			m2info->cmap.cfb32[regno] =
-				(red << p->var.red.offset)     |
-				(green << p->var.green.offset) |
-				(blue << p->var.blue.offset)   |
-				(transp << p->var.transp.offset);
+				(red << m2info->fbcon.var.red.offset)     |
+				(green << m2info->fbcon.var.green.offset) |
+				(blue << m2info->fbcon.var.blue.offset)   |
+				(transp << m2info->fbcon.var.transp.offset);
 			break;
 #endif
 	}
@@ -99,10 +97,10 @@
 
 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
 		struct my_timming* mt,
-		struct display* p,
 		int mode,
 		unsigned int pos) {
 	u_int32_t tmp;
+	u_int32_t datactl;
 	MINFO_FROM(m2info->primary_dev);
 
 	switch (mode) {
@@ -117,26 +115,26 @@
 			tmp = 0x00800000;
 			break;
 	}
-
-	if (ACCESS_FBINFO(output.sh)) {
-		tmp |= 0x00000001;	/* enable CRTC2 */
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			if (ACCESS_FBINFO(devflags.g450dac)) {
-				tmp |= 0x00000006; /* source from secondary pixel PLL */
-				/* no vidrst */
-			} else {
-				tmp |= 0x00000002; /* source from VDOCLK */
-				tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
-				/* MGA TVO is our clock source */
+	tmp |= 0x00000001;	/* enable CRTC2 */
+	datactl = 0;
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			tmp |= 0x00000006; /* source from secondary pixel PLL */
+			/* no vidrst when in monitor mode */
+			if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+				tmp |=  0xC0001000; /* Enable H/V vidrst */
 			}
-		} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			tmp |= 0x00000004; /* source from pixclock */
-			/* PIXPLL is our clock source */
-		}
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
-			tmp |= 0x00100000;	/* connect CRTC2 to DAC */
+		} else {
+			tmp |= 0x00000002; /* source from VDOCLK */
+			tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
+			/* MGA TVO is our clock source */
+		}
+	} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		tmp |= 0x00000004; /* source from pixclock */
+		/* PIXPLL is our clock source */
+	}
+	if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		tmp |= 0x00100000;	/* connect CRTC2 to DAC */
 	}
 	if (mt->interlaced) {
 		tmp |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
@@ -145,35 +143,63 @@
 		mt->VSyncEnd >>= 1;
 		mt->VTotal >>= 1;
 	}
-	mga_outl(0x3C10, tmp | 0x10000000);	/* depth and so on... 0x10000000 is VIDRST polarity */
+	if ((mt->HTotal & 7) == 2) {
+		datactl |= 0x00000010;
+		mt->HTotal &= ~7;
+	}
+	tmp |= 0x10000000;	/* 0x10000000 is VIDRST polarity */
 	mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
 	mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
 	mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
 	mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
 	mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart));	/* preload */
 	{
-		u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
-		if (mt->interlaced) {
+		u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3);
+		if (tmp & 0x02000000) {
 			/* field #0 is smaller, so... */
 			mga_outl(0x3C2C, pos);			/* field #1 vmemory start */
 			mga_outl(0x3C28, pos + linelen);	/* field #0 vmemory start */
 			linelen <<= 1;
+			m2info->interlaced = 1;
 		} else {
 			mga_outl(0x3C28, pos);		/* vmemory start */
+			m2info->interlaced = 0;
 		}
 		mga_outl(0x3C40, linelen);
 	}
+	mga_outl(0x3C4C, datactl);	/* data control */
+	if (tmp & 0x02000000) {
+		int i;
+
+		mga_outl(0x3C10, tmp & ~0x02000000);
+		for (i = 0; i < 2; i++) {
+			unsigned int nl;
+			unsigned int lastl = 0;
+
+			while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
+				lastl = nl;
+			}
+		}
+	}
+	mga_outl(0x3C10, tmp);
+	ACCESS_FBINFO(hw).crtc2.ctl = tmp;
+
 	tmp = 0x0FFF0000;		/* line compare */
 	if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
 		tmp |= 0x00000100;
 	if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
 		tmp |= 0x00000200;
 	mga_outl(0x3C44, tmp);
-	mga_outl(0x3C4C, 0);		/* data control */
 }
 
-static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
-		struct display* p) {
+static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
+	MINFO_FROM(m2info->primary_dev);
+
+	mga_outl(0x3C10, 0x00000004);	/* disable CRTC2, CRTC1->DAC1, PLL as clock source */
+	ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
+}
+
+static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
 	/* no acceleration for secondary head... */
 }
 
@@ -182,23 +208,23 @@
 	unsigned int pos;
 	unsigned int linelen;
 	unsigned int pixelsize;
+	MINFO_FROM(m2info->primary_dev);
 
-#define minfo (m2info->primary_dev)
-	pixelsize = var->bits_per_pixel >> 3;
-	linelen = var->xres_virtual * pixelsize;
-	pos = var->yoffset * linelen + var->xoffset * pixelsize;
+	m2info->fbcon.var.xoffset = var->xoffset;
+	m2info->fbcon.var.yoffset = var->yoffset;
+	pixelsize = m2info->fbcon.var.bits_per_pixel >> 3;
+	linelen = m2info->fbcon.var.xres_virtual * pixelsize;
+	pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize;
 	pos += m2info->video.offbase;
-	if (var->vmode & FB_VMODE_INTERLACED) {
+	if (m2info->interlaced) {
 		mga_outl(0x3C2C, pos);
 		mga_outl(0x3C28, pos + linelen);
 	} else {
 		mga_outl(0x3C28, pos);
 	}
-#undef minfo
 }
 
 static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
-		struct display* p,
 		struct fb_var_screeninfo* var,
 		int *visual,
 		int *video_cmap_len,
@@ -277,7 +303,7 @@
 }
 
 static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) {
-	switch (p->var.bits_per_pixel) {
+	switch (m2info->fbcon.var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB16
 		case 16:
 			p->dispsw_data = m2info->cmap.cfb16;
@@ -298,7 +324,7 @@
 }
 
 static int matroxfb_dh_open(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -311,7 +337,7 @@
 }
 
 static int matroxfb_dh_release(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -320,49 +346,24 @@
 #undef m2info
 }
 
-static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
-		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	struct display* p;
+static void matroxfb_dh_update_fix(struct matroxfb_dh_fb_info *m2info) {
+	struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
 
-	if (con >= 0)
-		p = fb_display + con;
-	else
-		p = m2info->fbcon.disp;
-
-	memset(fix, 0, sizeof(*fix));
 	strcpy(fix->id, "MATROX DH");
 
 	fix->smem_start = m2info->video.base;
 	fix->smem_len = m2info->video.len_usable;
-	fix->type = p->type;
-	fix->type_aux = p->type_aux;
-	fix->visual = p->visual;
-	fix->xpanstep = 8;	/* TBD */
 	fix->ypanstep = 1;
 	fix->ywrapstep = 0;
-	fix->line_length = p->line_length;
+	fix->xpanstep = 8;	/* TBD */
 	fix->mmio_start = m2info->mmio.base;
 	fix->mmio_len = m2info->mmio.len;
 	fix->accel = 0;		/* no accel... */
-	return 0;
-#undef m2info
-}
-
-static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
-		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	if (con < 0)
-		*var = m2info->fbcon.disp->var;
-	else
-		*var = fb_display[con].var;
-	return 0;
-#undef m2info
 }
 
 static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 	int chgvar;
 	int visual;
@@ -375,7 +376,7 @@
 		p = m2info->fbcon.disp;
 	else
 		p = fb_display + con;
-	if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0)
+	if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0)
 		return err;
 	switch (var->activate & FB_ACTIVATE_MASK) {
 		case FB_ACTIVATE_TEST:	return 0;
@@ -396,13 +397,15 @@
 		chgvar = 0;
 	p->var = *var;
 	/* cmap */
-	m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
-	p->visual = visual;
-	p->ypanstep = 1;
-	p->ywrapstep = 0;
-	p->type = FB_TYPE_PACKED_PIXELS;
-	p->type_aux = 0;
-	p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+	if (con == m2info->fbcon.currcon) {
+		m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
+		m2info->fbcon.var = *var;
+		m2info->fbcon.fix.visual = visual;
+		m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
+		m2info->fbcon.fix.type_aux = 0;
+		p->next_line = m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+		matroxfb_dh_update_fix(m2info);
+	}
 	p->can_soft_blank = 0;
 	p->inverse = 0;	/* TBD */
 	initMatroxDH(m2info, p);
@@ -411,47 +414,51 @@
 	if (con == m2info->fbcon.currcon) {
 		struct my_timming mt;
 		unsigned int pos;
+		int out;
+		int cnt;
 
-		matroxfb_var2my(var, &mt);
+		matroxfb_var2my(&m2info->fbcon.var, &mt);
+		mt.crtc = MATROXFB_SRC_CRTC2;
 		/* CRTC2 delay */
 		mt.delay = 34;
 
-		pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
+		pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3;
 		pos += m2info->video.offbase;
-		DAC1064_global_init(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->compute(MINFO, &mt);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-			up_read(&ACCESS_FBINFO(altout.lock));
+		cnt = 0;
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+				cnt++;
+				if (ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+		}
+		ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
+		ACCESS_FBINFO(crtc2).mnp = mt.mnp;
+		up_read(&ACCESS_FBINFO(altout).lock);
+		if (cnt) {
+			matroxfb_dh_restore(m2info, &mt, mode, pos);
+		} else {
+			matroxfb_dh_disable(m2info);
 		}
-		matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		DAC1064_global_init(PMINFO2);
 		DAC1064_global_restore(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->program(MINFO);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->start(MINFO);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->program) {
+				ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+			}
+		}
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->start) {
+				ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
-		matroxfb_dh_cfbX_init(m2info, p);
+		up_read(&ACCESS_FBINFO(altout).lock);
+		matroxfb_dh_cfbX_init(m2info);
 		my_install_cmap(m2info);
 	}
 	return 0;
@@ -460,7 +467,7 @@
 
 static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -479,7 +486,7 @@
 
 static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -503,7 +510,7 @@
 
 static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
 	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
 		return -EINVAL;
@@ -525,7 +532,7 @@
 	/* mask out reserved bits + field number (odd/even) */
 	vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
 	/* compatibility stuff */
-	if (vblank->vcount >= m2info->currcon_display->var.yres)
+	if (vblank->vcount >= m2info->fbcon.var.yres)
 		vblank->flags |= FB_VBLANK_VBLANKING;
 	return 0;
 }
@@ -536,7 +543,7 @@
 		unsigned long arg,
 		int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	DBG("matroxfb_crtc2_ioctl")
@@ -563,49 +570,95 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int out;
+				int changes;
 
 				if (get_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.ph))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP)
-					return -EINVAL;
-				if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
-					return -EINVAL;
-				if (tmp == ACCESS_FBINFO(output.sh))
+				for (out = 0; out < 32; out++) {
+					if (tmp & (1 << out)) {
+						if (out >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[out]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+						return -EINVAL;
+					if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
+						return -EBUSY;
+				}
+				changes = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (tmp & (1 << out)) {
+						if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
+						}
+					} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.sh) = tmp;
 				matroxfb_dh_switch(m2info->fbcon.currcon, info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						conn |= 1 << out;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t tmp = 0;
+				int out;
 
-				/* we do not support DFP from CRTC2 */
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
-				/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).output) {
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								tmp |= 1 << out;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
+					if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
+						tmp = 0;
+					}
+				}
 				if (put_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 	}
-	return -EINVAL;
+	return -ENOTTY;
 #undef m2info
 }
 
 static int matroxfb_dh_blank(int blank, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	switch (blank) {
 		case 1:
 		case 2:
@@ -619,22 +672,20 @@
 }
 
 static struct fb_ops matroxfb_dh_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	matroxfb_dh_open,
-	fb_release:	matroxfb_dh_release,
-	fb_get_fix:	matroxfb_dh_get_fix,
-	fb_get_var:	matroxfb_dh_get_var,
-	fb_set_var:	matroxfb_dh_set_var,
-	fb_get_cmap:	matroxfb_dh_get_cmap,
-	fb_set_cmap:	matroxfb_dh_set_cmap,
-	fb_setcolreg:	matroxfb_dh_setcolreg,
-	fb_pan_display:	matroxfb_dh_pan_display,
-	fb_blank:	matroxfb_dh_blank,
-	fb_ioctl:	matroxfb_dh_ioctl,
+	.owner =	THIS_MODULE,
+	.fb_open =	matroxfb_dh_open,
+	.fb_release =	matroxfb_dh_release,
+	.fb_set_var =	matroxfb_dh_set_var,
+	.fb_get_cmap =	matroxfb_dh_get_cmap,
+	.fb_set_cmap =	matroxfb_dh_set_cmap,
+	.fb_setcolreg =	matroxfb_dh_setcolreg,
+	.fb_pan_display =matroxfb_dh_pan_display,
+	.fb_blank =	matroxfb_dh_blank,
+	.fb_ioctl =	matroxfb_dh_ioctl,
 };
 
 static int matroxfb_dh_switch(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display* p;
 
@@ -657,7 +708,7 @@
 }
 
 static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	matroxfb_dh_pan_var(m2info, &fb_display[con].var);
 	return 0;
 #undef m2info
@@ -730,11 +781,10 @@
 	/*
 	 *  If we have unused output, connect CRTC2 to it...
 	 */
-	if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && 
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
-		ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
+	if (ACCESS_FBINFO(outputs[1]).output &&
+	    ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
+	    ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
 	}
 
 	matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
@@ -747,7 +797,7 @@
 	}
 	down_write(&ACCESS_FBINFO(crtc2.lock));
 	oldcrtc2 = ACCESS_FBINFO(crtc2.info);
-	ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
+	ACCESS_FBINFO(crtc2.info) = m2info;
 	up_write(&ACCESS_FBINFO(crtc2.lock));
 	if (oldcrtc2) {
 		printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
@@ -776,16 +826,16 @@
 #define minfo (m2info->primary_dev)
 	if (m2info->fbcon_registered) {
 		int id;
-		struct fb_info* crtc2;
+		struct matroxfb_dh_fb_info* crtc2;
 
 		down_write(&ACCESS_FBINFO(crtc2.lock));
 		crtc2 = ACCESS_FBINFO(crtc2.info);
-		if (crtc2 == &m2info->fbcon)
+		if (crtc2 == m2info)
 			ACCESS_FBINFO(crtc2.info) = NULL;
 		up_write(&ACCESS_FBINFO(crtc2.lock));
-		if (crtc2 != &m2info->fbcon) {
+		if (crtc2 != m2info) {
 			printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
-				crtc2, &m2info->fbcon);
+				crtc2, m2info);
 			printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
 			return;
 		}
@@ -823,12 +873,13 @@
 
 static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
 	matroxfb_dh_deregisterfb(crtc2);
+	kfree(crtc2);
 }
 
 static struct matroxfb_driver crtc2 = {
-		name:	"Matrox G400 CRTC2",
-		probe:	matroxfb_crtc2_probe,
-		remove:	matroxfb_crtc2_remove };
+		.name =		"Matrox G400 CRTC2",
+		.probe =	matroxfb_crtc2_probe,
+		.remove =	matroxfb_crtc2_remove };
 
 static int matroxfb_crtc2_init(void) {
 	matroxfb_register_driver(&crtc2);
@@ -839,7 +890,7 @@
 	matroxfb_unregister_driver(&crtc2);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_crtc2_init);
diff -Nru a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h
--- a/drivers/video/matrox/matroxfb_crtc2.h	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/matrox/matroxfb_crtc2.h	Tue Aug 27 12:28:01 2002
@@ -27,8 +27,9 @@
 		unsigned int	len;
 			      } mmio;
 
-	int			currcon;
 	struct display*		currcon_display;
+	
+	int			interlaced:1;
 
 	union {
 #ifdef FBCON_HAS_CFB16
diff -Nru a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c
--- a/drivers/video/matrox/matroxfb_g450.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/matrox/matroxfb_g450.c	Tue Aug 27 12:28:02 2002
@@ -2,145 +2,418 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/02
  *
  * See matroxfb_base.c for contributors.
  *
  */
 
-#include "matroxfb_g450.h"
+#include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_DAC1064.h"
 #include "g450_pll.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
+#include <asm/div64.h>
 
-static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	ACCESS_FBINFO(hw).vidclk = mt->pixclock;
-#undef minfo
-#undef m2info
-	return 0;
-}
+static void cve2_set_reg(WPMINFO int reg, int val) {
+	unsigned long flags;
 
-static int matroxfb_g450_program(void* md) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL);
-#undef minfo
-#undef m2info	
-	return 0;
-}
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+struct output_desc {
+	unsigned int	h_vis;
+	unsigned int	h_f_porch;
+	unsigned int	h_sync;
+	unsigned int	h_b_porch;
+	unsigned long long int	chromasc;
+	unsigned int	burst;
+	unsigned int	v_total;
+};
 
-static int matroxfb_g450_start(void* md) {
-	return 0;
-}
+static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
+	u_int32_t chromasc;
+	u_int32_t hlen;
+	u_int32_t hsl;
+	u_int32_t hbp;
+	u_int32_t hfp;
+	u_int32_t hvis;
+	unsigned int pixclock;
+	unsigned long long piic;
+	int mnp;
+	int over;
+	
+	r->regs[0x80] = 0x03;	/* | 0x40 for SCART */
 
-static void matroxfb_g450_incuse(void* md) {
-	MOD_INC_USE_COUNT;
-}
+	hvis = ((mt->HDisplay << 1) + 3) & ~3;
+	
+	if (hvis >= 2048) {
+		hvis = 2044;
+	}
+	
+	piic = 1000000000ULL * hvis;
+	do_div(piic, outd->h_vis);
+
+	dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
+	
+	mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
+	
+	mt->mnp = mnp;
+	mt->pixclock = g450_mnp2f(PMINFO mnp);
+
+	dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
+
+	pixclock = 1000000000U / mt->pixclock;
+
+	dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
+
+	piic = outd->chromasc;
+	do_div(piic, mt->pixclock);
+	chromasc = piic;
+	
+	dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
+
+	r->regs[0] = piic >> 24;
+	r->regs[1] = piic >> 16;
+	r->regs[2] = piic >>  8;
+	r->regs[3] = piic >>  0;
+	hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
+	hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
+	hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
+	hlen = hvis + hfp + hsl + hbp;
+	over = hlen & 0x0F;
+	
+	dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
 
-static void matroxfb_g450_decuse(void* md) {
-	MOD_DEC_USE_COUNT;
+	if (over) {
+		hfp -= over;
+		hlen -= over;
+		if (over <= 2) {
+		} else if (over < 10) {
+			hfp += 4;
+			hlen += 4;
+		} else {
+			hfp += 16;
+			hlen += 16;
+		}
+	}
+
+	/* maybe cve2 has requirement 800 < hlen < 1184 */
+	r->regs[0x08] = hsl;
+	r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;	/* burst length */
+	r->regs[0x0A] = hbp;
+	r->regs[0x2C] = hfp;
+	r->regs[0x31] = hvis / 8;
+	r->regs[0x32] = hvis & 7;
+	
+	dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
+
+	r->regs[0x84] = 1;	/* x sync point */
+	r->regs[0x85] = 0;
+	hvis = hvis >> 1;
+	hlen = hlen >> 1;
+	
+	dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
+
+	mt->interlaced = 1;
+
+	mt->HDisplay = hvis & ~7;
+	mt->HSyncStart = mt->HDisplay + 8;
+	mt->HSyncEnd = (hlen & ~7) - 8;
+	mt->HTotal = hlen;
+
+	{
+		int upper;
+		unsigned int vtotal;
+		unsigned int vsyncend;
+		unsigned int vdisplay;
+		
+		vtotal = mt->VTotal;
+		vsyncend = mt->VSyncEnd;
+		vdisplay = mt->VDisplay;
+		if (vtotal < outd->v_total) {
+			unsigned int yovr = outd->v_total - vtotal;
+			
+			vsyncend += yovr >> 1;
+		} else if (vtotal > outd->v_total) {
+			vdisplay = outd->v_total - 4;
+			vsyncend = outd->v_total;
+		}
+		upper = (outd->v_total - vsyncend) >> 1;	/* in field lines */
+		r->regs[0x17] = outd->v_total / 4;
+		r->regs[0x18] = outd->v_total & 3;
+		r->regs[0x33] = upper - 1;	/* upper blanking */
+		r->regs[0x82] = upper;		/* y sync point */
+		r->regs[0x83] = upper >> 8;
+		
+		mt->VDisplay = vdisplay;
+		mt->VSyncStart = outd->v_total - 2;
+		mt->VSyncEnd = outd->v_total;
+		mt->VTotal = outd->v_total;
+	}
 }
 
-static int matroxfb_g450_set_mode(void* md, u_int32_t arg) {
-	if (arg == MATROXFB_OUTPUT_MODE_MONITOR) {
-		return 1;
+static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
+	static const struct output_desc paloutd = {
+		.h_vis	   = 52148148,	// ps
+		.h_f_porch =  1407407,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  5777778,	// ps
+		.chromasc  = 19042247534182ULL,	// 4433618.750 Hz
+		.burst     =  2518518,	// ps
+		.v_total   =      625,
+	};
+	static const struct output_desc ntscoutd = {
+		.h_vis     = 52888889,	// ps
+		.h_f_porch =  1333333,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  4666667,	// ps
+		.chromasc  = 15374030659475ULL,	// 3579545.454 Hz
+		.burst     =  2418418,	// ps
+		.v_total   =      525,	// lines
+	};
+
+	static const struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+//		0x3F, 0x03, /* 0E-0F */
+		0x3C, 0x03,
+		0x3C, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+//		0x89, 0x03, /* 1E-1F */
+		0xAD, 0x03,
+//		0x72,	/* 20 */
+		0xA5,
+		0x07,	/* 21 */
+//		0x72,	/* 22 */
+		0xA5,
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	} };
+	static struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		//0x89, 0x02, /* 1E-1F */
+		0xC0, 0x02, /* 1E-1F */
+		//0x5F,	/* 20 */
+		0x9C,	/* 20 */
+		0x04,	/* 21 */
+		//0x5F,	/* 22 */
+		0x9C,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	} };
+
+	if (norm == MATROXFB_OUTPUT_MODE_PAL) {
+		*data = palregs;
+		*outd = &paloutd;
+	} else {
+  		*data = ntscregs;
+		*outd = &ntscoutd;
 	}
-	return -EINVAL;
+ 	return;
 }
 
-static int matroxfb_g450_get_mode(void* md, u_int32_t* arg) {
-	*arg = MATROXFB_OUTPUT_MODE_MONITOR;
-	return 0;
+#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
+static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
+	int i;
+
+	LR(0x80);
+	LR(0x82); LR(0x83);
+	LR(0x84); LR(0x85);
+	
+	cve2_set_reg(PMINFO 0x3E, 0x01);
+	
+	for (i = 0; i < 0x3E; i++) {
+		LR(i);
+	}
+	cve2_set_reg(PMINFO 0x3E, 0x00);
 }
 
-static struct matrox_altout matroxfb_g450_altout = {
-	matroxfb_g450_compute,
-	matroxfb_g450_program,
-	matroxfb_g450_start,
-	matroxfb_g450_incuse,
-	matroxfb_g450_decuse,
-	matroxfb_g450_set_mode,
-	matroxfb_g450_get_mode
-};
+static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
 
-static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+	dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
 
-	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = m2info;
-	ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout;
-	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-	matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), (struct fb_info*)MINFO);	
+	if (mt->crtc == MATROXFB_SRC_CRTC2 &&
+	    ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		const struct output_desc* outd;
+
+		cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
+		computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
+	} else if (mt->mnp < 0) {
+		/* We must program clocks before CRTC2, otherwise interlaced mode
+		   startup may fail */
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
+	dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
 	return 0;
 }
 
-static void matroxfb_g450_shutdown(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+static int matroxfb_g450_program(void* md) {
+	MINFO_FROM(md);
 	
-	if (MINFO) {
-		ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&ACCESS_FBINFO(altout.lock));
-		ACCESS_FBINFO(altout.device) = NULL;
-		ACCESS_FBINFO(altout.output) = NULL;
-		up_write(&ACCESS_FBINFO(altout.lock));
-		m2info->primary_dev = NULL;
+	if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
 	}
+	return 0;
 }
 
-/* we do not have __setup() yet */
-static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) {
-	struct matroxfb_g450_info* m2info;
-
-	/* hardware is not G450... */
-	if (!ACCESS_FBINFO(devflags.g450dac))
-		return NULL;
-	m2info = (struct matroxfb_g450_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
-	if (!m2info) {
-		printk(KERN_ERR "matroxfb_g450: Not enough memory for G450 DAC control structs\n");
-		return NULL;
-	}
-	memset(m2info, 0, sizeof(*m2info));
-	m2info->primary_dev = MINFO;
-	if (matroxfb_g450_connect(m2info)) {
-		kfree(m2info);
-		printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n");
-		return NULL;
+static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
 	}
-	return m2info;
+	return -EINVAL;
 }
 
-static void matroxfb_g450_remove(struct matrox_fb_info* minfo, void* g450) {
-	matroxfb_g450_shutdown(g450);
-	kfree(g450);
+static int g450_dvi_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
+
+	if (mt->mnp < 0) {
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
+	return 0;
 }
 
-static struct matroxfb_driver g450 = {
-		name:	"Matrox G450 output #2",
-		probe:	matroxfb_g450_probe,
-		remove:	matroxfb_g450_remove };
+static struct matrox_altout matroxfb_g450_altout = {
+	.name		= "Secondary output",
+	.compute	= matroxfb_g450_compute,
+	.program	= matroxfb_g450_program,
+	.verifymode	= matroxfb_g450_verify_mode,
+};
 
-static int matroxfb_g450_init(void) {
-	matroxfb_register_driver(&g450);
-	return 0;
+static struct matrox_altout matroxfb_g450_dvi = {
+	.name		= "DVI output",
+	.compute	= g450_dvi_compute,
+};
+
+void matroxfb_g450_connect(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[1]).data = MINFO;
+		ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
 }
 
-static void matroxfb_g450_exit(void) {
-	matroxfb_unregister_driver(&g450);
+void matroxfb_g450_shutdown(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).output = NULL;
+		ACCESS_FBINFO(outputs[2]).data = NULL;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
 }
 
-MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Matrox G450 secondary output driver");
+EXPORT_SYMBOL(matroxfb_g450_connect);
+EXPORT_SYMBOL(matroxfb_g450_shutdown);
+
+MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 output driver");
 MODULE_LICENSE("GPL");
-module_init(matroxfb_g450_init);
-module_exit(matroxfb_g450_exit);
diff -Nru a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h
--- a/drivers/video/matrox/matroxfb_g450.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/matrox/matroxfb_g450.h	Tue Aug 27 12:28:08 2002
@@ -1,12 +1,14 @@
 #ifndef __MATROXFB_G450_H__
 #define __MATROXFB_G450_H__
 
-#include <linux/ioctl.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_g450_info {
-	struct matrox_fb_info*	primary_dev;
-	unsigned int		timmings;
-};
+#ifdef CONFIG_FB_MATROX_G450
+void matroxfb_g450_connect(WPMINFO2);
+void matroxfb_g450_shutdown(WPMINFO2);
+#else
+static inline void matroxfb_g450_connect(WPMINFO2) { };
+static inline void matroxfb_g450_shutdown(WPMINFO2) { };
+#endif
 
-#endif /* __MATROXFB_MAVEN_H__ */
+#endif /* __MATROXFB_G450_H__ */
diff -Nru a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
--- a/drivers/video/matrox/matroxfb_maven.c	Tue Aug 27 12:27:45 2002
+++ b/drivers/video/matrox/matroxfb_maven.c	Tue Aug 27 12:27:45 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -22,18 +22,12 @@
 
 #define MAVEN_I2CID	(0x1B)
 
-#define MODE_PAL	MATROXFB_OUTPUT_MODE_PAL
-#define MODE_NTSC	MATROXFB_OUTPUT_MODE_NTSC
-#define MODE_TV(x)	(((x) == MODE_PAL) || ((x) == MODE_NTSC))
-#define MODE_MONITOR	MATROXFB_OUTPUT_MODE_MONITOR
-
 #define MGATVO_B	1
 #define MGATVO_C	2
 
 struct maven_data {
 	struct matrox_fb_info*		primary_head;
 	struct i2c_client*		client;
-	int				mode;
 	int				version;
 };
 
@@ -127,7 +121,7 @@
 	fwant = htotal * vtotal;
 	fmax = pll->vco_freq_max / ctl->den;
 
-	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
+	dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
 		fwant, fxtal, htotal, vtotal, fmax);
 	for (p = 1; p <= pll->post_shift_max; p++) {
 		if (fwant * 2 > fmax)
@@ -163,9 +157,9 @@
 			ln = ln - scrlen;
 			if (ln > htotal)
 				continue;
-			printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
+			dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
 			if (ln > besth2) {
-				printk(KERN_DEBUG "Better...\n");
+				dprintk(KERN_DEBUG "Better...\n");
 				*h2 = besth2 = ln;
 				*post = p;
 				*in = m;
@@ -221,6 +215,13 @@
 	return;
 }
 
+static unsigned char maven_compute_deflicker (const struct maven_data* md) {
+	unsigned char df;
+	
+	df = (md->version == MGATVO_B?0x40:0x00);
+	return df;
+}
+
 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
 	static struct mavenregs palregs = { {
 		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
@@ -273,7 +274,7 @@
 		0x3F, 0x03, /* 3C-3D */
 		0x00,	/* 3E written multiple times */
 		0x00,	/* 3F not written */
-	}, MODE_PAL, 625, 50 };
+	}, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
 	static struct mavenregs ntscregs = { {
 		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
 		0x00,
@@ -325,14 +326,16 @@
 		0x3C, 0x00, /* 3C-3D */
 		0x00,	/* 3E written multiple times */
 		0x00,	/* never written */
-	}, MODE_NTSC, 525, 60 };
+	}, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
+	MINFO_FROM(md->primary_head);
 
-	if (md->mode & MODE_PAL)
+	if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
 		*data = palregs;
 	else
 		*data = ntscregs;
 
-	data->regs[0x93] = 0xA2;
+	/* Set deflicker */
+	data->regs[0x93] = maven_compute_deflicker(md);
 
 	/* gamma correction registers */
 	data->regs[0x83] = 0x00;
@@ -386,7 +389,7 @@
 	LRP(0x17);
 	LR(0x0B);
 	LR(0x0C);
-	if (m->mode & MODE_PAL) {
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
 		maven_set_reg(c, 0x35, 0x10); /* ... */
 	} else {
 		maven_set_reg(c, 0x35, 0x0F); /* ... */
@@ -424,7 +427,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);	/* ... */
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -473,7 +476,7 @@
 	LR(0xC2);
 
 	maven_get_reg(c, 0x8D);
-	maven_set_reg(c, 0x8D, 0x00);
+	maven_set_reg(c, 0x8D, 0x04);
 
 	LR(0x20);	/* saturation #1 */
 	LR(0x22);	/* saturation #2 */
@@ -498,7 +501,7 @@
 	LR(0x8B);
 
 	val = maven_get_reg(c, 0x8D);
-	val &= 0x10;			/* 0x10 or anything ored with it */
+	val &= 0x14;			/* 0x10 or anything ored with it */
 	maven_set_reg(c, 0x8D, val);
 
 	LR(0x33);
@@ -524,7 +527,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -562,7 +565,7 @@
 		unsigned int a, b, c, h2;
 		unsigned int h = ht + 2 + x;
 
-		if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
+		if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
 			unsigned int diff = h - h2;
 
 			if (diff < err) {
@@ -583,9 +586,10 @@
 		struct mavenregs* m) {
 	unsigned int tmpi;
 	unsigned int a, bv, c;
+	MINFO_FROM(md->primary_head);
 
-	m->mode = md->mode;
-	if (MODE_TV(md->mode)) {
+	m->mode = ACCESS_FBINFO(outputs[1]).mode;
+	if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
 		unsigned int lmargin;
 		unsigned int umargin;
 		unsigned int vslen;
@@ -804,7 +808,7 @@
 	m->regs[0xB0] = 0x03;	/* output: monitor */
 	m->regs[0xB1] = 0xA0;	/* ??? */
 	m->regs[0x8C] = 0x20;	/* must be set... */
-	m->regs[0x8D] = 0x00;	/* defaults to 0x10: test signal */
+	m->regs[0x8D] = 0x04;	/* defaults to 0x10: test signal */
 	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
 	m->regs[0xBF] = 0x22;	/* makes picture stable */
 
@@ -815,7 +819,7 @@
 		const struct mavenregs* m) {
 	struct i2c_client* c = md->client;
 
-	if (m->mode & MODE_MONITOR) {
+	if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
 		LR(0x80);
 		LR(0x81);
 		LR(0x82);
@@ -855,22 +859,16 @@
 	return 0;
 }
 
-static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) {
+static int maven_verify_output_mode(struct maven_data* md, u_int32_t arg) {
 	switch (arg) {
 		case MATROXFB_OUTPUT_MODE_PAL:
 		case MATROXFB_OUTPUT_MODE_NTSC:
 		case MATROXFB_OUTPUT_MODE_MONITOR:
-			md->mode = arg;
-			return 1;
+			return 0;
 	}
 	return -EINVAL;
 }
 
-static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
-	*arg = md->mode;
-	return 0;
-}
-
 /******************************************************/
 
 static int maven_out_compute(void* md, struct my_timming* mt) {
@@ -893,48 +891,31 @@
 	return maven_resync(md);
 }
 
-static void maven_out_incuse(void* md) {
-	if (md)
-		i2c_inc_use_client(((struct maven_data*)md)->client);
-}
-
-static void maven_out_decuse(void* md) {
-	if (md)
-		i2c_dec_use_client(((struct maven_data*)md)->client);
-}
-
-static int maven_out_set_mode(void* md, u_int32_t arg) {
-	return maven_set_output_mode(md, arg);
-}
-
-static int maven_out_get_mode(void* md, u_int32_t* arg) {
-	return maven_get_output_mode(md, arg);
+static int maven_out_verify_mode(void* md, u_int32_t arg) {
+	return maven_verify_output_mode(md, arg);
 }
 
 static struct matrox_altout maven_altout = {
-	maven_out_compute,
-	maven_out_program,
-	maven_out_start,
-	maven_out_incuse,
-	maven_out_decuse,
-	maven_out_set_mode,
-	maven_out_get_mode
+	.name		= "Secondary output",
+	.compute	= maven_out_compute,
+	.program	= maven_out_program,
+	.start		= maven_out_start,
+	.verifymode	= maven_out_verify_mode,
 };
 
 static int maven_init_client(struct i2c_client* clnt) {
 	struct i2c_adapter* a = clnt->adapter;
 	struct maven_data* md = clnt->data;
-	struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo;
-	MINFO_FROM(m2info->primary_dev);
+	MINFO_FROM(container_of(a, struct i2c_bit_adapter, adapter)->minfo);
 
-	md->mode = MODE_MONITOR;
 	md->primary_head = MINFO;
 	md->client = clnt;
 	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = md;
-	ACCESS_FBINFO(altout.output) = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+	ACCESS_FBINFO(outputs[1]).data = md;
+	ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
 	if (maven_get_reg(clnt, 0xB2) < 0x14) {
 		md->version = MGATVO_B;
 	} else {
@@ -947,13 +928,14 @@
 	struct maven_data* md = clnt->data;
 
 	if (md->primary_head) {
-		md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&md->primary_head->altout.lock);
-		md->primary_head->altout.device = NULL;
-		md->primary_head->altout.output = NULL;
-		up_write(&md->primary_head->altout.lock);
+		MINFO_FROM(md->primary_head);
+
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
 		md->primary_head = NULL;
 	}
 	return 0;
@@ -983,7 +965,7 @@
 					      I2C_FUNC_SMBUS_BYTE_DATA |
 					      I2C_FUNC_PROTOCOL_MANGLING))
 		goto ERROR0;
-	if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data),
+	if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data),
 			GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto ERROR0;
@@ -1066,7 +1048,7 @@
 		i2c_del_driver(&maven_driver);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_maven_init);
diff -Nru a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h
--- a/drivers/video/matrox/matroxfb_maven.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/matrox/matroxfb_maven.h	Tue Aug 27 12:28:08 2002
@@ -6,21 +6,15 @@
 #include <linux/i2c-algo-bit.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_dh_maven_info;
-
 struct i2c_bit_adapter {
 	struct i2c_adapter		adapter;
 	int				initialized;
 	struct i2c_algo_bit_data	bac;
-	struct matroxfb_dh_maven_info  *minfo;
-};
-
-struct matroxfb_dh_maven_info {
-	struct matrox_fb_info*	primary_dev;
-
-	struct i2c_bit_adapter	maven;
-	struct i2c_bit_adapter	ddc1;
-	struct i2c_bit_adapter	ddc2;
+	struct matrox_fb_info*		minfo;
+	struct {
+		unsigned int		data;
+		unsigned int		clock;
+				      } mask;
 };
 
 #endif /* __MATROXFB_MAVEN_H__ */
diff -Nru a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
--- a/drivers/video/matrox/matroxfb_misc.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/matrox/matroxfb_misc.c	Tue Aug 27 12:28:07 2002
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000,2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.65 2002/08/14
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -146,6 +146,7 @@
 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
 	mt->pixclock = 1000000000 / pixclock;
 	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->mnp = -1;
 	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
 	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
 	mt->HDisplay = var->xres;
@@ -226,7 +227,7 @@
 	unsigned int wd;
 	unsigned int divider;
 	int i;
-	int text = p->type == FB_TYPE_TEXT;
+	int text = ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT;
 	int fwidth;
 	struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
 
@@ -360,7 +361,8 @@
 			  ((hd      & 0x100) >> 7) | /* blanking */
 			  ((hs      & 0x100) >> 6) | /* sync start */
 			   (hbe     & 0x040);	 /* end hor. blanking */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
 		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */
 	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
 			  ((vd & 0x400) >>  8) |	/* disp end */
@@ -872,7 +874,7 @@
 	mult = bd->pins[4]?8000:6000;
 	
 	MINFO->limits.pixel.vcomax	= (bd->pins[ 38] == 0xFF) ? 600000			: bd->pins[ 38] * mult;
-	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 39] * mult;
+	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 36] * mult;
 	MINFO->limits.video.vcomax	= (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax	: bd->pins[ 37] * mult;
 	MINFO->limits.pixel.vcomin	= (bd->pins[123] == 0xFF) ? 256000			: bd->pins[123] * mult;
 	MINFO->limits.system.vcomin	= (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin	: bd->pins[121] * mult;
@@ -1011,6 +1013,6 @@
 EXPORT_SYMBOL(matroxfb_vgaHWrestore);		/* DAC1064, Ti3026 */
 EXPORT_SYMBOL(matroxfb_read_pins);
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
--- a/drivers/video/maxinefb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/maxinefb.c	Tue Aug 27 12:28:02 2002
@@ -45,23 +45,23 @@
 static struct display disp;
 
 static struct fb_var_screeninfo maxinefb_defined = {
-	xres:		1024,
-	yres:		768,
-	xres_virtual:	1024,
-	yres_virtual:	768,
-	bits_per_pixel:	8,
-	activate:	FB_ACTIVATE_NOW,
-	height:		-1,
-	width:		-1,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres =		1024,
+	.yres =		768,
+	.xres_virtual =	1024,
+	.yres_virtual =	768,
+	.bits_per_pixel =8,
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.vmode =	FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo maxinefb_fix = {
-	id:		"Maxine onboard graphics 1024x768x8",
-	smem_len:	(1024*768),
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	line_length:	1024,
+	.id =		"Maxine onboard graphics 1024x768x8",
+	.smem_len =	(1024*768),
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.line_length =	1024,
 }
 
 /* Reference to machine type set in arch/mips/dec/prom/identify.c, KM */
@@ -111,16 +111,14 @@
 }
 
 static struct fb_ops maxinefb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	maxinefb_setcolreg,	
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,		
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= maxinefb_setcolreg,	
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,		
 };
 
 int __init maxinefb_init(void)
diff -Nru a/drivers/video/mdacon.c b/drivers/video/mdacon.c
--- a/drivers/video/mdacon.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/mdacon.c	Tue Aug 27 12:28:07 2002
@@ -587,22 +587,22 @@
  */
 
 const struct consw mda_con = {
-	con_startup:		mdacon_startup,
-	con_init:		mdacon_init,
-	con_deinit:		mdacon_deinit,
-	con_clear:		mdacon_clear,
-	con_putc:		mdacon_putc,
-	con_putcs:		mdacon_putcs,
-	con_cursor:		mdacon_cursor,
-	con_scroll:		mdacon_scroll,
-	con_bmove:		mdacon_bmove,
-	con_switch:		mdacon_switch,
-	con_blank:		mdacon_blank,
-	con_font_op:		mdacon_font_op,
-	con_set_palette:	mdacon_set_palette,
-	con_scrolldelta:	mdacon_scrolldelta,
-	con_build_attr:		mdacon_build_attr,
-	con_invert_region:	mdacon_invert_region,
+	.con_startup =		mdacon_startup,
+	.con_init =		mdacon_init,
+	.con_deinit =		mdacon_deinit,
+	.con_clear =		mdacon_clear,
+	.con_putc =		mdacon_putc,
+	.con_putcs =		mdacon_putcs,
+	.con_cursor =		mdacon_cursor,
+	.con_scroll =		mdacon_scroll,
+	.con_bmove =		mdacon_bmove,
+	.con_switch =		mdacon_switch,
+	.con_blank =		mdacon_blank,
+	.con_font_op =		mdacon_font_op,
+	.con_set_palette =	mdacon_set_palette,
+	.con_scrolldelta =	mdacon_scrolldelta,
+	.con_build_attr =	mdacon_build_attr,
+	.con_invert_region =	mdacon_invert_region,
 };
 
 void __init mda_console_init(void)
diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/neofb.c	Tue Aug 27 12:27:59 2002
@@ -1386,20 +1386,18 @@
 }
 
 static struct fb_ops neofb_ops = {
-	owner:		THIS_MODULE,
-	fb_check_var:	neofb_check_var,
-	fb_set_par:	neofb_set_par,
-	fb_set_var:	gen_set_var,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	neofb_setcolreg,
-	fb_pan_display:	neofb_pan_display,
-	fb_blank:	neofb_blank,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_check_var	= neofb_check_var,
+	.fb_set_par	= neofb_set_par,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= neofb_setcolreg,
+	.fb_pan_display	= neofb_pan_display,
+	.fb_blank	= neofb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 /* --------------------------------------------------------------------- */
@@ -1988,10 +1986,10 @@
 MODULE_DEVICE_TABLE(pci, neofb_devices);
 
 static struct pci_driver neofb_driver = {
-	name:		"neofb",
-	id_table:	neofb_devices,
-	probe:		neofb_probe,
-	remove:		__devexit_p(neofb_remove)
+	.name =		"neofb",
+	.id_table =	neofb_devices,
+	.probe =	neofb_probe,
+	.remove =	__devexit_p(neofb_remove)
 };
 
 /* **************************** init-time only **************************** */
diff -Nru a/drivers/video/newport_con.c b/drivers/video/newport_con.c
--- a/drivers/video/newport_con.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/newport_con.c	Tue Aug 27 12:28:08 2002
@@ -700,22 +700,22 @@
 #define DUMMY (void *) newport_dummy
 
 const struct consw newport_con = {
-    con_startup:	newport_startup,
-    con_init:		newport_init,
-    con_deinit:		DUMMY,
-    con_clear:		newport_clear,
-    con_putc:		newport_putc,
-    con_putcs:		newport_putcs,
-    con_cursor:		newport_cursor,
-    con_scroll:		newport_scroll,
-    con_bmove:		newport_bmove,
-    con_switch:		newport_switch,
-    con_blank:		newport_blank,
-    con_font_op:	newport_font_op,
-    con_set_palette:	newport_set_palette,
-    con_scrolldelta:	newport_scrolldelta,
-    con_set_origin:	DUMMY,
-    con_save_screen:	DUMMY
+    .con_startup =	newport_startup,
+    .con_init =		newport_init,
+    .con_deinit =	DUMMY,
+    .con_clear =	newport_clear,
+    .con_putc =		newport_putc,
+    .con_putcs =	newport_putcs,
+    .con_cursor =	newport_cursor,
+    .con_scroll =	newport_scroll,
+    .con_bmove =	newport_bmove,
+    .con_switch =	newport_switch,
+    .con_blank =	newport_blank,
+    .con_font_op =	newport_font_op,
+    .con_set_palette =	newport_set_palette,
+    .con_scrolldelta =	newport_scrolldelta,
+    .con_set_origin =	DUMMY,
+    .con_save_screen =	DUMMY
 };
 
 #ifdef MODULE
diff -Nru a/drivers/video/offb.c b/drivers/video/offb.c
--- a/drivers/video/offb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/offb.c	Tue Aug 27 12:28:05 2002
@@ -82,17 +82,15 @@
 			 unsigned long address, struct device_node *dp);
 
 static struct fb_ops offb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	offb_setcolreg,
-	fb_blank:	offb_blank,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= offb_setcolreg,
+	.fb_blank	= offb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
     /*
@@ -399,7 +397,6 @@
 	struct fb_fix_screeninfo *fix;
 	struct fb_var_screeninfo *var;
 	struct fb_info *info;
-	int i;
 
 	if (!request_mem_region(res_start, res_size, "offb"))
 		return;
@@ -414,14 +411,15 @@
 		return;
 	}
 
-	info =
-	    kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
-		    sizeof(u32) * 17, GFP_ATOMIC);
+	size = sizeof(struct fb_info) + sizeof(struct display) + sizeof(u32) * 17;
+
+	info = kmalloc(size, GFP_ATOMIC);
+	
 	if (info == 0) {
 		release_mem_region(res_start, res_size);
 		return;
 	}
-	memset(info, 0, sizeof(*info));
+	memset(info, 0, size);
 
 	fix = &info->fix;
 	var = &info->var;
@@ -465,7 +463,7 @@
 			unsigned long base = address & 0xff000000UL;
 			par->cmap_adr =
 			    ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
-			par->cmap_data = info->cmap_adr + 1;
+			par->cmap_data = par->cmap_adr + 1;
 			par->cmap_type = cmap_m64;
 		} else if (device_is_compatible(dp, "pci1014,b7")) {
 			unsigned long regbase = dp->addrs[0].address;
@@ -555,7 +553,7 @@
 	}
 
 	printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n",
-	       GET_FB_IDX(info->info.node), full_name);
+	       GET_FB_IDX(info->node), full_name);
 }
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
--- a/drivers/video/platinumfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/platinumfb.c	Tue Aug 27 12:28:02 2002
@@ -149,14 +149,14 @@
 int platinum_setup(char*);
 
 static struct fb_ops platinumfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	platinum_get_fix,
-	fb_get_var:	platinum_get_var,
-	fb_set_var:	platinum_set_var,
-	fb_get_cmap:	platinum_get_cmap,
-	fb_set_cmap:	platinum_set_cmap,
-	fb_setcolreg:	platinum_setcolreg,
-	fb_blank:	platinum_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	platinum_get_fix,
+	.fb_get_var =	platinum_get_var,
+	.fb_set_var =	platinum_set_var,
+	.fb_get_cmap =	platinum_get_cmap,
+	.fb_set_cmap =	platinum_set_cmap,
+	.fb_setcolreg =	platinum_setcolreg,
+	.fb_blank =	platinum_blank,
 };
 
 static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/pm2fb.c	Tue Aug 27 12:28:08 2002
@@ -413,15 +413,15 @@
 				unsigned transp, struct fb_info* info);
 
 static struct fb_ops pm2fb_ops={
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
-	fb_pan_display:	fbgen_pan_display,
-	fb_setcolreg:	pm2fb_setcolreg,
-	fb_blank:	fbgen_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	fbgen_set_cmap,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_setcolreg =	pm2fb_setcolreg,
+	.fb_blank =	fbgen_blank,
 };
 
 /***************************************************************************
@@ -1434,23 +1434,23 @@
 }
 
 static struct display_switch pm2_cfb8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		pm2fb_pp_bmove,
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	pm2fb_pp_bmove,
 #ifdef __alpha__
 	/* Not sure why, but this works and the other does not. */
 	/* Also, perhaps we need a separate routine to wait for the
 	   blitter to stop before doing this? */
 	/* In addition, maybe we need to do this for 16 and 32 bit depths? */
-	clear:		fbcon_cfb8_clear,
+	.clear =	fbcon_cfb8_clear,
 #else
-	clear:		pm2fb_clear8,
+	.clear =	pm2fb_clear8,
 #endif
-	putc:		fbcon_cfb8_putc,
-	putcs:		fbcon_cfb8_putcs,
-	revc:		fbcon_cfb8_revc,
-	cursor:		pm2fb_cursor,
-	set_font:	pm2fb_set_font,
-	clear_margins:	pm2fb_clear_margins8,
+	.putc =		fbcon_cfb8_putc,
+	.putcs =	fbcon_cfb8_putcs,
+	.revc =		fbcon_cfb8_revc,
+	.cursor =	pm2fb_cursor,
+	.set_font =	pm2fb_set_font,
+	.clear_margins =pm2fb_clear_margins8,
 	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB8 */
 
@@ -1487,16 +1487,16 @@
 }
 
 static struct display_switch pm2_cfb16 = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		pm2fb_pp_bmove,
-	clear:		pm2fb_clear16,
-	putc:		fbcon_cfb16_putc,
-	putcs:		fbcon_cfb16_putcs,
-	revc:		fbcon_cfb16_revc,
-	cursor:		pm2fb_cursor,
-	set_font:	pm2fb_set_font,
-	clear_margins:	pm2fb_clear_margins16,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb16_setup,
+	.bmove =	pm2fb_pp_bmove,
+	.clear =	pm2fb_clear16,
+	.putc =		fbcon_cfb16_putc,
+	.putcs =	fbcon_cfb16_putcs,
+	.revc =		fbcon_cfb16_revc,
+	.cursor =	pm2fb_cursor,
+	.set_font =	pm2fb_set_font,
+	.clear_margins =pm2fb_clear_margins16,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif /* FBCON_HAS_CFB16 */
 
@@ -1540,16 +1540,16 @@
 }
 
 static struct display_switch pm2_cfb24 = {
-	setup:		fbcon_cfb24_setup,
-	bmove:		pm2fb_bmove,
-	clear:		pm2fb_clear24,
-	putc:		fbcon_cfb24_putc,
-	putcs:		fbcon_cfb24_putcs,
-	revc:		fbcon_cfb24_revc,
-	cursor:		pm2fb_cursor,
-	set_font:	pm2fb_set_font,
-	clear_margins:	pm2fb_clear_margins24,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb24_setup,
+	.bmove =	pm2fb_bmove,
+	.clear =	pm2fb_clear24,
+	.putc =		fbcon_cfb24_putc,
+	.putcs =	fbcon_cfb24_putcs,
+	.revc =		fbcon_cfb24_revc,
+	.cursor =	pm2fb_cursor,
+	.set_font =	pm2fb_set_font,
+	.clear_margins =pm2fb_clear_margins24,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif /* FBCON_HAS_CFB24 */
 
@@ -1584,16 +1584,16 @@
 }
 
 static struct display_switch pm2_cfb32 = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		pm2fb_bmove,
-	clear:		pm2fb_clear32,
-	putc:		fbcon_cfb32_putc,
-	putcs:		fbcon_cfb32_putcs,
-	revc:		fbcon_cfb32_revc,
-	cursor:		pm2fb_cursor,
-	set_font:	pm2fb_set_font,
-	clear_margins:	pm2fb_clear_margins32,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =	fbcon_cfb32_setup,
+	.bmove =	pm2fb_bmove,
+	.clear =	pm2fb_clear32,
+	.putc =		fbcon_cfb32_putc,
+	.putcs =	fbcon_cfb32_putcs,
+	.revc =		fbcon_cfb32_revc,
+	.cursor =	pm2fb_cursor,
+	.set_font =	pm2fb_set_font,
+	.clear_margins =pm2fb_clear_margins32,
+	.fontwidthmask =FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif /* FBCON_HAS_CFB32 */
 
diff -Nru a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
--- a/drivers/video/pm3fb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/pm3fb.c	Tue Aug 27 12:28:01 2002
@@ -688,16 +688,16 @@
 };
 
 static struct fb_ops pm3fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
-	fb_setcolreg:	pm3fb_setcolreg,
-	fb_pan_display:	fbgen_pan_display,
-	fb_blank:	fbgen_blank,
-	fb_ioctl:	pm3fb_ioctl,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	fbgen_set_cmap,
+	.fb_setcolreg =	pm3fb_setcolreg,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_blank =	fbgen_blank,
+	.fb_ioctl =	pm3fb_ioctl,
 };
 #endif /* KERNEL_2_4 or KERNEL_2_5 */
 #ifdef PM3FB_USE_ACCEL
diff -Nru a/drivers/video/pm3fb.h b/drivers/video/pm3fb.h
--- a/drivers/video/pm3fb.h	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/pm3fb.h	Tue Aug 27 12:28:08 2002
@@ -1281,4 +1281,4 @@
     } \
 } while (0)
 
-#endif PM3FB_H
+#endif /* PM3FB_H */
diff -Nru a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
--- a/drivers/video/pmag-ba-fb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/pmag-ba-fb.c	Tue Aug 27 12:28:08 2002
@@ -55,24 +55,24 @@
 static struct display pmagba_disp[3];
 
 static struct fb_var_screeninfo pmagbafb_defined = {
-	xres:		1024,
-	yres:		864,
-	xres_virtual:	1024,
-	yres_virtual:	864,
-	bits_per_pixel:	8,
-	activate:	FB_ACTIVATE_NOW, 
-	height:		274,	
-	width:		195,
-	accel:		FB_ACCEL_NONE,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres =		1024,
+	.yres =		864,
+	.xres_virtual =	1024,
+	.yres_virtual =	864,
+	.bits_per_pixel =8,
+	.activate =	FB_ACTIVATE_NOW, 
+	.height =	274,	
+	.width =	195,
+	.accel =	FB_ACCEL_NONE,
+	.vmode =	FB_VMODE_NONINTERLACED,
 }
 
 static struct fb_fix_screeninfo pmagbafb_fix = {
-	id:		"PMAG-BA",
-	smem_len:	(1024 * 864),
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	line_length:	1024,
+	.id =		"PMAG-BA",
+	.smem_len =	(1024 * 864),
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.line_length =	1024,
 }
 
 /*
@@ -110,16 +110,14 @@
 }
 
 static struct fb_ops pmagbafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	pmagbafb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= pmagbafb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 }
 
 int __init pmagbafb_init_one(int slot)
diff -Nru a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
--- a/drivers/video/pmagb-b-fb.c	Tue Aug 27 12:27:57 2002
+++ b/drivers/video/pmagb-b-fb.c	Tue Aug 27 12:27:57 2002
@@ -58,24 +58,24 @@
 static struct display pmagbb_disp[3];
 
 static struct fb_var_screeninfo pmagbbfb_defined = {
-	xres:		1280,
-	yres:		1024,
-	xres_virtual:	1280,
-	yres_virtual:	1024,
-	bits_per_pixel:	8,
-	activate:	FB_ACTIVATE_NOW,
-	height:		274,
-	width:		195,
-	accel_flags:	FB_ACCEL_NONE,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres =		1280,
+	.yres =		1024,
+	.xres_virtual =	1280,
+	.yres_virtual =	1024,
+	.bits_per_pixel =8,
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	274,
+	.width =	195,
+	.accel_flags =	FB_ACCEL_NONE,
+	.vmode =	FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo pmagbafb_fix = {
-	id:		"PMAGB-BA",
-	smem_len:	(1280 * 1024),
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	line_length:	1280,
+	.id =		"PMAGB-BA",
+	.smem_len =	(1280 * 1024),
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.line_length =	1280,
 }
 
 /*
@@ -113,16 +113,14 @@
 }
 
 static struct fb_ops pmagbbfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	pmagbbfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= pmagbbfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 int __init pmagbbfb_init_one(int slot)
diff -Nru a/drivers/video/promcon.c b/drivers/video/promcon.c
--- a/drivers/video/promcon.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/promcon.c	Tue Aug 27 12:28:07 2002
@@ -575,22 +575,22 @@
 #define DUMMY (void *) promcon_dummy
 
 const struct consw prom_con = {
-	con_startup:		promcon_startup,
-	con_init:		promcon_init,
-	con_deinit:		promcon_deinit,
-	con_clear:		promcon_clear,
-	con_putc:		promcon_putc,
-	con_putcs:		promcon_putcs,
-	con_cursor:		promcon_cursor,
-	con_scroll:		promcon_scroll,
-	con_bmove:		promcon_bmove,
-	con_switch:		promcon_switch,
-	con_blank:		promcon_blank,
-	con_font_op:		promcon_font_op,
-	con_set_palette:	DUMMY,
-	con_scrolldelta:	DUMMY,
+	.con_startup =		promcon_startup,
+	.con_init =		promcon_init,
+	.con_deinit =		promcon_deinit,
+	.con_clear =		promcon_clear,
+	.con_putc =		promcon_putc,
+	.con_putcs =		promcon_putcs,
+	.con_cursor =		promcon_cursor,
+	.con_scroll =		promcon_scroll,
+	.con_bmove =		promcon_bmove,
+	.con_switch =		promcon_switch,
+	.con_blank =		promcon_blank,
+	.con_font_op =		promcon_font_op,
+	.con_set_palette =	DUMMY,
+	.con_scrolldelta =	DUMMY,
 #if !(PROMCON_COLOR)
-	con_build_attr:		promcon_build_attr,
+	.con_build_attr =	promcon_build_attr,
 #endif
 };
 
diff -Nru a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
--- a/drivers/video/pvr2fb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/pvr2fb.c	Tue Aug 27 12:27:59 2002
@@ -252,15 +252,15 @@
                             int val, int size);
 
 static struct fb_ops pvr2fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	pvr2fb_get_fix,
-	fb_get_var:	pvr2fb_get_var,
-	fb_set_var:	pvr2fb_set_var,
-	fb_get_cmap:	pvr2fb_get_cmap,
-	fb_set_cmap:	pvr2fb_set_cmap,
-	fb_setcolreg:	pvr2fb_setcolreg,
-	fb_pan_display: pvr2fb_pan_display,
-	fb_blank:	pvr2fb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	pvr2fb_get_fix,
+	.fb_get_var =	pvr2fb_get_var,
+	.fb_set_var =	pvr2fb_set_var,
+	.fb_get_cmap =	pvr2fb_get_cmap,
+	.fb_set_cmap =	pvr2fb_set_cmap,
+	.fb_setcolreg =	pvr2fb_setcolreg,
+	.fb_pan_display = pvr2fb_pan_display,
+	.fb_blank =	pvr2fb_blank,
 };
 
 static struct fb_videomode pvr2_modedb[] __initdata = {
diff -Nru a/drivers/video/q40fb.c b/drivers/video/q40fb.c
--- a/drivers/video/q40fb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/q40fb.c	Tue Aug 27 12:28:02 2002
@@ -37,27 +37,27 @@
 static struct display display;
 
 static struct fb_fix_screeninfo q40fb_fix __initdata = {
-	id:		"Q40",
-	smem_len:	1024*1024,
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_TRUECOLOR,
-	line_length:	1024*2,
-	accel:		FB_ACCEL_NONE,
+	.id		= "Q40",
+	.smem_len	= 1024*1024,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.line_length	= 1024*2,
+	.accel		= FB_ACCEL_NONE,
 };
 
 static struct fb_var_screeninfo q40fb_var __initdata = {
-	xres:		1024,
-	yres:		512,
-	xres_virtual:	1024,
-	yres_virtual:	512,
-	bits_per_pixel:	16,
-    	red:		{6, 5, 0}, 
-	green:		{11, 5, 0},
-	blue:		{0, 6, 0},
-	activate:	FB_ACTIVATE_NOW,
-	height:		230,
-	width:		300,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.xres		= 1024,
+	.yres		= 512,
+	.xres_virtual	= 1024,
+	.yres_virtual	= 512,
+	.bits_per_pixel	= 16,
+    	.red		= {6, 5, 0}, 
+	.green		= {11, 5, 0},
+	.blue		= {0, 6, 0},
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= 230,
+	.width		= 300,
+	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
 /* frame buffer operations */
@@ -68,16 +68,14 @@
                            struct fb_info *info);
 
 static struct fb_ops q40fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	q40fb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= q40fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
diff -Nru a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
--- a/drivers/video/radeonfb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/radeonfb.c	Tue Aug 27 12:28:08 2002
@@ -602,23 +602,23 @@
 #endif
 
 static struct fb_ops radeon_fb_ops = {
-	fb_get_fix:		radeonfb_get_fix,
-	fb_get_var:		radeonfb_get_var,
-	fb_set_var:		radeonfb_set_var,
-	fb_get_cmap:		radeonfb_get_cmap,
-	fb_set_cmap:		gen_set_cmap,
-	fb_setcolreg:		radeonfb_setcolreg,
-	fb_pan_display:		radeonfb_pan_display,
-	fb_blank:		radeonfb_blank,
-	fb_ioctl:		radeonfb_ioctl,
+	.fb_get_fix =		radeonfb_get_fix,
+	.fb_get_var =		radeonfb_get_var,
+	.fb_set_var =		radeonfb_set_var,
+	.fb_get_cmap =		radeonfb_get_cmap,
+	.fb_set_cmap =		gen_set_cmap,
+	.fb_setcolreg =		radeonfb_setcolreg,
+	.fb_pan_display =	radeonfb_pan_display,
+	.fb_blank =		radeonfb_blank,
+	.fb_ioctl =		radeonfb_ioctl,
 };
 
 
 static struct pci_driver radeonfb_driver = {
-	name:		"radeonfb",
-	id_table:	radeonfb_pci_table,
-	probe:		radeonfb_pci_register,
-	remove:		__devexit_p(radeonfb_pci_unregister),
+	.name =		"radeonfb",
+	.id_table =	radeonfb_pci_table,
+	.probe =	radeonfb_pci_register,
+	.remove =	__devexit_p(radeonfb_pci_unregister),
 };
 
 
@@ -2485,13 +2485,13 @@
 
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_radeon8 = {
-	setup:			fbcon_cfb8_setup,
-	bmove:			fbcon_radeon_bmove,
-	clear:			fbcon_radeon_clear,
-	putc:			fbcon_cfb8_putc,
-	putcs:			fbcon_cfb8_putcs,
-	revc:			fbcon_cfb8_revc,
-	clear_margins:		fbcon_cfb8_clear_margins,
-	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup =		fbcon_cfb8_setup,
+	.bmove =		fbcon_radeon_bmove,
+	.clear =		fbcon_radeon_clear,
+	.putc =			fbcon_cfb8_putc,
+	.putcs =		fbcon_cfb8_putcs,
+	.revc =			fbcon_cfb8_revc,
+	.clear_margins =	fbcon_cfb8_clear_margins,
+	.fontwidthmask =	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
diff -Nru a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
--- a/drivers/video/retz3fb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/retz3fb.c	Tue Aug 27 12:28:08 2002
@@ -1312,14 +1312,14 @@
 }
 
 static struct fb_ops retz3fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	retz3fb_get_fix,
-	fb_get_var:	retz3fb_get_var,
-	fb_set_var:	retz3fb_set_var,
-	fb_get_cmap:	retz3fb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	retz3fb_setcolreg,
-	fb_blank:	retz3fb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	retz3fb_get_fix,
+	.fb_get_var =	retz3fb_get_var,
+	.fb_set_var =	retz3fb_set_var,
+	.fb_get_cmap =	retz3fb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	retz3fb_setcolreg,
+	.fb_blank =	retz3fb_blank,
 };
 
 int __init retz3fb_setup(char *options)
diff -Nru a/drivers/video/riva/accel.c b/drivers/video/riva/accel.c
--- a/drivers/video/riva/accel.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/riva/accel.c	Tue Aug 27 12:28:08 2002
@@ -238,14 +238,14 @@
 }
 
 struct display_switch fbcon_riva8 = {
-	setup:		fbcon_riva8_setup,
-	bmove:		fbcon_riva_bmove,
-	clear:		fbcon_riva8_clear,
-	putc:		fbcon_riva8_putc,
-	putcs:		fbcon_riva8_putcs,
-	revc:		fbcon_riva8_revc,
-	clear_margins:	fbcon_riva8_clear_margins,
-	fontwidthmask:	FONTWIDTHRANGE(4, 16)
+	.setup =	fbcon_riva8_setup,
+	.bmove =	fbcon_riva_bmove,
+	.clear =	fbcon_riva8_clear,
+	.putc =		fbcon_riva8_putc,
+	.putcs =	fbcon_riva8_putcs,
+	.revc =		fbcon_riva8_revc,
+	.clear_margins =fbcon_riva8_clear_margins,
+	.fontwidthmask =FONTWIDTHRANGE(4, 16)
 };
 #endif
 
@@ -341,14 +341,14 @@
 }
 
 struct display_switch fbcon_riva16 = {
-	setup:		fbcon_riva16_setup,
-	bmove:		fbcon_riva_bmove,
-	clear:		fbcon_riva16_clear,
-	putc:		fbcon_riva16_putc,
-	putcs:		fbcon_riva16_putcs,
-	revc:		fbcon_riva1632_revc,
-	clear_margins:	fbcon_riva16_clear_margins,
-	fontwidthmask:	FONTWIDTHRANGE(4, 16)
+	.setup =	fbcon_riva16_setup,
+	.bmove =	fbcon_riva_bmove,
+	.clear =	fbcon_riva16_clear,
+	.putc =		fbcon_riva16_putc,
+	.putcs =	fbcon_riva16_putcs,
+	.revc =		fbcon_riva1632_revc,
+	.clear_margins =fbcon_riva16_clear_margins,
+	.fontwidthmask =FONTWIDTHRANGE(4, 16)
 };
 #endif
 
@@ -415,13 +415,13 @@
 }
 
 struct display_switch fbcon_riva32 = {
-	setup:		fbcon_riva32_setup,
-	bmove:		fbcon_riva_bmove,
-	clear:		fbcon_riva32_clear,
-	putc:		fbcon_riva32_putc,
-	putcs:		fbcon_riva32_putcs,
-	revc:		fbcon_riva1632_revc,
-	clear_margins:	fbcon_riva32_clear_margins,
-	fontwidthmask:	FONTWIDTHRANGE(4, 16)
+	.setup =	fbcon_riva32_setup,
+	.bmove =	fbcon_riva_bmove,
+	.clear =	fbcon_riva32_clear,
+	.putc =		fbcon_riva32_putc,
+	.putcs =	fbcon_riva32_putcs,
+	.revc =		fbcon_riva1632_revc,
+	.clear_margins =fbcon_riva32_clear_margins,
+	.fontwidthmask =FONTWIDTHRANGE(4, 16)
 };
 #endif
diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
--- a/drivers/video/riva/fbdev.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/riva/fbdev.c	Tue Aug 27 12:28:01 2002
@@ -266,32 +266,32 @@
 #endif
 
 static struct fb_var_screeninfo rivafb_default_var = {
-	xres:		640,
-	yres:		480,
-	xres_virtual:	640,
-	yres_virtual:	480,
-	xoffset:	0,
-	yoffset:	0,
-	bits_per_pixel:	8,
-	grayscale:	0,
-	red:		{0, 6, 0},
-	green:		{0, 6, 0},
-	blue:		{0, 6, 0},
-	transp:		{0, 0, 0},
-	nonstd:		0,
-	activate:	0,
-	height:		-1,
-	width:		-1,
-	accel_flags:	0,
-	pixclock:	39721,
-	left_margin:	40,
-	right_margin:	24,
-	upper_margin:	32,
-	lower_margin:	11,
-	hsync_len:	96,
-	vsync_len:	2,
-	sync:		0,
-	vmode:		FB_VMODE_NONINTERLACED
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	480,
+	.xoffset =	0,
+	.yoffset =	0,
+	.bits_per_pixel =8,
+	.grayscale =	0,
+	.red =		{0, 6, 0},
+	.green =	{0, 6, 0},
+	.blue =		{0, 6, 0},
+	.transp =	{0, 0, 0},
+	.nonstd =	0,
+	.activate =	0,
+	.height =	-1,
+	.width =	-1,
+	.accel_flags =	0,
+	.pixclock =	39721,
+	.left_margin =	40,
+	.right_margin =	24,
+	.upper_margin =	32,
+	.lower_margin =	11,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.sync =		0,
+	.vmode =	FB_VMODE_NONINTERLACED
 };
 
 /* from GGI */
@@ -1744,17 +1744,17 @@
 
 /* kernel interface */
 static struct fb_ops riva_fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	rivafb_get_fix,
-	fb_get_var:	rivafb_get_var,
-	fb_set_var:	rivafb_set_var,
-	fb_get_cmap:	rivafb_get_cmap,
-	fb_set_cmap:	rivafb_set_cmap,
-	fb_setcolreg:	rivafb_setcolreg,
-	fb_pan_display:	rivafb_pan_display,
-	fb_blank:	rivafb_blank,
-	fb_ioctl:	rivafb_ioctl,
-	fb_rasterimg:	rivafb_rasterimg,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	rivafb_get_fix,
+	.fb_get_var =	rivafb_get_var,
+	.fb_set_var =	rivafb_set_var,
+	.fb_get_cmap =	rivafb_get_cmap,
+	.fb_set_cmap =	rivafb_set_cmap,
+	.fb_setcolreg =	rivafb_setcolreg,
+	.fb_pan_display =rivafb_pan_display,
+	.fb_blank =	rivafb_blank,
+	.fb_ioctl =	rivafb_ioctl,
+	.fb_rasterimg =	rivafb_rasterimg,
 };
 
 static int __devinit riva_init_disp_var(struct rivafb_info *rinfo)
@@ -2081,10 +2081,10 @@
 #endif /* !MODULE */
 
 static struct pci_driver rivafb_driver = {
-	name:		"rivafb",
-	id_table:	rivafb_pci_tbl,
-	probe:		rivafb_init_one,
-	remove:		__devexit_p(rivafb_remove_one),
+	.name =		"rivafb",
+	.id_table =	rivafb_pci_tbl,
+	.probe =	rivafb_init_one,
+	.remove =	__devexit_p(rivafb_remove_one),
 };
 
 
diff -Nru a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c
--- a/drivers/video/sbusfb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/sbusfb.c	Tue Aug 27 12:28:01 2002
@@ -78,10 +78,6 @@
 static int sbusfb_release(struct fb_info *info, int user);
 static int sbusfb_mmap(struct fb_info *info, struct file *file, 
 			struct vm_area_struct *vma);
-static int sbusfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			struct fb_info *info);
-static int sbusfb_get_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
 static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
 			struct fb_info *info);
 static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
@@ -112,18 +108,16 @@
 			    u_int *transp, struct fb_info *info);
 
 static struct fb_ops sbusfb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	sbusfb_open,
-	fb_release:	sbusfb_release,
-	fb_get_fix:	sbusfb_get_fix,
-	fb_get_var:	sbusfb_get_var,
-	fb_set_var:	sbusfb_set_var,
-	fb_get_cmap:	sbusfb_get_cmap,
-	fb_set_cmap:	sbusfb_set_cmap,
-	fb_setcolreg:	sbusfb_setcolreg,
-	fb_blank:	sbusfb_blank,
-	fb_ioctl:	sbusfb_ioctl,
-	fb_mmap:	sbusfb_mmap,
+	.owner =	THIS_MODULE,
+	.fb_open =	sbusfb_open,
+	.fb_release =	sbusfb_release,
+	.fb_set_var =	sbusfb_set_var,
+	.fb_get_cmap =	sbusfb_get_cmap,
+	.fb_set_cmap =	sbusfb_set_cmap,
+	.fb_setcolreg =	sbusfb_setcolreg,
+	.fb_blank =	sbusfb_blank,
+	.fb_ioctl =	sbusfb_ioctl,
+	.fb_mmap =	sbusfb_mmap,
 };
 
     /*
@@ -303,31 +297,6 @@
 	sbusfb_clear_margin(p, 0);
 }
 
-    /*
-     *  Get the Fixed Part of the Display
-     */
-
-static int sbusfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			  struct fb_info *info)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
-	memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
-	return 0;
-}
-
-    /*
-     *  Get the User Defined Part of the Display
-     */
-
-static int sbusfb_get_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
-	memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
-	return 0;
-}
 
     /*
      *  Set the User Defined Part of the Display
@@ -1084,10 +1053,6 @@
 	fb->dispsw.clear_margins = NULL;
 
 	disp->var = *var;
-	disp->visual = fix->visual;
-	disp->type = fix->type;
-	disp->type_aux = fix->type_aux;
-	disp->line_length = fix->line_length;
 	
 	if (fb->blank)
 		disp->can_soft_blank = 1;
diff -Nru a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
--- a/drivers/video/sgivwfb.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/sgivwfb.c	Tue Aug 27 12:28:05 2002
@@ -55,34 +55,34 @@
 static int ywrap = 0;
 
 static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
-	id:		"SGI Vis WS FB",
-	type:		FB_TYPE_PACKED_PIXELS,
-        visual:		FB_VISUAL_PSEUDOCOLOR,
-	mmio_start:	DBE_REG_PHYS,
-	mmio_len:	DBE_REG_SIZE,
-        accel_flags:	FB_ACCEL_NONE
+	.id		= "SGI Vis WS FB",
+	.type		= FB_TYPE_PACKED_PIXELS,
+        .visual		= FB_VISUAL_PSEUDOCOLOR,
+	.mmio_start	= DBE_REG_PHYS,
+	.mmio_len	= DBE_REG_SIZE,
+        .accel_flags	= FB_ACCEL_NONE
 };
 
 static struct fb_var_screeninfo sgivwfb_var __initdata = {
         /* 640x480, 8 bpp */
-        xres:		640,
-	yres:		480,
-	xres_virtual:	640,
-	yres_virtual:	480,
-	bits_per_pixel:	8,
-        red:		{0, 8, 0},
-	green:		{0, 8, 0},
-	blue:		{0, 8, 0},
-        height:		-1,
-	width:		-1,
-	pixclock:	20000,
-	left_margin:	64,
-	right_margin:	64,
-	upper_margin:	32,
-	lower_margin:	32,
-	hsync_len:	64,
-	vsync_len:	2,
-        vmode:		FB_VMODE_NONINTERLACED
+        .xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 8,
+        .red		= {0, 8, 0},
+	.green		= {0, 8, 0},
+	.blue		= {0, 8, 0},
+        .height		= -1,
+	.width		= -1,
+	.pixclock	= 20000,
+	.left_margin	= 64,
+	.right_margin	= 64,
+	.upper_margin	= 32,
+	.lower_margin	= 32,
+	.hsync_len	= 64,
+	.vsync_len	= 2,
+        .vmode		= FB_VMODE_NONINTERLACED
 };
 
 /* console related variables */
@@ -103,19 +103,17 @@
 			struct vm_area_struct *vma);
 
 static struct fb_ops sgivwfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_check_var:	sgivwfb_check_var,
-	fb_set_par:	sgivwfb_set_par,
-	fb_setcolreg:	sgivwfb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
-	fb_mmap:	sgivwfb_mmap,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= sgivwfb_check_var,
+	.fb_set_par	= sgivwfb_set_par,
+	.fb_setcolreg	= sgivwfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_mmap	= sgivwfb_mmap,
 };
 
 /*
diff -Nru a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
--- a/drivers/video/sis/sis_main.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/sis/sis_main.c	Tue Aug 27 12:28:08 2002
@@ -2559,18 +2559,18 @@
 }
 
 static struct fb_ops sisfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sisfb_get_fix,
-	fb_get_var:	sisfb_get_var,
-	fb_set_var:	sisfb_set_var,
-	fb_get_cmap:	sisfb_get_cmap,
-	fb_set_cmap:	sisfb_set_cmap,
+	.owner		= THIS_MODULE,
+	.fb_get_fix	= sisfb_get_fix,
+	.fb_get_var	= sisfb_get_var,
+	.fb_set_var	= sisfb_set_var,
+	.fb_get_cmap	= sisfb_get_cmap,
+	.fb_set_cmap	= sisfb_set_cmap,
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
-        fb_setcolreg:   sisfb_setcolreg,
-        fb_blank:       sisfb_blank,
+        .fb_setcolreg	= sisfb_setcolreg,
+        .fb_blank	= sisfb_blank,
 #endif
-	fb_ioctl:	sisfb_ioctl,
-	fb_mmap:	sisfb_mmap,
+	.fb_ioctl	= sisfb_ioctl,
+	.fb_mmap	= sisfb_mmap,
 };
 
 /* ------------ Interface to the low level console driver -------------*/
diff -Nru a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
--- a/drivers/video/skeletonfb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/skeletonfb.c	Tue Aug 27 12:28:01 2002
@@ -80,13 +80,13 @@
  * to get a fb_var_screeninfo. Otherwise define a default var as well. 
  */
 static struct fb_fix_screeninfo xxxfb_fix __initdata = {
-	id:		"FB's name", 
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	xpanstep:	1,
-	ypanstep:	1,
-	ywrapstep:	1, 
-	accel:		FB_ACCEL_NONE,
+	.id =		"FB's name", 
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1, 
+	.accel =	FB_ACCEL_NONE,
 };
 
     /*
@@ -507,26 +507,24 @@
 }
 
 static struct fb_ops xxxfb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	xxxfb_open,    /* only if you need it to do something */
-	fb_release:	xxxfb_release, /* only if you need it to do something */
+	.owner		= THIS_MODULE,
+	.fb_open	= xxxfb_open,    /* only if you need it to do something */
+	.fb_release	= xxxfb_release, /* only if you need it to do something */
 	/* Stuff to go away. Use generic functions for now */
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,	
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-
-	fb_check_var:	xxxfb_check_var,
-	fb_set_par:	xxxfb_set_par,	   /* optional */	
-	fb_setcolreg:	xxxfb_setcolreg,
-	fb_blank:	xxxfb_blank,	   /* optional */
-	fb_pan_display:	xxxfb_pan_display, /* optional */	
-	fb_fillrect:	xxxfb_fillrect,  
-	fb_copyarea:	xxxfb_copyarea,  
-	fb_imageblit:	xxxfb_imageblit, 
-	fb_ioctl:       xxxfb_ioctl,     /* optional */
-	fb_mmap:	xxxfb_mmap,      /* optional */	
+	.fb_set_var	= gen_set_var,	
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+
+	.fb_check_var	= xxxfb_check_var,
+	.fb_set_par	= xxxfb_set_par,	/* optional */	
+	.fb_setcolreg	= xxxfb_setcolreg,
+	.fb_blank	= xxxfb_blank,		/* optional */
+	.fb_pan_display	= xxxfb_pan_display,	/* optional */	
+	.fb_fillrect	= xxxfb_fillrect,  
+	.fb_copyarea	= xxxfb_copyarea,  
+	.fb_imageblit	= xxxfb_imageblit, 
+	.fb_ioctl	= xxxfb_ioctl,		/* optional */
+	.fb_mmap	= xxxfb_mmap,		/* optional */	
 };
 
 /* ------------------------------------------------------------------------- */
diff -Nru a/drivers/video/sstfb.c b/drivers/video/sstfb.c
--- a/drivers/video/sstfb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/sstfb.c	Tue Aug 27 12:28:07 2002
@@ -205,16 +205,16 @@
 static void sst_shutdown(struct sstfb_info *sst_info);
 
 static struct fb_ops sstfb_ops = {
-	owner : THIS_MODULE,
-	fb_open:	sstfb_open,
-	fb_release:	sstfb_release,
-	fb_get_fix:	sstfb_get_fix,
-	fb_get_var:	sstfb_get_var,
-	fb_set_var:	sstfb_set_var,
-	fb_get_cmap:	sstfb_get_cmap,
-	fb_set_cmap:	sstfb_set_cmap,
-	fb_pan_display:	sstfb_pan_display,
-	fb_ioctl:	sstfb_ioctl,
+	.owner		= THIS_MODULE,
+	.fb_open	= sstfb_open,
+	.fb_release	= sstfb_release,
+	.fb_get_fix	= sstfb_get_fix,
+	.fb_get_var	= sstfb_get_var,
+	.fb_set_var	= sstfb_set_var,
+	.fb_get_cmap	= sstfb_get_cmap,
+	.fb_set_cmap	= sstfb_set_cmap,
+	.fb_pan_display	= sstfb_pan_display,
+	.fb_ioctl	= sstfb_ioctl,
 };
 
 enum {
@@ -225,12 +225,12 @@
 #define IS_VOODOO2(info) ((info)->type == ID_VOODOO2 )
 
 static struct sst_spec voodoo_spec[] __devinitdata = {
-	{ name : "Voodoo Graphics",
-	default_gfx_clock : 50000,
-	max_gfxclk : 60, },
-	{ name : "Voodoo2",
-	default_gfx_clock : 75000,
-	max_gfxclk : 85, },
+	{ .name = "Voodoo Graphics",
+	.default_gfx_clock = 50000,
+	.max_gfxclk = 60, },
+	{ .name = "Voodoo2",
+	.default_gfx_clock = 75000,
+	.max_gfxclk = 85, },
 };
 
 static struct pci_device_id sstfb_id_tbl[] __devinitdata = {
@@ -242,10 +242,10 @@
 };
 
 static struct pci_driver sstfb_driver = {
-	name:		"sstfb",
-	id_table:	sstfb_id_tbl,
-	probe:          sstfb_probe,
-	remove:		__devexit_p(sstfb_remove),
+	.name		= "sstfb",
+	.id_table	= sstfb_id_tbl,
+	.probe		= sstfb_probe,
+	.remove		= __devexit_p(sstfb_remove),
 };
 
 static struct fb_var_screeninfo	sstfb_default =
@@ -283,19 +283,19 @@
 #endif
 
 static struct dac_switch dacs[] __devinitdata = {
-	{	name:		"TI TVP3409",
-		detect:		sst_detect_ti,
-		set_pll:	sst_set_pll_att_ti,
-		set_vidmod:	sst_set_vidmod_att_ti },
-
-	{	name:		"AT&T ATT20C409",
-		detect:		sst_detect_att,
-		set_pll:	sst_set_pll_att_ti,
-		set_vidmod:	sst_set_vidmod_att_ti },
-	{	name:		"ICS ICS5342",
-		detect:		sst_detect_ics,
-		set_pll:	sst_set_pll_ics,
-		set_vidmod:	sst_set_vidmod_ics },
+	{	.name		= "TI TVP3409",
+		.detect		= sst_detect_ti,
+		.set_pll	= sst_set_pll_att_ti,
+		.set_vidmod	= sst_set_vidmod_att_ti },
+
+	{	.name		= "AT&T ATT20C409",
+		.detect		= sst_detect_att,
+		.set_pll	= sst_set_pll_att_ti,
+		.set_vidmod	= sst_set_vidmod_att_ti },
+	{	.name		= "ICS ICS5342",
+		.detect		= sst_detect_ics,
+		.set_pll	= sst_set_pll_ics,
+		.set_vidmod	= sst_set_vidmod_ics },
 };
 
 
diff -Nru a/drivers/video/sticon-bmode.c b/drivers/video/sticon-bmode.c
--- a/drivers/video/sticon-bmode.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/sticon-bmode.c	Tue Aug 27 12:28:08 2002
@@ -182,9 +182,9 @@
 static void sti_inq_conf(struct sti_struct *sti)
 {
 	struct sti_conf_inptr inptr = { NULL };
-	struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
+	struct sti_conf_outptr_ext outptr_ext = { .future_ptr = NULL };
 	struct sti_conf_outptr outptr = {
-		ext_ptr: STI_PTR(&outptr_ext)
+		.ext_ptr = STI_PTR(&outptr_ext)
 	};
 	unsigned long flags;
 	s32 ret;
@@ -415,22 +415,22 @@
 }
 
 static struct consw sti_con = {
-	con_startup: 		sticon_startup, 
-	con_init: 		sticon_init,
-	con_deinit: 		sticon_deinit,
-	con_clear: 		sticon_clear,
-	con_putc: 		sticon_putc,
-	con_putcs: 		sticon_putcs,
-	con_cursor: 		sticon_cursor,
-	con_scroll: 		sticon_scroll,
-	con_bmove: 		sticon_bmove,
-	con_switch: 		sticon_switch,
-	con_blank: 		sticon_blank,
-	con_font_op:		sticon_font_op,
-	con_set_palette:	sticon_set_palette,
-	con_scrolldelta:	sticon_scrolldelta,
-	con_set_origin: 	sticon_set_origin,
-	con_build_attr:		sticon_build_attr,
+	.con_startup = 		sticon_startup, 
+	.con_init = 		sticon_init,
+	.con_deinit = 		sticon_deinit,
+	.con_clear = 		sticon_clear,
+	.con_putc = 		sticon_putc,
+	.con_putcs = 		sticon_putcs,
+	.con_cursor = 		sticon_cursor,
+	.con_scroll = 		sticon_scroll,
+	.con_bmove = 		sticon_bmove,
+	.con_switch = 		sticon_switch,
+	.con_blank = 		sticon_blank,
+	.con_font_op =		sticon_font_op,
+	.con_set_palette =	sticon_set_palette,
+	.con_scrolldelta =	sticon_scrolldelta,
+	.con_set_origin = 	sticon_set_origin,
+	.con_build_attr =	sticon_build_attr,
 };
 
 #include <asm/pgalloc.h>	/* need cache flush routines */
diff -Nru a/drivers/video/sticon.c b/drivers/video/sticon.c
--- a/drivers/video/sticon.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/sticon.c	Tue Aug 27 12:28:08 2002
@@ -183,22 +183,22 @@
 }
 
 struct consw sti_con = {
-	con_startup: 		sticon_startup, 
-	con_init: 		sticon_init,
-	con_deinit: 		sticon_deinit,
-	con_clear: 		sticon_clear,
-	con_putc: 		sticon_putc,
-	con_putcs: 		sticon_putcs,
-	con_cursor: 		sticon_cursor,
-	con_scroll: 		sticon_scroll,
-	con_bmove: 		sticon_bmove,
-	con_switch: 		sticon_switch,
-	con_blank: 		sticon_blank,
-	con_font_op:		sticon_font_op,
-	con_set_palette:	sticon_set_palette,
-	con_scrolldelta:	sticon_scrolldelta,
-	con_set_origin: 	sticon_set_origin,
-	con_build_attr:		sticon_build_attr,
+	.con_startup = 		sticon_startup, 
+	.con_init = 		sticon_init,
+	.con_deinit = 		sticon_deinit,
+	.con_clear = 		sticon_clear,
+	.con_putc = 		sticon_putc,
+	.con_putcs = 		sticon_putcs,
+	.con_cursor = 		sticon_cursor,
+	.con_scroll = 		sticon_scroll,
+	.con_bmove = 		sticon_bmove,
+	.con_switch = 		sticon_switch,
+	.con_blank = 		sticon_blank,
+	.con_font_op =		sticon_font_op,
+	.con_set_palette =	sticon_set_palette,
+	.con_scrolldelta =	sticon_scrolldelta,
+	.con_set_origin = 	sticon_set_origin,
+	.con_build_attr =	sticon_build_attr,
 };
 
 static int __init sti_init(void)
diff -Nru a/drivers/video/sticore.c b/drivers/video/sticore.c
--- a/drivers/video/sticore.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/sticore.c	Tue Aug 27 12:28:02 2002
@@ -75,9 +75,9 @@
 sti_inq_conf(struct sti_struct *sti)
 {
 	struct sti_conf_inptr inptr = { NULL };
-	struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
+	struct sti_conf_outptr_ext outptr_ext = { .future_ptr = NULL };
 	struct sti_conf_outptr outptr = {
-		ext_ptr: STI_PTR(&outptr_ext)
+		.ext_ptr = STI_PTR(&outptr_ext)
 	};
 	unsigned long flags;
 	s32 ret;
diff -Nru a/drivers/video/stifb.c b/drivers/video/stifb.c
--- a/drivers/video/stifb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/stifb.c	Tue Aug 27 12:28:08 2002
@@ -123,14 +123,14 @@
 /* ------------ Interfaces to hardware functions ------------ */
 
 struct fbgen_hwswitch sti_switch = {
-	detect:		sti_detect,
-	encode_fix:	sti_encode_fix,
-	decode_var:	sti_decode_var,
-	encode_var:	sti_encode_var,
-	get_par:	sti_get_par,
-	set_par:	sti_set_par,
-	getcolreg:	sti_getcolreg,
-	set_disp:	sti_set_disp
+	.detect =	sti_detect,
+	.encode_fix =	sti_encode_fix,
+	.decode_var =	sti_decode_var,
+	.encode_var =	sti_encode_var,
+	.get_par =	sti_get_par,
+	.set_par =	sti_set_par,
+	.getcolreg =	sti_getcolreg,
+	.set_disp =	sti_set_disp
 };
 
 
@@ -199,12 +199,12 @@
 
 
 static struct fb_ops stifb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_pan_display:	fbgen_pan_display,
-	fb_blank:	fbgen_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_blank =	fbgen_blank,
 };
diff -Nru a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
--- a/drivers/video/sun3fb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/sun3fb.c	Tue Aug 27 12:28:02 2002
@@ -109,14 +109,14 @@
 			    u_int *transp, struct fb_info *info);
 
 static struct fb_ops sun3fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sun3fb_get_fix,
-	fb_get_var:	sun3fb_get_var,
-	fb_set_var:	sun3fb_set_var,
-	fb_get_cmap:	sun3fb_get_cmap,
-	fb_set_cmap:	sun3fb_set_cmap,
-	fb_setcolreg:	sun3fb_setcolreg,
-	fb_blank:	sun3fb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	sun3fb_get_fix,
+	.fb_get_var =	sun3fb_get_var,
+	.fb_set_var =	sun3fb_set_var,
+	.fb_get_cmap =	sun3fb_get_cmap,
+	.fb_set_cmap =	sun3fb_set_cmap,
+	.fb_setcolreg =	sun3fb_setcolreg,
+	.fb_blank =	sun3fb_blank,
 };
 
 static void sun3fb_clear_margin(struct display *p, int s)
diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/tdfxfb.c	Tue Aug 27 12:28:02 2002
@@ -91,36 +91,36 @@
 #define VOODOO5_MAX_PIXCLOCK 350000.0
 
 static struct fb_fix_screeninfo tdfx_fix __initdata = {
-	id:		"3Dfx",
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR, 
-	ypanstep:	1,
-	ywrapstep:	1, 
-	accel:		FB_ACCEL_3DFX_BANSHEE
+	.id =		"3Dfx",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR, 
+	.ypanstep =	1,
+	.ywrapstep =	1, 
+	.accel =	FB_ACCEL_3DFX_BANSHEE
 };
 
 static struct fb_var_screeninfo tdfx_var __initdata = {
 	/* "640x480, 8 bpp @ 60 Hz */
-	xres:		640,
-	yres:		480,
-	xres_virtual:	640,
-	yres_virtual:	1024,
-	bits_per_pixel:	8,
-	red:		{0, 8, 0},
-	blue:		{0, 8, 0},
-	green:		{0, 8, 0},
-	activate:	FB_ACTIVATE_NOW,
-	height:		-1,
-	width:		-1,
-	accel_flags:	FB_ACCELF_TEXT,
-	pixclock:	39722,
-	left_margin:	40,
-	right_margin:	24,
-	upper_margin:	32,
-	lower_margin:	11,
-	hsync_len:	96,
-	vsync_len:	2,
-	vmode:		FB_VMODE_NONINTERLACED
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	1024,
+	.bits_per_pixel =8,
+	.red =		{0, 8, 0},
+	.blue =		{0, 8, 0},
+	.green =	{0, 8, 0},
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.accel_flags =	FB_ACCELF_TEXT,
+	.pixclock =	39722,
+	.left_margin =	40,
+	.right_margin =	24,
+	.upper_margin =	32,
+	.lower_margin =	11,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.vmode =	FB_VMODE_NONINTERLACED
 };
 
 /*
@@ -143,10 +143,10 @@
 };
 
 static struct pci_driver tdfxfb_driver = {
-	name:		"tdfxfb",
-	id_table:	tdfxfb_id_table,
-	probe:		tdfxfb_probe,
-	remove:		tdfxfb_remove,
+	.name =		"tdfxfb",
+	.id_table =	tdfxfb_id_table,
+	.probe =	tdfxfb_probe,
+	.remove =	tdfxfb_remove,
 };
 
 MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
@@ -168,20 +168,18 @@
 static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *image); 
 
 static struct fb_ops tdfxfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_check_var:	tdfxfb_check_var,
-	fb_set_par:	tdfxfb_set_par,
-	fb_setcolreg:	tdfxfb_setcolreg,
-	fb_blank:	tdfxfb_blank,
-	fb_pan_display:	tdfxfb_pan_display,
-	fb_fillrect:	tdfxfb_fillrect,
-	fb_copyarea:	tdfxfb_copyarea,
-	fb_imageblit:	tdfxfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= tdfxfb_check_var,
+	.fb_set_par	= tdfxfb_set_par,
+	.fb_setcolreg	= tdfxfb_setcolreg,
+	.fb_blank	= tdfxfb_blank,
+	.fb_pan_display	= tdfxfb_pan_display,
+	.fb_fillrect	= tdfxfb_fillrect,
+	.fb_copyarea	= tdfxfb_copyarea,
+	.fb_imageblit	= tdfxfb_imageblit,
 };
 
 /*
diff -Nru a/drivers/video/tgafb.c b/drivers/video/tgafb.c
--- a/drivers/video/tgafb.c	Tue Aug 27 12:28:01 2002
+++ b/drivers/video/tgafb.c	Tue Aug 27 12:28:01 2002
@@ -867,14 +867,14 @@
      */
 
 static struct fb_ops tgafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	tgafb_set_cmap,
-	fb_setcolreg:	tgafb_setcolreg,
-	fb_blank:	fbgen_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	tgafb_set_cmap,
+	.fb_setcolreg =	tgafb_setcolreg,
+	.fb_blank =	fbgen_blank,
 };
 
 
diff -Nru a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
--- a/drivers/video/tridentfb.c	Tue Aug 27 12:28:06 2002
+++ b/drivers/video/tridentfb.c	Tue Aug 27 12:28:06 2002
@@ -351,14 +351,14 @@
 }
 
 static struct display_switch trident_8bpp = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		trident_bmove,
-	clear:		trident_8bpp_clear,
-	putc:		fbcon_cfb8_putc,
-	putcs:		fbcon_cfb8_putcs,
-	revc:		fbcon_cfb8_revc,
-	clear_margins:	fbcon_cfb8_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	trident_bmove,
+	.clear =	trident_8bpp_clear,
+	.putc =		fbcon_cfb8_putc,
+	.putcs =	fbcon_cfb8_putcs,
+	.revc =		fbcon_cfb8_revc,
+	.clear_margins =fbcon_cfb8_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
@@ -372,14 +372,14 @@
 }
 
 static struct display_switch trident_16bpp = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		trident_bmove,
-	clear:		trident_16bpp_clear,
-	putc:		fbcon_cfb16_putc,
-	putcs:		fbcon_cfb16_putcs,
-	revc:		fbcon_cfb16_revc,
-	clear_margins:	fbcon_cfb16_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb16_setup,
+	.bmove =	trident_bmove,
+	.clear =	trident_16bpp_clear,
+	.putc =		fbcon_cfb16_putc,
+	.putcs =	fbcon_cfb16_putcs,
+	.revc =		fbcon_cfb16_revc,
+	.clear_margins =fbcon_cfb16_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -392,14 +392,14 @@
 }
 
 static struct display_switch trident_32bpp = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		trident_bmove,
-	clear:		trident_32bpp_clear,
-	putc:		fbcon_cfb32_putc,
-	putcs:		fbcon_cfb32_putcs,
-	revc:		fbcon_cfb32_revc,
-	clear_margins:	fbcon_cfb32_clear_margins,
-	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+	.setup =	fbcon_cfb32_setup,
+	.bmove =	trident_bmove,
+	.clear =	trident_32bpp_clear,
+	.putc =		fbcon_cfb32_putc,
+	.putcs =	fbcon_cfb32_putcs,
+	.revc =		fbcon_cfb32_revc,
+	.clear_margins =fbcon_cfb32_clear_margins,
+	.fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
 };
 #endif
 
@@ -1286,13 +1286,13 @@
 }
 
 static struct fb_ops tridentfb_ops = {
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
-	fb_setcolreg:	tridentfb_setcolreg,
-	fb_pan_display:	fbgen_pan_display,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	fbgen_set_cmap,
+	.fb_setcolreg =	tridentfb_setcolreg,
+	.fb_pan_display =fbgen_pan_display,
 };
 
 #ifdef MODULE
diff -Nru a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
--- a/drivers/video/tx3912fb.c	Tue Aug 27 12:28:07 2002
+++ b/drivers/video/tx3912fb.c	Tue Aug 27 12:28:07 2002
@@ -36,44 +36,44 @@
 static struct display disp;
 
 static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
-	id:		"tx3912fb",
+	.id =		"tx3912fb",
 #ifdef CONFIG_NINO_16MB
-	smem_len:	(240 * 320),
+	.smem_len =	(240 * 320),
 #else
-	smem_len:	((240 * 320)/2),
+	.smem_len =	((240 * 320)/2),
 #endif
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_TRUECOLOR, 
-	xpanstep:	1,
-	ypanstep:	1,
-	ywrapstep:	1,
-	accel:		FB_ACCEL_NONE,
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR, 
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel =	FB_ACCEL_NONE,
 };
 
 static struct fb_var_screeninfo tx3912fb_var = {
-	xres:		240,
-	yres:		320,
-	xres_virtual:	240,
-	yres_virtual:	320,
+	.xres =		240,
+	.yres =		320,
+	.xres_virtual =	240,
+	.yres_virtual =	320,
 #ifdef CONFIG_NINO_16MB
-	bits_per_pixel:	8,
-	red:		{ 5, 3, 0 },	/* RGB 332 */
-	green:		{ 2, 3, 0 },
-	blue:		{ 0, 2, 0 },
+	.bits_per_pixel =8,
+	.red =		{ 5, 3, 0 },	/* RGB 332 */
+	.green =	{ 2, 3, 0 },
+	.blue =		{ 0, 2, 0 },
 #else
-	bits_per_pixel:	4,
+	.bits_per_pixel =4,
 #endif
-	activate:	FB_ACTIVATE_NOW,
-	width:		-1,
-	height:		-1,
-	pixclock:	20000,
-	left_margin:	64,
-	right_margin:	64,
-	upper_margin:	32,
-	lower_margin:	32,
-	hsync_len:	64,
-	vsync_len:	2,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.activate =	FB_ACTIVATE_NOW,
+	.width =	-1,
+	.height =	-1,
+	.pixclock =	20000,
+	.left_margin =	64,
+	.right_margin =	64,
+	.upper_margin =	32,
+	.lower_margin =	32,
+	.hsync_len =	64,
+	.vsync_len =	2,
+	.vmode =	FB_VMODE_NONINTERLACED,
 };
 
 /*
@@ -95,16 +95,14 @@
  * Frame buffer operations structure used by console driver
  */
 static struct fb_ops tx3912fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	tx3912fb_setcolreg,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= tx3912fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
diff -Nru a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
--- a/drivers/video/valkyriefb.c	Tue Aug 27 12:28:08 2002
+++ b/drivers/video/valkyriefb.c	Tue Aug 27 12:28:08 2002
@@ -156,14 +156,14 @@
 static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p);
 
 static struct fb_ops valkyriefb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	valkyrie_get_fix,
-	fb_get_var:	valkyrie_get_var,
-	fb_set_var:	valkyrie_set_var,
-	fb_get_cmap:	valkyrie_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	valkyriefb_setcolreg,
-	fb_blank:	valkyriefb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	valkyrie_get_fix,
+	.fb_get_var =	valkyrie_get_var,
+	.fb_set_var =	valkyrie_set_var,
+	.fb_get_cmap =	valkyrie_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	valkyriefb_setcolreg,
+	.fb_blank =	valkyriefb_blank,
 };
 
 static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green,
diff -Nru a/drivers/video/vesafb.c b/drivers/video/vesafb.c
--- a/drivers/video/vesafb.c	Tue Aug 27 12:27:59 2002
+++ b/drivers/video/vesafb.c	Tue Aug 27 12:27:59 2002
@@ -33,20 +33,20 @@
 /* --------------------------------------------------------------------- */
 
 static struct fb_var_screeninfo vesafb_defined __initdata = {
-	activate:	FB_ACTIVATE_NOW,
-	height:		-1,
-	width:		-1,
-	right_margin:	32,
-	upper_margin:	16,
-	lower_margin:	4,
-	vsync_len:	4,
-	vmode:		FB_VMODE_NONINTERLACED,
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.right_margin	= 32,
+	.upper_margin	= 16,
+	.lower_margin	= 4,
+	.vsync_len	= 4,
+	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo vesafb_fix __initdata = {
-	id:	"VESA VGA",
-	type:	FB_TYPE_PACKED_PIXELS,
-	accel:	FB_ACCEL_NONE,
+	.id	= "VESA VGA",
+	.type	= FB_TYPE_PACKED_PIXELS,
+	.accel	= FB_ACCEL_NONE,
 };
 
 static struct display disp;
@@ -174,17 +174,15 @@
 }
 
 static struct fb_ops vesafb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	vesafb_setcolreg,
-	fb_pan_display:	vesafb_pan_display,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= gen_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= vesafb_setcolreg,
+	.fb_pan_display	= vesafb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
 };
 
 int __init vesafb_setup(char *options)
diff -Nru a/drivers/video/vfb.c b/drivers/video/vfb.c
--- a/drivers/video/vfb.c	Tue Aug 27 12:27:39 2002
+++ b/drivers/video/vfb.c	Tue Aug 27 12:27:39 2002
@@ -45,35 +45,35 @@
 static struct display disp;
 
 static struct fb_var_screeninfo vfb_default __initdata = {
-	xres:		640,
-	yres:		480,
-	xres_virtual:	640,
-	yres_virtual:	480,
-	bits_per_pixel:	8,
-	red:		{ 0, 8, 0 },
-      	green:		{ 0, 8, 0 },
-      	blue:		{ 0, 8, 0 },
-      	activate:	FB_ACTIVATE_TEST,
-      	height:		-1,
-      	width:		-1,
-      	pixclock:	20000,
-      	left_margin:	64,
-      	right_margin:	64,
-      	upper_margin:	32,
-      	lower_margin:	32,
-      	hsync_len:	64,
-      	vsync_len:	2,
-      	vmode:		FB_VMODE_NONINTERLACED,
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	480,
+	.bits_per_pixel = 8,
+	.red =		{ 0, 8, 0 },
+      	.green =	{ 0, 8, 0 },
+      	.blue =		{ 0, 8, 0 },
+      	.activate =	FB_ACTIVATE_TEST,
+      	.height =	-1,
+      	.width =	-1,
+      	.pixclock =	20000,
+      	.left_margin =	64,
+      	.right_margin =	64,
+      	.upper_margin =	32,
+      	.lower_margin =	32,
+      	.hsync_len =	64,
+      	.vsync_len =	2,
+      	.vmode =	FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo vfb_fix __initdata = {
-	id:		"Virtual FB",
-	type:		FB_TYPE_PACKED_PIXELS,
-	visual:		FB_VISUAL_PSEUDOCOLOR,
-	xpanstep:	1,
-	ypanstep:	1,
-	ywrapstep:	1,
-	accel:		FB_ACCEL_NONE,
+	.id =		"Virtual FB",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel =	FB_ACCEL_NONE,
 };
 
 static int vfb_enable __initdata = 0;	/* disabled by default */
@@ -96,19 +96,17 @@
 		    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
-	fb_get_fix:	gen_get_fix,
-	fb_get_var:	gen_get_var,
-	fb_set_var:	gen_set_var,
-	fb_get_cmap:	gen_set_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_check_var:	vfb_check_var,
-	fb_set_par:	vfb_set_par,
-	fb_setcolreg:	vfb_setcolreg,
-	fb_pan_display:	vfb_pan_display,
-	fb_fillrect:	cfb_fillrect,
-	fb_copyarea:	cfb_copyarea,
-	fb_imageblit:	cfb_imageblit,
-	fb_mmap:	vfb_mmap,
+	.fb_set_var	gen_set_var,
+	.fb_get_cmap	gen_set_cmap,
+	.fb_set_cmap	gen_set_cmap,
+	.fb_check_var	vfb_check_var,
+	.fb_set_par	vfb_set_par,
+	.fb_setcolreg	vfb_setcolreg,
+	.fb_pan_display	vfb_pan_display,
+	.fb_fillrect	cfb_fillrect,
+	.fb_copyarea	cfb_copyarea,
+	.fb_imageblit	cfb_imageblit,
+	.fb_mmap	vfb_mmap,
 };
 
     /*
diff -Nru a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
--- a/drivers/video/vga16fb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/vga16fb.c	Tue Aug 27 12:28:02 2002
@@ -810,15 +810,15 @@
 }
 
 static struct fb_ops vga16fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	vga16fb_get_fix,
-	fb_get_var:	vga16fb_get_var,
-	fb_set_var:	vga16fb_set_var,
-	fb_get_cmap:	vga16fb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	vga16fb_setcolreg,
-	fb_pan_display:	vga16fb_pan_display,
-	fb_blank:	vga16fb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	vga16fb_get_fix,
+	.fb_get_var =	vga16fb_get_var,
+	.fb_set_var =	vga16fb_set_var,
+	.fb_get_cmap =	vga16fb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	vga16fb_setcolreg,
+	.fb_pan_display =vga16fb_pan_display,
+	.fb_blank =	vga16fb_blank,
 };
 
 int vga16fb_setup(char *options)
diff -Nru a/drivers/video/vgacon.c b/drivers/video/vgacon.c
--- a/drivers/video/vgacon.c	Tue Aug 27 12:28:05 2002
+++ b/drivers/video/vgacon.c	Tue Aug 27 12:28:05 2002
@@ -1032,24 +1032,24 @@
 #define DUMMY (void *) vgacon_dummy
 
 const struct consw vga_con = {
-	con_startup:		vgacon_startup,
-	con_init:		vgacon_init,
-	con_deinit:		vgacon_deinit,
-	con_clear:		DUMMY,
-	con_putc:		DUMMY,
-	con_putcs:		DUMMY,
-	con_cursor:		vgacon_cursor,
-	con_scroll:		vgacon_scroll,
-	con_bmove:		DUMMY,
-	con_switch:		vgacon_switch,
-	con_blank:		vgacon_blank,
-	con_font_op:		vgacon_font_op,
-	con_set_palette:	vgacon_set_palette,
-	con_scrolldelta:	vgacon_scrolldelta,
-	con_set_origin:		vgacon_set_origin,
-	con_save_screen:	vgacon_save_screen,
-	con_build_attr:		vgacon_build_attr,
-	con_invert_region:	vgacon_invert_region,
+	.con_startup =		vgacon_startup,
+	.con_init =		vgacon_init,
+	.con_deinit =		vgacon_deinit,
+	.con_clear =		DUMMY,
+	.con_putc =		DUMMY,
+	.con_putcs =		DUMMY,
+	.con_cursor =		vgacon_cursor,
+	.con_scroll =		vgacon_scroll,
+	.con_bmove =		DUMMY,
+	.con_switch =		vgacon_switch,
+	.con_blank =		vgacon_blank,
+	.con_font_op =		vgacon_font_op,
+	.con_set_palette =	vgacon_set_palette,
+	.con_scrolldelta =	vgacon_scrolldelta,
+	.con_set_origin =	vgacon_set_origin,
+	.con_save_screen =	vgacon_save_screen,
+	.con_build_attr =	vgacon_build_attr,
+	.con_invert_region =	vgacon_invert_region,
 };
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/virgefb.c b/drivers/video/virgefb.c
--- a/drivers/video/virgefb.c	Tue Aug 27 12:28:02 2002
+++ b/drivers/video/virgefb.c	Tue Aug 27 12:28:02 2002
@@ -1348,12 +1348,12 @@
 /* -------------------- Interfaces to hardware functions -------------------- */
 
 static struct fb_hwswitch virgefb_hw_switch = {
-	init:		virge_init,
-	encode_fix:	virgefb_encode_fix,
-	decode_var:	virgefb_decode_var,
-	encode_var:	virgefb_encode_var,
-	getcolreg:	virgefb_getcolreg,
-	blank:		virgefb_gfx_on_off
+	.init		= virge_init,
+	.encode_fix	= virgefb_encode_fix,
+	.decode_var	= virgefb_decode_var,
+	.encode_var	= virgefb_encode_var,
+	.getcolreg	= virgefb_getcolreg,
+	.blank		= virgefb_gfx_on_off
 };
 
 
@@ -1626,14 +1626,14 @@
 }
 
 static struct fb_ops virgefb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	virgefb_get_fix,
-	fb_get_var:	virgefb_get_var,
-	fb_set_var:	virgefb_set_var,
-	fb_get_cmap:	virgefb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	virgefb_setcolreg,
-	fb_blank:	virgefb_blank,
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	virgefb_get_fix,
+	.fb_get_var =	virgefb_get_var,
+	.fb_set_var =	virgefb_set_var,
+	.fb_get_cmap =	virgefb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	virgefb_setcolreg,
+	.fb_blank =	virgefb_blank,
 };
 
 int __init virgefb_setup(char *options)
@@ -1917,14 +1917,14 @@
 }
 
 static struct display_switch fbcon_virge8 = {
-	setup:		fbcon_cfb8_setup,
-	bmove:		fbcon_virge8_bmove,
-	clear:		fbcon_virge8_clear,
-	putc:		fbcon_virge8_putc,
-	putcs:		fbcon_virge8_putcs,
-	revc:		fbcon_virge8_revc,
-	clear_margins:	fbcon_virge8_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb8_setup,
+	.bmove		= fbcon_virge8_bmove,
+	.clear		= fbcon_virge8_clear,
+	.putc		= fbcon_virge8_putc,
+	.putcs		= fbcon_virge8_putcs,
+	.revc		= fbcon_virge8_revc,
+	.clear_margins	= fbcon_virge8_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -1982,14 +1982,14 @@
 }
 
 static struct display_switch fbcon_virge16 = {
-	setup:		fbcon_cfb16_setup,
-	bmove:		fbcon_virge16_bmove,
-	clear:		fbcon_virge16_clear,
-	putc:		fbcon_virge16_putc,
-	putcs:		fbcon_virge16_putcs,
-	revc:		fbcon_virge16_revc,
-	clear_margins:	fbcon_virge16_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb16_setup,
+	.bmove		= fbcon_virge16_bmove,
+	.clear		= fbcon_virge16_clear,
+	.putc		= fbcon_virge16_putc,
+	.putcs		= fbcon_virge16_putcs,
+	.revc		= fbcon_virge16_revc,
+	.clear_margins	= fbcon_virge16_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -2047,14 +2047,14 @@
 }
 
 static struct display_switch fbcon_virge32 = {
-	setup:		fbcon_cfb32_setup,
-	bmove:		fbcon_virge32_bmove,
-	clear:		fbcon_virge32_clear,
-	putc:		fbcon_virge32_putc,
-	putcs:		fbcon_virge32_putcs,
-	revc:		fbcon_virge32_revc,
-	clear_margins:	fbcon_virge32_clear_margins,
-	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb32_setup,
+	.bmove		= fbcon_virge32_bmove,
+	.clear		= fbcon_virge32_clear,
+	.putc		= fbcon_virge32_putc,
+	.putcs		= fbcon_virge32_putcs,
+	.revc		= fbcon_virge32_revc,
+	.clear_margins	= fbcon_virge32_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Tue Aug 27 12:27:51 2002
+++ b/fs/Makefile	Tue Aug 27 12:27:51 2002
@@ -7,14 +7,14 @@
 
 O_TARGET := fs.o
 
-export-objs :=	open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o
+export-objs :=	open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
-		fs-writeback.o mpage.o direct-io.o
+		fs-writeback.o mpage.o direct-io.o aio.o
 
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
diff -Nru a/fs/aio.c b/fs/aio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/aio.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,1116 @@
+/*
+ *	An async IO implementation for Linux
+ *	Written by Benjamin LaHaise <bcrl@redhat.com>
+ *
+ *	Implements an efficient asynchronous io interface.
+ *
+ *	Copyright 2000, 2001, 2002 Red Hat, Inc.  All Rights Reserved.
+ *
+ *	See ../COPYING for licensing terms.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/aio_abi.h>
+
+//#define DEBUG 1
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/vmalloc.h>
+#include <linux/iobuf.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/brlock.h>
+#include <linux/aio.h>
+#include <linux/smp_lock.h>
+#include <linux/compiler.h>
+#include <linux/brlock.h>
+#include <linux/module.h>
+
+#include <asm/kmap_types.h>
+#include <asm/uaccess.h>
+#include <linux/highmem.h>
+
+#if DEBUG > 1
+#define dprintk		printk
+#else
+#define dprintk(x...)	do { ; } while (0)
+#endif
+
+/*------ sysctl variables----*/
+atomic_t aio_nr = ATOMIC_INIT(0);	/* current system wide number of aio requests */
+unsigned aio_max_nr = 0x10000;	/* system wide maximum number of aio requests */
+/*----end sysctl variables---*/
+
+static kmem_cache_t	*kiocb_cachep;
+static kmem_cache_t	*kioctx_cachep;
+
+/* Used for rare fput completion. */
+static void aio_fput_routine(void *);
+static struct tq_struct	fput_tqueue = {
+	routine:	aio_fput_routine,
+};
+
+static spinlock_t	fput_lock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD(fput_head);
+
+/* aio_setup
+ *	Creates the slab caches used by the aio routines, panic on
+ *	failure as this is done early during the boot sequence.
+ */
+static int __init aio_setup(void)
+{
+	kiocb_cachep = kmem_cache_create("kiocb", sizeof(struct kiocb),
+				0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!kiocb_cachep)
+		panic("unable to create kiocb cache\n");
+
+	kioctx_cachep = kmem_cache_create("kioctx", sizeof(struct kioctx),
+				0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!kioctx_cachep)
+		panic("unable to create kioctx cache");
+
+	printk(KERN_NOTICE "aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
+
+	return 0;
+}
+
+static void aio_free_ring(struct kioctx *ctx)
+{
+	struct aio_ring_info *info = &ctx->ring_info;
+	long i;
+
+	for (i=0; i<info->nr_pages; i++)
+		put_page(info->ring_pages[i]);
+
+	if (info->mmap_size) {
+		down_write(&ctx->mm->mmap_sem);
+		do_munmap(ctx->mm, info->mmap_base, info->mmap_size);
+		up_write(&ctx->mm->mmap_sem);
+	}
+
+	if (info->ring_pages && info->ring_pages != info->internal_pages)
+		kfree(info->ring_pages);
+	info->ring_pages = NULL;
+	info->nr = 0;
+}
+
+static int aio_setup_ring(struct kioctx *ctx)
+{
+	struct aio_ring *ring;
+	struct aio_ring_info *info = &ctx->ring_info;
+	unsigned nr_events = ctx->max_reqs;
+	unsigned long size;
+	int nr_pages;
+
+	/* Compensate for the ring buffer's head/tail overlap entry */
+	nr_events += 2;	/* 1 is required, 2 for good luck */
+
+	size = sizeof(struct aio_ring);
+	size += sizeof(struct io_event) * nr_events;
+	nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+	if (nr_pages < 0)
+		return -EINVAL;
+
+	info->nr_pages = nr_pages;
+
+	nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event);
+
+	info->nr = 0;
+	info->ring_pages = info->internal_pages;
+	if (nr_pages > AIO_RING_PAGES) {
+		info->ring_pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_KERNEL);
+		if (!info->ring_pages)
+			return -ENOMEM;
+		memset(info->ring_pages, 0, sizeof(struct page *) * nr_pages);
+	}
+
+	info->mmap_size = nr_pages * PAGE_SIZE;
+	dprintk("attempting mmap of %lu bytes\n", info->mmap_size);
+	down_write(&ctx->mm->mmap_sem);
+	info->mmap_base = do_mmap(NULL, 0, info->mmap_size, 
+				  PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
+				  0);
+	if (IS_ERR((void *)info->mmap_base)) {
+		up_write(&ctx->mm->mmap_sem);
+		printk("mmap err: %ld\n", -info->mmap_base);
+		info->mmap_size = 0;
+		aio_free_ring(ctx);
+		return -EAGAIN;
+	}
+
+	dprintk("mmap address: 0x%08lx\n", info->mmap_base);
+	info->nr_pages = get_user_pages(current, ctx->mm,
+					info->mmap_base, info->mmap_size, 
+					1, 0, info->ring_pages, NULL);
+	up_write(&ctx->mm->mmap_sem);
+
+	if (unlikely(info->nr_pages != nr_pages)) {
+		aio_free_ring(ctx);
+		return -EAGAIN;
+	}
+
+	ctx->user_id = info->mmap_base;
+
+	info->nr = nr_events;		/* trusted copy */
+
+	ring = kmap_atomic(info->ring_pages[0], KM_USER0);
+	ring->nr = nr_events;	/* user copy */
+	ring->id = ctx->user_id;
+	ring->head = ring->tail = 0;
+	ring->magic = AIO_RING_MAGIC;
+	ring->compat_features = AIO_RING_COMPAT_FEATURES;
+	ring->incompat_features = AIO_RING_INCOMPAT_FEATURES;
+	ring->header_length = sizeof(struct aio_ring);
+	kunmap_atomic(ring, KM_USER0);
+
+	return 0;
+}
+
+/* aio_ring_event: returns a pointer to the event at the given index from
+ * kmap_atomic(, km).  Release the pointer with put_aio_ring_event();
+ */
+static inline struct io_event *aio_ring_event(struct aio_ring_info *info, int nr, enum km_type km)
+{
+	struct io_event *events;
+#define AIO_EVENTS_PER_PAGE	(PAGE_SIZE / sizeof(struct io_event))
+#define AIO_EVENTS_FIRST_PAGE	((PAGE_SIZE - sizeof(struct aio_ring)) / sizeof(struct io_event))
+
+	if (nr < AIO_EVENTS_FIRST_PAGE) {
+		struct aio_ring *ring;
+		ring = kmap_atomic(info->ring_pages[0], km);
+		return &ring->io_events[nr];
+	}
+	nr -= AIO_EVENTS_FIRST_PAGE;
+
+	events = kmap_atomic(info->ring_pages[1 + nr / AIO_EVENTS_PER_PAGE], km);
+
+	return events + (nr % AIO_EVENTS_PER_PAGE);
+}
+
+static inline void put_aio_ring_event(struct io_event *event, enum km_type km)
+{
+	void *p = (void *)((unsigned long)event & PAGE_MASK);
+	kunmap_atomic(p, km);
+}
+
+/* ioctx_alloc
+ *	Allocates and initializes an ioctx.  Returns an ERR_PTR if it failed.
+ */
+static struct kioctx *ioctx_alloc(unsigned nr_events)
+{
+	struct mm_struct *mm;
+	struct kioctx *ctx;
+
+	/* Prevent overflows */
+	if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
+	    (nr_events > (0x10000000U / sizeof(struct kiocb)))) {
+		pr_debug("ENOMEM: nr_events too high\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (nr_events > aio_max_nr)
+		return ERR_PTR(-EAGAIN);
+
+	ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->max_reqs = nr_events;
+	mm = ctx->mm = current->mm;
+	atomic_inc(&mm->mm_count);
+
+	atomic_set(&ctx->users, 1);
+	spin_lock_init(&ctx->ctx_lock);
+	spin_lock_init(&ctx->ring_info.ring_lock);
+	init_waitqueue_head(&ctx->wait);
+
+	INIT_LIST_HEAD(&ctx->active_reqs);
+
+	if (aio_setup_ring(ctx) < 0)
+		goto out_freectx;
+
+	/* now link into global list.  kludge.  FIXME */
+	atomic_add(ctx->max_reqs, &aio_nr);	/* undone by __put_ioctx */
+	if (unlikely(atomic_read(&aio_nr) > aio_max_nr))
+		goto out_cleanup;
+	write_lock(&mm->ioctx_list_lock);
+	ctx->next = mm->ioctx_list;
+	mm->ioctx_list = ctx;
+	write_unlock(&mm->ioctx_list_lock);
+
+	dprintk("aio: allocated ioctx %p[%ld]: mm=%p mask=0x%x\n",
+		ctx, ctx->user_id, current->mm, ctx->ring_info.ring->nr);
+	return ctx;
+
+out_cleanup:
+	atomic_sub(ctx->max_reqs, &aio_nr);	/* undone by __put_ioctx */
+	ctx->max_reqs = 0;	/* prevent __put_ioctx from sub'ing aio_nr */
+	__put_ioctx(ctx);
+	return ERR_PTR(-EAGAIN);
+
+out_freectx:
+	kmem_cache_free(kioctx_cachep, ctx);
+	ctx = ERR_PTR(-ENOMEM);
+
+	dprintk("aio: error allocating ioctx %p\n", ctx);
+	return ctx;
+}
+
+/* aio_cancel_all
+ *	Cancels all outstanding aio requests on an aio context.  Used 
+ *	when the processes owning a context have all exited to encourage 
+ *	the rapid destruction of the kioctx.
+ */
+static void aio_cancel_all(struct kioctx *ctx)
+{
+	int (*cancel)(struct kiocb *, struct io_event *);
+	struct io_event res;
+	spin_lock_irq(&ctx->ctx_lock);
+	ctx->dead = 1;
+	while (!list_empty(&ctx->active_reqs)) {
+		struct list_head *pos = ctx->active_reqs.next;
+		struct kiocb *iocb = list_kiocb(pos);
+		list_del_init(&iocb->ki_list);
+		cancel = iocb->ki_cancel;
+		if (cancel)
+			iocb->ki_users++;
+		spin_unlock_irq(&ctx->ctx_lock);
+		if (cancel)
+			cancel(iocb, &res);
+		spin_lock_irq(&ctx->ctx_lock);
+	}
+	spin_unlock_irq(&ctx->ctx_lock);
+}
+
+void wait_for_all_aios(struct kioctx *ctx)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	if (!ctx->reqs_active)
+		return;
+
+	add_wait_queue(&ctx->wait, &wait);
+	set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	while (ctx->reqs_active) {
+		printk("ctx->reqs_active = %d\n", ctx->reqs_active);
+		schedule();
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	}
+	set_task_state(tsk, TASK_RUNNING);
+	remove_wait_queue(&ctx->wait, &wait);
+}
+
+/* exit_aio: called when the last user of mm goes away.  At this point, 
+ * there is no way for any new requests to be submited or any of the 
+ * io_* syscalls to be called on the context.  However, there may be 
+ * outstanding requests which hold references to the context; as they 
+ * go away, they will call put_ioctx and release any pinned memory
+ * associated with the request (held via struct page * references).
+ */
+void exit_aio(struct mm_struct *mm)
+{
+	struct kioctx *ctx = mm->ioctx_list;
+	mm->ioctx_list = NULL;
+	while (ctx) {
+		struct kioctx *next = ctx->next;
+		ctx->next = NULL;
+		aio_cancel_all(ctx);
+
+		wait_for_all_aios(ctx);
+
+		if (1 != atomic_read(&ctx->users))
+			printk(KERN_DEBUG
+				"exit_aio:ioctx still alive: %d %d %d\n",
+				atomic_read(&ctx->users), ctx->dead,
+				ctx->reqs_active);
+		put_ioctx(ctx);
+		ctx = next;
+	}
+}
+
+/* __put_ioctx
+ *	Called when the last user of an aio context has gone away,
+ *	and the struct needs to be freed.
+ */
+void __put_ioctx(struct kioctx *ctx)
+{
+	unsigned nr_events = ctx->max_reqs;
+
+	if (unlikely(ctx->reqs_active))
+		BUG();
+
+	aio_free_ring(ctx);
+	mmdrop(ctx->mm);
+	ctx->mm = NULL;
+	pr_debug("__put_ioctx: freeing %p\n", ctx);
+	kmem_cache_free(kioctx_cachep, ctx);
+
+	atomic_sub(nr_events, &aio_nr);
+}
+
+/* aio_get_req
+ *	Allocate a slot for an aio request.  Increments the users count
+ * of the kioctx so that the kioctx stays around until all requests are
+ * complete.  Returns -EAGAIN if no requests are free.
+ */
+static struct kiocb *FASTCALL(__aio_get_req(struct kioctx *ctx));
+static struct kiocb *__aio_get_req(struct kioctx *ctx)
+{
+	struct kiocb *req = NULL;
+	struct aio_ring *ring;
+
+	req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL);
+	if (unlikely(!req))
+		return NULL;
+
+	/* Check if the completion queue has enough free space to
+	 * accept an event from this io.
+	 */
+	spin_lock_irq(&ctx->ctx_lock);
+	ring = kmap_atomic(ctx->ring_info.ring_pages[0], KM_USER0);
+	if (likely(ctx->reqs_active < aio_ring_avail(&ctx->ring_info, ring))) {
+		list_add(&req->ki_list, &ctx->active_reqs);
+		get_ioctx(ctx);
+		ctx->reqs_active++;
+		req->ki_user_obj = NULL;
+		req->ki_ctx = ctx;
+		req->ki_users = 1;
+	} else
+		kmem_cache_free(kiocb_cachep, req);
+	kunmap_atomic(ring, KM_USER0);
+	spin_unlock_irq(&ctx->ctx_lock);
+
+	return req;
+}
+
+static inline struct kiocb *aio_get_req(struct kioctx *ctx)
+{
+	struct kiocb *req;
+	/* Handle a potential starvation case -- should be exceedingly rare as 
+	 * requests will be stuck on fput_head only if the aio_fput_routine is 
+	 * delayed and the requests were the last user of the struct file.
+	 */
+	req = __aio_get_req(ctx);
+	if (unlikely(NULL == req)) {
+		aio_fput_routine(NULL);
+		req = __aio_get_req(ctx);
+	}
+	return req;
+}
+
+static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
+{
+	req->ki_ctx = NULL;
+	req->ki_filp = NULL;
+	req->ki_user_obj = NULL;
+	kmem_cache_free(kiocb_cachep, req);
+	ctx->reqs_active--;
+
+	if (unlikely(!ctx->reqs_active && ctx->dead))
+		wake_up(&ctx->wait);
+}
+
+static void aio_fput_routine(void *data)
+{
+	spin_lock_irq(&fput_lock);
+	while (likely(!list_empty(&fput_head))) {
+		struct kiocb *req = list_kiocb(fput_head.next);
+		struct kioctx *ctx = req->ki_ctx;
+
+		list_del(&req->ki_list);
+		spin_unlock_irq(&fput_lock);
+
+		/* Complete the fput */
+		__fput(req->ki_filp);
+
+		/* Link the iocb into the context's free list */
+		spin_lock_irq(&ctx->ctx_lock);
+		really_put_req(ctx, req);
+		spin_unlock_irq(&ctx->ctx_lock);
+
+		put_ioctx(ctx);
+		spin_lock_irq(&fput_lock);
+	}
+	spin_unlock_irq(&fput_lock);
+}
+
+/* __aio_put_req
+ *	Returns true if this put was the last user of the request.
+ */
+static inline int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
+{
+	dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n",
+		req, atomic_read(&req->ki_filp->f_count));
+
+	req->ki_users --;
+	if (unlikely(req->ki_users < 0))
+		BUG();
+	if (likely(req->ki_users))
+		return 0;
+	list_del(&req->ki_list);		/* remove from active_reqs */
+	req->ki_cancel = NULL;
+
+	/* Must be done under the lock to serialise against cancellation.
+	 * Call this aio_fput as it duplicates fput via the fput_tqueue.
+	 */
+	if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) {
+		get_ioctx(ctx);
+		spin_lock(&fput_lock);
+		list_add(&req->ki_list, &fput_head);
+		spin_unlock(&fput_lock);
+		schedule_task(&fput_tqueue);
+	} else
+		really_put_req(ctx, req);
+	return 1;
+}
+
+/* aio_put_req
+ *	Returns true if this put was the last user of the kiocb,
+ *	false if the request is still in use.
+ */
+int aio_put_req(struct kiocb *req)
+{
+	struct kioctx *ctx = req->ki_ctx;
+	int ret;
+	spin_lock_irq(&ctx->ctx_lock);
+	ret = __aio_put_req(ctx, req);
+	spin_unlock_irq(&ctx->ctx_lock);
+	if (ret)
+		put_ioctx(ctx);
+	return ret;
+}
+
+/*	Lookup an ioctx id.  ioctx_list is lockless for reads.
+ *	FIXME: this is O(n) and is only suitable for development.
+ */
+static inline struct kioctx *lookup_ioctx(unsigned long ctx_id)
+{
+	struct kioctx *ioctx;
+	struct mm_struct *mm;
+
+	mm = current->mm;
+	read_lock(&mm->ioctx_list_lock);
+	for (ioctx = mm->ioctx_list; ioctx; ioctx = ioctx->next)
+		if (likely(ioctx->user_id == ctx_id && !ioctx->dead)) {
+			get_ioctx(ioctx);
+			break;
+		}
+	read_unlock(&mm->ioctx_list_lock);
+
+	return ioctx;
+}
+
+/* aio_complete
+ *	Called when the io request on the given iocb is complete.
+ *	Returns true if this is the last user of the request.  The 
+ *	only other user of the request can be the cancellation code.
+ */
+int aio_complete(struct kiocb *iocb, long res, long res2)
+{
+	struct kioctx	*ctx = iocb->ki_ctx;
+	struct aio_ring_info	*info = &ctx->ring_info;
+	struct aio_ring	*ring;
+	struct io_event	*event;
+	unsigned long	flags;
+	unsigned long	tail;
+	int		ret;
+
+	/* add a completion event to the ring buffer.
+	 * must be done holding ctx->ctx_lock to prevent
+	 * other code from messing with the tail
+	 * pointer since we might be called from irq
+	 * context.
+	 */
+	spin_lock_irqsave(&ctx->ctx_lock, flags);
+
+	ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
+
+	tail = info->tail;
+	event = aio_ring_event(info, tail, KM_IRQ0);
+	tail = (tail + 1) % info->nr;
+
+	event->obj = (u64)(unsigned long)iocb->ki_user_obj;
+	event->data = iocb->ki_user_data;
+	event->res = res;
+	event->res2 = res2;
+
+	dprintk("aio_complete: %p[%lu]: %p: %p %Lx %lx %lx\n",
+		ctx, tail, iocb, iocb->ki_user_obj, iocb->ki_user_data,
+		res, res2);
+
+	/* after flagging the request as done, we
+	 * must never even look at it again
+	 */
+	barrier();
+
+	info->tail = tail;
+	ring->tail = tail;
+
+	wmb();
+	put_aio_ring_event(event, KM_IRQ0);
+	kunmap_atomic(ring, KM_IRQ1);
+
+	pr_debug("added to ring %p at [%lu]\n", iocb, tail);
+
+	/* everything turned out well, dispose of the aiocb. */
+	ret = __aio_put_req(ctx, iocb);
+
+	spin_unlock_irqrestore(&ctx->ctx_lock, flags);
+
+	if (waitqueue_active(&ctx->wait))
+		wake_up(&ctx->wait);
+
+	if (ret)
+		put_ioctx(ctx);
+
+	return ret;
+}
+
+/* aio_read_evt
+ *	Pull an event off of the ioctx's event ring.  Returns the number of 
+ *	events fetched (0 or 1 ;-)
+ *	FIXME: make this use cmpxchg.
+ *	TODO: make the ringbuffer user mmap()able (requires FIXME).
+ */
+static int aio_read_evt(struct kioctx *ioctx, struct io_event *ent)
+{
+	struct aio_ring_info *info = &ioctx->ring_info;
+	struct aio_ring *ring;
+	unsigned long head;
+	int ret = 0;
+
+	ring = kmap_atomic(info->ring_pages[0], KM_USER0);
+	dprintk("in aio_read_evt h%lu t%lu m%lu\n",
+		 (unsigned long)ring->head, (unsigned long)ring->tail,
+		 (unsigned long)ring->nr);
+	barrier();
+	if (ring->head == ring->tail)
+		goto out;
+
+	spin_lock(&info->ring_lock);
+
+	head = ring->head % info->nr;
+	if (head != ring->tail) {
+		struct io_event *evp = aio_ring_event(info, head, KM_USER1);
+		*ent = *evp;
+		head = (head + 1) % info->nr;
+		barrier();
+		ring->head = head;
+		ret = 1;
+		put_aio_ring_event(evp, KM_USER1);
+	}
+	spin_unlock(&info->ring_lock);
+
+out:
+	kunmap_atomic(ring, KM_USER0);
+	dprintk("leaving aio_read_evt: %d  h%lu t%lu\n", ret,
+		 (unsigned long)ring->head, (unsigned long)ring->tail);
+	return ret;
+}
+
+struct timeout {
+	struct timer_list	timer;
+	int			timed_out;
+	struct task_struct	*p;
+};
+
+static void timeout_func(unsigned long data)
+{
+	struct timeout *to = (struct timeout *)data;
+
+	to->timed_out = 1;
+	wake_up_process(to->p);
+}
+
+static inline void init_timeout(struct timeout *to)
+{
+	init_timer(&to->timer);
+	to->timer.data = (unsigned long)to;
+	to->timer.function = timeout_func;
+	to->timed_out = 0;
+	to->p = current;
+}
+
+static inline void set_timeout(long start_jiffies, struct timeout *to,
+			       const struct timespec *ts)
+{
+	unsigned long how_long;
+
+	if (ts->tv_sec < 0 || (!ts->tv_sec && !ts->tv_nsec)) {
+		to->timed_out = 1;
+		return;
+	}
+
+	how_long = ts->tv_sec * HZ;
+#define HZ_NS (1000000000 / HZ)
+	how_long += (ts->tv_nsec + HZ_NS - 1) / HZ_NS;
+	
+	to->timer.expires = jiffies + how_long;
+	add_timer(&to->timer);
+}
+
+static inline void clear_timeout(struct timeout *to)
+{
+	del_timer_sync(&to->timer);
+}
+
+static int read_events(struct kioctx *ctx,
+			long min_nr, long nr,
+			struct io_event *event,
+			struct timespec *timeout)
+{
+	long			start_jiffies = jiffies;
+	struct task_struct	*tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	int			ret;
+	int			i = 0;
+	struct io_event		ent;
+	struct timeout		to;
+
+	/* needed to zero any padding within an entry (there shouldn't be 
+	 * any, but C is fun!
+	 */
+	memset(&ent, 0, sizeof(ent));
+	ret = 0;
+
+	while (likely(i < nr)) {
+		ret = aio_read_evt(ctx, &ent);
+		if (unlikely(ret <= 0))
+			break;
+
+		dprintk("read event: %Lx %Lx %Lx %Lx\n",
+			ent.data, ent.obj, ent.res, ent.res2);
+
+		/* Could we split the check in two? */
+		ret = -EFAULT;
+		if (unlikely(copy_to_user(event, &ent, sizeof(ent)))) {
+			dprintk("aio: lost an event due to EFAULT.\n");
+			break;
+		}
+		ret = 0;
+
+		/* Good, event copied to userland, update counts. */
+		event ++;
+		i ++;
+	}
+
+	if (min_nr <= i)
+		return i;
+	if (ret)
+		return ret;
+
+	/* End fast path */
+
+	if (timeout) {
+		struct timespec	ts;
+		ret = -EFAULT;
+		if (unlikely(copy_from_user(&ts, timeout, sizeof(ts))))
+			goto out;
+
+		init_timeout(&to);
+		set_timeout(start_jiffies, &to, &ts);
+	}
+
+	while (likely(i < nr)) {
+		add_wait_queue_exclusive(&ctx->wait, &wait);
+		do {
+			set_task_state(tsk, TASK_INTERRUPTIBLE);
+
+			ret = aio_read_evt(ctx, &ent);
+			if (ret)
+				break;
+			if (min_nr <= i)
+				break;
+			ret = 0;
+			if (to.timed_out)	/* Only check after read evt */
+				break;
+			schedule();
+			if (signal_pending(tsk)) {
+				ret = -EINTR;
+				break;
+			}
+			/*ret = aio_read_evt(ctx, &ent);*/
+		} while (1) ;
+
+		set_task_state(tsk, TASK_RUNNING);
+		remove_wait_queue(&ctx->wait, &wait);
+
+		if (unlikely(ret <= 0))
+			break;
+
+		ret = -EFAULT;
+		if (unlikely(copy_to_user(event, &ent, sizeof(ent)))) {
+			dprintk("aio: lost an event due to EFAULT.\n");
+			break;
+		}
+
+		/* Good, event copied to userland, update counts. */
+		event ++;
+		i ++;
+	}
+
+	if (timeout)
+		clear_timeout(&to);
+out:
+	return i ? i : ret;
+}
+
+/* Take an ioctx and remove it from the list of ioctx's.  Protects 
+ * against races with itself via ->dead.
+ */
+static void io_destroy(struct kioctx *ioctx)
+{
+	struct mm_struct *mm = current->mm;
+	struct kioctx **tmp;
+	int was_dead;
+
+	/* delete the entry from the list is someone else hasn't already */
+	write_lock(&mm->ioctx_list_lock);
+	was_dead = ioctx->dead;
+	ioctx->dead = 1;
+	for (tmp = &mm->ioctx_list; *tmp && *tmp != ioctx;
+	     tmp = &(*tmp)->next)
+		;
+	if (*tmp)
+		*tmp = ioctx->next;
+	write_unlock(&mm->ioctx_list_lock);
+
+	dprintk("aio_release(%p)\n", ioctx);
+	if (likely(!was_dead))
+		put_ioctx(ioctx);	/* twice for the list */
+
+	aio_cancel_all(ioctx);
+	wait_for_all_aios(ioctx);
+	put_ioctx(ioctx);	/* once for the lookup */
+}
+
+/* sys_io_setup:
+ *	Create an aio_context capable of receiving at least nr_events.
+ *	ctxp must not point to an aio_context that already exists, and
+ *	must be initialized to 0 prior to the call.  On successful
+ *	creation of the aio_context, *ctxp is filled in with the resulting 
+ *	handle.  May fail with -EINVAL if *ctxp is not initialized,
+ *	if the specified nr_events exceeds internal limits.  May fail 
+ *	with -EAGAIN if the specified nr_events exceeds the user's limit 
+ *	of available events.  May fail with -ENOMEM if insufficient kernel
+ *	resources are available.  May fail with -EFAULT if an invalid
+ *	pointer is passed for ctxp.  Will fail with -ENOSYS if not
+ *	implemented.
+ */
+asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t *ctxp)
+{
+	struct kioctx *ioctx = NULL;
+	unsigned long ctx;
+	long ret;
+
+	ret = get_user(ctx, ctxp);
+	if (unlikely(ret))
+		goto out;
+
+	ret = -EINVAL;
+	if (unlikely(ctx || !nr_events || (int)nr_events < 0)) {
+		pr_debug("EINVAL: io_setup: ctx or nr_events > max\n");
+		goto out;
+	}
+
+	ioctx = ioctx_alloc(nr_events);
+	ret = PTR_ERR(ioctx);
+	if (!IS_ERR(ioctx)) {
+		ret = put_user(ioctx->user_id, ctxp);
+		if (!ret)
+			return 0;
+		io_destroy(ioctx);
+	}
+
+out:
+	return ret;
+}
+
+/* sys_io_destroy:
+ *	Destroy the aio_context specified.  May cancel any outstanding 
+ *	AIOs and block on completion.  Will fail with -ENOSYS if not
+ *	implemented.  May fail with -EFAULT if the context pointed to
+ *	is invalid.
+ */
+asmlinkage long sys_io_destroy(aio_context_t ctx)
+{
+	struct kioctx *ioctx = lookup_ioctx(ctx);
+	if (likely(NULL != ioctx)) {
+		io_destroy(ioctx);
+		return 0;
+	}
+	pr_debug("EINVAL: io_destroy: invalid context id\n");
+	return -EINVAL;
+}
+
+static int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb *user_iocb,
+				  struct iocb *iocb));
+static int io_submit_one(struct kioctx *ctx, struct iocb *user_iocb,
+			 struct iocb *iocb)
+{
+	struct kiocb *req;
+	struct file *file;
+	ssize_t ret;
+	char *buf;
+
+	/* enforce forwards compatibility on users */
+	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
+		     iocb->aio_reserved3)) {
+		pr_debug("EINVAL: io_submit: reserve field set\n");
+		return -EINVAL;
+	}
+
+	/* prevent overflows */
+	if (unlikely(
+	    (iocb->aio_buf != (unsigned long)iocb->aio_buf) ||
+	    (iocb->aio_nbytes != (size_t)iocb->aio_nbytes) ||
+	    ((ssize_t)iocb->aio_nbytes < 0)
+	   )) {
+		pr_debug("EINVAL: io_submit: overflow check\n");
+		return -EINVAL;
+	}
+
+	file = fget(iocb->aio_fildes);
+	if (unlikely(!file))
+		return -EBADF;
+
+	req = aio_get_req(ctx);
+	if (unlikely(!req)) {
+		fput(file);
+		return -EAGAIN;
+	}
+
+	req->ki_filp = file;
+	iocb->aio_key = req->ki_key;
+	ret = put_user(iocb->aio_key, &user_iocb->aio_key);
+	if (unlikely(ret)) {
+		dprintk("EFAULT: aio_key\n");
+		goto out_put_req;
+	}
+
+	req->ki_user_obj = user_iocb;
+	req->ki_user_data = iocb->aio_data;
+
+	buf = (char *)(unsigned long)iocb->aio_buf;
+
+	switch (iocb->aio_lio_opcode) {
+	case IOCB_CMD_PREAD:
+		ret = -EBADF;
+		if (unlikely(!(file->f_mode & FMODE_READ)))
+			goto out_put_req;
+		ret = -EFAULT;
+		if (unlikely(!access_ok(VERIFY_WRITE, buf, iocb->aio_nbytes)))
+			goto out_put_req;
+		ret = -EINVAL;
+		if (file->f_op->aio_read)
+			ret = file->f_op->aio_read(req, buf,
+					iocb->aio_nbytes, iocb->aio_offset);
+		break;
+	case IOCB_CMD_PWRITE:
+		ret = -EBADF;
+		if (unlikely(!(file->f_mode & FMODE_WRITE)))
+			goto out_put_req;
+		ret = -EFAULT;
+		if (unlikely(!access_ok(VERIFY_READ, buf, iocb->aio_nbytes)))
+			goto out_put_req;
+		ret = -EINVAL;
+		if (file->f_op->aio_write)
+			ret = file->f_op->aio_write(req, buf,
+					iocb->aio_nbytes, iocb->aio_offset);
+		break;
+	case IOCB_CMD_FDSYNC:
+		ret = -EINVAL;
+		if (file->f_op->aio_fsync)
+			ret = file->f_op->aio_fsync(req, 1);
+		break;
+	case IOCB_CMD_FSYNC:
+		ret = -EINVAL;
+		if (file->f_op->aio_fsync)
+			ret = file->f_op->aio_fsync(req, 0);
+		break;
+	default:
+		dprintk("EINVAL: io_submit: no operation provided\n");
+		ret = -EINVAL;
+	}
+
+	if (likely(EIOCBQUEUED == ret))
+		return 0;
+	if (ret >= 0) {
+		aio_complete(req, ret, 0);
+		return 0;
+	}
+
+out_put_req:
+	aio_put_req(req);
+	return ret;
+}
+
+/* sys_io_submit:
+ *	Queue the nr iocbs pointed to by iocbpp for processing.  Returns
+ *	the number of iocbs queued.  May return -EINVAL if the aio_context
+ *	specified by ctx_id is invalid, if nr is < 0, if the iocb at
+ *	*iocbpp[0] is not properly initialized, if the operation specified
+ *	is invalid for the file descriptor in the iocb.  May fail with
+ *	-EFAULT if any of the data structures point to invalid data.  May
+ *	fail with -EBADF if the file descriptor specified in the first
+ *	iocb is invalid.  May fail with -EAGAIN if insufficient resources
+ *	are available to queue any iocbs.  Will return 0 if nr is 0.  Will
+ *	fail with -ENOSYS if not implemented.
+ */
+asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr,
+			      struct iocb **iocbpp)
+{
+	struct kioctx *ctx;
+	long ret = 0;
+	int i;
+
+	if (unlikely(nr < 0))
+		return -EINVAL;
+
+	if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp)))))
+		return -EFAULT;
+
+	ctx = lookup_ioctx(ctx_id);
+	if (unlikely(!ctx)) {
+		pr_debug("EINVAL: io_submit: invalid context id\n");
+		return -EINVAL;
+	}
+
+	for (i=0; i<nr; i++) {
+		struct iocb *user_iocb, tmp;
+
+		if (unlikely(__get_user(user_iocb, iocbpp + i))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (unlikely(__copy_from_user(&tmp, user_iocb, sizeof(tmp)))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = io_submit_one(ctx, user_iocb, &tmp);
+		if (ret)
+			break;
+	}
+
+	put_ioctx(ctx);
+	return i ? i : ret;
+}
+
+/* lookup_kiocb
+ *	Finds a given iocb for cancellation.
+ *	MUST be called with ctx->ctx_lock held.
+ */
+struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb *iocb, u32 key)
+{
+	struct list_head *pos;
+	/* TODO: use a hash or array, this sucks. */
+	list_for_each(pos, &ctx->active_reqs) {
+		struct kiocb *kiocb = list_kiocb(pos);
+		if (kiocb->ki_user_obj == iocb && kiocb->ki_key == key)
+			return kiocb;
+	}
+	return NULL;
+}
+
+/* sys_io_cancel:
+ *	Attempts to cancel an iocb previously passed to io_submit.  If
+ *	the operation is successfully cancelled, the resulting event is
+ *	copied into the memory pointed to by result without being placed
+ *	into the completion queue and 0 is returned.  May fail with
+ *	-EFAULT if any of the data structures pointed to are invalid.
+ *	May fail with -EINVAL if aio_context specified by ctx_id is
+ *	invalid.  May fail with -EAGAIN if the iocb specified was not
+ *	cancelled.  Will fail with -ENOSYS if not implemented.
+ */
+asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb *iocb,
+			      struct io_event *result)
+{
+	int (*cancel)(struct kiocb *iocb, struct io_event *res);
+	struct kioctx *ctx;
+	struct kiocb *kiocb;
+	u32 key;
+	int ret;
+
+	ret = get_user(key, &iocb->aio_key);
+	if (unlikely(ret))
+		return -EFAULT;
+
+	ctx = lookup_ioctx(ctx_id);
+	if (unlikely(!ctx))
+		return -EINVAL;
+
+	spin_lock_irq(&ctx->ctx_lock);
+	ret = -EAGAIN;
+	kiocb = lookup_kiocb(ctx, iocb, key);
+	if (kiocb && kiocb->ki_cancel) {
+		cancel = kiocb->ki_cancel;
+		kiocb->ki_users ++;
+	} else
+		cancel = NULL;
+	spin_unlock_irq(&ctx->ctx_lock);
+
+	if (NULL != cancel) {
+		struct io_event tmp;
+		printk("calling cancel\n");
+		ret = cancel(kiocb, &tmp);
+		if (!ret) {
+			/* Cancellation succeeded -- copy the result
+			 * into the user's buffer.
+			 */
+			if (copy_to_user(result, &tmp, sizeof(tmp)))
+				ret = -EFAULT;
+		}
+	} else
+		printk(KERN_DEBUG "iocb has no cancel operation\n");
+
+	put_ioctx(ctx);
+
+	return ret;
+}
+
+/* io_getevents:
+ *	Attempts to read at least min_nr events and up to nr events from
+ *	the completion queue for the aio_context specified by ctx_id.  May
+ *	fail with -EINVAL if ctx_id is invalid, if min_nr is out of range,
+ *	if nr is out of range, if when is out of range.  May fail with
+ *	-EFAULT if any of the memory specified to is invalid.  May return
+ *	0 or < min_nr if no events are available and the timeout specified
+ *	by when	has elapsed, where when == NULL specifies an infinite
+ *	timeout.  Note that the timeout pointed to by when is relative and
+ *	will be updated if not NULL and the operation blocks.  Will fail
+ *	with -ENOSYS if not implemented.
+ */
+asmlinkage long sys_io_getevents(aio_context_t ctx_id,
+				 long min_nr,
+				 long nr,
+				 struct io_event *events,
+				 struct timespec *timeout)
+{
+	struct kioctx *ioctx = lookup_ioctx(ctx_id);
+	long ret = -EINVAL;
+
+	if (unlikely(min_nr > nr || min_nr < 0 || nr < 0))
+		return ret;
+
+	if (likely(NULL != ioctx)) {
+		ret = read_events(ioctx, min_nr, nr, events, timeout);
+		put_ioctx(ioctx);
+	}
+
+	return ret;
+}
+
+__initcall(aio_setup);
+
+EXPORT_SYMBOL(aio_complete);
+EXPORT_SYMBOL(aio_put_req);
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Aug 27 12:28:08 2002
+++ b/fs/block_dev.c	Tue Aug 27 12:28:08 2002
@@ -26,12 +26,12 @@
 
 static sector_t max_block(struct block_device *bdev)
 {
-	sector_t retval = ~0U;
+	sector_t retval = ~((sector_t)0);
 	loff_t sz = bdev->bd_inode->i_size;
 
 	if (sz) {
-		sector_t size = block_size(bdev);
-		unsigned sizebits = blksize_bits(size);
+		unsigned int size = block_size(bdev);
+		unsigned int sizebits = blksize_bits(size);
 		retval = (sz >> sizebits);
 	}
 	return retval;
@@ -797,7 +797,7 @@
 	part = disk->part + minor(dev) - disk->first_minor;
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
-	if (down_trylock(&bdev->bd_sem));
+	if (down_trylock(&bdev->bd_sem))
 		return -EBUSY;
 	if (bdev->bd_part_count) {
 		up(&bdev->bd_sem);
@@ -874,7 +874,7 @@
 	release:	blkdev_close,
 	llseek:		block_llseek,
 	read:		generic_file_read,
-	write:		generic_file_write,
+	write:		generic_file_write_nolock,
 	mmap:		generic_file_mmap,
 	fsync:		block_fsync,
 	ioctl:		blkdev_ioctl,
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Tue Aug 27 12:27:51 2002
+++ b/fs/buffer.c	Tue Aug 27 12:27:51 2002
@@ -180,7 +180,10 @@
 	if (uptodate) {
 		set_buffer_uptodate(bh);
 	} else {
-		buffer_io_error(bh);
+		/*
+		 * This happens, due to failed READA attempts.
+		 * buffer_io_error(bh);
+		 */
 		clear_buffer_uptodate(bh);
 	}
 	unlock_buffer(bh);
@@ -1274,15 +1277,32 @@
  *
  * This is a transparent caching front-end to sb_bread(), sb_getblk() and
  * sb_find_get_block().
+ *
+ * The LRUs themselves only need locking against invalidate_bh_lrus.  We use
+ * a local interrupt disable for that.
  */
 
-#define BH_LRU_SIZE	7
+#define BH_LRU_SIZE	8
 
 static struct bh_lru {
-	spinlock_t lock;
 	struct buffer_head *bhs[BH_LRU_SIZE];
 } ____cacheline_aligned_in_smp bh_lrus[NR_CPUS];
 
+#ifdef CONFIG_SMP
+#define bh_lru_lock()	local_irq_disable()
+#define bh_lru_unlock()	local_irq_enable()
+#else
+#define bh_lru_lock()	preempt_disable()
+#define bh_lru_unlock()	preempt_enable()
+#endif
+
+static inline void check_irqs_on(void)
+{
+#ifdef irqs_disabled
+	BUG_ON(irqs_disabled());
+#endif
+}
+
 /*
  * The LRU management algorithm is dopey-but-simple.  Sorry.
  */
@@ -1294,8 +1314,9 @@
 	if (bh == NULL)
 		return;
 
-	lru = &bh_lrus[get_cpu()];
-	spin_lock(&lru->lock);
+	check_irqs_on();
+	bh_lru_lock();
+	lru = &bh_lrus[smp_processor_id()];
 	if (lru->bhs[0] != bh) {
 		struct buffer_head *bhs[BH_LRU_SIZE];
 		int in;
@@ -1321,8 +1342,7 @@
 			bhs[out++] = NULL;
 		memcpy(lru->bhs, bhs, sizeof(bhs));
 	}
-	spin_unlock(&lru->lock);
-	put_cpu();
+	bh_lru_unlock();
 
 	if (evictee) {
 		touch_buffer(evictee);
@@ -1337,8 +1357,9 @@
 	struct bh_lru *lru;
 	int i;
 
-	lru = &bh_lrus[get_cpu()];
-	spin_lock(&lru->lock);
+	check_irqs_on();
+	bh_lru_lock();
+	lru = &bh_lrus[smp_processor_id()];
 	for (i = 0; i < BH_LRU_SIZE; i++) {
 		struct buffer_head *bh = lru->bhs[i];
 
@@ -1356,8 +1377,7 @@
 			break;
 		}
 	}
-	spin_unlock(&lru->lock);
-	put_cpu();
+	bh_lru_unlock();
 	return ret;
 }
 
@@ -1404,25 +1424,32 @@
 EXPORT_SYMBOL(__bread);
 
 /*
- * This is called rarely - at unmount.
+ * invalidate_bh_lrus() is called rarely - at unmount.  Because it is only for
+ * unmount it only needs to ensure that all buffers from the target device are
+ * invalidated on return and it doesn't need to worry about new buffers from
+ * that device being added - the unmount code has to prevent that.
  */
-static void invalidate_bh_lrus(void)
+static void invalidate_bh_lru(void *arg)
 {
-	int cpu_idx;
-
-	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++)
-		spin_lock(&bh_lrus[cpu_idx].lock);
-	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++) {
-		int i;
+	const int cpu = get_cpu();
+	int i;
 
-		for (i = 0; i < BH_LRU_SIZE; i++) {
-			brelse(bh_lrus[cpu_idx].bhs[i]);
-			bh_lrus[cpu_idx].bhs[i] = NULL;
-		}
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		brelse(bh_lrus[cpu].bhs[i]);
+		bh_lrus[cpu].bhs[i] = NULL;
 	}
-	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++)
-		spin_unlock(&bh_lrus[cpu_idx].lock);
+	put_cpu();
 }
+	
+static void invalidate_bh_lrus(void)
+{
+	preempt_disable();
+	invalidate_bh_lru(NULL);
+	smp_call_function(invalidate_bh_lru, NULL, 1, 1);
+	preempt_enable();
+}
+
+
 
 void set_bh_page(struct buffer_head *bh,
 		struct page *page, unsigned long offset)
@@ -2283,7 +2310,13 @@
 		return -EIO;
 	}
 
-	/* The page straddles i_size */
+	/*
+	 * The page straddles i_size.  It must be zeroed out on each and every
+	 * writepage invokation because it may be mmapped.  "A file is mapped
+	 * in multiples of the page size.  For a file that is not a multiple of
+	 * the  page size, the remaining memory is zeroed when mapped, and
+	 * writes to that region are not written out to the file."
+	 */
 	kaddr = kmap(page);
 	memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
 	flush_dcache_page(page);
@@ -2544,9 +2577,6 @@
 void __init buffer_init(void)
 {
 	int i;
-
-	for (i = 0; i < NR_CPUS; i++)
-		spin_lock_init(&bh_lrus[i].lock);
 
 	bh_cachep = kmem_cache_create("buffer_head",
 			sizeof(struct buffer_head), 0,
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Tue Aug 27 12:28:02 2002
+++ b/fs/exec.c	Tue Aug 27 12:28:02 2002
@@ -209,11 +209,6 @@
 		/* XXX: add architecture specific overflow check here. */ 
 		pos = bprm->p;
 
-		/*
-		 * The only sleeping function which we are allowed to call in
-		 * this loop is copy_from_user().  Otherwise, copy_user_state
-		 * could get trashed.
-		 */
 		while (len > 0) {
 			int i, new, err;
 			int offset, bytes_to_copy;
diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Tue Aug 27 12:27:45 2002
+++ b/fs/ext2/dir.c	Tue Aug 27 12:27:45 2002
@@ -655,8 +655,8 @@
 }
 
 struct file_operations ext2_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	ext2_readdir,
-	ioctl:		ext2_ioctl,
-	fsync:		ext2_sync_file,
+	.read		= generic_read_dir,
+	.readdir	= ext2_readdir,
+	.ioctl		= ext2_ioctl,
+	.fsync		= ext2_sync_file,
 };
diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c
--- a/fs/ext2/file.c	Tue Aug 27 12:28:02 2002
+++ b/fs/ext2/file.c	Tue Aug 27 12:28:02 2002
@@ -38,17 +38,17 @@
  * the ext2 filesystem.
  */
 struct file_operations ext2_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	ioctl:		ext2_ioctl,
-	mmap:		generic_file_mmap,
-	open:		generic_file_open,
-	release:	ext2_release_file,
-	fsync:		ext2_sync_file,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.ioctl		= ext2_ioctl,
+	.mmap		= generic_file_mmap,
+	.open		= generic_file_open,
+	.release	= ext2_release_file,
+	.fsync		= ext2_sync_file,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations ext2_file_inode_operations = {
-	truncate:	ext2_truncate,
+	.truncate	= ext2_truncate,
 };
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Tue Aug 27 12:27:59 2002
+++ b/fs/ext2/inode.c	Tue Aug 27 12:27:59 2002
@@ -640,16 +640,16 @@
 }
 
 struct address_space_operations ext2_aops = {
-	readpage:		ext2_readpage,
-	readpages:		ext2_readpages,
-	writepage:		ext2_writepage,
-	sync_page:		block_sync_page,
-	prepare_write:		ext2_prepare_write,
-	commit_write:		generic_commit_write,
-	bmap:			ext2_bmap,
-	direct_IO:		ext2_direct_IO,
-	writepages:		ext2_writepages,
-	vm_writeback:		generic_vm_writeback,
+	.readpage		= ext2_readpage,
+	.readpages		= ext2_readpages,
+	.writepage		= ext2_writepage,
+	.sync_page		= block_sync_page,
+	.prepare_write		= ext2_prepare_write,
+	.commit_write		= generic_commit_write,
+	.bmap			= ext2_bmap,
+	.direct_IO		= ext2_direct_IO,
+	.writepages		= ext2_writepages,
+	.vm_writeback		= generic_vm_writeback,
 };
 
 /*
diff -Nru a/fs/ext2/namei.c b/fs/ext2/namei.c
--- a/fs/ext2/namei.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ext2/namei.c	Tue Aug 27 12:28:08 2002
@@ -359,13 +359,13 @@
 }
 
 struct inode_operations ext2_dir_inode_operations = {
-	create:		ext2_create,
-	lookup:		ext2_lookup,
-	link:		ext2_link,
-	unlink:		ext2_unlink,
-	symlink:	ext2_symlink,
-	mkdir:		ext2_mkdir,
-	rmdir:		ext2_rmdir,
-	mknod:		ext2_mknod,
-	rename:		ext2_rename,
+	.create		= ext2_create,
+	.lookup		= ext2_lookup,
+	.link		= ext2_link,
+	.unlink		= ext2_unlink,
+	.symlink	= ext2_symlink,
+	.mkdir		= ext2_mkdir,
+	.rmdir		= ext2_rmdir,
+	.mknod		= ext2_mknod,
+	.rename		= ext2_rename,
 };
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Tue Aug 27 12:28:07 2002
+++ b/fs/ext2/super.c	Tue Aug 27 12:28:07 2002
@@ -194,16 +194,16 @@
 }
 
 static struct super_operations ext2_sops = {
-	alloc_inode:	ext2_alloc_inode,
-	destroy_inode:	ext2_destroy_inode,
-	read_inode:	ext2_read_inode,
-	write_inode:	ext2_write_inode,
-	put_inode:	ext2_put_inode,
-	delete_inode:	ext2_delete_inode,
-	put_super:	ext2_put_super,
-	write_super:	ext2_write_super,
-	statfs:		ext2_statfs,
-	remount_fs:	ext2_remount,
+	.alloc_inode	= ext2_alloc_inode,
+	.destroy_inode	= ext2_destroy_inode,
+	.read_inode	= ext2_read_inode,
+	.write_inode	= ext2_write_inode,
+	.put_inode	= ext2_put_inode,
+	.delete_inode	= ext2_delete_inode,
+	.put_super	= ext2_put_super,
+	.write_super	= ext2_write_super,
+	.statfs		= ext2_statfs,
+	.remount_fs	= ext2_remount,
 };
 
 /* Yes, most of these are left as NULL!!
@@ -213,7 +213,7 @@
  */
 struct dentry *ext2_get_parent(struct dentry *child);
 static struct export_operations ext2_export_ops = {
-	get_parent: ext2_get_parent,
+	.get_parent = ext2_get_parent,
 };
 
 /*
@@ -698,6 +698,9 @@
 			printk(KERN_ERR "EXT2-fs: get root inode failed\n");
 		goto failed_mount2;
 	}
+	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+		ext2_warning(sb, __FUNCTION__,
+			"mounting ext3 filesystem as ext2\n");
 	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
 	return 0;
 failed_mount2:
@@ -871,11 +874,11 @@
 }
 
 static struct file_system_type ext2_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"ext2",
-	get_sb:		ext2_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "ext2",
+	.get_sb		= ext2_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_ext2_fs(void)
diff -Nru a/fs/ext2/symlink.c b/fs/ext2/symlink.c
--- a/fs/ext2/symlink.c	Tue Aug 27 12:28:01 2002
+++ b/fs/ext2/symlink.c	Tue Aug 27 12:28:01 2002
@@ -32,6 +32,6 @@
 }
 
 struct inode_operations ext2_fast_symlink_inode_operations = {
-	readlink:	ext2_readlink,
-	follow_link:	ext2_follow_link,
+	.readlink	= ext2_readlink,
+	.follow_link	= ext2_follow_link,
 };
diff -Nru a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c	Tue Aug 27 12:28:02 2002
+++ b/fs/fat/file.c	Tue Aug 27 12:28:02 2002
@@ -21,6 +21,7 @@
 	write:		fat_file_write,
 	mmap:		generic_file_mmap,
 	fsync:		file_fsync,
+	sendfile:	generic_file_sendfile,
 };
 
 struct inode_operations fat_file_inode_operations = {
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Tue Aug 27 12:27:40 2002
+++ b/fs/jfs/inode.c	Tue Aug 27 12:27:40 2002
@@ -18,6 +18,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/mpage.h>
 #include <linux/buffer_head.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
@@ -271,9 +272,20 @@
 	return block_write_full_page(page, jfs_get_block);
 }
 
+static int jfs_writepages(struct address_space *mapping, int *nr_to_write)
+{
+	return mpage_writepages(mapping, nr_to_write, jfs_get_block);
+}
+
 static int jfs_readpage(struct file *file, struct page *page)
 {
-	return block_read_full_page(page, jfs_get_block);
+	return mpage_readpage(page, jfs_get_block);
+}
+
+static int jfs_readpages(struct address_space *mapping,
+		struct list_head *pages, unsigned nr_pages)
+{
+	return mpage_readpages(mapping, pages, nr_pages, jfs_get_block);
 }
 
 static int jfs_prepare_write(struct file *file,
@@ -308,7 +320,9 @@
 
 struct address_space_operations jfs_aops = {
 	.readpage	= jfs_readpage,
+	.readpages	= jfs_readpages,
 	.writepage	= jfs_writepage,
+	.writepages	= jfs_writepages,
 	.sync_page	= block_sync_page,
 	.prepare_write	= jfs_prepare_write,
 	.commit_write	= generic_commit_write,
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Tue Aug 27 12:28:07 2002
+++ b/fs/jfs/jfs_txnmgr.c	Tue Aug 27 12:28:07 2002
@@ -2755,7 +2755,7 @@
  *	context, or where blocking is not wanted, this routine will process
  *	committed transactions from the unlock queue.
  */
-int jfs_lazycommit(void)
+int jfs_lazycommit(void *arg)
 {
 	int WorkDone;
 	tblock_t *tblk;
@@ -2952,7 +2952,7 @@
  *	We write any inodes that have anonymous tlocks so they will become
  *	available.
  */
-int jfs_sync(void)
+int jfs_sync(void *arg)
 {
 	struct inode *ip;
 	struct jfs_inode_info *jfs_ip;
diff -Nru a/fs/jfs/resize.c b/fs/jfs/resize.c
--- a/fs/jfs/resize.c	Tue Aug 27 12:28:07 2002
+++ b/fs/jfs/resize.c	Tue Aug 27 12:28:07 2002
@@ -312,9 +312,8 @@
 	/* compute number of blocks that can be extended by current mapfile */
 	t64 = dbMapFileSizeToMapSize(ipbmap);
 	if (mapSize > t64) {
-		printk(KERN_ERR
-		       "jfs_extendfs: mapSize (0x%llx) > t64 (0x%llx)\n",
-		       mapSize, t64);
+		printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
+		       (long long) mapSize, (long long) t64);
 		rc = EIO;
 		goto error_out;
 	}
diff -Nru a/fs/lockd/svclock.c b/fs/lockd/svclock.c
--- a/fs/lockd/svclock.c	Tue Aug 27 12:28:02 2002
+++ b/fs/lockd/svclock.c	Tue Aug 27 12:28:02 2002
@@ -472,7 +472,6 @@
 	struct nlm_block	**bp, *block;
 
 	dprintk("lockd: VFS unblock notification for block %p\n", fl);
-	posix_unblock_lock(fl);
 	for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
 		if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
 			nlmsvc_insert_block(block, 0);
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Tue Aug 27 12:28:02 2002
+++ b/fs/mpage.c	Tue Aug 27 12:28:02 2002
@@ -19,6 +19,7 @@
 #include <linux/highmem.h>
 #include <linux/prefetch.h>
 #include <linux/mpage.h>
+#include <linux/pagevec.h>
 
 /*
  * The largest-sized BIO which this code will assemble, in bytes.  Set this
@@ -262,18 +263,25 @@
 	struct bio *bio = NULL;
 	unsigned page_idx;
 	sector_t last_block_in_bio = 0;
+	struct pagevec lru_pvec;
 
+	pagevec_init(&lru_pvec);
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
 		struct page *page = list_entry(pages->prev, struct page, list);
 
 		prefetchw(&page->flags);
 		list_del(&page->list);
-		if (!add_to_page_cache(page, mapping, page->index))
+		if (!add_to_page_cache(page, mapping, page->index)) {
 			bio = do_mpage_readpage(bio, page,
 					nr_pages - page_idx,
 					&last_block_in_bio, get_block);
-		page_cache_release(page);
+			if (!pagevec_add(&lru_pvec, page))
+				__pagevec_lru_add(&lru_pvec);
+		} else {
+			page_cache_release(page);
+		}
 	}
+	pagevec_lru_add(&lru_pvec);
 	BUG_ON(!list_empty(pages));
 	if (bio)
 		mpage_bio_submit(READ, bio);
@@ -522,12 +530,14 @@
 	sector_t last_block_in_bio = 0;
 	int ret = 0;
 	int done = 0;
+	struct pagevec pvec;
 	int (*writepage)(struct page *);
 
 	writepage = NULL;
 	if (get_block == NULL)
 		writepage = mapping->a_ops->writepage;
 
+	pagevec_init(&pvec);
 	write_lock(&mapping->page_lock);
 
 	list_splice_init(&mapping->dirty_pages, &mapping->io_pages);
@@ -557,29 +567,26 @@
 
 		if (page->mapping && !PageWriteback(page) &&
 					TestClearPageDirty(page)) {
-			/* FIXME: batch this up */
-			if (!PageActive(page) && PageLRU(page)) {
-				spin_lock(&pagemap_lru_lock);
-				if (!PageActive(page) && PageLRU(page)) {
-					list_del(&page->lru);
-					list_add(&page->lru, &inactive_list);
-				}
-				spin_unlock(&pagemap_lru_lock);
-			}
-
 			if (writepage) {
 				ret = (*writepage)(page);
 			} else {
 				bio = mpage_writepage(bio, page, get_block,
 						&last_block_in_bio, &ret);
 			}
+			if ((current->flags & PF_MEMALLOC) &&
+					!PageActive(page) && PageLRU(page)) {
+				if (!pagevec_add(&pvec, page))
+					pagevec_deactivate_inactive(&pvec);
+				page = NULL;
+			}
 			if (ret || (nr_to_write && --(*nr_to_write) <= 0))
 				done = 1;
 		} else {
 			unlock_page(page);
 		}
 
-		page_cache_release(page);
+		if (page)
+			page_cache_release(page);
 		write_lock(&mapping->page_lock);
 	}
 	/*
@@ -587,6 +594,7 @@
 	 */
 	list_splice_init(&mapping->io_pages, mapping->dirty_pages.prev);
 	write_unlock(&mapping->page_lock);
+	pagevec_deactivate_inactive(&pvec);
 	if (bio)
 		mpage_bio_submit(WRITE, bio);
 	return ret;
diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
--- a/fs/ncpfs/inode.c	Tue Aug 27 12:28:06 2002
+++ b/fs/ncpfs/inode.c	Tue Aug 27 12:28:06 2002
@@ -221,9 +221,9 @@
 }
 
 static struct inode_operations ncp_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	setattr:	ncp_notify_change,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setattr	= ncp_notify_change,
 };
 
 /*
diff -Nru a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
--- a/fs/ncpfs/mmap.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ncpfs/mmap.c	Tue Aug 27 12:28:08 2002
@@ -90,7 +90,7 @@
 
 static struct vm_operations_struct ncp_file_mmap =
 {
-	nopage:	ncp_file_mmap_nopage,
+	.nopage	= ncp_file_mmap_nopage,
 };
 
 
diff -Nru a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
--- a/fs/ncpfs/symlink.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ncpfs/symlink.c	Tue Aug 27 12:28:08 2002
@@ -100,7 +100,7 @@
  * symlinks can't do much...
  */
 struct address_space_operations ncp_symlink_aops = {
-	readpage:	ncp_symlink_readpage,
+	.readpage	= ncp_symlink_readpage,
 };
 	
 /* ----- create a new symbolic link -------------------------------------- */
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nfs/nfs2xdr.c	Tue Aug 27 12:28:02 2002
@@ -233,6 +233,7 @@
 static int
 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct iovec *iov = req->rq_rvec;
 	int	status, count, recvd, hdrlen;
 
@@ -241,25 +242,33 @@
 	p = xdr_decode_fattr(p, res->fattr);
 
 	count = ntohl(*p++);
+	res->eof = 0;
+	if (rcvbuf->page_len) {
+		u32 end = page_offset(rcvbuf->pages[0]) + rcvbuf->page_base + count;
+		if (end >= res->fattr->size)
+			res->eof = 1;
+	}
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	if (iov->iov_len > hdrlen) {
+	if (iov->iov_len < hdrlen) {
+		printk(KERN_WARNING "NFS: READ reply header overflowed:"
+				"length %d > %d\n", hdrlen, iov->iov_len);
+		return -errno_NFSERR_IO;
+	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
-	recvd = req->rq_rlen - hdrlen;
+	recvd = req->rq_received - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
 		count = recvd;
+		res->eof = 0;
 	}
 
 	dprintk("RPC:      readres OK count %d\n", count);
-	if (count < res->count) {
+	if (count < res->count)
 		res->count = count;
-		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
-	} else
-		res->eof = 0;
 
 	return count;
 }
@@ -384,7 +393,7 @@
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct iovec *iov = rcvbuf->head;
 	struct page **page;
-	int hdrlen;
+	int hdrlen, recvd;
 	int status, nr;
 	unsigned int len, pglen;
 	u32 *end, *entry;
@@ -393,17 +402,24 @@
 		return -nfs_stat_to_errno(status);
 
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	if (iov->iov_len > hdrlen) {
+	if (iov->iov_len < hdrlen) {
+		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+				"length %d > %d\n", hdrlen, iov->iov_len);
+		return -errno_NFSERR_IO;
+	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
 	pglen = rcvbuf->page_len;
+	recvd = req->rq_received - hdrlen;
+	if (pglen > recvd)
+		pglen = recvd;
 	page = rcvbuf->pages;
 	p = kmap(*page);
 	end = (u32 *)((char *)p + pglen);
+	entry = p;
 	for (nr = 0; *p++; nr++) {
-		entry = p - 1;
 		if (p + 2 > end)
 			goto short_pkt;
 		p++; /* fileid */
@@ -416,14 +432,21 @@
 		}
 		if (p + 2 > end)
 			goto short_pkt;
+		entry = p;
 	}
+	if (!nr)
+		goto short_pkt;
+ out:
 	kunmap(*page);
 	return nr;
  short_pkt:
-	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	entry[0] = entry[1] = 0;
-	kunmap(*page);
-	return nr;
+	/* truncate listing ? */
+	if (!nr) {
+		printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+		entry[1] = 1;
+	}
+	goto out;
 err_unmap:
 	kunmap(*page);
 	return -errno_NFSERR_IO;
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Tue Aug 27 12:28:08 2002
+++ b/fs/nfs/nfs3xdr.c	Tue Aug 27 12:28:08 2002
@@ -504,7 +504,7 @@
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct iovec *iov = rcvbuf->head;
 	struct page **page;
-	int hdrlen;
+	int hdrlen, recvd;
 	int status, nr;
 	unsigned int len, pglen;
 	u32 *entry, *end;
@@ -523,17 +523,24 @@
 	}
 
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	if (iov->iov_len > hdrlen) {
+	if (iov->iov_len < hdrlen) {
+		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+				"length %d > %d\n", hdrlen, iov->iov_len);
+		return -errno_NFSERR_IO;
+	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
 	pglen = rcvbuf->page_len;
+	recvd = req->rq_received - hdrlen;
+	if (pglen > recvd)
+		pglen = recvd;
 	page = rcvbuf->pages;
 	p = kmap(*page);
 	end = (u32 *)((char *)p + pglen);
+	entry = p;
 	for (nr = 0; *p++; nr++) {
-		entry = p - 1;
 		if (p + 3 > end)
 			goto short_pkt;
 		p += 2;				/* inode # */
@@ -570,15 +577,21 @@
 
 		if (p + 2 > end)
 			goto short_pkt;
+		entry = p;
 	}
+	if (!nr)
+		goto short_pkt;
+ out:
 	kunmap(*page);
 	return nr;
  short_pkt:
-	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
-	/* truncate listing */
 	entry[0] = entry[1] = 0;
-	kunmap(*page);
-	return nr;
+	/* truncate listing ? */
+	if (!nr) {
+		printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+		entry[1] = 1;
+	}
+	goto out;
 err_unmap:
 	kunmap(*page);
 	return -errno_NFSERR_IO;
@@ -793,16 +806,21 @@
 	}
 
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	if (iov->iov_len > hdrlen) {
+	if (iov->iov_len < hdrlen) {
+		printk(KERN_WARNING "NFS: READ reply header overflowed:"
+				"length %d > %d\n", hdrlen, iov->iov_len);
+       		return -errno_NFSERR_IO;
+	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
-	recvd = req->rq_rlen - hdrlen;
+	recvd = req->rq_received - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
 		count = recvd;
+		res->eof = 0;
 	}
 
 	if (count < res->count)
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Tue Aug 27 12:27:40 2002
+++ b/fs/nfs/read.c	Tue Aug 27 12:27:40 2002
@@ -424,9 +424,14 @@
 				memset(p + count, 0, PAGE_CACHE_SIZE - count);
 				kunmap(page);
 				count = 0;
-			} else
+				if (data->res.eof)
+					SetPageUptodate(page);
+				else
+					SetPageError(page);
+			} else {
 				count -= PAGE_CACHE_SIZE;
-			SetPageUptodate(page);
+				SetPageUptodate(page);
+			}
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
diff -Nru a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
--- a/fs/nfsd/nfs3proc.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nfsd/nfs3proc.c	Tue Aug 27 12:28:02 2002
@@ -134,7 +134,7 @@
 
 	fh_copy(&resp->fh, &argp->fh);
 	resp->access = argp->access;
-	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access);
+	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
 	RETURN_STATUS(nfserr);
 }
 
@@ -267,7 +267,7 @@
 	/* Now create the file and set attributes */
 	nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
 				attr, newfhp,
-				argp->createmode, argp->verf);
+				argp->createmode, argp->verf, NULL);
 
 	RETURN_STATUS(nfserr);
 }
@@ -460,7 +460,7 @@
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, 
 					nfs3svc_encode_entry,
-					buffer, &count, argp->verf);
+					buffer, &count, argp->verf, NULL);
 	memcpy(resp->verf, argp->verf, 8);
 	resp->count = count;
 
@@ -495,7 +495,7 @@
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, 
 					nfs3svc_encode_entry_plus,
-					buffer, &count, argp->verf);
+					buffer, &count, argp->verf, NULL);
 	memcpy(resp->verf, argp->verf, 8);
 	resp->count = count;
 
diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nfsd/nfsfh.c	Tue Aug 27 12:28:02 2002
@@ -107,8 +107,10 @@
 		int fsid = 0;
 
 		error = nfserr_stale;
-		if (rqstp->rq_vers == 3)
+		if (rqstp->rq_vers > 2)
 			error = nfserr_badhandle;
+		if (rqstp->rq_vers == 4 && fh->fh_size == 0)
+			return nfserr_nofilehandle;
 
 		if (fh->fh_version == 1) {
 			datap = fh->fh_auth;
@@ -171,7 +173,7 @@
 		 * Look up the dentry using the NFS file handle.
 		 */
 		error = nfserr_stale;
-		if (rqstp->rq_vers == 3)
+		if (rqstp->rq_vers > 2)
 			error = nfserr_badhandle;
 
 		if (fh->fh_version != 1) {
@@ -234,11 +236,23 @@
 
 	/* Type can be negative when creating hardlinks - not to a dir */
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
-		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
+			error = nfserr_symlink;
+		else if (type == S_IFDIR)
+			error = nfserr_notdir;
+		else if ((inode->i_mode & S_IFMT) == S_IFDIR)
+			error = nfserr_isdir;
+		else
+			error = nfserr_inval;
 		goto out;
 	}
 	if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
-		error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
+			error = nfserr_symlink;
+		else if (type == -S_IFDIR)
+			error = nfserr_isdir;
+		else
+			error = nfserr_notdir;
 		goto out;
 	}
 
@@ -302,7 +316,9 @@
 	 * Then create a 32byte filehandle using nfs_fhbase_old
 	 *
 	 */
-	
+
+	u8 ref_fh_version = 0;
+	u8 ref_fh_fsid_type = 0;
 	struct inode * inode = dentry->d_inode;
 	struct dentry *parent = dentry->d_parent;
 	__u32 *datap;
@@ -312,6 +328,13 @@
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
+	if (ref_fh) {
+		ref_fh_version = ref_fh->fh_handle.fh_version;
+		ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
+		if (ref_fh == fhp)
+			fh_put(ref_fh);
+	}
+
 	if (fhp->fh_locked || fhp->fh_dentry) {
 		printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
 			parent->d_name.name, dentry->d_name.name);
@@ -323,8 +346,7 @@
 	fhp->fh_dentry = dentry; /* our internal copy */
 	fhp->fh_export = exp;
 
-	if (ref_fh &&
-	    ref_fh->fh_handle.fh_version == 0xca) {
+	if (ref_fh_version == 0xca) {
 		/* old style filehandle please */
 		memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 		fhp->fh_handle.fh_size = NFS_FHSIZE;
@@ -340,7 +362,7 @@
 		fhp->fh_handle.fh_auth_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
 		if ((exp->ex_flags & NFSEXP_FSID) &&
-		    (!ref_fh || ref_fh->fh_handle.fh_fsid_type == 1)) {
+		    (ref_fh_fsid_type == 1)) {
 			fhp->fh_handle.fh_fsid_type = 1;
 			/* fsid_type 1 == 4 bytes filesystem id */
 			*datap++ = exp->ex_fsid;
@@ -424,6 +446,10 @@
 		fh_unlock(fhp);
 		fhp->fh_dentry = NULL;
 		dput(dentry);
+#ifdef CONFIG_NFSD_V3
+		fhp->fh_pre_saved = 0;
+		fhp->fh_post_saved = 0;
+#endif
 		nfsd_nr_put++;
 	}
 	return;
diff -Nru a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
--- a/fs/nfsd/nfsproc.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nfsd/nfsproc.c	Tue Aug 27 12:28:02 2002
@@ -492,7 +492,7 @@
 	/* Read directory and encode entries on the fly */
 	nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, 
 			      nfssvc_encode_entry,
-			      buffer, &count, NULL);
+			      buffer, &count, NULL, NULL);
 	resp->count = count;
 
 	fh_put(&argp->fh);
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nfsd/vfs.c	Tue Aug 27 12:28:02 2002
@@ -348,12 +348,12 @@
 };
 
 int
-nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
+nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported)
 {
 	struct accessmap	*map;
 	struct svc_export	*export;
 	struct dentry		*dentry;
-	u32			query, result = 0;
+	u32			query, result = 0, sresult = 0;
 	unsigned int		error;
 
 	error = fh_verify(rqstp, fhp, 0, MAY_NOP);
@@ -375,6 +375,9 @@
 	for  (; map->access; map++) {
 		if (map->access & query) {
 			unsigned int err2;
+
+			sresult |= map->access;
+
 			err2 = nfsd_permission(export, dentry, map->how);
 			switch (err2) {
 			case nfs_ok:
@@ -395,6 +398,8 @@
 		}
 	}
 	*access = result;
+	if (supported)
+		*supported = sresult;
 
  out:
 	return error;
@@ -756,6 +761,9 @@
 	struct file	file;
 	int		err;
 
+	if ((u64)count > ~(u64)offset)
+		return nfserr_inval;
+
 	if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
 		return err;
 	if (EX_ISSYNC(fhp->fh_export)) {
@@ -904,7 +912,8 @@
 int
 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		char *fname, int flen, struct iattr *iap,
-		struct svc_fh *resfhp, int createmode, u32 *verifier)
+		struct svc_fh *resfhp, int createmode, u32 *verifier,
+	        int *truncp)
 {
 	struct dentry	*dentry, *dchild;
 	struct inode	*dirp;
@@ -966,6 +975,16 @@
 		case NFS3_CREATE_UNCHECKED:
 			if (! S_ISREG(dchild->d_inode->i_mode))
 				err = nfserr_exist;
+			else if (truncp) {
+				/* in nfsv4, we need to treat this case a little
+				 * differently.  we don't want to truncate the
+				 * file now; this would be wrong if the OPEN
+				 * fails for some other reason.  furthermore,
+				 * if the size is nonzero, we should ignore it
+				 * according to spec!
+				 */
+				*truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size;
+			}
 			else {
 				iap->ia_valid &= ATTR_SIZE;
 				goto set_attr;
@@ -1326,6 +1345,9 @@
 		goto out;
 	}
 
+	if (!type)
+		type = rdentry->d_inode->i_mode & S_IFMT;
+
 	if (type != S_IFDIR) { /* It's UNLINK */
 #ifdef MSNFS
 		if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
@@ -1359,7 +1381,7 @@
  */
 int
 nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, 
-             encode_dent_fn func, u32 *buffer, int *countp, u32 *verf)
+             encode_dent_fn func, u32 *buffer, int *countp, u32 *verf, u32 *bmval)
 {
 	u32		*p;
 	int		oldlen, eof, err;
@@ -1380,6 +1402,10 @@
 	cd.buffer = buffer;
 	cd.buflen = *countp; /* count of words */
 	cd.dirfh  = fhp;
+	if (bmval) {
+		cd.bmval[0] = bmval[0];
+		cd.bmval[1] = bmval[1];
+	}
 
 	/*
 	 * Read the directory entries. This silly loop is necessary because
@@ -1395,13 +1421,20 @@
 		if (err < 0)
 			goto out_nfserr;
 
+		err = cd.nfserr;
+		if (err)
+			goto out_close;
 	} while (oldlen != cd.buflen && !cd.eob);
 
+	err = nfserr_readdir_nospc;
+	if (rqstp->rq_vers == 4 && cd.eob && cd.buffer == buffer)
+		goto out_close;
+
 	/* If we didn't fill the buffer completely, we're at EOF */
 	eof = !cd.eob;
 
 	if (cd.offset) {
-		if (rqstp->rq_vers == 3)
+		if (rqstp->rq_vers > 2)
 			(void)xdr_encode_hyper(cd.offset, file.f_pos);
 		else
 			*cd.offset = htonl(file.f_pos);
diff -Nru a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c
--- a/fs/nls/nls_iso8859-1.c	Tue Aug 27 12:27:56 2002
+++ b/fs/nls/nls_iso8859-1.c	Tue Aug 27 12:27:56 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x00a1, 0x00a2, 0x00a3,
 	0x00a4, 0x00a5, 0x00a6, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -154,10 +154,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -190,10 +190,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c
--- a/fs/nls/nls_iso8859-13.c	Tue Aug 27 12:28:07 2002
+++ b/fs/nls/nls_iso8859-13.c	Tue Aug 27 12:28:07 2002
@@ -53,15 +53,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x201d, 0x00a2, 0x00a3,
 	0x00a4, 0x201e, 0x00a6, 0x00a7,
@@ -112,10 +112,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -182,10 +182,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -218,10 +218,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c
--- a/fs/nls/nls_iso8859-14.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nls/nls_iso8859-14.c	Tue Aug 27 12:28:02 2002
@@ -60,15 +60,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b, 
 	0x007c, 0x007d, 0x007e, 0x007f, 
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x1e02, 0x1e03, 0x00a3, 
 	0x010a, 0x010b, 0x1e0a, 0x00a7, 
@@ -119,10 +119,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
 	0x00, 0xa9, 0x00, 0x00, 0x00, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */
@@ -238,10 +238,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa2, 0xa2, 0xa3, 0xab, 0xab, 0xab, 0xa7, /* 0xa0-0xa7 */
 	0xb8, 0xa9, 0xba, 0xab, 0xbc, 0xad, 0xae, 0xff, /* 0xa8-0xaf */
 	0xb1, 0xb1, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb9, /* 0xb0-0xb7 */
@@ -274,10 +274,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa1, 0xa3, 0xa6, 0xa6, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xa6, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb0, 0xb2, 0xb2, 0xb4, 0xb4, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c
--- a/fs/nls/nls_iso8859-15.c	Tue Aug 27 12:28:07 2002
+++ b/fs/nls/nls_iso8859-15.c	Tue Aug 27 12:28:07 2002
@@ -53,15 +53,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x00a1, 0x00a2, 0x00a3,
 	0x20ac, 0x00a5, 0x0160, 0x00a7,
@@ -112,10 +112,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
 	0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -204,10 +204,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb8, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -240,10 +240,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa6, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c
--- a/fs/nls/nls_iso8859-2.c	Tue Aug 27 12:28:05 2002
+++ b/fs/nls/nls_iso8859-2.c	Tue Aug 27 12:28:05 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x0104, 0x02d8, 0x0141,
 	0x00a4, 0x013d, 0x015a, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 	0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
@@ -205,10 +205,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -241,10 +241,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c
--- a/fs/nls/nls_iso8859-3.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nls/nls_iso8859-3.c	Tue Aug 27 12:28:02 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x0126, 0x02d8, 0x00a3,
 	0x00a4, 0x0000, 0x0124, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0xa3, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 	0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */
@@ -205,10 +205,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xb1, 0xa2, 0xa3, 0xa4, 0x00, 0xb6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0x69, 0xba, 0xbb, 0xbc, 0xad, 0x00, 0xbf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -241,10 +241,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xa1, 0xb2, 0xb3, 0xb4, 0x00, 0xa6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c
--- a/fs/nls/nls_iso8859-4.c	Tue Aug 27 12:27:56 2002
+++ b/fs/nls/nls_iso8859-4.c	Tue Aug 27 12:27:56 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x0104, 0x0138, 0x0156,
 	0x00a4, 0x0128, 0x013b, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
@@ -205,10 +205,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -241,10 +241,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c
--- a/fs/nls/nls_iso8859-5.c	Tue Aug 27 12:28:02 2002
+++ b/fs/nls/nls_iso8859-5.c	Tue Aug 27 12:28:02 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x0401, 0x0402, 0x0403,
 	0x0404, 0x0405, 0x0406, 0x0407,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 };
@@ -169,10 +169,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xa0-0xa7 */
 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xad, 0xfe, 0xff, /* 0xa8-0xaf */
 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xb0-0xb7 */
@@ -205,10 +205,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c
--- a/fs/nls/nls_iso8859-6.c	Tue Aug 27 12:28:01 2002
+++ b/fs/nls/nls_iso8859-6.c	Tue Aug 27 12:28:01 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x0000, 0x0000, 0x0000,
 	0x00a4, 0x0000, 0x0000, 0x0000,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 };
@@ -161,10 +161,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
 	0x00, 0x00, 0x00, 0x00, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
@@ -197,10 +197,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
 	0x00, 0x00, 0x00, 0x00, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c
--- a/fs/nls/nls_iso8859-7.c	Tue Aug 27 12:27:45 2002
+++ b/fs/nls/nls_iso8859-7.c	Tue Aug 27 12:27:45 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x02bd, 0x02bc, 0x00a3,
 	0x0000, 0x0000, 0x00a6, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
@@ -214,10 +214,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xdc, 0xb7, /* 0xb0-0xb7 */
@@ -250,10 +250,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c
--- a/fs/nls/nls_iso8859-9.c	Tue Aug 27 12:28:07 2002
+++ b/fs/nls/nls_iso8859-9.c	Tue Aug 27 12:28:07 2002
@@ -55,15 +55,15 @@
 	0x0078, 0x0079, 0x007a, 0x007b,
 	0x007c, 0x007d, 0x007e, 0x007f,
 	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0080, 0x0081, 0x0082, 0x0083,
+	0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b,
+	0x008c, 0x008d, 0x008e, 0x008f,
 	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0090, 0x0091, 0x0092, 0x0093,
+	0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b,
+	0x009c, 0x009d, 0x009e, 0x009f,
 	/* 0xa0*/
 	0x00a0, 0x00a1, 0x00a2, 0x00a3,
 	0x00a4, 0x00a5, 0x00a6, 0x00a7,
@@ -114,10 +114,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -169,10 +169,10 @@
 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
@@ -205,10 +205,10 @@
 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Tue Aug 27 12:28:02 2002
+++ b/fs/ntfs/ChangeLog	Tue Aug 27 12:28:02 2002
@@ -2,6 +2,16 @@
 	- Find and fix bugs.
 	- Enable NFS exporting of NTFS.
 
+2.0.25 - Small bug fixes and cleanups.
+
+	- Unlock the page in an out of memory error code path in
+	  fs/ntfs/aops.c::ntfs_read_block().
+	- If fs/ntfs/aops.c::ntfs_read_page() is called on an uptodate page,
+	  just unlock the page and return. (This can happen due to ->writepage
+	  clearing PageUptodate() during write out of MstProtected()
+	  attributes.
+	- Remove leaked write code again.
+
 2.0.24 - Cleanups.
 
 	- Treat BUG_ON() as ASSERT() not VERIFY(), i.e. do not use side effects
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Tue Aug 27 12:27:51 2002
+++ b/fs/ntfs/Makefile	Tue Aug 27 12:27:51 2002
@@ -5,7 +5,7 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.24\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.25\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ntfs/aops.c	Tue Aug 27 12:28:08 2002
@@ -156,6 +156,9 @@
  * applies the mst fixups to the page before finally marking it uptodate and
  * unlocking it.
  *
+ * We only enforce allocated_size limit because i_size is checked for in
+ * generic_file_read().
+ *
  * Return 0 on success and -errno on error.
  *
  * Contains an adapted version of fs/buffer.c::block_read_full_page().
@@ -182,8 +185,10 @@
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
-	if (unlikely(!bh))
+	if (unlikely(!bh)) {
+		unlock_page(page);
 		return -ENOMEM;
+	}
 
 	iblock = page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
 	lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits;
@@ -343,8 +348,16 @@
 	u32 attr_len;
 	int err = 0;
 
-	if (unlikely(!PageLocked(page)))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
+
+	/*
+	 * This can potentially happen because we clear PageUptodate() during
+	 * ntfs_writepage() of MstProtected() attributes.
+	 */
+	if (PageUptodate(page)) {
+		unlock_page(page);
+		return 0;
+	}
 
 	ni = NTFS_I(page->mapping->host);
 
diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c
--- a/fs/ntfs/file.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ntfs/file.c	Tue Aug 27 12:28:08 2002
@@ -51,9 +51,6 @@
 struct file_operations ntfs_file_ops = {
 	.llseek		= generic_file_llseek,	/* Seek inside file. */
 	.read		= generic_file_read,	/* Read from file. */
-#ifdef NTFS_RW
-	.write		= generic_file_write,	/* Write to a file. */
-#endif
 	.mmap		= generic_file_mmap,	/* Mmap file. */
 	.sendfile	= generic_file_sendfile,/* Zero-copy data send with the
 						   data source being on the
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Tue Aug 27 12:28:02 2002
+++ b/fs/partitions/check.c	Tue Aug 27 12:28:02 2002
@@ -79,22 +79,7 @@
 #endif
 	NULL
 };
-
-/*
- *	This is ucking fugly but its probably the best thing for 2.4.x
- *	Take it as a clear reminder that: 1) we should put the device name
- *	generation in the object kdev_t points to in 2.5.
- *	and 2) ioctls better work on half-opened devices.
- */
  
-#ifdef CONFIG_ARCH_S390
-int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
-int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
-			unsigned int no, unsigned long data);
-EXPORT_SYMBOL(genhd_dasd_name);
-EXPORT_SYMBOL(genhd_dasd_ioctl);
-#endif
-
 /*
  * disk_name() is used by partition check code and the md driver.
  * It formats the devicename of the indicated disk into
@@ -119,11 +104,6 @@
 			return buf + pos;
 	}
 
-#ifdef CONFIG_ARCH_S390
-	if (genhd_dasd_name
-	    && genhd_dasd_name (buf, unit, part, hd) == 0)
-		return buf;
-#endif
 	/*
 	 * Yes, I know, ... in cases is gccism and not a pretty one.  
 	 * However, the first variant will eventually consume _all_ cases
@@ -137,24 +117,7 @@
 			sprintf(s, "%s%d", "md", unit);
 			maj = s;
 			break;
-		case COMPAQ_CISS_MAJOR ... COMPAQ_CISS_MAJOR+7:
-			sprintf(s, "cciss/c%dd%d",
-				hd->major - COMPAQ_CISS_MAJOR, unit);
-			maj = s;
-			break;
-		case DAC960_MAJOR ... DAC960_MAJOR+7:
-			sprintf(s, "rd/c%dd%d",
-				hd->major - DAC960_MAJOR, unit);
-			maj = s;
-			break;
-		case ATARAID_MAJOR:
-			sprintf(s, "ataraid/d%d", unit);
-			maj = s;
-			break;
-		case ACSI_MAJOR:
-		case XT_DISK_MAJOR:
 		case I2O_MAJOR:
-		case DASD_MAJOR:
 			sprintf(s, "%s%c", hd->major_name, unit + 'a');
 			maj = s;
 	}
@@ -175,14 +138,14 @@
 	kdev.value=(int)(long)driverfs_dev->driver_data;
 	return off ? 0 : sprintf (page, "%x\n",kdev.value);
 }
-static DEVICE_ATTR(kdev,"kdev",S_IRUGO,partition_device_kdev_read,NULL);
+static DEVICE_ATTR(kdev,S_IRUGO,partition_device_kdev_read,NULL);
 
 static ssize_t partition_device_type_read(struct device *driverfs_dev, 
 			char *page, size_t count, loff_t off) 
 {
 	return off ? 0 : sprintf (page, "BLK\n");
 }
-static DEVICE_ATTR(type,"type",S_IRUGO,partition_device_type_read,NULL);
+static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
 
 void driverfs_create_partitions(struct gendisk *hd, int minor)
 {
diff -Nru a/fs/partitions/ibm.c b/fs/partitions/ibm.c
--- a/fs/partitions/ibm.c	Tue Aug 27 12:28:08 2002
+++ b/fs/partitions/ibm.c	Tue Aug 27 12:28:08 2002
@@ -53,39 +53,6 @@
 }
 
 /*
- * We used to use ioctl_by_bdev in early 2.4, but it broke
- * between 2.4.9 and 2.4.18 somewhere.
- */
-extern int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
-			       unsigned int no, unsigned long data);
-
-static int
-ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg)
-{
-	int res;
-	mm_segment_t old_fs = get_fs();
-	
-	if (genhd_dasd_ioctl == NULL)
-		return -ENODEV;
-#if 0
-	lock_kernel();
-	if (bd_ops->owner)
-		__MOD_INC_USE_COUNT(bdev->bd_op->owner);
-	unlock_kernel();
-#endif
-	set_fs(KERNEL_DS);
-	res = (*genhd_dasd_ioctl)(bdev->bd_inode, NULL, cmd, arg);
-	set_fs(old_fs);
-#if 0
-	lock_kernel();
-	if (bd_ops->owner)
-		__MOD_DEV_USE_COUNT(bd_ops->owner);
-	unlock_kernel();
-#endif
-	return res;
-}
-
-/*
  */
 int 
 ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
@@ -106,8 +73,8 @@
 	if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
 		goto out_novlab;
 	
-	if (ibm_ioctl_unopened(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
-	    ibm_ioctl_unopened(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
+	if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
+	    ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
 		goto out_noioctl;
 	
 	if ((blocksize = bdev_hardsect_size(bdev)) <= 0)
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Tue Aug 27 12:27:59 2002
+++ b/fs/proc/base.c	Tue Aug 27 12:27:59 2002
@@ -1121,12 +1121,6 @@
 	return ERR_PTR(-ENOENT);
 }
 
-void proc_pid_delete_inode(struct inode *inode)
-{
-	if (proc_task(inode))
-		put_task_struct(proc_task(inode));
-}
-
 #define PROC_NUMBUF 10
 #define PROC_MAXPIDS 20
 
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Tue Aug 27 12:28:02 2002
+++ b/fs/proc/inode.c	Tue Aug 27 12:28:02 2002
@@ -59,14 +59,18 @@
  */
 static void proc_delete_inode(struct inode *inode)
 {
-	struct proc_dir_entry *de = PDE(inode);
+	struct proc_dir_entry *de;
+	struct task_struct *tsk;
 
 	inode->i_state = I_CLEAR;
 
-	if (PROC_INODE_PROPER(inode)) {
-		proc_pid_delete_inode(inode);
-		return;
-	}
+	/* Let go of any associated process */
+	tsk = PROC_I(inode)->task;
+	if (tsk)
+		put_task_struct(tsk);
+
+	/* Let go of any associated proc directory entry */
+	de = PROC_I(inode)->pde;
 	if (de) {
 		if (de->owner)
 			__MOD_DEC_USE_COUNT(de->owner);
@@ -86,10 +90,18 @@
 static struct inode *proc_alloc_inode(struct super_block *sb)
 {
 	struct proc_inode *ei;
+	struct inode *inode;
+
 	ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL);
 	if (!ei)
 		return NULL;
-	return &ei->vfs_inode;
+	ei->task = NULL;
+	ei->type = 0;
+	ei->op.proc_get_link = NULL;
+	ei->pde = NULL;
+	inode = &ei->vfs_inode;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	return inode;
 }
 
 static void proc_destroy_inode(struct inode *inode)
diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c
--- a/fs/romfs/inode.c	Tue Aug 27 12:28:08 2002
+++ b/fs/romfs/inode.c	Tue Aug 27 12:28:08 2002
@@ -83,6 +83,12 @@
 	struct inode vfs_inode;
 };
 
+/* instead of private superblock data */
+static inline unsigned long romfs_maxsize(struct super_block *sb)
+{
+	return (unsigned long)sb->u.generic_sbp;
+}
+
 static inline struct romfs_inode_info *ROMFS_I(struct inode *inode)
 {
 	return list_entry(inode, struct romfs_inode_info, vfs_inode);
@@ -113,7 +119,6 @@
 	/* I would parse the options here, but there are none.. :) */
 
 	sb_set_blocksize(s, ROMBSIZE);
-	s->u.generic_sbp = (void *) 0;
 	s->s_maxbytes = 0xFFFFFFFF;
 
 	bh = sb_bread(s, 0);
@@ -139,7 +144,7 @@
 	}
 
 	s->s_magic = ROMFS_MAGIC;
-	s->u.romfs_sb.s_maxsize = sz;
+	s->u.generic_sbp = (void *)sz;
 
 	s->s_flags |= MS_RDONLY;
 
@@ -175,7 +180,7 @@
 	buf->f_type = ROMFS_MAGIC;
 	buf->f_bsize = ROMBSIZE;
 	buf->f_bfree = buf->f_bavail = buf->f_ffree;
-	buf->f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
+	buf->f_blocks = (romfs_maxsize(sb)+ROMBSIZE-1)>>ROMBSBITS;
 	buf->f_namelen = ROMFS_MAXFN;
 	return 0;
 }
@@ -188,7 +193,7 @@
 	struct buffer_head *bh;
 	unsigned long avail, maxsize, res;
 
-	maxsize = i->i_sb->u.romfs_sb.s_maxsize;
+	maxsize = romfs_maxsize(i->i_sb);
 	if (offset >= maxsize)
 		return -1;
 
@@ -230,7 +235,7 @@
 	struct buffer_head *bh;
 	unsigned long avail, maxsize, res;
 
-	maxsize = i->i_sb->u.romfs_sb.s_maxsize;
+	maxsize = romfs_maxsize(i->i_sb);
 	if (offset >= maxsize || count > maxsize || offset+count>maxsize)
 		return -1;
 
@@ -275,8 +280,8 @@
 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
 
 	lock_kernel();
-	
-	maxoff = i->i_sb->u.romfs_sb.s_maxsize;
+
+	maxoff = romfs_maxsize(i->i_sb);
 
 	offset = filp->f_pos;
 	if (!offset) {
@@ -339,7 +344,7 @@
 	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
 		goto out;
 
-	maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
+	maxoff = romfs_maxsize(dir->i_sb);
 	offset = ntohl(ri.spec) & ROMFH_MASK;
 
 	/* OK, now find the file whose name is in "dentry" in the
diff -Nru a/fs/ufs/balloc.c b/fs/ufs/balloc.c
--- a/fs/ufs/balloc.c	Tue Aug 27 12:27:59 2002
+++ b/fs/ufs/balloc.c	Tue Aug 27 12:27:59 2002
@@ -47,7 +47,7 @@
 	unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno;
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	
 	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
@@ -89,7 +89,7 @@
 	
 	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
 	fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count);
-	fs32_add(sb, &sb->fs_cs(cgno).cs_nffree, count);
+	fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
 	blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
 	ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
 
@@ -100,12 +100,12 @@
 	if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
 		fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
 		fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
-		fs32_sub(sb, &sb->fs_cs(cgno).cs_nffree, uspi->s_fpb);
-		if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+		fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
+		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
 		fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
-		fs32_add(sb, &sb->fs_cs(cgno).cs_nbfree, 1);
+		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
 		cylno = ufs_cbtocylno (bbase);
 		fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1);
 		fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
@@ -141,7 +141,7 @@
 	unsigned overflow, cgno, bit, end_bit, blkno, i, cylno;
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 
 	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
@@ -184,13 +184,13 @@
 			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
 		}
 		ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
-		if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 		DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
 
 		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
 		fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
-		fs32_add(sb, &sb->fs_cs(cgno).cs_nbfree, 1);
+		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
 		cylno = ufs_cbtocylno(i);
 		fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1);
 		fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
@@ -247,7 +247,7 @@
 	UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	*err = -ENOSPC;
 
@@ -285,7 +285,7 @@
 			return 0;
 		}
 	}
-	
+
 	/*
 	 * There is not enough space for user on the device
 	 */
@@ -293,8 +293,8 @@
 		unlock_super (sb);
 		UFSD(("EXIT (FAILED)\n"))
 		return 0;
-	} 
-	
+	}
+
 	if (goal >= uspi->s_size) 
 		goal = 0;
 	if (goal == 0) 
@@ -407,12 +407,12 @@
 	UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
 	count = newcount - oldcount;
 	
 	cgno = ufs_dtog(fragment);
-	if (sb->fs_cs(cgno).cs_nffree < count)
+	if (UFS_SB(sb)->fs_cs(cgno).cs_nffree < count)
 		return 0;
 	if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
 		return 0;
@@ -453,7 +453,7 @@
 	}
 
 	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
-	fs32_sub(sb, &sb->fs_cs(cgno).cs_nffree, count);
+	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
 	fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
 	
 	ubh_mark_buffer_dirty (USPI_UBH);
@@ -470,7 +470,7 @@
 }
 
 #define UFS_TEST_FREE_SPACE_CG \
-	ucg = (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[cgno]->b_data; \
+	ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
 	if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
 		goto cg_found; \
 	for (k = count; k < uspi->s_fpb; k++) \
@@ -490,7 +490,7 @@
 	UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	oldcg = cgno;
 	
@@ -557,7 +557,7 @@
 
 		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
 		fs32_add(sb, &usb1->fs_cstotal.cs_nffree, i);
-		fs32_add(sb, &sb->fs_cs(cgno).cs_nffree, i);
+		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
 		fs32_add(sb, &ucg->cg_frsum[i], 1);
 		goto succed;
 	}
@@ -574,7 +574,7 @@
 	
 	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
 	fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
-	fs32_sub(sb, &sb->fs_cs(cgno).cs_nffree, count);
+	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
 	fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
 
 	if (count != allocsize)
@@ -606,7 +606,7 @@
 	UFSD(("ENTER, goal %u\n", goal))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	ucg = ubh_get_ucg(UCPI_UBH);
 
@@ -633,7 +633,7 @@
 gotit:
 	blkno = ufs_fragstoblks(result);
 	ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
-	if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 		ufs_clusteracct (sb, ucpi, blkno, -1);
 	if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
 		*err = -EDQUOT;
@@ -642,7 +642,7 @@
 
 	fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
 	fs32_sub(sb, &usb1->fs_cstotal.cs_nbfree, 1);
-	fs32_sub(sb, &sb->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
+	fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
 	cylno = ufs_cbtocylno(result);
 	fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1);
 	fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
@@ -663,7 +663,7 @@
 	
 	UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
 
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
 	ucg = ubh_get_ucg(UCPI_UBH);
 
@@ -729,7 +729,7 @@
 	struct ufs_sb_private_info * uspi;
 	int i, start, end, forw, back;
 	
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	if (uspi->s_contigsumsize <= 0)
 		return;
 
diff -Nru a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
--- a/fs/ufs/cylinder.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ufs/cylinder.c	Tue Aug 27 12:28:08 2002
@@ -36,26 +36,27 @@
 static void ufs_read_cylinder (struct super_block * sb,
 	unsigned cgno, unsigned bitmap_nr)
 {
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
 	struct ufs_cg_private_info * ucpi;
 	struct ufs_cylinder_group * ucg;
 	unsigned i, j;
 
 	UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
-	uspi = sb->u.ufs_sb.s_uspi;
-	ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
-	ucg = (struct ufs_cylinder_group *)sb->u.ufs_sb.s_ucg[cgno]->b_data;
+	uspi = sbi->s_uspi;
+	ucpi = sbi->s_ucpi[bitmap_nr];
+	ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data;
 
 	UCPI_UBH->fragment = ufs_cgcmin(cgno);
 	UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
 	/*
 	 * We have already the first fragment of cylinder group block in buffer
 	 */
-	UCPI_UBH->bh[0] = sb->u.ufs_sb.s_ucg[cgno];
+	UCPI_UBH->bh[0] = sbi->s_ucg[cgno];
 	for (i = 1; i < UCPI_UBH->count; i++)
 		if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i)))
 			goto failed;
-	sb->u.ufs_sb.s_cgno[bitmap_nr] = cgno;
+	sbi->s_cgno[bitmap_nr] = cgno;
 			
 	ucpi->c_cgx	= fs32_to_cpu(sb, ucg->cg_cgx);
 	ucpi->c_ncyl	= fs16_to_cpu(sb, ucg->cg_ncyl);
@@ -77,8 +78,8 @@
 	
 failed:
 	for (j = 1; j < i; j++)
-		brelse (sb->u.ufs_sb.s_ucg[j]);
-	sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+		brelse (sbi->s_ucg[j]);
+	sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
 	ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno);
 }
 
@@ -88,6 +89,7 @@
  */
 void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
 {
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi; 
 	struct ufs_cg_private_info * ucpi;
 	struct ufs_cylinder_group * ucg;
@@ -95,15 +97,15 @@
 
 	UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
 
-	uspi = sb->u.ufs_sb.s_uspi;
-	if (sb->u.ufs_sb.s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
+	uspi = sbi->s_uspi;
+	if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
 		UFSD(("EXIT\n"))
 		return;
 	}
-	ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
+	ucpi = sbi->s_ucpi[bitmap_nr];
 	ucg = ubh_get_ucg(UCPI_UBH);
 
-	if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sb->u.ufs_sb.s_cg_loaded) {
+	if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) {
 		ufs_panic (sb, "ufs_put_cylinder", "internal error");
 		return;
 	}
@@ -119,7 +121,7 @@
 		brelse (UCPI_UBH->bh[i]);
 	}
 
-	sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+	sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
 	UFSD(("EXIT\n"))
 }
 
@@ -132,13 +134,14 @@
 struct ufs_cg_private_info * ufs_load_cylinder (
 	struct super_block * sb, unsigned cgno)
 {
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
 	struct ufs_cg_private_info * ucpi;
 	unsigned cg, i, j;
 
 	UFSD(("ENTER, cgno %u\n", cgno))
 
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = sbi->s_uspi;
 	if (cgno >= uspi->s_ncg) {
 		ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg");
 		return NULL;
@@ -146,61 +149,61 @@
 	/*
 	 * Cylinder group number cg it in cache and it was last used
 	 */
-	if (sb->u.ufs_sb.s_cgno[0] == cgno) {
+	if (sbi->s_cgno[0] == cgno) {
 		UFSD(("EXIT\n"))
-		return sb->u.ufs_sb.s_ucpi[0];
+		return sbi->s_ucpi[0];
 	}
 	/*
 	 * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED
 	 */
 	if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) {
-		if (sb->u.ufs_sb.s_cgno[cgno] != UFS_CGNO_EMPTY) {
-			if (sb->u.ufs_sb.s_cgno[cgno] != cgno) {
+		if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) {
+			if (sbi->s_cgno[cgno] != cgno) {
 				ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache");
 				UFSD(("EXIT (FAILED)\n"))
 				return NULL;
 			}
 			else {
 				UFSD(("EXIT\n"))
-				return sb->u.ufs_sb.s_ucpi[cgno];
+				return sbi->s_ucpi[cgno];
 			}
 		} else {
 			ufs_read_cylinder (sb, cgno, cgno);
 			UFSD(("EXIT\n"))
-			return sb->u.ufs_sb.s_ucpi[cgno];
+			return sbi->s_ucpi[cgno];
 		}
 	}
 	/*
 	 * Cylinder group number cg is in cache but it was not last used, 
 	 * we will move to the first position
 	 */
-	for (i = 0; i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] != cgno; i++);
-	if (i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] == cgno) {
-		cg = sb->u.ufs_sb.s_cgno[i];
-		ucpi = sb->u.ufs_sb.s_ucpi[i];
+	for (i = 0; i < sbi->s_cg_loaded && sbi->s_cgno[i] != cgno; i++);
+	if (i < sbi->s_cg_loaded && sbi->s_cgno[i] == cgno) {
+		cg = sbi->s_cgno[i];
+		ucpi = sbi->s_ucpi[i];
 		for (j = i; j > 0; j--) {
-			sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
-			sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+			sbi->s_cgno[j] = sbi->s_cgno[j-1];
+			sbi->s_ucpi[j] = sbi->s_ucpi[j-1];
 		}
-		sb->u.ufs_sb.s_cgno[0] = cg;
-		sb->u.ufs_sb.s_ucpi[0] = ucpi;
+		sbi->s_cgno[0] = cg;
+		sbi->s_ucpi[0] = ucpi;
 	/*
 	 * Cylinder group number cg is not in cache, we will read it from disk
 	 * and put it to the first position
 	 */
 	} else {
-		if (sb->u.ufs_sb.s_cg_loaded < UFS_MAX_GROUP_LOADED)
-			sb->u.ufs_sb.s_cg_loaded++;
+		if (sbi->s_cg_loaded < UFS_MAX_GROUP_LOADED)
+			sbi->s_cg_loaded++;
 		else
 			ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1);
-		ucpi = sb->u.ufs_sb.s_ucpi[sb->u.ufs_sb.s_cg_loaded - 1];
-		for (j = sb->u.ufs_sb.s_cg_loaded - 1; j > 0; j--) {
-			sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
-			sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+		ucpi = sbi->s_ucpi[sbi->s_cg_loaded - 1];
+		for (j = sbi->s_cg_loaded - 1; j > 0; j--) {
+			sbi->s_cgno[j] = sbi->s_cgno[j-1];
+			sbi->s_ucpi[j] = sbi->s_ucpi[j-1];
 		}
-		sb->u.ufs_sb.s_ucpi[0] = ucpi;
+		sbi->s_ucpi[0] = ucpi;
 		ufs_read_cylinder (sb, cgno, 0);
 	}
 	UFSD(("EXIT\n"))
-	return sb->u.ufs_sb.s_ucpi[0];
+	return sbi->s_ucpi[0];
 }
diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Tue Aug 27 12:28:02 2002
+++ b/fs/ufs/dir.c	Tue Aug 27 12:28:02 2002
@@ -67,7 +67,7 @@
 	lock_kernel();
 
 	sb = inode->i_sb;
-	flags = sb->u.ufs_sb.s_flags;
+	flags = UFS_SB(sb)->s_flags;
 
 	UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
 
@@ -308,8 +308,8 @@
 		error_msg = "reclen is too small for namlen";
 	else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
 		error_msg = "directory entry across blocks";
-	else if (fs32_to_cpu(sb, de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg *
-				      sb->u.ufs_sb.s_uspi->s_ncg))
+	else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
+				      UFS_SB(sb)->s_uspi->s_ncg))
 		error_msg = "inode out of bounds";
 
 	if (error_msg != NULL)
@@ -386,7 +386,7 @@
 	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
 	
 	sb = dir->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 
 	if (!namelen)
 		return -EINVAL;
diff -Nru a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
--- a/fs/ufs/ialloc.c	Tue Aug 27 12:28:02 2002
+++ b/fs/ufs/ialloc.c	Tue Aug 27 12:28:02 2002
@@ -71,7 +71,7 @@
 	UFSD(("ENTER, ino %lu\n", inode->i_ino))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	
 	ino = inode->i_ino;
@@ -112,12 +112,12 @@
 			ucpi->c_irotor = ino;
 		fs32_add(sb, &ucg->cg_cs.cs_nifree, 1);
 		fs32_add(sb, &usb1->fs_cstotal.cs_nifree, 1);
-		fs32_add(sb, &sb->fs_cs(cg).cs_nifree, 1);
+		fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1);
 
 		if (is_directory) {
 			fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1);
 			fs32_sub(sb, &usb1->fs_cstotal.cs_ndir, 1);
-			fs32_sub(sb, &sb->fs_cs(cg).cs_ndir, 1);
+			fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1);
 		}
 	}
 
@@ -146,6 +146,7 @@
 struct inode * ufs_new_inode(struct inode * dir, int mode)
 {
 	struct super_block * sb;
+	struct ufs_sb_info * sbi;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_cg_private_info * ucpi;
@@ -164,7 +165,8 @@
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 	ufsi = UFS_I(inode);
-	uspi = sb->u.ufs_sb.s_uspi;
+	sbi = UFS_SB(sb);
+	uspi = sbi->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 
 	lock_super (sb);
@@ -173,7 +175,7 @@
 	 * Try to place the inode in its parent directory
 	 */
 	i = ufs_inotocg(dir->i_ino);
-	if (sb->fs_cs(i).cs_nifree) {
+	if (sbi->fs_cs(i).cs_nifree) {
 		cg = i;
 		goto cg_found;
 	}
@@ -185,7 +187,7 @@
 		i += j;
 		if (i >= uspi->s_ncg)
 			i -= uspi->s_ncg;
-		if (sb->fs_cs(i).cs_nifree) {
+		if (sbi->fs_cs(i).cs_nifree) {
 			cg = i;
 			goto cg_found;
 		}
@@ -199,7 +201,7 @@
 		i++;
 		if (i >= uspi->s_ncg)
 			i = 0;
-		if (sb->fs_cs(i).cs_nifree) {
+		if (sbi->fs_cs(i).cs_nifree) {
 			cg = i;
 			goto cg_found;
 		}
@@ -235,12 +237,12 @@
 	
 	fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1);
 	fs32_sub(sb, &usb1->fs_cstotal.cs_nifree, 1);
-	fs32_sub(sb, &sb->fs_cs(cg).cs_nifree, 1);
+	fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1);
 	
 	if (S_ISDIR(mode)) {
 		fs32_add(sb, &ucg->cg_cs.cs_ndir, 1);
 		fs32_add(sb, &usb1->fs_cstotal.cs_ndir, 1);
-		fs32_add(sb, &sb->fs_cs(cg).cs_ndir, 1);
+		fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1);
 	}
 
 	ubh_mark_buffer_dirty (USPI_UBH);
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Tue Aug 27 12:28:01 2002
+++ b/fs/ufs/inode.c	Tue Aug 27 12:28:01 2002
@@ -52,7 +52,7 @@
 
 static int ufs_block_to_path(struct inode *inode, long i_block, int offsets[4])
 {
-	struct ufs_sb_private_info *uspi = inode->i_sb->u.ufs_sb.s_uspi;
+	struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi;
 	int ptrs = uspi->s_apb;
 	int ptrs_bits = uspi->s_apbshift;
 	const long direct_blocks = UFS_NDADDR,
@@ -86,7 +86,7 @@
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block *sb = inode->i_sb;
-	struct ufs_sb_private_info *uspi = sb->u.ufs_sb.s_uspi;
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
 	int mask = uspi->s_apbmask>>uspi->s_fpbshift;
 	int shift = uspi->s_apbshift-uspi->s_fpbshift;
 	int offsets[4], *p;
@@ -137,7 +137,7 @@
 		inode->i_ino, fragment, new_fragment, required))         
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
 	p = ufsi->i_u1.i_data + block;
@@ -243,7 +243,7 @@
 	u32 * p;
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
 
@@ -313,7 +313,7 @@
 static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
 	struct super_block * sb = inode->i_sb;
-	struct ufs_sb_private_info * uspi = sb->u.ufs_sb.s_uspi;
+	struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
 	struct buffer_head * bh;
 	int ret, err, new;
 	unsigned long ptr, phys;
@@ -483,8 +483,8 @@
 	UFSD(("ENTER, ino %lu\n", inode->i_ino))
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
-	flags = sb->u.ufs_sb.s_flags;
+	uspi = UFS_SB(sb)->s_uspi;
+	flags = UFS_SB(sb)->s_flags;
 
 	if (inode->i_ino < UFS_ROOTINO || 
 	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
@@ -579,8 +579,8 @@
 	UFSD(("ENTER, ino %lu\n", inode->i_ino))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
-	flags = sb->u.ufs_sb.s_flags;
+	uspi = UFS_SB(sb)->s_uspi;
+	flags = UFS_SB(sb)->s_flags;
 
 	if (inode->i_ino < UFS_ROOTINO || 
 	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
diff -Nru a/fs/ufs/namei.c b/fs/ufs/namei.c
--- a/fs/ufs/namei.c	Tue Aug 27 12:28:08 2002
+++ b/fs/ufs/namei.c	Tue Aug 27 12:28:08 2002
@@ -139,7 +139,7 @@
 	if (IS_ERR(inode))
 		goto out;
 
-	if (l > sb->u.ufs_sb.s_uspi->s_maxsymlinklen) {
+	if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
 		/* slow symlink */
 		inode->i_op = &page_symlink_inode_operations;
 		inode->i_mapping->a_ops = &ufs_aops;
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Tue Aug 27 12:27:42 2002
+++ b/fs/ufs/super.c	Tue Aug 27 12:27:42 2002
@@ -189,7 +189,7 @@
 	struct ufs_super_block_first * usb1;
 	va_list args;
 
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
@@ -201,7 +201,7 @@
 	va_start (args, fmt);
 	vsprintf (error_buf, fmt, args);
 	va_end (args);
-	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_ONERROR) {
+	switch (UFS_SB(sb)->s_mount_opt & UFS_MOUNT_ONERROR) {
 	case UFS_MOUNT_ONERROR_PANIC:
 		panic ("UFS-fs panic (device %s): %s: %s\n", 
 			sb->s_id, function, error_buf);
@@ -221,7 +221,7 @@
 	struct ufs_super_block_first * usb1;
 	va_list args;
 	
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
@@ -317,6 +317,7 @@
  * Read on-disk structures associated with cylinder groups
  */
 int ufs_read_cylinder_structures (struct super_block * sb) {
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
@@ -324,7 +325,7 @@
 	
 	UFSD(("ENTER\n"))
 	
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = sbi->s_uspi;
 	
 	/*
 	 * Read cs structures from (usually) first data block
@@ -343,7 +344,7 @@
 		if (!ubh)
 			goto failed;
 		ubh_ubhcpymem (space, ubh, size);
-		sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+		sbi->s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
 		space += size;
 		ubh_brelse (ubh);
 		ubh = NULL;
@@ -353,41 +354,41 @@
 	 * Read cylinder group (we read only first fragment from block
 	 * at this time) and prepare internal data structures for cg caching.
 	 */
-	if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
+	if (!(sbi->s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
 		goto failed;
 	for (i = 0; i < uspi->s_ncg; i++) 
-		sb->u.ufs_sb.s_ucg[i] = NULL;
+		sbi->s_ucg[i] = NULL;
 	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
-		sb->u.ufs_sb.s_ucpi[i] = NULL;
-		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+		sbi->s_ucpi[i] = NULL;
+		sbi->s_cgno[i] = UFS_CGNO_EMPTY;
 	}
 	for (i = 0; i < uspi->s_ncg; i++) {
 		UFSD(("read cg %u\n", i))
-		if (!(sb->u.ufs_sb.s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
+		if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
 			goto failed;
-		if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
+		if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data))
 			goto failed;
 #ifdef UFS_SUPER_DEBUG_MORE
-		ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data);
+		ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data);
 #endif
 	}
 	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
-		if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+		if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
 			goto failed;
-		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+		sbi->s_cgno[i] = UFS_CGNO_EMPTY;
 	}
-	sb->u.ufs_sb.s_cg_loaded = 0;
+	sbi->s_cg_loaded = 0;
 	UFSD(("EXIT\n"))
 	return 1;
 
 failed:
 	if (base) kfree (base);
-	if (sb->u.ufs_sb.s_ucg) {
+	if (sbi->s_ucg) {
 		for (i = 0; i < uspi->s_ncg; i++)
-			if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
-		kfree (sb->u.ufs_sb.s_ucg);
+			if (sbi->s_ucg[i]) brelse (sbi->s_ucg[i]);
+		kfree (sbi->s_ucg);
 		for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
-			if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
+			if (sbi->s_ucpi[i]) kfree (sbi->s_ucpi[i]);
 	}
 	UFSD(("EXIT (FAILED)\n"))
 	return 0;
@@ -398,6 +399,7 @@
  * write them back to disk
  */
 void ufs_put_cylinder_structures (struct super_block * sb) {
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
@@ -405,11 +407,11 @@
 	
 	UFSD(("ENTER\n"))
 	
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = sbi->s_uspi;
 
 	size = uspi->s_cssize;
 	blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
-	base = space = (char*) sb->u.ufs_sb.s_csp[0];
+	base = space = (char*) sbi->s_csp[0];
 	for (i = 0; i < blks; i += uspi->s_fpb) {
 		size = uspi->s_bsize;
 		if (i + uspi->s_fpb > blks)
@@ -421,21 +423,22 @@
 		ubh_mark_buffer_dirty (ubh);
 		ubh_brelse (ubh);
 	}
-	for (i = 0; i < sb->u.ufs_sb.s_cg_loaded; i++) {
+	for (i = 0; i < sbi->s_cg_loaded; i++) {
 		ufs_put_cylinder (sb, i);
-		kfree (sb->u.ufs_sb.s_ucpi[i]);
+		kfree (sbi->s_ucpi[i]);
 	}
 	for (; i < UFS_MAX_GROUP_LOADED; i++) 
-		kfree (sb->u.ufs_sb.s_ucpi[i]);
+		kfree (sbi->s_ucpi[i]);
 	for (i = 0; i < uspi->s_ncg; i++) 
-		brelse (sb->u.ufs_sb.s_ucg[i]);
-	kfree (sb->u.ufs_sb.s_ucg);
+		brelse (sbi->s_ucg[i]);
+	kfree (sbi->s_ucg);
 	kfree (base);
 	UFSD(("EXIT\n"))
 }
 
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 {
+	struct ufs_sb_info * sbi;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_second * usb2;
@@ -451,6 +454,12 @@
 	
 	UFSD(("ENTER\n"))
 		
+	sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
+	if (!sbi)
+		goto failed_nomem;
+	sb->u.generic_sbp = sbi;
+	memset(sbi, 0, sizeof(struct ufs_sb_info));
+
 	UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
 	
 #ifndef CONFIG_UFS_FS_WRITE
@@ -464,22 +473,22 @@
 	 * Set default mount options
 	 * Parse mount options
 	 */
-	sb->u.ufs_sb.s_mount_opt = 0;
-	ufs_set_opt (sb->u.ufs_sb.s_mount_opt, ONERROR_LOCK);
-	if (!ufs_parse_options ((char *) data, &sb->u.ufs_sb.s_mount_opt)) {
+	sbi->s_mount_opt = 0;
+	ufs_set_opt (sbi->s_mount_opt, ONERROR_LOCK);
+	if (!ufs_parse_options ((char *) data, &sbi->s_mount_opt)) {
 		printk("wrong mount options\n");
 		goto failed;
 	}
-	if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
+	if (!(sbi->s_mount_opt & UFS_MOUNT_UFSTYPE)) {
 		printk("You didn't specify the type of your ufs filesystem\n\n"
 		"mount -t ufs -o ufstype="
 		"sun|sunx86|44bsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
 		">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
 		"default is ufstype=old\n");
-		ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
+		ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD);
 	}
 
-	sb->u.ufs_sb.s_uspi = uspi =
+	sbi->s_uspi = uspi =
 		kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
 	if (!uspi)
 		goto failed;
@@ -488,7 +497,7 @@
 	   this but as I don't know which I'll let those in the know loosen
 	   the rules */
 	   
-	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) {
+	switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
 	case UFS_MOUNT_UFSTYPE_44BSD:
 		UFSD(("ufstype=44bsd\n"))
 		uspi->s_fsize = block_size = 512;
@@ -596,7 +605,10 @@
 	}
 	
 again:	
-	sb_set_blocksize(sb, block_size);
+	if (sb_set_blocksize(sb, block_size)) {
+		printk(KERN_ERR "UFS: failed to set blocksize\n");
+		goto failed;
+	}
 
 	/*
 	 * read ufs super block from device
@@ -617,7 +629,7 @@
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
-			sb->u.ufs_sb.s_bytesex = BYTESEX_LE;
+			sbi->s_bytesex = BYTESEX_LE;
 			goto magic_found;
 	}
 	switch (__constant_be32_to_cpu(usb3->fs_magic)) {
@@ -625,13 +637,13 @@
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
-			sb->u.ufs_sb.s_bytesex = BYTESEX_BE;
+			sbi->s_bytesex = BYTESEX_BE;
 			goto magic_found;
 	}
 
-	if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) 
-	  || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) 
-	  || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) 
+	if ((((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) 
+	  || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) 
+	  || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) 
 	  && uspi->s_sbbase < 256) {
 		ubh_brelse_uspi(uspi);
 		ubh = NULL;
@@ -652,32 +664,32 @@
 	uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
 
 	if (uspi->s_fsize & (uspi->s_fsize - 1)) {
-		printk("ufs_read_super: fragment size %u is not a power of 2\n",
+		printk(KERN_ERR "ufs_read_super: fragment size %u is not a power of 2\n",
 			uspi->s_fsize);
 			goto failed;
 	}
 	if (uspi->s_fsize < 512) {
-		printk("ufs_read_super: fragment size %u is too small\n",
+		printk(KERN_ERR "ufs_read_super: fragment size %u is too small\n",
 			uspi->s_fsize);
 		goto failed;
 	}
 	if (uspi->s_fsize > 4096) {
-		printk("ufs_read_super: fragment size %u is too large\n",
+		printk(KERN_ERR "ufs_read_super: fragment size %u is too large\n",
 			uspi->s_fsize);
 		goto failed;
 	}
 	if (uspi->s_bsize & (uspi->s_bsize - 1)) {
-		printk("ufs_read_super: block size %u is not a power of 2\n",
+		printk(KERN_ERR "ufs_read_super: block size %u is not a power of 2\n",
 			uspi->s_bsize);
 		goto failed;
 	}
 	if (uspi->s_bsize < 4096) {
-		printk("ufs_read_super: block size %u is too small\n",
+		printk(KERN_ERR "ufs_read_super: block size %u is too small\n",
 			uspi->s_bsize);
 		goto failed;
 	}
 	if (uspi->s_bsize / uspi->s_fsize > 8) {
-		printk("ufs_read_super: too many fragments per block (%u)\n",
+		printk(KERN_ERR "ufs_read_super: too many fragments per block (%u)\n",
 			uspi->s_bsize / uspi->s_fsize);
 		goto failed;
 	}
@@ -801,12 +813,12 @@
 	uspi->s_bpf = uspi->s_fsize << 3;
 	uspi->s_bpfshift = uspi->s_fshift + 3;
 	uspi->s_bpfmask = uspi->s_bpf - 1;
-	if ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) ==
+	if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) ==
 	    UFS_MOUNT_UFSTYPE_44BSD)
 		uspi->s_maxsymlinklen =
 		    fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen);
 	
-	sb->u.ufs_sb.s_flags = flags;
+	sbi->s_flags = flags;
 
 	inode = iget(sb, UFS_ROOTINO);
 	if (!inode || is_bad_inode(inode))
@@ -831,8 +843,14 @@
 failed:
 	if (ubh) ubh_brelse_uspi (uspi);
 	if (uspi) kfree (uspi);
+	if (sbi) kfree(sbi);
+	sb->u.generic_sbp = NULL;
 	UFSD(("EXIT (FAILED)\n"))
 	return -EINVAL;
+
+failed_nomem:
+	UFSD(("EXIT (NOMEM)\n"))
+	return -ENOMEM;
 }
 
 void ufs_write_super (struct super_block * sb) {
@@ -844,8 +862,8 @@
 	lock_kernel();
 
 	UFSD(("ENTER\n"))
-	flags = sb->u.ufs_sb.s_flags;
-	uspi = sb->u.ufs_sb.s_uspi;
+	flags = UFS_SB(sb)->s_flags;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
 
@@ -864,17 +882,17 @@
 
 void ufs_put_super (struct super_block * sb)
 {
-	struct ufs_sb_private_info * uspi;
+	struct ufs_sb_info * sbi = UFS_SB(sb);
 		
 	UFSD(("ENTER\n"))
 
-	uspi = sb->u.ufs_sb.s_uspi;
-
 	if (!(sb->s_flags & MS_RDONLY))
 		ufs_put_cylinder_structures (sb);
 	
-	ubh_brelse_uspi (uspi);
-	kfree (sb->u.ufs_sb.s_uspi);
+	ubh_brelse_uspi (sbi->s_uspi);
+	kfree (sbi->s_uspi);
+	kfree (sbi);
+	sb->u.generic_sbp = NULL;
 	return;
 }
 
@@ -887,8 +905,8 @@
 	unsigned new_mount_opt, ufstype;
 	unsigned flags;
 	
-	uspi = sb->u.ufs_sb.s_uspi;
-	flags = sb->u.ufs_sb.s_flags;
+	uspi = UFS_SB(sb)->s_uspi;
+	flags = UFS_SB(sb)->s_flags;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
 	
@@ -896,7 +914,7 @@
 	 * Allow the "check" option to be passed as a remount option.
 	 * It is not possible to change ufstype option during remount
 	 */
-	ufstype = sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE;
+	ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE;
 	new_mount_opt = 0;
 	ufs_set_opt (new_mount_opt, ONERROR_LOCK);
 	if (!ufs_parse_options (data, &new_mount_opt))
@@ -910,7 +928,7 @@
 	}
 
 	if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
-		sb->u.ufs_sb.s_mount_opt = new_mount_opt;
+		UFS_SB(sb)->s_mount_opt = new_mount_opt;
 		return 0;
 	}
 	
@@ -950,7 +968,7 @@
 		sb->s_flags &= ~MS_RDONLY;
 #endif
 	}
-	sb->u.ufs_sb.s_mount_opt = new_mount_opt;
+	UFS_SB(sb)->s_mount_opt = new_mount_opt;
 	return 0;
 }
 
@@ -961,7 +979,7 @@
 
 	lock_kernel();
 
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
 	
 	buf->f_type = UFS_MAGIC;
diff -Nru a/fs/ufs/swab.h b/fs/ufs/swab.h
--- a/fs/ufs/swab.h	Tue Aug 27 12:28:08 2002
+++ b/fs/ufs/swab.h	Tue Aug 27 12:28:08 2002
@@ -25,7 +25,7 @@
 static __inline u64
 fs64_to_cpu(struct super_block *sbp, u64 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return le64_to_cpu(n);
 	else
 		return be64_to_cpu(n);
@@ -34,7 +34,7 @@
 static __inline u64
 cpu_to_fs64(struct super_block *sbp, u64 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return cpu_to_le64(n);
 	else
 		return cpu_to_be64(n);
@@ -43,7 +43,7 @@
 static __inline u32
 fs64_add(struct super_block *sbp, u32 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le64(le64_to_cpu(*n)+d);
 	else
 		return *n = cpu_to_be64(be64_to_cpu(*n)+d);
@@ -52,7 +52,7 @@
 static __inline u32
 fs64_sub(struct super_block *sbp, u32 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le64(le64_to_cpu(*n)-d);
 	else
 		return *n = cpu_to_be64(be64_to_cpu(*n)-d);
@@ -61,7 +61,7 @@
 static __inline u32
 fs32_to_cpu(struct super_block *sbp, u32 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return le32_to_cpu(n);
 	else
 		return be32_to_cpu(n);
@@ -70,7 +70,7 @@
 static __inline u32
 cpu_to_fs32(struct super_block *sbp, u32 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return cpu_to_le32(n);
 	else
 		return cpu_to_be32(n);
@@ -79,7 +79,7 @@
 static __inline u32
 fs32_add(struct super_block *sbp, u32 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le32(le32_to_cpu(*n)+d);
 	else
 		return *n = cpu_to_be32(be32_to_cpu(*n)+d);
@@ -88,7 +88,7 @@
 static __inline u32
 fs32_sub(struct super_block *sbp, u32 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le32(le32_to_cpu(*n)-d);
 	else
 		return *n = cpu_to_be32(be32_to_cpu(*n)-d);
@@ -97,7 +97,7 @@
 static __inline u16
 fs16_to_cpu(struct super_block *sbp, u16 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return le16_to_cpu(n);
 	else
 		return be16_to_cpu(n);
@@ -106,7 +106,7 @@
 static __inline u16
 cpu_to_fs16(struct super_block *sbp, u16 n)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return cpu_to_le16(n);
 	else
 		return cpu_to_be16(n);
@@ -115,7 +115,7 @@
 static __inline u16
 fs16_add(struct super_block *sbp, u16 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le16(le16_to_cpu(*n)+d);
 	else
 		return *n = cpu_to_be16(be16_to_cpu(*n)+d);
@@ -124,7 +124,7 @@
 static __inline u16
 fs16_sub(struct super_block *sbp, u16 *n, int d)
 {
-	if (sbp->u.ufs_sb.s_bytesex == BYTESEX_LE)
+	if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
 		return *n = cpu_to_le16(le16_to_cpu(*n)-d);
 	else
 		return *n = cpu_to_be16(be16_to_cpu(*n)-d);
diff -Nru a/fs/ufs/truncate.c b/fs/ufs/truncate.c
--- a/fs/ufs/truncate.c	Tue Aug 27 12:28:06 2002
+++ b/fs/ufs/truncate.c	Tue Aug 27 12:28:06 2002
@@ -82,7 +82,7 @@
 	UFSD(("ENTER\n"))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	
 	frag_to_free = 0;
 	free_count = 0;
@@ -212,7 +212,7 @@
 	UFSD(("ENTER\n"))
 		
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 
 	frag_to_free = 0;
 	free_count = 0;
@@ -306,7 +306,7 @@
 	UFSD(("ENTER\n"))
 	
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 
 	dindirect_block = (DIRECT_BLOCK > offset) 
 		? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0;
@@ -374,7 +374,7 @@
 	UFSD(("ENTER\n"))
 
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	retry = 0;
 	
 	tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
@@ -435,7 +435,7 @@
 	
 	UFSD(("ENTER\n"))
 	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
 		return;
diff -Nru a/fs/ufs/util.h b/fs/ufs/util.h
--- a/fs/ufs/util.h	Tue Aug 27 12:28:06 2002
+++ b/fs/ufs/util.h	Tue Aug 27 12:28:06 2002
@@ -31,7 +31,7 @@
 ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
 		 struct ufs_super_block_third *usb3)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_ST_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
 		return fs32_to_cpu(sb, usb3->fs_u2.fs_sun.fs_state);
 	case UFS_ST_SUNx86:
@@ -46,7 +46,7 @@
 ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
 		 struct ufs_super_block_third *usb3, s32 value)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_ST_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
 		usb3->fs_u2.fs_sun.fs_state = cpu_to_fs32(sb, value);
 		break;
@@ -63,7 +63,7 @@
 ufs_get_fs_npsect(struct super_block *sb, struct ufs_super_block_first *usb1,
 		  struct ufs_super_block_third *usb3)
 {
-	if ((sb->u.ufs_sb.s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
 		return fs32_to_cpu(sb, usb3->fs_u2.fs_sunx86.fs_npsect);
 	else
 		return fs32_to_cpu(sb, usb1->fs_u1.fs_sun.fs_npsect);
@@ -74,7 +74,7 @@
 {
 	u64 tmp;
 
-	switch (sb->u.ufs_sb.s_flags & UFS_ST_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
 		((u32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0];
 		((u32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1];
@@ -97,7 +97,7 @@
 {
 	u64 tmp;
 
-	switch (sb->u.ufs_sb.s_flags & UFS_ST_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
 		((u32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0];
 		((u32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1];
@@ -118,7 +118,7 @@
 static inline u16
 ufs_get_de_namlen(struct super_block *sb, struct ufs_dir_entry *de)
 {
-	if ((sb->u.ufs_sb.s_flags & UFS_DE_MASK) == UFS_DE_OLD)
+	if ((UFS_SB(sb)->s_flags & UFS_DE_MASK) == UFS_DE_OLD)
 		return fs16_to_cpu(sb, de->d_u.d_namlen);
 	else
 		return de->d_u.d_44.d_namlen; /* XXX this seems wrong */
@@ -127,7 +127,7 @@
 static inline void
 ufs_set_de_namlen(struct super_block *sb, struct ufs_dir_entry *de, u16 value)
 {
-	if ((sb->u.ufs_sb.s_flags & UFS_DE_MASK) == UFS_DE_OLD)
+	if ((UFS_SB(sb)->s_flags & UFS_DE_MASK) == UFS_DE_OLD)
 		de->d_u.d_namlen = cpu_to_fs16(sb, value);
 	else
 		de->d_u.d_44.d_namlen = value; /* XXX this seems wrong */
@@ -136,7 +136,7 @@
 static inline void
 ufs_set_de_type(struct super_block *sb, struct ufs_dir_entry *de, int mode)
 {
-	if ((sb->u.ufs_sb.s_flags & UFS_DE_MASK) != UFS_DE_44BSD)
+	if ((UFS_SB(sb)->s_flags & UFS_DE_MASK) != UFS_DE_44BSD)
 		return;
 
 	/*
@@ -172,7 +172,7 @@
 static inline u32
 ufs_get_inode_uid(struct super_block *sb, struct ufs_inode *inode)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_UID_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) {
 	case UFS_UID_EFT:
 		return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid);
 	case UFS_UID_44BSD:
@@ -185,7 +185,7 @@
 static inline void
 ufs_set_inode_uid(struct super_block *sb, struct ufs_inode *inode, u32 value)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_UID_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) {
 	case UFS_UID_EFT:
 		inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value);
 		break;
@@ -199,7 +199,7 @@
 static inline u32
 ufs_get_inode_gid(struct super_block *sb, struct ufs_inode *inode)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_UID_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) {
 	case UFS_UID_EFT:
 		return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid);
 	case UFS_UID_44BSD:
@@ -212,7 +212,7 @@
 static inline void
 ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value)
 {
-	switch (sb->u.ufs_sb.s_flags & UFS_UID_MASK) {
+	switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) {
 	case UFS_UID_EFT:
 		inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value);
 		break;
@@ -481,7 +481,7 @@
 	struct ufs_sb_private_info * uspi;
 	unsigned fragsize, pos;
 	
-	uspi = sb->u.ufs_sb.s_uspi;
+	uspi = UFS_SB(sb)->s_uspi;
 	
 	fragsize = 0;
 	for (pos = 0; pos < uspi->s_fpb; pos++) {
diff -Nru a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h
--- a/include/asm-alpha/keyboard.h	Tue Aug 27 12:27:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-/*
- *  linux/include/asm-alpha/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- */
-
-/*
- *  This file contains the alpha architecture specific keyboard definitions
- */
-
-#ifndef _ALPHA_KEYBOARD_H
-#define _ALPHA_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/io.h>
-
-#define KEYBOARD_IRQ                    1
-#define DISABLE_KBD_DURING_INTERRUPTS   0
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate		pckbd_sysrq_xlate
-
-#define INIT_KBD
-
-#define SYSRQ_KEY 0x54
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input() inb(KBD_DATA_REG)
-#define kbd_read_status() inb(KBD_STATUS_REG)
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-/* Jensen puts this at 9, everyone else at the standard 12.  */
-#define AUX_IRQ  (RTC_PORT(0) == 0x170 ? 9 : 12)
-
-#define aux_request_irq(hand, dev_id)                                  \
-       request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASMalpha_KEYBOARD_H */
diff -Nru a/include/asm-alpha/rtc.h b/include/asm-alpha/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-alpha/rtc.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,10 @@
+#ifndef _ALPHA_RTC_H
+#define _ALPHA_RTC_H
+
+/*
+ * Alpha uses the default access methods for the RTC.
+ */
+
+#include <asm-generic/rtc.h>
+
+#endif
diff -Nru a/include/asm-alpha/smplock.h b/include/asm-alpha/smplock.h
--- a/include/asm-alpha/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,56 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-static __inline__ void release_kernel_lock(struct task_struct *task)
-{
-	if (unlikely(task->lock_depth >= 0))
-		spin_unlock(&kernel_flag);
-}
-
-/*
- * Re-acquire the kernel lock
- */
-static __inline__ void reacquire_kernel_lock(struct task_struct *task)
-{
-	if (unlikely(task->lock_depth >= 0))
-		spin_lock(&kernel_flag);
-}
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void lock_kernel(void)
-{
-#ifdef CONFIG_PREEMPT
-	if (current->lock_depth == -1)
-		spin_lock(&kernel_flag);
-	++current->lock_depth;
-#else
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-#endif
-}
-
-static __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-arm/keyboard.h b/include/asm-arm/keyboard.h
--- a/include/asm-arm/keyboard.h	Tue Aug 27 12:28:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,72 +0,0 @@
-/*
- *  linux/include/asm-arm/keyboard.h
- *
- *  Copyright (C) 1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Keyboard driver definitions for ARM
- */
-#ifndef __ASM_ARM_KEYBOARD_H
-#define __ASM_ARM_KEYBOARD_H
-
-#include <linux/kd.h>
-#include <linux/pm.h>
-
-/*
- * We provide a unified keyboard interface when in VC_MEDIUMRAW
- * mode.  This means that all keycodes must be common between
- * all supported keyboards.  This unfortunately puts us at odds
- * with the PC keyboard interface chip... but we can't do anything
- * about that now.
- */
-#ifdef __KERNEL__
-
-extern int  (*k_setkeycode)(unsigned int, unsigned int);
-extern int  (*k_getkeycode)(unsigned int);
-extern int  (*k_translate)(unsigned char, unsigned char *, char);
-extern char (*k_unexpected_up)(unsigned char);
-extern void (*k_leds)(unsigned char);
-
-
-static inline int kbd_setkeycode(unsigned int sc, unsigned int kc)
-{
-	int ret = -EINVAL;
-
-	if (k_setkeycode)
-		ret = k_setkeycode(sc, kc);
-
-	return ret;
-}
-
-static inline int kbd_getkeycode(unsigned int sc)
-{
-	int ret = -EINVAL;
-
-	if (k_getkeycode)
-		ret = k_getkeycode(sc);
-
-	return ret;
-}
-
-static inline void kbd_leds(unsigned char leds)
-{
-	if (k_leds)
-		k_leds(leds);
-}
-
-extern int k_sysrq_key;
-extern unsigned char *k_sysrq_xlate;
-
-#define SYSRQ_KEY		k_sysrq_key
-#define kbd_sysrq_xlate		k_sysrq_xlate
-#define kbd_translate		k_translate
-#define kbd_unexpected_up	k_unexpected_up
-
-#include <asm/arch/keyboard.h>
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASM_ARM_KEYBOARD_H */
diff -Nru a/include/asm-arm/smplock.h b/include/asm-arm/smplock.h
--- a/include/asm-arm/smplock.h	Tue Aug 27 12:27:56 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,60 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_PREEMPT
-#define kernel_locked()		preempt_get_count()
-#else
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_unlock(&kernel_flag);	\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static inline void lock_kernel(void)
-{
-#ifdef CONFIG_PREEMPT
-	if (current->lock_depth == -1)
-		spin_lock(&kernel_flag);
-	++current->lock_depth;
-#else
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-#endif
-}
-
-static inline void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-cris/smplock.h b/include/asm-cris/smplock.h
--- a/include/asm-cris/smplock.h	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-#ifndef __ASM_CRIS_SMPLOCK_H
-#define __ASM_CRIS_SMPLOCK_H
-
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/config.h>
-
-#ifndef CONFIG_SMP
-
-#define lock_kernel()                           do { } while(0)
-#define unlock_kernel()                         do { } while(0)
-#define release_kernel_lock(task, cpu, depth)   ((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
-
-#else
-
-#error "We do not support SMP on CRIS"
-
-#endif
-
-#endif
diff -Nru a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
--- a/include/asm-generic/percpu.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-generic/percpu.h	Tue Aug 27 12:28:02 2002
@@ -1,13 +1,34 @@
 #ifndef _ASM_GENERIC_PERCPU_H_
 #define _ASM_GENERIC_PERCPU_H_
+#include <linux/compiler.h>
 
 #define __GENERIC_PER_CPU
-#include <linux/compiler.h>
+#ifdef CONFIG_SMP
 
 extern unsigned long __per_cpu_offset[NR_CPUS];
 
+/* Separate out the type, so (int[3], foo) works. */
+#ifndef MODULE
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".percpu"))) __typeof__(type) name##__per_cpu
+#endif
+
 /* var is in discarded region: offset to particular copy we want */
-#define per_cpu(var, cpu) (*RELOC_HIDE(&var, __per_cpu_offset[cpu]))
-#define this_cpu(var) per_cpu(var, smp_processor_id())
+#define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu]))
+#define __get_cpu_var(var) per_cpu(var, smp_processor_id())
+
+#else /* ! SMP */
+
+/* Can't define per-cpu variables in modules.  Sorry --RR */
+#ifndef MODULE
+#define DEFINE_PER_CPU(type, name) \
+    __typeof__(type) name##__per_cpu
+#endif
+
+#define per_cpu(var, cpu)			var##__per_cpu
+#define __get_cpu_var(var)			var##__per_cpu
+#endif
+
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu
 
 #endif /* _ASM_GENERIC_PERCPU_H_ */
diff -Nru a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-generic/rtc.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,211 @@
+/* 
+ * inclue/asm-generic/rtc.h
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * Based on:
+ * drivers/char/rtc.c
+ *
+ * Please read the COPYING file for all license details.
+ */
+
+#ifndef __ASM_RTC_H__
+#define __ASM_RTC_H__
+
+#ifdef __KERNEL__
+
+#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+extern void gen_rtc_interrupt(unsigned long);
+
+/* some dummy definitions */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+/*
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char rtc_is_updating(void)
+{
+	unsigned char uip;
+
+	spin_lock_irq(&rtc_lock);
+	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	spin_unlock_irq(&rtc_lock);
+	return uip;
+}
+
+static inline void get_rtc_time(struct rtc_time *time)
+{
+	unsigned long uip_watchdog = jiffies;
+	unsigned char ctrl;
+#ifdef CONFIG_DECSTATION
+	unsigned int real_year;
+#endif
+
+	/*
+	 * read RTC once any update in progress is done. The update
+	 * can take just over 2ms. We wait 10 to 20ms. There is no need to
+	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+	 * If you need to know *exactly* when a second has started, enable
+	 * periodic update complete interrupts, (via ioctl) and then 
+	 * immediately read /dev/rtc which will block until you get the IRQ.
+	 * Once the read clears, read the RTC time (again via ioctl). Easy.
+	 */
+
+	if (rtc_is_updating() != 0)
+		while (jiffies - uip_watchdog < 2*HZ/100) {
+			barrier();
+			cpu_relax();
+		}
+
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	spin_lock_irq(&rtc_lock);
+	time->tm_sec = CMOS_READ(RTC_SECONDS);
+	time->tm_min = CMOS_READ(RTC_MINUTES);
+	time->tm_hour = CMOS_READ(RTC_HOURS);
+	time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	time->tm_mon = CMOS_READ(RTC_MONTH);
+	time->tm_year = CMOS_READ(RTC_YEAR);
+#ifdef CONFIG_DECSTATION
+	real_year = CMOS_READ(RTC_DEC_YEAR);
+#endif
+	ctrl = CMOS_READ(RTC_CONTROL);
+	spin_unlock_irq(&rtc_lock);
+
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(time->tm_sec);
+		BCD_TO_BIN(time->tm_min);
+		BCD_TO_BIN(time->tm_hour);
+		BCD_TO_BIN(time->tm_mday);
+		BCD_TO_BIN(time->tm_mon);
+		BCD_TO_BIN(time->tm_year);
+	}
+
+#ifdef CONFIG_DECSTATION
+	time->tm_year += real_year - 72;
+#endif
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+	if (time->tm_year <= 69)
+		time->tm_year += 100;
+
+	time->tm_mon--;
+}
+
+/* Set the current date and time in the real time clock. */
+static inline int set_rtc_time(struct rtc_time *time)
+{
+	unsigned char mon, day, hrs, min, sec;
+	unsigned char save_control, save_freq_select;
+	unsigned int yrs;
+#ifdef CONFIG_DECSTATION
+	unsigned int real_yrs, leap_yr;
+#endif
+
+	yrs = time->tm_year;
+	mon = time->tm_mon + 1;   /* tm_mon starts at zero */
+	day = time->tm_mday;
+	hrs = time->tm_hour;
+	min = time->tm_min;
+	sec = time->tm_sec;
+
+	if (yrs > 255)	/* They are unsigned */
+		return -EINVAL;
+
+	spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_DECSTATION
+	real_yrs = yrs;
+	leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
+			!((yrs + 1900) % 400));
+	yrs = 72;
+
+	/*
+	 * We want to keep the year set to 73 until March
+	 * for non-leap years, so that Feb, 29th is handled
+	 * correctly.
+	 */
+	if (!leap_yr && mon < 3) {
+		real_yrs--;
+		yrs = 73;
+	}
+#endif
+	/* These limits and adjustments are independant of
+	 * whether the chip is in binary mode or not.
+	 */
+	if (yrs > 169) {
+		spin_unlock_irq(&rtc_lock);
+		return -EINVAL;
+	}
+
+	if (yrs >= 100)
+		yrs -= 100;
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+	    || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(mon);
+		BIN_TO_BCD(yrs);
+	}
+
+	save_control = CMOS_READ(RTC_CONTROL);
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+#ifdef CONFIG_DECSTATION
+	CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
+#endif
+	CMOS_WRITE(yrs, RTC_YEAR);
+	CMOS_WRITE(mon, RTC_MONTH);
+	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(hrs, RTC_HOURS);
+	CMOS_WRITE(min, RTC_MINUTES);
+	CMOS_WRITE(sec, RTC_SECONDS);
+
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	spin_unlock_irq(&rtc_lock);
+
+	return 0;
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	struct rtc_time h;
+
+	get_rtc_time(&h);
+	return h.tm_sec;
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_RTC_H__ */
diff -Nru a/include/asm-generic/smplock.h b/include/asm-generic/smplock.h
--- a/include/asm-generic/smplock.h	Tue Aug 27 12:27:57 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,50 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	local_irq_enable(); \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-i386/desc.h b/include/asm-i386/desc.h
--- a/include/asm-i386/desc.h	Tue Aug 27 12:27:40 2002
+++ b/include/asm-i386/desc.h	Tue Aug 27 12:27:42 2002
@@ -2,50 +2,12 @@
 #define __ARCH_DESC_H
 
 #include <asm/ldt.h>
-
-/*
- * The layout of the per-CPU GDT under Linux:
- *
- *   0 - null
- *   1 - Thread-Local Storage (TLS) segment
- *   2 - kernel code segment
- *   3 - kernel data segment
- *   4 - user code segment		<==== new cacheline
- *   5 - user data segment
- *   6 - TSS
- *   7 - LDT
- *   8 - APM BIOS support		<==== new cacheline
- *   9 - APM BIOS support
- *  10 - APM BIOS support
- *  11 - APM BIOS support
- *  12 - PNPBIOS support		<==== new cacheline
- *  13 - PNPBIOS support
- *  14 - PNPBIOS support
- *  15 - PNPBIOS support
- *  16 - PNPBIOS support		<==== new cacheline
- *  17 - not used
- *  18 - not used
- *  19 - not used
- */
-#define TLS_ENTRY 1
-#define TSS_ENTRY 6
-#define LDT_ENTRY 7
-/*
- * The interrupt descriptor table has room for 256 idt's,
- * the global descriptor table is dependent on the number
- * of tasks we can have..
- *
- * We pad the GDT to cacheline boundary.
- */
-#define IDT_ENTRIES 256
-#define GDT_ENTRIES 20
+#include <asm/segment.h>
 
 #ifndef __ASSEMBLY__
 
 #include <asm/mmu.h>
 
-#define GDT_SIZE (GDT_ENTRIES*sizeof(struct desc_struct))
-
 extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES];
 
 struct Xgt_desc_struct {
@@ -55,8 +17,8 @@
 
 extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
 
-#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (TSS_ENTRY<<3))
-#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (LDT_ENTRY<<3))
+#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
+#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
 
 /*
  * This is the ldt that every process will get unless we need
@@ -78,21 +40,48 @@
 
 static inline void set_tss_desc(unsigned int cpu, void *addr)
 {
-	_set_tssldt_desc(&cpu_gdt_table[cpu][TSS_ENTRY], (int)addr, 235, 0x89);
+	_set_tssldt_desc(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (int)addr, 235, 0x89);
 }
 
 static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
 {
-	_set_tssldt_desc(&cpu_gdt_table[cpu][LDT_ENTRY], (int)addr, ((size << 3)-1), 0x82);
+	_set_tssldt_desc(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82);
 }
 
-#define TLS_FLAGS_MASK			0x00000001
+#define LDT_entry_a(info) \
+	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
 
-#define TLS_FLAG_WRITABLE		0x00000001
+#define LDT_entry_b(info) \
+	(((info)->base_addr & 0xff000000) | \
+	(((info)->base_addr & 0x00ff0000) >> 16) | \
+	((info)->limit & 0xf0000) | \
+	(((info)->read_exec_only ^ 1) << 9) | \
+	((info)->contents << 10) | \
+	(((info)->seg_not_present ^ 1) << 15) | \
+	((info)->seg_32bit << 22) | \
+	((info)->limit_in_pages << 23) | \
+	((info)->useable << 20) | \
+	0x7000)
+
+#define LDT_empty(info) (\
+	(info)->base_addr	== 0	&& \
+	(info)->limit		== 0	&& \
+	(info)->contents	== 0	&& \
+	(info)->read_exec_only	== 1	&& \
+	(info)->seg_32bit	== 0	&& \
+	(info)->limit_in_pages	== 0	&& \
+	(info)->seg_not_present	== 1	&& \
+	(info)->useable		== 0	)
+
+#if TLS_SIZE != 24
+# error update this code.
+#endif
 
-static inline void load_TLS_desc(struct thread_struct *t, unsigned int cpu)
+static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
 {
-	cpu_gdt_table[cpu][TLS_ENTRY] = t->tls_desc;
+#define C(i) cpu_gdt_table[cpu][GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
+	C(0); C(1); C(2);
+#undef C
 }
 
 static inline void clear_LDT(void)
diff -Nru a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-i386/hardirq.h	Tue Aug 27 12:28:08 2002
@@ -77,8 +77,10 @@
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
+# define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()	(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 #define irq_exit()							\
diff -Nru a/include/asm-i386/ide.h b/include/asm-i386/ide.h
--- a/include/asm-i386/ide.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-i386/ide.h	Tue Aug 27 12:27:59 2002
@@ -72,10 +72,24 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw);
+		ide_register_hw(&hw, NULL);
 	}
 #endif
 }
+
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h
--- a/include/asm-i386/keyboard.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,72 +0,0 @@
-/*
- *  linux/include/asm-i386/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- */
-
-/*
- *  This file contains the i386 architecture specific keyboard definitions
- */
-
-#ifndef _I386_KEYBOARD_H
-#define _I386_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <linux/pm.h>
-#include <asm/io.h>
-
-#define KEYBOARD_IRQ			1
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *);
-extern pm_callback pm_kbd_request_override;
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate		pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input() inb(KBD_DATA_REG)
-#define kbd_read_status() inb(KBD_STATUS_REG)
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ 12
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-#endif /* _I386_KEYBOARD_H */
diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h
--- a/include/asm-i386/kmap_types.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-i386/kmap_types.h	Tue Aug 27 12:28:08 2002
@@ -19,7 +19,9 @@
 D(6)	KM_BIO_DST_IRQ,
 D(7)	KM_PTE0,
 D(8)	KM_PTE1,
-D(9)	KM_TYPE_NR
+D(9)	KM_IRQ0,
+D(10)	KM_IRQ1,
+D(11)	KM_TYPE_NR
 };
 
 #undef D
diff -Nru a/include/asm-i386/ldt.h b/include/asm-i386/ldt.h
--- a/include/asm-i386/ldt.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-i386/ldt.h	Tue Aug 27 12:28:02 2002
@@ -12,7 +12,7 @@
 #define LDT_ENTRY_SIZE	8
 
 #ifndef __ASSEMBLY__
-struct modify_ldt_ldt_s {
+struct user_desc {
 	unsigned int  entry_number;
 	unsigned long base_addr;
 	unsigned int  limit;
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Tue Aug 27 12:27:57 2002
+++ b/include/asm-i386/processor.h	Tue Aug 27 12:27:57 2002
@@ -22,6 +22,11 @@
 	unsigned long a,b;
 };
 
+#define desc_empty(desc) \
+		(!((desc)->a + (desc)->b))
+
+#define desc_equal(desc1, desc2) \
+		(((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -359,6 +364,8 @@
 };
 
 struct thread_struct {
+/* cached TLS descriptors. */
+	struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
 	unsigned long	esp0;
 	unsigned long	eip;
 	unsigned long	esp;
@@ -376,11 +383,10 @@
 	unsigned long		v86flags, v86mask, v86mode, saved_esp0;
 /* IO permissions */
 	unsigned long	*ts_io_bitmap;
-/* TLS cached descriptor */
-	struct desc_struct tls_desc;
 };
 
 #define INIT_THREAD  {						\
+	{ { 0, 0 } , },						\
 	0,							\
 	0, 0, 0, 0, 						\
 	{ [0 ... 7] = 0 },	/* debugging registers */	\
@@ -401,7 +407,7 @@
 	0,0,0,0, /* esp,ebp,esi,edi */				\
 	0,0,0,0,0,0, /* es,cs,ss */				\
 	0,0,0,0,0,0, /* ds,fs,gs */				\
-	LDT_ENTRY,0, /* ldt */					\
+	GDT_ENTRY_LDT,0, /* ldt */					\
 	0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */		\
 	{~0, } /* ioperm */					\
 }
diff -Nru a/include/asm-i386/rtc.h b/include/asm-i386/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/rtc.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,10 @@
+#ifndef _I386_RTC_H
+#define _I386_RTC_H
+
+/*
+ * x86 uses the default access methods for the RTC.
+ */
+
+#include <asm-generic/rtc.h>
+
+#endif
diff -Nru a/include/asm-i386/segment.h b/include/asm-i386/segment.h
--- a/include/asm-i386/segment.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-i386/segment.h	Tue Aug 27 12:28:02 2002
@@ -1,10 +1,79 @@
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
-#define __KERNEL_CS	0x10
-#define __KERNEL_DS	0x18
+/*
+ * The layout of the per-CPU GDT under Linux:
+ *
+ *   0 - null
+ *   1 - reserved
+ *   2 - reserved
+ *   3 - reserved
+ *
+ *   4 - default user CS		<==== new cacheline
+ *   5 - default user DS
+ *
+ *  ------- start of TLS (Thread-Local Storage) segments:
+ *
+ *   6 - TLS segment #1			[ glibc's TLS segment ]
+ *   7 - TLS segment #2			[ Wine's %fs Win32 segment ]
+ *   8 - TLS segment #3
+ *   9 - reserved
+ *  10 - reserved
+ *  11 - reserved
+ *
+ *  ------- start of kernel segments:
+ *
+ *  12 - kernel code segment		<==== new cacheline
+ *  13 - kernel data segment
+ *  14 - TSS
+ *  15 - LDT
+ *  16 - PNPBIOS support (16->32 gate)
+ *  17 - PNPBIOS support
+ *  18 - PNPBIOS support
+ *  19 - PNPBIOS support
+ *  20 - PNPBIOS support
+ *  21 - APM BIOS support
+ *  22 - APM BIOS support
+ *  23 - APM BIOS support 
+ */
+#define GDT_ENTRY_TLS_ENTRIES	3
+#define GDT_ENTRY_TLS_MIN	6
+#define GDT_ENTRY_TLS_MAX 	(GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
 
-#define __USER_CS	0x23
-#define __USER_DS	0x2B
+#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
+
+#define GDT_ENTRY_DEFAULT_USER_CS	4
+#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)
+
+#define GDT_ENTRY_DEFAULT_USER_DS	5
+#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)
+
+#define GDT_ENTRY_KERNEL_BASE	12
+
+#define GDT_ENTRY_KERNEL_CS		(GDT_ENTRY_KERNEL_BASE + 0)
+#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)
+
+#define GDT_ENTRY_KERNEL_DS		(GDT_ENTRY_KERNEL_BASE + 1)
+#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
+
+#define GDT_ENTRY_TSS			(GDT_ENTRY_KERNEL_BASE + 2)
+#define GDT_ENTRY_LDT			(GDT_ENTRY_KERNEL_BASE + 3)
+
+#define GDT_ENTRY_PNPBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 4)
+#define GDT_ENTRY_APMBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 9)
+
+/*
+ * The GDT has 21 entries but we pad it to cacheline boundary:
+ */
+#define GDT_ENTRIES 24
+
+#define GDT_SIZE (GDT_ENTRIES * 8)
+
+/*
+ * The interrupt descriptor table has room for 256 idt's,
+ * the global descriptor table is dependent on the number
+ * of tasks we can have..
+ */
+#define IDT_ENTRIES 256
 
 #endif
diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h
--- a/include/asm-i386/smp.h	Tue Aug 27 12:27:57 2002
+++ b/include/asm-i386/smp.h	Tue Aug 27 12:27:57 2002
@@ -7,7 +7,6 @@
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/ptrace.h>
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff -Nru a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h
--- a/include/asm-i386/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * i386 SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <asm/current.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_SMP
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-#else
-#ifdef CONFIG_PREEMPT
-#define kernel_locked()		preempt_count()
-#else
-#define kernel_locked()		1
-#endif
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_unlock(&kernel_flag);	\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void lock_kernel(void)
-{
-#ifdef CONFIG_PREEMPT
-	if (current->lock_depth == -1)
-		spin_lock(&kernel_flag);
-	++current->lock_depth;
-#else
-#if 1
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-#else
-	__asm__ __volatile__(
-		"incl %1\n\t"
-		"jne 9f"
-		spin_lock_string
-		"\n9:"
-		:"=m" (__dummy_lock(&kernel_flag)),
-		 "=m" (current->lock_depth));
-#endif
-#endif
-}
-
-static __inline__ void unlock_kernel(void)
-{
-	if (current->lock_depth < 0)
-		BUG();
-#if 1
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-#else
-	__asm__ __volatile__(
-		"decl %1\n\t"
-		"jns 9f\n\t"
-		spin_unlock_string
-		"\n9:"
-		:"=m" (__dummy_lock(&kernel_flag)),
-		 "=m" (current->lock_depth));
-#endif
-}
diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Tue Aug 27 12:28:07 2002
+++ b/include/asm-i386/unistd.h	Tue Aug 27 12:28:07 2002
@@ -248,6 +248,12 @@
 #define __NR_sched_setaffinity	241
 #define __NR_sched_getaffinity	242
 #define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -Nru a/include/asm-i386/user.h b/include/asm-i386/user.h
--- a/include/asm-i386/user.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-i386/user.h	Tue Aug 27 12:28:01 2002
@@ -2,7 +2,6 @@
 #define _I386_USER_H
 
 #include <asm/page.h>
-#include <linux/ptrace.h>
 /* Core file format: The core file is written in such a way that gdb
    can understand it and provide useful information to the user (under
    linux we use the 'trad-core' bfd).  There are quite a number of
diff -Nru a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
--- a/include/asm-ia64/acpi.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/acpi.h	Tue Aug 27 12:28:02 2002
@@ -30,11 +30,74 @@
 
 #ifdef __KERNEL__
 
-#define __acpi_map_table(phys_addr, size) __va(phys_addr)
+#define COMPILER_DEPENDENT_INT64	long
+#define COMPILER_DEPENDENT_UINT64	unsigned long
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* Asm macros */
+
+#define ACPI_ASM_MACROS
+#define BREAKPOINT3
+#define ACPI_DISABLE_IRQS() local_irq_disable()
+#define ACPI_ENABLE_IRQS()  local_irq_enable()
+#define ACPI_FLUSH_CPU_CACHE()
+
+#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+	__asm__ volatile ("1:  ld4      r29=%1\n"  \
+		";;\n"                  \
+		"mov    ar.ccv=r29\n"   \
+		"mov    r2=r29\n"       \
+		"shr.u  r30=r29,1\n"    \
+		"and    r29=-4,r29\n"   \
+		";;\n"                  \
+		"add    r29=2,r29\n"    \
+		"and    r30=1,r30\n"    \
+		";;\n"                  \
+		"add    r29=r29,r30\n"  \
+		";;\n"                  \
+		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		";;\n"                  \
+		"cmp.eq p6,p7=r2,r30\n" \
+		"(p7) br.dpnt.few 1b\n" \
+		"cmp.gt p8,p9=3,r29\n"  \
+		";;\n"                  \
+		"(p8) mov %0=-1\n"      \
+		"(p9) mov %0=r0\n"      \
+		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+	} while (0)
+
+#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+	__asm__ volatile ("1:  ld4      r29=%1\n" \
+		";;\n"                  \
+		"mov    ar.ccv=r29\n"   \
+		"mov    r2=r29\n"       \
+		"and    r29=-4,r29\n"   \
+		";;\n"                  \
+		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		";;\n"                  \
+		"cmp.eq p6,p7=r2,r30\n" \
+		"(p7) br.dpnt.few 1b\n" \
+		"and    %0=1,r2\n"      \
+		";;\n"                  \
+		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+	} while (0)
 
 const char *acpi_get_sysname (void);
 int acpi_boot_init (char *cdline);
-int acpi_find_rsdp (unsigned long *phys_addr);
 int acpi_request_vector (u32 int_type);
 int acpi_get_prt (struct pci_vector_struct **vectors, int *count);
 int acpi_get_interrupt_model(int *type);
diff -Nru a/include/asm-ia64/agp.h b/include/asm-ia64/agp.h
--- a/include/asm-ia64/agp.h	Tue Aug 27 12:27:40 2002
+++ b/include/asm-ia64/agp.h	Tue Aug 27 12:27:40 2002
@@ -1,11 +1,21 @@
-#ifndef AGP_H
-#define AGP_H 1
+#ifndef _ASM_IA64_AGP_H
+#define _ASM_IA64_AGP_H
 
-/* dummy for now */
+/*
+ * IA-64 specific AGP definitions.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
 
-#define map_page_into_agp(page) 
-#define unmap_page_from_agp(page) 
-#define flush_agp_mappings() 
-#define flush_agp_cache() mb()
+/*
+ * To avoid memory-attribute aliasing issues, we require that the AGPGART engine operate
+ * in coherent mode, which lets us map the AGP memory as normal (write-back) memory
+ * (unlike x86, where it gets mapped "write-coalescing").
+ */
+#define map_page_into_agp(page)		/* nothing */
+#define unmap_page_from_agp(page)	/* nothing */
+#define flush_agp_mappings()		/* nothing */
+#define flush_agp_cache()		mb()
 
-#endif
+#endif /* _ASM_IA64_AGP_H */
diff -Nru a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
--- a/include/asm-ia64/bitops.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ia64/bitops.h	Tue Aug 27 12:28:08 2002
@@ -326,7 +326,7 @@
 	return exp - 0xffff;
 }
 
-static int
+static inline int
 fls (int x)
 {
 	return ia64_fls((unsigned int) x);
diff -Nru a/include/asm-ia64/cacheflush.h b/include/asm-ia64/cacheflush.h
--- a/include/asm-ia64/cacheflush.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ia64/cacheflush.h	Tue Aug 27 12:28:01 2002
@@ -6,6 +6,8 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
+#include <linux/page-flags.h>
+
 #include <asm/bitops.h>
 #include <asm/page.h>
 
@@ -23,7 +25,7 @@
 
 #define flush_dcache_page(page)			\
 do {						\
-	clear_bit(PG_arch_1, &page->flags);	\
+	clear_bit(PG_arch_1, &(page)->flags);	\
 } while (0)
 
 extern void flush_icache_range (unsigned long start, unsigned long end);
diff -Nru a/include/asm-ia64/delay.h b/include/asm-ia64/delay.h
--- a/include/asm-ia64/delay.h	Tue Aug 27 12:27:51 2002
+++ b/include/asm-ia64/delay.h	Tue Aug 27 12:27:51 2002
@@ -53,7 +53,7 @@
 
 	__asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory");
 #ifdef CONFIG_ITANIUM
-	while (unlikely ((__s32) result == -1)
+	while (unlikely((__s32) result == -1))
 		__asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory");
 #endif
 	return result;
diff -Nru a/include/asm-ia64/dma.h b/include/asm-ia64/dma.h
--- a/include/asm-ia64/dma.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ia64/dma.h	Tue Aug 27 12:28:08 2002
@@ -2,8 +2,8 @@
 #define _ASM_IA64_DMA_H
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
@@ -17,5 +17,7 @@
 #else
 # define isa_dma_bridge_buggy 	(0)
 #endif
+
+#define free_dma(x)
 
 #endif /* _ASM_IA64_DMA_H */
diff -Nru a/include/asm-ia64/efi.h b/include/asm-ia64/efi.h
--- a/include/asm-ia64/efi.h	Tue Aug 27 12:28:06 2002
+++ b/include/asm-ia64/efi.h	Tue Aug 27 12:28:06 2002
@@ -190,6 +190,9 @@
 #define SAL_SYSTEM_TABLE_GUID    \
     EFI_GUID(  0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
 
+#define HCDP_TABLE_GUID	\
+    EFI_GUID(  0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 )
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
@@ -225,6 +228,7 @@
 	void *smbios;			/* SM BIOS table */
 	void *sal_systab;		/* SAL system table */
 	void *boot_info;		/* boot info table */
+	void *hcdp;			/* HCDP table */
 	efi_get_time_t *get_time;
 	efi_set_time_t *set_time;
 	efi_get_wakeup_time_t *get_wakeup_time;
diff -Nru a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h
--- a/include/asm-ia64/elf.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ia64/elf.h	Tue Aug 27 12:28:08 2002
@@ -2,7 +2,7 @@
 #define _ASM_IA64_ELF_H
 
 /*
- * ELF archtecture specific definitions.
+ * ELF-specific definitions.
  *
  * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
--- a/include/asm-ia64/hardirq.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/hardirq.h	Tue Aug 27 12:28:02 2002
@@ -17,89 +17,93 @@
  * No irq_cpustat_t for IA-64.  The data is held in the per-CPU data structure.
  */
 #define softirq_pending(cpu)		(cpu_data(cpu)->softirq_pending)
-#define ksoftirqd_task(cpu)		(cpu_data(cpu)->ksoftirqd)
-#define irq_count(cpu)			(cpu_data(cpu)->irq_stat.f.irq_count)
-#define bh_count(cpu)			(cpu_data(cpu)->irq_stat.f.bh_count)
 #define syscall_count(cpu)		/* unused on IA-64 */
+#define ksoftirqd_task(cpu)		(cpu_data(cpu)->ksoftirqd)
 #define nmi_count(cpu)			0
 
 #define local_softirq_pending()		(local_cpu_data->softirq_pending)
-#define local_ksoftirqd_task()		(local_cpu_data->ksoftirqd)
-#define really_local_irq_count()	(local_cpu_data->irq_stat.f.irq_count)	/* XXX fix me */
-#define really_local_bh_count()		(local_cpu_data->irq_stat.f.bh_count)	/* XXX fix me */
 #define local_syscall_count()		/* unused on IA-64 */
+#define local_ksoftirqd_task()		(local_cpu_data->ksoftirqd)
 #define local_nmi_count()		0
 
 /*
- * Are we in an interrupt context? Either doing bottom half or hardware interrupt
- * processing?
+ * We put the hardirq and softirq counter into the preemption counter. The bitmask has the
+ * following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-31 are the hardirq count (max # of hardirqs: 65536)
+ *
+ * - (bit 63 is the PREEMPT_ACTIVE flag---not currently implemented.)
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0xffff0000
  */
-#define in_interrupt()			(local_cpu_data->irq_stat.irq_and_bh_counts != 0)
-#define in_irq()			(local_cpu_data->irq_stat.f.irq_count != 0)
 
-#ifndef CONFIG_SMP
-# define local_hardirq_trylock()	(really_local_irq_count() == 0)
-# define local_hardirq_endlock()	do { } while (0)
+#define PREEMPT_BITS	8
+#define SOFTIRQ_BITS	8
+#define HARDIRQ_BITS	16
+
+#define PREEMPT_SHIFT	0
+#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+#define __MASK(x)	((1UL << (x))-1)
+
+#define PREEMPT_MASK	(__MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define HARDIRQ_MASK	(__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define SOFTIRQ_MASK	(__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+
+#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
+#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
 
-# define local_irq_enter(irq)		(really_local_irq_count()++)
-# define local_irq_exit(irq)		(really_local_irq_count()--)
+/*
+ * The hardirq mask has to be large enough to have space for potentially all IRQ sources
+ * in the system nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
 
-# define synchronize_irq()		barrier()
+/*
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context?
+ * Interrupt context?
+ */
+#define in_irq()		(hardirq_count())
+#define in_softirq()		(softirq_count())
+#define in_interrupt()		(irq_count())
+
+#define hardirq_trylock()	(!in_interrupt())
+#define hardirq_endlock()	do { } while (0)
+
+#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
+
+#if CONFIG_PREEMPT
+# error CONFIG_PREEMT currently not supported.
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
 
-#include <asm/atomic.h>
-#include <asm/smp.h>
-
-extern unsigned int global_irq_holder;
-extern volatile unsigned long global_irq_lock;
-
-static inline int
-irqs_running (void)
-{
-	int i;
-
-	for (i = 0; i < NR_CPUS; i++)
-		if (irq_count(i))
-			return 1;
-	return 0;
-}
-
-static inline void
-release_irqlock (int cpu)
-{
-	/* if we didn't own the irq lock, just ignore.. */
-	if (global_irq_holder == cpu) {
-		global_irq_holder = NO_PROC_ID;
-		smp_mb__before_clear_bit();	/* need barrier before releasing lock... */
-		clear_bit(0,&global_irq_lock);
-        }
-}
-
-static inline void
-local_irq_enter (int irq)
-{
-	really_local_irq_count()++;
-
-	while (test_bit(0,&global_irq_lock)) {
-		/* nothing */;
-	}
-}
-
-static inline void
-local_irq_exit (int irq)
-{
-	really_local_irq_count()--;
-}
-
-static inline int
-local_hardirq_trylock (void)
-{
-	return !really_local_irq_count() && !test_bit(0,&global_irq_lock);
-}
-
-#define local_hardirq_endlock()		do { } while (0)
-
-extern void synchronize_irq (void);
+#define irq_exit()								\
+do {										\
+		preempt_count() -= IRQ_EXIT_OFFSET;				\
+		if (!in_interrupt() && softirq_pending(smp_processor_id()))	\
+			do_softirq();						\
+		preempt_enable_no_resched();					\
+} while (0)
 
+#ifdef CONFIG_SMP
+  extern void synchronize_irq (unsigned int irq);
+#else
+# define synchronize_irq(irq)	barrier()
 #endif /* CONFIG_SMP */
+
 #endif /* _ASM_IA64_HARDIRQ_H */
diff -Nru a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
--- a/include/asm-ia64/hw_irq.h	Tue Aug 27 12:28:05 2002
+++ b/include/asm-ia64/hw_irq.h	Tue Aug 27 12:28:05 2002
@@ -2,10 +2,11 @@
 #define _ASM_IA64_HW_IRQ_H
 
 /*
- * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 
@@ -67,6 +68,8 @@
 
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)	isa_irq_to_vector_map[(x)]
+extern __u8 gsi_to_vector_map[255];
+#define gsi_to_vector(x)	gsi_to_vector_map[(x)]
 
 extern unsigned long ipi_base_addr;
 
diff -Nru a/include/asm-ia64/keyboard.h b/include/asm-ia64/keyboard.h
--- a/include/asm-ia64/keyboard.h	Tue Aug 27 12:28:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-#ifndef _ASM_IA64_KEYBOARD_H
-#define _ASM_IA64_KEYBOARD_H
-
-/*
- * This file contains the ia64 architecture specific keyboard definitions.
- *
- * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-# ifdef __KERNEL__
-
-#include <linux/irq.h>
-#include <linux/kd.h>
-
-#define KEYBOARD_IRQ			isa_irq_to_vector(1)
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_pretranslate	pckbd_pretranslate
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate		pckbd_sysrq_xlate
-
-#define INIT_KBD
-
-#define SYSRQ_KEY		0x54
-#define E1_PAUSE   119		/* PAUSE key */
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input()	inb(KBD_DATA_REG)
-#define kbd_read_status()	inb(KBD_STATUS_REG)
-#define kbd_write_output(val)	outb(val, KBD_DATA_REG)
-#define kbd_write_command(val)	outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ				isa_irq_to_vector(12)
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-# endif /* __KERNEL__ */
-#endif /* _ASM_IA64_KEYBOARD_H */
diff -Nru a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
--- a/include/asm-ia64/kregs.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ia64/kregs.h	Tue Aug 27 12:28:01 2002
@@ -64,6 +64,15 @@
 #define IA64_PSR_RI_BIT		41
 #define IA64_PSR_ED_BIT		43
 #define IA64_PSR_BN_BIT		44
+#define IA64_PSR_IA_BIT		45
+
+/* A mask of PSR bits that we generally don't want to inherit across a clone2() or an
+   execve().  Only list flags here that need to be cleared/set for BOTH clone2() and
+   execve().  */
+#define IA64_PSR_BITS_TO_CLEAR	(IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \
+				 IA64_PSR_TB  | IA64_PSR_ID  | IA64_PSR_DA | IA64_PSR_DD | \
+				 IA64_PSR_SS  | IA64_PSR_ED  | IA64_PSR_IA)
+#define IA64_PSR_BITS_TO_SET	(IA64_PSR_DFH)
 
 #define IA64_PSR_BE	(__IA64_UL(1) << IA64_PSR_BE_BIT)
 #define IA64_PSR_UP	(__IA64_UL(1) << IA64_PSR_UP_BIT)
@@ -85,6 +94,7 @@
 #define IA64_PSR_TB	(__IA64_UL(1) << IA64_PSR_TB_BIT)
 #define IA64_PSR_RT	(__IA64_UL(1) << IA64_PSR_RT_BIT)
 /* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_CPL	(__IA64_UL(3) << IA64_PSR_CPL0_BIT)
 #define IA64_PSR_IS	(__IA64_UL(1) << IA64_PSR_IS_BIT)
 #define IA64_PSR_MC	(__IA64_UL(1) << IA64_PSR_MC_BIT)
 #define IA64_PSR_IT	(__IA64_UL(1) << IA64_PSR_IT_BIT)
@@ -95,6 +105,7 @@
 #define IA64_PSR_RI	(__IA64_UL(3) << IA64_PSR_RI_BIT)
 #define IA64_PSR_ED	(__IA64_UL(1) << IA64_PSR_ED_BIT)
 #define IA64_PSR_BN	(__IA64_UL(1) << IA64_PSR_BN_BIT)
+#define IA64_PSR_IA	(__IA64_UL(1) << IA64_PSR_IA_BIT)
 
 /* User mask bits: */
 #define IA64_PSR_UM	(IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH)
diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
--- a/include/asm-ia64/machvec.h	Tue Aug 27 12:27:45 2002
+++ b/include/asm-ia64/machvec.h	Tue Aug 27 12:27:45 2002
@@ -210,6 +210,7 @@
 extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
 extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
 extern ia64_mv_pci_dma_address swiotlb_dma_address;
+extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
 
 /*
  * Define default versions so we can extend machvec for new platforms without having
diff -Nru a/include/asm-ia64/machvec_init.h b/include/asm-ia64/machvec_init.h
--- a/include/asm-ia64/machvec_init.h	Tue Aug 27 12:27:56 2002
+++ b/include/asm-ia64/machvec_init.h	Tue Aug 27 12:27:56 2002
@@ -16,6 +16,7 @@
 extern ia64_mv_outb_t __ia64_outb;
 extern ia64_mv_outw_t __ia64_outw;
 extern ia64_mv_outl_t __ia64_outl;
+extern ia64_mv_mmiob_t __ia64_mmiob;
 
 #define MACHVEC_HELPER(name)									\
  struct ia64_machine_vector machvec_##name __attribute__ ((unused, __section__ (".machvec")))	\
diff -Nru a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
--- a/include/asm-ia64/mmu_context.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-ia64/mmu_context.h	Tue Aug 27 12:27:59 2002
@@ -2,8 +2,8 @@
 #define _ASM_IA64_MMU_CONTEXT_H
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 /*
@@ -13,8 +13,6 @@
  * consider the region number when performing a TLB lookup, we need to assign a unique
  * region id to each region in a process.  We use the least significant three bits in a
  * region id for this purpose.
- *
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #define IA64_REGION_ID_KERNEL	0 /* the kernel's region id (tlb.c depends on this being 0) */
@@ -23,6 +21,8 @@
 
 # ifndef __ASSEMBLY__
 
+#include <linux/compiler.h>
+#include <linux/percpu.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 
@@ -36,6 +36,7 @@
 };
 
 extern struct ia64_ctx ia64_ctx;
+extern u8 ia64_need_tlb_flush __per_cpu_data;
 
 extern void wrap_mmu_context (struct mm_struct *mm);
 
@@ -44,6 +45,23 @@
 {
 }
 
+/*
+ * When the context counter wraps around all TLBs need to be flushed because an old
+ * context number might have been reused. This is signalled by the ia64_need_tlb_flush
+ * per-CPU variable, which is checked in the routine below. Called by activate_mm().
+ * <efocht@ess.nec.de>
+ */
+static inline void
+delayed_tlb_flush (void)
+{
+	extern void __flush_tlb_all (void);
+
+	if (unlikely(ia64_need_tlb_flush)) {
+		__flush_tlb_all();
+		ia64_need_tlb_flush = 0;
+	}
+}
+
 static inline void
 get_new_mmu_context (struct mm_struct *mm)
 {
@@ -54,7 +72,6 @@
 		mm->context = ia64_ctx.next++;
 	}
 	spin_unlock(&ia64_ctx.lock);
-
 }
 
 static inline void
@@ -109,6 +126,8 @@
 static inline void
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
+	delayed_tlb_flush();
+
 	/*
 	 * We may get interrupts here, but that's OK because interrupt
 	 * handlers cannot touch user-space.
diff -Nru a/include/asm-ia64/module.h b/include/asm-ia64/module.h
--- a/include/asm-ia64/module.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/module.h	Tue Aug 27 12:28:02 2002
@@ -75,7 +75,7 @@
 		return 1;
 	}
 	if (!mod_bound(archdata->segment_base, 0, mod)) {
-		printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->segment_base out of bounds.\n");
 		return 1;
 	}
 
diff -Nru a/include/asm-ia64/offsets.h b/include/asm-ia64/offsets.h
--- a/include/asm-ia64/offsets.h	Tue Aug 27 12:28:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-#ifndef _ASM_IA64_OFFSETS_H
-#define _ASM_IA64_OFFSETS_H
-/*
- * DO NOT MODIFY
- *
- * This file was generated by arch/ia64/tools/print_offsets.awk.
- *
- */
-#define IA64_TASK_SIZE			3952	/* 0xf70 */
-#define IA64_THREAD_INFO_SIZE		32	/* 0x20 */
-#define IA64_PT_REGS_SIZE		400	/* 0x190 */
-#define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
-#define IA64_SIGINFO_SIZE		128	/* 0x80 */
-#define IA64_CPU_SIZE			224	/* 0xe0 */
-#define SIGFRAME_SIZE			2816	/* 0xb00 */
-#define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
-
-#define IA64_TASK_THREAD_KSP_OFFSET	1496	/* 0x5d8 */
-#define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
-#define IA64_PT_REGS_CR_IIP_OFFSET	8	/* 0x8 */
-#define IA64_PT_REGS_CR_IFS_OFFSET	16	/* 0x10 */
-#define IA64_PT_REGS_AR_UNAT_OFFSET	24	/* 0x18 */
-#define IA64_PT_REGS_AR_PFS_OFFSET	32	/* 0x20 */
-#define IA64_PT_REGS_AR_RSC_OFFSET	40	/* 0x28 */
-#define IA64_PT_REGS_AR_RNAT_OFFSET	48	/* 0x30 */
-#define IA64_PT_REGS_AR_BSPSTORE_OFFSET	56	/* 0x38 */
-#define IA64_PT_REGS_PR_OFFSET		64	/* 0x40 */
-#define IA64_PT_REGS_B6_OFFSET		72	/* 0x48 */
-#define IA64_PT_REGS_LOADRS_OFFSET	80	/* 0x50 */
-#define IA64_PT_REGS_R1_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_R2_OFFSET		96	/* 0x60 */
-#define IA64_PT_REGS_R3_OFFSET		104	/* 0x68 */
-#define IA64_PT_REGS_R12_OFFSET		112	/* 0x70 */
-#define IA64_PT_REGS_R13_OFFSET		120	/* 0x78 */
-#define IA64_PT_REGS_R14_OFFSET		128	/* 0x80 */
-#define IA64_PT_REGS_R15_OFFSET		136	/* 0x88 */
-#define IA64_PT_REGS_R8_OFFSET		144	/* 0x90 */
-#define IA64_PT_REGS_R9_OFFSET		152	/* 0x98 */
-#define IA64_PT_REGS_R10_OFFSET		160	/* 0xa0 */
-#define IA64_PT_REGS_R11_OFFSET		168	/* 0xa8 */
-#define IA64_PT_REGS_R16_OFFSET		176	/* 0xb0 */
-#define IA64_PT_REGS_R17_OFFSET		184	/* 0xb8 */
-#define IA64_PT_REGS_R18_OFFSET		192	/* 0xc0 */
-#define IA64_PT_REGS_R19_OFFSET		200	/* 0xc8 */
-#define IA64_PT_REGS_R20_OFFSET		208	/* 0xd0 */
-#define IA64_PT_REGS_R21_OFFSET		216	/* 0xd8 */
-#define IA64_PT_REGS_R22_OFFSET		224	/* 0xe0 */
-#define IA64_PT_REGS_R23_OFFSET		232	/* 0xe8 */
-#define IA64_PT_REGS_R24_OFFSET		240	/* 0xf0 */
-#define IA64_PT_REGS_R25_OFFSET		248	/* 0xf8 */
-#define IA64_PT_REGS_R26_OFFSET		256	/* 0x100 */
-#define IA64_PT_REGS_R27_OFFSET		264	/* 0x108 */
-#define IA64_PT_REGS_R28_OFFSET		272	/* 0x110 */
-#define IA64_PT_REGS_R29_OFFSET		280	/* 0x118 */
-#define IA64_PT_REGS_R30_OFFSET		288	/* 0x120 */
-#define IA64_PT_REGS_R31_OFFSET		296	/* 0x128 */
-#define IA64_PT_REGS_AR_CCV_OFFSET	304	/* 0x130 */
-#define IA64_PT_REGS_AR_FPSR_OFFSET	312	/* 0x138 */
-#define IA64_PT_REGS_B0_OFFSET		320	/* 0x140 */
-#define IA64_PT_REGS_B7_OFFSET		328	/* 0x148 */
-#define IA64_PT_REGS_F6_OFFSET		336	/* 0x150 */
-#define IA64_PT_REGS_F7_OFFSET		352	/* 0x160 */
-#define IA64_PT_REGS_F8_OFFSET		368	/* 0x170 */
-#define IA64_PT_REGS_F9_OFFSET		384	/* 0x180 */
-#define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0	/* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8	/* 0x8 */
-#define IA64_SWITCH_STACK_F2_OFFSET	16	/* 0x10 */
-#define IA64_SWITCH_STACK_F3_OFFSET	32	/* 0x20 */
-#define IA64_SWITCH_STACK_F4_OFFSET	48	/* 0x30 */
-#define IA64_SWITCH_STACK_F5_OFFSET	64	/* 0x40 */
-#define IA64_SWITCH_STACK_F10_OFFSET	80	/* 0x50 */
-#define IA64_SWITCH_STACK_F11_OFFSET	96	/* 0x60 */
-#define IA64_SWITCH_STACK_F12_OFFSET	112	/* 0x70 */
-#define IA64_SWITCH_STACK_F13_OFFSET	128	/* 0x80 */
-#define IA64_SWITCH_STACK_F14_OFFSET	144	/* 0x90 */
-#define IA64_SWITCH_STACK_F15_OFFSET	160	/* 0xa0 */
-#define IA64_SWITCH_STACK_F16_OFFSET	176	/* 0xb0 */
-#define IA64_SWITCH_STACK_F17_OFFSET	192	/* 0xc0 */
-#define IA64_SWITCH_STACK_F18_OFFSET	208	/* 0xd0 */
-#define IA64_SWITCH_STACK_F19_OFFSET	224	/* 0xe0 */
-#define IA64_SWITCH_STACK_F20_OFFSET	240	/* 0xf0 */
-#define IA64_SWITCH_STACK_F21_OFFSET	256	/* 0x100 */
-#define IA64_SWITCH_STACK_F22_OFFSET	272	/* 0x110 */
-#define IA64_SWITCH_STACK_F23_OFFSET	288	/* 0x120 */
-#define IA64_SWITCH_STACK_F24_OFFSET	304	/* 0x130 */
-#define IA64_SWITCH_STACK_F25_OFFSET	320	/* 0x140 */
-#define IA64_SWITCH_STACK_F26_OFFSET	336	/* 0x150 */
-#define IA64_SWITCH_STACK_F27_OFFSET	352	/* 0x160 */
-#define IA64_SWITCH_STACK_F28_OFFSET	368	/* 0x170 */
-#define IA64_SWITCH_STACK_F29_OFFSET	384	/* 0x180 */
-#define IA64_SWITCH_STACK_F30_OFFSET	400	/* 0x190 */
-#define IA64_SWITCH_STACK_F31_OFFSET	416	/* 0x1a0 */
-#define IA64_SWITCH_STACK_R4_OFFSET	432	/* 0x1b0 */
-#define IA64_SWITCH_STACK_R5_OFFSET	440	/* 0x1b8 */
-#define IA64_SWITCH_STACK_R6_OFFSET	448	/* 0x1c0 */
-#define IA64_SWITCH_STACK_R7_OFFSET	456	/* 0x1c8 */
-#define IA64_SWITCH_STACK_B0_OFFSET	464	/* 0x1d0 */
-#define IA64_SWITCH_STACK_B1_OFFSET	472	/* 0x1d8 */
-#define IA64_SWITCH_STACK_B2_OFFSET	480	/* 0x1e0 */
-#define IA64_SWITCH_STACK_B3_OFFSET	488	/* 0x1e8 */
-#define IA64_SWITCH_STACK_B4_OFFSET	496	/* 0x1f0 */
-#define IA64_SWITCH_STACK_B5_OFFSET	504	/* 0x1f8 */
-#define IA64_SWITCH_STACK_AR_PFS_OFFSET	512	/* 0x200 */
-#define IA64_SWITCH_STACK_AR_LC_OFFSET	520	/* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528	/* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
-#define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
-#define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
-#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
-#define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
-#define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
-#define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
-#define IA64_SIGCONTEXT_AR_UNAT_OFFSET	96	/* 0x60 */
-#define IA64_SIGCONTEXT_B0_OFFSET	136	/* 0x88 */
-#define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
-#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
-#define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
-#define IA64_SIGCONTEXT_PR_OFFSET	128	/* 0x80 */
-#define IA64_SIGCONTEXT_R12_OFFSET	296	/* 0x128 */
-#define IA64_SIGCONTEXT_RBS_BASE_OFFSET	2512	/* 0x9d0 */
-#define IA64_SIGCONTEXT_LOADRS_OFFSET	2520	/* 0x9d8 */
-#define IA64_SIGFRAME_ARG0_OFFSET	0	/* 0x0 */
-#define IA64_SIGFRAME_ARG1_OFFSET	8	/* 0x8 */
-#define IA64_SIGFRAME_ARG2_OFFSET	16	/* 0x10 */
-#define IA64_SIGFRAME_HANDLER_OFFSET	24	/* 0x18 */
-#define IA64_SIGFRAME_SIGCONTEXT_OFFSET	160	/* 0xa0 */
-#define IA64_CLONE_VFORK		16384	/* 0x4000 */
-#define IA64_CLONE_VM			256	/* 0x100 */
-
-#endif /* _ASM_IA64_OFFSETS_H */
diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ia64/page.h	Tue Aug 27 12:28:01 2002
@@ -87,7 +87,12 @@
 #define REGION_SIZE		REGION_NUMBER(1)
 #define REGION_KERNEL		7
 
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
+#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+# define ia64_abort()	__builtin_trap()
+#else
+# define ia64_abort()	(*(volatile int *) 0 = 0)
+#endif
+#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
 static __inline__ int
diff -Nru a/include/asm-ia64/param.h b/include/asm-ia64/param.h
--- a/include/asm-ia64/param.h	Tue Aug 27 12:28:06 2002
+++ b/include/asm-ia64/param.h	Tue Aug 27 12:28:06 2002
@@ -4,8 +4,8 @@
 /*
  * Fundamental kernel parameters.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
@@ -33,6 +33,7 @@
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
 
 #ifdef __KERNEL__
+# define USER_HZ	HZ
 # define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
 #endif
 
diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ia64/pci.h	Tue Aug 27 12:28:08 2002
@@ -21,7 +21,7 @@
 #define PCIBIOS_MIN_MEM		0x10000000
 
 void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int seg, int bus);
+struct pci_bus * pcibios_scan_root(int bus);
 extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
 extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
 
@@ -90,7 +90,7 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
-#define sg_dma_len(sg)		((sg)->length)
+#define sg_dma_len(sg)		((sg)->dma_length)
 
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
--- a/include/asm-ia64/percpu.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ia64/percpu.h	Tue Aug 27 12:28:01 2002
@@ -8,7 +8,7 @@
 
 #ifdef __ASSEMBLY__
 
-#define THIS_CPU(var)	(var)	/* use this to mark accesses to per-CPU variables... */
+#define THIS_CPU(var)	(var##__per_cpu)	/* use this to mark accesses to per-CPU variables... */
 
 #else /* !__ASSEMBLY__ */
 
@@ -16,8 +16,14 @@
 
 extern unsigned long __per_cpu_offset[NR_CPUS];
 
-#define per_cpu(var, cpu)	(*(__typeof__(&(var))) ((void *) &(var) + __per_cpu_offset[cpu]))
-#define this_cpu(var)		(var)
+#ifndef MODULE
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".data.percpu"))) __typeof__(type) name##__per_cpu
+#endif
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu
+
+#define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu]))
+#define __get_cpu_var(var)	(var##__per_cpu)
 
 #endif /* !__ASSEMBLY__ */
 
diff -Nru a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h
--- a/include/asm-ia64/perfmon.h	Tue Aug 27 12:28:07 2002
+++ b/include/asm-ia64/perfmon.h	Tue Aug 27 12:28:07 2002
@@ -172,9 +172,8 @@
 extern int  pfm_release_debug_registers(struct task_struct *);
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
 extern void pfm_syst_wide_update_task(struct task_struct *, int);
-extern void pfm_ovfl_block_reset (void);
-
-extern int pfm_syst_wide;
+extern void pfm_ovfl_block_reset(void);
+extern void perfmon_init_percpu(void);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
--- a/include/asm-ia64/pgalloc.h	Tue Aug 27 12:27:54 2002
+++ b/include/asm-ia64/pgalloc.h	Tue Aug 27 12:27:54 2002
@@ -15,9 +15,10 @@
 
 #include <linux/config.h>
 
+#include <linux/compiler.h>
 #include <linux/mm.h>
+#include <linux/page-flags.h>
 #include <linux/threads.h>
-#include <linux/compiler.h>
 
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/processor.h	Tue Aug 27 12:28:02 2002
@@ -134,7 +134,7 @@
  * CPU type, hardware bug flags, and per-CPU state.  Frequently used
  * state comes earlier:
  */
-extern struct cpuinfo_ia64 {
+struct cpuinfo_ia64 {
 	/* irq_stat must be 64-bit aligned */
 	union {
 		struct {
@@ -175,13 +175,15 @@
 	__u64 prof_counter;
 	__u64 prof_multiplier;
 #endif
-} cpu_info __per_cpu_data;
+};
+
+DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info);
 
 /*
  * The "local" data pointer.  It points to the per-CPU data of the currently executing
  * CPU, much like "current" points to the per-task data of the currently executing task.
  */
-#define local_cpu_data		(&this_cpu(cpu_info))
+#define local_cpu_data		(&__get_cpu_var(cpu_info))
 #define cpu_data(cpu)		(&per_cpu(cpu_info, cpu))
 
 extern void identify_cpu (struct cpuinfo_ia64 *);
@@ -223,6 +225,7 @@
 	__u64 map_base;			/* base address for get_unmapped_area() */
 	__u64 task_size;		/* limit for task size */
 	struct siginfo *siginfo;	/* current siginfo struct for ptrace() */
+	int last_fph_cpu;		/* CPU that may hold the contents of f32-f127 */
 
 #ifdef CONFIG_IA32_SUPPORT
 	__u64 eflag;			/* IA32 EFLAGS reg */
@@ -270,12 +273,8 @@
 
 #define start_thread(regs,new_ip,new_sp) do {							\
 	set_fs(USER_DS);									\
-	ia64_psr(regs)->dfh = 1;	/* disable fph */					\
-	ia64_psr(regs)->mfh = 0;	/* clear mfh */						\
-	ia64_psr(regs)->cpl = 3;	/* set user mode */					\
-	ia64_psr(regs)->ri = 0;		/* clear return slot number */				\
-	ia64_psr(regs)->is = 0;		/* IA-64 instruction set */				\
-	ia64_psr(regs)->sp = 1;		/* enforce secure perfmon */				\
+	regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP))	\
+			 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));		\
 	regs->cr_iip = new_ip;									\
 	regs->ar_rsc = 0xf;		/* eager mode, privilege level 3 */			\
 	regs->ar_rnat = 0;									\
@@ -284,7 +283,7 @@
 	regs->loadrs = 0;									\
 	regs->r8 = current->mm->dumpable;	/* set "don't zap registers" flag */		\
 	regs->r12 = new_sp - 16;	/* allocate 16 byte scratch area */			\
-	if (!likely (current->mm->dumpable)) {					\
+	if (unlikely(!current->mm->dumpable)) {					\
 		/*										\
 		 * Zap scratch regs to avoid leaking bits between processes with different	\
 		 * uid/privileges.								\
@@ -393,8 +392,6 @@
 	}
 }
 
-#ifndef CONFIG_SMP
-
 static inline struct task_struct *
 ia64_get_fpu_owner (void)
 {
@@ -406,8 +403,6 @@
 {
 	ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t);
 }
-
-#endif /* !CONFIG_SMP */
 
 extern void __ia64_init_fpu (void);
 extern void __ia64_save_fpu (struct ia64_fpreg *fph);
diff -Nru a/include/asm-ia64/rmap.h b/include/asm-ia64/rmap.h
--- a/include/asm-ia64/rmap.h	Tue Aug 27 12:28:05 2002
+++ b/include/asm-ia64/rmap.h	Tue Aug 27 12:28:05 2002
@@ -1,7 +1,7 @@
-#ifndef _IA64_RMAP_H
-#define _IA64_RMAP_H
+#ifndef _ASM_IA64_RMAP_H
+#define _ASM_IA64_RMAP_H
 
 /* nothing to see, move along */
 #include <asm-generic/rmap.h>
 
-#endif
+#endif /* _ASM_IA64_RMAP_H */
diff -Nru a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h
--- a/include/asm-ia64/scatterlist.h	Tue Aug 27 12:28:07 2002
+++ b/include/asm-ia64/scatterlist.h	Tue Aug 27 12:28:07 2002
@@ -7,12 +7,12 @@
  */
 
 struct scatterlist {
-	char *orig_address;	/* for use by swiotlb */
-
-	/* These two are only valid if ADDRESS member of this struct is NULL.  */
 	struct page *page;
 	unsigned int offset;
 	unsigned int length;	/* buffer length */
+
+	dma_addr_t dma_address;
+	unsigned int dma_length;
 };
 
 #define ISA_DMA_THRESHOLD	(~0UL)
diff -Nru a/include/asm-ia64/serial.h b/include/asm-ia64/serial.h
--- a/include/asm-ia64/serial.h	Tue Aug 27 12:28:05 2002
+++ b/include/asm-ia64/serial.h	Tue Aug 27 12:28:05 2002
@@ -1,6 +1,6 @@
 /*
  * include/asm-ia64/serial.h
- * 
+ *
  * Derived from the i386 version.
  */
 
@@ -35,7 +35,7 @@
 #else
 #define RS_TABLE_SIZE
 #endif
-	
+
 /*
  * The following define the access methods for the HUB6 card. All
  * access is through two ports for all 24 possible chips. The card is
@@ -115,21 +115,8 @@
 #define HUB6_SERIAL_PORT_DFNS
 #endif
 
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS			\
-	{ 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
-#else
-#define MCA_SERIAL_PORT_DFNS
-#endif
-
 #define SERIAL_PORT_DFNS		\
 	STD_SERIAL_PORT_DEFNS		\
 	EXTRA_SERIAL_PORT_DEFNS		\
-	HUB6_SERIAL_PORT_DFNS		\
-	MCA_SERIAL_PORT_DFNS
+	HUB6_SERIAL_PORT_DFNS
 
diff -Nru a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
--- a/include/asm-ia64/smp.h	Tue Aug 27 12:28:05 2002
+++ b/include/asm-ia64/smp.h	Tue Aug 27 12:28:05 2002
@@ -17,6 +17,7 @@
 #include <linux/threads.h>
 #include <linux/kernel.h>
 
+#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/param.h>
 #include <asm/processor.h>
@@ -36,6 +37,7 @@
 
 extern char no_int_routing __initdata;
 
+extern unsigned long phys_cpu_present_map;
 extern volatile unsigned long cpu_online_map;
 extern unsigned long ipi_base_addr;
 extern unsigned char smp_int_redirect;
@@ -45,23 +47,26 @@
 
 extern unsigned long ap_wakeup_vector;
 
-#define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
-extern inline unsigned int num_online_cpus(void)
+#define cpu_possible(cpu)	(phys_cpu_present_map & (1UL << (cpu)))
+#define cpu_online(cpu)		(cpu_online_map & (1UL << (cpu)))
+
+static inline unsigned int
+num_online_cpus (void)
 {
 	return hweight64(cpu_online_map);
 }
 
-extern inline int any_online_cpu(unsigned int mask)
+static inline int
+any_online_cpu (unsigned int mask)
 {
 	if (mask & cpu_online_map)
 		return __ffs(mask & cpu_online_map);
-
 	return -1;
 }
 
 /*
- * Function to map hard smp processor id to logical id.  Slow, so
- * don't use this in performance-critical code.
+ * Function to map hard smp processor id to logical id.  Slow, so don't use this in
+ * performance-critical code.
  */
 static inline int
 cpu_logical_id (int cpuid)
@@ -120,11 +125,10 @@
 }
 
 /* Upping and downing of CPUs */
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
-extern int __cpu_up(unsigned int cpu);
-
-#define NO_PROC_ID		0xffffffff	/* no processor magic marker */
+extern int __cpu_disable (void);
+extern void __cpu_die (unsigned int cpu);
+extern int __cpu_up (unsigned int cpu);
+extern void __init smp_build_cpu_map(void);
 
 extern void __init init_smp_config (void);
 extern void smp_do_timer (struct pt_regs *regs);
diff -Nru a/include/asm-ia64/smplock.h b/include/asm-ia64/smplock.h
--- a/include/asm-ia64/smplock.h	Tue Aug 27 12:28:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,65 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-
-#include <asm/current.h>
-#include <asm/hardirq.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_SMP
-# define kernel_locked()	spin_is_locked(&kernel_flag)
-# define check_irq_holder(cpu)			\
-do {						\
-	if (global_irq_holder == (cpu))		\
-		BUG();				\
-} while (0)
-#else
-# define kernel_locked()	(1)
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0)) {	\
-		spin_unlock(&kernel_flag);	\
-		check_irq_holder(cpu);		\
-	}					\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void
-lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-static __inline__ void
-unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-ia64/softirq.h b/include/asm-ia64/softirq.h
--- a/include/asm-ia64/softirq.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ia64/softirq.h	Tue Aug 27 12:28:08 2002
@@ -4,22 +4,23 @@
 #include <linux/compiler.h>
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
+#include <linux/compiler.h>
+#include <linux/preempt.h>
+
 #include <asm/hardirq.h>
 
-#define __local_bh_enable()	do { barrier(); really_local_bh_count()--; } while (0)
+#define __local_bh_enable()	do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
 
-#define local_bh_disable()	do { really_local_bh_count()++; barrier(); } while (0)
-#define local_bh_enable()								\
-do {											\
-	__local_bh_enable();								\
-	if (unlikely(local_softirq_pending()) && really_local_bh_count() == 0)	\
-		do_softirq();								\
+#define local_bh_disable()	do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0)
+#define local_bh_enable()						\
+do {									\
+	__local_bh_enable();						\
+	if (unlikely(!in_interrupt() && local_softirq_pending()))	\
+		do_softirq();						\
+	preempt_check_resched();					\
 } while (0)
-
-
-#define in_softirq()		(really_local_bh_count() != 0)
 
 #endif /* _ASM_IA64_SOFTIRQ_H */
diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h
--- a/include/asm-ia64/system.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/system.h	Tue Aug 27 12:28:02 2002
@@ -13,9 +13,11 @@
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  */
 #include <linux/config.h>
+#include <linux/percpu.h>
 
 #include <asm/kregs.h>
 #include <asm/page.h>
+#include <asm/pal.h>
 
 #define KERNEL_START		(PAGE_OFFSET + 68*1024*1024)
 
@@ -102,6 +104,8 @@
 #define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
 #define set_wmb(var, value)	do { (var) = (value); mb(); } while (0)
 
+#define safe_halt()         ia64_pal_halt(1)                /* PAL_HALT */
+
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
  * that none of the previous instructions in the same group are
@@ -168,27 +172,7 @@
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
 #define local_irq_enable()	__asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
-
-#define local_irq_disable()			local_irq_disable ()
 #define local_save_flags(flags)	__asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory")
-#define local_irq_save(flags)	local_irq_save(flags)
-#define save_and_cli(flags)	local_irq_save(flags)
-
-#ifdef CONFIG_SMP
-  extern void __global_cli (void);
-  extern void __global_sti (void);
-  extern unsigned long __global_save_flags (void);
-  extern void __global_restore_flags (unsigned long);
-# define cli()			__global_cli()
-# define sti()			__global_sti()
-# define save_flags(flags)	((flags) = __global_save_flags())
-# define restore_flags(flags)	__global_restore_flags(flags)
-#else /* !CONFIG_SMP */
-# define cli()			local_irq_disable()
-# define sti()			local_irq_enable()
-# define save_flags(flags)	local_save_flags(flags)
-# define restore_flags(flags)	local_irq_restore(flags)
-#endif /* !CONFIG_SMP */
 
 /*
  * Force an unresolved reference if someone tries to use
@@ -376,7 +360,7 @@
  * newly created thread returns directly to
  * ia64_ret_from_syscall_clear_r8.
  */
-extern void ia64_switch_to (void *next_task);
+extern struct task_struct *ia64_switch_to (void *next_task);
 
 struct task_struct;
 
@@ -384,19 +368,20 @@
 extern void ia64_load_extra (struct task_struct *task);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PERFMON)
-# define PERFMON_IS_SYSWIDE() (local_cpu_data->pfm_syst_wide != 0)
+  extern int __per_cpu_data pfm_syst_wide;
+# define PERFMON_IS_SYSWIDE() (this_cpu(pfm_syst_wide) != 0)
 #else
 # define PERFMON_IS_SYSWIDE() (0)
 #endif
 
-#define __switch_to(prev,next) do {							\
+#define __switch_to(prev,next,last) do {							\
 	if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID))	\
 	    || IS_IA32_PROCESS(ia64_task_regs(prev)) || PERFMON_IS_SYSWIDE())		\
 		ia64_save_extra(prev);							\
 	if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID))	\
 	    || IS_IA32_PROCESS(ia64_task_regs(next)) || PERFMON_IS_SYSWIDE())		\
 		ia64_load_extra(next);							\
-	ia64_switch_to((next));								\
+	(last) = ia64_switch_to((next));						\
 } while (0)
 
 #ifdef CONFIG_SMP
@@ -411,19 +396,28 @@
  * task->thread.fph, avoiding the complication of having to fetch
  * the latest fph state from another CPU.
  */
-# define switch_to(prev,next) do {						\
-	if (ia64_psr(ia64_task_regs(prev))->mfh) {				\
-		ia64_psr(ia64_task_regs(prev))->mfh = 0;			\
-		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;			\
-		__ia64_save_fpu((prev)->thread.fph);				\
-	}									\
-	ia64_psr(ia64_task_regs(prev))->dfh = 1;				\
-	__switch_to(prev,next);							\
+# define switch_to(prev,next,last) do {					\
+	if (ia64_psr(ia64_task_regs(prev))->mfh) {			\
+		ia64_psr(ia64_task_regs(prev))->mfh = 0;		\
+		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;		\
+		__ia64_save_fpu((prev)->thread.fph);			\
+		(prev)->thread.last_fph_cpu = smp_processor_id();	\
+	}								\
+	if ((next)->thread.flags & IA64_THREAD_FPH_VALID) {		\
+		if (((next)->thread.last_fph_cpu == smp_processor_id())	\
+		    && (ia64_get_fpu_owner() == next))			\
+		{							\
+			ia64_psr(ia64_task_regs(next))->dfh = 0;	\
+			ia64_psr(ia64_task_regs(next))->mfh = 0;	\
+		} else							\
+			ia64_psr(ia64_task_regs(next))->dfh = 1;	\
+	}								\
+	__switch_to(prev,next,last);					\
   } while (0)
 #else
-# define switch_to(prev,next) do {						\
+# define switch_to(prev,next,last) do {						\
 	ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next));	\
-	__switch_to(prev,next);							\
+	__switch_to(prev,next,last);						\
 } while (0)
 #endif
 
diff -Nru a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h
--- a/include/asm-ia64/tlb.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/tlb.h	Tue Aug 27 12:28:02 2002
@@ -1,7 +1,202 @@
-/* XXX fix me! */
+#ifndef _ASM_IA64_TLB_H
+#define _ASM_IA64_TLB_H
+/*
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * This file was derived from asm-generic/tlb.h.
+ */
+/*
+ * Removing a translation from a page table (including TLB-shootdown) is a four-step
+ * procedure:
+ *
+ *	(1) Flush (virtual) caches --- ensures virtual memory is coherent with kernel memory
+ *	    (this is a no-op on ia64).
+ *	(2) Clear the relevant portions of the page-table
+ *	(3) Flush the TLBs --- ensures that stale content is gone from CPU TLBs
+ *	(4) Release the pages that were freed up in step (2).
+ *
+ * Note that the ordering of these steps is crucial to avoid races on MP machines.
+ *
+ * The Linux kernel defines several platform-specific hooks for TLB-shootdown.  When
+ * unmapping a portion of the virtual address space, these hooks are called according to
+ * the following template:
+ *
+ *	tlb <- tlb_gather_mmu(mm, full_mm_flush);	// start unmap for address space MM
+ *	{
+ *	  for each vma that needs a shootdown do {
+ *	    tlb_start_vma(tlb, vma);
+ *	      for each page-table-entry PTE that needs to be removed do {
+ *		tlb_remove_tlb_entry(tlb, pte, address);
+ *		if (pte refers to a normal page) {
+ *		  tlb_remove_page(tlb, page);
+ *		}
+ *	      }
+ *	    tlb_end_vma(tlb, vma);
+ *	  }
+ *	}
+ *	tlb_finish_mmu(tlb, start, end);	// finish unmap for address space MM
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+
+#include <asm/processor.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_SMP
+# define FREE_PTE_NR		2048
+# define tlb_fast_mode(tlb)	((tlb)->nr == ~0U)
+#else
+# define FREE_PTE_NR		0
+# define tlb_fast_mode(tlb)	(1)
+#endif
+
+typedef struct {
+	struct mm_struct	*mm;
+	unsigned int		nr;	/* == ~0U => fast mode */
+	unsigned int		fullmm;	/* non-zero means full mm flush */
+	unsigned long		freed;	/* number of pages freed */
+	unsigned long		start_addr;
+	unsigned long		end_addr;
+	struct page 		*pages[FREE_PTE_NR];
+} mmu_gather_t;
+
+/* Users of the generic TLB shootdown code must declare this storage space. */
+extern mmu_gather_t	mmu_gathers[NR_CPUS];
+
+/*
+ * Flush the TLB for address range START to END and, if not in fast mode, release the
+ * freed pages that where gathered up to this point.
+ */
+static inline void
+ia64_tlb_flush_mmu (mmu_gather_t *tlb, unsigned long start, unsigned long end)
+{
+	unsigned int nr;
+
+	if (tlb->fullmm) {
+		/*
+		 * Tearing down the entire address space.  This happens both as a result
+		 * of exit() and execve().  The latter case necessitates the call to
+		 * flush_tlb_mm() here.
+		 */
+		flush_tlb_mm(tlb->mm);
+	} else if (unlikely (end - start >= 1024*1024*1024*1024UL
+		      || REGION_NUMBER(start) != REGION_NUMBER(end - 1)))
+	{
+		/*
+		 * If we flush more than a tera-byte or across regions, we're probably
+		 * better off just flushing the entire TLB(s).  This should be very rare
+		 * and is not worth optimizing for.
+		 */
+		flush_tlb_all();
+	} else {
+		/*
+		 * XXX fix me: flush_tlb_range() should take an mm pointer instead of a
+		 * vma pointer.
+		 */
+		struct vm_area_struct vma;
+
+		vma.vm_mm = tlb->mm;
+		/* flush the address range from the tlb: */
+		flush_tlb_range(&vma, start, end);
+		/* now flush the virt. page-table area mapping the address range: */
+		flush_tlb_range(&vma, ia64_thash(start), ia64_thash(end));
+	}
+
+	/* lastly, release the freed pages */
+	nr = tlb->nr;
+	if (!tlb_fast_mode(tlb)) {
+		unsigned long i;
+		tlb->nr = 0;
+		tlb->start_addr = ~0UL;
+		for (i = 0; i < nr; ++i)
+			free_page_and_swap_cache(tlb->pages[i]);
+	}
+}
+
+/*
+ * Return a pointer to an initialized mmu_gather_t.
+ */
+static inline mmu_gather_t *
+tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
+{
+	mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()];
+
+	tlb->mm = mm;
+	/*
+	 * Use fast mode if only 1 CPU is online.
+	 *
+	 * It would be tempting to turn on fast-mode for full_mm_flush as well.  But this
+	 * doesn't work because of speculative accesses and software prefetching: the page
+	 * table of "mm" may (and usually is) the currently active page table and even
+	 * though the kernel won't do any user-space accesses during the TLB shoot down, a
+	 * compiler might use speculation or lfetch.fault on what happens to be a valid
+	 * user-space address.  This in turn could trigger a TLB miss fault (or a VHPT
+	 * walk) and re-insert a TLB entry we just removed.  Slow mode avoids such
+	 * problems.  (We could make fast-mode work by switching the current task to a
+	 * different "mm" during the shootdown.) --davidm 08/02/2002
+	 */
+	tlb->nr = (num_online_cpus() == 1) ? ~0U : 0;
+	tlb->fullmm = full_mm_flush;
+	tlb->freed = 0;
+	tlb->start_addr = ~0UL;
+	return tlb;
+}
+
+/*
+ * Called at the end of the shootdown operation to free up any resources that were
+ * collected.  The page table lock is still held at this point.
+ */
+static inline void
+tlb_finish_mmu (mmu_gather_t *tlb, unsigned long start, unsigned long end)
+{
+	unsigned long freed = tlb->freed;
+	struct mm_struct *mm = tlb->mm;
+	unsigned long rss = mm->rss;
+
+	if (rss < freed)
+		freed = rss;
+	mm->rss = rss - freed;
+	/*
+	 * Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
+	 * tlb->end_addr.
+	 */
+	ia64_tlb_flush_mmu(tlb, start, end);
+
+	/* keep the page table cache within bounds */
+	check_pgt_cache();
+}
+
+/*
+ * Remove TLB entry for PTE mapped at virtual address ADDRESS.  This is called for any
+ * PTE, not just those pointing to (normal) physical memory.
+ */
+static inline void
+tlb_remove_tlb_entry (mmu_gather_t *tlb, pte_t *ptep, unsigned long address)
+{
+	if (tlb->start_addr == ~0UL)
+		tlb->start_addr = address;
+	tlb->end_addr = address + PAGE_SIZE;
+}
+
+/*
+ * Logically, this routine frees PAGE.  On MP machines, the actual freeing of the page
+ * must be delayed until after the TLB has been flushed (see comments at the beginning of
+ * this file).
+ */
+static inline void
+tlb_remove_page (mmu_gather_t *tlb, struct page *page)
+{
+	if (tlb_fast_mode(tlb)) {
+		free_page_and_swap_cache(page);
+		return;
+	}
+	tlb->pages[tlb->nr++] = page;
+	if (tlb->nr >= FREE_PTE_NR)
+		ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+}
+
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)
-#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
-#define tlb_flush(tlb)				flush_tlb_mm((tlb)->mm)
 
-#include <asm-generic/tlb.h>
+#endif /* _ASM_IA64_TLB_H */
diff -Nru a/include/asm-ia64/tlbflush.h b/include/asm-ia64/tlbflush.h
--- a/include/asm-ia64/tlbflush.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ia64/tlbflush.h	Tue Aug 27 12:28:02 2002
@@ -60,6 +60,8 @@
 #else
 	if (vma->vm_mm == current->active_mm)
 		asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(PAGE_SHIFT << 2) : "memory");
+	else
+		vma->vm_mm->context = 0;
 #endif
 }
 
@@ -70,12 +72,10 @@
 static inline void
 flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	struct vm_area_struct vma;
-
-	if (REGION_NUMBER(start) != REGION_NUMBER(end))
-		printk("flush_tlb_pgtables: can't flush across regions!!\n");
-	vma.vm_mm = mm;
-	flush_tlb_range(&vma, ia64_thash(start), ia64_thash(end));
+	/*
+	 * Deprecated.  The virtual page table is now flushed via the normal gather/flush
+	 * interface (see tlb.h).
+	 */
 }
 
 #define flush_tlb_kernel_range(start, end)	flush_tlb_all()	/* XXX fix me */
diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-ia64/unistd.h	Tue Aug 27 12:27:59 2002
@@ -223,6 +223,10 @@
 #define __NR_sched_setaffinity		1231
 #define __NR_sched_getaffinity		1232
 #define __NR_security			1233
+#define __NR_get_large_pages		1234
+#define __NR_free_large_pages		1235
+#define __NR_share_large_pages		1236
+#define __NR_unshare_large_pages	1237
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Nru a/include/asm-m68k/keyboard.h b/include/asm-m68k/keyboard.h
--- a/include/asm-m68k/keyboard.h	Tue Aug 27 12:27:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,72 +0,0 @@
-/*
- *  linux/include/asm-m68k/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- */
-
-/*
- *  This file contains the m68k architecture specific keyboard definitions
- */
-
-#ifndef __M68K_KEYBOARD_H
-#define __M68K_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/kd.h>
-#include <asm/machdep.h>
-
-#ifdef CONFIG_Q40
-#include <asm/q40_keyboard.h>
-#endif
-
-static __inline__ int kbd_setkeycode(unsigned int scancode,
-				     unsigned int keycode)
-{
-#ifdef CONFIG_Q40
-    if (MACH_IS_Q40)
-        return q40kbd_setkeycode(scancode,keycode);
-#endif
-    return -EOPNOTSUPP;
-}
-
-static __inline__ int kbd_getkeycode(unsigned int scancode)
-{
-#ifdef CONFIG_Q40
-    if (MACH_IS_Q40)
-        return q40kbd_getkeycode(scancode);
-#endif
-    return scancode > 127 ? -EINVAL : scancode;
-}
-
-static __inline__ char kbd_unexpected_up(unsigned char keycode)
-{
-#ifdef CONFIG_Q40
-    if (MACH_IS_Q40)
-        return q40kbd_unexpected_up(keycode);
-#endif
-    return 0200;
-}
-
-static __inline__ void kbd_leds(unsigned char leds)
-{
-    if (mach_kbd_leds)
-	mach_kbd_leds(leds);
-}
-
-#define kbd_init_hw		mach_keyb_init
-#define kbd_translate		mach_kbd_translate
-#define kbd_rate		mach_kbdrate
-
-#define kbd_sysrq_xlate		mach_sysrq_xlate
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler)
-
-extern unsigned int SYSRQ_KEY;
-
-#endif /* __KERNEL__ */
-
-#endif /* __M68K_KEYBOARD_H */
diff -Nru a/include/asm-m68k/smplock.h b/include/asm-m68k/smplock.h
--- a/include/asm-m68k/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,51 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	local_irq_enable(); \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-mips/keyboard.h b/include/asm-mips/keyboard.h
--- a/include/asm-mips/keyboard.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,94 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2001 Ralf Baechle
- * Copyright (C) 2001 MIPS Technologies, Inc.
- */
-#ifndef _ASM_KEYBOARD_H
-#define _ASM_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/bootinfo.h>
-
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-
-#ifdef CONFIG_PC_KEYB
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern int pckbd_rate(struct kbd_repeat *rep);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-extern void kbd_forward_char (int ch);
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_rate		pckbd_rate
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate         pckbd_sysrq_xlate
-
-#else
-
-extern int kbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int kbd_getkeycode(unsigned int scancode);
-extern int kbd_translate(unsigned char scancode, unsigned char *keycode,
-	char raw_mode);
-extern char kbd_unexpected_up(unsigned char keycode);
-extern void kbd_leds(unsigned char leds);
-extern void kbd_init_hw(void);
-extern unsigned char *kbd_sysrq_xlate;
-
-#endif
-
-#define SYSRQ_KEY 0x54
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-struct kbd_ops {
-	/* Keyboard driver resource allocation  */
-	void (*kbd_request_region)(void);
-	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
-
-	/* PSaux driver resource management  */
-	int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
-	void (*aux_free_irq)(void);
-
-	/* Methods to access the keyboard processor's I/O registers  */
-	unsigned char (*kbd_read_input)(void);
-	void (*kbd_write_output)(unsigned char val);
-	void (*kbd_write_command)(unsigned char val);
-	unsigned char (*kbd_read_status)(void);
-};
-
-extern struct kbd_ops *kbd_ops;
-
-/* Do the actual calls via kbd_ops vector  */
-#define kbd_request_region() kbd_ops->kbd_request_region()
-#define kbd_request_irq(handler) kbd_ops->kbd_request_irq(handler)
-
-#define aux_request_irq(hand, dev_id) kbd_ops->aux_request_irq(hand)
-#define aux_free_irq(dev_id) kbd_ops->aux_free_irq()
-
-#define kbd_read_input() kbd_ops->kbd_read_input()
-#define kbd_write_output(val) kbd_ops->kbd_write_output(val)
-#define kbd_write_command(val) kbd_ops->kbd_write_command(val)
-#define kbd_read_status() kbd_ops->kbd_read_status()
-
-#endif /* __KERNEL */
-
-#endif /* _ASM_KEYBOARD_H */
diff -Nru a/include/asm-mips/smplock.h b/include/asm-mips/smplock.h
--- a/include/asm-mips/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-/* $Id: smplock.h,v 1.2 1999/10/09 00:01:43 ralf Exp $
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Default SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	local_irq_enable(); \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-mips64/keyboard.h b/include/asm-mips64/keyboard.h
--- a/include/asm-mips64/keyboard.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,77 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2001 Ralf Baechle
- * Copyright (C) 2001 MIPS Technologies, Inc.
- */
-#ifndef _ASM_KEYBOARD_H
-#define _ASM_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/bootinfo.h>
-
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern int pckbd_rate(struct kbd_repeat *rep);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_rate		pckbd_rate
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate         pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-struct kbd_ops {
-	/* Keyboard driver resource allocation  */
-	void (*kbd_request_region)(void);
-	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
-
-	/* PSaux driver resource management  */
-	int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
-	void (*aux_free_irq)(void);
-
-	/* Methods to access the keyboard processor's I/O registers  */
-	unsigned char (*kbd_read_input)(void);
-	void (*kbd_write_output)(unsigned char val);
-	void (*kbd_write_command)(unsigned char val);
-	unsigned char (*kbd_read_status)(void);
-};
-
-extern struct kbd_ops *kbd_ops;
-
-/* Do the actual calls via kbd_ops vector  */
-#define kbd_request_region() kbd_ops->kbd_request_region()
-#define kbd_request_irq(handler) kbd_ops->kbd_request_irq(handler)
-
-#define aux_request_irq(hand, dev_id) kbd_ops->aux_request_irq(hand)
-#define aux_free_irq(dev_id) kbd_ops->aux_free_irq()
-
-#define kbd_read_input() kbd_ops->kbd_read_input()
-#define kbd_write_output(val) kbd_ops->kbd_write_output(val)
-#define kbd_write_command(val) kbd_ops->kbd_write_command(val)
-#define kbd_read_status() kbd_ops->kbd_read_status()
-
-#endif /* __KERNEL */
-
-#endif /* _ASM_KEYBOARD_H */
diff -Nru a/include/asm-mips64/smplock.h b/include/asm-mips64/smplock.h
--- a/include/asm-mips64/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,56 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#ifndef _ASM_SMPLOCK_H
-#define _ASM_SMPLOCK_H
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()			spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-static __inline__ void release_kernel_lock(struct task_struct *task, int cpu)
-{
-	if (task->lock_depth >= 0)
-		spin_unlock(&kernel_flag);
-	release_irqlock(cpu);
-	local_irq_enable();
-}
-
-/*
- * Re-acquire the kernel lock
- */
-static __inline__ void reacquire_kernel_lock(struct task_struct *task)
-{
-	if (task->lock_depth >= 0)
-		spin_lock(&kernel_flag);
-}
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-static __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
-
-#endif /* _ASM_SMPLOCK_H */
diff -Nru a/include/asm-parisc/keyboard.h b/include/asm-parisc/keyboard.h
--- a/include/asm-parisc/keyboard.h	Tue Aug 27 12:27:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,67 +0,0 @@
-/*
- *  linux/include/asm-parisc/keyboard.h
- *
- *  Original by Geert Uytterhoeven
- *  updates by Alex deVries <adevries@thepuffingroup.com>
- *  portions copyright (1999) The Puffin Group
- *  mostly rewritten by Philipp Rumpf <prumpf@tux.org>,
- *   Copyright 2000 Philipp Rumpf
- */
-
-/*
- *  We try to keep the amount of generic code as low as possible -
- *  we want to support all HIL, PS/2, and untranslated USB keyboards
- */
-
-#ifndef _PARISC_KEYBOARD_H
-#define _PARISC_KEYBOARD_H
-
-#include <linux/config.h>
-
-#ifdef __KERNEL__
-#ifdef CONFIG_VT
-
-/*  These are basically the generic functions / variables.  The only
- *  unexpected detail is the initialization sequence for the keyboard
- *  driver is something like this:
- *
- *  detect keyboard port
- *  detect keyboard
- *  call register_kbd_ops 
- *  wait for init_hw
- *
- *  only after init_hw has been called you're allowed to call
- *  handle_scancode.  This means you either have to be extremely
- *  careful or use a global flag or something - I strongly suggest
- *  the latter.    prumpf */
-
-extern struct kbd_ops {
-	int (*setkeycode)(unsigned int, unsigned int);
-	int (*getkeycode)(unsigned int);
-	int (*translate)(unsigned char, unsigned char *, char);
-	char (*unexpected_up)(unsigned char);
-	void (*leds)(unsigned char);
-	void (*init_hw)(void);
-
-	unsigned char sysrq_key;
-	unsigned char *sysrq_xlate;
-} *kbd_ops;
-
-#define kbd_setkeycode		(*kbd_ops->setkeycode)
-#define kbd_getkeycode		(*kbd_ops->getkeycode)
-#define kbd_translate		(*kbd_ops->translate)
-#define kbd_unexpected_up	(*kbd_ops->unexpected_up)
-#define kbd_leds		(*kbd_ops->leds)
-#define kbd_init_hw		(*kbd_ops->init_hw)
-
-#define SYSRQ_KEY		(kbd_ops->sysrq_key)
-#define	kbd_sysrq_xlate		(kbd_ops->sysrq_xlate)
-extern unsigned char hp_ps2kbd_sysrq_xlate[128]; 	/* from drivers/char/hp_keyb.c */
-
-extern void register_kbd_ops(struct kbd_ops *ops);
-
-#endif /* CONFIG_VT */
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASMPARISC_KEYBOARD_H */
diff -Nru a/include/asm-parisc/rtc.h b/include/asm-parisc/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-parisc/rtc.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,131 @@
+/* 
+ * inclue/asm-parisc/rtc.h
+ *
+ * Copyright 2002 Randolph CHung <tausq@debian.org>
+ *
+ * Based on: include/asm-ppc/rtc.h and the genrtc driver in the
+ * 2.4 parisc linux tree
+ */
+
+#ifndef __ASM_RTC_H__
+#define __ASM_RTC_H__
+
+#ifdef __KERNEL__
+
+#include <linux/rtc.h>
+
+#include <asm/pdc.h>
+
+#define SECS_PER_HOUR   (60 * 60)
+#define SECS_PER_DAY    (SECS_PER_HOUR * 24)
+
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+extern void gen_rtc_interrupt(unsigned long);
+
+/* some dummy definitions */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+# define __isleap(year) \
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+/* How many days come before each month (0-12).  */
+static const unsigned short int __mon_yday[2][13] =
+{
+	/* Normal years.  */
+	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+	/* Leap years.  */
+	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+static int get_rtc_time(struct rtc_time *wtime)
+{
+	struct pdc_tod tod_data;
+	long int days, rem, y;
+	const unsigned short int *ip;
+
+	if(pdc_tod_read(&tod_data) < 0)
+		return -1;
+
+	
+	// most of the remainder of this function is:
+//	Copyright (C) 1991, 1993, 1997, 1998 Free Software Foundation, Inc.
+//	This was originally a part of the GNU C Library.
+//      It is distributed under the GPL, and was swiped from offtime.c
+
+
+	days = tod_data.tod_sec / SECS_PER_DAY;
+	rem = tod_data.tod_sec % SECS_PER_DAY;
+
+	wtime->tm_hour = rem / SECS_PER_HOUR;
+	rem %= SECS_PER_HOUR;
+	wtime->tm_min = rem / 60;
+	wtime->tm_sec = rem % 60;
+
+	y = 1970;
+	
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+
+	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
+	{
+		/* Guess a corrected year, assuming 365 days per year.  */
+		long int yg = y + days / 365 - (days % 365 < 0);
+
+		/* Adjust DAYS and Y to match the guessed year.  */
+		days -= ((yg - y) * 365
+			 + LEAPS_THRU_END_OF (yg - 1)
+			 - LEAPS_THRU_END_OF (y - 1));
+		y = yg;
+	}
+	wtime->tm_year = y - 1900;
+
+	ip = __mon_yday[__isleap(y)];
+	for (y = 11; days < (long int) ip[y]; --y)
+		continue;
+	days -= ip[y];
+	wtime->tm_mon = y;
+	wtime->tm_mday = days + 1;
+	
+	return 0;
+}
+
+static int set_rtc_time(struct rtc_time *wtime)
+{
+	u_int32_t secs;
+
+	secs = mktime(wtime->tm_year + 1900, wtime->tm_mon + 1, wtime->tm_mday, 
+		      wtime->tm_hour, wtime->tm_min, wtime->tm_sec);
+
+	if(pdc_tod_set(secs, 0) < 0)
+		return -1;
+	else
+		return 0;
+
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	struct rtc_time h;
+
+	get_rtc_time(&h);
+	return h.tm_sec;
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_RTC_H__ */
diff -Nru a/include/asm-parisc/smplock.h b/include/asm-parisc/smplock.h
--- a/include/asm-parisc/smplock.h	Tue Aug 27 12:27:57 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,49 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	local_irq_enable(); \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
--- a/include/asm-ppc/cache.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ppc/cache.h	Tue Aug 27 12:28:08 2002
@@ -21,12 +21,13 @@
 #define LG_L1_CACHE_LINE_SIZE	7
 #define MAX_COPY_PREFETCH	1
 #else
-#define	L1_CACHE_LINE_SIZE  32
+#define	L1_CACHE_LINE_SIZE	32
 #define LG_L1_CACHE_LINE_SIZE	5
 #define MAX_COPY_PREFETCH	4
 #endif
 
 #define	L1_CACHE_BYTES L1_CACHE_LINE_SIZE
+#define L1_CACHE_SHIFT LG_L1_CACHE_LINE_SIZE
 #define	SMP_CACHE_BYTES L1_CACHE_BYTES
 
 #define	L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
--- a/include/asm-ppc/ide.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ppc/ide.h	Tue Aug 27 12:28:02 2002
@@ -98,14 +98,35 @@
 			continue;
 		ide_init_hwif_ports(&hw, base, 0, NULL);
 		hw.irq = ide_default_irq(base);
-		ide_register_hw(&hw);
+		ide_register_hw(&hw, NULL);
 	}
 #endif
 }
 
+#if !defined(ide_request_irq)
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#endif
+
+#if !defined(ide_free_irq)
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#endif
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+extern void ide_fix_driveid(struct hd_driveid *id);
+
+/*
+ * The following are not needed for the non-m68k ports
+ * unless direct IDE on 8xx
+ */
 #if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE )
-#define ATA_ARCH_ACK_INTR
+#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
+#else
+#define ide_ack_intr(hwif)		(1)
 #endif
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h
--- a/include/asm-ppc/keyboard.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,112 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/include/asm-ppc/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- *  Modified for Power Macintosh by Paul Mackerras
- */
-
-/*
- * This file contains the ppc architecture specific keyboard definitions -
- * like the intel pc for prep systems, different for power macs.
- */
-
-#ifndef __ASM_KEYBOARD_H__
-#define __ASM_KEYBOARD_H__
-
-#ifdef __KERNEL__
-
-#include <linux/adb.h>
-#include <asm/machdep.h>
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/io.h>
-
-#ifndef KEYBOARD_IRQ
-#define KEYBOARD_IRQ			1
-#endif
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-#define INIT_KBD
-
-extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
-				 char raw_mode);
-extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	return 0;
-}
-  
-static inline int kbd_getkeycode(unsigned int scancode)
-{
-	return 0;
-}
-  
-static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
-				char raw_mode)
-{
-	if ( ppc_md.kbd_translate )
-		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
-	else
-		return pckbd_translate(keycode, keycodep, raw_mode);
-}
-  
-static inline int kbd_unexpected_up(unsigned char keycode)
-{
-	if ( ppc_md.kbd_unexpected_up )
-		return ppc_md.kbd_unexpected_up(keycode);
-	else
-		return pckbd_unexpected_up(keycode);
-}
-  
-static inline void kbd_leds(unsigned char leds)
-{
-}
-
-static inline void kbd_init_hw(void)
-{
-}
-
-#define kbd_sysrq_xlate	pckbd_sysrq_xlate
-
-extern unsigned long SYSRQ_KEY;
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#ifndef kbd_read_input
-#define kbd_read_input() inb(KBD_DATA_REG)
-#define kbd_read_status() inb(KBD_STATUS_REG)
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-#endif
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#ifndef AUX_IRQ	
-#define AUX_IRQ 12
-#endif
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-#endif /* __ASM_KEYBOARD_H__ */
diff -Nru a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h
--- a/include/asm-ppc/kmap_types.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ppc/kmap_types.h	Tue Aug 27 12:28:01 2002
@@ -15,6 +15,8 @@
 	KM_BIO_DST_IRQ,
 	KM_PTE0,
 	KM_PTE1,
+	KM_IRQ0,
+	KM_IRQ1,
 	KM_TYPE_NR
 };
 
diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ppc/machdep.h	Tue Aug 27 12:28:02 2002
@@ -57,12 +57,6 @@
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
-	/* Tons of keyboard stuff. */
-	int		(*kbd_translate)(unsigned char scancode,
-				unsigned char *keycode,
-				char raw_mode);
-	char		(*kbd_unexpected_up)(unsigned char keycode);
-
 	/*
 	 * optional PCI "hooks"
 	 */
diff -Nru a/include/asm-ppc/rtc.h b/include/asm-ppc/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/rtc.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,95 @@
+/* 
+ * inclue/asm-ppc/rtc.h
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * Based on:
+ * include/asm-m68k/rtc.h
+ *
+ * Copyright Richard Zidlicky
+ * implementation details for genrtc/q40rtc driver
+ *
+ * And the old drivers/macintosh/rtc.c which was heavily based on:
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * With additional work by Paul Mackerras and Franz Sirl.
+ */
+/* permission is hereby granted to copy, modify and redistribute this code
+ * in terms of the GNU Library General Public License, Version 2 or later,
+ * at your option.
+ */
+
+#ifndef __ASM_RTC_H__
+#define __ASM_RTC_H__
+
+#ifdef __KERNEL__
+
+#include <linux/rtc.h>
+
+#include <asm/machdep.h>
+#include <asm/time.h>
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+extern void gen_rtc_interrupt(unsigned long);
+
+/* some dummy definitions */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+static inline void get_rtc_time(struct rtc_time *time)
+{
+	if (ppc_md.get_rtc_time) {
+		unsigned long nowtime;
+
+		nowtime = (ppc_md.get_rtc_time)();
+
+		to_tm(nowtime, time);
+
+		time->tm_year -= 1900;
+		time->tm_mon -= 1; /* Make sure userland has a 0-based month */
+	}
+}
+
+/* Set the current date and time in the real time clock. */
+static inline int set_rtc_time(struct rtc_time *time)
+{
+	if (ppc_md.get_rtc_time) {
+		unsigned long nowtime;
+
+		nowtime = mktime(time->tm_year+1900, time->tm_mon+1,
+				time->tm_mday, time->tm_hour, time->tm_min,
+				time->tm_sec);
+
+		(ppc_md.set_rtc_time)(nowtime);
+
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	struct rtc_time h;
+
+	get_rtc_time(&h);
+	return h.tm_sec;
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_RTC_H__ */
diff -Nru a/include/asm-ppc/smplock.h b/include/asm-ppc/smplock.h
--- a/include/asm-ppc/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#ifdef __KERNEL__
-#ifndef __ASM_SMPLOCK_H__
-#define __ASM_SMPLOCK_H__
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_SMP
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-#elif defined(CONFIG_PREEMPT)
-#define kernel_locked()		preempt_count()
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_unlock(&kernel_flag);	\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void lock_kernel(void)
-{
-#ifdef CONFIG_PREEMPT
-	if (current->lock_depth == -1)
-		spin_lock(&kernel_flag);
-	++current->lock_depth;
-#else
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-#endif /* CONFIG_PREEMPT */
-}
-
-static __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
-#endif /* __ASM_SMPLOCK_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ppc/unistd.h	Tue Aug 27 12:28:01 2002
@@ -233,6 +233,12 @@
 #define __NR_sched_getaffinity	223
 #define __NR_security		224
 #define __NR_tuxcall		225
+#define __NR_sendfile64		226
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-ppc64/delay.h b/include/asm-ppc64/delay.h
--- a/include/asm-ppc64/delay.h	Tue Aug 27 12:27:42 2002
+++ b/include/asm-ppc64/delay.h	Tue Aug 27 12:27:42 2002
@@ -33,6 +33,7 @@
 
 	while((__get_tb()-start) < loops)
 		__HMT_low();
+	__HMT_medium();
 }
 
 static inline void udelay(unsigned long usecs)
@@ -40,7 +41,6 @@
 	unsigned long loops = tb_ticks_per_usec * usecs;
 
 	__delay(loops);
-	__HMT_medium();
 }
 
 #endif /* _PPC64_DELAY_H */
diff -Nru a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h
--- a/include/asm-ppc64/hardirq.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-ppc64/hardirq.h	Tue Aug 27 12:28:01 2002
@@ -13,30 +13,86 @@
 #include <linux/preempt.h>
 
 typedef struct {
-	unsigned long __softirq_pending;
-	unsigned long __syscall_count;
+	unsigned int __softirq_pending;
+	unsigned int __syscall_count;
 	struct task_struct * __ksoftirqd_task;
 	unsigned long idle_timestamp;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
-#define IRQ_OFFSET 64
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-24 are the hardirq count (max # of hardirqs: 512)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x01ff0000
+ */
+
+#define PREEMPT_BITS	8
+#define SOFTIRQ_BITS	8
+#define HARDIRQ_BITS	9
+
+#define PREEMPT_SHIFT	0
+#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+#define __HARDIRQ_MASK(x)	((1UL << (x))-1)
+
+#define PREEMPT_MASK	(__HARDIRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define SOFTIRQ_MASK	(__HARDIRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+#define HARDIRQ_MASK	(__HARDIRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+
+#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
+#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
 
 /*
- * Are we in an interrupt context? Either doing bottom half
- * or hardware interrupt processing?
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
  */
-#define in_interrupt() \
-		((preempt_count() & ~PREEMPT_ACTIVE) >= IRQ_OFFSET)
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+/*
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
+ */
+#define in_irq()		(hardirq_count())
+#define in_softirq()		(softirq_count())
+#define in_interrupt()		(irq_count())
 
-#define in_irq in_interrupt
 
 #define hardirq_trylock()	(!in_interrupt())
 #define hardirq_endlock()	do { } while (0)
 
-#define irq_enter()		(preempt_count() += IRQ_OFFSET)
-#define irq_exit()		(preempt_count() -= IRQ_OFFSET)
+#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
+
+#if CONFIG_PREEMPT
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#else
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+#define irq_exit()							\
+do {									\
+		preempt_count() -= IRQ_EXIT_OFFSET;			\
+		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
+			do_softirq();					\
+		preempt_enable_no_resched();				\
+} while (0)
 
 #ifndef CONFIG_SMP
 # define synchronize_irq(irq)	barrier()
@@ -45,4 +101,13 @@
 #endif /* CONFIG_SMP */
 
 #endif /* __KERNEL__ */
+	
+#define show_stack(SP)				\
+do {						\
+	if (SP)					\
+		print_backtrace(SP);		\
+	else					\
+		print_backtrace(_get_SP());	\
+} while (0)
+
 #endif /* __ASM_HARDIRQ_H */
diff -Nru a/include/asm-ppc64/keyboard.h b/include/asm-ppc64/keyboard.h
--- a/include/asm-ppc64/keyboard.h	Tue Aug 27 12:28:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/*
- *  linux/include/asm-ppc/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- *  Modified for Power Macintosh by Paul Mackerras
- *
- * 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 file contains the ppc architecture specific keyboard definitions -
- * like the intel pc for prep systems, different for power macs.
- */
-
-#ifndef __ASMPPC64_KEYBOARD_H
-#define __ASMPPC64_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/adb.h>
-#include <asm/machdep.h>
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/io.h>
-
-#define KEYBOARD_IRQ			1
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-#define INIT_KBD
-
-static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	if ( ppc_md.kbd_setkeycode )
-		return ppc_md.kbd_setkeycode(scancode, keycode);
-	else
-		return 0;
-}
-  
-static inline int kbd_getkeycode(unsigned int scancode)
-{
-	if ( ppc_md.kbd_getkeycode )
-		return ppc_md.kbd_getkeycode(scancode);
-	else
-		return 0;
-}
-  
-static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
-				char raw_mode)
-{
-	if ( ppc_md.kbd_translate )
-		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
-	else
-		return 0;
-}
-  
-static inline int kbd_unexpected_up(unsigned char keycode)
-{
-	if ( ppc_md.kbd_unexpected_up )
-		return ppc_md.kbd_unexpected_up(keycode);
-	else
-		return 0;
-}
-  
-static inline void kbd_leds(unsigned char leds)
-{
-	if ( ppc_md.kbd_leds )
-		ppc_md.kbd_leds(leds);
-}
-
-static inline void kbd_init_hw(void)
-{
-	if ( ppc_md.kbd_init_hw )
-		ppc_md.kbd_init_hw();
-}
-
-#define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
-
-extern unsigned long SYSRQ_KEY;
-#define E1_PAUSE	119		/* PAUSE key */
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input() inb(KBD_DATA_REG)
-static inline int kbd_read_status(void) {
-	int ret = inb(0x64);
-	return (ret == 0xff) ? 0 : ret;	/* translate float to bad status. */
-}
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ 12
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASMPPC64_KEYBOARD_H */
diff -Nru a/include/asm-ppc64/kgdb.h b/include/asm-ppc64/kgdb.h
--- a/include/asm-ppc64/kgdb.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/* 
- * kgdb.h: Defines and declarations for serial line source level
- *         remote debugging of the Linux kernel using gdb.
- *
- * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * 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.
- */
-#ifndef _PPC64_KGDB_H
-#define _PPC64_KGDB_H
-
-#ifndef __ASSEMBLY__
-/* To initialize the serial, first thing called */
-extern void zs_kgdb_hook(int tty_num);
-/* To init the kgdb engine. (called by serial hook)*/
-extern void set_debug_traps(void);
-
-/* To enter the debugger explicitly. */
-extern void breakpoint(void);
-
-/* For taking exceptions
- * these are defined in traps.c
- */
-extern void (*debugger)(struct pt_regs *regs);
-extern int (*debugger_bpt)(struct pt_regs *regs);
-extern int (*debugger_sstep)(struct pt_regs *regs);
-extern int (*debugger_iabr_match)(struct pt_regs *regs);
-extern int (*debugger_dabr_match)(struct pt_regs *regs);
-extern void (*debugger_fault_handler)(struct pt_regs *regs);
-
-/* What we bring to the party */
-int kgdb_bpt(struct pt_regs *regs);
-int kgdb_sstep(struct pt_regs *regs);
-void kgdb(struct pt_regs *regs);
-int kgdb_iabr_match(struct pt_regs *regs);
-int kgdb_dabr_match(struct pt_regs *regs);
-static void kgdb_fault_handler(struct pt_regs *regs);
-static void handle_exception (struct pt_regs *regs);
-
-/*
- * external low-level support routines (ie macserial.c)
- */
-extern void kgdb_interruptible(int); /* control interrupts from serial */
-extern void putDebugChar(char);   /* write a single character      */
-extern char getDebugChar(void);   /* read and return a single char */
-
-#endif /* !(__ASSEMBLY__) */
-#endif /* !(_PPC64_KGDB_H) */
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ppc64/machdep.h	Tue Aug 27 12:28:02 2002
@@ -20,6 +20,17 @@
 struct TceTable;
 struct rtc_time;
 
+#ifdef CONFIG_SMP
+struct smp_ops_t {
+	void  (*message_pass)(int target, int msg, unsigned long data, int wait);
+	int   (*probe)(void);
+	void  (*kick_cpu)(int nr);
+	void  (*setup_cpu)(int nr);
+	void  (*take_timebase)(void);
+	void  (*give_timebase)(void);
+};
+#endif
+
 struct machdep_calls {
 	/* High use functions in the first cachelines, low use functions
 	 * follow.  DRENG collect profile data.
@@ -58,14 +69,6 @@
 	void		(*tce_free_one)(struct TceTable *tbl,
 				        long tcenum);    
 
-	void		(*smp_message_pass)(int target,
-					    int msg, 
-					    unsigned long data,
-					    int wait);
-	void		(*smp_probe)(void);
-	void		(*smp_kick_cpu)(int nr);
-	void		(*smp_setup_cpu)(int nr);
-
 	void		(*setup_arch)(void);
 	/* Optional, may be NULL. */
 	void		(*setup_residual)(struct seq_file *m, int cpu_id);
@@ -145,6 +148,11 @@
 
 	/* this is for modules, since _machine can be a define -- Cort */
 	int ppc_machine;
+
+#ifdef CONFIG_SMP
+	/* functions for dealing with other cpus */
+	struct smp_ops_t smp_ops;
+#endif /* CONFIG_SMP */
 };
 
 extern struct machdep_calls ppc_md;
diff -Nru a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h
--- a/include/asm-ppc64/mmu_context.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-ppc64/mmu_context.h	Tue Aug 27 12:28:02 2002
@@ -72,19 +72,19 @@
 	panic("mmu_context_underflow");
 }
 
-
 /*
  * Set up the context for a new address space.
  */
 static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
-	long head, size;
+	long head;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
-	if ( (size = mmu_context_queue.size) <= 0 ) {
-		spin_unlock( &mmu_context_queue.lock );
+	if (mmu_context_queue.size <= 0) {
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		return -ENOMEM;
 	}
 
@@ -93,9 +93,9 @@
 
 	head = (head < LAST_USER_CONTEXT-1) ? head+1 : 0;
 	mmu_context_queue.head = head;
-	mmu_context_queue.size = size-1;
+	mmu_context_queue.size--;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 
 	return 0;
 }
@@ -106,12 +106,13 @@
 static inline void
 destroy_context(struct mm_struct *mm)
 {
-	long index, size = mmu_context_queue.size;
+	long index;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
-	if ( (size = mmu_context_queue.size) >= NUM_USER_CONTEXT ) {
-		spin_unlock( &mmu_context_queue.lock );
+	if (mmu_context_queue.size >= NUM_USER_CONTEXT) {
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		mmu_context_underflow();
 	}
 
@@ -125,10 +126,10 @@
 	mmu_context_queue.tail = index;
 #endif
 
-	mmu_context_queue.size = size+1;
+	mmu_context_queue.size++;
 	mmu_context_queue.elements[index] = mm->context;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 }
 
 extern void flush_stab(struct task_struct *tsk, struct mm_struct *mm);
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ppc64/mmzone.h	Tue Aug 27 12:28:08 2002
@@ -22,7 +22,10 @@
 #define MAX_NUMNODES 4
 
 /* XXX grab this from the device tree - Anton */
-#define PHYSADDR_TO_NID(pa)		((pa) >> 36)
+#define MEMORY_ZONE_BITS	33
+#define CPU_SHIFT_BITS          1
+
+#define PHYSADDR_TO_NID(pa)		((pa) >> MEMORY_ZONE_BITS)
 #define PLAT_NODE_DATA(n)		(&plat_node_data[(n)])
 #define PLAT_NODE_DATA_STARTNR(n)	\
 	(PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
@@ -84,7 +87,7 @@
 #ifdef CONFIG_NUMA
 
 /* XXX grab this from the device tree - Anton */
-#define cputonode(cpu)	((cpu) >> 3)
+#define cputonode(cpu)	((cpu) >> CPU_SHIFT_BITS)
 
 #define numa_node_id()	cputonode(smp_processor_id())
 
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-ppc64/processor.h	Tue Aug 27 12:27:59 2002
@@ -274,16 +274,10 @@
 #define	SPRN_SPRG3	0x113	/* Special Purpose Register General 3 */
 #define	SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 #define	SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
-#define	SPRN_SRR2	0x3DE	/* Save/Restore Register 2 */
-#define	SPRN_SRR3 	0x3DF	/* Save/Restore Register 3 */
-#define	SPRN_TBHI	0x3DC	/* Time Base High */
-#define	SPRN_TBHU	0x3CC	/* Time Base High User-mode */
-#define	SPRN_TBLO	0x3DD	/* Time Base Low */
-#define	SPRN_TBLU	0x3CD	/* Time Base Low User-mode */
-#define	SPRN_TBRL	0x10D	/* Time Base Read Lower Register */
-#define	SPRN_TBRU	0x10C	/* Time Base Read Upper Register */
-#define	SPRN_TBWL	0x11D	/* Time Base Write Lower Register */
-#define	SPRN_TBWU	0x11C	/* Time Base Write Upper Register */
+#define	SPRN_TBRL	0x10C	/* Time Base Read Lower Register (user, R/O) */
+#define	SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
+#define	SPRN_TBWL	0x11C	/* Time Base Lower Register (super, W/O) */
+#define	SPRN_TBWU	0x11D	/* Time Base Write Upper Register (super, W/O) */
 #define	SPRN_TCR	0x3DA	/* Timer Control Register */
 #define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
 #define	    WP_2_17		0		/* 2^17 clocks */
@@ -585,6 +579,9 @@
 #define mftb()		({unsigned long rval;	\
 			asm volatile("mftb %0" : "=r" (rval)); rval;})
 
+#define mttbl(v)	asm volatile("mttbl %0":: "r"(v))
+#define mttbu(v)	asm volatile("mttbu %0":: "r"(v))
+
 /* iSeries CTRL register (for runlatch) */
 
 #define CTRLT		0x098
@@ -655,6 +652,7 @@
 	mm_segment_t	fs;		/* for get_fs() validation */
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr;		/* Floating point status */
+	unsigned int	fpexc_mode;	/* Floating-point exception mode */
 };
 
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
@@ -664,7 +662,8 @@
 	(struct pt_regs *)INIT_SP - 1, /* regs */ \
 	KERNEL_DS, /*fs*/ \
 	{0}, /* fpr */ \
-	0 /* fpscr */ \
+	0, /* fpscr */ \
+	MSR_FE0|MSR_FE1, /* fpexc_mode */ \
 }
 
 /*
@@ -692,7 +691,24 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
-#define cpu_relax()     barrier()
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
+static inline unsigned int __unpack_fe01(unsigned long msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned int __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+#define cpu_relax()	do { HMT_low(); HMT_medium(); barrier(); } while (0)
 
 /*
  * Prefetch macros.
diff -Nru a/include/asm-ppc64/rwsem.h b/include/asm-ppc64/rwsem.h
--- a/include/asm-ppc64/rwsem.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-ppc64/rwsem.h	Tue Aug 27 12:28:08 2002
@@ -57,6 +57,7 @@
 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
 
 static inline void init_rwsem(struct rw_semaphore *sem)
 {
@@ -73,12 +74,26 @@
  */
 static inline void __down_read(struct rw_semaphore *sem)
 {
-	if (atomic_inc_return((atomic_t *)(&sem->count)) >= 0)
+	if (atomic_inc_return((atomic_t *)(&sem->count)) > 0)
 		smp_wmb();
 	else
 		rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -94,6 +109,16 @@
 		rwsem_down_write_failed(sem);
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
@@ -124,6 +149,19 @@
 static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
 {
 	atomic_add(delta, (atomic_t *)(&sem->count));
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	smp_wmb();
+	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+	if (tmp < 0)
+		rwsem_downgrade_wake(sem);
 }
 
 /*
diff -Nru a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h
--- a/include/asm-ppc64/smp.h	Tue Aug 27 12:27:39 2002
+++ b/include/asm-ppc64/smp.h	Tue Aug 27 12:27:39 2002
@@ -30,7 +30,6 @@
 extern unsigned long cpu_online_map;
 
 extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
-extern void smp_store_cpu_info(int id);
 extern void smp_send_tlb_invalidate(int);
 extern void smp_send_xmon_break(int cpu);
 struct pt_regs;
@@ -57,9 +56,7 @@
 
 #define smp_processor_id() (get_paca()->xPacaIndex)
 
-/* remove when the boot sequence gets rewritten to use hotplug interface */
 extern int boot_cpuid;
-extern int ppc64_is_smp;
 
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  *
diff -Nru a/include/asm-ppc64/smplock.h b/include/asm-ppc64/smplock.h
--- a/include/asm-ppc64/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- *
- * 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.
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_unlock(&kernel_flag);	\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-static __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-static __inline__ void unlock_kernel(void)
-{
-	if (current->lock_depth < 0)
-		BUG();
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
diff -Nru a/include/asm-ppc64/softirq.h b/include/asm-ppc64/softirq.h
--- a/include/asm-ppc64/softirq.h	Tue Aug 27 12:27:51 2002
+++ b/include/asm-ppc64/softirq.h	Tue Aug 27 12:27:51 2002
@@ -12,24 +12,16 @@
 #include <asm/hardirq.h>
 
 #define local_bh_disable() \
-		do { preempt_count() += IRQ_OFFSET; barrier(); } while (0)
-
+		do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0)
 #define __local_bh_enable() \
-		do { barrier(); preempt_count() -= IRQ_OFFSET; } while (0)
+		do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
 
-#define local_bh_enable() \
-do { \
-	if (unlikely((preempt_count() == IRQ_OFFSET) && \
-		     softirq_pending(smp_processor_id()))) { \
-		__local_bh_enable(); \
-		do_softirq(); \
-		preempt_check_resched(); \
-	} else { \
-		__local_bh_enable(); \
-		preempt_check_resched(); \
-	} \
+#define local_bh_enable()						\
+do {									\
+	__local_bh_enable();						\
+	if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \
+		do_softirq();						\
+	preempt_check_resched();					\
 } while (0)
-
-#define in_softirq() in_interrupt()
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -Nru a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h
--- a/include/asm-ppc64/spinlock.h	Tue Aug 27 12:27:57 2002
+++ b/include/asm-ppc64/spinlock.h	Tue Aug 27 12:27:57 2002
@@ -210,7 +210,7 @@
 }
 
 #define spin_lock_init(x)      do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
-#define spin_unlock_wait(x)    do { barrier(); } while(spin_is_locked(x))
+#define spin_unlock_wait(x)    do { cpu_relax(); } while(spin_is_locked(x))
 
 #define rwlock_init(x)         do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
diff -Nru a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
--- a/include/asm-ppc64/system.h	Tue Aug 27 12:28:05 2002
+++ b/include/asm-ppc64/system.h	Tue Aug 27 12:28:05 2002
@@ -88,26 +88,18 @@
 extern void __switch_to(struct task_struct *, struct task_struct *);
 #define switch_to(prev, next, last) __switch_to((prev), (next))
 
-#define prepare_arch_schedule(prev)		do { } while(0)
-#define finish_arch_schedule(prev)		do { } while(0)
-#define prepare_arch_switch(rq)			do { } while(0)
-#define finish_arch_switch(rq)			spin_unlock_irq(&(rq)->lock)
-
 struct thread_struct;
 extern void _switch(struct thread_struct *prev, struct thread_struct *next);
 
 struct pt_regs;
 extern void dump_regs(struct pt_regs *);
 
-#ifndef CONFIG_SMP
-
-#define cli()	local_irq_disable()
-#define sti()	local_irq_enable()
-#define save_flags(flags)	local_save_flags(flags)
-#define restore_flags(flags)	local_irq_restore(flags)
-#define save_and_cli(flags)	local_irq_save(flags)
-
-#endif /* !CONFIG_SMP */
+#define irqs_disabled()				\
+({						\
+	unsigned long flags;			\
+	local_save_flags(flags);		\
+	!(flags & MSR_EE);			\
+})
 
 static __inline__ int __is_processor(unsigned long pv)
 {
diff -Nru a/include/asm-ppc64/thread_info.h b/include/asm-ppc64/thread_info.h
--- a/include/asm-ppc64/thread_info.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-ppc64/thread_info.h	Tue Aug 27 12:27:59 2002
@@ -27,6 +27,8 @@
 
 /*
  * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)			\
 {						\
@@ -34,6 +36,7 @@
 	exec_domain:	&default_exec_domain,	\
 	flags:		0,			\
 	cpu:		0,			\
+	preempt_count:	1,			\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Tue Aug 27 12:27:51 2002
+++ b/include/asm-ppc64/unistd.h	Tue Aug 27 12:27:51 2002
@@ -200,6 +200,7 @@
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
 #define __NR_ugetrlimit		190	/* SuS compliant getrlimit */
+#define __NR_readahead		191
 #define __NR_mmap2		192
 #define __NR_truncate64		193
 #define __NR_ftruncate64	194
@@ -230,15 +231,10 @@
 #define __NR_lremovexattr	219
 #define __NR_fremovexattr	220
 #define __NR_futex		221
-#define __NR_tux		222
-#define __NR_sched_setaffinity	223     
-#define __NR_sched_getaffinity	224
-
-#if 0
-/* Remind paulus to add these into ppc32 */
-__NR_security
-__NR_readahead
-#endif
+#define __NR_sched_setaffinity	222     
+#define __NR_sched_getaffinity	223
+#define __NR_security		224
+#define __NR_tuxcall		225
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-s390/smplock.h b/include/asm-s390/smplock.h
--- a/include/asm-s390/smplock.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,62 +0,0 @@
-/*
- *  include/asm-s390/smplock.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/smplock.h"
- */
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()                spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu)     \
-do {                                       \
-	if (task->lock_depth >= 0)         \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu);              \
-	local_irq_enable();                           \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)        \
-do {                                       \
-	if (task->lock_depth >= 0)         \
-		spin_lock(&kernel_flag);   \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-        if (!++current->lock_depth)
-                spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-        if (--current->lock_depth < 0)
-                spin_unlock(&kernel_flag);
-}
-
diff -Nru a/include/asm-s390x/smplock.h b/include/asm-s390x/smplock.h
--- a/include/asm-s390x/smplock.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,62 +0,0 @@
-/*
- *  include/asm-s390/smplock.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/smplock.h"
- */
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()                spin_is_locked(&kernel_flag)
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu)     \
-do {                                       \
-	if (task->lock_depth >= 0)         \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu);              \
-	local_irq_enable();                           \
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)        \
-do {                                       \
-	if (task->lock_depth >= 0)         \
-		spin_lock(&kernel_flag);   \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-        if (!++current->lock_depth)
-                spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-        if (--current->lock_depth < 0)
-                spin_unlock(&kernel_flag);
-}
-
diff -Nru a/include/asm-sh/keyboard.h b/include/asm-sh/keyboard.h
--- a/include/asm-sh/keyboard.h	Tue Aug 27 12:28:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,57 +0,0 @@
-#ifndef	__ASM_SH_KEYBOARD_H
-#define	__ASM_SH_KEYBOARD_H
-/*
- *	$Id: keyboard.h,v 1.12 2001/09/06 04:01:41 gniibe Exp $
- */
-
-#include <linux/kd.h>
-#include <linux/config.h>
-#include <asm/machvec.h>
-
-#ifdef CONFIG_SH_EC3104
-#include <asm/keyboard-ec3104.h>
-#else
-static __inline__ int kbd_setkeycode(unsigned int scancode,
-				     unsigned int keycode)
-{
-    return -EOPNOTSUPP;
-}
-
-static __inline__ int kbd_getkeycode(unsigned int scancode)
-{
-    return scancode > 127 ? -EINVAL : scancode;
-}
-
-#ifdef CONFIG_SH_DREAMCAST
-extern int kbd_translate(unsigned char scancode, unsigned char *keycode,
-			 char raw_mode);
-#else
-static __inline__ int kbd_translate(unsigned char scancode,
-				    unsigned char *keycode, char raw_mode)
-{
-    *keycode = scancode;
-    return 1;
-}
-#endif
-
-static __inline__ char kbd_unexpected_up(unsigned char keycode)
-{
-    return 0200;
-}
-
-static __inline__ void kbd_leds(unsigned char leds)
-{
-}
-
-extern void hp600_kbd_init_hw(void);
-extern void dreamcast_kbd_init_hw(void);
-
-static __inline__ void kbd_init_hw(void)
-{
-	if (MACH_HP600) {
-		hp600_kbd_init_hw();
-	}
-}
-
-#endif
-#endif
diff -Nru a/include/asm-sh/smplock.h b/include/asm-sh/smplock.h
--- a/include/asm-sh/smplock.h	Tue Aug 27 12:28:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-#ifndef __ASM_SH_SMPLOCK_H
-#define __ASM_SH_SMPLOCK_H
-
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/config.h>
-
-#ifndef CONFIG_SMP
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-#error "We do not support SMP on SH"
-#endif /* CONFIG_SMP */
-
-#endif /* __ASM_SH_SMPLOCK_H */
diff -Nru a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h
--- a/include/asm-sparc/hardirq.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-sparc/hardirq.h	Tue Aug 27 12:28:08 2002
@@ -12,47 +12,108 @@
 #include <linux/brlock.h>
 #include <linux/spinlock.h>
 
-/* entry.S is sensitive to the offsets of these fields */
+/* entry.S is sensitive to the offsets of these fields */ /* XXX P3 Is it? */
 typedef struct {
 	unsigned int __softirq_pending;
 	unsigned int __unused_1;
 #ifndef CONFIG_SMP
-	unsigned int __local_irq_count;
+	unsigned int WAS__local_irq_count;
 #else
 	unsigned int __unused_on_SMP;	/* DaveM says use brlock for SMP irq. KAO */
 #endif
-	unsigned int __local_bh_count;
+	unsigned int WAS__local_bh_count;
 	unsigned int __syscall_count;
         struct task_struct * __ksoftirqd_task;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
-/* Note that local_irq_count() is replaced by sparc64 specific version for SMP */
 
-#ifndef CONFIG_SMP
-#define irq_enter(cpu, irq)	((void)(irq), local_irq_count(cpu)++)
-#define irq_exit(cpu, irq)	((void)(irq), local_irq_count(cpu)--)
-#else
-#undef local_irq_count
-#define local_irq_count(cpu)	(__brlock_array[cpu][BR_GLOBALIRQ_LOCK])
-#define irq_enter(cpu, irq)	br_read_lock(BR_GLOBALIRQ_LOCK)
-#define irq_exit(cpu, irq)	br_read_unlock(BR_GLOBALIRQ_LOCK)
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * HARDIRQ_MASK: 0x0000ff00
+ * SOFTIRQ_MASK: 0x00ff0000
+ */
+
+#define PREEMPT_BITS    8
+#define SOFTIRQ_BITS    8
+#define HARDIRQ_BITS    8
+
+#define PREEMPT_SHIFT   0
+#define SOFTIRQ_SHIFT   (PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT   (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+#define __MASK(x)       ((1UL << (x))-1)
+
+#define PREEMPT_MASK    (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define HARDIRQ_MASK    (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define SOFTIRQ_MASK    (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+
+#define hardirq_count() (preempt_count() & HARDIRQ_MASK)
+#define softirq_count() (preempt_count() & SOFTIRQ_MASK)
+#define irq_count()     (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+#define PREEMPT_OFFSET  (1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET  (1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET  (1UL << HARDIRQ_SHIFT)
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
 #endif
 
 /*
- * Are we in an interrupt context? Either doing bottom half
- * or hardware interrupt processing?
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
  */
-#define in_interrupt() ((local_irq_count(smp_processor_id()) + \
-		         local_bh_count(smp_processor_id())) != 0)
+#define in_irq()                (hardirq_count())
+#define in_softirq()            (softirq_count())
+#define in_interrupt()          (irq_count())
 
-/* This tests only the local processors hw IRQ context disposition.  */
-#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
+#define hardirq_trylock()       (!in_interrupt())
+#define hardirq_endlock()       do { } while (0)
 
 #ifndef CONFIG_SMP
+#define irq_enter()             (preempt_count() += HARDIRQ_OFFSET)
 
-#define hardirq_trylock(cpu)	((void)(cpu), local_irq_count(smp_processor_id()) == 0)
-#define hardirq_endlock(cpu)	do { (void)(cpu); } while(0)
+#if CONFIG_PREEMPT
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#else
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+#define irq_exit()                                                      \
+do {                                                                    \
+                preempt_count() -= IRQ_EXIT_OFFSET;                     \
+                if (!in_interrupt() && softirq_pending(smp_processor_id())) \
+                        do_softirq();                                   \
+                preempt_enable_no_resched();                            \
+} while (0)
+
+#else
+
+/* Note that local_irq_count() is replaced by sparc64 specific version for SMP */
+
+/* XXX This is likely to be broken by the above preempt-based IRQs */
+#define irq_enter()		br_read_lock(BR_GLOBALIRQ_LOCK)
+#undef local_irq_count
+#define local_irq_count(cpu)	(__brlock_array[cpu][BR_GLOBALIRQ_LOCK])
+#define irq_exit()		br_read_unlock(BR_GLOBALIRQ_LOCK)
+#endif
+
+#ifndef CONFIG_SMP
 
 #define synchronize_irq()	barrier()
 
@@ -79,17 +140,19 @@
 	}
 }
 
+#if 0
 static inline int hardirq_trylock(int cpu)
 {
 	spinlock_t *lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;
 
 	return (!local_irq_count(cpu) && !spin_is_locked(lock));
 }
+#endif
 
-#define hardirq_endlock(cpu)	do { (void)(cpu); } while (0)
-
-extern void synchronize_irq(void);
+extern void synchronize_irq(unsigned int irq);
 
 #endif /* CONFIG_SMP */
+
+// extern void show_stack(unsigned long * esp);
 
 #endif /* __SPARC_HARDIRQ_H */
diff -Nru a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
--- a/include/asm-sparc/ide.h	Tue Aug 27 12:28:06 2002
+++ b/include/asm-sparc/ide.h	Tue Aug 27 12:28:06 2002
@@ -66,16 +66,24 @@
 	for (index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw);
+		ide_register_hw(&hw, NULL);
 	}
 #endif
 }
 
-#undef  SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS 0
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
 
-#undef  HD_DATA
-#define HD_DATA ((ide_ioreg_t)0)
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 /* From m68k code... */
 
diff -Nru a/include/asm-sparc/keyboard.h b/include/asm-sparc/keyboard.h
--- a/include/asm-sparc/keyboard.h	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,79 +0,0 @@
-/* $Id: keyboard.h,v 1.8 2002/01/08 16:00:20 davem Exp $
- * linux/include/asm-sparc/keyboard.h
- *
- * sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
- */
-
-/*
- *  This file contains the Ultra/PCI architecture specific keyboard definitions
- */
-
-#ifndef _SPARC_KEYBOARD_H
-#define _SPARC_KEYBOARD_H 1
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <asm/io.h>
-
-#define KEYBOARD_IRQ			13
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-
-extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pcikbd_getkeycode(unsigned int scancode);
-extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
-			    char raw_mode);
-extern char pcikbd_unexpected_up(unsigned char keycode);
-extern void pcikbd_leds(unsigned char leds);
-extern void pcikbd_init_hw(void);
-extern unsigned char pcikbd_sysrq_xlate[128];
-
-#define kbd_setkeycode			pcikbd_setkeycode
-#define kbd_getkeycode			pcikbd_getkeycode
-#define kbd_translate			pcikbd_translate
-#define kbd_unexpected_up		pcikbd_unexpected_up
-#define kbd_leds			pcikbd_leds
-#define kbd_init_hw			pcikbd_init_hw
-#define kbd_sysrq_xlate			pcikbd_sysrq_xlate
-#define kbd_init			pcikbd_init
-
-#define compute_shiftstate		pci_compute_shiftstate
-#define getkeycode			pci_getkeycode
-#define setkeycode			pci_setkeycode
-#define getledstate			pci_getledstate
-#define setledstate			pci_setledstate
-#define register_leds			pci_register_leds
-
-/* #define SYSRQ_KEY 0x54 */	/* sparc64 */
-#define SYSRQ_KEY 0x63		/* sparc */
-
-/* resource allocation */
-#define kbd_request_region() request_region(0x60, 16, "keyboard")
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input() inb(KBD_DATA_REG)
-#define kbd_read_status() inb(KBD_STATUS_REG)
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ 12
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-
-#endif /* !(_SPARC_KEYBOARD_H) */
diff -Nru a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
--- a/include/asm-sparc/oplib.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-sparc/oplib.h	Tue Aug 27 12:28:08 2002
@@ -153,8 +153,9 @@
 /* Blocking put character to console. */
 extern void prom_putchar(char character);
 
-/* Prom's internal printf routine, don't use in kernel/boot code. */
-void prom_printf(char *fmt, ...);
+/* Prom's internal routines, don't use in kernel/boot code. */
+extern void prom_printf(char *fmt, ...);
+extern void prom_write(const char *buf, unsigned int len);
 
 /* Query for input device type */
 
diff -Nru a/include/asm-sparc/page.h b/include/asm-sparc/page.h
--- a/include/asm-sparc/page.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc/page.h	Tue Aug 27 12:28:02 2002
@@ -24,7 +24,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm/head.h>       /* for KERNBASE */
+/* #include <asm/head.h> XXX */      /* for KERNBASE */
 #include <asm/btfixup.h>
 
 #ifndef __ASSEMBLY__
@@ -89,7 +89,7 @@
  */
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long iopte; } iopte_t;
-typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pmdv[16]; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long ctxd; } ctxd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
@@ -97,7 +97,7 @@
 
 #define pte_val(x)	((x).pte)
 #define iopte_val(x)	((x).iopte)
-#define pmd_val(x)      ((x).pmd)
+#define pmd_val(x)      ((x).pmdv[0])
 #define pgd_val(x)	((x).pgd)
 #define ctxd_val(x)	((x).ctxd)
 #define pgprot_val(x)	((x).pgprot)
@@ -105,7 +105,7 @@
 
 #define __pte(x)	((pte_t) { (x) } )
 #define __iopte(x)	((iopte_t) { (x) } )
-#define __pmd(x)        ((pmd_t) { (x) } )
+/* #define __pmd(x)        ((pmd_t) { (x) } ) */ /* XXX procedure with loop */
 #define __pgd(x)	((pgd_t) { (x) } )
 #define __ctxd(x)	((ctxd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
@@ -117,7 +117,7 @@
  */
 typedef unsigned long pte_t;
 typedef unsigned long iopte_t;
-typedef unsigned long pmd_t;
+typedef struct { unsigned long pmdv[16]; } pmd_t;
 typedef unsigned long pgd_t;
 typedef unsigned long ctxd_t;
 typedef unsigned long pgprot_t;
@@ -125,7 +125,7 @@
 
 #define pte_val(x)	(x)
 #define iopte_val(x)	(x)
-#define pmd_val(x)      (x)
+#define pmd_val(x)      ((x).pmdv[0])
 #define pgd_val(x)	(x)
 #define ctxd_val(x)	(x)
 #define pgprot_val(x)	(x)
@@ -133,7 +133,7 @@
 
 #define __pte(x)	(x)
 #define __iopte(x)	(x)
-#define __pmd(x)        (x)
+/* #define __pmd(x)        (x) */ /* XXX later */
 #define __pgd(x)	(x)
 #define __ctxd(x)	(x)
 #define __pgprot(x)	(x)
diff -Nru a/include/asm-sparc/pgalloc.h b/include/asm-sparc/pgalloc.h
--- a/include/asm-sparc/pgalloc.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-sparc/pgalloc.h	Tue Aug 27 12:27:59 2002
@@ -40,13 +40,8 @@
 #define pgd_set(pgdp,pmdp) BTFIXUP_CALL(pgd_set)(pgdp,pmdp)
 #define pgd_populate(MM, PGD, PMD)      pgd_set(PGD, PMD)
 
-static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-	return 0;
-}
-
-BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one_fast, struct mm_struct *, unsigned long)
-#define pmd_alloc_one_fast(mm, address)	BTFIXUP_CALL(pmd_alloc_one_fast)(mm, address)
+BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one, struct mm_struct *, unsigned long)
+#define pmd_alloc_one(mm, address)	BTFIXUP_CALL(pmd_alloc_one)(mm, address)
 
 BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *)
 #define free_pmd_fast(pmd)	BTFIXUP_CALL(free_pmd_fast)(pmd)
@@ -65,8 +60,7 @@
 #define pte_alloc_one_kernel(mm, addr)	BTFIXUP_CALL(pte_alloc_one_kernel)(mm, addr)
 
 BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *)
-#define free_pte_fast(pte)	BTFIXUP_CALL(free_pte_fast)(pte)
-#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free_kernel(pte)	BTFIXUP_CALL(free_pte_fast)(pte)
 
 BTFIXUPDEF_CALL(void, pte_free, struct page *)
 #define pte_free(pte)		BTFIXUP_CALL(pte_free)(pte)
diff -Nru a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
--- a/include/asm-sparc/pgtable.h	Tue Aug 27 12:28:07 2002
+++ b/include/asm-sparc/pgtable.h	Tue Aug 27 12:28:07 2002
@@ -11,9 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/spinlock.h>
-/* XXX This creates many nasty warnings. */
-/* #include <linux/highmem.h> */	/* kmap_atomic in pte_offset_map */
-#include <asm/asi.h>
+/* #include <asm/asi.h> */	/* doesn't seem like being used XXX */
 #ifdef CONFIG_SUN4
 #include <asm/pgtsun4.h>
 #else
@@ -32,10 +30,6 @@
 
 extern void load_mmu(void);
 extern unsigned long calc_highpages(void);
-			       
-BTFIXUPDEF_CALL(void, quick_kernel_fault, unsigned long)
-
-#define quick_kernel_fault(addr) BTFIXUP_CALL(quick_kernel_fault)(addr)
 
 /* Routines for data transfer buffers. */
 BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
@@ -187,16 +181,10 @@
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR      (8*sizeof(unsigned long))
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK          (~(sizeof(void*)-1))
-
-#define SIZEOF_PTR_LOG2   2
+#define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page))
 
+/*
+ */
 BTFIXUPDEF_CALL_CONST(struct page *, pmd_page, pmd_t)
 BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page, pgd_t)
 
@@ -340,20 +328,15 @@
 BTFIXUPDEF_CALL(pte_t *, pte_offset_kernel, pmd_t *, unsigned long)
 #define pte_offset_kernel(dir,addr) BTFIXUP_CALL(pte_offset_kernel)(dir,addr)
 
-/* __pte_offset is not BTFIXUP-ed, but PTRS_PER_PTE is, so it's ok. */
-#define __pte_offset(address) \
-	(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#if 0 /* XXX Should we expose pmd_page_kernel? */
-#define pte_offset_kernel(dir, addr) \
-	((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(addr))
-#endif
-#define pte_offset_map(dir, addr) \
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + __pte_offset(addr))
-#define pte_offset_map_nested(dir, addr) \
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + __pte_offset(addr))
+/*
+ * This shortcut works on sun4m (and sun4d) because the nocache area is static,
+ * and sun4c is guaranteed to have no highmem anyway.
+ */
+#define pte_offset_map(d, a)		pte_offset_kernel(d,a)
+#define pte_offset_map_nested(d, a)	pte_offset_kernel(d,a)
 
-#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
+#define pte_unmap(pte)		do{}while(0)
+#define pte_unmap_nested(pte)	do{}while(0)
 
 /* The permissions for pgprot_val to make a page mapped on the obio space */
 extern unsigned int pg_iobits;
diff -Nru a/include/asm-sparc/pgtsrmmu.h b/include/asm-sparc/pgtsrmmu.h
--- a/include/asm-sparc/pgtsrmmu.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc/pgtsrmmu.h	Tue Aug 27 12:28:02 2002
@@ -10,11 +10,11 @@
 #include <asm/page.h>
 #include <asm/thread_info.h>	/* TI_UWINMASK for WINDOW_FLUSH */
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
+/* PMD_SHIFT determines the size of the area a second-level page table entry can map */
 #define SRMMU_PMD_SHIFT         18
 #define SRMMU_PMD_SIZE          (1UL << SRMMU_PMD_SHIFT)
 #define SRMMU_PMD_MASK          (~(SRMMU_PMD_SIZE-1))
-#define SRMMU_PMD_ALIGN(addr)   (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+/* #define SRMMU_PMD_ALIGN(addr)   (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK) */
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
 #define SRMMU_PGDIR_SHIFT       24
diff -Nru a/include/asm-sparc/smplock.h b/include/asm-sparc/smplock.h
--- a/include/asm-sparc/smplock.h	Tue Aug 27 12:28:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#define kernel_locked()			\
-	(spin_is_locked(&kernel_flag) &&\
-	 (current->lock_depth >= 0))
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0)) {	\
-		spin_unlock(&kernel_flag);	\
-		release_irqlock(cpu);		\
-		local_irq_enable();			\
-	}					\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-#define lock_kernel()				\
-do {						\
-	if (!++current->lock_depth)		\
-		spin_lock(&kernel_flag);	\
-} while(0)
-
-#define unlock_kernel()				\
-do {						\
-	if (--current->lock_depth < 0)		\
-		spin_unlock(&kernel_flag);	\
-} while(0)
diff -Nru a/include/asm-sparc/softirq.h b/include/asm-sparc/softirq.h
--- a/include/asm-sparc/softirq.h	Tue Aug 27 12:27:57 2002
+++ b/include/asm-sparc/softirq.h	Tue Aug 27 12:27:57 2002
@@ -7,21 +7,25 @@
 #ifndef __SPARC_SOFTIRQ_H
 #define __SPARC_SOFTIRQ_H
 
-#include <linux/threads.h>	/* For NR_CPUS */
+// #include <linux/threads.h>	/* For NR_CPUS */
 
-#include <asm/atomic.h>
+// #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/hardirq.h>
 
-#define local_bh_disable()	(local_bh_count(smp_processor_id())++)
-#define __local_bh_enable()	(local_bh_count(smp_processor_id())--)
+#define local_bh_disable() \
+		do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0)
+#define __local_bh_enable() \
+		do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
+
 #define local_bh_enable()			  \
-do { if (!--local_bh_count(smp_processor_id()) && \
+do {						\
+	__local_bh_enable();			\
+	if (!in_interrupt() &&			\
 	 softirq_pending(smp_processor_id())) {   \
 		do_softirq();			  \
-		local_irq_enable();			  \
      }						  \
+	preempt_check_resched();		  \
 } while (0)
-#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
 #endif	/* __SPARC_SOFTIRQ_H */
diff -Nru a/include/asm-sparc/system.h b/include/asm-sparc/system.h
--- a/include/asm-sparc/system.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-sparc/system.h	Tue Aug 27 12:28:08 2002
@@ -104,7 +104,7 @@
  * XXX prepare_arch_switch() is much smarter than this in sparc64, are we sure?
  * XXX Cosider if doing it the flush_user_windows way is faster (by uwinmask).
  */
-#define prepare_arch_switch(rq) do { \
+#define prepare_arch_switch(rq, next) do { \
 	__asm__ __volatile__( \
 	".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
 	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
@@ -112,7 +112,7 @@
 	"save %sp, -0x40, %sp\n\t" \
 	"restore; restore; restore; restore; restore; restore; restore"); \
 } while(0)
-#define finish_arch_switch(rq)	do{ }while(0)
+#define finish_arch_switch(rq, next)	do{ }while(0)
 
 	/* Much care has gone into this code, do not touch it.
 	 *
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Tue Aug 27 12:27:59 2002
+++ b/include/asm-sparc/unistd.h	Tue Aug 27 12:27:59 2002
@@ -171,7 +171,7 @@
 #define __NR_poll               153 /* Common                                      */
 #define __NR_getdents64		154 /* Linux specific				   */
 #define __NR_fcntl64		155 /* Linux sparc32 Specific                      */
-/* #define __NR_getdirentries   156    SunOS Specific                              */
+#define __NR_security           156 /* getdirentries under SunOS                   */
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
 #define __NR_umount             159 /* Common                                      */
diff -Nru a/include/asm-sparc64/asi.h b/include/asm-sparc64/asi.h
--- a/include/asm-sparc64/asi.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/asi.h	Tue Aug 27 12:28:02 2002
@@ -40,6 +40,7 @@
 #define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag		*/
 #define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag		*/
 #define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag		*/
+#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init			*/
 #define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
 #define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
 #define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag		*/
diff -Nru a/include/asm-sparc64/dcr.h b/include/asm-sparc64/dcr.h
--- a/include/asm-sparc64/dcr.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-sparc64/dcr.h	Tue Aug 27 12:28:08 2002
@@ -2,11 +2,13 @@
 #ifndef _SPARC64_DCR_H
 #define _SPARC64_DCR_H
 
-/* UltraSparc-III Dispatch Control Register, ASR 0x12 */
+/* UltraSparc-III/III+ Dispatch Control Register, ASR 0x12 */
+#define DCR_DPE		0x0000000000001000 /* III+: D$ Parity Error Enable	*/
 #define DCR_OBS		0x0000000000000fc0 /* Observability Bus Controls	*/
 #define DCR_BPE		0x0000000000000020 /* Branch Predict Enable		*/
 #define DCR_RPE		0x0000000000000010 /* Return Address Prediction Enable	*/
 #define DCR_SI		0x0000000000000008 /* Single Instruction Disable	*/
+#define DCR_IPE		0x0000000000000004 /* III+: I$ Parity Error Enable	*/
 #define DCR_IFPOE	0x0000000000000002 /* IRQ FP Operation Enable		*/
 #define DCR_MS		0x0000000000000001 /* Multi-Scalar dispatch		*/
 
diff -Nru a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
--- a/include/asm-sparc64/elf.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/elf.h	Tue Aug 27 12:28:02 2002
@@ -89,7 +89,8 @@
 #define ELF_HWCAP	((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
 			  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
 			  HWCAP_SPARC_V9) | \
-			 ((tlb_type == cheetah) ? HWCAP_SPARC_ULTRA3 : 0))
+			 ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
+			  HWCAP_SPARC_ULTRA3 : 0))
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
diff -Nru a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h
--- a/include/asm-sparc64/head.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/head.h	Tue Aug 27 12:28:02 2002
@@ -8,4 +8,7 @@
 
 #define	PTREGS_OFF	(STACK_BIAS + REGWIN_SZ)
 
+#define CHEETAH_ID	0x003e0014
+#define CHEETAH_PLUS_ID	0x003e0015
+
 #endif /* !(_SPARC64_HEAD_H) */
diff -Nru a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/ide.h	Tue Aug 27 12:28:02 2002
@@ -62,16 +62,25 @@
 	for (index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw);
+		ide_register_hw(&hw, NULL);
 	}
 #endif
 }
 
-#undef  SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS 0
 
-#undef  HD_DATA
-#define HD_DATA ((ide_ioreg_t)0)
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 /* From m68k code... */
 
diff -Nru a/include/asm-sparc64/keyboard.h b/include/asm-sparc64/keyboard.h
--- a/include/asm-sparc64/keyboard.h	Tue Aug 27 12:28:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/* $Id: keyboard.h,v 1.6 2002/01/08 16:00:20 davem Exp $
- * linux/include/asm-sparc64/keyboard.h
- *
- * Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
- */
-
-/*
- *  This file contains the Ultra/PCI architecture specific keyboard definitions
- */
-
-#ifndef _SPARC64_KEYBOARD_H
-#define _SPARC64_KEYBOARD_H 1
-
-#ifdef __KERNEL__
-
-/* We use the generic input layer for keyboard handling, thus
- * some of this stuff should never be invoked.
- */
-#define kbd_setkeycode(scancode, keycode)	(BUG(), 0)
-#define kbd_getkeycode(scancode)		(BUG(), 0)
-
-#define kbd_translate(keycode, keycodep, raw_mode) \
-	({ *(keycodep) = scancode; 1; })
-#define kbd_unexpected_up(keycode)		(0200)
-
-#define kbd_leds(leds)				do { } while (0)
-#define kbd_init_hw()				do { } while (0)
-
-#define SYSRQ_KEY 0x54
-extern unsigned char kbd_sysrq_xlate[128];
-
-#endif /* __KERNEL__ */
-
-#endif /* !(_SPARC64_KEYBOARD_H) */
diff -Nru a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
--- a/include/asm-sparc64/oplib.h	Tue Aug 27 12:28:08 2002
+++ b/include/asm-sparc64/oplib.h	Tue Aug 27 12:28:08 2002
@@ -153,8 +153,9 @@
 /* Blocking put character to console. */
 extern void prom_putchar(char character);
 
-/* Prom's internal printf routine, don't use in kernel/boot code. */
-void prom_printf(char *fmt, ...);
+/* Prom's internal routines, don't use in kernel/boot code. */
+extern void prom_printf(char *fmt, ...);
+extern void prom_write(const char *buf, unsigned int len);
 
 /* Query for input device type */
 
diff -Nru a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
--- a/include/asm-sparc64/smp.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/smp.h	Tue Aug 27 12:28:02 2002
@@ -91,7 +91,7 @@
 
 extern __inline__ int hard_smp_processor_id(void)
 {
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		unsigned long safari_config;
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (safari_config)
diff -Nru a/include/asm-sparc64/smplock.h b/include/asm-sparc64/smplock.h
--- a/include/asm-sparc64/smplock.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,60 +0,0 @@
-/*
- * <asm/smplock.h>
- *
- * Default SMP lock implementation
- */
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_SMP
-#define kernel_locked()			\
-	(spin_is_locked(&kernel_flag) &&\
-	 (current->lock_depth >= 0))
-#else
-#ifdef CONFIG_PREEMPT
-#define kernel_locked()			preempt_get_count()
-#else
-#define kernel_locked()			1
-#endif
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_unlock(&kernel_flag);	\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task)		\
-do {						\
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag);	\
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-#define lock_kernel()				\
-do {						\
-	if (!++current->lock_depth)		\
-		spin_lock(&kernel_flag);	\
-} while(0)
-
-#define unlock_kernel()				\
-do {						\
-	if (--current->lock_depth < 0)		\
-		spin_unlock(&kernel_flag);	\
-} while(0)
diff -Nru a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h
--- a/include/asm-sparc64/spitfire.h	Tue Aug 27 12:28:02 2002
+++ b/include/asm-sparc64/spitfire.h	Tue Aug 27 12:28:02 2002
@@ -22,6 +22,7 @@
 #define TSB_EXTENSION_P		0x0000000000000048 /* Ultra-III and later		*/
 #define TSB_EXTENSION_S		0x0000000000000050 /* Ultra-III and later, D-TLB only	*/
 #define TSB_EXTENSION_N		0x0000000000000058 /* Ultra-III and later		*/
+#define TLB_TAG_ACCESS_EXT	0x0000000000000060 /* Ultra-III+ and later		*/
 
 /* These registers only exist as one entity, and are accessed
  * via ASI_DMMU only.
@@ -38,12 +39,13 @@
 
 enum ultra_tlb_layout {
 	spitfire = 0,
-	cheetah = 1
+	cheetah = 1,
+	cheetah_plus = 2,
 };
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define SPARC64_USE_STICK	(tlb_type == cheetah)
+#define SPARC64_USE_STICK	(tlb_type != spitfire)
 
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
@@ -433,35 +435,35 @@
 			       "i" (ASI_ITLB_DATA_ACCESS));
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_data(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_data(int entry, int tlb)
 {
 	unsigned long data;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
 			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
 
 	return data;
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry, int tlb)
 {
 	unsigned long tag;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (tag)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
 	return tag;
 }
 
-extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data)
+extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data, int tlb)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "membar	#Sync"
 			     : /* No outputs */
 			     : "r" (data),
-			       "r" ((2 << 16) | (entry << 3)),
+			       "r" ((tlb << 16) | (entry << 3)),
 			       "i" (ASI_DTLB_DATA_ACCESS));
 }
 
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-sparc64/unistd.h	Tue Aug 27 12:28:01 2002
@@ -171,7 +171,7 @@
 #define __NR_poll               153 /* Common                                      */
 #define __NR_getdents64		154 /* Linux specific				   */
 /* #define __NR_fcntl64         155    Linux sparc32 Specific                      */
-/* #define __NR_getdirentries   156    SunOS Specific                              */
+#define __NR_security           156 /* getdirentries under SunOS                   */
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
 #define __NR_umount             159 /* Common                                      */
diff -Nru a/include/asm-x86_64/keyboard.h b/include/asm-x86_64/keyboard.h
--- a/include/asm-x86_64/keyboard.h	Tue Aug 27 12:28:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,71 +0,0 @@
-/*
- *  linux/include/asm-x8664/keyboard.h
- *
- *  Created 3 Nov 1996 by Geert Uytterhoeven
- */
-
-/*
- *  This file contains the x8664 architecture specific keyboard definitions
- */
-
-#ifndef _X8664_KEYBOARD_H
-#define _X8664_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <linux/pm.h>
-#include <asm/io.h>
-
-#define KEYBOARD_IRQ			1
-#define DISABLE_KBD_DURING_INTERRUPTS	0
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode		pckbd_setkeycode
-#define kbd_getkeycode		pckbd_getkeycode
-#define kbd_translate		pckbd_translate
-#define kbd_unexpected_up	pckbd_unexpected_up
-#define kbd_leds		pckbd_leds
-#define kbd_init_hw		pckbd_init_hw
-#define kbd_sysrq_xlate		pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
-
-/* resource allocation */
-#define kbd_request_region()
-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
-                                             "keyboard", NULL)
-
-/* How to access the keyboard macros on this platform.  */
-#define kbd_read_input() inb(KBD_DATA_REG)
-#define kbd_read_status() inb(KBD_STATUS_REG)
-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-
-/* Some stoneage hardware needs delays after some operations.  */
-#define kbd_pause() do { } while(0)
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ 12
-
-#define aux_request_irq(hand, dev_id)					\
-	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
-
-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
-
-#endif /* __KERNEL__ */
-#endif /* _X8664_KEYBOARD_H */
diff -Nru a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
--- a/include/asm-x86_64/percpu.h	Tue Aug 27 12:28:01 2002
+++ b/include/asm-x86_64/percpu.h	Tue Aug 27 12:28:01 2002
@@ -4,7 +4,7 @@
 #include <asm/pda.h>
 
 /* var is in discarded region: offset to particular copy we want */
-#define this_cpu(var)     (*RELOC_HIDE(&var, read_pda(cpudata_offset)))
+#define __get_cpu_var(var)     (*RELOC_HIDE(&var, read_pda(cpudata_offset)))
 #define per_cpu(var, cpu) (*RELOC_HIDE(&var, per_cpu_pda[cpu]))
 
 void setup_per_cpu_areas(void);
diff -Nru a/include/asm-x86_64/smplock.h b/include/asm-x86_64/smplock.h
--- a/include/asm-x86_64/smplock.h	Tue Aug 27 12:28:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,95 +0,0 @@
-/*
- * <asm/smplock.h>
- */
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <asm/current.h>
-
-extern spinlock_t kernel_flag;
-
-#ifdef CONFIG_SMP
-#define kernel_locked()		spin_is_locked(&kernel_flag)
-#define check_irq_holder(cpu) 	\
-	if (global_irq_holder == (cpu))	\
-			BUG();		       
-#else
-#ifdef CONFIG_PREEMPT
-#define kernel_locked()		preempt_get_count()
-#define global_irq_holder 	0
-#define check_irq_holder(cpu) do {} while(0)
-#else
-#define kernel_locked()		1
-#define check_irq_holder(cpu) 	\
-	if (global_irq_holder == (cpu))	\
-			BUG();		       
-#endif
-#endif
-
-/*
- * Release global kernel lock and global interrupt lock
- */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (unlikely(task->lock_depth >= 0)) {	\
-		spin_unlock(&kernel_flag); \
-		check_irq_holder(cpu);	\
-	}					\
-} while (0)
-
-/*
- * Re-acquire the kernel lock
- */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (unlikely(task->lock_depth >= 0))	\
-		spin_lock(&kernel_flag); \
-} while (0)
-
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously,
- * so we only need to worry about other
- * CPU's.
- */
-extern __inline__ void lock_kernel(void)
-{
-#ifdef CONFIG_PREEMPT
-	if (current->lock_depth == -1)
-		spin_lock(&kernel_flag);
-	++current->lock_depth;
-#else
-#if 1
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-#else
-	__asm__ __volatile__(
-		"incl %1\n\t"
-		"jne 9f"
-		spin_lock_string
-		"\n9:"
-		:"=m" (__dummy_lock(&kernel_flag)),
-		 "=m" (current->lock_depth));
-#endif
-#endif
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (current->lock_depth < 0)
-		BUG();
-#if 1
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-#else
-	__asm__ __volatile__(
-		"decl %1\n\t"
-		"jns 9f\n\t"
-		spin_unlock_string
-		"\n9:"
-		:"=m" (__dummy_lock(&kernel_flag)),
-		 "=m" (current->lock_depth));
-#endif
-}
diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h
--- a/include/linux/acpi.h	Tue Aug 27 12:27:42 2002
+++ b/include/linux/acpi.h	Tue Aug 27 12:27:42 2002
@@ -39,7 +39,7 @@
 #include <asm/acpi.h>
 
 
-#ifdef CONFIG_ACPI_BOOT
+#ifdef CONFIG_ACPI
 
 enum acpi_irq_model_id {
 	ACPI_IRQ_MODEL_PIC = 0,
diff -Nru a/include/linux/aio.h b/include/linux/aio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/aio.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,127 @@
+#ifndef __LINUX__AIO_H
+#define __LINUX__AIO_H
+
+#include <linux/tqueue.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+
+#include <linux/aio_abi.h>
+
+#define AIO_MAXSEGS		4
+#define AIO_KIOGRP_NR_ATOMIC	8
+
+struct kioctx;
+
+/* Notes on cancelling a kiocb:
+ *	If a kiocb is cancelled, aio_complete may return 0 to indicate 
+ *	that cancel has not yet disposed of the kiocb.  All cancel 
+ *	operations *must* call aio_put_req to dispose of the kiocb 
+ *	to guard against races with the completion code.
+ */
+#define KIOCB_C_CANCELLED	0x01
+#define KIOCB_C_COMPLETE	0x02
+
+#define KIOCB_PRIVATE_SIZE	(16 * sizeof(long))
+
+struct kiocb {
+	int			ki_users;
+	struct file		*ki_filp;
+	struct kioctx		*ki_ctx;	/* may be NULL for sync ops */
+	int			(*ki_cancel)(struct kiocb *, struct io_event *);
+
+	struct list_head	ki_list;
+
+	void			*ki_data;	/* for use by the the file */
+	void			*ki_user_obj;	/* pointer to userland's iocb */
+	__u64			ki_user_data;	/* user's data for completion */
+	unsigned		ki_key;		/* id of this request */
+
+	long			private[KIOCB_PRIVATE_SIZE/sizeof(long)];
+};
+
+#define init_sync_kiocb(x, filp)	\
+	do {				\
+		(x)->ki_users = 1;	\
+		(x)->ki_filp = (filp);	\
+		(x)->ki_ctx = 0;	\
+		(x)->ki_cancel = NULL;	\
+	} while (0)
+
+#define AIO_RING_MAGIC			0xa10a10a1
+#define AIO_RING_COMPAT_FEATURES	1
+#define AIO_RING_INCOMPAT_FEATURES	0
+struct aio_ring {
+	unsigned	id;	/* kernel internal index number */
+	unsigned	nr;	/* number of io_events */
+	unsigned	head;
+	unsigned	tail;
+
+	unsigned	magic;
+	unsigned	compat_features;
+	unsigned	incompat_features;
+	unsigned	header_length;	/* size of aio_ring */
+
+
+	struct io_event		io_events[0];
+}; /* 128 bytes + ring size */
+
+#define aio_ring_avail(info, ring)	(((ring)->head + (info)->nr - 1 - (ring)->tail) % (info)->nr)
+
+#define AIO_RING_PAGES	8
+struct aio_ring_info {
+	unsigned long		mmap_base;
+	unsigned long		mmap_size;
+
+	struct page		**ring_pages;
+	spinlock_t		ring_lock;
+	long			nr_pages;
+
+	unsigned		nr, tail;
+
+	struct page		*internal_pages[AIO_RING_PAGES];
+};
+
+struct kioctx {
+	atomic_t		users;
+	int			dead;
+	struct mm_struct	*mm;
+
+	/* This needs improving */
+	unsigned long		user_id;
+	struct kioctx		*next;
+
+	wait_queue_head_t	wait;
+
+	spinlock_t		ctx_lock;
+
+	int			reqs_active;
+	struct list_head	active_reqs;	/* used for cancellation */
+
+	unsigned		max_reqs;
+
+	struct aio_ring_info	ring_info;
+};
+
+/* prototypes */
+extern unsigned aio_max_size;
+
+extern int FASTCALL(aio_put_req(struct kiocb *iocb));
+extern int FASTCALL(aio_complete(struct kiocb *iocb, long res, long res2));
+extern void FASTCALL(__put_ioctx(struct kioctx *ctx));
+struct mm_struct;
+extern void FASTCALL(exit_aio(struct mm_struct *mm));
+
+#define get_ioctx(kioctx)	do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0)
+#define put_ioctx(kioctx)	do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0)
+
+#include <linux/aio_abi.h>
+
+static inline struct kiocb *list_kiocb(struct list_head *h)
+{
+	return list_entry(h, struct kiocb, ki_list);
+}
+
+/* for sysctl: */
+extern unsigned aio_max_nr, aio_max_size, aio_max_pinned;
+
+#endif /* __LINUX__AIO_H */
diff -Nru a/include/linux/aio_abi.h b/include/linux/aio_abi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/aio_abi.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,92 @@
+/* linux/aio_abi.h
+ *
+ * Copyright 2000,2001,2002 Red Hat.
+ *
+ * Written by Benjamin LaHaise <bcrl@redhat.com>
+ *
+ * Distribute under the terms of the GPLv2 (see ../../COPYING) or under 
+ * the following terms.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied.  Red Hat makes no representations about
+ * the suitability of this software for any purpose.
+ *
+ * IN NO EVENT SHALL RED HAT BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+ * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RED HAT HAS BEEN ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * RED HAT DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
+ * RED HAT HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ * ENHANCEMENTS, OR MODIFICATIONS.
+ */
+#ifndef __LINUX__AIO_ABI_H
+#define __LINUX__AIO_ABI_H
+
+#include <asm/byteorder.h>
+
+typedef unsigned long	aio_context_t;
+
+enum {
+	IOCB_CMD_PREAD = 0,
+	IOCB_CMD_PWRITE = 1,
+	IOCB_CMD_FSYNC = 2,
+	IOCB_CMD_FDSYNC = 3,
+	/* These two are experimental.
+	 * IOCB_CMD_PREADX = 4,
+	 * IOCB_CMD_POLL = 5,
+	 */
+	IOCB_CMD_NOOP = 6,
+};
+
+/* read() from /dev/aio returns these structures. */
+struct io_event {
+	__u64		data;		/* the data field from the iocb */
+	__u64		obj;		/* what iocb this event came from */
+	__s64		res;		/* result code for this event */
+	__s64		res2;		/* secondary result */
+};
+
+#if defined(__LITTLE_ENDIAN)
+#define PADDED(x,y)	x, y
+#elif defined(__BIG_ENDIAN)
+#define PADDED(x,y)	y, x
+#else
+#error edit for your odd byteorder.
+#endif
+
+/*
+ * we always use a 64bit off_t when communicating
+ * with userland.  its up to libraries to do the
+ * proper padding and aio_error abstraction
+ */
+
+struct iocb {
+	/* these are internal to the kernel/libc. */
+	__u64	aio_data;	/* data to be returned in event's data */
+	__u32	PADDED(aio_key, aio_reserved1);
+				/* the kernel sets aio_key to the req # */
+
+	/* common fields */
+	__u16	aio_lio_opcode;	/* see IOCB_CMD_ above */
+	__s16	aio_reqprio;
+	__u32	aio_fildes;
+
+	__u64	aio_buf;
+	__u64	aio_nbytes;
+	__s64	aio_offset;
+
+	/* extra parameters */
+	__u64	aio_reserved2;	/* TODO: use this for a (struct sigevent *) */
+	__u64	aio_reserved3;
+}; /* 64 bytes */
+
+#undef IFBIG
+#undef IFLITTLE
+
+#endif /* __LINUX__AIO_ABI_H */
+
diff -Nru a/include/linux/apm_bios.h b/include/linux/apm_bios.h
--- a/include/linux/apm_bios.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/apm_bios.h	Tue Aug 27 12:28:07 2002
@@ -21,8 +21,7 @@
 
 #ifdef __KERNEL__
 
-#define APM_40		0x40
-#define APM_CS		(APM_40 + 8)
+#define APM_CS		(GDT_ENTRY_APMBIOS_BASE * 8)
 #define APM_CS_16	(APM_CS + 8)
 #define APM_DS		(APM_CS_16 + 8)
 
diff -Nru a/include/linux/binfmts.h b/include/linux/binfmts.h
--- a/include/linux/binfmts.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/binfmts.h	Tue Aug 27 12:28:07 2002
@@ -1,7 +1,6 @@
 #ifndef _LINUX_BINFMTS_H
 #define _LINUX_BINFMTS_H
 
-#include <linux/ptrace.h>
 #include <linux/capability.h>
 
 /*
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/blkdev.h	Tue Aug 27 12:28:01 2002
@@ -86,7 +86,9 @@
 	__REQ_SENSE,	/* sense retrival */
 
 	__REQ_SPECIAL,	/* driver suplied command */
-
+	__REQ_DRIVE_CMD,
+	__REQ_DRIVE_TASK,
+	__REQ_DRIVE_TASKFILE,
 	__REQ_NR_BITS,	/* stops here */
 };
 
@@ -102,6 +104,9 @@
 #define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
 #define REQ_SENSE	(1 << __REQ_SENSE)
 #define REQ_SPECIAL	(1 << __REQ_SPECIAL)
+#define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
+#define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
+#define REQ_DRIVE_TASKFILE	(1 << __REQ_DRIVE_TASKFILE)
 
 #include <linux/elevator.h>
 
diff -Nru a/include/linux/brlock.h b/include/linux/brlock.h
--- a/include/linux/brlock.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/brlock.h	Tue Aug 27 12:28:02 2002
@@ -29,13 +29,11 @@
  * compare-and-swap cpus (Sparc64).  So we control which
  * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM
  *
- * Added BR_LLC_LOCK for use in net/core/ext8022.c -acme
  */
 
 /* Register bigreader lock indices here. */
 enum brlock_indices {
 	BR_NETPROTO_LOCK,
-	BR_LLC_LOCK,
 	__BR_END
 };
 
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/device.h	Tue Aug 27 12:28:02 2002
@@ -50,6 +50,7 @@
 
 struct device;
 struct device_driver;
+struct device_class;
 
 struct bus_type {
 	char			* name;
@@ -93,9 +94,9 @@
 	ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off);
 };
 
-#define BUS_ATTR(_name,_str,_mode,_show,_store)	\
+#define BUS_ATTR(_name,_mode,_show,_store)	\
 struct bus_attribute bus_attr_##_name = { 		\
-	.attr = {.name	= _str,	.mode	= _mode },	\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
 	.show	= _show,				\
 	.store	= _store,				\
 };
@@ -106,12 +107,14 @@
 struct device_driver {
 	char			* name;
 	struct bus_type		* bus;
+	struct device_class	* devclass;
 
 	rwlock_t		lock;
 	atomic_t		refcount;
 
-	list_t			bus_list;
-	list_t			devices;
+	struct list_head	bus_list;
+	struct list_head	class_list;
+	struct list_head	devices;
 
 	struct driver_dir_entry	dir;
 
@@ -150,9 +153,9 @@
 	ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off);
 };
 
-#define DRIVER_ATTR(_name,_str,_mode,_show,_store)	\
+#define DRIVER_ATTR(_name,_mode,_show,_store)	\
 struct driver_attribute driver_attr_##_name = { 		\
-	.attr = {.name	= _str,	.mode	= _mode },	\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
 	.show	= _show,				\
 	.store	= _store,				\
 };
@@ -160,12 +163,105 @@
 extern int driver_create_file(struct device_driver *, struct driver_attribute *);
 extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
 
+
+/*
+ * device classes
+ */
+struct device_class {
+	char			* name;
+	u32			devnum;
+
+	struct list_head	node;
+	struct list_head	drivers;
+	struct list_head	intf_list;
+
+	struct driver_dir_entry	dir;
+	struct driver_dir_entry	driver_dir;
+	struct driver_dir_entry	device_dir;
+
+	int	(*add_device)(struct device *);
+	void	(*remove_device)(struct device *);
+};
+
+extern int devclass_register(struct device_class *);
+extern void devclass_unregister(struct device_class *);
+
+
+struct devclass_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
+	ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
+};
+
+#define DEVCLASS_ATTR(_name,_str,_mode,_show,_store)	\
+struct devclass_attribute devclass_attr_##_name = { 		\
+	.attr = {.name	= _str,	.mode	= _mode },	\
+	.show	= _show,				\
+	.store	= _store,				\
+};
+
+extern int devclass_create_file(struct device_class *, struct devclass_attribute *);
+extern void devclass_remove_file(struct device_class *, struct devclass_attribute *);
+
+
+/*
+ * device interfaces
+ * These are the logical interfaces of device classes. 
+ * These entities map directly to specific userspace interfaces, like 
+ * device nodes.
+ * Interfaces are registered with the device class they belong to. When
+ * a device is registered with the class, each interface's add_device 
+ * callback is called. It is up to the interface to decide whether or not
+ * it supports the device.
+ */
+
+struct intf_data;
+
+struct device_interface {
+	char			* name;
+	struct device_class	* devclass;
+
+	struct list_head	node;
+	struct list_head	devices;
+	struct driver_dir_entry	dir;
+
+	u32			devnum;
+
+	int (*add_device)	(struct device *);
+	int (*remove_device)	(struct intf_data *);
+};
+
+extern int interface_register(struct device_interface *);
+extern void interface_unregister(struct device_interface *);
+
+
+/*
+ * intf_data - per-device data for an interface
+ * Each interface typically has a per-device data structure 
+ * that it allocates. It should embed one of these structures 
+ * in that structure and call interface_add_data() to add it
+ * to the device's list.
+ * That will also enumerate the device within the interface
+ * and create a driverfs symlink for it.
+ */
+struct intf_data {
+	struct list_head	node;
+	struct device_interface	* intf;
+	struct device		* dev;
+	u32			intf_num;
+};
+
+extern int interface_add_data(struct intf_data *);
+
+
+
 struct device {
 	struct list_head g_list;        /* node in depth-first order list */
 	struct list_head node;		/* node in sibling list */
 	struct list_head bus_list;	/* node in bus's list */
 	struct list_head driver_list;
 	struct list_head children;
+	struct list_head intf_list;
 	struct device 	* parent;
 
 	char	name[DEVICE_NAME_SIZE];	/* descriptive ascii string */
@@ -183,6 +279,8 @@
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
 	void		*driver_data;	/* data private to the driver */
+
+	u32		class_num;	/* class-enumerated value */
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
 					   BIOS data relevant to device) */
 
@@ -222,13 +320,14 @@
 	ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
 };
 
-#define DEVICE_ATTR(_name,_str,_mode,_show,_store)	\
+#define DEVICE_ATTR(_name,_mode,_show,_store) \
 struct device_attribute dev_attr_##_name = { 		\
-	.attr = {.name	= _str,	.mode	= _mode },	\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
 	.show	= _show,				\
 	.store	= _store,				\
 };
 
+
 extern int device_create_file(struct device *device, struct device_attribute * entry);
 extern void device_remove_file(struct device * dev, struct device_attribute * attr);
 
@@ -260,12 +359,7 @@
  * get_device - atomically increment the reference count for the device.
  *
  */
-static inline void get_device(struct device * dev)
-{
-	BUG_ON(!atomic_read(&dev->refcount));
-	atomic_inc(&dev->refcount);
-}
-
+extern struct device * get_device(struct device * dev);
 extern void put_device(struct device * dev);
 
 /* drivers/base/sys.c */
diff -Nru a/include/linux/elfcore.h b/include/linux/elfcore.h
--- a/include/linux/elfcore.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/elfcore.h	Tue Aug 27 12:28:05 2002
@@ -4,7 +4,6 @@
 #include <linux/types.h>
 #include <linux/signal.h>
 #include <linux/time.h>
-#include <linux/ptrace.h>
 #include <linux/user.h>
 
 struct elf_siginfo
diff -Nru a/include/linux/errno.h b/include/linux/errno.h
--- a/include/linux/errno.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/errno.h	Tue Aug 27 12:28:08 2002
@@ -20,6 +20,7 @@
 #define ESERVERFAULT	526	/* An untranslatable error occurred */
 #define EBADTYPE	527	/* Type not supported by server */
 #define EJUKEBOX	528	/* Request initiated, but will not complete before timeout */
+#define EIOCBQUEUED	529	/* iocb queued, will get completion event */
 
 #endif
 
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/fb.h	Tue Aug 27 12:28:02 2002
@@ -316,12 +316,6 @@
     struct module *owner;
     int (*fb_open)(struct fb_info *info, int user);
     int (*fb_release)(struct fb_info *info, int user);
-    /* get non settable parameters */
-    int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
-		      struct fb_info *info); 
-    /* get settable parameters */
-    int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
-		      struct fb_info *info);		
     /* set settable parameters */
     int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
 		      struct fb_info *info);		
@@ -399,10 +393,6 @@
      *  `Generic' versions of the frame buffer device operations
      */
 
-extern int gen_get_fix(struct fb_fix_screeninfo *fix, int con,
-		       struct fb_info *info);
-extern int gen_get_var(struct fb_var_screeninfo *var, int con,
-		       struct fb_info *info);
 extern int gen_set_var(struct fb_var_screeninfo *var, int con,
 		       struct fb_info *info);
 extern int gen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
@@ -419,6 +409,7 @@
      *  Helper functions
      */
 
+extern void do_install_cmap(int con, struct fb_info *info);
 extern int gen_update_var(int con, struct fb_info *info);
 extern int fb_blank(int blank, struct fb_info *info);
 extern int gen_switch(int con, struct fb_info *info);
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/fs.h	Tue Aug 27 12:28:02 2002
@@ -624,8 +624,6 @@
 
 #include <linux/ext3_fs_sb.h>
 #include <linux/hpfs_fs_sb.h>
-#include <linux/ufs_fs_sb.h>
-#include <linux/romfs_fs_sb.h>
 
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
@@ -670,8 +668,6 @@
 	union {
 		struct ext3_sb_info	ext3_sb;
 		struct hpfs_sb_info	hpfs_sb;
-		struct ufs_sb_info	ufs_sb;
-		struct romfs_sb_info	romfs_sb;
 		void			*generic_sbp;
 	} u;
 	/*
@@ -744,11 +740,14 @@
  * read, write, poll, fsync, readv, writev can be called
  *   without the big kernel lock held in all filesystems.
  */
+struct kiocb;
 struct file_operations {
 	struct module *owner;
 	loff_t (*llseek) (struct file *, loff_t, int);
 	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
+	ssize_t (*aio_read) (struct kiocb *, char *, size_t, loff_t);
 	ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
+	ssize_t (*aio_write) (struct kiocb *, char *, size_t, loff_t);
 	int (*readdir) (struct file *, void *, filldir_t);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
@@ -757,6 +756,7 @@
 	int (*flush) (struct file *);
 	int (*release) (struct inode *, struct file *);
 	int (*fsync) (struct file *, struct dentry *, int datasync);
+	int (*aio_fsync) (struct kiocb *, int datasync);
 	int (*fasync) (int, struct file *, int);
 	int (*lock) (struct file *, int, struct file_lock *);
 	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
@@ -1241,6 +1241,7 @@
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t generic_file_write_nolock(struct file *, const char *, size_t, loff_t *);
 extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
 ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf,
diff -Nru a/include/linux/futex.h b/include/linux/futex.h
--- a/include/linux/futex.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/futex.h	Tue Aug 27 12:28:07 2002
@@ -6,4 +6,6 @@
 #define FUTEX_WAKE (1)
 #define FUTEX_FD (2)
 
+extern asmlinkage int sys_futex(void *uaddr, int op, int val, struct timespec *utime);
+
 #endif
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/hdreg.h	Tue Aug 27 12:28:05 2002
@@ -2,23 +2,349 @@
 #define _LINUX_HDREG_H
 
 /*
+ * This file contains some defines for the AT-hd-controller.
+ * Various sources.
+ */
+
+/* ide.c has its own port definitions in "ide.h" */
+
+/* Hd controller regs. Ref: IBM AT Bios-listing */
+#define HD_DATA		0x1f0		/* _CTL when writing */
+#define HD_ERROR	0x1f1		/* see err-bits */
+#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
+#define HD_SECTOR	0x1f3		/* starting sector */
+#define HD_LCYL		0x1f4		/* starting cylinder */
+#define HD_HCYL		0x1f5		/* high byte of starting cyl */
+#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS	0x1f7		/* see status-bits */
+#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
+#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
+#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
+
+#define HD_CMD		0x3f6		/* used for resets */
+#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
+
+/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
+
+/* Bits of HD_STATUS */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define SERVICE_STAT		SEEK_STAT
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+/*
  * Command Header sizes for IOCTL commands
  */
+
 #define HDIO_DRIVE_CMD_HDR_SIZE		(4 * sizeof(u8))
 #define HDIO_DRIVE_HOB_HDR_SIZE		(8 * sizeof(u8))
+#define HDIO_DRIVE_TASK_HDR_SIZE	(8 * sizeof(u8))
+
+#define IDE_DRIVE_TASK_INVALID		-1
+#define IDE_DRIVE_TASK_NO_DATA		0
+#define IDE_DRIVE_TASK_SET_XFER		1
+
+#define IDE_DRIVE_TASK_IN		2
+
+#define IDE_DRIVE_TASK_OUT		3
+#define IDE_DRIVE_TASK_RAW_WRITE	4
+
+/*
+ * Define standard taskfile in/out register
+ */
+#define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
+#define IDE_TASKFILE_STD_IN_FLAGS	0xFE
+#define IDE_HOB_STD_OUT_FLAGS		0x3C     /* sector, nsector lcyl and hcyl */
+#define IDE_HOB_STD_IN_FLAGS		0x3C
+
+typedef unsigned char task_ioreg_t;
+
+typedef union ide_reg_valid_s {
+	unsigned all				: 16;
+	struct {
+		unsigned data			: 1;
+		unsigned error_feature		: 1;
+		unsigned sector			: 1;
+		unsigned nsector		: 1;
+		unsigned lcyl			: 1;
+		unsigned hcyl			: 1;
+		unsigned select			: 1;
+		unsigned status_command		: 1;
+
+		unsigned data_hob		: 1;
+		unsigned error_feature_hob	: 1;
+		unsigned sector_hob		: 1;
+		unsigned nsector_hob		: 1;
+		unsigned lcyl_hob		: 1;
+		unsigned hcyl_hob		: 1;
+		unsigned select_hob		: 1;
+		unsigned control_hob		: 1;
+	} b;
+} ide_reg_valid_t;
+
+typedef struct ide_task_request_s {
+	task_ioreg_t	io_ports[8];
+	task_ioreg_t	hob_ports[8];
+	ide_reg_valid_t	out_flags;
+	ide_reg_valid_t	in_flags;
+	int		data_phase;
+	int		req_cmd;
+	unsigned long	out_size;
+	unsigned long	in_size;
+} ide_task_request_t;
+
+typedef struct ide_ioctl_request_s {
+	ide_task_request_t	*task_request;
+	unsigned char		*out_buffer;
+	unsigned char		*in_buffer;
+} ide_ioctl_request_t;
+
+struct hd_drive_cmd_hdr {
+	task_ioreg_t command;
+	task_ioreg_t sector_number;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+};
+
+typedef struct hd_drive_task_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t command;
+} task_struct_t;
+
+typedef struct hd_drive_hob_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t control;
+} hob_struct_t;
+
+#define TASKFILE_INVALID		0x7fff
+#define TASKFILE_48			0x8000
+
+#define TASKFILE_NO_DATA		0x0000
+
+#define TASKFILE_IN			0x0001
+#define TASKFILE_MULTI_IN		0x0002
+
+#define TASKFILE_OUT			0x0004
+#define TASKFILE_MULTI_OUT		0x0008
+#define TASKFILE_IN_OUT			0x0010
+
+#define TASKFILE_IN_DMA			0x0020
+#define TASKFILE_OUT_DMA		0x0040
+#define TASKFILE_IN_DMAQ		0x0080
+#define TASKFILE_OUT_DMAQ		0x0100
+
+#define TASKFILE_P_IN			0x0200
+#define TASKFILE_P_OUT			0x0400
+#define TASKFILE_P_IN_DMA		0x0800
+#define TASKFILE_P_OUT_DMA		0x1000
+#define TASKFILE_P_IN_DMAQ		0x2000
+#define TASKFILE_P_OUT_DMAQ		0x4000
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP				0x00
+#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+#define WIN_SRST			0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET		0x08
+#define WIN_RECAL			0x10
+#define WIN_RESTORE			0x10
+#define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_EXT			0x24 /* 48-Bit */
+#define WIN_READDMA_EXT			0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+#define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_EXT			0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+#define WIN_FORMAT			0x50
+#define WIN_INIT			0x60
+#define WIN_SEEK			0x70
+#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE			0x90
+#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE		0x92
+#define WIN_STANDBYNOW2			0x94
+#define WIN_SETIDLE2			0x97
+#define WIN_CHECKPOWERMODE2		0x98
+#define WIN_SLEEPNOW2			0x99
+#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
+#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_SMART			0xB0 /* self-monitoring and reporting */
+#define CFA_ERASE_SECTORS		0xC0
+#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS		0xDA
+#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1			0xE0
+#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY			0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1			0xE3
+#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1		0xE5
+#define WIN_SLEEPNOW1			0xE6
+#define WIN_FLUSH_CACHE			0xE7
+#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
+#define WIN_MEDIAEJECT			0xED
+#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES			0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST		0xF0
+#define WIN_SECURITY_SET_PASS		0xF1
+#define WIN_SECURITY_UNLOCK		0xF2
+#define WIN_SECURITY_ERASE_PREPARE	0xF3
+#define WIN_SECURITY_ERASE_UNIT		0xF4
+#define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define WIN_SECURITY_DISABLE		0xF6
+#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
+#define WIN_SET_MAX			0xF9
+#define DISABLE_SEAGATE			0xFB
+
+/* WIN_SMART sub-commands */
+
+#define SMART_READ_VALUES		0xD0
+#define SMART_READ_THRESHOLDS		0xD1
+#define SMART_AUTOSAVE			0xD2
+#define SMART_SAVE			0xD3
+#define SMART_IMMEDIATE_OFFLINE		0xD4
+#define SMART_READ_LOG_SECTOR		0xD5
+#define SMART_WRITE_LOG_SECTOR		0xD6
+#define SMART_WRITE_THRESHOLDS		0xD7
+#define SMART_ENABLE			0xD8
+#define SMART_DISABLE			0xD9
+#define SMART_STATUS			0xDA
+#define SMART_AUTO_OFFLINE		0xDB
+
+/* Password used in TF4 & TF5 executing SMART commands */
+
+#define SMART_LCYL_PASS			0x4F
+#define SMART_HCYL_PASS			0xC2
+
+/* WIN_SETFEATURES sub-commands */
+#define SETFEATURES_EN_8BIT	0x01	/* Enable 8-Bit Transfers */
+#define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
+#define SETFEATURES_XFER	0x03	/* Set transfer mode */
+#	define XFER_UDMA_7	0x47	/* 0100|0111 */
+#	define XFER_UDMA_6	0x46	/* 0100|0110 */
+#	define XFER_UDMA_5	0x45	/* 0100|0101 */
+#	define XFER_UDMA_4	0x44	/* 0100|0100 */
+#	define XFER_UDMA_3	0x43	/* 0100|0011 */
+#	define XFER_UDMA_2	0x42	/* 0100|0010 */
+#	define XFER_UDMA_1	0x41	/* 0100|0001 */
+#	define XFER_UDMA_0	0x40	/* 0100|0000 */
+#	define XFER_MW_DMA_2	0x22	/* 0010|0010 */
+#	define XFER_MW_DMA_1	0x21	/* 0010|0001 */
+#	define XFER_MW_DMA_0	0x20	/* 0010|0000 */
+#	define XFER_SW_DMA_2	0x12	/* 0001|0010 */
+#	define XFER_SW_DMA_1	0x11	/* 0001|0001 */
+#	define XFER_SW_DMA_0	0x10	/* 0001|0000 */
+#	define XFER_PIO_4	0x0C	/* 0000|1100 */
+#	define XFER_PIO_3	0x0B	/* 0000|1011 */
+#	define XFER_PIO_2	0x0A	/* 0000|1010 */
+#	define XFER_PIO_1	0x09	/* 0000|1001 */
+#	define XFER_PIO_0	0x08	/* 0000|1000 */
+#	define XFER_PIO_SLOW	0x00	/* 0000|0000 */
+#define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
+#define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
+#define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_DIS_RETRY	0x33	/* Disable Retry */
+#define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
+#define SETFEATURES_RW_LONG	0x44	/* Set Lenght of VS bytes */
+#define SETFEATURES_SET_CACHE	0x54	/* Set Cache segments to SC Reg. Val */
+#define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
+#define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
+#define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
+#define SETFEATURES_DIS_RPOD	0x66	/* Disable reverting to power on defaults */
+#define SETFEATURES_DIS_ECC	0x77	/* Disable ECC byte count */
+#define SETFEATURES_DIS_8BIT	0x81	/* Disable 8-Bit Transfers */
+#define SETFEATURES_DIS_WCACHE	0x82	/* Disable write cache */
+#define SETFEATURES_EN_DEFECT	0x84	/* Enable Defect Management */
+#define SETFEATURES_DIS_APM	0x85	/* Disable advanced power management */
+#define SETFEATURES_EN_ECC	0x88	/* Enable ECC byte count */
+#define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
+#define SETFEATURES_EN_RETRY	0x99	/* Enable Retry */
+#define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
+#define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_4B_RW_LONG	0xBB	/* Set Lenght of 4 bytes */
+#define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
+#define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
+#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
+#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
+
+/* WIN_SECURITY sub-commands */
+
+#define SECURITY_SET_PASSWORD		0xBA
+#define SECURITY_UNLOCK			0xBB
+#define SECURITY_ERASE_PREPARE		0xBC
+#define SECURITY_ERASE_UNIT		0xBD
+#define SECURITY_FREEZE_LOCK		0xBE
+#define SECURITY_DISABLE_PASSWORD	0xBF
 
 struct hd_geometry {
-      __u8 heads;
-      __u8 sectors;
-      __u16 cylinders;
+      unsigned char heads;
+      unsigned char sectors;
+      unsigned short cylinders;
       unsigned long start;
 };
 
+/* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */
+struct hd_big_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	unsigned long start;
+};
+
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x0304	/* get current IDE blockmode setting */
 #define HDIO_GET_QDMA		0x0305	/* get use-qdma flag */
+#define HDIO_OBSOLETE_IDENTITY	0x0307	/* OBSOLETE, DO NOT USE: returns 142 bytes */
+#define HDIO_GET_KEEPSETTINGS	0x0308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_32BIT		0x0309	/* get current io_32bit setting */
 #define HDIO_GET_NOWERR		0x030a	/* get ignore-write-error flag */
 #define HDIO_GET_DMA		0x030b	/* get use-dma flag */
@@ -29,24 +355,296 @@
 #define	HDIO_GET_ADDRESS	0x0310	/* */
 
 #define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
+#define HDIO_TRISTATE_HWIF	0x031b	/* execute a channel tristate */
+#define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
+#define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
+#define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
 #define HDIO_DRIVE_CMD		0x031f	/* execute a special drive command */
+#define HDIO_DRIVE_CMD_AEB	HDIO_DRIVE_TASK
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
 #define HDIO_SET_MULTCOUNT	0x0321	/* change IDE blockmode */
 #define HDIO_SET_UNMASKINTR	0x0322	/* permit other irqs during I/O */
+#define HDIO_SET_KEEPSETTINGS	0x0323	/* keep ioctl settings on reset */
 #define HDIO_SET_32BIT		0x0324	/* change io_32bit flags */
 #define HDIO_SET_NOWERR		0x0325	/* change ignore-write-error flag */
 #define HDIO_SET_DMA		0x0326	/* change use-dma flag */
 #define HDIO_SET_PIO_MODE	0x0327	/* reconfig interface to new speed */
+#define HDIO_SCAN_HWIF		0x0328	/* register and (re)scan interface */
 #define HDIO_SET_NICE		0x0329	/* set nice flags */
+#define HDIO_UNREGISTER_HWIF	0x032a  /* unregister interface */
 #define HDIO_SET_WCACHE		0x032b	/* change write cache enable-disable */
 #define HDIO_SET_ACOUSTIC	0x032c	/* change acoustic behavior */
 #define HDIO_SET_BUSSTATE	0x032d	/* set the bus state of the hwif */
 #define HDIO_SET_QDMA		0x032e	/* change use-qdma flag */
 #define HDIO_SET_ADDRESS	0x032f	/* change lba addressing modes */
 
+/* bus states */
+enum {
+	BUSSTATE_OFF = 0,
+	BUSSTATE_ON,
+	BUSSTATE_TRISTATE
+};
+
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
 /* 0x330 is reserved - used to be HDIO_GETGEO_BIG */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
-#endif
+#define __NEW_HD_DRIVE_ID
+
+/*
+ * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec.
+ *
+ * If you change something here, please remember to update fix_driveid() in
+ * ide/probe.c.
+ */
+struct hd_driveid {
+	unsigned short	config;		/* lots of obsolete bit flags */
+	unsigned short	cyls;		/* Obsolete, "physical" cyls */
+	unsigned short	reserved2;	/* reserved (word 2) */
+	unsigned short	heads;		/* Obsolete, "physical" heads */
+	unsigned short	track_bytes;	/* unformatted bytes per track */
+	unsigned short	sector_bytes;	/* unformatted bytes per sector */
+	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
+	unsigned short	vendor0;	/* vendor unique */
+	unsigned short	vendor1;	/* vendor unique */
+	unsigned short	vendor2;	/* Retired vendor unique */
+	unsigned char	serial_no[20];	/* 0 = not_specified */
+	unsigned short	buf_type;	/* Retired */
+	unsigned short	buf_size;	/* Retired, 512 byte increments
+					 * 0 = not_specified
+					 */
+	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
+	unsigned char	fw_rev[8];	/* 0 = not_specified */
+	unsigned char	model[40];	/* 0 = not_specified */
+	unsigned char	max_multsect;	/* 0=not_implemented */
+	unsigned char	vendor3;	/* vendor unique */
+	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
+	unsigned char	vendor4;	/* vendor unique */
+	unsigned char	capability;	/* (upper byte of word 49)
+					 *  3:	IORDYsup
+					 *  2:	IORDYsw
+					 *  1:	LBA
+					 *  0:	DMA
+					 */
+	unsigned short	reserved50;	/* reserved (word 50) */
+	unsigned char	vendor5;	/* Obsolete, vendor unique */
+	unsigned char	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned char	vendor6;	/* Obsolete, vendor unique */
+	unsigned char	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned short	field_valid;	/* (word 53)
+					 *  2:	ultra_ok	word  88
+					 *  1:	eide_ok		words 64-70
+					 *  0:	cur_ok		words 54-58
+					 */
+	unsigned short	cur_cyls;	/* Obsolete, logical cylinders */
+	unsigned short	cur_heads;	/* Obsolete, l heads */
+	unsigned short	cur_sectors;	/* Obsolete, l sectors per track */
+	unsigned short	cur_capacity0;	/* Obsolete, l total sectors on drive */
+	unsigned short	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
+	unsigned char	multsect;	/* current multiple sector count */
+	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
+	unsigned int	lba_capacity;	/* Obsolete, total number of sectors */
+	unsigned short	dma_1word;	/* Obsolete, single-word dma info */
+	unsigned short	dma_mword;	/* multiple-word dma info */
+	unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
+	unsigned short  eide_dma_min;	/* min mword dma cycle time (ns) */
+	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
+	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
+	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
+	unsigned short	words69_70[2];	/* reserved words 69-70
+					 * future command overlap and queuing
+					 */
+	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+	unsigned short	words71_74[4];	/* reserved words 71-74
+					 * for IDENTIFY PACKET DEVICE command
+					 */
+	unsigned short  queue_depth;	/* (word 75)
+					 * 15:5	reserved
+					 *  4:0	Maximum queue depth -1
+					 */
+	unsigned short  words76_79[4];	/* reserved words 76-79 */
+	unsigned short  major_rev_num;	/* (word 80) */
+	unsigned short  minor_rev_num;	/* (word 81) */
+	unsigned short  command_set_1;	/* (word 82) supported
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  command_set_2;	/* (word 83)
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  cfsse;		/* (word 84)
+					 * cmd set-feature supported extensions
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  cfs_enable_1;	/* (word 85)
+					 * command set-feature enabled
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  cfs_enable_2;	/* (word 86)
+					 * command set-feature enabled
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  csf_default;	/* (word 87)
+					 * command set-feature default
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  dma_ultra;	/* (word 88) */
+	unsigned short	word89;		/* reserved (word 89) */
+	unsigned short	word90;		/* reserved (word 90) */
+	unsigned short	CurAPMvalues;	/* current APM values */
+	unsigned short	word92;		/* reserved (word 92) */
+	unsigned short	hw_config;	/* hardware config (word 93)
+					 * 15:
+					 * 14:
+					 * 13:
+					 * 12:
+					 * 11:
+					 * 10:
+					 *  9:
+					 *  8:
+					 *  7:
+					 *  6:
+					 *  5:
+					 *  4:
+					 *  3:
+					 *  2:
+					 *  1:
+					 *  0:
+					 */
+	unsigned short	acoustic;	/* (word 94)
+					 * 15:8	Vendor's recommended value
+					 *  7:0	current value
+					 */
+	unsigned short	words95_99[5];	/* reserved words 95-99 */
+	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+	unsigned short	words104_125[22];/* reserved words 104-125 */
+	unsigned short	last_lun;	/* (word 126) */
+	unsigned short	word127;	/* (word 127) Feature Set
+					 * Removable Media Notification
+					 * 15:2	reserved
+					 *  1:0	00 = not supported
+					 *	01 = supported
+					 *	10 = reserved
+					 *	11 = reserved
+					 */
+	unsigned short	dlf;		/* (word 128)
+					 * device lock function
+					 * 15:9	reserved
+					 *  8	security level 1:max 0:high
+					 *  7:6	reserved
+					 *  5	enhanced erase
+					 *  4	expire
+					 *  3	frozen
+					 *  2	locked
+					 *  1	en/disabled
+					 *  0	capability
+					 */
+	unsigned short  csfo;		/*  (word 129)
+					 * current set features options
+					 * 15:4	reserved
+					 *  3:	auto reassign
+					 *  2:	reverting
+					 *  1:	read-look-ahead
+					 *  0:	write cache
+					 */
+	unsigned short	words130_155[26];/* reserved vendor words 130-155 */
+	unsigned short	word156;	/* reserved vendor word 156 */
+	unsigned short	words157_159[3];/* reserved vendor words 157-159 */
+	unsigned short	cfa_power;	/* (word 160) CFA Power Mode
+					 * 15 word 160 supported
+					 * 14 reserved
+					 * 13
+					 * 12
+					 * 11:0
+					 */
+	unsigned short	words161_175[14];/* Reserved for CFA */
+	unsigned short	words176_205[31];/* Current Media Serial Number */
+	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	integrity_word;	/* (word 255)
+					 * 15:8 Checksum
+					 *  7:0 Signature
+					 */
+} __attribute__((packed));
+
+/*
+ * IDE "nice" flags. These are used on a per drive basis to determine
+ * when to be nice and give more bandwidth to the other devices which
+ * share the same IDE bus.
+ */
+#define IDE_NICE_DSC_OVERLAP	(0)	/* per the DSC overlap protocol */
+#define IDE_NICE_ATAPI_OVERLAP	(1)	/* not supported yet */
+#define IDE_NICE_0		(2)	/* when sure that it won't affect us */
+#define IDE_NICE_1		(3)	/* when probably won't affect us much */
+#define IDE_NICE_2		(4)	/* when we know it's on our expense */
+
+#endif	/* _LINUX_HDREG_H */
diff -Nru a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
--- a/include/linux/i2c-dev.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/i2c-dev.h	Tue Aug 27 12:28:02 2002
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: i2c-dev.h,v 1.10 2001/11/19 19:01:46 mds Exp $ */
+/* $Id: i2c-dev.h,v 1.11 2002/07/07 15:42:47 mds Exp $ */
 
 #ifndef I2C_DEV_H
 #define I2C_DEV_H
@@ -144,7 +144,7 @@
 	else {
 		for (i = 1; i <= data.block[0]; i++)
 			values[i-1] = data.block[i];
-			return data.block[0];
+		return data.block[0];
 	}
 }
 
@@ -190,6 +190,27 @@
 	data.block[0] = length;
 	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 	                        I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
+                                                 __u8 length, __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_BLOCK_PROC_CALL,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
 }
 
 #endif /* ndef __KERNEL__ */
diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h
--- a/include/linux/i2c-id.h	Tue Aug 27 12:27:57 2002
+++ b/include/linux/i2c-id.h	Tue Aug 27 12:27:57 2002
@@ -20,7 +20,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */
 
-/* $Id: i2c-id.h,v 1.41 2002/03/11 07:18:55 simon Exp $ */
+/* $Id: i2c-id.h,v 1.52 2002/07/10 13:28:44 abz Exp $ */
 
 #ifndef I2C_ID_H
 #define I2C_ID_H
@@ -90,8 +90,12 @@
 #define I2C_DRIVERID_DRP3510	43     /* ADR decoder (Astra Radio)	*/
 #define I2C_DRIVERID_SP5055	44     /* Satellite tuner		*/
 #define I2C_DRIVERID_STV0030	45     /* Multipurpose switch		*/
-#define I2C_DRIVERID_SAA7108    46     /* video decoder, image scaler   */
-
+#define I2C_DRIVERID_SAA7108	46     /* video decoder, image scaler   */
+#define I2C_DRIVERID_DS1307	47     /* DS1307 real time clock	*/
+#define I2C_DRIVERID_ADV717x	48     /* ADV 7175/7176 video encoder	*/
+#define I2C_DRIVERID_ZR36067	49     /* Zoran 36067 video encoder	*/
+#define I2C_DRIVERID_ZR36120	50     /* Zoran 36120 video encoder	*/
+#define I2C_DRIVERID_24LC32A	51		/* Microchip 24LC32A 32k EEPROM	*/
 
 
 
@@ -102,6 +106,8 @@
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_I2CPROC	901
+#define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
+#define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
 
 /* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
    These were originally in sensors.h in the lm_sensors package */
@@ -134,6 +140,9 @@
 #define I2C_DRIVERID_FSCPOS 1028
 #define I2C_DRIVERID_FSCSCY 1029
 #define I2C_DRIVERID_PCF8591 1030
+#define I2C_DRIVERID_SMSC47M1 1031
+#define I2C_DRIVERID_VT1211 1032
+#define I2C_DRIVERID_LM92 1033
 
 /*
  * ---- Adapter types ----------------------------------------------------
@@ -155,6 +164,7 @@
 #define I2C_ALGO_EC     0x100000        /* ACPI embedded controller     */
 
 #define I2C_ALGO_MPC8XX 0x110000	/* MPC8xx PowerPC I2C algorithm */
+#define I2C_ALGO_OCP    0x120000	/* IBM or otherwise On-chip I2C algorithm */
 
 #define I2C_ALGO_EXP	0x800000	/* experimental			*/
 
@@ -182,9 +192,11 @@
 #define I2C_HW_B_I810	0x0a	/* Intel I810 				*/
 #define I2C_HW_B_VOO	0x0b	/* 3dfx Voodoo 3 / Banshee      	*/
 #define I2C_HW_B_PPORT  0x0c	/* Primitive parallel port adapter	*/
+#define I2C_HW_B_SAVG	0x0d	/* Savage 4                     	*/
 #define I2C_HW_B_RIVA	0x10	/* Riva based graphics cards		*/
 #define I2C_HW_B_IOC	0x11	/* IOC bit-wiggling			*/
 #define I2C_HW_B_TSUNA  0x12	/* DEC Tsunami chipset			*/
+#define I2C_HW_B_FRODO  0x13    /* 2d3D, Inc. SA-1110 Development Board */
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_LP	0x00	/* Parallel port interface		*/
@@ -199,6 +211,10 @@
 
 /* --- ITE based algorithms						*/
 #define I2C_HW_I_IIC	0x00	/* controller on the ITE */
+
+/* --- PowerPC on-chip adapters						*/
+#define I2C_HW_OCP 0x00	/* IBM on-chip I2C adapter 	*/
+
 
 /* --- SMBus only adapters						*/
 #define I2C_HW_SMBUS_PIIX4	0x00
diff -Nru a/include/linux/i2c.h b/include/linux/i2c.h
--- a/include/linux/i2c.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/i2c.h	Tue Aug 27 12:28:01 2002
@@ -23,13 +23,13 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c.h,v 1.50 2002/03/23 00:53:38 phil Exp $ */
+/* $Id: i2c.h,v 1.59 2002/07/19 20:53:45 phil Exp $ */
 
 #ifndef I2C_H
 #define I2C_H
 
-#define I2C_DATE "20020322"
-#define I2C_VERSION "2.6.3"
+#define I2C_DATE "20020719"
+#define I2C_VERSION "2.6.4"
 
 #include <linux/i2c-id.h>	/* id values of adapters et. al. 	*/
 #include <linux/types.h>
@@ -280,6 +280,9 @@
 #define I2C_CLIENT_ALLOW_USE		0x01	/* Client allows access */
 #define I2C_CLIENT_ALLOW_MULTIPLE_USE 	0x02  	/* Allow multiple access-locks */
 						/* on an i2c_client */
+#define I2C_CLIENT_PEC  0x04			/* Use Packet Error Checking */
+#define I2C_CLIENT_TEN	0x10			/* we have a ten bit chip address	*/
+						/* Must equal I2C_M_TEN below */
 
 /* i2c_client_address_data is the struct for holding default client
  * addresses for a driver and for the parameters supplied on the
@@ -395,6 +398,12 @@
 #define I2C_FUNC_I2C			0x00000001
 #define I2C_FUNC_10BIT_ADDR		0x00000002
 #define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART} */
+#define I2C_FUNC_SMBUS_HWPEC_CALC	0x00000008 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC  0x00000800 /* SMBus 2.0 */ 
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ 
+#define I2C_FUNC_SMBUS_PROC_CALL_PEC	0x00002000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 */
 #define I2C_FUNC_SMBUS_QUICK		0x00010000 
 #define I2C_FUNC_SMBUS_READ_BYTE	0x00020000 
 #define I2C_FUNC_SMBUS_WRITE_BYTE	0x00040000 
@@ -409,6 +418,8 @@
 #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2	 0x10000000 /* I2C-like block xfer  */
 #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC  0x40000000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
 
 #define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
                             I2C_FUNC_SMBUS_WRITE_BYTE
@@ -422,6 +433,17 @@
                                   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
 #define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
                                    I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
+#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
+                                      I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
+#define I2C_FUNC_SMBUS_WORD_DATA_PEC  I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
+                                      I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
+
+#define I2C_FUNC_SMBUS_READ_BYTE_PEC		I2C_FUNC_SMBUS_READ_BYTE_DATA
+#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC		I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC	I2C_FUNC_SMBUS_READ_WORD_DATA
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC	I2C_FUNC_SMBUS_WRITE_WORD_DATA
+#define I2C_FUNC_SMBUS_BYTE_PEC			I2C_FUNC_SMBUS_BYTE_DATA
+#define I2C_FUNC_SMBUS_BYTE_DATA_PEC		I2C_FUNC_SMBUS_WORD_DATA
 
 #define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
                             I2C_FUNC_SMBUS_BYTE | \
@@ -429,16 +451,20 @@
                             I2C_FUNC_SMBUS_WORD_DATA | \
                             I2C_FUNC_SMBUS_PROC_CALL | \
                             I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
-                            I2C_FUNC_SMBUS_I2C_BLOCK | \
-                            I2C_FUNC_SMBUS_I2C_BLOCK_2
+                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
+                            I2C_FUNC_SMBUS_I2C_BLOCK
 
 /* 
  * Data for SMBus Messages 
  */
+#define I2C_SMBUS_BLOCK_MAX	32	/* As specified in SMBus standard */	
+#define I2C_SMBUS_I2C_BLOCK_MAX	32	/* Not specified but we use same structure */
 union i2c_smbus_data {
 	__u8 byte;
 	__u16 word;
-	__u8 block[33]; /* block[0] is used for length */
+	__u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */
+                          /* one more for read length in block process call */
+	                                            /* and one more for PEC */
 };
 
 /* smbus_access read or write markers */
@@ -454,6 +480,11 @@
 #define I2C_SMBUS_PROC_CALL	    4
 #define I2C_SMBUS_BLOCK_DATA	    5
 #define I2C_SMBUS_I2C_BLOCK_DATA    6
+#define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
+#define I2C_SMBUS_BLOCK_DATA_PEC    8		/* SMBus 2.0 */
+#define I2C_SMBUS_PROC_CALL_PEC     9		/* SMBus 2.0 */
+#define I2C_SMBUS_BLOCK_PROC_CALL_PEC  10	/* SMBus 2.0 */
+#define I2C_SMBUS_WORD_DATA_PEC	   11		/* SMBus 2.0 */
 
 
 /* ----- commands for the ioctl like i2c_command call:
@@ -479,6 +510,7 @@
 
 #define I2C_FUNCS	0x0705	/* Get the adapter functionality */
 #define I2C_RDWR	0x0707	/* Combined R/W transfer (one stop only)*/
+#define I2C_PEC		0x0708	/* != 0 for SMBus PEC                   */
 #if 0
 #define I2C_ACK_TEST	0x0710	/* See if a slave is at a specific address */
 #endif
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/ide.h	Tue Aug 27 12:28:08 2002
@@ -1,583 +1,184 @@
 #ifndef _IDE_H
 #define _IDE_H
-
 /*
- *  Copyright (C) 1994-2002  Linus Torvalds & authors
+ *  linux/include/linux/ide.h
+ *
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors
  */
 
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/hdreg.h>
 #include <linux/hdsmart.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
 #include <linux/bio.h>
 #include <asm/byteorder.h>
+#include <asm/system.h>
 #include <asm/hdreg.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
+#  define __IDEDMA_TIMEOUT
+#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+#  undef __IDEDMA_TIMEOUT
+#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14, 15).
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary i/f:    ide0: major=3;  (hda) minor=0; (hdb) minor=64
- * Secondary i/f:  ide1: major=22; (hdc) minor=0; (hdd) minor=64
- * Tertiary i/f:   ide2: major=33; (hde) minor=0; (hdf) minor=64
- * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64
+ * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
+ * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
+ * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
  */
 
 /******************************************************************************
  * IDE driver configuration options (play with these as desired):
+ *
+ * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
  */
+#undef REALLY_FAST_IO			/* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
 
-#ifndef SUPPORT_SLOW_DATA_PORTS			/* 1 to support slow data ports */
-# define SUPPORT_SLOW_DATA_PORTS	1	/* 0 to reduce kernel size */
+#ifndef SUPPORT_SLOW_DATA_PORTS		/* 1 to support slow data ports */
+#define SUPPORT_SLOW_DATA_PORTS	1	/* 0 to reduce kernel size */
+#endif
+#ifndef SUPPORT_VLB_SYNC		/* 1 to support weird 32-bit chips */
+#define SUPPORT_VLB_SYNC	1	/* 0 to reduce kernel size */
+#endif
+#ifndef DISK_RECOVERY_TIME		/* off=0; on=access_delay_time */
+#define DISK_RECOVERY_TIME	0	/*  for hardware that needs it */
+#endif
+#ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
+#define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
 #endif
-
 #ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
-# define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
+#define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
+#endif
+
+#ifdef CONFIG_BLK_DEV_CMD640
+#if 0	/* change to 1 when debugging cmd640 problems */
+void cmd640_dump_regs (void);
+#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
 #endif
+#endif  /* CONFIG_BLK_DEV_CMD640 */
+
 #ifndef DISABLE_IRQ_NOSYNC
-# define DISABLE_IRQ_NOSYNC	0
+#define DISABLE_IRQ_NOSYNC	0
 #endif
 
 /*
- *  "No user-serviceable parts" beyond this point
- *****************************************************************************/
-
+ * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
+ */
+#define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
 
-/* ATA/ATAPI Commands pre T13 Spec */
-#define WIN_NOP				0x00
-#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
-#define WIN_SRST			0x08 /* ATAPI soft reset command */
-#define WIN_DEVICE_RESET		0x08
-#define WIN_RESTORE			0x10
-#define WIN_READ			0x20 /* 28-Bit */
-#define WIN_READ_EXT			0x24 /* 48-Bit */
-#define WIN_READDMA_EXT			0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
-#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
-#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
-#define WIN_WRITE			0x30 /* 28-Bit */
-#define WIN_WRITE_EXT			0x34 /* 48-Bit */
-#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
-#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
-#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
-#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
-#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
-#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
-#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
-#define WIN_FORMAT			0x50
-#define WIN_INIT			0x60
-#define WIN_SEEK			0x70
-#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
-#define WIN_DIAGNOSE			0x90
-#define WIN_SPECIFY			0x91 /* set drive geometry translation */
-#define WIN_DOWNLOAD_MICROCODE		0x92
-#define WIN_STANDBYNOW2			0x94
-#define WIN_SETIDLE2			0x97
-#define WIN_CHECKPOWERMODE2		0x98
-#define WIN_SLEEPNOW2			0x99
-#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
-#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
-#define WIN_QUEUED_SERVICE		0xA2
-#define WIN_SMART			0xB0 /* self-monitoring and reporting */
-#define CFA_ERASE_SECTORS		0xC0
-#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
-#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
-#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
-#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
-#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
-#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS		0xDA
-#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
-#define WIN_STANDBYNOW1			0xE0
-#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY			0xE2 /* Set device in Standby Mode */
-#define WIN_SETIDLE1			0xE3
-#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
-#define WIN_CHECKPOWERMODE1		0xE5
-#define WIN_SLEEPNOW1			0xE6
-#define WIN_FLUSH_CACHE			0xE7
-#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
-#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
-#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
-#define WIN_MEDIAEJECT			0xED
-#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES			0xEF /* set special drive features */
-#define EXABYTE_ENABLE_NEST		0xF0
-#define WIN_SECURITY_SET_PASS		0xF1
-#define WIN_SECURITY_UNLOCK		0xF2
-#define WIN_SECURITY_ERASE_PREPARE	0xF3
-#define WIN_SECURITY_ERASE_UNIT		0xF4
-#define WIN_SECURITY_FREEZE_LOCK	0xF5
-#define WIN_SECURITY_DISABLE		0xF6
-#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
-#define WIN_SET_MAX			0xF9
-#define DISABLE_SEAGATE			0xFB
-
-/* WIN_SMART sub-commands */
-
-#define SMART_READ_VALUES		0xD0
-#define SMART_READ_THRESHOLDS		0xD1
-#define SMART_AUTOSAVE			0xD2
-#define SMART_SAVE			0xD3
-#define SMART_IMMEDIATE_OFFLINE		0xD4
-#define SMART_READ_LOG_SECTOR		0xD5
-#define SMART_WRITE_LOG_SECTOR		0xD6
-#define SMART_WRITE_THRESHOLDS		0xD7
-#define SMART_ENABLE			0xD8
-#define SMART_DISABLE			0xD9
-#define SMART_STATUS			0xDA
-#define SMART_AUTO_OFFLINE		0xDB
-
-/* Password used in TF4 & TF5 executing SMART commands */
-
-#define SMART_LCYL_PASS			0x4F
-#define SMART_HCYL_PASS			0xC2
-
-/* WIN_SETFEATURES sub-commands */
-
-#define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
-
-#define SETFEATURES_XFER	0x03	/* Set transfer mode */
-#	define XFER_UDMA_7	0x47	/* 0100|0111 */
-#	define XFER_UDMA_6	0x46	/* 0100|0110 */
-#	define XFER_UDMA_5	0x45	/* 0100|0101 */
-#	define XFER_UDMA_4	0x44	/* 0100|0100 */
-#	define XFER_UDMA_3	0x43	/* 0100|0011 */
-#	define XFER_UDMA_2	0x42	/* 0100|0010 */
-#	define XFER_UDMA_1	0x41	/* 0100|0001 */
-#	define XFER_UDMA_0	0x40	/* 0100|0000 */
-#	define XFER_MW_DMA_2	0x22	/* 0010|0010 */
-#	define XFER_MW_DMA_1	0x21	/* 0010|0001 */
-#	define XFER_MW_DMA_0	0x20	/* 0010|0000 */
-#	define XFER_SW_DMA_2	0x12	/* 0001|0010 */
-#	define XFER_SW_DMA_1	0x11	/* 0001|0001 */
-#	define XFER_SW_DMA_0	0x10	/* 0001|0000 */
-#	define XFER_PIO_4	0x0C	/* 0000|1100 */
-#	define XFER_PIO_3	0x0B	/* 0000|1011 */
-#	define XFER_PIO_2	0x0A	/* 0000|1010 */
-#	define XFER_PIO_1	0x09	/* 0000|1001 */
-#	define XFER_PIO_0	0x08	/* 0000|1000 */
-#	define XFER_PIO_SLOW	0x00	/* 0000|0000 */
-
-#define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
-#define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
-#define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
-#define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
-#define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
-#define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
-#define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
-#define SETFEATURES_DIS_RPOD	0x66	/* Disable reverting to power on defaults */
-#define SETFEATURES_DIS_WCACHE	0x82	/* Disable write cache */
-#define SETFEATURES_EN_DEFECT	0x84	/* Enable Defect Management */
-#define SETFEATURES_DIS_APM	0x85	/* Disable advanced power management */
-#define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
-#define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
-#define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
-#define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
-#define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
-#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
-#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
-
-/* WIN_SECURITY sub-commands */
-
-#define SECURITY_SET_PASSWORD		0xBA
-#define SECURITY_UNLOCK			0xBB
-#define SECURITY_ERASE_PREPARE		0xBC
-#define SECURITY_ERASE_UNIT		0xBD
-#define SECURITY_FREEZE_LOCK		0xBE
-#define SECURITY_DISABLE_PASSWORD	0xBF
-
-
-/* Taskfile related constants.
- */
-#define IDE_DRIVE_TASK_INVALID		-1
-#define IDE_DRIVE_TASK_NO_DATA		0
-#define IDE_DRIVE_TASK_SET_XFER		1
-
-#define IDE_DRIVE_TASK_IN		2
-
-#define IDE_DRIVE_TASK_OUT		3
-#define IDE_DRIVE_TASK_RAW_WRITE	4
-
-struct hd_drive_task_hdr {
-	u8 feature;
-	u8 sector_count;
-	u8 sector_number;
-	u8 low_cylinder;
-	u8 high_cylinder;
-	u8 device_head;
-} __attribute__((packed));
-
-/*
- * Define standard taskfile in/out register
- */
-#define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
-#define IDE_TASKFILE_STD_IN_FLAGS	0xFE
-#define IDE_HOB_STD_OUT_FLAGS		0xC0
-#define IDE_HOB_STD_IN_FLAGS		0xC0
-
-#define TASKFILE_INVALID		0x7fff
-#define TASKFILE_48			0x8000
-
-#define TASKFILE_NO_DATA		0x0000
-
-#define TASKFILE_IN			0x0001
-#define TASKFILE_MULTI_IN		0x0002
-
-#define TASKFILE_OUT			0x0004
-#define TASKFILE_MULTI_OUT		0x0008
-#define TASKFILE_IN_OUT			0x0010
-
-#define TASKFILE_IN_DMA			0x0020
-#define TASKFILE_OUT_DMA		0x0040
-#define TASKFILE_IN_DMAQ		0x0080
-#define TASKFILE_OUT_DMAQ		0x0100
-
-#define TASKFILE_P_IN			0x0200
-#define TASKFILE_P_OUT			0x0400
-#define TASKFILE_P_IN_DMA		0x0800
-#define TASKFILE_P_OUT_DMA		0x1000
-#define TASKFILE_P_IN_DMAQ		0x2000
-#define TASKFILE_P_OUT_DMAQ		0x4000
-
-/* bus states */
-enum {
-	BUSSTATE_OFF = 0,
-	BUSSTATE_ON,
-	BUSSTATE_TRISTATE
-};
+#define IDE_DRIVE_TASK			98
 
 /*
- * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec.
- *
- * If you change something here, please remember to update fix_driveid() in
- * ide/probe.c.
+ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
  */
-struct hd_driveid {
-	u16	config;		/* lots of obsolete bit flags */
-	u16	cyls;		/* Obsolete, "physical" cyls */
-	u16	reserved2;	/* reserved (word 2) */
-	u16	heads;		/* Obsolete, "physical" heads */
-	u16	track_bytes;	/* unformatted bytes per track */
-	u16	sector_bytes;	/* unformatted bytes per sector */
-	u16	sectors;	/* Obsolete, "physical" sectors per track */
-	u16	vendor0;	/* vendor unique */
-	u16	vendor1;	/* vendor unique */
-	u16	vendor2;	/* Retired vendor unique */
-	u8	serial_no[20];	/* 0 = not_specified */
-	u16	buf_type;	/* Retired */
-	u16	buf_size;	/* Retired, 512 byte increments
-				 * 0 = not_specified
-				 */
-	u16	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
-	u8	fw_rev[8];	/* 0 = not_specified */
-	char	model[40];	/* 0 = not_specified */
-	u8	max_multsect;	/* 0=not_implemented */
-	u8	vendor3;	/* vendor unique */
-	u16	dword_io;	/* 0=not_implemented; 1=implemented */
-	u8	vendor4;	/* vendor unique */
-	u8	capability;	/* (upper byte of word 49)
-				 *  3:	IORDYsup
-				 *  2:	IORDYsw
-				 *  1:	LBA
-				 *  0:	DMA
-				 */
-	u16	reserved50;	/* reserved (word 50) */
-	u8	vendor5;	/* Obsolete, vendor unique */
-	u8	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
-	u8	vendor6;	/* Obsolete, vendor unique */
-	u8	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
-	u16	field_valid;	/* (word 53)
-				 *  2:	ultra_ok	word  88
-				 *  1:	eide_ok		words 64-70
-				 *  0:	cur_ok		words 54-58
-				 */
-	u16	cur_cyls;	/* Obsolete, logical cylinders */
-	u16	cur_heads;	/* Obsolete, l heads */
-	u16	cur_sectors;	/* Obsolete, l sectors per track */
-	u16	cur_capacity0;	/* Obsolete, l total sectors on drive */
-	u16	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
-	u8	multsect;	/* current multiple sector count */
-	u8	multsect_valid;	/* when (bit0==1) multsect is ok */
-	u32	lba_capacity;	/* Obsolete, total number of sectors */
-	u16	dma_1word;	/* Obsolete, single-word dma info */
-	u16	dma_mword;	/* multiple-word dma info */
-	u16	eide_pio_modes; /* bits 0:mode3 1:mode4 */
-	u16	eide_dma_min;	/* min mword dma cycle time (ns) */
-	u16	eide_dma_time;	/* recommended mword dma cycle time (ns) */
-	u16	eide_pio;       /* min cycle time (ns), no IORDY  */
-	u16	eide_pio_iordy; /* min cycle time (ns), with IORDY */
-	u16	words69_70[2];	/* reserved words 69-70
-				 * future command overlap and queuing
-				 */
-	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
-	u16	words71_74[4];	/* reserved words 71-74
-				 * for IDENTIFY PACKET DEVICE command
-				 */
-	u16	queue_depth;	/* (word 75)
-				 * 15:5	reserved
-				 *  4:0	Maximum queue depth -1
-				 */
-	u16	words76_79[4];	/* reserved words 76-79 */
-	u16	major_rev_num;	/* (word 80) */
-	u16	minor_rev_num;	/* (word 81) */
-	u16	command_set_1;	/* (word 82) supported
-				 * 15:	Obsolete
-				 * 14:	NOP command
-				 * 13:	READ_BUFFER
-				 * 12:	WRITE_BUFFER
-				 * 11:	Obsolete
-				 * 10:	Host Protected Area
-				 *  9:	DEVICE Reset
-				 *  8:	SERVICE Interrupt
-				 *  7:	Release Interrupt
-				 *  6:	look-ahead
-				 *  5:	write cache
-				 *  4:	PACKET Command
-				 *  3:	Power Management Feature Set
-				 *  2:	Removable Feature Set
-				 *  1:	Security Feature Set
-				 *  0:	SMART Feature Set
-				 */
-	u16	command_set_2;	/* (word 83)
-				 * 15:	Shall be ZERO
-				 * 14:	Shall be ONE
-				 * 13:	FLUSH CACHE EXT
-				 * 12:	FLUSH CACHE
-				 * 11:	Device Configuration Overlay
-				 * 10:	48-bit Address Feature Set
-				 *  9:	Automatic Acoustic Management
-				 *  8:	SET MAX security
-				 *  7:	reserved 1407DT PARTIES
-				 *  6:	SetF sub-command Power-Up
-				 *  5:	Power-Up in Standby Feature Set
-				 *  4:	Removable Media Notification
-				 *  3:	APM Feature Set
-				 *  2:	CFA Feature Set
-				 *  1:	READ/WRITE DMA QUEUED
-				 *  0:	Download MicroCode
-				 */
-	u16	cfsse;		/* (word 84)
-				 * cmd set-feature supported extensions
-				 * 15:	Shall be ZERO
-				 * 14:	Shall be ONE
-				 * 13:3	reserved
-				 *  2:	Media Serial Number Valid
-				 *  1:	SMART selt-test supported
-				 *  0:	SMART error logging
-				 */
-	u16	cfs_enable_1;	/* (word 85)
-				 * command set-feature enabled
-				 * 15:	Obsolete
-				 * 14:	NOP command
-				 * 13:	READ_BUFFER
-				 * 12:	WRITE_BUFFER
-				 * 11:	Obsolete
-				 * 10:	Host Protected Area
-				 *  9:	DEVICE Reset
-				 *  8:	SERVICE Interrupt
-				 *  7:	Release Interrupt
-				 *  6:	look-ahead
-				 *  5:	write cache
-				 *  4:	PACKET Command
-				 *  3:	Power Management Feature Set
-				 *  2:	Removable Feature Set
-				 *  1:	Security Feature Set
-				 *  0:	SMART Feature Set
-				 */
-	u16	cfs_enable_2;	/* (word 86)
-				 * command set-feature enabled
-				 * 15:	Shall be ZERO
-				 * 14:	Shall be ONE
-				 * 13:	FLUSH CACHE EXT
-				 * 12:	FLUSH CACHE
-				 * 11:	Device Configuration Overlay
-				 * 10:	48-bit Address Feature Set
-				 *  9:	Automatic Acoustic Management
-				 *  8:	SET MAX security
-				 *  7:	reserved 1407DT PARTIES
-				 *  6:	SetF sub-command Power-Up
-				 *  5:	Power-Up in Standby Feature Set
-				 *  4:	Removable Media Notification
-				 *  3:	APM Feature Set
-				 *  2:	CFA Feature Set
-				 *  1:	READ/WRITE DMA QUEUED
-				 *  0:	Download MicroCode
-				 */
-	u16	csf_default;	/* (word 87)
-				 * command set-feature default
-				 * 15:	Shall be ZERO
-				 * 14:	Shall be ONE
-				 * 13:3	reserved
-				 *  2:	Media Serial Number Valid
-				 *  1:	SMART selt-test supported
-				 *  0:	SMART error logging
-				 */
-	u16	dma_ultra;	/* (word 88) */
-	u16	word89;		/* reserved (word 89) */
-	u16	word90;		/* reserved (word 90) */
-	u16	CurAPMvalues;	/* current APM values */
-	u16	word92;		/* reserved (word 92) */
-	u16	hw_config;	/* hardware config (word 93)
-				 * 15:
-				 * 14:
-				 * 13:
-				 * 12:
-				 * 11:
-				 * 10:
-				 *  9:
-				 *  8:
-				 *  7:
-				 *  6:
-				 *  5:
-				 *  4:
-				 *  3:
-				 *  2:
-				 *  1:
-				 *  0:
-				 */
-	u16	acoustic;	/* (word 94)
-				 * 15:8	Vendor's recommended value
-				 *  7:0	current value
-				 */
-	u16	words95_99[5];	/* reserved words 95-99 */
-	u64	lba_capacity_2;	/* 48-bit total number of sectors */
-	u16	words104_125[22];/* reserved words 104-125 */
-	u16	last_lun;	/* (word 126) */
-	u16	word127;	/* (word 127) Feature Set
-				 * Removable Media Notification
-				 * 15:2	reserved
-				 *  1:0	00 = not supported
-				 *	01 = supported
-				 *	10 = reserved
-				 *	11 = reserved
-				 */
-	u16	dlf;		/* (word 128)
-				 * device lock function
-				 * 15:9	reserved
-				 *  8	security level 1:max 0:high
-				 *  7:6	reserved
-				 *  5	enhanced erase
-				 *  4	expire
-				 *  3	frozen
-				 *  2	locked
-				 *  1	en/disabled
-				 *  0	capability
-				 */
-	u16	csfo;		/* (word 129)
-				 * current set features options
-				 * 15:4	reserved
-				 *  3:	auto reassign
-				 *  2:	reverting
-				 *  1:	read-look-ahead
-				 *  0:	write cache
-				 */
-	u16	words130_155[26];/* reserved vendor words 130-155 */
-	u16	word156;	/* reserved vendor word 156 */
-	u16	words157_159[3];/* reserved vendor words 157-159 */
-	u16	cfa_power;	/* (word 160) CFA Power Mode
-				 * 15 word 160 supported
-				 * 14 reserved
-				 * 13
-				 * 12
-				 * 11:0
-				 */
-	u16	words161_175[14];/* Reserved for CFA */
-	u16	words176_205[31];/* Current Media Serial Number */
-	u16	words206_254[48];/* reserved words 206-254 */
-	u16	integrity_word;	/* (word 255)
-				 * 15:8 Checksum
-				 *  7:0 Signature
-				 */
-} __attribute__((packed));
+#define IDE_DRIVE_TASKFILE		97
 
-#define IDE_NICE_DSC_OVERLAP	(0)	/* per the DSC overlap protocol */
+/*
+ *  "No user-serviceable parts" beyond this point  :)
+ *****************************************************************************/
+
+typedef unsigned char	byte;	/* used everywhere */
 
 /*
  * Probably not wise to fiddle with these
  */
 #define ERROR_MAX	8	/* Max read/write errors per sector */
 #define ERROR_RESET	3	/* Reset controller every 4th retry */
+#define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
 /*
- * State flags.
+ * state flags
  */
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
 
 /*
- * Definitions for accessing IDE controller registers.
+ * Ensure that various configuration flags have compatible settings
  */
+#ifdef REALLY_SLOW_IO
+#undef REALLY_FAST_IO
+#endif
 
-enum {
-	IDE_DATA_OFFSET		= 0,
-	IDE_ERROR_OFFSET	= 1,
-	IDE_FEATURE_OFFSET	= 1,
-	IDE_NSECTOR_OFFSET	= 2,
-	IDE_SECTOR_OFFSET	= 3,
-	IDE_LCYL_OFFSET		= 4,
-	IDE_HCYL_OFFSET		= 5,
-	IDE_SELECT_OFFSET	= 6,
-	IDE_STATUS_OFFSET	= 7,
-	IDE_COMMAND_OFFSET	= 7,
-	IDE_CONTROL_OFFSET	= 8,
-	IDE_ALTSTATUS_OFFSET	= 8,
-	IDE_IRQ_OFFSET		= 9,
-	IDE_NR_PORTS		= 10
-};
-
-
-#define IDE_DATA_REG		(drive->channel->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG		(drive->channel->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG		(drive->channel->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG		(drive->channel->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG		(drive->channel->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG		(drive->channel->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG		(drive->channel->io_ports[IDE_SELECT_OFFSET])
-#define IDE_COMMAND_REG		(drive->channel->io_ports[IDE_STATUS_OFFSET])
-#define IDE_IRQ_REG		(drive->channel->io_ports[IDE_IRQ_OFFSET])
+#define HWIF(drive)		((ide_hwif_t *)((drive)->hwif))
+#define HWGROUP(drive)		((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
+
+/*
+ * Definitions for accessing IDE controller registers
+ */
+#define IDE_NR_PORTS		(10)
+
+#define IDE_DATA_OFFSET		(0)
+#define IDE_ERROR_OFFSET	(1)
+#define IDE_NSECTOR_OFFSET	(2)
+#define IDE_SECTOR_OFFSET	(3)
+#define IDE_LCYL_OFFSET		(4)
+#define IDE_HCYL_OFFSET		(5)
+#define IDE_SELECT_OFFSET	(6)
+#define IDE_STATUS_OFFSET	(7)
+#define IDE_CONTROL_OFFSET	(8)
+#define IDE_IRQ_OFFSET		(9)
+
+#define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
+
+#define IDE_DATA_OFFSET_HOB	(0)
+#define IDE_ERROR_OFFSET_HOB	(1)
+#define IDE_NSECTOR_OFFSET_HOB	(2)
+#define IDE_SECTOR_OFFSET_HOB	(3)
+#define IDE_LCYL_OFFSET_HOB	(4)
+#define IDE_HCYL_OFFSET_HOB	(5)
+#define IDE_SELECT_OFFSET_HOB	(6)
+#define IDE_CONTROL_OFFSET_HOB	(7)
+
+#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
+
+#define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG		(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG		(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG		(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG		(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG		(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
+
+#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
 
 #define IDE_FEATURE_REG		IDE_ERROR_REG
+#define IDE_COMMAND_REG		IDE_STATUS_REG
+#define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
 #define IDE_IREASON_REG		IDE_NSECTOR_REG
 #define IDE_BCOUNTL_REG		IDE_LCYL_REG
 #define IDE_BCOUNTH_REG		IDE_HCYL_REG
 
 #define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
-#define GET_ALTSTAT()		IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET])
-#define GET_FEAT()		IN_BYTE(IDE_NSECTOR_REG)
-
-/* Bits of HD_STATUS */
-#define ERR_STAT		0x01
-#define INDEX_STAT		0x02
-#define ECC_STAT		0x04	/* Corrected error */
-#define DRQ_STAT		0x08
-#define SEEK_STAT		0x10
-#define SERVICE_STAT		SEEK_STAT
-#define WRERR_STAT		0x20
-#define READY_STAT		0x40
-#define BUSY_STAT		0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR		0x01	/* Bad address mark */
-#define TRK0_ERR		0x02	/* couldn't find track 0 */
-#define ABRT_ERR		0x04	/* Command aborted */
-#define MCR_ERR			0x08	/* media change request */
-#define ID_ERR			0x10	/* ID field not found */
-#define MC_ERR			0x20	/* media changed */
-#define ECC_ERR			0x40	/* Uncorrectable ECC error */
-#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
-#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
+#define GET_ALTSTAT()		IN_BYTE(IDE_CONTROL_REG)
+#define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
+#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
+#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
+#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
+#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
+#define DATA_READY		(DRQ_STAT)
 
 /*
  * sector count bits
@@ -586,12 +187,6 @@
 #define NSEC_IO			0x02
 #define NSEC_REL		0x04
 
-#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
-#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
-
-#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
-#define DATA_READY		(DRQ_STAT)
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
@@ -601,6 +196,10 @@
  * the usual worst case.  Most requests seem to include some contiguous blocks,
  * further reducing the number of table entries required.
  *
+ * The driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ *
  * As it turns out though, we must allocate a full 4KB page for this,
  * so the two PRD tables (ide0 & ide1) will each get half of that,
  * allowing each to have about 256 entries (8 bytes each) from this.
@@ -616,119 +215,186 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
+#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
 #define SECTOR_SIZE	512
 #define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
+#define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
+#define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
+#define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
+
+#ifndef SPLIT_WORD
+#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
+#endif
+#ifndef MAKE_WORD
+#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
+#endif
+
 
 /*
  * Timeouts for various operations:
  */
 #define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
-#define WAIT_READY	(5*HZ)		/* 5sec   - some laptops are very slow */
-#define WAIT_PIDENTIFY	(10*HZ)		/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE	(30*HZ)		/* 30sec  - worst case when spinning up */
-#define WAIT_CMD	(10*HZ)		/* 10sec  - maximum wait for an IRQ to happen */
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+#define WAIT_READY	(5*HZ)		/* 5sec - some laptops are very slow */
+#else
+#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
+#endif /* CONFIG_APM || CONFIG_APM_MODULE */
+#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
+#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
+#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
+#define SELECT_DRIVE(hwif,drive)				\
+{								\
+	if (hwif->selectproc)					\
+		hwif->selectproc(drive);			\
+	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+}
+
+#define SELECT_INTERRUPT(hwif,drive)				\
+{								\
+	if (hwif->intrproc)					\
+		hwif->intrproc(drive);				\
+	else							\
+		OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);	\
+}
+
+#define SELECT_MASK(hwif,drive,mask)				\
+{								\
+	if (hwif->maskproc)					\
+		hwif->maskproc(drive,mask);			\
+}
+
+#define SELECT_READ_WRITE(hwif,drive,func)			\
+{								\
+	if (hwif->rwproc)					\
+		hwif->rwproc(drive,func);			\
+}
+
+#define QUIRK_LIST(hwif,drive)					\
+{								\
+	if (hwif->quirkproc)					\
+		(drive)->quirk_list = hwif->quirkproc(drive);	\
+}
+
+#define HOST(hwif,chipset)					\
+{								\
+	return ((hwif)->chipset == chipset) ? 1 : 0;		\
+}
+
+#define IDE_DEBUG(lineno) \
+	printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
+
 /*
  * Check for an interrupt and acknowledge the interrupt status
  */
-struct ata_channel;
-typedef int (ide_ack_intr_t)(struct ata_channel *);
+struct hwif_s;
+typedef int (ide_ack_intr_t)(struct hwif_s *);
 
 #ifndef NO_DMA
-# define NO_DMA  255
+#define NO_DMA  255
 #endif
 
 /*
- * This is used to keep track of the specific hardware chipset used by each IDE
- * interface, if known. Please note that we don't discriminate between
- * different PCI host chips here.
+ * hwif_chipset_t is used to keep track of the specific hardware
+ * chipset used by each IDE interface, if known.
  */
-typedef enum {
-	ide_unknown,
-	ide_generic,
-	ide_pci,
-        ide_cmd640,
-	ide_dtc2278,
-	ide_ali14xx,
-	ide_qd65xx,
-	ide_umc8672,
-	ide_ht6560b,
-	ide_pdc4030,
-	ide_rz1000,
-	ide_trm290,
-	ide_cmd646,
-	ide_cy82c693,
-	ide_pmac,
-	ide_etrax100,
-	ide_acorn
+typedef enum {	ide_unknown,	ide_generic,	ide_pci,
+		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
+		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
+		ide_pdc4030,	ide_rz1000,	ide_trm290,
+		ide_cmd646,	ide_cy82c693,	ide_4drives,
+		ide_pmac,	ide_etrax100
 } hwif_chipset_t;
 
-
-#define IDE_CHIPSET_PCI_MASK    \
-    ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
-#define IDE_CHIPSET_IS_PCI(c)   ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
-
 /*
  * Structure to hold all information about the location of this port
  */
 typedef struct hw_regs_s {
-	ide_ioreg_t	io_ports[IDE_NR_PORTS];		    /* task file registers */
-	int		irq;				    /* our irq number */
-	int		dma;				    /* our dma entry */
-	int		(*ack_intr)(struct ata_channel *);  /* acknowledge interrupt */
+	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+	int		irq;			/* our irq number */
+	int		dma;			/* our dma entry */
+	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
+	void		*priv;			/* interface specific data */
 	hwif_chipset_t  chipset;
 } hw_regs_t;
 
 /*
+ * Register new hardware with ide
+ */
+int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
+
+/*
  * Set up hw_regs_t structure before calling ide_register_hw (optional)
  */
-extern void ide_setup_ports(hw_regs_t *hw,
-	ide_ioreg_t base, int *offsets,
-	ide_ioreg_t ctrl, ide_ioreg_t intr,
-	int (*ack_intr)(struct ata_channel *),
-	int irq);
+void ide_setup_ports(	hw_regs_t *hw,
+			ide_ioreg_t base,
+			int *offsets,
+			ide_ioreg_t ctrl,
+			ide_ioreg_t intr,
+			ide_ack_intr_t *ack_intr,
+			int irq);
 
 #include <asm/ide.h>
 
-/* Currently only m68k, apus and m8xx need it */
-#ifdef ATA_ARCH_ACK_INTR
-extern int ide_irq_lock;
-# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
-# define ide_ack_intr(hwif) (1)
-#endif
-
-/* Currently only Atari needs it */
-#ifndef ATA_ARCH_LOCK
-# define ide_release_lock(lock)		do {} while (0)
-# define ide_get_lock(lock, hdlr, data)	do {} while (0)
-#endif
-
 /*
- * If the arch-dependant ide.h did not declare/define any OUT_BYTE or IN_BYTE
- * functions, we make some defaults here. The only architecture currently
- * needing this is Cris.
+ * If the arch-dependant ide.h did not declare/define any OUT_BYTE
+ * or IN_BYTE functions, we make some defaults here.
  */
 
-#ifndef HAVE_ARCH_IN_OUT
-# define OUT_BYTE(b,p)		outb((b),(p))
-# define OUT_WORD(w,p)		outw((w),(p))
-# define IN_BYTE(p)		(u8)inb(p)
-# define IN_WORD(p)		(u16)inw(p)
+#ifndef HAVE_ARCH_OUT_BYTE
+# ifdef REALLY_FAST_IO
+#  define OUT_BYTE(b,p)		outb((b),(p))
+#  define OUT_WORD(w,p)		outw((w),(p))
+# else
+#  define OUT_BYTE(b,p)		outb_p((b),(p))
+#  define OUT_WORD(w,p)		outw_p((w),(p))
+# endif
+#endif
+
+#ifndef HAVE_ARCH_IN_BYTE
+# ifdef REALLY_FAST_IO
+#  define IN_BYTE(p)		(byte)inb(p)
+#  define IN_WORD(p)		(short)inw(p)
+# else
+#  define IN_BYTE(p)		(byte)inb_p(p)
+#  define IN_WORD(p)		(short)inw_p(p)
+# endif
 #endif
 
 /*
- * Device types - the nomenclature is analogous to SCSI code.
+ * Now for the data we need to maintain per-drive:  ide_drive_t
  */
 
-#define ATA_DISK        0x20
-#define ATA_TAPE        0x01
-#define ATA_ROM         0x05	/* CD-ROM */
-#define ATA_MOD		0x07    /* optical */
-#define ATA_FLOPPY	0x00
-#define ATA_SCSI	0x21
-#define ATA_NO_LUN      0x7f
+#define ide_scsi	0x21
+#define ide_disk	0x20
+#define ide_optical	0x7
+#define ide_cdrom	0x5
+#define ide_tape	0x1
+#define ide_floppy	0x0
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned set_geometry	: 1;	/* respecify drive geometry */
+		unsigned recalibrate	: 1;	/* seek to cyl 0      */
+		unsigned set_multmode	: 1;	/* set multmode count */
+		unsigned set_tune	: 1;	/* tune interface for drive */
+		unsigned serviced	: 1;	/* service command */
+		unsigned reserved	: 3;	/* unused */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	: 3;	/* unused */
+		unsigned serviced	: 1;	/* service command */
+		unsigned set_tune	: 1;	/* tune interface for drive */
+		unsigned set_multmode	: 1;	/* set multmode count */
+		unsigned recalibrate	: 1;	/* seek to cyl 0      */
+		unsigned set_geometry	: 1;	/* respecify drive geometry */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} special_t;
 
 typedef union {
 	unsigned all			: 8;	/* all of the bits together */
@@ -740,337 +406,550 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 #elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bit7		: 1;
-		unsigned lba		: 1;
-		unsigned bit5		: 1;
-		unsigned unit		: 1;
-		unsigned head		: 4;
+		unsigned bit7		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned unit		: 1;	/* drive select number: 0/1 */
+		unsigned head		: 4;	/* always zeros here */
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 	} b;
 } select_t;
 
-/*
- * ATA/ATAPI device structure :
- */
-struct ata_device {
-	struct ata_channel *	channel;
-	char			name[6];	/* device name */
-
-	unsigned int usage;		/* current "open()" count for drive */
-	char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
-
-	request_queue_t	queue;		/* per device request queue */
-	struct request *rq;		/* current request */
-
-	u8	 retry_pio;		/* retrying dma capable host in pio */
-	u8	 state;			/* retry state */
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456    : 3;
+		unsigned HOB            : 1;	/* 48-bit address ordering */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} control_t;
 
-	unsigned using_dma	: 1;	/* disk is using dma for read/write */
-	unsigned using_tcq	: 1;	/* disk is using queueing */
-	unsigned dsc_overlap	: 1;	/* flag: DSC overlap */
 
-	unsigned busy		: 1;	/* currently doing revalidate_disk() */
-	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
+struct ide_driver_s;
+struct ide_settings_s;
 
+typedef struct ide_drive_s {
+	request_queue_t		 queue;	/* request queue */
+	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
+	unsigned long sleep;		/* sleep until this time */
+	unsigned long service_start;	/* time we started last request */
+	unsigned long service_time;	/* service time of last request */
+	unsigned long timeout;		/* max time to wait for irq */
+	special_t	special;	/* special action flags */
+	byte     keep_settings;		/* restore settings after drive reset */
+	byte     using_dma;		/* disk is using dma for read/write */
+	byte	 retry_pio;		/* retrying dma capable host in pio */
+	byte	 state;			/* retry state */
+	byte     waiting_for_dma;	/* dma currently in progress */
+	byte     unmask;		/* flag: okay to unmask other irqs */
+	byte     slow;			/* flag: slow data port */
+	byte     bswap;			/* flag: byte swap data */
+	byte     dsc_overlap;		/* flag: DSC overlap */
+	byte     nice1;			/* flag: give potential excess bandwidth */
 	unsigned present	: 1;	/* drive is physically present */
-	unsigned noprobe	: 1;	/* from:  hdx=noprobe */
+	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
+	unsigned busy		: 1;	/* currently doing revalidate_disk() */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
+	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
+	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
 	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
 	unsigned revalidate	: 1;	/* request revalidation */
 	unsigned atapi_overlap	: 1;	/* flag: ATAPI overlap (not supported) */
+	unsigned nice0		: 1;	/* flag: give obvious excess bandwidth */
+	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
 	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
+	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
-	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
-	u8		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
-
+	unsigned addressing;		/*	: 3;
+					 *  0=28-bit
+					 *  1=48-bit
+					 *  2=48-bit doing 28-bit
+					 *  3=64-bit
+					 */
+	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
+	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
-	u8		status;		/* last retrived status value for device */
-
-	u8		ready_stat;	/* min status value for drive ready */
-	u8		mult_count;	/* current multiple sector setting */
-	u8		bad_wstat;	/* used for ignoring WRERR_STAT */
-	u8		nowerr;		/* used for ignoring WRERR_STAT */
-	u8		head;		/* "real" number of heads */
-	u8		sect;		/* "real" sectors per track */
-	u8		bios_head;	/* BIOS/fdisk/LILO number of heads */
-	u8		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
+	byte		ready_stat;	/* min status value for drive ready */
+	byte		mult_count;	/* current multiple sector setting */
+	byte 		mult_req;	/* requested multiple sector setting */
+	byte 		tune_req;	/* requested drive tuning setting */
+	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
+	byte		nowerr;		/* used for ignoring WRERR_STAT */
+	byte		sect0;		/* offset of first sector for DM6:DDO */
+	unsigned int	usage;		/* current "open()" count for drive */
+	byte 		head;		/* "real" number of heads */
+	byte		sect;		/* "real" sectors per track */
+	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
+	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
-	u64		capacity;	/* total number of sectors */
+	unsigned long	capacity;	/* total number of sectors */
+	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-
+	struct hwif_s	  *hwif;	/* actually (ide_hwif_t *) */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
-
 	struct hd_driveid *id;		/* drive model identification info */
 	struct hd_struct  *part;	/* drive partition table */
-
-	struct ata_operations *driver;
-
+	char		name[4];	/* drive name, such as "hda" */
+	struct ide_driver_s *driver;	/* (ide_driver_t *) */
 	void		*driver_data;	/* extra driver data */
 	devfs_handle_t	de;		/* directory for device */
-
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct ide_settings_s *settings;	/* /proc/ide/ drive settings */
 	char		driver_req[10];	/* requests specific driver */
-
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
-
 	int		crc_count;	/* crc counter to reduce drive speed */
-	int		quirk_list;	/* drive is considered quirky if set for a specific host */
-	u8		current_speed;	/* current transfer rate set */
-	u8		dn;		/* now wide spread use */
-	u8		wcache;		/* status of write cache */
-	u8		acoustic;	/* acoustic management */
-	unsigned int	queue_depth;	/* max queue depth */
+	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
+	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
+	byte		init_speed;	/* transfer rate set at boot */
+	byte		current_speed;	/* current transfer rate set */
+	byte		dn;		/* now wide spread use */
+	byte		wcache;		/* status of write cache */
+	byte		acoustic;	/* acoustic management */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
-	struct device	dev;		/* global device tree handle */
-
-	/*
-	 * tcq statistics
-	 */
-	unsigned long	immed_rel;
-	unsigned long	immed_comp;
-	int		max_last_depth;
-	int		max_depth;
-};
+} ide_drive_t;
 
 /*
- * Status returned by various functions.
+ * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case the caller
+ * should either try again later, or revert to PIO for the current request.
+ */
+typedef enum {	ide_dma_read,	ide_dma_write,		ide_dma_begin,
+		ide_dma_end,	ide_dma_check,		ide_dma_on,
+		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
+		ide_dma_host_on,			ide_dma_host_off,
+		ide_dma_bad_drive,			ide_dma_good_drive,
+		ide_dma_verbose,			ide_dma_retune,
+		ide_dma_lostirq,			ide_dma_timeout
+} ide_dma_action_t;
+
+typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
+
+/*
+ * An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
+ * Arguments are: the drive, the buffer pointer, and the length (in bytes or
+ * words depending on if it's an IDE or ATAPI call).
+ *
+ * If it is not defined for a controller, standard-code is used from ide.c.
+ *
+ * Controllers which are not memory-mapped in the standard way need to 
+ * override that mechanism using this function to work.
+ *
  */
-typedef enum {
-	ATA_OP_FINISHED,	/* no drive operation was started */
-	ATA_OP_CONTINUES,	/* a drive operation was started, and a handler was set */
-	ATA_OP_RELEASED,	/* started and released bus */
-	ATA_OP_READY		/* indicate status poll finished fine */
-} ide_startstop_t;
+typedef enum { ideproc_ide_input_data,    ideproc_ide_output_data,
+	       ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
+} ide_ide_action_t;
+
+typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
 
 /*
- *  Interrupt and timeout handler type.
+ * mapping stuff, prepare for highmem...
+ * 
+ * temporarily mapping a (possible) highmem bio for PIO transfer
  */
-typedef ide_startstop_t (ata_handler_t)(struct ata_device *, struct request *);
-typedef ide_startstop_t (ata_expiry_t)(struct ata_device *, struct request *, unsigned long *);
-
-enum {
-	ATA_PRIMARY	= 0,
-	ATA_SECONDARY	= 1
-};
-
-enum {
-	IDE_BUSY,	/* awaiting an interrupt */
-	IDE_SLEEP,
-	IDE_PIO,	/* PIO in progress */
-	IDE_DMA		/* DMA in progress */
-};
-
-struct ata_channel {
-	struct device	dev;		/* device handle */
-	int		unit;		/* channel number */
+#define ide_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
-	/* This lock is used to serialize requests on the same device queue or
-	 * between differen queues sharing the same irq line.
-	 */
-	spinlock_t *lock;
-	unsigned long *active;		/* active processing request */
-	ide_startstop_t (*handler)(struct ata_device *, struct request *);	/* irq handler, if active */
+/*
+ * taskfiles really should use hard_cur_sectors as well!
+ */
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
 
-	/* FIXME: Only still used in PDC4030.  Localize this code there by
-	 * replacing with busy waits.
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	/*
+	 * fs request
 	 */
-	struct timer_list timer;				/* failsafe timer */
-	ide_startstop_t (*expiry)(struct ata_device *, struct request *, unsigned long *);	/* irq handler, if active */
-	unsigned long poll_timeout;				/* timeout value during polled operations */
-
-	struct ata_device *drive;				/* last serviced drive */
-
-
-	ide_ioreg_t io_ports[IDE_NR_PORTS];	/* task file registers */
-	hw_regs_t hw;				/* hardware info */
-#ifdef CONFIG_PCI
-	struct pci_dev *pci_dev;		/* for pci chipsets */
-#endif
-	struct ata_device drives[MAX_DRIVES];	/* drive info */
-	struct gendisk *gd[MAX_DRIVES];		/* gendisk structure */
+	if (rq->bio)
+		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
 
 	/*
-	 * Routines to tune PIO and DMA mode for drives.
-	 *
-	 * A value of 255 indicates that the function should choose the optimal
-	 * mode itself.
+	 * task request
 	 */
+	return rq->buffer + task_rq_offset(rq);
+}
 
-	/* setup disk on a channel for a particular PIO transfer mode */
-	void (*tuneproc) (struct ata_device *, u8 pio);
-
-	/* setup the chipset timing for a particular transfer mode */
-	int (*speedproc) (struct ata_device *, u8 pio);
-
-	/* tweaks hardware to select drive */
-	void (*selectproc) (struct ata_device *);
-
-	/* routine to reset controller after a disk reset */
-	void (*resetproc) (struct ata_device *);
-
-	/* special interrupt handling for shared pci interrupts */
-	void (*intrproc) (struct ata_device *);
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bio_kunmap_irq(buffer, flags);
+}
 
-	/* special host masking for drive selection */
-	void (*maskproc) (struct ata_device *);
+/*
+ * A Verbose noise maker for debugging on the attempted transfer rates.
+ */
+extern inline char *ide_xfer_verbose (byte xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_7:	return("UDMA 7");
+		case XFER_UDMA_6:	return("UDMA 6");
+		case XFER_UDMA_5:	return("UDMA 5");
+		case XFER_UDMA_4:	return("UDMA 4");
+		case XFER_UDMA_3:	return("UDMA 3");
+		case XFER_UDMA_2:	return("UDMA 2");
+		case XFER_UDMA_1:	return("UDMA 1");
+		case XFER_UDMA_0:	return("UDMA 0");
+		case XFER_MW_DMA_2:	return("MW DMA 2");
+		case XFER_MW_DMA_1:	return("MW DMA 1");
+		case XFER_MW_DMA_0:	return("MW DMA 0");
+		case XFER_SW_DMA_2:	return("SW DMA 2");
+		case XFER_SW_DMA_1:	return("SW DMA 1");
+		case XFER_SW_DMA_0:	return("SW DMA 0");
+		case XFER_PIO_4:	return("PIO 4");
+		case XFER_PIO_3:	return("PIO 3");
+		case XFER_PIO_2:	return("PIO 2");
+		case XFER_PIO_1:	return("PIO 1");
+		case XFER_PIO_0:	return("PIO 0");
+		case XFER_PIO_SLOW:	return("PIO SLOW");
+		default:		return("XFER ERROR");
+	}
+}
 
-	/* check host's drive quirk list */
-	int (*quirkproc) (struct ata_device *);
+/*
+ * A Verbose noise maker for debugging on the attempted dmaing calls.
+ */
+extern inline char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
+{
+	switch (dmafunc) {
+		case ide_dma_read:		return("ide_dma_read");
+		case ide_dma_write:		return("ide_dma_write");
+		case ide_dma_begin:		return("ide_dma_begin");
+		case ide_dma_end:		return("ide_dma_end:");
+		case ide_dma_check:		return("ide_dma_check");
+		case ide_dma_on:		return("ide_dma_on");
+		case ide_dma_off:		return("ide_dma_off");
+		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
+		case ide_dma_test_irq:		return("ide_dma_test_irq");
+		case ide_dma_host_on:		return("ide_dma_host_on");
+		case ide_dma_host_off:		return("ide_dma_host_off");
+		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
+		case ide_dma_good_drive:	return("ide_dma_good_drive");
+		case ide_dma_verbose:		return("ide_dma_verbose");
+		case ide_dma_retune:		return("ide_dma_retune");
+		case ide_dma_lostirq:		return("ide_dma_lostirq");
+		case ide_dma_timeout:		return("ide_dma_timeout");
+		default:			return("unknown");
+	}
+}
 
-	/* driver soft-power interface */
-	int (*busproc)(struct ata_device *, int);
+/*
+ * An ide_tuneproc_t() is used to set the speed of an IDE interface
+ * to a particular PIO mode.  The "byte" parameter is used
+ * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
+ * indicates that the interface driver should "auto-tune" the PIO mode
+ * according to the drive capabilities in drive->id;
+ *
+ * Not all interface types support tuning, and not all of those
+ * support all possible PIO settings.  They may silently ignore
+ * or round values as they see fit.
+ */
+typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
+typedef int (ide_speedproc_t) (ide_drive_t *, byte);
 
-	/* CPU-polled transfer routines */
-	void (*ata_read)(struct ata_device *, void *, unsigned int);
-	void (*ata_write)(struct ata_device *, void *, unsigned int);
-	void (*atapi_read)(struct ata_device *, void *, unsigned int);
-	void (*atapi_write)(struct ata_device *, void *, unsigned int);
+/*
+ * This is used to provide support for strange interfaces
+ */
+typedef void (ide_selectproc_t) (ide_drive_t *);
+typedef void (ide_resetproc_t) (ide_drive_t *);
+typedef int (ide_quirkproc_t) (ide_drive_t *);
+typedef void (ide_intrproc_t) (ide_drive_t *);
+typedef void (ide_maskproc_t) (ide_drive_t *, int);
+typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
 
-	int (*udma_setup)(struct ata_device *, int);
+/*
+ * ide soft-power support
+ */
+typedef int (ide_busproc_t) (ide_drive_t *, int);
 
-	void (*udma_enable)(struct ata_device *, int, int);
-	void (*udma_start) (struct ata_device *, struct request *);
-	int (*udma_stop) (struct ata_device *);
-	int (*udma_init) (struct ata_device *, struct request *);
-	int (*udma_irq_status) (struct ata_device *);
-	void (*udma_timeout) (struct ata_device *);
-	void (*udma_irq_lost) (struct ata_device *);
+#define IDE_CHIPSET_PCI_MASK	\
+    ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
+#define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
-	unsigned long	seg_boundary_mask;
-	unsigned int	max_segment_size;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+typedef struct ide_pci_devid_s {
+	unsigned short	vid;
+	unsigned short	did;
+} ide_pci_devid_t;
+
+#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
+#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+typedef struct hwif_s {
+	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
+	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
+	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+/*
+ *     FIXME!! need a generic register set :-/  PPC guys ideas??
+ *
+ *     ide_mmioreg_t   mm_ports[IDE_NR_PORTS]; "task file registers"
+ *
+ */
+	hw_regs_t	hw;		/* Hardware info */
+	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
+	struct gendisk	*gd[MAX_DRIVES];/* gendisk structure */
+	int		addressing;	/* hosts addressing */
+	void		(*tuneproc)(ide_drive_t *, byte);	/* routine to tune PIO mode for drives */
+	int		(*speedproc)(ide_drive_t *, byte);	/* routine to retune DMA modes for drives */
+	void		(*selectproc)(ide_drive_t *);		/* tweaks hardware to select drive */
+	void		(*resetproc)(ide_drive_t *);		/* routine to reset controller after a disk reset */
+	void		(*intrproc)(ide_drive_t *);		/* special interrupt handling for shared pci interrupts */
+	void		(*maskproc)(ide_drive_t *, int);	/* special host masking for drive selection */
+	int		(*quirkproc)(ide_drive_t *);		/* check host's drive quirk list */
+	void		(*rwproc)(ide_drive_t *, ide_dma_action_t);	/* adjust timing based upon rq->cmd direction */
+	void		(*ideproc)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);	/* CPU-polled transfer routine */
+	int		(*dmaproc)(ide_dma_action_t, ide_drive_t *);	/* dma read/write/abort routine */
+	int		(*busproc)(ide_drive_t *, int);		/* driver soft-power interface */
 	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
 	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
+	int sg_dma_active;		/* is it in use */
+	struct hwif_s	*mate;		/* other hwif from same PCI chip */
 	unsigned long	dma_base;	/* base addr for dma ports */
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
 	unsigned long	select_data;	/* for use by chipset-specific code */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	int		irq;		/* our irq number */
-	int		major;		/* our major number */
-	char		name[8];	/* name of interface */
-	int		index;		/* 0 for ide0; 1 for ide1; ... */
+	byte		major;		/* our major number */
+	char 		name[6];	/* name of interface, eg. "ide0" */
+	byte		index;		/* 0 for ide0; 1 for ide1; ... */
 	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
-	unsigned noprobe	: 1;	/* don't probe for this interface */
-	unsigned present	: 1;	/* there is a device on this interface */
-	unsigned serialized	: 1;	/* serialized operation between channels */
-	unsigned sharing_irq	: 1;	/* 1 = sharing irq with another hwif */
-	unsigned reset		: 1;	/* reset after probe */
-	unsigned autodma	: 1;	/* automatically try to enable DMA at boot */
-	unsigned udma_four	: 1;	/* 1=ATA-66 capable, 0=default */
-	unsigned highmem	: 1;	/* can do full 32-bit dma */
-	unsigned straight8	: 1;	/* Alan's straight 8 check */
-	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
-	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
-	unsigned auto_poll	: 1;	/* supports nop auto-poll */
-	unsigned unmask		: 1;	/* flag: okay to unmask other irqs */
-	unsigned slow		: 1;	/* flag: slow data port */
-	unsigned io_32bit	: 1;	/* 0=16-bit, 1=32-bit */
-	unsigned no_atapi_autodma : 1;	/* flag: use auto DMA only for disks */
-	unsigned char bus_state;	/* power state of the IDE bus */
-	int modes_map;			/* map of supported transfer modes */
-};
+	unsigned	noprobe    : 1;	/* don't probe for this interface */
+	unsigned	present    : 1;	/* this interface exists */
+	unsigned	serialized : 1;	/* serialized operation with mate hwif */
+	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
+	unsigned	reset      : 1;	/* reset after probe */
+	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
+	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
+	unsigned	no_highmem : 1;	/* always use high i/o bounce */
+	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	struct pci_dev	*pci_dev;	/* for pci chipsets */
+	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+#if (DISK_RECOVERY_TIME > 0)
+	unsigned long	last_time;	/* time when previous rq was done */
+#endif
+	byte		straight8;	/* Alan's straight 8 check */
+	void		*hwif_data;	/* extra hwif data */
+	byte		bus_state;	/* power state of the IDE bus */
+} ide_hwif_t;
 
 /*
- * Register new hardware with ide
+ * Status returned from various ide_ functions
  */
-extern int ide_register_hw(hw_regs_t *hw);
-extern void ide_unregister(struct ata_channel *);
-
-#define IDE_MAX_TAG	32
-
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-static inline int ata_pending_commands(struct ata_device *drive)
-{
-	if (drive->using_tcq)
-		return blk_queue_tag_depth(&drive->queue);
-
-	return 0;
-}
-
-static inline int ata_can_queue(struct ata_device *drive)
-{
-	if (drive->using_tcq)
-		return blk_queue_tag_queue(&drive->queue);
+typedef enum {
+	ide_stopped,	/* no drive operation was started */
+	ide_started	/* a drive operation was started, and a handler was set */
+} ide_startstop_t;
 
-	return 1;
+/*
+ *  internal ide interrupt handler type
+ */
+typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
+typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
+
+/*
+ * when ide_timer_expiry fires, invoke a handler of this type
+ * to decide what to do.
+ */
+typedef int (ide_expiry_t)(ide_drive_t *);
+
+typedef struct hwgroup_s {
+	ide_handler_t		*handler;/* irq handler, if active */
+	ide_handler_t		*handler_save;/* irq handler, if active */
+	volatile int		busy;	/* BOOL: protects all fields below */
+	int			sleeping; /* BOOL: wake us up on timer expiry */
+	ide_drive_t		*drive;	/* current drive */
+	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
+	struct request		*rq;	/* current request */
+	struct timer_list	timer;	/* failsafe timer */
+	struct request		wrq;	/* local copy of current write rq */
+	unsigned long		poll_timeout;	/* timeout value during long polls */
+	ide_expiry_t		*expiry;	/* queried upon timeouts */
+	int			pio_clock;	/* ide_system_bus_speed */
+} ide_hwgroup_t;
+
+/* structure attached to the request for IDE_TASK_CMDS */
+
+/*
+ * configurable drive settings
+ */
+
+#define TYPE_INT	0
+#define TYPE_INTA	1
+#define TYPE_BYTE	2
+#define TYPE_SHORT	3
+
+#define SETTING_READ	(1 << 0)
+#define SETTING_WRITE	(1 << 1)
+#define SETTING_RW	(SETTING_READ | SETTING_WRITE)
+
+typedef int (ide_procset_t)(ide_drive_t *, int);
+typedef struct ide_settings_s {
+	char			*name;
+	int			rw;
+	int			read_ioctl;
+	int			write_ioctl;
+	int			data_type;
+	int			min;
+	int			max;
+	int			mul_factor;
+	int			div_factor;
+	void			*data;
+	ide_procset_t		*set;
+	int			auto_remove;
+	struct ide_settings_s	*next;
+} ide_settings_t;
+
+void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set);
+void ide_remove_setting(ide_drive_t *drive, char *name);
+ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name);
+int ide_read_setting(ide_drive_t *t, ide_settings_t *setting);
+int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val);
+void ide_add_generic_settings(ide_drive_t *drive);
+
+/*
+ * /proc/ide interface
+ */
+typedef struct {
+	const char	*name;
+	mode_t		mode;
+	read_proc_t	*read_proc;
+	write_proc_t	*write_proc;
+} ide_proc_entry_t;
+
+#ifdef CONFIG_PROC_FS
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_drives(ide_hwif_t *);
+void create_proc_ide_interfaces(void);
+void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
+void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_capacity;
+read_proc_t proc_ide_read_geometry;
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{					\
+	len -= off;			\
+	if (len < count) {		\
+		*eof = 1;		\
+		if (len <= 0)		\
+			return 0;	\
+	} else				\
+		len = count;		\
+	*start = page + off;		\
+	return len;			\
 }
 #else
-# define ata_pending_commands(drive)	(0)
-# define ata_can_queue(drive)		(1)
-#endif
-
-/* FIXME: kill this as soon as possible */
 #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
+#endif
 
 /*
- * This structure describes the operations possible on a particular device type
- * (CD-ROM, tape, DISK and so on).
- *
- * This is the main hook for device type support submodules.
+ * Subdrivers support.
  */
+#define IDE_SUBDRIVER_VERSION	1
 
-struct ata_operations {
-	struct module *owner;
-	void (*attach) (struct ata_device *);
-	int (*cleanup)(struct ata_device *);
-	int (*standby)(struct ata_device *);
-	ide_startstop_t	(*do_request)(struct ata_device *, struct request *, sector_t);
-	int (*end_request)(struct ata_device *, struct request *, int);
-
-	int (*ioctl)(struct ata_device *, struct inode *, struct file *, unsigned int, unsigned long);
-	int (*open)(struct inode *, struct file *, struct ata_device *);
-	void (*release)(struct inode *, struct file *, struct ata_device *);
-	int (*check_media_change)(struct ata_device *);
-	void (*revalidate)(struct ata_device *);
-
-	sector_t (*capacity)(struct ata_device *);
-
-	/* linked list of rgistered device type drivers */
-	struct ata_operations *next;
-};
-
-/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
-#define ata_get(ata) \
-	(((ata) && (ata)->owner)	\
-		? ( try_inc_mod_count((ata)->owner) ? (ata) : NULL ) \
-		: (ata))
-
-#define ata_put(ata) \
-do {	\
-	if ((ata) && (ata)->owner) \
-		__MOD_DEC_USE_COUNT((ata)->owner);	\
-} while(0)
-
-extern sector_t ata_capacity(struct ata_device *drive);
-
-extern void unregister_ata_driver(struct ata_operations *driver);
-extern int register_ata_driver(struct ata_operations *driver);
-static inline int ata_driver_module(struct ata_operations *driver)
-{
-#ifdef MODULE
-	if (register_ata_driver(driver) <= 0) {
-		unregister_ata_driver(driver);
-		return -ENODEV;
-	}
-#else
-	register_ata_driver(driver);
+typedef struct ide_driver_s {
+	const char			*name;
+	const char			*version;
+	byte				media;
+	unsigned busy			: 1;
+	unsigned supports_dma		: 1;
+	unsigned supports_dsc_overlap	: 1;
+	int		(*cleanup)(ide_drive_t *);
+	int		(*standby)(ide_drive_t *);
+	int		(*suspend)(ide_drive_t *);
+	int		(*resume)(ide_drive_t *);
+	int		(*flushcache)(ide_drive_t *);
+	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
+	int		(*end_request)(ide_drive_t *, int);
+	byte		(*sense)(ide_drive_t *, const char *, byte);
+	ide_startstop_t (*error)(ide_drive_t *, const char *, byte);
+	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+	int		(*open)(struct inode *, struct file *, ide_drive_t *);
+	void		(*release)(struct inode *, struct file *, ide_drive_t *);
+	int		(*media_change)(ide_drive_t *);
+	void		(*revalidate)(ide_drive_t *);
+	void		(*pre_reset)(ide_drive_t *);
+	unsigned long	(*capacity)(ide_drive_t *);
+	ide_startstop_t	(*special)(ide_drive_t *);
+	ide_proc_entry_t        *proc;
+	int		(*init)(void);
+	int		(*reinit)(ide_drive_t *);
+	void		(*ata_prebuilder)(ide_drive_t *);
+	void		(*atapi_prebuilder)(ide_drive_t *);
+} ide_driver_t;
+
+#define DRIVER(drive)		((drive)->driver)
+
+/*
+ * IDE modules.
+ */
+#define IDE_CHIPSET_MODULE		0	/* not supported yet */
+#define IDE_PROBE_MODULE		1
+#define IDE_DRIVER_MODULE		2
+
+typedef int	(ide_module_init_proc)(void);
+
+typedef struct ide_module_s {
+	int				type;
+	ide_module_init_proc		*init;
+	void				*info;
+	struct ide_module_s		*next;
+} ide_module_t;
+
+/*
+ * ide_hwifs[] is the master data structure used to keep track
+ * of just about everything in ide.c.  Whenever possible, routines
+ * should be using pointers to a drive (ide_drive_t *) or
+ * pointers to a hwif (ide_hwif_t *), rather than indexing this
+ * structure directly (the allocation/layout may change!).
+ *
+ */
+#ifndef _IDE_C
+extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
+extern	ide_module_t	*ide_modules;
+extern	ide_module_t	*ide_probe;
 #endif
-	return 0;
-}
-
-#define ata_ops(drive)		((drive)->driver)
-
-extern struct ata_channel ide_hwifs[];		/* master data repository */
 extern int noautodma;
 
 /*
@@ -1081,201 +960,374 @@
 #define DEVICE_NR(device)	(minor(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-extern int ata_end_request(struct ata_device *, struct request *, int, unsigned int);
-extern void ata_set_handler(struct ata_device *drive, ata_handler_t handler,
-		unsigned long timeout, ata_expiry_t expiry);
+int ide_end_request (ide_drive_t *drive, int uptodate);
 
-extern u8 ata_dump(struct ata_device *, struct request *, const char *);
-extern ide_startstop_t ata_error(struct ata_device *, struct request *rq, const char *);
+/*
+ * This is used on exit from the driver, to designate the next irq handler
+ * and also to start the safety timer.
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
 
-extern void ide_fixstring(char *s, const int bytecount, const int byteswap);
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * ide_error() takes action based on the error returned by the controller.
+ * The caller should return immediately after invoking this.
+ */
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * Issue a simple drive command
+ * The drive must be selected beforehand.
+ */
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+
+/*
+ * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+ * removing leading/trailing blanks and compressing internal blanks.
+ * It is primarily used to tidy up the model name/number fields as
+ * returned by the WIN_[P]IDENTIFY commands.
+ */
+void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after doing "*startstop = ide_error()", and the
+ * caller should return the updated value of "startstop" in this case.
+ * "startstop" is unchanged when the function returns 0;
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
 
 /*
  * This routine is called from the partition-table code in genhd.c
  * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
  */
-int ide_xlate_1024(kdev_t, int, int, const char *);
+int ide_xlate_1024 (kdev_t, int, int, const char *);
 
 /*
- * Convert kdev_t structure into struct ata_device * one.
+ * Convert kdev_t structure into ide_drive_t * one.
  */
-struct ata_device *get_info_ptr(kdev_t i_rdev);
+ide_drive_t *get_info_ptr (kdev_t i_rdev);
 
 /*
- * temporarily mapping a (possible) highmem bio for PIO transfer
+ * Return the current idea about the total capacity of this drive.
  */
-#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+unsigned long current_capacity (ide_drive_t *drive);
 
-struct ata_taskfile {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_task_hdr  hobfile;
-	u8 cmd;					/* actual ATA command */
-	int command_type;
-	ide_startstop_t (*XXX_handler)(struct ata_device *, struct request *);
-};
-
-extern void ata_read(struct ata_device *, void *, unsigned int);
-extern void ata_write(struct ata_device *, void *, unsigned int);
-
-extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *, char *);
-extern int ide_config_drive_speed(struct ata_device *, u8);
-extern int eighty_ninty_three(struct ata_device *);
+void ide_revalidate_drive (ide_drive_t *drive);
 
-extern int system_bus_speed;
+/*
+ * Start a reset operation for an IDE interface.
+ * The caller should return immediately after invoking this.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *);
 
 /*
- * CompactFlash cards and their brethern pretend to be removable hard disks,
- * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate
- * config bits.
+ * Re-Start an operation for an IDE interface.
+ * The caller should return immediately after invoking this.
  */
+int restart_request (ide_drive_t *, struct request *);
 
-extern int drive_is_flashcard(struct ata_device *);
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_cmd (struct request *rq);
 
-extern int ide_spin_wait_hwgroup(struct ata_device *);
-extern void ide_timer_expiry(unsigned long data);
-extern void ata_irq_request(int irq, void *data, struct pt_regs *regs);
-extern void do_ide_request(request_queue_t * q);
-extern void ide_init_subdrivers(void);
+/*
+ * "action" parameter type for ide_do_drive_cmd() below.
+ */
+typedef enum {
+	ide_wait,	/* insert rq at end of list, and wait for it */
+	ide_next,	/* insert rq immediately after current request */
+	ide_preempt,	/* insert rq in front of current request */
+	ide_end		/* insert rq at end of list, but don't wait for it */
+} ide_action_t;
 
-extern struct block_device_operations ide_fops[];
+/*
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * If action is ide_wait, then the rq is queued at the end of the
+ * request queue, and the function sleeps until it has been processed.
+ * This is for use when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then the rq is queued at the head of
+ * the request queue, displacing the currently-being-processed
+ * request and this function returns immediately without waiting
+ * for the new rq to be completed.  This is VERY DANGEROUS, and is
+ * intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_next, then the rq is queued immediately after
+ * the currently-being-processed-request (if any), and the function
+ * returns without waiting for the new rq to be completed.  As above,
+ * This is VERY DANGEROUS, and is intended for careful use by the
+ * ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code.
+ */
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
 
-/* Probe for devices attached to the systems host controllers.
+/*
+ * Clean up after success/failure of an explicit drive cmd.
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
  */
-extern int ideprobe_init(void);
-#ifdef CONFIG_BLK_DEV_IDEDISK
-extern int idedisk_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDECD
-extern int ide_cdrom_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDETAPE
-extern int idetape_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-extern int idefloppy_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDESCSI
-extern int idescsi_init(void);
-#endif
+void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
-extern int ata_register_device(struct ata_device *, struct ata_operations *);
-extern int ata_unregister_device(struct ata_device *drive);
-extern int ide_revalidate(kdev_t i_rdev);
-extern void ide_driver_module(void);
-
-#ifdef CONFIG_PCI
-# define ON_BOARD		0
-# define NEVER_BOARD		1
-# ifdef CONFIG_BLK_DEV_OFFBOARD
-#  define OFF_BOARD		ON_BOARD
-# else
-#  define OFF_BOARD		NEVER_BOARD
-# endif
+/*
+ * Issue ATA command and wait for completion. use for implementing commands in kernel
+ */
+int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
 
-void __init ide_scan_pcibus(int scan_direction);
-#endif
+int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
+ 
+typedef struct ide_task_s {
+	task_ioreg_t		tfRegister[8];
+	task_ioreg_t		hobRegister[8];
+	ide_reg_valid_t		tf_out_flags;
+	ide_reg_valid_t		tf_in_flags;
+	int			data_phase;
+	int			command_type;
+	ide_pre_handler_t	*prehandler;
+	ide_handler_t		*handler;
+	ide_post_handler_t	*posthandler;
+	struct request		*rq;		/* copy of request */
+	void			*special;	/* valid_t generally */
+} ide_task_t;
 
-static inline void udma_enable(struct ata_device *drive, int on, int verbose)
-{
-	drive->channel->udma_enable(drive, on, verbose);
-}
+typedef struct pkt_task_s {
+	task_ioreg_t		tfRegister[8];
+	int			data_phase;
+	int			command_type;
+	ide_handler_t		*handler;
+	struct request		*rq;		/* copy of request */
+	void			*special;
+} pkt_task_t;
 
-static inline void udma_start(struct ata_device *drive, struct request *rq)
-{
-	drive->channel->udma_start(drive, rq);
-}
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
 
-static inline int udma_stop(struct ata_device *drive)
-{
-	int ret;
+int drive_is_ready (ide_drive_t *drive);
+int wait_for_ready (ide_drive_t *drive, int timeout);
 
-	ret = drive->channel->udma_stop(drive);
-	clear_bit(IDE_DMA, drive->channel->active);
+/*
+ * taskfile io for disks for now...and builds request from ide_ioctl
+ */
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
 
-	return ret;
-}
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err);
 
 /*
- * Initiate actual DMA data transfer. The direction is encoded in the request.
+ * Special Flagged Register Validation Caller
  */
-static inline ide_startstop_t udma_init(struct ata_device *drive, struct request *rq)
-{
-	int ret;
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
 
-	set_bit(IDE_DMA, drive->channel->active);
-	ret = drive->channel->udma_init(drive, rq);
-	if (ret != ATA_OP_CONTINUES)
-		clear_bit(IDE_DMA, drive->channel->active);
+ide_startstop_t set_multmode_intr (ide_drive_t *drive);
+ide_startstop_t set_geometry_intr (ide_drive_t *drive);
+ide_startstop_t recal_intr (ide_drive_t *drive);
+ide_startstop_t task_no_data_intr (ide_drive_t *drive);
+ide_startstop_t task_in_intr (ide_drive_t *drive);
+ide_startstop_t task_mulin_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_out_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_mulout_intr (ide_drive_t *drive);
+void ide_init_drive_taskfile (struct request *rq);
 
-	return ret;
-}
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
 
-static inline int udma_irq_status(struct ata_device *drive)
-{
-	return drive->channel->udma_irq_status(drive);
-}
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+/* Expects args is a full set of TF registers and parses the command type */
+int ide_cmd_type_parser (ide_task_t *args);
 
-static inline void udma_timeout(struct ata_device *drive)
-{
-	drive->channel->udma_timeout(drive);
-}
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 
-static inline void udma_irq_lost(struct ata_device *drive)
-{
-	drive->channel->udma_irq_lost(drive);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
+#ifdef CONFIG_PKT_TASK_IOCTL
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
 
-extern void udma_pci_enable(struct ata_device *drive, int on, int verbose);
-extern void udma_pci_start(struct ata_device *drive, struct request *rq);
-extern int udma_pci_stop(struct ata_device *drive);
-extern int udma_pci_init(struct ata_device *drive, struct request *rq);
-extern int udma_pci_irq_status(struct ata_device *drive);
-extern void udma_pci_timeout(struct ata_device *drive);
-extern void udma_pci_irq_lost(struct ata_device *);
-extern int udma_pci_setup(struct ata_device *, int);
+void ide_delay_50ms (void);
+int system_bus_clock(void);
 
-extern int udma_generic_setup(struct ata_device *, int);
+byte ide_auto_reduce_xfer (ide_drive_t *drive);
+int ide_driveid_update (ide_drive_t *drive);
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
+int ide_config_drive_speed (ide_drive_t *drive, byte speed);
+byte eighty_ninty_three (ide_drive_t *drive);
+int set_transfer (ide_drive_t *drive, ide_task_t *args);
+int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf);
 
-extern int udma_new_table(struct ata_device *, struct request *);
-extern void udma_destroy_table(struct ata_channel *);
-extern void udma_print(struct ata_device *);
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ */
+int ide_system_bus_speed (void);
 
-extern int udma_black_list(struct ata_device *);
-extern int udma_white_list(struct ata_device *);
+/*
+ * ide_stall_queue() can be used by a drive to give excess bandwidth back
+ * to the hwgroup by sleeping for timeout jiffies.
+ */
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
 
-extern ide_startstop_t udma_tcq_init(struct ata_device *, struct request *);
-extern int udma_tcq_enable(struct ata_device *, int);
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+request_queue_t *ide_get_queue (kdev_t dev);
 
-extern ide_startstop_t ide_dma_intr(struct ata_device *, struct request *);
-extern int check_drive_lists(struct ata_device *, int good_bad);
-extern void ide_release_dma(struct ata_channel *);
-extern int ata_start_dma(struct ata_device *, struct request *rq);
+/*
+ * CompactFlash cards and their brethern pretend to be removable hard disks,
+ * but they never have a slave unit, and they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ */
+int drive_is_flashcard (ide_drive_t *drive);
 
-extern void ata_init_dma(struct ata_channel *,	unsigned long) __init;
+int ide_spin_wait_hwgroup (ide_drive_t *drive);
+void ide_timer_expiry (unsigned long data);
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
+void do_ide_request (request_queue_t * q);
+void ide_init_subdrivers (void);
 
+#ifndef _IDE_C
+extern struct block_device_operations ide_fops[];
+extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
-extern void ata_fix_driveid(struct hd_driveid *);
+int ide_reinit_drive (ide_drive_t *drive);
+
+#ifdef _IDE_C
+#ifdef CONFIG_BLK_DEV_IDE
+int ideprobe_init (void);
+#endif /* CONFIG_BLK_DEV_IDE */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_reinit (ide_drive_t *drive);
+int idedisk_init (void);
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_reinit (ide_drive_t *drive);
+int ide_cdrom_init (void);
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_reinit (ide_drive_t *drive);
+int idetape_init (void);
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_reinit (ide_drive_t *drive);
+int idefloppy_init (void);
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_reinit (ide_drive_t *drive);
+int idescsi_init (void);
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+#endif /* _IDE_C */
+
+int ide_register_module (ide_module_t *module);
+void ide_unregister_module (ide_module_t *module);
+ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
+int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
+int ide_unregister_subdriver (ide_drive_t *drive);
+int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#define ON_BOARD		1
+#define NEVER_BOARD		0
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+#  define OFF_BOARD		ON_BOARD
+#else /* CONFIG_BLK_DEV_OFFBOARD */
+#  define OFF_BOARD		NEVER_BOARD
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
 
-extern spinlock_t ide_lock;
 
-#define DRIVE_LOCK(drive)	((drive)->queue.queue_lock)
+typedef struct ide_pci_enablebit_s {
+	byte	reg;	/* byte pci reg holding the enable-bit */
+	byte	mask;	/* mask to isolate the enable-bit */
+	byte	val;	/* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+	ide_pci_devid_t		devid;
+	char			*name;
+	void			(*fixup_device)(struct pci_dev *, struct ide_pci_device_s *);
+	unsigned int		(*init_chipset)(struct pci_dev *, const char *);
+	unsigned int		(*ata66_check)(ide_hwif_t *);
+	void			(*init_hwif)(ide_hwif_t *);
+	void			(*dma_init)(ide_hwif_t *, unsigned long);
+	ide_pci_enablebit_t	enablebits[2];
+	byte			bootable;
+	unsigned int		extra;
+} ide_pci_device_t;
 
-/* Low level device access functions. */
+#ifdef LINUX_PCI_H
+extern inline void ide_register_xp_fix(struct pci_dev *dev)
+{
+	int i;
+	unsigned short cmd;
+	unsigned long flags;
+	unsigned long base_address[4] = { 0x1f0, 0x3f4, 0x170, 0x374 };
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for (i=0; i<4; i++) {
+		dev->resource[i].start = 0;
+		dev->resource[i].end = 0;
+		dev->resource[i].flags = 0;
+	}
+	for (i=0; i<4; i++) {
+		dev->resource[i].start = base_address[i];
+		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+		pci_write_config_dword(dev,
+			(PCI_BASE_ADDRESS_0 + (i * 4)),
+			dev->resource[i].start);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+	local_irq_restore(flags);
+}
 
-extern void ata_select(struct ata_device *, unsigned long);
-extern void ata_mask(struct ata_device *);
-extern int ata_status(struct ata_device *, u8, u8);
-extern int ata_status_irq(struct ata_device *drive);
-extern int ata_status_poll( struct ata_device *, u8, u8,
-		unsigned long, struct request *rq);
-
-extern int ata_irq_enable(struct ata_device *, int);
-extern void ata_reset(struct ata_channel *);
-extern void ata_out_regfile(struct ata_device *, struct hd_drive_task_hdr *);
-extern void ata_in_regfile(struct ata_device *, struct hd_drive_task_hdr *);
+void ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) __init;
+#endif /* LINUX_PCI_H */
 
+unsigned long ide_find_free_region (unsigned short size) __init;
+void ide_scan_pcibus (int scan_direction) __init;
 #endif
+#ifdef CONFIG_BLK_DEV_IDEDMA
+#define BAD_DMA_DRIVE		0
+#define GOOD_DMA_DRIVE		1
+int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
+void ide_destroy_dmatable (ide_drive_t *drive);
+ide_startstop_t ide_dma_intr (ide_drive_t *drive);
+int check_drive_lists (ide_drive_t *drive, int good_bad);
+int report_drive_dmaing (ide_drive_t *drive);
+int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
+int ide_release_dma (ide_hwif_t *hwif);
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
+unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+void hwif_unregister (ide_hwif_t *hwif);
+
+void export_ide_init_queue (ide_drive_t *drive);
+byte export_probe_for_drive (ide_drive_t *drive);
+
+extern spinlock_t ide_lock;
+
+#define local_irq_set(flags)	do { local_save_flags((flags)); local_irq_enable(); } while (0)
+
+#endif /* _IDE_H */
diff -Nru a/include/linux/init_task.h b/include/linux/init_task.h
--- a/include/linux/init_task.h	Tue Aug 27 12:27:59 2002
+++ b/include/linux/init_task.h	Tue Aug 27 12:27:59 2002
@@ -5,34 +5,34 @@
 
 #define INIT_FILES \
 { 							\
-	count:		ATOMIC_INIT(1), 		\
-	file_lock:	RW_LOCK_UNLOCKED, 		\
-	max_fds:	NR_OPEN_DEFAULT, 		\
-	max_fdset:	__FD_SETSIZE, 			\
-	next_fd:	0, 				\
-	fd:		&init_files.fd_array[0], 	\
-	close_on_exec:	&init_files.close_on_exec_init, \
-	open_fds:	&init_files.open_fds_init, 	\
-	close_on_exec_init: { { 0, } }, 		\
-	open_fds_init:	{ { 0, } }, 			\
-	fd_array:	{ NULL, } 			\
+	.count		= ATOMIC_INIT(1), 		\
+	.file_lock	= RW_LOCK_UNLOCKED, 		\
+	.max_fds	= NR_OPEN_DEFAULT, 		\
+	.max_fdset	= __FD_SETSIZE, 		\
+	.next_fd	= 0, 				\
+	.fd		= &init_files.fd_array[0], 	\
+	.close_on_exec	= &init_files.close_on_exec_init, \
+	.open_fds	= &init_files.open_fds_init, 	\
+	.close_on_exec_init = { { 0, } }, 		\
+	.open_fds_init	= { { 0, } }, 			\
+	.fd_array	= { NULL, } 			\
 }
 
 #define INIT_MM(name) \
 {			 				\
-	mm_rb:		RB_ROOT,			\
-	pgd:		swapper_pg_dir, 		\
-	mm_users:	ATOMIC_INIT(2), 		\
-	mm_count:	ATOMIC_INIT(1), 		\
-	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
-	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
-	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
+	.mm_rb		= RB_ROOT,			\
+	.pgd		= swapper_pg_dir, 		\
+	.mm_users	= ATOMIC_INIT(2), 		\
+	.mm_count	= ATOMIC_INIT(1), 		\
+	.mmap_sem	= __RWSEM_INITIALIZER(name.mmap_sem), \
+	.page_table_lock =  SPIN_LOCK_UNLOCKED, 	\
+	.mmlist		= LIST_HEAD_INIT(name.mmlist),	\
 }
 
 #define INIT_SIGNALS {	\
-	count:		ATOMIC_INIT(1), 		\
-	action:		{ {{0,}}, }, 			\
-	siglock:	SPIN_LOCK_UNLOCKED 		\
+	.count		= ATOMIC_INIT(1), 		\
+	.action		= { {{0,}}, }, 			\
+	.siglock	= SPIN_LOCK_UNLOCKED 		\
 }
 
 /*
@@ -41,45 +41,47 @@
  */
 #define INIT_TASK(tsk)	\
 {									\
-    state:		0,						\
-    thread_info:	&init_thread_info,				\
-    flags:		0,						\
-    lock_depth:		-1,						\
-    prio:		MAX_PRIO-20,					\
-    static_prio:	MAX_PRIO-20,					\
-    policy:		SCHED_NORMAL,					\
-    cpus_allowed:	-1,						\
-    mm:			NULL,						\
-    active_mm:		&init_mm,					\
-    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
-    time_slice:		HZ,						\
-    tasks:		LIST_HEAD_INIT(tsk.tasks),			\
-    real_parent:	&tsk,						\
-    parent:		&tsk,						\
-    children:		LIST_HEAD_INIT(tsk.children),			\
-    sibling:		LIST_HEAD_INIT(tsk.sibling),			\
-    thread_group:	LIST_HEAD_INIT(tsk.thread_group),		\
-    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
-    real_timer:		{						\
-	function:		it_real_fn				\
-    },									\
-    cap_effective:	CAP_INIT_EFF_SET,				\
-    cap_inheritable:	CAP_INIT_INH_SET,				\
-    cap_permitted:	CAP_FULL_SET,					\
-    keep_capabilities:	0,						\
-    rlim:		INIT_RLIMITS,					\
-    user:		INIT_USER,					\
-    comm:		"swapper",					\
-    thread:		INIT_THREAD,					\
-    fs:			&init_fs,					\
-    files:		&init_files,					\
-    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
-    sig:		&init_signals,					\
-    pending:		{ NULL, &tsk.pending.head, {{0}}},		\
-    blocked:		{{0}},						\
-    alloc_lock:		SPIN_LOCK_UNLOCKED,				\
-    switch_lock:	SPIN_LOCK_UNLOCKED,				\
-    journal_info:	NULL,						\
+	.state		= 0,						\
+	.thread_info	= &init_thread_info,				\
+	.flags		= 0,						\
+	.lock_depth	= -1,						\
+	.prio		= MAX_PRIO-20,					\
+	.static_prio	= MAX_PRIO-20,					\
+	.policy		= SCHED_NORMAL,					\
+	.cpus_allowed	= -1,						\
+	.mm		= NULL,						\
+	.active_mm	= &init_mm,					\
+	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
+	.time_slice	= HZ,						\
+	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
+	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
+	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
+	.real_parent	= &tsk,						\
+	.parent		= &tsk,						\
+	.children	= LIST_HEAD_INIT(tsk.children),			\
+	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
+	.thread_group	= LIST_HEAD_INIT(tsk.thread_group),		\
+	.wait_chldexit	= __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+	.real_timer	= {						\
+		.function	= it_real_fn				\
+	},								\
+	.cap_effective	= CAP_INIT_EFF_SET,				\
+	.cap_inheritable = CAP_INIT_INH_SET,				\
+	.cap_permitted	= CAP_FULL_SET,					\
+	.keep_capabilities = 0,						\
+	.rlim		= INIT_RLIMITS,					\
+	.user		= INIT_USER,					\
+	.comm		= "swapper",					\
+	.thread		= INIT_THREAD,					\
+	.fs		= &init_fs,					\
+	.files		= &init_files,					\
+	.sigmask_lock	= SPIN_LOCK_UNLOCKED,				\
+	.sig		= &init_signals,				\
+	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
+	.blocked	= {{0}},					\
+	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
+	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
+	.journal_info	= NULL,						\
 }
 
 
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/input.h	Tue Aug 27 12:28:05 2002
@@ -570,6 +570,7 @@
 
 #define SND_CLICK		0x00
 #define SND_BELL		0x01
+#define SND_TONE		0x02
 #define SND_MAX			0x07
 
 /*
@@ -756,6 +757,9 @@
 #define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
+#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
+	((dev->keycodesize == 1) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
+
 struct input_dev {
 
 	void *private;
@@ -807,8 +811,8 @@
 	int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
 	int (*erase_effect)(struct input_dev *dev, int effect_id);
 
-	struct input_handle *handle;
-	struct input_dev *next;
+	struct list_head	h_list;
+	struct list_head	node;
 };
 
 /*
@@ -852,6 +856,8 @@
 	unsigned long driver_info;
 };
 
+struct input_handle;
+
 struct input_handler {
 
 	void *private;
@@ -866,8 +872,8 @@
 
 	struct input_device_id *id_table;
 
-	struct input_handle *handle;
-	struct input_handler *next;
+	struct list_head	h_list;
+	struct list_head	node;
 };
 
 struct input_handle {
@@ -880,10 +886,15 @@
 	struct input_dev *dev;
 	struct input_handler *handler;
 
-	struct input_handle *dnext;
-	struct input_handle *hnext;
+	struct list_head	d_node;
+	struct list_head	h_node;
 };
 
+#define to_dev(n) container_of(n,struct input_dev,node)
+#define to_handler(n) container_of(n,struct input_handler,node);
+#define to_handle(n) container_of(n,struct input_handle,d_node)
+#define to_handle_h(n) container_of(n,struct input_handle,h_node)
+
 void input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
@@ -907,6 +918,8 @@
 #define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)
 #define input_report_ff(a,b,c)	input_event(a, EV_FF, b, c)
 #define input_report_ff_status(a,b,c)	input_event(a, EV_FF_STATUS, b, c)
+
+extern struct device_class input_devclass;
 
 #endif
 #endif
diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h
--- a/include/linux/isdn.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/isdn.h	Tue Aug 27 12:28:05 2002
@@ -317,6 +317,7 @@
                                        /*   0 = Transparent                */
   int                    huptimer;     /* Timeout-counter for auto-hangup  */
   int                    charge;       /* Counter for charging units       */
+  int                    charge_state; /* ChargeInfo state machine         */
   ulong                  chargetime;   /* Timer for Charging info          */
   int                    hupflags;     /* Flags for charge-unit-hangup:    */
 				       /* bit0: chargeint is invalid       */
@@ -329,6 +330,7 @@
   int                    onum;         /* Flag: at least 1 outgoing number */
   int                    cps;          /* current speed of this interface  */
   int                    transcount;   /* byte-counter for cps-calculation */
+  int                    last_jiffies; /* when transcount was reset        */
   int                    sqfull;       /* Flag: netdev-queue overloaded    */
   ulong                  sqfull_stamp; /* Start-Time of overload           */
   ulong                  slavedelay;   /* Dynamic bundling delaytime       */
diff -Nru a/include/linux/kbd_ll.h b/include/linux/kbd_ll.h
--- a/include/linux/kbd_ll.h	Tue Aug 27 12:27:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-/*
- *	Interface between the low-level keyboard driver and the keymapper
- */
-
-#ifndef _KBD_LL_H
-#define _KBD_LL_H
-
-extern struct pt_regs *kbd_pt_regs;
-
-void handle_scancode(unsigned char scancode, int down);
-
-#endif	/* _KBD_LL_H */
diff -Nru a/include/linux/kernel.h b/include/linux/kernel.h
--- a/include/linux/kernel.h	Tue Aug 27 12:27:42 2002
+++ b/include/linux/kernel.h	Tue Aug 27 12:27:42 2002
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <asm/byteorder.h>
 
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
@@ -116,11 +117,17 @@
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
 
+#if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
 	((unsigned char *)&addr)[3], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[0]
+#elif defined(__BIG_ENDIAN)
+#define HIPQUAD	NIPQUAD
+#else
+#error "Please fix asm/byteorder.h"
+#endif /* __LITTLE_ENDIAN */
 
 /*
  * min()/max() macros that also do
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Tue Aug 27 12:27:57 2002
+++ b/include/linux/mm.h	Tue Aug 27 12:27:57 2002
@@ -194,10 +194,17 @@
  * routine so they can be sure the page doesn't go away from under them.
  */
 #define get_page(p)		atomic_inc(&(p)->count)
-#define put_page(p)		__free_page(p)
+#define __put_page(p)		atomic_dec(&(p)->count)
 #define put_page_testzero(p) 	atomic_dec_and_test(&(p)->count)
 #define page_count(p)		atomic_read(&(p)->count)
 #define set_page_count(p,v) 	atomic_set(&(p)->count, v)
+extern void FASTCALL(__page_cache_release(struct page *));
+#define put_page(p)							\
+	do {								\
+		if (!PageReserved(p) && put_page_testzero(p))		\
+			__page_cache_release(p);			\
+	} while (0)
+void FASTCALL(__free_pages_ok(struct page *page, unsigned int order));
 
 /*
  * Multiple processes may "see" the same page. E.g. for untouched
@@ -347,12 +354,6 @@
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
-extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
-extern int ptrace_attach(struct task_struct *tsk);
-extern int ptrace_detach(struct task_struct *, unsigned int);
-extern void ptrace_disable(struct task_struct *);
-extern int ptrace_check_attach(struct task_struct *task, int kill);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/netdevice.h	Tue Aug 27 12:28:08 2002
@@ -162,7 +162,7 @@
 	unsigned fastroute_deferred_out;
 	unsigned fastroute_latency_reduction;
 	unsigned cpu_collision;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+} ____cacheline_aligned;
 
 extern struct netif_rx_stats netdev_rx_stat[];
 
@@ -376,6 +376,7 @@
 	int			(*stop)(struct net_device *dev);
 	int			(*hard_start_xmit) (struct sk_buff *skb,
 						    struct net_device *dev);
+#define HAVE_NETDEV_POLL
 	int			(*poll) (struct net_device *dev, int *quota);
 	int			(*hard_header) (struct sk_buff *skb,
 						struct net_device *dev,
@@ -501,7 +502,7 @@
 	struct sk_buff		*completion_queue;
 
 	struct net_device	backlog_dev;	/* Sorry. 8) */
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+} ____cacheline_aligned;
 
 
 extern struct softnet_data softnet_data[NR_CPUS];
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h	Tue Aug 27 12:28:02 2002
@@ -43,12 +43,57 @@
 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
 };
 
+#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
+
+/* per conntrack: protocol private data */
+union ip_conntrack_proto {
+	/* insert conntrack proto private data here */
+	struct ip_ct_tcp tcp;
+	struct ip_ct_icmp icmp;
+};
+
+union ip_conntrack_expect_proto {
+	/* insert expect proto private data here */
+};
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
+/* per expectation: application helper private data */
+union ip_conntrack_expect_help {
+	/* insert conntrack helper private data (expect) here */
+	struct ip_ct_ftp_expect exp_ftp_info;
+	struct ip_ct_irc_expect exp_irc_info;
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	union {
+		/* insert nat helper private data (expect) here */
+	} nat;
+#endif
+};
+
+/* per conntrack: application helper private data */
+union ip_conntrack_help {
+	/* insert conntrack helper private data (master) here */
+	struct ip_ct_ftp_master ct_ftp_info;
+	struct ip_ct_irc_master ct_irc_info;
+};
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+
+/* per conntrack: nat application helper private data */
+union ip_conntrack_nat_help {
+	/* insert nat helper private data here */
+};
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
 
 #ifdef CONFIG_NF_DEBUG
 #define IP_NF_ASSERT(x)							\
@@ -63,19 +108,14 @@
 #define IP_NF_ASSERT(x)
 #endif
 
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
-#endif
-
-/* Add protocol helper include file here */
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
-
 struct ip_conntrack_expect
 {
 	/* Internal linked list (global expectation list) */
 	struct list_head list;
 
+	/* reference count */
+	atomic_t use;
+
 	/* expectation list for this master */
 	struct list_head expected_list;
 
@@ -103,19 +143,12 @@
 	/* At which sequence number did this expectation occur */
 	u_int32_t seq;
   
-	union {
-		/* insert conntrack helper private data (expect) here */
-		struct ip_ct_ftp_expect exp_ftp_info;
-		struct ip_ct_irc_expect exp_irc_info;
-  
-#ifdef CONFIG_IP_NF_NAT_NEEDED
- 		union {
-			/* insert nat helper private data (expect) here */
-		} nat;
-#endif
-	} help;
+	union ip_conntrack_expect_proto proto;
+
+	union ip_conntrack_expect_help help;
 };
 
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 struct ip_conntrack
 {
 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
@@ -150,23 +183,14 @@
 
 	/* Storage reserved for other modules: */
 
-	union {
-		struct ip_ct_tcp tcp;
-		struct ip_ct_icmp icmp;
-	} proto;
+	union ip_conntrack_proto proto;
 
-	union {
-		/* insert conntrack helper private data (master) here */
-		struct ip_ct_ftp_master ct_ftp_info;
-		struct ip_ct_irc_master ct_irc_info;
-	} help;
+	union ip_conntrack_help help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 	struct {
 		struct ip_nat_info info;
-		union {
-			/* insert nat helper private data here */
-		} help;
+		union ip_conntrack_nat_help help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
 	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
 		int masq_index;
@@ -194,6 +218,16 @@
 /* Return conntrack_info and tuple hash for given skb. */
 extern struct ip_conntrack *
 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo);
+
+/* decrement reference count on a conntrack */
+extern inline void ip_conntrack_put(struct ip_conntrack *ct);
+
+/* find unconfirmed expectation based on tuple */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
+
+/* decrement reference count on an expectation */
+void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
 
 extern struct module *ip_conntrack_module;
 
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h	Tue Aug 27 12:28:08 2002
@@ -45,7 +45,7 @@
 }
 
 extern struct list_head *ip_conntrack_hash;
-extern struct list_head expect_list;
+extern struct list_head ip_conntrack_expect_list;
 DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 #endif /* _IP_CONNTRACK_CORE_H */
 
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Tue Aug 27 12:28:08 2002
@@ -2,9 +2,7 @@
 #define _IP_CONNTRACK_FTP_H
 /* FTP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
+#ifdef __KERNEL__
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
@@ -12,6 +10,8 @@
 DECLARE_LOCK_EXTERN(ip_ftp_lock);
 
 #define FTP_PORT	21
+
+#endif /* __KERNEL__ */
 
 enum ip_ct_ftp_type
 {
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Tue Aug 27 12:28:02 2002
@@ -14,22 +14,6 @@
 #ifndef _IP_CONNTRACK_IRC_H
 #define _IP_CONNTRACK_IRC_H
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
-
-#include <linux/netfilter_ipv4/lockhelp.h>
-
-#define IRC_PORT	6667
-
-struct dccproto {
-	char* match;
-	int matchlen;
-};
-
-/* Protects irc part of conntracks */
-DECLARE_LOCK_EXTERN(ip_irc_lock);
-
 /* We record seq number and length of irc ip/port text here: all in
    host order. */
 
@@ -45,5 +29,22 @@
 /* This structure exists only once per master */
 struct ip_ct_irc_master {
 };
+
+
+#ifdef __KERNEL__
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+#define IRC_PORT	6667
+
+struct dccproto {
+	char* match;
+	int matchlen;
+};
+
+/* Protects irc part of conntracks */
+DECLARE_LOCK_EXTERN(ip_irc_lock);
+
+#endif /* __KERNEL__ */
 
 #endif /* _IP_CONNTRACK_IRC_H */
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Tue Aug 27 12:28:02 2002
@@ -2,10 +2,6 @@
 #define _IP_CONNTRACK_TCP_H
 /* TCP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
-
 enum tcp_conntrack {
 	TCP_CONNTRACK_NONE,
 	TCP_CONNTRACK_ESTABLISHED,
diff -Nru a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
--- a/include/linux/netfilter_ipv4/ip_nat.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/netfilter_ipv4/ip_nat.h	Tue Aug 27 12:28:08 2002
@@ -60,22 +60,6 @@
 	struct ip_nat_range range[1];
 };
 
-#ifdef __KERNEL__
-#include <linux/list.h>
-#include <linux/netfilter_ipv4/lockhelp.h>
-
-/* Protects NAT hash tables, and NAT-private part of conntracks. */
-DECLARE_RWLOCK_EXTERN(ip_nat_lock);
-
-/* Hashes for by-source and IP/protocol. */
-struct ip_nat_hash
-{
-	struct list_head list;
-
-	/* conntrack we're embedded in: NULL if not in hash. */
-	struct ip_conntrack *conntrack;
-};
-
 /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */
 #define IP_NAT_MAX_MANIPS (2*3)
 
@@ -93,7 +77,23 @@
 	/* Manipulations to occur at each conntrack in this dirn. */
 	struct ip_conntrack_manip manip;
 };
-	
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects NAT hash tables, and NAT-private part of conntracks. */
+DECLARE_RWLOCK_EXTERN(ip_nat_lock);
+
+/* Hashes for by-source and IP/protocol. */
+struct ip_nat_hash
+{
+	struct list_head list;
+
+	/* conntrack we're embedded in: NULL if not in hash. */
+	struct ip_conntrack *conntrack;
+};
+
 /* The structure embedded in the conntrack structure. */
 struct ip_nat_info
 {
diff -Nru a/include/linux/netfilter_ipv4/ipt_DSCP.h b/include/linux/netfilter_ipv4/ipt_DSCP.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_DSCP.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,20 @@
+/* iptables module for setting the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
+*/
+#ifndef _IPT_DSCP_TARGET_H
+#define _IPT_DSCP_TARGET_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+/* target info */
+struct ipt_DSCP_info {
+	u_int8_t dscp;
+};
+
+#endif /* _IPT_DSCP_TARGET_H */
diff -Nru a/include/linux/netfilter_ipv4/ipt_ECN.h b/include/linux/netfilter_ipv4/ipt_ECN.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_ECN.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,31 @@
+/* Header file for iptables ipt_ECN target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
+*/
+#ifndef _IPT_ECN_TARGET_H
+#define _IPT_ECN_TARGET_H
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_SET_IP	0x01	/* set ECN bits of IPv4 header */
+#define IPT_ECN_OP_SET_ECE	0x10	/* set ECE bit of TCP header */
+#define IPT_ECN_OP_SET_CWR	0x20	/* set CWR bit of TCP header */
+
+#define IPT_ECN_OP_MASK		0xce
+
+struct ipt_ECN_info {
+	u_int8_t operation;	/* bitset of operations */
+	u_int8_t ip_ect;	/* ECT codepoint of IPv4 header, pre-shifted */
+	union {
+		struct {
+			u_int8_t ece:1, cwr:1; /* TCP ECT bits */
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_TARGET_H */
diff -Nru a/include/linux/netfilter_ipv4/ipt_conntrack.h b/include/linux/netfilter_ipv4/ipt_conntrack.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_conntrack.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,38 @@
+/* Header file for kernel module to match connection tracking information.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+
+#ifndef _IPT_CONNTRACK_H
+#define _IPT_CONNTRACK_H
+
+#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
+
+#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
+
+/* flags, invflags: */
+#define IPT_CONNTRACK_STATE	0x01
+#define IPT_CONNTRACK_PROTO	0x02
+#define IPT_CONNTRACK_ORIGSRC	0x04
+#define IPT_CONNTRACK_ORIGDST	0x08
+#define IPT_CONNTRACK_REPLSRC	0x10
+#define IPT_CONNTRACK_REPLDST	0x20
+#define IPT_CONNTRACK_STATUS	0x40
+#define IPT_CONNTRACK_EXPIRES	0x80
+
+struct ipt_conntrack_info
+{
+	unsigned int statemask, statusmask;
+
+	struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX];
+	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
+
+	unsigned long expires_min, expires_max;
+
+	/* Flags word */
+	u_int8_t flags;
+	/* Inverse flags */
+	u_int8_t invflags;
+};
+#endif /*_IPT_CONNTRACK_H*/
diff -Nru a/include/linux/netfilter_ipv4/ipt_dscp.h b/include/linux/netfilter_ipv4/ipt_dscp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_dscp.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,23 @@
+/* iptables module for matching the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
+*/
+#ifndef _IPT_DSCP_H
+#define _IPT_DSCP_H
+
+#define IPT_DSCP_MASK	0xfc	/* 11111100 */
+#define IPT_DSCP_SHIFT	2
+#define IPT_DSCP_MAX	0x3f	/* 00111111 */
+
+/* match info */
+struct ipt_dscp_info {
+	u_int8_t dscp;
+	u_int8_t invert;
+};
+
+#endif /* _IPT_DSCP_H */
diff -Nru a/include/linux/netfilter_ipv4/ipt_ecn.h b/include/linux/netfilter_ipv4/ipt_ecn.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_ecn.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,33 @@
+/* iptables module for matching the ECN header in IPv4 and TCP header
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
+*/
+#ifndef _IPT_ECN_H
+#define _IPT_ECN_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_MATCH_IP	0x01
+#define IPT_ECN_OP_MATCH_ECE	0x10
+#define IPT_ECN_OP_MATCH_CWR	0x20
+
+#define IPT_ECN_OP_MATCH_MASK	0xce
+
+/* match info */
+struct ipt_ecn_info {
+	u_int8_t operation;
+	u_int8_t invert;
+	u_int8_t ip_ect;
+	union {
+		struct {
+			u_int8_t ect;
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_H */
diff -Nru a/include/linux/netfilter_ipv4/ipt_helper.h b/include/linux/netfilter_ipv4/ipt_helper.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_helper.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,8 @@
+#ifndef _IPT_HELPER_H
+#define _IPT_HELPER_H
+
+struct ipt_helper_info {
+	int invert;
+	char name[30];
+};
+#endif /* _IPT_HELPER_H */
diff -Nru a/include/linux/netfilter_ipv4/ipt_owner.h b/include/linux/netfilter_ipv4/ipt_owner.h
--- a/include/linux/netfilter_ipv4/ipt_owner.h	Tue Aug 27 12:27:59 2002
+++ b/include/linux/netfilter_ipv4/ipt_owner.h	Tue Aug 27 12:27:59 2002
@@ -6,12 +6,14 @@
 #define IPT_OWNER_GID	0x02
 #define IPT_OWNER_PID	0x04
 #define IPT_OWNER_SID	0x08
+#define IPT_OWNER_COMM	0x10
 
 struct ipt_owner_info {
     uid_t uid;
     gid_t gid;
     pid_t pid;
     pid_t sid;
+    char comm[16];
     u_int8_t match, invert;	/* flags */
 };
 
diff -Nru a/include/linux/netfilter_ipv4/ipt_pkttype.h b/include/linux/netfilter_ipv4/ipt_pkttype.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv4/ipt_pkttype.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,8 @@
+#ifndef _IPT_PKTTYPE_H
+#define _IPT_PKTTYPE_H
+
+struct ipt_pkttype_info {
+	int	pkttype;
+	int	invert;
+};
+#endif /*_IPT_PKTTYPE_H*/
diff -Nru a/include/linux/netfilter_ipv6/ip6t_length.h b/include/linux/netfilter_ipv6/ip6t_length.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_ipv6/ip6t_length.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,10 @@
+#ifndef _IP6T_LENGTH_H
+#define _IP6T_LENGTH_H
+
+struct ip6t_length_info {
+	u_int16_t  min, max;
+	u_int8_t   invert;
+};
+
+#endif /*_IP6T_LENGTH_H*/
+	
diff -Nru a/include/linux/nfs.h b/include/linux/nfs.h
--- a/include/linux/nfs.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/nfs.h	Tue Aug 27 12:28:01 2002
@@ -39,40 +39,69 @@
  * standard, but seem to be widely used nevertheless.
  */
  enum nfs_stat {
-	NFS_OK = 0,			/* v2 v3 */
-	NFSERR_PERM = 1,		/* v2 v3 */
-	NFSERR_NOENT = 2,		/* v2 v3 */
-	NFSERR_IO = 5,			/* v2 v3 */
-	NFSERR_NXIO = 6,		/* v2 v3 */
+	NFS_OK = 0,			/* v2 v3 v4 */
+	NFSERR_PERM = 1,		/* v2 v3 v4 */
+	NFSERR_NOENT = 2,		/* v2 v3 v4 */
+	NFSERR_IO = 5,			/* v2 v3 v4 */
+	NFSERR_NXIO = 6,		/* v2 v3 v4 */
 	NFSERR_EAGAIN = 11,		/* v2 v3 */
-	NFSERR_ACCES = 13,		/* v2 v3 */
-	NFSERR_EXIST = 17,		/* v2 v3 */
-	NFSERR_XDEV = 18,		/*    v3 */
-	NFSERR_NODEV = 19,		/* v2 v3 */
-	NFSERR_NOTDIR = 20,		/* v2 v3 */
-	NFSERR_ISDIR = 21,		/* v2 v3 */
-	NFSERR_INVAL = 22,		/* v2 v3 that Sun forgot */
-	NFSERR_FBIG = 27,		/* v2 v3 */
-	NFSERR_NOSPC = 28,		/* v2 v3 */
-	NFSERR_ROFS = 30,		/* v2 v3 */
-	NFSERR_MLINK = 31,		/*    v3 */
+	NFSERR_ACCES = 13,		/* v2 v3 v4 */
+	NFSERR_EXIST = 17,		/* v2 v3 v4 */
+	NFSERR_XDEV = 18,		/*    v3 v4 */
+	NFSERR_NODEV = 19,		/* v2 v3 v4 */
+	NFSERR_NOTDIR = 20,		/* v2 v3 v4 */
+	NFSERR_ISDIR = 21,		/* v2 v3 v4 */
+	NFSERR_INVAL = 22,		/* v2 v3 v4 */
+	NFSERR_FBIG = 27,		/* v2 v3 v4 */
+	NFSERR_NOSPC = 28,		/* v2 v3 v4 */
+	NFSERR_ROFS = 30,		/* v2 v3 v4 */
+	NFSERR_MLINK = 31,		/*    v3 v4 */
 	NFSERR_OPNOTSUPP = 45,		/* v2 v3 */
-	NFSERR_NAMETOOLONG = 63,	/* v2 v3 */
-	NFSERR_NOTEMPTY = 66,		/* v2 v3 */
-	NFSERR_DQUOT = 69,		/* v2 v3 */
-	NFSERR_STALE = 70,		/* v2 v3 */
+	NFSERR_NAMETOOLONG = 63,	/* v2 v3 v4 */
+	NFSERR_NOTEMPTY = 66,		/* v2 v3 v4 */
+	NFSERR_DQUOT = 69,		/* v2 v3 v4 */
+	NFSERR_STALE = 70,		/* v2 v3 v4 */
 	NFSERR_REMOTE = 71,		/* v2 v3 */
 	NFSERR_WFLUSH = 99,		/* v2    */
-	NFSERR_BADHANDLE = 10001,	/*    v3 */
+	NFSERR_BADHANDLE = 10001,	/*    v3 v4 */
 	NFSERR_NOT_SYNC = 10002,	/*    v3 */
-	NFSERR_BAD_COOKIE = 10003,	/*    v3 */
-	NFSERR_NOTSUPP = 10004,		/*    v3 */
-	NFSERR_TOOSMALL = 10005,	/*    v3 */
-	NFSERR_SERVERFAULT = 10006,	/*    v3 */
-	NFSERR_BADTYPE = 10007,		/*    v3 */
-	NFSERR_JUKEBOX = 10008		/*    v3 */
- };
- 
+	NFSERR_BAD_COOKIE = 10003,	/*    v3 v4 */
+	NFSERR_NOTSUPP = 10004,		/*    v3 v4 */
+	NFSERR_TOOSMALL = 10005,	/*    v3 v4 */
+	NFSERR_SERVERFAULT = 10006,	/*    v3 v4 */
+	NFSERR_BADTYPE = 10007,		/*    v3 v4 */
+	NFSERR_JUKEBOX = 10008,		/*    v3 v4 */
+	NFSERR_SAME = 10009,		/*       v4 */
+	NFSERR_DENIED = 10010,		/*       v4 */
+	NFSERR_EXPIRED = 10011,		/*       v4 */
+	NFSERR_LOCKED = 10012,		/*       v4 */
+	NFSERR_GRACE = 10013,		/*       v4 */
+	NFSERR_FHEXPIRED = 10014,	/*       v4 */
+	NFSERR_SHARE_DENIED = 10015,	/*       v4 */
+	NFSERR_WRONGSEC = 10016,	/*       v4 */
+	NFSERR_CLID_INUSE = 10017,	/*       v4 */
+	NFSERR_RESOURCE = 10018,	/*       v4 */
+	NFSERR_MOVED = 10019,		/*       v4 */
+	NFSERR_NOFILEHANDLE = 10020,	/*       v4 */
+	NFSERR_MINOR_VERS_MISMATCH = 10021,   /* v4 */
+	NFSERR_STALE_CLIENTID = 10022,	/*       v4 */
+	NFSERR_STALE_STATEID = 10023,	/*       v4 */
+	NFSERR_OLD_STATEID = 10024,	/*       v4 */
+	NFSERR_BAD_STATEID = 10025,	/*       v4 */
+	NFSERR_BAD_SEQID = 10026,	/*       v4 */
+	NFSERR_NOT_SAME = 10027,	/*       v4 */
+	NFSERR_LOCK_RANGE = 10028,	/*       v4 */
+	NFSERR_SYMLINK = 10029,		/*       v4 */
+	NFSERR_READDIR_NOSPC = 10030,	/*       v4 */
+	NFSERR_LEASE_MOVED = 10031,	/*       v4 */
+	NFSERR_ATTRNOTSUPP = 10032,	/*       v4 */
+	NFSERR_NO_GRACE = 10033,	/*       v4 */
+	NFSERR_RECLAIM_BAD = 10034,	/*       v4 */
+	NFSERR_RECLAIM_CONFLICT = 10035,/*       v4 */
+	NFSERR_BAD_XDR = 10036,		/*       v4 */
+	NFSERR_LOCKS_HELD = 10037	/*       v4 */
+};
+
 /* NFSv2 file types - beware, these are not the same in NFSv3 */
 
 enum nfs_ftype {
diff -Nru a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
--- a/include/linux/nfsd/nfsd.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/nfsd/nfsd.h	Tue Aug 27 12:28:05 2002
@@ -55,6 +55,8 @@
 	char			plus;		/* readdirplus */
 	char			eob;		/* end of buffer */
 	char			dotonly;
+	int			nfserr;		/* v4 only */
+	u32			bmval[2];	/* v4 only */
 };
 typedef int		(*encode_dent_fn)(struct readdir_cd *, const char *,
 						int, loff_t, ino_t, unsigned int);
@@ -86,11 +88,11 @@
 				char *name, int len, struct iattr *attrs,
 				int type, dev_t rdev, struct svc_fh *res);
 #ifdef CONFIG_NFSD_V3
-int		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
+int		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
 int		nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, struct iattr *attrs,
 				struct svc_fh *res, int createmode,
-				u32 *verifier);
+				u32 *verifier, int *truncp);
 int		nfsd_commit(struct svc_rqst *, struct svc_fh *,
 				off_t, unsigned long);
 #endif /* CONFIG_NFSD_V3 */
@@ -119,7 +121,8 @@
 				unsigned long size);
 int		nfsd_readdir(struct svc_rqst *, struct svc_fh *,
 				loff_t, encode_dent_fn,
-				u32 *buffer, int *countp, u32 *verf);
+				u32 *buffer, int *countp, u32 *verf,
+				u32 *bmval);
 int		nfsd_statfs(struct svc_rqst *, struct svc_fh *,
 				struct statfs *);
 
@@ -170,6 +173,16 @@
 #define	nfserr_serverfault	__constant_htonl(NFSERR_SERVERFAULT)
 #define	nfserr_badtype		__constant_htonl(NFSERR_BADTYPE)
 #define	nfserr_jukebox		__constant_htonl(NFSERR_JUKEBOX)
+#define	nfserr_bad_cookie	__constant_htonl(NFSERR_BAD_COOKIE)
+#define	nfserr_same		__constant_htonl(NFSERR_SAME)
+#define	nfserr_clid_inuse	__constant_htonl(NFSERR_CLID_INUSE)
+#define	nfserr_resource		__constant_htonl(NFSERR_RESOURCE)
+#define	nfserr_nofilehandle	__constant_htonl(NFSERR_NOFILEHANDLE)
+#define	nfserr_minor_vers_mismatch	__constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
+#define	nfserr_symlink		__constant_htonl(NFSERR_SYMLINK)
+#define	nfserr_not_same		__constant_htonl(NFSERR_NOT_SAME)
+#define	nfserr_readdir_nospc	__constant_htonl(NFSERR_READDIR_NOSPC)
+#define	nfserr_bad_xdr		__constant_htonl(NFSERR_BAD_XDR)
 
 /* error code for internal use - if a request fails due to
  * kmalloc failure, it gets dropped.  Client should resend eventually
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/page-flags.h	Tue Aug 27 12:28:01 2002
@@ -154,6 +154,7 @@
 		ret;							\
 	})
 
+#define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
 #define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
 #define TestSetPageLRU(page)	test_and_set_bit(PG_lru, &(page)->flags)
 #define TestClearPageLRU(page)	test_and_clear_bit(PG_lru, &(page)->flags)
@@ -161,6 +162,7 @@
 #define PageActive(page)	test_bit(PG_active, &(page)->flags)
 #define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
 #define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
+#define TestClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags)
 
 #define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
 #define SetPageSlab(page)	set_bit(PG_slab, &(page)->flags)
diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Tue Aug 27 12:27:51 2002
+++ b/include/linux/pagemap.h	Tue Aug 27 12:27:51 2002
@@ -23,14 +23,18 @@
 #define PAGE_CACHE_ALIGN(addr)	(((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
 
 #define page_cache_get(x)	get_page(x)
-extern void FASTCALL(page_cache_release(struct page *));
+
+static inline void page_cache_release(struct page *page)
+{
+	if (!PageReserved(page) && put_page_testzero(page))
+		__page_cache_release(page);
+}
 
 static inline struct page *page_cache_alloc(struct address_space *x)
 {
 	return alloc_pages(x->gfp_mask, 0);
 }
 
-
 typedef int filler_t(void *, struct page *);
 
 extern struct page * find_get_page(struct address_space *mapping,
@@ -57,6 +61,8 @@
 				void *data);
 
 extern int add_to_page_cache(struct page *page,
+		struct address_space *mapping, unsigned long index);
+extern int add_to_page_cache_lru(struct page *page,
 		struct address_space *mapping, unsigned long index);
 extern void remove_from_page_cache(struct page *page);
 extern void __remove_from_page_cache(struct page *page);
diff -Nru a/include/linux/pagevec.h b/include/linux/pagevec.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/pagevec.h	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,77 @@
+/*
+ * include/linux/pagevec.h
+ *
+ * In many places it is efficient to batch an operation up against multiple
+ * pages.  A pagevec is a multipage container which is used for that.
+ */
+
+#define PAGEVEC_SIZE	16
+
+struct page;
+
+struct pagevec {
+	unsigned nr;
+	struct page *pages[PAGEVEC_SIZE];
+};
+
+void __pagevec_release(struct pagevec *pvec);
+void __pagevec_release_nonlru(struct pagevec *pvec);
+void __pagevec_free(struct pagevec *pvec);
+void __pagevec_lru_add(struct pagevec *pvec);
+void __pagevec_lru_del(struct pagevec *pvec);
+void lru_add_drain(void);
+void pagevec_deactivate_inactive(struct pagevec *pvec);
+
+static inline void pagevec_init(struct pagevec *pvec)
+{
+	pvec->nr = 0;
+}
+
+static inline unsigned pagevec_count(struct pagevec *pvec)
+{
+	return pvec->nr;
+}
+
+static inline unsigned pagevec_space(struct pagevec *pvec)
+{
+	return PAGEVEC_SIZE - pvec->nr;
+}
+
+/*
+ * Add a page to a pagevec.  Returns the number of slots still available.
+ */
+static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)
+{
+	pvec->pages[pvec->nr++] = page;
+	return pagevec_space(pvec);
+}
+
+static inline void pagevec_release(struct pagevec *pvec)
+{
+	if (pagevec_count(pvec))
+		__pagevec_release(pvec);
+}
+
+static inline void pagevec_release_nonlru(struct pagevec *pvec)
+{
+	if (pagevec_count(pvec))
+		__pagevec_release_nonlru(pvec);
+}
+
+static inline void pagevec_free(struct pagevec *pvec)
+{
+	if (pagevec_count(pvec))
+		__pagevec_free(pvec);
+}
+
+static inline void pagevec_lru_add(struct pagevec *pvec)
+{
+	if (pagevec_count(pvec))
+		__pagevec_lru_add(pvec);
+}
+
+static inline void pagevec_lru_del(struct pagevec *pvec)
+{
+	if (pagevec_count(pvec))
+		__pagevec_lru_del(pvec);
+}
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/pci_ids.h	Tue Aug 27 12:28:02 2002
@@ -612,12 +612,14 @@
 #define PCI_DEVICE_ID_PROMISE_20267	0x4d30
 #define PCI_DEVICE_ID_PROMISE_20246	0x4d33
 #define PCI_DEVICE_ID_PROMISE_20262	0x4d38
+#define PCI_DEVICE_ID_PROMISE_20263	0x0D38
 #define PCI_DEVICE_ID_PROMISE_20268	0x4d68
 #define PCI_DEVICE_ID_PROMISE_20268R	0x6268
 #define PCI_DEVICE_ID_PROMISE_20269	0x4d69
 #define PCI_DEVICE_ID_PROMISE_20271	0x6269
 #define PCI_DEVICE_ID_PROMISE_20275	0x1275
 #define PCI_DEVICE_ID_PROMISE_20276	0x5275
+#define PCI_DEVICE_ID_PROMISE_20277	0x7275
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
 #define PCI_VENDOR_ID_N9		0x105d
@@ -940,6 +942,8 @@
 #define PCI_DEVICE_ID_TTI_HPT343	0x0003
 #define PCI_DEVICE_ID_TTI_HPT366	0x0004
 #define PCI_DEVICE_ID_TTI_HPT372	0x0005
+#define PCI_DEVICE_ID_TTI_HPT302	0x0006
+#define PCI_DEVICE_ID_TTI_HPT371	0x0007
 #define PCI_DEVICE_ID_TTI_HPT374	0x0008
 
 #define PCI_VENDOR_ID_VIA		0x1106
@@ -1676,6 +1680,7 @@
 #define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
 #define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
 #define PCI_DEVICE_ID_INTEL_82801E_9	0x245b
+#define PCI_DEVICE_ID_INTEL_82801E_11	PCI_DEVICE_ID_INTEL_82801E_9
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
@@ -1687,6 +1692,7 @@
 #define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
 #define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
 #define PCI_DEVICE_ID_INTEL_82801DB_9	0x24cb
+#define PCI_DEVICE_ID_INTEL_82801DB_11	PCI_DEVICE_ID_INTEL_82801DB_9
 #define PCI_DEVICE_ID_INTEL_80310	0x530d
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
diff -Nru a/include/linux/percpu.h b/include/linux/percpu.h
--- a/include/linux/percpu.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/percpu.h	Tue Aug 27 12:28:02 2002
@@ -1,14 +1,9 @@
 #ifndef __LINUX_PERCPU_H
 #define __LINUX_PERCPU_H
-#include <linux/config.h>
-
-#ifdef CONFIG_SMP
-#define __per_cpu_data	__attribute__((section(".data.percpu")))
+#include <linux/spinlock.h> /* For preempt_disable() */
 #include <asm/percpu.h>
-#else
-#define __per_cpu_data
-#define per_cpu(var, cpu)			var
-#define this_cpu(var)				var
-#endif
+
+#define get_cpu_var(var) ({ preempt_disable(); __get_cpu_var(var); })
+#define put_cpu_var(var) preempt_enable()
 
 #endif /* __LINUX_PERCPU_H */
diff -Nru a/include/linux/prctl.h b/include/linux/prctl.h
--- a/include/linux/prctl.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/prctl.h	Tue Aug 27 12:28:07 2002
@@ -26,4 +26,12 @@
 # define PR_FPEMU_NOPRINT	1	/* silently emulate fp operations accesses */
 # define PR_FPEMU_SIGFPE	2	/* don't emulate fp operations, send SIGFPE instead */
 
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC	11
+#define PR_SET_FPEXC	12
+# define PR_FP_EXC_DISABLED	0	/* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV	1	/* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC	2	/* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE	3	/* precise exception mode */
+
 #endif /* _LINUX_PRCTL_H */
diff -Nru a/include/linux/preempt.h b/include/linux/preempt.h
--- a/include/linux/preempt.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/preempt.h	Tue Aug 27 12:28:02 2002
@@ -1,9 +1,14 @@
 #ifndef __LINUX_PREEMPT_H
 #define __LINUX_PREEMPT_H
 
+/*
+ * include/linux/preempt.h - macros for accessing and manipulating
+ * preempt_count (used for kernel preemption, interrupt count, etc.)
+ */
+
 #include <linux/config.h>
 
-#define preempt_count() (current_thread_info()->preempt_count)
+#define preempt_count()	(current_thread_info()->preempt_count)
 
 #define inc_preempt_count() \
 do { \
@@ -31,17 +36,16 @@
 	barrier(); \
 } while (0)
 
-#define preempt_enable() \
+#define preempt_check_resched() \
 do { \
-	preempt_enable_no_resched(); \
 	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
 		preempt_schedule(); \
 } while (0)
 
-#define preempt_check_resched() \
+#define preempt_enable() \
 do { \
-	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
-		preempt_schedule(); \
+	preempt_enable_no_resched(); \
+	preempt_check_resched(); \
 } while (0)
 
 #define inc_preempt_count_non_preempt()	do { } while (0)
@@ -50,7 +54,7 @@
 #else
 
 #define preempt_disable()		do { } while (0)
-#define preempt_enable_no_resched()	do {} while(0)
+#define preempt_enable_no_resched()	do { } while (0)
 #define preempt_enable()		do { } while (0)
 #define preempt_check_resched()		do { } while (0)
 
diff -Nru a/include/linux/prefetch.h b/include/linux/prefetch.h
--- a/include/linux/prefetch.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/prefetch.h	Tue Aug 27 12:28:08 2002
@@ -39,17 +39,14 @@
  */
  
 #ifndef ARCH_HAS_PREFETCH
-#define ARCH_HAS_PREFETCH
 static inline void prefetch(const void *x) {;}
 #endif
 
 #ifndef ARCH_HAS_PREFETCHW
-#define ARCH_HAS_PREFETCHW
 static inline void prefetchw(const void *x) {;}
 #endif
 
 #ifndef ARCH_HAS_SPINLOCK_PREFETCH
-#define ARCH_HAS_SPINLOCK_PREFETCH
 #define spin_lock_prefetch(x) prefetchw(x)
 #endif
 
diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Tue Aug 27 12:27:42 2002
+++ b/include/linux/proc_fs.h	Tue Aug 27 12:27:42 2002
@@ -74,8 +74,6 @@
 	kdev_t	rdev;
 };
 
-#define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff)
-
 #ifdef CONFIG_PROC_FS
 
 extern struct proc_dir_entry proc_root;
@@ -89,7 +87,6 @@
 extern void proc_misc_init(void);
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry);
-void proc_pid_delete_inode(struct inode *inode);
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
 
 extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h	Tue Aug 27 12:27:59 2002
+++ b/include/linux/ptrace.h	Tue Aug 27 12:27:59 2002
@@ -3,6 +3,8 @@
 /* ptrace.h */
 /* structs and defines to help the user use the ptrace system call. */
 
+#include <linux/compiler.h>
+
 /* has the defines to get at the registers. */
 
 #define PTRACE_TRACEME		   0
@@ -22,5 +24,27 @@
 #define PTRACE_SYSCALL		  24
 
 #include <asm/ptrace.h>
+
+extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
+extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
+extern int ptrace_attach(struct task_struct *tsk);
+extern int ptrace_detach(struct task_struct *, unsigned int);
+extern void ptrace_disable(struct task_struct *);
+extern int ptrace_check_attach(struct task_struct *task, int kill);
+extern void __ptrace_link(struct task_struct *child,
+				struct task_struct *new_parent);
+extern void __ptrace_unlink(struct task_struct *child);
+
+static inline void ptrace_link(struct task_struct *child,
+				struct task_struct *new_parent)
+{
+	if (unlikely(child->ptrace))
+		__ptrace_link(child, new_parent);
+}
+static inline void ptrace_unlink(struct task_struct *child)
+{
+	if (unlikely(child->ptrace))
+		__ptrace_unlink(child);
+}
 
 #endif
diff -Nru a/include/linux/quota.h b/include/linux/quota.h
--- a/include/linux/quota.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/quota.h	Tue Aug 27 12:28:08 2002
@@ -13,11 +13,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *   This product includes software developed by the University of
- *   California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
diff -Nru a/include/linux/raid/linear.h b/include/linux/raid/linear.h
--- a/include/linux/raid/linear.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/raid/linear.h	Tue Aug 27 12:28:02 2002
@@ -4,7 +4,7 @@
 #include <linux/raid/md.h>
 
 struct dev_info {
-	struct block_device *bdev;
+	mdk_rdev_t	*rdev;
 	unsigned long	size;
 	unsigned long	offset;
 };
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Tue Aug 27 12:27:59 2002
+++ b/include/linux/raid/md.h	Tue Aug 27 12:27:59 2002
@@ -76,9 +76,8 @@
 extern void md_wakeup_thread(mdk_thread_t *thread);
 extern void md_interrupt_thread (mdk_thread_t *thread);
 extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
-extern void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors);
-extern int md_error (mddev_t *mddev, struct block_device *bdev);
-extern int md_run_setup(void);
+extern void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors);
+extern void md_error (mddev_t *mddev, mdk_rdev_t *rdev);
 
 extern void md_print_devices (void);
 
diff -Nru a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
--- a/include/linux/raid/md_k.h	Tue Aug 27 12:27:57 2002
+++ b/include/linux/raid/md_k.h	Tue Aug 27 12:27:57 2002
@@ -154,12 +154,26 @@
 	mdp_super_t	*sb;
 	unsigned long	sb_offset;
 
-	int alias_device;		/* device alias to the same disk */
+	/* A device can be in one of three states based on two flags:
+	 * Not working:   faulty==1 in_sync==0
+	 * Fully working: faulty==0 in_sync==1
+	 * Working, but not
+	 * in sync with array
+	 *                faulty==0 in_sync==0
+	 *
+	 * It can never have faulty==1, in_sync==1
+	 * This reduces the burden of testing multiple flags in many cases
+	 */
 	int faulty;			/* if faulty do not issue IO requests */
 	int in_sync;			/* device is a full member of the array */
 
 	int desc_nr;			/* descriptor index in the superblock */
 	int raid_disk;			/* role of device in array */
+
+	atomic_t	nr_pending;	/* number of pending requests.
+					 * only maintained for arrays that
+					 * support hot removal
+					 */
 };
 
 typedef struct mdk_personality_s mdk_personality_t;
@@ -202,7 +216,7 @@
 	int				in_sync;	/* know to not need resync */
 	struct semaphore		reconfig_sem;
 	atomic_t			active;
-	mdk_rdev_t			*spare;
+	int				spares;
 
 	int				degraded;	/* whether md should consider
 							 * adding a spare
@@ -223,11 +237,12 @@
 	int (*run)(mddev_t *mddev);
 	int (*stop)(mddev_t *mddev);
 	int (*status)(char *page, mddev_t *mddev);
-	int (*error_handler)(mddev_t *mddev, struct block_device *bdev);
+	/* error_handler must set ->faulty and clear ->in_sync
+	 * if appropriate, and should abort recovery if needed 
+	 */
+	void (*error_handler)(mddev_t *mddev, mdk_rdev_t *rdev);
 	int (*hot_add_disk) (mddev_t *mddev, mdk_rdev_t *rdev);
 	int (*hot_remove_disk) (mddev_t *mddev, int number);
-	int (*spare_write) (mddev_t *mddev);
-	int (*spare_inactive) (mddev_t *mddev);
 	int (*spare_active) (mddev_t *mddev);
 	int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
 };
@@ -271,9 +286,6 @@
  */
 #define ITERATE_RDEV_PENDING(rdev,tmp)					\
 	ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp)
-
-#define xchg_values(x,y) do { __typeof__(x) __tmp = x; \
-				x = y; y = __tmp; } while (0)
 
 typedef struct mdk_thread_s {
 	void			(*run) (void *data);
diff -Nru a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h
--- a/include/linux/raid/multipath.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/raid/multipath.h	Tue Aug 27 12:28:08 2002
@@ -5,14 +5,7 @@
 #include <linux/bio.h>
 
 struct multipath_info {
-	struct block_device *bdev;
-
-	/*
-	 * State bits:
-	 */
-	int		operational;
-
-	int		used_slot;
+	mdk_rdev_t	*rdev;
 };
 
 struct multipath_private_data {
diff -Nru a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
--- a/include/linux/raid/raid1.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/raid/raid1.h	Tue Aug 27 12:28:07 2002
@@ -6,18 +6,8 @@
 typedef struct mirror_info mirror_info_t;
 
 struct mirror_info {
-	struct block_device *bdev;
+	mdk_rdev_t	*rdev;
 	sector_t	head_position;
-	atomic_t	nr_pending;
-
-	/*
-	 * State bits:
-	 */
-	int		operational;
-	int		write_only;
-	int		spare;
-
-	int		used_slot;
 };
 
 typedef struct r1bio_s r1bio_t;
@@ -30,7 +20,6 @@
 	int			last_used;
 	sector_t		next_seq_sect;
 	mdk_thread_t		*thread;
-	mirror_info_t		*spare;
 	spinlock_t		device_lock;
 
 	/* for use when syncing mirrors: */
diff -Nru a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
--- a/include/linux/raid/raid5.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/raid/raid5.h	Tue Aug 27 12:28:08 2002
@@ -148,6 +148,11 @@
 #define	R5_UPTODATE	0	/* page contains current data */
 #define	R5_LOCKED	1	/* IO has been submitted on "req" */
 #define	R5_OVERWRITE	2	/* towrite covers whole page */
+/* and some that are internal to handle_stripe */
+#define	R5_Insync	3	/* rdev && rdev->in_sync at start */
+#define	R5_Wantread	4	/* want to schedule a read */
+#define	R5_Wantwrite	5
+#define	R5_Syncio	6	/* this io need to be accounted as resync io */
 
 /*
  * Write method
@@ -192,11 +197,7 @@
  
 
 struct disk_info {
-	struct block_device *bdev;
-	int	operational;
-	int	write_only;
-	int	spare;
-	int	used_slot;
+	mdk_rdev_t	*rdev;
 };
 
 struct raid5_private_data {
diff -Nru a/include/linux/romfs_fs_sb.h b/include/linux/romfs_fs_sb.h
--- a/include/linux/romfs_fs_sb.h	Tue Aug 27 12:28:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-#ifndef __ROMFS_FS_SB
-#define __ROMFS_FS_SB
-
-/* romfs superblock in-core data */
-
-struct romfs_sb_info {
-	unsigned long s_maxsize;
-};
-
-#endif
diff -Nru a/include/linux/rtc.h b/include/linux/rtc.h
--- a/include/linux/rtc.h	Tue Aug 27 12:27:42 2002
+++ b/include/linux/rtc.h	Tue Aug 27 12:27:42 2002
@@ -39,10 +39,32 @@
 	struct rtc_time time;	/* time the alarm is set to */
 };
 
+/*
+ * Data structure to control PLL correction some better RTC feature
+ * pll_value is used to get or set current value of correction,
+ * the rest of the struct is used to query HW capabilities.
+ * This is modeled after the RTC used in Q40/Q60 computers but
+ * should be sufficiently flexible for other devices
+ *
+ * +ve pll_value means clock will run faster by
+ *   pll_value*pll_posmult/pll_clock
+ * -ve pll_value means clock will run slower by
+ *   pll_value*pll_negmult/pll_clock
+ */ 
+
+struct rtc_pll_info {
+	int pll_ctrl;       /* placeholder for fancier control */
+	int pll_value;      /* get/set correction value */
+	int pll_max;        /* max +ve (faster) adjustment value */
+	int pll_min;        /* max -ve (slower) adjustment value */
+	int pll_posmult;    /* factor for +ve corection */
+	int pll_negmult;    /* factor for -ve corection */
+	long pll_clock;     /* base PLL frequency */
+};
 
 /*
  * ioctl calls that are permitted to the /dev/rtc interface, if 
- * CONFIG_RTC/CONFIG_EFI_RTC was enabled.
+ * any of the RTC drivers are enabled.
  */
 
 #define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
@@ -65,6 +87,8 @@
 
 #define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
 #define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
+#define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
+#define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
 #ifdef __KERNEL__
 
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Aug 27 12:27:59 2002
+++ b/include/linux/sched.h	Tue Aug 27 12:27:59 2002
@@ -45,6 +45,10 @@
 #define CLONE_THREAD	0x00010000	/* Same thread group? */
 #define CLONE_NEWNS	0x00020000	/* New namespace group? */
 #define CLONE_SYSVSEM	0x00040000	/* share system V SEM_UNDO semantics */
+#define CLONE_SETTLS	0x00080000	/* create a new TLS for the child */
+#define CLONE_SETTID	0x00100000	/* write the TID back to userspace */
+#define CLONE_CLEARTID	0x00200000	/* clear the userspace TID */
+#define CLONE_DETACHED	0x00400000	/* parent wants no child-exit signal */
 
 #define CLONE_SIGNAL	(CLONE_SIGHAND | CLONE_THREAD)
 
@@ -166,6 +170,7 @@
 /* Maximum number of active map areas.. This is a random (large) number */
 #define MAX_MAP_COUNT	(65536)
 
+struct kioctx;
 struct mm_struct {
 	struct vm_area_struct * mmap;		/* list of VMAs */
 	rb_root_t mm_rb;
@@ -194,6 +199,10 @@
 
 	/* Architecture-specific MM context */
 	mm_context_t context;
+
+	/* aio bits */
+	rwlock_t		ioctx_list_lock;
+	struct kioctx		*ioctx_list;
 };
 
 extern int mmlist_nr;
@@ -266,6 +275,8 @@
 	unsigned int time_slice, first_time_slice;
 
 	struct list_head tasks;
+	struct list_head ptrace_children;
+	struct list_head ptrace_list;
 
 	struct mm_struct *mm, *active_mm;
 	struct list_head local_pages;
@@ -303,6 +314,7 @@
 
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct completion *vfork_done;		/* for vfork() */
+	int *user_tid;				/* for CLONE_CLEARTID */
 
 	unsigned long rt_priority;
 	unsigned long it_real_value, it_prof_value, it_virt_value;
@@ -440,7 +452,6 @@
 extern struct task_struct init_task;
 
 extern struct   mm_struct init_mm;
-extern struct task_struct *init_tasks[NR_CPUS];
 
 /* PID hashing. (shouldnt this be dynamic?) */
 #define PIDHASH_SZ (4096 >> 2)
diff -Nru a/include/linux/smp.h b/include/linux/smp.h
--- a/include/linux/smp.h	Tue Aug 27 12:28:07 2002
+++ b/include/linux/smp.h	Tue Aug 27 12:28:07 2002
@@ -96,9 +96,7 @@
 #define cpu_online_map				1
 #define cpu_online(cpu)				({ cpu; 1; })
 #define num_online_cpus()			1
-#define __per_cpu_data
-#define per_cpu(var, cpu)			var
-#define this_cpu(var)				var
+#define num_booting_cpus()			1
 
 struct notifier_block;
 
diff -Nru a/include/linux/smp_lock.h b/include/linux/smp_lock.h
--- a/include/linux/smp_lock.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/smp_lock.h	Tue Aug 27 12:28:02 2002
@@ -2,19 +2,66 @@
 #define __LINUX_SMPLOCK_H
 
 #include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
 
-#if !defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT)
+#if CONFIG_SMP || CONFIG_PREEMPT
+
+extern spinlock_t kernel_flag;
+
+#define kernel_locked()		(current->lock_depth >= 0)
+
+#define get_kernel_lock()	spin_lock(&kernel_flag)
+#define put_kernel_lock()	spin_unlock(&kernel_flag)
+
+/*
+ * Release global kernel lock.
+ */
+static inline void release_kernel_lock(struct task_struct *task)
+{
+	if (unlikely(task->lock_depth >= 0))
+		put_kernel_lock();
+}
+
+/*
+ * Re-acquire the kernel lock
+ */
+static inline void reacquire_kernel_lock(struct task_struct *task)
+{
+	if (unlikely(task->lock_depth >= 0))
+		get_kernel_lock();
+}
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+static inline void lock_kernel(void)
+{
+	int depth = current->lock_depth+1;
+	if (likely(!depth))
+		get_kernel_lock();
+	current->lock_depth = depth;
+}
+
+static inline void unlock_kernel(void)
+{
+	if (unlikely(current->lock_depth < 0))
+		BUG();
+	if (likely(--current->lock_depth < 0))
+		put_kernel_lock();
+}
+
+#else
 
 #define lock_kernel()				do { } while(0)
 #define unlock_kernel()				do { } while(0)
 #define release_kernel_lock(task)		do { } while(0)
 #define reacquire_kernel_lock(task)		do { } while(0)
-#define kernel_locked() 1
-
-#else
-
-#include <asm/smplock.h>
-
-#endif /* CONFIG_SMP */
+#define kernel_locked()				1
 
-#endif
+#endif /* CONFIG_SMP || CONFIG_PREEMPT */
+#endif /* __LINUX_SMPLOCK_H */
diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h
--- a/include/linux/spinlock.h	Tue Aug 27 12:28:06 2002
+++ b/include/linux/spinlock.h	Tue Aug 27 12:28:06 2002
@@ -1,52 +1,23 @@
 #ifndef __LINUX_SPINLOCK_H
 #define __LINUX_SPINLOCK_H
 
+/*
+ * include/linux/spinlock.h - generic locking declarations
+ */
+
 #include <linux/config.h>
 #include <linux/preempt.h>
 #include <linux/linkage.h>
 #include <linux/compiler.h>
 #include <linux/thread_info.h>
 #include <linux/kernel.h>
+#include <linux/stringify.h>
 
 #include <asm/system.h>
 
 /*
- * These are the generic versions of the spinlocks and read-write
- * locks..
+ * Must define these before including other files, inline functions need them
  */
-#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
-#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
-#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
-#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
-#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
-#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
-#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags)	do { _raw_spin_unlock(lock);  local_irq_restore(flags); preempt_enable(); } while (0)
-#define _raw_spin_unlock_irqrestore(lock, flags) do { _raw_spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)			do { _raw_spin_unlock(lock);  local_irq_enable(); preempt_enable();       } while (0)
-#define spin_unlock_bh(lock)			do { spin_unlock(lock); local_bh_enable(); } while (0)
-
-#define read_unlock_irqrestore(lock, flags)	do { _raw_read_unlock(lock);  local_irq_restore(flags); preempt_enable(); } while (0)
-#define read_unlock_irq(lock)			do { _raw_read_unlock(lock);  local_irq_enable(); preempt_enable(); } while (0)
-#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
-
-#define write_unlock_irqrestore(lock, flags)	do { _raw_write_unlock(lock); local_irq_restore(flags); preempt_enable(); } while (0)
-#define write_unlock_irq(lock)			do { _raw_write_unlock(lock); local_irq_enable(); preempt_enable();       } while (0)
-#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
-#define spin_trylock_bh(lock)			({ int __r; local_bh_disable();\
-						__r = spin_trylock(lock);      \
-						if (!__r) local_bh_enable();   \
-						__r; })
-
-/* Must define these before including other files, inline functions need them */
-
-#include <linux/stringify.h>
-
 #define LOCK_SECTION_NAME			\
 	".text.lock." __stringify(KBUILD_BASENAME)
 
@@ -60,11 +31,17 @@
 #define LOCK_SECTION_END			\
 	".previous\n\t"
 
+/*
+ * If CONFIG_SMP is set, pull in the _raw_* definitions
+ */
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
 
-#elif !defined(spin_lock_init) /* !SMP and spin_lock_init not previously
-                                  defined (e.g. by including asm/spinlock.h */
+/*
+ * !CONFIG_SMP and spin_lock_init not previously defined
+ * (e.g. by including include/asm/spinlock.h)
+ */
+#elif !defined(spin_lock_init)
 
 #ifndef CONFIG_PREEMPT
 # define atomic_dec_and_lock(atomic,lock) atomic_dec_and_test(atomic)
@@ -72,55 +49,42 @@
 #endif
 
 /*
- * Your basic spinlocks, allowing only a single CPU anywhere
- *
- * Most gcc versions have a nasty bug with empty initializers.
+ * gcc versions before ~2.95 have a nasty bug with empty initializers.
  */
 #if (__GNUC__ > 2)
   typedef struct { } spinlock_t;
-# define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+  typedef struct { } rwlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+  #define RW_LOCK_UNLOCKED (rwlock_t) { }
 #else
   typedef struct { int gcc_is_buggy; } spinlock_t;
-# define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+  typedef struct { int gcc_is_buggy; } rwlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 #endif
 
+/*
+ * If CONFIG_SMP is unset, declare the _raw_* definitions as nops
+ */
 #define spin_lock_init(lock)	do { (void)(lock); } while(0)
-#define _raw_spin_lock(lock)	(void)(lock) /* Not "unused variable". */
+#define _raw_spin_lock(lock)	(void)(lock)
 #define spin_is_locked(lock)	((void)(lock), 0)
 #define _raw_spin_trylock(lock)	((void)(lock), 1)
 #define spin_unlock_wait(lock)	do { (void)(lock); } while(0)
 #define _raw_spin_unlock(lock)	do { (void)(lock); } while(0)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- *
- * Most gcc versions have a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2)
-  typedef struct { } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
 #define rwlock_init(lock)	do { } while(0)
-#define _raw_read_lock(lock)	(void)(lock) /* Not "unused variable". */
+#define _raw_read_lock(lock)	(void)(lock)
 #define _raw_read_unlock(lock)	do { } while(0)
-#define _raw_write_lock(lock)	(void)(lock) /* Not "unused variable". */
+#define _raw_write_lock(lock)	(void)(lock)
 #define _raw_write_unlock(lock)	do { } while(0)
 
 #endif /* !SMP */
 
-#ifdef CONFIG_PREEMPT
-
+/*
+ * Define the various spin_lock and rw_lock methods.  Note we define these
+ * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
+ * methods are defined as nops in the case they are not required.
+ */
 #define spin_lock(lock)	\
 do { \
 	preempt_disable(); \
@@ -129,31 +93,175 @@
 
 #define spin_trylock(lock)	({preempt_disable(); _raw_spin_trylock(lock) ? \
 				1 : ({preempt_enable(); 0;});})
+
 #define spin_unlock(lock) \
 do { \
 	_raw_spin_unlock(lock); \
 	preempt_enable(); \
 } while (0)
 
-#define read_lock(lock)		({preempt_disable(); _raw_read_lock(lock);})
-#define read_unlock(lock)	({_raw_read_unlock(lock); preempt_enable();})
-#define write_lock(lock)	({preempt_disable(); _raw_write_lock(lock);})
-#define write_unlock(lock)	({_raw_write_unlock(lock); preempt_enable();})
+#define read_lock(lock)	\
+do { \
+	preempt_disable(); \
+	_raw_read_lock(lock); \
+} while(0)
+
+#define read_unlock(lock) \
+do { \
+	_raw_read_unlock(lock); \
+	preempt_enable(); \
+} while(0)
+
+#define write_lock(lock) \
+do { \
+	preempt_disable(); \
+	_raw_write_lock(lock); \
+} while(0)
+
+#define write_unlock(lock) \
+do { \
+	_raw_write_unlock(lock); \
+	preempt_enable(); \
+} while(0)
+
 #define write_trylock(lock)	({preempt_disable();_raw_write_trylock(lock) ? \
 				1 : ({preempt_enable(); 0;});})
 
-#else
+#define spin_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_raw_spin_lock(lock); \
+} while (0)
 
-#define spin_lock(lock)			_raw_spin_lock(lock)
-#define spin_trylock(lock)		_raw_spin_trylock(lock)
-#define spin_unlock(lock)		_raw_spin_unlock(lock)
-
-#define read_lock(lock)			_raw_read_lock(lock)
-#define read_unlock(lock)		_raw_read_unlock(lock)
-#define write_lock(lock)		_raw_write_lock(lock)
-#define write_unlock(lock)		_raw_write_unlock(lock)
-#define write_trylock(lock)		_raw_write_trylock(lock)
-#endif
+#define spin_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_raw_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_raw_spin_lock(lock); \
+} while (0)
+
+#define read_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_raw_read_lock(lock); \
+} while (0)
+
+#define read_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_raw_read_lock(lock); \
+} while (0)
+
+#define read_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_raw_read_lock(lock); \
+} while (0)
+
+#define write_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_raw_write_lock(lock); \
+} while (0)
+
+#define write_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_raw_write_lock(lock); \
+} while (0)
+
+#define write_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_raw_write_lock(lock); \
+} while (0)
+
+#define spin_unlock_irqrestore(lock, flags) \
+do { \
+	_raw_spin_unlock(lock); \
+	local_irq_restore(flags); \
+	preempt_enable(); \
+} while (0)
+
+#define _raw_spin_unlock_irqrestore(lock, flags) \
+do { \
+	_raw_spin_unlock(lock); \
+	local_irq_restore(flags); \
+} while (0)
+
+#define spin_unlock_irq(lock) \
+do { \
+	_raw_spin_unlock(lock); \
+	local_irq_enable(); \
+	preempt_enable(); \
+} while (0)
+
+#define spin_unlock_bh(lock) \
+do { \
+	_raw_spin_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define read_unlock_irqrestore(lock, flags) \
+do { \
+	_raw_read_unlock(lock); \
+	local_irq_restore(flags); \
+	preempt_enable(); \
+} while (0)
+
+#define read_unlock_irq(lock) \
+do { \
+	_raw_read_unlock(lock); \
+	local_irq_enable(); \
+	preempt_enable(); \
+} while (0)
+
+#define read_unlock_bh(lock) \
+do { \
+	_raw_read_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define write_unlock_irqrestore(lock, flags) \
+do { \
+	_raw_write_unlock(lock); \
+	local_irq_restore(flags); \
+	preempt_enable(); \
+} while (0)
+
+#define write_unlock_irq(lock) \
+do { \
+	_raw_write_unlock(lock); \
+	local_irq_enable(); \
+	preempt_enable(); \
+} while (0)
+
+#define write_unlock_bh(lock) \
+do { \
+	_raw_write_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define spin_trylock_bh(lock)	({ local_bh_disable(); preempt_disable(); \
+				_raw_spin_trylock(lock) ? 1 : \
+				({preempt_enable(); local_bh_enable(); 0;});})
 
 /* "lock on reference count zero" */
 #ifndef ATOMIC_DEC_AND_LOCK
diff -Nru a/include/linux/stringify.h b/include/linux/stringify.h
--- a/include/linux/stringify.h	Tue Aug 27 12:28:01 2002
+++ b/include/linux/stringify.h	Tue Aug 27 12:28:01 2002
@@ -4,10 +4,6 @@
 /* Indirect stringification.  Doing two levels allows the parameter to be a
  * macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
  * converts to "bar".
- *
- * The "..." is gcc's cpp vararg macro syntax.  It is required because __ALIGN,
- * in linkage.h, contains a comma, which when expanded, causes it to look 
- * like two arguments, which breaks the standard non-vararg stringizer.
  */
 
 #define __stringify_1(x)	#x
diff -Nru a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
--- a/include/linux/sunrpc/svcsock.h	Tue Aug 27 12:28:02 2002
+++ b/include/linux/sunrpc/svcsock.h	Tue Aug 27 12:28:02 2002
@@ -30,6 +30,7 @@
 #define	SK_TEMP		4			/* temp (TCP) socket */
 #define	SK_QUED		5			/* on serv->sk_sockets */
 #define	SK_DEAD		6			/* socket closed */
+#define	SK_CHNGBUF	7			/* need to change snd/rcv buffer sizes */
 
 	int			sk_reserved;	/* space on outq that is reserved */
 
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/sunrpc/xprt.h	Tue Aug 27 12:28:08 2002
@@ -57,8 +57,7 @@
 	unsigned long		to_current,		/* current timeout */
 				to_initval,		/* initial timeout */
 				to_maxval,		/* max timeout */
-				to_increment,		/* if !exponential */
-				to_resrvval;		/* reserve timeout */
+				to_increment;		/* if !exponential */
 	short			to_retries;		/* max # of retries */
 	unsigned char		to_exponential;
 };
@@ -173,7 +172,7 @@
 void			xprt_set_timeout(struct rpc_timeout *, unsigned int,
 					unsigned long);
 
-int			xprt_reserve(struct rpc_task *);
+void			xprt_reserve(struct rpc_task *);
 void			xprt_transmit(struct rpc_task *);
 void			xprt_receive(struct rpc_task *);
 int			xprt_adjust_timeout(struct rpc_timeout *);
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Tue Aug 27 12:27:56 2002
+++ b/include/linux/swap.h	Tue Aug 27 12:27:56 2002
@@ -156,8 +156,6 @@
 
 /* linux/mm/swap.c */
 extern void FASTCALL(lru_cache_add(struct page *));
-extern void FASTCALL(__lru_cache_del(struct page *));
-extern void FASTCALL(lru_cache_del(struct page *));
 
 extern void FASTCALL(activate_page(struct page *));
 
@@ -211,7 +209,7 @@
 asmlinkage long sys_swapoff(const char *);
 asmlinkage long sys_swapon(const char *, int);
 
-extern spinlock_t pagemap_lru_lock;
+extern spinlock_t _pagemap_lru_lock;
 
 extern void FASTCALL(mark_page_accessed(struct page *));
 
@@ -227,12 +225,17 @@
 		BUG();				\
 } while (0)
 
+#define __add_page_to_active_list(page)		\
+do {						\
+	list_add(&(page)->lru, &active_list);	\
+	inc_page_state(nr_active);		\
+} while (0)
+
 #define add_page_to_active_list(page)		\
 do {						\
 	DEBUG_LRU_PAGE(page);			\
 	SetPageActive(page);			\
-	list_add(&(page)->lru, &active_list);	\
-	inc_page_state(nr_active);		\
+	__add_page_to_active_list(page);	\
 } while (0)
 
 #define add_page_to_inactive_list(page)		\
diff -Nru a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
--- a/include/linux/ufs_fs.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/ufs_fs.h	Tue Aug 27 12:28:08 2002
@@ -33,6 +33,9 @@
 #include <linux/stat.h>
 #include <linux/fs.h>
 
+#include <linux/ufs_fs_i.h>
+#include <linux/ufs_fs_sb.h>
+
 #define UFS_BBLOCK 0
 #define UFS_BBSIZE 8192
 #define UFS_SBLOCK 8192
@@ -398,7 +401,7 @@
  * Convert cylinder group to base address of its global summary info.
  */
 #define fs_cs(indx) \
-	u.ufs_sb.s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+	s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
 
 /*
  * Cylinder group block for a file system.
@@ -780,7 +783,10 @@
 /* truncate.c */
 extern void ufs_truncate (struct inode *);
 
-#include <linux/ufs_fs_i.h>
+static inline struct ufs_sb_info *UFS_SB(struct super_block *sb)
+{
+	return sb->u.generic_sbp;
+}
 
 static inline struct ufs_inode_info *UFS_I(struct inode *inode)
 {
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Tue Aug 27 12:28:05 2002
+++ b/include/linux/usb.h	Tue Aug 27 12:28:05 2002
@@ -58,27 +58,6 @@
 #define USB_ENDPOINT_XFER_INT		3
 
 /*
- * USB Packet IDs (PIDs)
- */
-#define USB_PID_UNDEF_0			0xf0
-#define USB_PID_OUT			0xe1
-#define USB_PID_ACK			0xd2
-#define USB_PID_DATA0			0xc3
-#define USB_PID_PING			0xb4	/* USB 2.0 */
-#define USB_PID_SOF			0xa5
-#define USB_PID_NYET			0x96	/* USB 2.0 */
-#define USB_PID_DATA2			0x87	/* USB 2.0 */
-#define USB_PID_SPLIT			0x78	/* USB 2.0 */
-#define USB_PID_IN			0x69
-#define USB_PID_NAK			0x5a
-#define USB_PID_DATA1			0x4b
-#define USB_PID_PREAMBLE		0x3c	/* Token mode */
-#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
-#define USB_PID_SETUP			0x2d
-#define USB_PID_STALL			0x1e
-#define USB_PID_MDATA			0x0f	/* USB 2.0 */
-
-/*
  * Standard requests
  */
 #define USB_REQ_GET_STATUS		0x00
@@ -167,10 +146,6 @@
 #define USB_DT_OTHER_SPEED_CONFIG	0x07
 #define USB_DT_INTERFACE_POWER		0x08
 
-// FIXME should be internal to hub driver
-#define USB_DT_HUB			(USB_TYPE_CLASS | 0x09)
-#define USB_DT_HUB_NONVAR_SIZE		7
-
 /*
  * Descriptor sizes per descriptor type
  */
@@ -258,6 +233,8 @@
 	void *private_data;
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
+#define	interface_to_usbdev(intf) \
+	container_of(intf->dev.parent, struct usb_device, dev)
 
 /* USB_DT_CONFIG: Configuration descriptor information.
  *
@@ -303,10 +280,8 @@
 	__u8  bRESERVED;
 } __attribute__ ((packed));
 
-/* helpers for driver access to descriptors */
-extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum);
-extern struct usb_interface *
-	usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+// FIXME remove; exported only for drivers/usb/misc/auserwald.c
+// prefer usb_device->epnum[0..31]
 extern struct usb_endpoint_descriptor *
 	usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
 
@@ -322,8 +297,6 @@
 
 struct usb_operations;
 
-#define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
-
 /*
  * Allocated per bus we have
  */
@@ -331,9 +304,7 @@
 	int busnum;			/* Bus number (in order of reg) */
 	char *bus_name;			/* stable id (PCI slot_name etc) */
 
-#ifdef DEVNUM_ROUND_ROBIN
 	int devnum_next;		/* Next open device number in round-robin allocation */
-#endif /* DEVNUM_ROUND_ROBIN */
 
 	struct usb_devmap devmap;	/* device address allocation map */
 	struct usb_operations *op;	/* Operations (specific to the HC) */
@@ -357,10 +328,6 @@
 	atomic_t refcnt;
 };
 
-// FIXME:  root_hub_string vanishes when "usb_hcd" conversion is done,
-// along with pre-hcd versions of the OHCI and UHCI drivers.
-extern int usb_root_hub_string(int id, int serial,
-		char *type, __u8 *data, int len);
 
 /* -------------------------------------------------------------------------- */
 
@@ -435,10 +402,6 @@
 /* for when layers above USB add new non-USB drivers */
 extern void usb_scan_devices(void);
 
-/* for probe/disconnect with correct module usage counting */
-void *usb_bind_driver(struct usb_driver *driver, struct usb_device *dev, unsigned int ifnum);
-void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf);
-
 /* mostly for devices emulating SCSI over USB */
 extern int usb_reset_device(struct usb_device *dev);
 
@@ -446,14 +409,12 @@
 extern int usb_get_current_frame_number (struct usb_device *usb_dev);
 
 /* used these for multi-interface device registration */
-extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int ifnum);
 extern void usb_driver_claim_interface(struct usb_driver *driver,
 			struct usb_interface *iface, void* priv);
 extern int usb_interface_claimed(struct usb_interface *iface);
 extern void usb_driver_release_interface(struct usb_driver *driver,
 			struct usb_interface *iface);
-const struct usb_device_id *usb_match_id(struct usb_device *dev,
-					 struct usb_interface *interface,
+const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
 
 /**
@@ -734,6 +695,7 @@
  */
 #define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */
 #define USB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame ignored */
+#define URB_NO_DMA_MAP		0x0004	/* urb->*_dma are valid on submit */
 #define USB_ASYNC_UNLINK	0x0008	/* usb_unlink_urb() returns asap */
 #define USB_NO_FSBR		0x0020	/* UHCI-specific */
 #define USB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
@@ -754,7 +716,7 @@
 /**
  * struct urb - USB Request Block
  * @urb_list: For use by current owner of the URB.
- * @pipe: Holds endpoint number, direction, type, and max packet size.
+ * @pipe: Holds endpoint number, direction, type, and more.
  *	Create these values with the eight macros available;
  *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"
  *	(control), "bulk", "int" (interrupt), or "iso" (isochronous).
@@ -771,15 +733,20 @@
  * @transfer_flags: A variety of flags may be used to affect how URB
  *	submission, unlinking, or operation are handled.  Different
  *	kinds of URB can use different flags.
- * @transfer_buffer: For non-iso transfers, this identifies the buffer
- *	to (or from) which the I/O request will be performed.  This
- *	buffer must be suitable for DMA; allocate it with kmalloc()
+ * @transfer_buffer:  This identifies the buffer to (or from) which
+ * 	the I/O request will be performed (unless URB_NO_DMA_MAP is set).
+ *	This buffer must be suitable for DMA; allocate it with kmalloc()
  *	or equivalent.  For transfers to "in" endpoints, contents of
- *	this buffer will be modified.
+ *	this buffer will be modified.  This buffer is used for data
+ *	phases of control transfers.
+ * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device
+ * 	driver is saying that it provided this DMA address, which the host
+ * 	controller driver should use instead of the transfer_buffer.
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
  *	be broken up into chunks according to the current maximum packet
  *	size for the endpoint, which is a function of the configuration
- *	and is encoded in the pipe.
+ *	and is encoded in the pipe.  When the length is zero, neither
+ *	transfer_buffer nor transfer_dma is used.
  * @actual_length: This is read in non-iso completion functions, and
  *	it tells how many bytes (out of transfer_buffer_length) were
  *	transferred.  It will normally be the same as requested, unless
@@ -789,6 +756,11 @@
  * @setup_packet: Only used for control transfers, this points to eight bytes
  *	of setup data.  Control transfers always start by sending this data
  *	to the device.  Then transfer_buffer is read or written, if needed.
+ *	(Not used when URB_NO_DMA_MAP is set.)
+ * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device
+ * 	driver has provided this DMA address for the setup packet.  The
+ * 	host controller driver should use this instead of setup_buffer.
+ * 	If there is a data phase, its buffer is identified by transfer_dma.
  * @start_frame: Returns the initial frame for interrupt or isochronous
  *	transfers.
  * @number_of_packets: Lists the number of ISO transfer buffers.
@@ -811,6 +783,24 @@
  * are submitted using usb_submit_urb(), and pending requests may be canceled
  * using usb_unlink_urb().
  *
+ * Data Transfer Buffers:
+ *
+ * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise
+ * taken from the general page pool.  That is provided by transfer_buffer
+ * (control requests also use setup_packet), and host controller drivers
+ * perform a dma mapping (and unmapping) for each buffer transferred.  Those
+ * mapping operations can be expensive on some platforms (perhaps using a dma
+ * bounce buffer or talking to an IOMMU),
+ * although they're cheap on commodity x86 and ppc hardware.
+ *
+ * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which
+ * tells the host controller driver that no such mapping is needed since
+ * the device driver is DMA-aware.  For example, they might allocate a DMA
+ * buffer with usb_buffer_alloc(), or call usb_buffer_map().
+ * When this transfer flag is provided, host controller drivers will use the
+ * dma addresses found in the transfer_dma and/or setup_dma fields rather than
+ * determing a dma address themselves.
+ *
  * Initialization:
  *
  * All URBs submitted must initialize dev, pipe,
@@ -818,10 +808,10 @@
  * The USB_ASYNC_UNLINK transfer flag affects later invocations of
  * the usb_unlink_urb() routine.
  *
- * All non-isochronous URBs must also initialize 
+ * All URBs must also initialize 
  * transfer_buffer and transfer_buffer_length.  They may provide the
  * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
- * to be treated as errors.
+ * to be treated as errors; that flag is invalid for write requests.
  *
  * Bulk URBs may
  * use the USB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers
@@ -867,7 +857,7 @@
  * things that a completion handler should do is check the status field.
  * The status field is provided for all URBs.  It is used to report
  * unlinked URBs, and status for all non-ISO transfers.  It should not
- * be examined outside of the completion handler.
+ * be examined before the URB is returned to the completion handler.
  *
  * The context field is normally used to link URBs back to the relevant
  * driver or request state.
@@ -896,10 +886,12 @@
 	int status;			/* (return) non-ISO status */
 	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
 	void *transfer_buffer;		/* (in) associated data buffer */
+	dma_addr_t transfer_dma;	/* (in) dma addr for transfer_buffer */
 	int transfer_buffer_length;	/* (in) data buffer length */
 	int actual_length;		/* (return) actual transfer length */
 	int bandwidth;			/* bandwidth for INT/ISO request */
 	unsigned char *setup_packet;	/* (in) setup packet (control only) */
+	dma_addr_t setup_dma;		/* (in) dma addr for setup_packet */
 	int start_frame;		/* (modify) start frame (INT/ISO) */
 	int number_of_packets;		/* (in) number of ISO packets */
 	int interval;			/* (in) transfer interval (INT/ISO) */
@@ -910,6 +902,8 @@
 	struct usb_iso_packet_descriptor iso_frame_desc[0];	/* (in) ISO ONLY */
 };
 
+/* -------------------------------------------------------------------------- */
+
 /**
  * usb_fill_control_urb - initializes a control urb
  * @urb: pointer to the urb to initialize.
@@ -1032,6 +1026,16 @@
 extern int usb_submit_urb(struct urb *urb, int mem_flags);
 extern int usb_unlink_urb(struct urb *urb);
 
+#define HAVE_USB_BUFFERS
+void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+	int mem_flags, dma_addr_t *dma);
+void usb_buffer_free (struct usb_device *dev, size_t size,
+	void *addr, dma_addr_t dma);
+
+struct urb *usb_buffer_map (struct urb *urb);
+void usb_buffer_dmasync (struct urb *urb);
+void usb_buffer_unmap (struct urb *urb);
+
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *
  *-------------------------------------------------------------------*/
@@ -1044,7 +1048,6 @@
 	int timeout);
 
 /* wrappers around usb_control_msg() for the most common standard requests */
-extern int usb_clear_halt(struct usb_device *dev, int pipe);
 extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
 	unsigned char descindex, void *buf, int size);
 extern int usb_get_device_descriptor(struct usb_device *dev);
@@ -1054,6 +1057,9 @@
 	unsigned short langid, unsigned char index, void *buf, int size);
 extern int usb_string(struct usb_device *dev, int index,
 	char *buf, size_t size);
+
+/* wrappers that also update important state inside usbcore */
+extern int usb_clear_halt(struct usb_device *dev, int pipe);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
 
@@ -1092,9 +1098,10 @@
  *
  *  - max size:		bits 0-1	[Historical; now gone.]
  *  - direction:	bit 7		(0 = Host-to-Device [Out],
- *					 1 = Device-to-Host [In])
- *  - device:		bits 8-14
- *  - endpoint:		bits 15-18
+ *					 1 = Device-to-Host [In] ...
+ *					like endpoint bEndpointAddress)
+ *  - device:		bits 8-14       ... bit positions known to uhci-hcd
+ *  - endpoint:		bits 15-18      ... bit positions known to uhci-hcd
  *  - Data0/1:		bit 19		[Historical; now gone. ]
  *  - lowspeed:		bit 26		[Historical; now gone. ]
  *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt,
@@ -1115,10 +1122,9 @@
 #define usb_maxpacket(dev, pipe, out)	(out \
 				? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
 				: (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
-#define usb_packetid(pipe)	(((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
 
-#define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
-#define usb_pipein(pipe)	(((pipe) >> 7) & 1)
+#define usb_pipein(pipe)	((pipe) & USB_DIR_IN)
+#define usb_pipeout(pipe)	(!usb_pipein(pipe))
 #define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
 #define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
 #define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
@@ -1127,19 +1133,16 @@
 #define usb_pipecontrol(pipe)	(usb_pipetype((pipe)) == PIPE_CONTROL)
 #define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == PIPE_BULK)
 
-#define PIPE_DEVEP_MASK		0x0007ff00
-
-/* The D0/D1 toggle bits */
+/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
 #define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
 #define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
 
-/* Endpoint halt control/status */
-#define usb_endpoint_out(ep_dir)	((((ep_dir) >> 7) & 1) ^ 1)
-#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
+/* Endpoint halt control/status ... likewise USE WITH CAUTION */
 #define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
 #define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
 
+
 static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
 {
 	return (dev->devnum << 8) | (endpoint << 15);
@@ -1179,47 +1182,6 @@
 #define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
 
-
-/* -------------------------------------------------------------------------- */
-
-/*
- * driver list
- * exported only for usbfs (not visible outside usbcore)
- */
-
-extern struct list_head usb_driver_list;
-
-/*
- * USB device fs stuff
- */
-
-#ifdef CONFIG_USB_DEVICEFS
-
-/*
- * these are expected to be called from the USB core/hub thread
- * with the kernel lock held
- */
-extern void usbfs_add_bus(struct usb_bus *bus);
-extern void usbfs_remove_bus(struct usb_bus *bus);
-extern void usbfs_add_device(struct usb_device *dev);
-extern void usbfs_remove_device(struct usb_device *dev);
-extern void usbfs_update_special (void);
-
-extern int usbfs_init(void);
-extern void usbfs_cleanup(void);
-
-#else /* CONFIG_USB_DEVICEFS */
-
-static inline void usbfs_add_bus(struct usb_bus *bus) {}
-static inline void usbfs_remove_bus(struct usb_bus *bus) {}
-static inline void usbfs_add_device(struct usb_device *dev) {}
-static inline void usbfs_remove_device(struct usb_device *dev) {}
-static inline void usbfs_update_special (void) {}
-
-static inline int usbfs_init(void) { return 0; }
-static inline void usbfs_cleanup(void) { }
-
-#endif /* CONFIG_USB_DEVICEFS */
 
 #endif  /* __KERNEL__ */
 
diff -Nru a/include/linux/vmalloc.h b/include/linux/vmalloc.h
--- a/include/linux/vmalloc.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/vmalloc.h	Tue Aug 27 12:28:08 2002
@@ -1,44 +1,47 @@
-#ifndef __LINUX_VMALLOC_H
-#define __LINUX_VMALLOC_H
+#ifndef _LINUX_VMALLOC_H
+#define _LINUX_VMALLOC_H
 
 #include <linux/spinlock.h>
 
-#include <asm/pgtable.h>
-
 /* bits in vm_struct->flags */
 #define VM_IOREMAP	0x00000001	/* ioremap() and friends */
 #define VM_ALLOC	0x00000002	/* vmalloc() */
+#define VM_MAP		0x00000004	/* vmap()ed pages */
 
 struct vm_struct {
-	unsigned long flags;
-	void * addr;
-	unsigned long size;
-	unsigned long phys_addr;
-	struct vm_struct * next;
+	void			*addr;
+	unsigned long		size;
+	unsigned long		flags;
+	struct page		**pages;
+	unsigned int		nr_pages;
+	unsigned long		phys_addr;
+	struct vm_struct	*next;
 };
 
-extern struct vm_struct * get_vm_area (unsigned long size, unsigned long flags);
-extern void vfree(void * addr);
-extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot);
-extern long vread(char *buf, char *addr, unsigned long count);
-extern void vmfree_area_pages(unsigned long address, unsigned long size);
-extern int vmalloc_area_pages(unsigned long address, unsigned long size,
-                              int gfp_mask, pgprot_t prot);
-extern struct vm_struct *remove_kernel_area(void *addr);
-
 /*
- * Various ways to allocate pages.
+ *	Highlevel APIs for driver use
  */
-
-extern void * vmalloc(unsigned long size);
-extern void * vmalloc_32(unsigned long size);
+extern void *vmalloc(unsigned long size);
+extern void *vmalloc_32(unsigned long size);
+extern void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot);
+extern void vfree(void *addr);
+
+extern void *vmap(struct page **pages, unsigned int count);
+extern void vunmap(void *addr);
+ 
+/*
+ *	Lowlevel-APIs (not for driver use!)
+ */
+extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
+extern struct vm_struct *remove_vm_area(void *addr);
+extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
+			struct page ***pages);
+extern void unmap_vm_area(struct vm_struct *area);
 
 /*
- * vmlist_lock is a read-write spinlock that protects vmlist
- * Used in mm/vmalloc.c (get_vm_area() and vfree()) and fs/proc/kcore.c.
+ *	Internals.  Dont't use..
  */
 extern rwlock_t vmlist_lock;
+extern struct vm_struct *vmlist;
 
-extern struct vm_struct * vmlist;
-#endif
-
+#endif /* _LINUX_VMALLOC_H */
diff -Nru a/include/linux/vt_kern.h b/include/linux/vt_kern.h
--- a/include/linux/vt_kern.h	Tue Aug 27 12:28:08 2002
+++ b/include/linux/vt_kern.h	Tue Aug 27 12:28:08 2002
@@ -32,8 +32,8 @@
 	wait_queue_head_t paste_wait;
 } *vt_cons[MAX_NR_CONSOLES];
 
-extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
-extern int (*kbd_rate)(struct kbd_repeat *rep);
+extern void kd_mksound(unsigned int hz, unsigned int ticks);
+extern int kbd_rate(struct kbd_repeat *rep);
 
 /* console.c */
 
diff -Nru a/include/linux/wait.h b/include/linux/wait.h
--- a/include/linux/wait.h	Tue Aug 27 12:27:42 2002
+++ b/include/linux/wait.h	Tue Aug 27 12:27:42 2002
@@ -43,16 +43,16 @@
  */
 
 #define __WAITQUEUE_INITIALIZER(name, tsk) {				\
-	task:		tsk,						\
-	func:		default_wake_function,				\
-	task_list:	{ NULL, NULL } }
+	.task		= tsk,						\
+	.func		= default_wake_function,			\
+	.task_list	= { NULL, NULL } }
 
 #define DECLARE_WAITQUEUE(name, tsk)					\
 	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
 
 #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {				\
-	lock:		SPIN_LOCK_UNLOCKED,				\
-	task_list:	{ &(name).task_list, &(name).task_list } }
+	.lock		= SPIN_LOCK_UNLOCKED,				\
+	.task_list	= { &(name).task_list, &(name).task_list } }
 
 #define DECLARE_WAIT_QUEUE_HEAD(name) \
 	wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
diff -Nru a/include/net/datalink.h b/include/net/datalink.h
--- a/include/net/datalink.h	Tue Aug 27 12:28:05 2002
+++ b/include/net/datalink.h	Tue Aug 27 12:28:05 2002
@@ -2,24 +2,17 @@
 #define _NET_INET_DATALINK_H_
 
 struct datalink_proto {
-        unsigned short  type_len;
         unsigned char   type[8];
-        const char      *string_name;
 
-        union {
-                struct llc_pinfo *llc;
-        } ll_pinfo;
-
-	struct llc_sc_info *llc_sc;
-	struct sock *sock;
+	struct llc_sap   *sap;
 
         unsigned short  header_length;
 
         int     (*rcvfunc)(struct sk_buff *, struct net_device *,
                                 struct packet_type *);
-        void    (*datalink_header)(struct datalink_proto *, struct sk_buff *,
+	int     (*request)(struct datalink_proto *, struct sk_buff *,
                                         unsigned char *);
-        struct datalink_proto   *next;
+	struct list_head node;
 };
 
 #endif
diff -Nru a/include/net/llc_actn.h b/include/net/llc_actn.h
--- a/include/net/llc_actn.h	Tue Aug 27 12:28:01 2002
+++ b/include/net/llc_actn.h	Tue Aug 27 12:28:01 2002
@@ -24,25 +24,25 @@
 
 /* All station state event action functions look like this */
 typedef int (*llc_station_action_t)(struct llc_station *station,
-				    struct llc_station_state_ev *ev);
+				    struct sk_buff *skb);
 extern int llc_station_ac_start_ack_timer(struct llc_station *station,
-					  struct llc_station_state_ev *ev);
+					  struct sk_buff *skb);
 extern int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
-					  struct llc_station_state_ev *ev);
+					  struct sk_buff *skb);
 extern int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
-					     struct llc_station_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
-					  struct llc_station_state_ev *ev);
+					  struct sk_buff *skb);
 extern int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
-					     struct llc_station_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+					       struct sk_buff *skb);
 extern int llc_station_ac_send_xid_r(struct llc_station *station,
-				     struct llc_station_state_ev *ev);
+				     struct sk_buff *skb);
 extern int llc_station_ac_send_test_r(struct llc_station *station,
-				      struct llc_station_state_ev *ev);
+				      struct sk_buff *skb);
 extern int llc_station_ac_report_status(struct llc_station *station,
-					struct llc_station_state_ev *ev);
+					struct sk_buff *skb);
 extern int llc_station_ac_report_status(struct llc_station *station,
-					struct llc_station_state_ev *ev);
+					struct sk_buff *skb);
 #endif /* LLC_ACTN_H */
diff -Nru a/include/net/llc_c_ac.h b/include/net/llc_c_ac.h
--- a/include/net/llc_c_ac.h	Tue Aug 27 12:28:08 2002
+++ b/include/net/llc_c_ac.h	Tue Aug 27 12:28:08 2002
@@ -87,168 +87,128 @@
 #define LLC_CONN_AC_STOP_SENDACK_TMR			70
 #define LLC_CONN_AC_START_SENDACK_TMR_IF_NOT_RUNNING	71
 
-typedef int (*llc_conn_action_t)(struct sock *sk, struct llc_conn_state_ev *ev);
+typedef int (*llc_conn_action_t)(struct sock *sk, struct sk_buff *skb);
 
-extern int llc_conn_ac_clear_remote_busy(struct sock *sk,
-					 struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_conn_confirm(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_data_ind(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_disc_ind(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_rst_ind(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_rst_confirm(struct sock* sk,
-				     struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_report_status(struct sock* sk,
-				     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ac_conn_confirm(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_data_ind(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_disc_ind(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_rst_ind(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_rst_confirm(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_report_status(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
+						   struct sk_buff *skb);
 extern int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
+						      struct sk_buff *skb);
 extern int llc_conn_ac_send_disc_cmd_p_set_x(struct sock* sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ac_send_dm_rsp_f_set_p(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ac_send_dm_rsp_f_set_1(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock* sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 extern int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock* sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock* sk,
-					       struct llc_conn_state_ev *ev);
+					       struct sk_buff *skb);
 extern int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock* sk,
-					       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_send_i_cmd_p_set_1(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_send_i_cmd_p_set_0(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
+					       struct sk_buff *skb);
+extern int llc_conn_ac_send_i_cmd_p_set_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_send_i_cmd_p_set_0(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_resend_i_cmd_p_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_send_i_xxx_x_set_0(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
+extern int llc_conn_ac_send_i_xxx_x_set_0(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_resend_i_xxx_x_set_0(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
+						       struct sk_buff *skb);
 extern int llc_conn_ac_resend_i_rsp_f_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rej_cmd_p_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rej_rsp_f_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rej_xxx_x_set_0(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_remote_busy(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
+extern int llc_conn_ac_set_remote_busy(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock* sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 extern int llc_conn_ac_send_rr_cmd_p_set_1(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ac_send_ack_cmd_p_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rr_rsp_f_set_1(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ac_send_ack_rsp_f_set_1(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_rr_xxx_x_set_0(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ac_send_ack_xxx_x_set_0(struct sock* sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock* sk,
-					      struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
 extern int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock* sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 extern int llc_conn_ac_send_ua_rsp_f_set_p(struct sock* sk,
-					   struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_s_flag_0(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_s_flag_1(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_start_p_timer(struct sock* sk,
-				     struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_start_ack_timer(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_start_rej_timer(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
+extern int llc_conn_ac_set_s_flag_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_s_flag_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_start_p_timer(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_start_ack_timer(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_start_rej_timer(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_start_ack_tmr_if_not_running(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_stop_ack_timer(struct sock* sk,
-				      struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_stop_p_timer(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_stop_rej_timer(struct sock* sk,
-				      struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_stop_all_timers(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_stop_other_timers(struct sock* sk,
-					 struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_upd_nr_received(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_inc_tx_win_size(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_dec_tx_win_size(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_upd_p_flag(struct sock* sk,
-				     struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_data_flag_2(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_data_flag_0(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_data_flag_1(struct sock* sk,
-				       struct llc_conn_state_ev *ev);
+						    struct sk_buff *skb);
+extern int llc_conn_ac_stop_ack_timer(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_stop_p_timer(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_stop_rej_timer(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_stop_all_timers(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_stop_other_timers(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_upd_nr_received(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_inc_tx_win_size(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_dec_tx_win_size(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_upd_p_flag(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_data_flag_2(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_data_flag_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_data_flag_1(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock* sk,
-						  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_p_flag_0(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_p_flag_1(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_remote_busy_0(struct sock* sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_retry_cnt_0(struct sock* sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_cause_flag_0(struct sock* sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_cause_flag_1(struct sock* sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_inc_retry_cnt_by_1(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_vr_0(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_inc_vr_by_1(struct sock* sk,
-				   struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_vs_0(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_vs_nr(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_rst_vs(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_upd_vs(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_set_f_flag_p(struct sock* sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_disc(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_reset(struct sock* sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_disc_confirm(struct sock* sk, struct llc_conn_state_ev *ev);
+							 struct sk_buff *skb);
+extern int llc_conn_ac_set_p_flag_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_p_flag_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_remote_busy_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_retry_cnt_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_cause_flag_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_cause_flag_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_inc_retry_cnt_by_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_vr_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_inc_vr_by_1(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_vs_0(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_vs_nr(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_rst_vs(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_upd_vs(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_set_f_flag_p(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_disc(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_reset(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_disc_confirm(struct sock* sk, struct sk_buff *skb);
 extern u8 llc_circular_between(u8 a, u8 b, u8 c);
-extern int llc_conn_ac_send_ack_if_needed(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_inc_npta_value(struct sock* sk,
-				      struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_adjust_npta_by_rr(struct sock* sk,
-					 struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_adjust_npta_by_rnr(struct sock* sk,
-					  struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_rst_sendack_flag(struct sock* sk,
-					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ack_if_needed(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_inc_npta_value(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_adjust_npta_by_rr(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_adjust_npta_by_rnr(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_rst_sendack_flag(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock* sk,
-					       struct llc_conn_state_ev *ev);
+					       struct sk_buff *skb);
 extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk,
-					      struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk,
-					 struct llc_conn_state_ev *ev);
-extern int llc_conn_ac_send_i_as_ack(struct sock* sk,
-				     struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
+extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb);
+extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb);
 #endif /* LLC_C_AC_H */
diff -Nru a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h
--- a/include/net/llc_c_ev.h	Tue Aug 27 12:28:01 2002
+++ b/include/net/llc_c_ev.h	Tue Aug 27 12:28:01 2002
@@ -124,7 +124,6 @@
 struct llc_conn_ev_pdu_if {
 	u8		ev;
 	u8		reason;
-	struct sk_buff *skb;
 };
 
 /* Event interface for timer-generated events */
@@ -155,169 +154,156 @@
 	union llc_conn_ev_if	  data;
 };
 
-typedef int (*llc_conn_ev_t)(struct sock *sk, struct llc_conn_state_ev *ev);
-typedef int (*llc_conn_ev_qfyr_t)(struct sock *sk,
-				  struct llc_conn_state_ev *ev);
-
-extern int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev);
+static __inline__ struct llc_conn_state_ev *llc_conn_ev(struct sk_buff *skb)
+{
+	return (struct llc_conn_state_ev *)skb->cb;
+}
+
+typedef int (*llc_conn_ev_t)(struct sock *sk, struct sk_buff *skb);
+typedef int (*llc_conn_ev_qfyr_t)(struct sock *sk, struct sk_buff *skb);
+
+extern int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_conn_resp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_rst_resp(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_local_busy_detected(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_local_busy_cleared(struct sock *sk,
-					  struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rx_bad_pdu(struct sock *sk,
-				  struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
+extern int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk,
-					      struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
 extern int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk,
-					      struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						    struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk,
-					       struct llc_conn_state_ev *ev);
+					       struct sk_buff *skb);
 extern int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rx_xxx_yyy(struct sock *sk,
-				  struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
+extern int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						      struct sk_buff *skb);
 extern int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_p_tmr_exp(struct sock *sk,
-				   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_ack_tmr_exp(struct sock *sk,
-				   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rej_tmr_exp(struct sock *sk,
-				   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_busy_tmr_exp(struct sock *sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_any_tmr_exp(struct sock *sk,
-				   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_sendack_tmr_exp(struct sock *sk,
-				       struct llc_conn_state_ev *ev);
+						      struct sk_buff *skb);
+extern int llc_conn_ev_p_tmr_exp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_any_tmr_exp(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_sendack_tmr_exp(struct sock *sk, struct sk_buff *skb);
 /* NOT_USED functions and their variations */
 extern int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_rx_any_frame(struct sock *sk,
-				    struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_tx_buffer_full(struct sock *sk,
-				      struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_init_p_f_cycle(struct sock *sk,
-				      struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
+extern int llc_conn_ev_rx_any_frame(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct sk_buff *skb);
 
 /* Available connection action qualifiers */
 extern int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk,
-					struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
+extern int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk,
-					struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
+extern int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk,
-					     struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk,
-					struct llc_conn_state_ev *ev);
-extern int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk,
-					struct llc_conn_state_ev *ev);
+					     struct sk_buff *skb);
+extern int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk,
-					   struct llc_conn_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_conn(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_disc(struct sock *sk,
-					    struct llc_conn_state_ev *ev);
+					    struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_failed(struct sock *sk,
-					      struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk,
-						  struct llc_conn_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_received(struct sock *sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk,
-					      struct llc_conn_state_ev *ev);
+					      struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
-						struct llc_conn_state_ev *ev);
+						struct sk_buff *skb);
 #endif /* LLC_C_EV_H */
diff -Nru a/include/net/llc_conn.h b/include/net/llc_conn.h
--- a/include/net/llc_conn.h	Tue Aug 27 12:28:08 2002
+++ b/include/net/llc_conn.h	Tue Aug 27 12:28:08 2002
@@ -136,12 +136,10 @@
 extern int llc_sock_init(struct sock *sk);
 
 /* Access to a connection */
-extern struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk);
-extern int llc_conn_send_ev(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb);
 extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
-extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb,
-			     struct llc_conn_state_ev *ev);
-extern void llc_conn_free_ev(struct llc_conn_state_ev *ev);
+extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb);
+extern void llc_conn_free_ev(struct sk_buff *skb);
 extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr,
 					 u8 first_p_bit);
 extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr,
diff -Nru a/include/net/llc_evnt.h b/include/net/llc_evnt.h
--- a/include/net/llc_evnt.h	Tue Aug 27 12:28:01 2002
+++ b/include/net/llc_evnt.h	Tue Aug 27 12:28:01 2002
@@ -58,7 +58,7 @@
 	struct llc_stat_ev_simple_if  a;	/* 'a' for simple, easy ... */
 	struct llc_stat_ev_prim_if    prim;
 	struct llc_stat_ev_pdu_if     pdu;
-	struct llc_stat_ev_tmr_if   tmr;
+	struct llc_stat_ev_tmr_if     tmr;
 	struct llc_stat_ev_rpt_sts_if rsts;	/* report status */
 };
 
@@ -68,26 +68,32 @@
 	struct list_head	node; /* node in station->ev_q.list */
 };
 
+static __inline__ struct llc_station_state_ev *
+					llc_station_ev(struct sk_buff *skb)
+{
+	return (struct llc_station_state_ev *)skb->cb;
+}
+
 typedef int (*llc_station_ev_t)(struct llc_station *station,
-				struct llc_station_state_ev *ev);
+				struct sk_buff *skb);
 
 extern int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+						  struct sk_buff *skb);
 extern int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+						     struct sk_buff *skb);
 extern int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *
 									station,
-					       struct llc_station_state_ev *ev);
+							  struct sk_buff *skb);
 extern int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+							  struct sk_buff *skb);
 extern int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
-					  struct llc_station_state_ev *ev);
+					  struct sk_buff *skb);
 extern int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+							 struct sk_buff *skb);
 extern int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+							 struct sk_buff *skb);
 extern int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
-					   struct llc_station_state_ev *ev);
+					   struct sk_buff *skb);
 extern int llc_stat_ev_disable_req(struct llc_station *station,
-				       struct llc_station_state_ev *ev);
+				   struct sk_buff *skb);
 #endif /* LLC_EVNT_H */
diff -Nru a/include/net/llc_mac.h b/include/net/llc_mac.h
--- a/include/net/llc_mac.h	Tue Aug 27 12:28:02 2002
+++ b/include/net/llc_mac.h	Tue Aug 27 12:28:02 2002
@@ -20,4 +20,15 @@
 extern int llc_pdu_router(struct llc_sap *sap, struct sock *sk,
 			  struct sk_buff *skb, u8 type);
 extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da);
+
+static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type)
+{
+	skb->cb[sizeof(skb->cb) - 1] = type;
+}
+
+static __inline__ char llc_backlog_type(struct sk_buff *skb)
+{
+	return skb->cb[sizeof(skb->cb) - 1];
+}
+
 #endif /* LLC_MAC_H */
diff -Nru a/include/net/llc_main.h b/include/net/llc_main.h
--- a/include/net/llc_main.h	Tue Aug 27 12:28:02 2002
+++ b/include/net/llc_main.h	Tue Aug 27 12:28:02 2002
@@ -19,37 +19,40 @@
 #define LLC_ACK_TIME		 3
 #define LLC_REJ_TIME		 3
 #define LLC_BUSY_TIME		 3
-#define LLC_SENDACK_TIME	50
 #define LLC_DEST_INVALID	 0	/* Invalid LLC PDU type */
 #define LLC_DEST_SAP		 1	/* Type 1 goes here */
 #define LLC_DEST_CONN		 2	/* Type 2 goes here */
 
-/* LLC Layer global default parameters */
-
-#define LLC_GLOBAL_DEFAULT_MAX_NBR_SAPS		4
-#define LLC_GLOBAL_DEFAULT_MAX_NBR_CONNS	64
-
-extern struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
-
-/* LLC station component (SAP and connection resource manager) */
-/* Station component; one per adapter */
+/**
+ * struct llc_station - LLC station component
+ *
+ * SAP and connection resource manager, one per adapter.
+ *
+ * @state - state of station
+ * @xid_r_count - XID response PDU counter
+ * @ack_tmr_running - 1 or 0
+ * @mac_sa - MAC source address
+ * @sap_list - list of related SAPs
+ * @ev_q - events entering state mach.
+ * @mac_pdu_q - PDUs ready to send to MAC
+ */
 struct llc_station {
-	u8     state;			/* state of station */
-	u8     xid_r_count;		/* XID response PDU counter */
-	struct timer_list ack_timer;
-	u8     ack_tmr_running;		/* 1 or 0 */
-	u8     retry_count;
-	u8     maximum_retry;
-	u8     mac_sa[6];		/* MAC source address */
+	u8			    state;
+	u8			    xid_r_count;
+	struct timer_list	    ack_timer;
+	u8			    ack_tmr_running;
+	u8			    retry_count;
+	u8			    maximum_retry;
+	u8			    mac_sa[6];
 	struct {
-		spinlock_t	 lock;
-		struct list_head list;
-	} sap_list;			/* list of related SAPs */
+		spinlock_t	    lock;
+		struct list_head    list;
+	} sap_list;
 	struct {
-		spinlock_t	 lock;
-		struct list_head list;
-	} ev_q;				/* events entering state mach. */
-	struct sk_buff_head mac_pdu_q;	/* PDUs ready to send to MAC */
+		struct sk_buff_head list;
+		spinlock_t	    lock;
+	} ev_q;
+	struct sk_buff_head	    mac_pdu_q;
 };
 struct llc_station_state_ev;
 
@@ -58,10 +61,8 @@
 extern void llc_free_sap(struct llc_sap *sap);
 extern struct llc_sap *llc_sap_find(u8 lsap);
 extern struct llc_station *llc_station_get(void);
-extern struct llc_station_state_ev *
-			     llc_station_alloc_ev(struct llc_station *station);
 extern void llc_station_send_ev(struct llc_station *station,
-				struct llc_station_state_ev *ev);
+				struct sk_buff *skb);
 extern void llc_station_send_pdu(struct llc_station *station,
 				 struct sk_buff *skb);
 extern struct sk_buff *llc_alloc_frame(void);
diff -Nru a/include/net/llc_pdu.h b/include/net/llc_pdu.h
--- a/include/net/llc_pdu.h	Tue Aug 27 12:28:01 2002
+++ b/include/net/llc_pdu.h	Tue Aug 27 12:28:01 2002
@@ -198,12 +198,27 @@
 	u8 ctrl_2;
 };
 
+static __inline__ struct llc_pdu_sn *llc_pdu_sn_hdr(struct sk_buff *skb)
+{
+	return (struct llc_pdu_sn *)skb->nh.raw;
+}
+
 /* Un-numbered PDU format (3 bytes in length) */
 struct llc_pdu_un {
 	u8 dsap;
 	u8 ssap;
 	u8 ctrl_1;
 };
+
+static __inline__ struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb)
+{
+	return (struct llc_pdu_un *)skb->nh.raw;
+}
+
+static __inline__ void *llc_set_pdu_hdr(struct sk_buff *skb, void *ptr)
+{
+	return skb->nh.raw = ptr;
+}
 
 /* LLC Type 1 XID command/response information fields format */
 struct llc_xid_info {
diff -Nru a/include/net/llc_s_ac.h b/include/net/llc_s_ac.h
--- a/include/net/llc_s_ac.h	Tue Aug 27 12:28:08 2002
+++ b/include/net/llc_s_ac.h	Tue Aug 27 12:28:08 2002
@@ -23,25 +23,17 @@
 #define SAP_ACT_TEST_IND	9
 
 /* All action functions must look like this */
-typedef int (*llc_sap_action_t)(struct llc_sap *sap,
-				struct llc_sap_state_ev *ev);
+typedef int (*llc_sap_action_t)(struct llc_sap *sap, struct sk_buff *skb);
 
 extern int llc_sap_action_unitdata_ind(struct llc_sap *sap,
-				       struct llc_sap_state_ev *ev);
-extern int llc_sap_action_send_ui(struct llc_sap *sap,
-				  struct llc_sap_state_ev *ev);
-extern int llc_sap_action_send_xid_c(struct llc_sap *sap,
-				     struct llc_sap_state_ev *ev);
-extern int llc_sap_action_send_xid_r(struct llc_sap *sap,
-				     struct llc_sap_state_ev *ev);
-extern int llc_sap_action_send_test_c(struct llc_sap *sap,
-				      struct llc_sap_state_ev *ev);
-extern int llc_sap_action_send_test_r(struct llc_sap *sap,
-				      struct llc_sap_state_ev *ev);
+				       struct sk_buff *skb);
+extern int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb);
 extern int llc_sap_action_report_status(struct llc_sap *sap,
-					struct llc_sap_state_ev *ev);
-extern int llc_sap_action_xid_ind(struct llc_sap *sap,
-				  struct llc_sap_state_ev *ev);
-extern int llc_sap_action_test_ind(struct llc_sap *sap,
-				   struct llc_sap_state_ev *ev);
+					struct sk_buff *skb);
+extern int llc_sap_action_xid_ind(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_action_test_ind(struct llc_sap *sap, struct sk_buff *skb);
 #endif /* LLC_S_AC_H */
diff -Nru a/include/net/llc_s_ev.h b/include/net/llc_s_ev.h
--- a/include/net/llc_s_ev.h	Tue Aug 27 12:27:59 2002
+++ b/include/net/llc_s_ev.h	Tue Aug 27 12:27:59 2002
@@ -11,6 +11,9 @@
  *
  * See the GNU General Public License for more details.
  */
+
+#include <linux/skbuff.h>
+
 /* Defines SAP component events */
 /* Types of events (possible values in 'ev->type') */
 #define LLC_SAP_EV_TYPE_SIMPLE		1
@@ -45,9 +48,8 @@
 };
 
 struct llc_sap_ev_pdu_if {
-	u8		   ev;
-	u8		   reason;
-	struct sk_buff *skb;
+	u8 ev;
+	u8 reason;
 };
 
 struct llc_sap_ev_tmr_if {
@@ -75,27 +77,24 @@
 	union llc_sap_ev_if	  data;
 };
 
+static __inline__ struct llc_sap_state_ev *llc_sap_ev(struct sk_buff *skb)
+{
+	return (struct llc_sap_state_ev *)skb->cb;
+}
+
 struct llc_sap;
 
-typedef int (*llc_sap_ev_t)(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+typedef int (*llc_sap_ev_t)(struct llc_sap *sap, struct sk_buff *skb);
 
-extern int llc_sap_ev_activation_req(struct llc_sap *sap,
-				     struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_unitdata_req(struct llc_sap *sap,
-				   struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_xid_req(struct llc_sap *sap,
-			      struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_rx_xid_c(struct llc_sap *sap,
-			       struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_rx_xid_r(struct llc_sap *sap,
-			       struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_test_req(struct llc_sap *sap,
-			       struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_rx_test_c(struct llc_sap *sap,
-				struct llc_sap_state_ev *ev);
-extern int llc_sap_ev_rx_test_r(struct llc_sap *sap,
-				struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb);
+extern int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct sk_buff *skb);
 extern int llc_sap_ev_deactivation_req(struct llc_sap *sap,
-				       struct llc_sap_state_ev *ev);
+				       struct sk_buff *skb);
 #endif /* LLC_S_EV_H */
diff -Nru a/include/net/llc_s_st.h b/include/net/llc_s_st.h
--- a/include/net/llc_s_st.h	Tue Aug 27 12:28:08 2002
+++ b/include/net/llc_s_st.h	Tue Aug 27 12:28:08 2002
@@ -15,7 +15,8 @@
 
 #define LLC_SAP_STATE_INACTIVE	1
 #define LLC_SAP_STATE_ACTIVE	2
-#define LLC_NBR_SAP_STATES	2       /* size of state table */
+#define LLC_NR_SAP_STATES	2       /* size of state table */
+
 /* structures and types */
 /* SAP state table structure */
 struct llc_sap_state_trans {
@@ -25,10 +26,10 @@
 };
 
 struct llc_sap_state {
-    u8				 curr_state;
-    struct llc_sap_state_trans **transitions;
+	u8			   curr_state;
+	struct llc_sap_state_trans **transitions;
 };
 
 /* only access to SAP state table */
-extern struct llc_sap_state llc_sap_state_table[LLC_NBR_SAP_STATES];
+extern struct llc_sap_state llc_sap_state_table[LLC_NR_SAP_STATES];
 #endif /* LLC_S_ST_H */
diff -Nru a/include/net/llc_sap.h b/include/net/llc_sap.h
--- a/include/net/llc_sap.h	Tue Aug 27 12:27:47 2002
+++ b/include/net/llc_sap.h	Tue Aug 27 12:27:51 2002
@@ -12,31 +12,44 @@
  * See the GNU General Public License for more details.
  */
 #include <linux/skbuff.h>
-/* Defines the SAP component */
+/**
+ * struct llc_sap - Defines the SAP component
+ *
+ * @p_bit - only lowest-order bit used
+ * @f_bit - only lowest-order bit used
+ * @req - provided by LLC layer
+ * @resp - provided by LLC layer
+ * @ind - provided by network layer
+ * @conf - provided by network layer
+ * @laddr - SAP value in this 'lsap'
+ * @node - entry in station sap_list
+ * @sk_list - LLC sockets this one manages
+ * @mac_pdu_q - PDUs ready to send to MAC
+ */
 struct llc_sap {
-	u8		    state;
-	struct llc_station *parent_station;
-	u8		    p_bit;		/* only lowest-order bit used */
-	u8		    f_bit;		/* only lowest-order bit used */
-	llc_prim_call_t	    req;		/* provided by LLC layer */
-	llc_prim_call_t	    resp;		/* provided by LLC layer */
-	llc_prim_call_t	    ind;		/* provided by network layer */
-	llc_prim_call_t	    conf;		/* provided by network layer */
-	struct llc_addr	    laddr;		/* SAP value in this 'lsap' */
-	struct list_head    node;		/* entry in station sap_list */
+	struct llc_station	 *parent_station;
+	u8			 state;
+	u8			 p_bit;
+	u8			 f_bit;
+	llc_prim_call_t		 req;
+	llc_prim_call_t		 resp;
+	llc_prim_call_t		 ind;
+	llc_prim_call_t		 conf;
+	struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
+	union llc_u_prim_data	 llc_ind_data_prim, llc_cfm_data_prim;
+	struct llc_addr		 laddr;
+	struct list_head	 node;
 	struct {
 		spinlock_t	 lock;
 		struct list_head list;
-	} sk_list; /* LLC sockets this one manages */
-	struct sk_buff_head mac_pdu_q;		/* PDUs ready to send to MAC */
+	} sk_list;
+	struct sk_buff_head	 mac_pdu_q;
 };
 struct llc_sap_state_ev;
 
 extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk);
 extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
-extern void llc_sap_send_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev);
-extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb,
-			    struct llc_sap_state_ev *ev);
+extern void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb);
+extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
-extern struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap);
 #endif /* LLC_SAP_H */
diff -Nru a/include/net/p8022.h b/include/net/p8022.h
--- a/include/net/p8022.h	Tue Aug 27 12:28:02 2002
+++ b/include/net/p8022.h	Tue Aug 27 12:28:02 2002
@@ -1,9 +1,9 @@
 #ifndef _NET_P8022_H
 #define _NET_P8022_H
+#include <net/llc_if.h>
+
 extern struct datalink_proto *register_8022_client(unsigned char type,
-						   int (*rcvfunc)
-						   	(struct sk_buff *,
-							 struct net_device *,
-							 struct packet_type *));
-extern void unregister_8022_client(unsigned char type);
+			   int (*indicate)(struct llc_prim_if_block *prim));
+extern void unregister_8022_client(struct datalink_proto *proto);
+
 #endif
diff -Nru a/include/net/psnap.h b/include/net/psnap.h
--- a/include/net/psnap.h	Tue Aug 27 12:28:01 2002
+++ b/include/net/psnap.h	Tue Aug 27 12:28:01 2002
@@ -2,6 +2,6 @@
 #define _NET_PSNAP_H
 
 extern struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *));
-extern void unregister_snap_client(unsigned char *desc);
+extern void unregister_snap_client(struct datalink_proto *proto);
 
 #endif
diff -Nru a/include/scsi/sg.h b/include/scsi/sg.h
--- a/include/scsi/sg.h	Tue Aug 27 12:28:02 2002
+++ b/include/scsi/sg.h	Tue Aug 27 12:28:02 2002
@@ -11,9 +11,13 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.5.26 (20020708)
+    Version: 3.5.27 (20020812)
     This version is for 2.5 series kernels.
 
+    Changes since 3.5.26 (20020708)
+	- re-add direct IO using Kai Makisara's work
+	- re-tab to 8, start using C99-isms
+	- simplify memory management
     Changes since 3.5.25 (20020504)
 	- driverfs additions
 	- copy_to/from_user() fixes [William Stinson]
diff -Nru a/include/video/fbcon.h b/include/video/fbcon.h
--- a/include/video/fbcon.h	Tue Aug 27 12:28:01 2002
+++ b/include/video/fbcon.h	Tue Aug 27 12:28:01 2002
@@ -55,12 +55,6 @@
     struct fb_var_screeninfo var;   /* variable infos. yoffset and vmode */
                                     /* are updated by fbcon.c */
     struct fb_cmap cmap;            /* colormap */
-    int visual;
-    int type;                       /* see FB_TYPE_* */
-    int type_aux;                   /* Interleave for interleaved Planes */
-    u_short ypanstep;               /* zero if no hardware ypan */
-    u_short ywrapstep;              /* zero if no hardware ywrap */
-    u_long line_length;             /* length of a line in bytes */
     u_short can_soft_blank;         /* zero if no hardware blanking */
     u_short inverse;                /* != 0 text black on white as default */
     struct display_switch *dispsw;  /* low level operations */
@@ -73,7 +67,6 @@
 #endif
 
     /* Filled in by the low-level console driver */
-
     struct vc_data *conp;           /* pointer to console data */
     struct fb_info *fb_info;        /* frame buffer for this console */
     int vrows;                      /* number of virtual rows */
diff -Nru a/init/Makefile b/init/Makefile
--- a/init/Makefile	Tue Aug 27 12:28:02 2002
+++ b/init/Makefile	Tue Aug 27 12:28:02 2002
@@ -19,4 +19,4 @@
 
 $(objtree)/include/linux/compile.h: FORCE
 	@echo -n '  Generating $@'
-	@../scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+	@$(srctree)/scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
diff -Nru a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c	Tue Aug 27 12:28:02 2002
+++ b/init/do_mounts.c	Tue Aug 27 12:28:02 2002
@@ -24,16 +24,16 @@
 
 extern int get_filesystem_list(char * buf);
 
-asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
+extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
 	 unsigned long flags, void *data);
-asmlinkage long sys_mkdir(char *name, int mode);
-asmlinkage long sys_chdir(char *name);
-asmlinkage long sys_chroot(char *name);
-asmlinkage long sys_unlink(char *name);
-asmlinkage long sys_symlink(char *old, char *new);
-asmlinkage long sys_mknod(char *name, int mode, dev_t dev);
-asmlinkage long sys_umount(char *name, int flags);
-asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
+extern asmlinkage long sys_mkdir(const char *name, int mode);
+extern asmlinkage long sys_chdir(const char *name);
+extern asmlinkage long sys_chroot(const char *name);
+extern asmlinkage long sys_unlink(const char *name);
+extern asmlinkage long sys_symlink(const char *old, const char *new);
+extern asmlinkage long sys_mknod(const char *name, int mode, dev_t dev);
+extern asmlinkage long sys_umount(char *name, int flags);
+extern asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned int real_root_dev;	/* do_proc_dointvec cannot handle kdev_t */
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Tue Aug 27 12:28:01 2002
+++ b/init/main.c	Tue Aug 27 12:28:01 2002
@@ -83,6 +83,12 @@
 #endif
 
 /*
+ * Are we up and running (ie do we have all the infrastructure
+ * set up)
+ */
+int system_running = 0;
+
+/*
  * Boot command-line arguments
  */
 #define MAX_INIT_ARGS 8
@@ -559,6 +565,7 @@
 	 */
 	free_initmem();
 	unlock_kernel();
+	system_running = 1;
 
 	kstat.pgfree = 0;
 
diff -Nru a/kernel/cpu.c b/kernel/cpu.c
--- a/kernel/cpu.c	Tue Aug 27 12:28:08 2002
+++ b/kernel/cpu.c	Tue Aug 27 12:28:08 2002
@@ -46,7 +46,7 @@
 
 	/* Now call notifier in preparation. */
 	printk("CPU %u IS NOW UP!\n", cpu);
-	notifier_call_chain(&cpu_chain, CPU_ONLINE, (void *)cpu);
+	notifier_call_chain(&cpu_chain, CPU_ONLINE, (void *)(long)cpu);
 
  out:
 	up(&cpucontrol);
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Tue Aug 27 12:28:02 2002
+++ b/kernel/exit.c	Tue Aug 27 12:28:02 2002
@@ -18,6 +18,7 @@
 #include <linux/acct.h>
 #include <linux/file.h>
 #include <linux/binfmts.h>
+#include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -56,21 +57,26 @@
 
 static void release_task(struct task_struct * p)
 {
-	if (p == current)
+	if (p->state != TASK_ZOMBIE)
 		BUG();
 #ifdef CONFIG_SMP
-	wait_task_inactive(p);
+	if (p != current)
+		wait_task_inactive(p);
 #endif
 	atomic_dec(&p->user->processes);
 	security_ops->task_free_security(p);
 	free_uid(p->user);
+	BUG_ON(p->ptrace || !list_empty(&p->ptrace_list) ||
+					!list_empty(&p->ptrace_children));
 	unhash_process(p);
 
 	release_thread(p);
-	current->cmin_flt += p->min_flt + p->cmin_flt;
-	current->cmaj_flt += p->maj_flt + p->cmaj_flt;
-	current->cnswap += p->nswap + p->cnswap;
-	sched_exit(p);
+	if (p != current) {
+		current->cmin_flt += p->min_flt + p->cmin_flt;
+		current->cmaj_flt += p->maj_flt + p->cmaj_flt;
+		current->cnswap += p->nswap + p->cnswap;
+		sched_exit(p);
+	}
 	put_task_struct(p);
 }
 
@@ -174,6 +180,7 @@
 {
 	write_lock_irq(&tasklist_lock);
 
+	ptrace_unlink(current);
 	/* Reparent to init */
 	REMOVE_LINKS(current);
 	current->parent = child_reaper;
@@ -228,45 +235,20 @@
 	atomic_inc(&current->files->count);
 }
 
-/*
- * When we die, we re-parent all our children.
- * Try to give them to another thread in our thread
- * group, and if no such member exists, give it to
- * the global child reaper process (ie "init")
- */
-static inline void forget_original_parent(struct task_struct * father)
+static void reparent_thread(task_t *p, task_t *reaper, task_t *child_reaper)
 {
-	struct task_struct * p, *reaper;
-
-	read_lock(&tasklist_lock);
-
-	/* Next in our thread group, if they're not already exiting */
-	reaper = father;
-	do {
-		reaper = next_thread(reaper);
-		if (!(reaper->flags & PF_EXITING))
-			break;
-	} while (reaper != father);
+	/* We dont want people slaying init */
+	p->exit_signal = SIGCHLD;
+	p->self_exec_id++;
+
+	/* Make sure we're not reparenting to ourselves */
+	if (p == reaper)
+		p->real_parent = child_reaper;
+	else
+		p->real_parent = reaper;
 
-	if (reaper == father)
-		reaper = child_reaper;
-
-	for_each_task(p) {
-		if (p->real_parent == father) {
-			/* We dont want people slaying init */
-			p->exit_signal = SIGCHLD;
-			p->self_exec_id++;
-
-			/* Make sure we're not reparenting to ourselves */
-			if (p == reaper)
-				p->real_parent = child_reaper;
-			else
-				p->real_parent = reaper;
-
-			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
-		}
-	}
-	read_unlock(&tasklist_lock);
+	if (p->pdeath_signal)
+		send_sig(p->pdeath_signal, p, 0);
 }
 
 static inline void close_files(struct files_struct * files)
@@ -417,12 +399,85 @@
 }
 
 /*
+ * When we die, we re-parent all our children.
+ * Try to give them to another thread in our thread
+ * group, and if no such member exists, give it to
+ * the global child reaper process (ie "init")
+ */
+static inline void forget_original_parent(struct task_struct * father)
+{
+	struct task_struct *p, *reaper;
+	list_t *_p;
+
+	read_lock(&tasklist_lock);
+
+	/* Next in our thread group, if they're not already exiting */
+	reaper = father;
+	do {
+		reaper = next_thread(reaper);
+		if (!(reaper->flags & PF_EXITING))
+			break;
+	} while (reaper != father);
+
+	if (reaper == father)
+		reaper = child_reaper;
+
+	/*
+	 * There are only two places where our children can be:
+	 *
+	 * - in our child list
+	 * - in the global ptrace list
+	 *
+	 * Search them and reparent children.
+	 */
+	list_for_each(_p, &father->children) {
+		p = list_entry(_p,struct task_struct,sibling);
+		reparent_thread(p, reaper, child_reaper);
+	}
+	list_for_each(_p, &father->ptrace_children) {
+		p = list_entry(_p,struct task_struct,ptrace_list);
+		reparent_thread(p, reaper, child_reaper);
+	}
+	read_unlock(&tasklist_lock);
+}
+
+static inline void zap_thread(task_t *p, task_t *father)
+{
+	ptrace_unlink(p);
+	list_del_init(&p->sibling);
+	p->ptrace = 0;
+
+	p->parent = p->real_parent;
+	list_add_tail(&p->sibling, &p->parent->children);
+	if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
+		do_notify_parent(p, p->exit_signal);
+	/*
+	 * process group orphan check
+	 * Case ii: Our child is in a different pgrp
+	 * than we are, and it was the only connection
+	 * outside, so the child pgrp is now orphaned.
+	 */
+	if ((p->pgrp != current->pgrp) &&
+	    (p->session == current->session)) {
+		int pgrp = p->pgrp;
+
+		write_unlock_irq(&tasklist_lock);
+		if (is_orphaned_pgrp(pgrp) && has_stopped_jobs(pgrp)) {
+			kill_pg(pgrp,SIGHUP,1);
+			kill_pg(pgrp,SIGCONT,1);
+		}
+		write_lock_irq(&tasklist_lock);
+	}
+}
+
+/*
  * Send signals to all our closest relatives so that they know
  * to properly mourn us..
  */
 static void exit_notify(void)
 {
-	struct task_struct * p, *t;
+	struct task_struct *t;
+	list_t *_p, *_n;
 
 	forget_original_parent(current);
 	/*
@@ -479,34 +534,22 @@
 
 	write_lock_irq(&tasklist_lock);
 	current->state = TASK_ZOMBIE;
-	do_notify_parent(current, current->exit_signal);
-	while ((p = eldest_child(current))) {
-		list_del_init(&p->sibling);
-		p->ptrace = 0;
-
-		p->parent = p->real_parent;
-		list_add_tail(&p->sibling,&p->parent->children);
-		if (p->state == TASK_ZOMBIE)
-			do_notify_parent(p, p->exit_signal);
-		/*
-		 * process group orphan check
-		 * Case ii: Our child is in a different pgrp
-		 * than we are, and it was the only connection
-		 * outside, so the child pgrp is now orphaned.
-		 */
-		if ((p->pgrp != current->pgrp) &&
-		    (p->session == current->session)) {
-			int pgrp = p->pgrp;
-
-			write_unlock_irq(&tasklist_lock);
-			if (is_orphaned_pgrp(pgrp) && has_stopped_jobs(pgrp)) {
-				kill_pg(pgrp,SIGHUP,1);
-				kill_pg(pgrp,SIGCONT,1);
-			}
-			write_lock_irq(&tasklist_lock);
-		}
-	}
+	if (current->exit_signal != -1)
+		do_notify_parent(current, current->exit_signal);
 
+zap_again:
+	list_for_each_safe(_p, _n, &current->children)
+		zap_thread(list_entry(_p,struct task_struct,sibling), current);
+	list_for_each_safe(_p, _n, &current->ptrace_children)
+		zap_thread(list_entry(_p,struct task_struct,ptrace_list), current);
+	/*
+	 * reparent_thread might drop the tasklist lock, thus we could
+	 * have new children queued back from the ptrace list into the
+	 * child list:
+	 */
+	if (unlikely(!list_empty(&current->children) ||
+			!list_empty(&current->ptrace_children)))
+		goto zap_again;
 	/*
 	 * No need to unlock IRQs, we'll schedule() immediately
 	 * anyway. In the preemption case this also makes it
@@ -555,6 +598,9 @@
 
 	tsk->exit_code = code;
 	exit_notify();
+	preempt_disable();
+	if (current->exit_signal == -1)
+		release_task(current);
 	schedule();
 	BUG();
 /*
@@ -616,6 +662,12 @@
 				if (p->pgrp != -pid)
 					continue;
 			}
+			/*
+			 * Do not consider detached threads that are
+			 * not ptraced:
+			 */
+			if (p->exit_signal == -1 && !p->ptrace)
+				continue;
 			/* Wait for all children (clone and not) if __WALL is set;
 			 * otherwise, wait for clone children *only* if __WCLONE is
 			 * set; otherwise, wait for non-clone children *only*.  (Note:
@@ -660,7 +712,7 @@
 				if (retval)
 					goto end_wait4; 
 				retval = p->pid;
-				if (p->real_parent != p->parent) {
+				if (p->real_parent != p->parent || p->ptrace) {
 					write_lock_irq(&tasklist_lock);
 					remove_parent(p);
 					p->parent = p->real_parent;
@@ -679,7 +731,7 @@
 		tsk = next_thread(tsk);
 	} while (tsk != current);
 	read_unlock(&tasklist_lock);
-	if (flag) {
+	if (flag || !list_empty(&current->ptrace_children)) {
 		retval = 0;
 		if (options & WNOHANG)
 			goto end_wait4;
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Tue Aug 27 12:27:59 2002
+++ b/kernel/fork.c	Tue Aug 27 12:27:59 2002
@@ -26,6 +26,8 @@
 #include <linux/mman.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/futex.h>
+#include <linux/ptrace.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -50,6 +52,31 @@
 
 rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;  /* outer */
 
+/*
+ * A per-CPU task cache - this relies on the fact that
+ * the very last portion of sys_exit() is executed with
+ * preemption turned off.
+ */
+static task_t *task_cache[NR_CPUS] __cacheline_aligned;
+
+void __put_task_struct(struct task_struct *tsk)
+{
+	if (tsk != current) {
+		free_thread_info(tsk->thread_info);
+		kmem_cache_free(task_struct_cachep,tsk);
+	} else {
+		int cpu = smp_processor_id();
+
+		tsk = task_cache[cpu];
+		if (tsk) {
+			free_thread_info(tsk->thread_info);
+			kmem_cache_free(task_struct_cachep,tsk);
+		}
+		task_cache[cpu] = current;
+	}
+}
+
+/* Protects next_safe and last_pid. */
 void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
@@ -106,9 +133,10 @@
 	struct thread_info *ti;
 
 	ti = alloc_thread_info();
-	if (!ti) return NULL;
+	if (!ti)
+		return NULL;
 
-	tsk = kmem_cache_alloc(task_struct_cachep,GFP_ATOMIC);
+	tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);
 	if (!tsk) {
 		free_thread_info(ti);
 		return NULL;
@@ -123,13 +151,6 @@
 	return tsk;
 }
 
-void __put_task_struct(struct task_struct *tsk)
-{
-	free_thread_info(tsk->thread_info);
-	kmem_cache_free(task_struct_cachep,tsk);
-}
-
-/* Protects next_safe and last_pid. */
 spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
 
 static int get_pid(unsigned long flags)
@@ -167,6 +188,8 @@
 				next_safe = p->pid;
 			if(p->pgrp > last_pid && next_safe > p->pgrp)
 				next_safe = p->pgrp;
+			if(p->tgid > last_pid && next_safe > p->tgid)
+				next_safe = p->tgid;
 			if(p->session > last_pid && next_safe > p->session)
 				next_safe = p->session;
 		}
@@ -349,6 +372,14 @@
 		tsk->vfork_done = NULL;
 		complete(vfork_done);
 	}
+	if (tsk->user_tid) {
+		/*
+		 * We dont check the error code - if userspace has
+		 * not set up a proper pointer then tough luck.
+		 */
+		put_user(0, tsk->user_tid);
+		sys_futex(tsk->user_tid, FUTEX_WAKE, 1, NULL);
+	}
 }
 
 static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
@@ -737,7 +768,10 @@
 
 	/* ok, now we should be set up.. */
 	p->swappable = 1;
-	p->exit_signal = clone_flags & CSIGNAL;
+	if (clone_flags & CLONE_DETACHED)
+		p->exit_signal = -1;
+	else
+		p->exit_signal = clone_flags & CSIGNAL;
 	p->pdeath_signal = 0;
 
 	/*
@@ -775,6 +809,8 @@
 	 */
 	p->tgid = p->pid;
 	INIT_LIST_HEAD(&p->thread_group);
+	INIT_LIST_HEAD(&p->ptrace_children);
+	INIT_LIST_HEAD(&p->ptrace_list);
 
 	/* Need tasklist lock for parent etc handling! */
 	write_lock_irq(&tasklist_lock);
@@ -794,6 +830,7 @@
 	}
 
 	SET_LINKS(p);
+	ptrace_link(p, p->parent);
 	hash_pid(p);
 	nr_threads++;
 	write_unlock_irq(&tasklist_lock);
diff -Nru a/kernel/kmod.c b/kernel/kmod.c
--- a/kernel/kmod.c	Tue Aug 27 12:28:02 2002
+++ b/kernel/kmod.c	Tue Aug 27 12:28:02 2002
@@ -32,7 +32,7 @@
 
 #include <asm/uaccess.h>
 
-extern int max_threads;
+extern int max_threads, system_running;
 
 static inline void
 use_init_fs_context(void)
@@ -158,6 +158,9 @@
 	char *argv[] = { modprobe_path, "-s", "-k", "--", (char*)module_name, NULL };
 	int ret;
 
+	if (!system_running)
+		return -EBUSY;
+
 	ret = exec_usermodehelper(modprobe_path, argv, envp);
 	if (ret) {
 		static unsigned long last;
@@ -197,10 +200,9 @@
 	unsigned long saved_policy = current->policy;
 
 	current->policy = SCHED_NORMAL;
-	/* Don't allow request_module() before the root fs is mounted!  */
-	if ( ! current->fs->root ) {
-		printk(KERN_ERR "request_module[%s]: Root fs not mounted\n",
-			module_name);
+	/* Don't allow request_module() when the system isn't set up */
+	if ( ! system_running ) {
+		printk(KERN_ERR "request_module[%s]: not ready\n", module_name);
 		ret = -EPERM;
 		goto out;
 	}
@@ -356,6 +358,9 @@
 		.routine	= __call_usermodehelper,
 		.data		= &sub_info,
 	};
+
+	if (!system_running)
+		return -EBUSY;
 
 	if (path[0] == '\0')
 		goto out;
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Aug 27 12:27:51 2002
+++ b/kernel/ksyms.c	Tue Aug 27 12:27:51 2002
@@ -50,6 +50,8 @@
 #include <linux/namei.h>
 #include <linux/buffer_head.h>
 #include <linux/root_dev.h>
+#include <linux/percpu.h>
+#include <linux/smp_lock.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -92,7 +94,7 @@
 EXPORT_SYMBOL(alloc_pages_node);
 EXPORT_SYMBOL(__get_free_pages);
 EXPORT_SYMBOL(get_zeroed_page);
-EXPORT_SYMBOL(page_cache_release);
+EXPORT_SYMBOL(__page_cache_release);
 EXPORT_SYMBOL(__free_pages);
 EXPORT_SYMBOL(free_pages);
 EXPORT_SYMBOL(num_physpages);
@@ -109,6 +111,8 @@
 EXPORT_SYMBOL(__vmalloc);
 EXPORT_SYMBOL(vmalloc);
 EXPORT_SYMBOL(vmalloc_32);
+EXPORT_SYMBOL(vmap);
+EXPORT_SYMBOL(vunmap);
 EXPORT_SYMBOL(vmalloc_to_page);
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(remap_page_range);
@@ -126,6 +130,7 @@
 EXPORT_SYMBOL(kmap_prot);
 EXPORT_SYMBOL(kmap_pte);
 #endif
+EXPORT_SYMBOL(get_user_pages);
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(def_blk_fops);
@@ -220,6 +225,7 @@
 EXPORT_SYMBOL(generic_file_sendfile);
 EXPORT_SYMBOL(do_generic_file_read);
 EXPORT_SYMBOL(generic_file_write);
+EXPORT_SYMBOL(generic_file_write_nolock);
 EXPORT_SYMBOL(generic_file_mmap);
 EXPORT_SYMBOL(generic_ro_fops);
 EXPORT_SYMBOL(file_lock_list);
@@ -340,7 +346,7 @@
 EXPORT_SYMBOL(read_dev_sector);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(wipe_partitions);
-EXPORT_SYMBOL(generic_file_direct_IO);
+EXPORT_SYMBOL_GPL(generic_file_direct_IO);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
@@ -476,6 +482,9 @@
 #if CONFIG_SMP
 EXPORT_SYMBOL_GPL(set_cpus_allowed);
 #endif
+#if CONFIG_SMP || CONFIG_PREEMPT
+EXPORT_SYMBOL(kernel_flag);
+#endif
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(jiffies_64);
 EXPORT_SYMBOL(xtime);
@@ -501,6 +510,7 @@
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(__bdevname);
 EXPORT_SYMBOL(cdevname);
+EXPORT_SYMBOL(simple_strtoull);
 EXPORT_SYMBOL(simple_strtoul);
 EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL(system_utsname);	/* UTS data */
@@ -595,3 +605,6 @@
 
 EXPORT_SYMBOL(tasklist_lock);
 EXPORT_SYMBOL(pidhash);
+#if defined(CONFIG_SMP) && defined(__GENERIC_PER_CPU)
+EXPORT_SYMBOL(__per_cpu_offset);
+#endif
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c	Tue Aug 27 12:28:05 2002
+++ b/kernel/printk.c	Tue Aug 27 12:28:05 2002
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>			/* For in_interrupt() */
 #include <linux/config.h>
+#include <linux/slab.h>
 #include <linux/delay.h>
 
 #include <asm/uaccess.h>
@@ -163,12 +164,15 @@
  * 	7 -- Enable printk's to console
  *	8 -- Set level of messages printed to console
  *	9 -- Return number of unread characters in the log buffer
+ *     10 -- Printk from userspace.  Includes loglevel.  Returns number of
+ *           chars printed.
  */
 int do_syslog(int type, char * buf, int len)
 {
 	unsigned long i, j, limit, count;
 	int do_clear = 0;
 	char c;
+	char *lbuf = NULL;
 	int error = 0;
 
 	switch (type) {
@@ -283,11 +287,23 @@
 		error = log_end - log_start;
 		spin_unlock_irq(&logbuf_lock);
 		break;
+	case 10:
+		lbuf = kmalloc(len + 1, GFP_KERNEL);
+		error = -ENOMEM;
+		if (lbuf == NULL)
+			break;
+		error = -EFAULT;
+		if (copy_from_user(lbuf, buf, len))
+			break;
+		lbuf[len] = '\0';
+		error = printk("%s", lbuf);
+		break;
 	default:
 		error = -EINVAL;
 		break;
 	}
 out:
+	kfree(lbuf);
 	return error;
 }
 
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c	Tue Aug 27 12:28:08 2002
+++ b/kernel/ptrace.c	Tue Aug 27 12:28:08 2002
@@ -13,11 +13,49 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include <linux/ptrace.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
 /*
+ * ptrace a task: make the debugger its new parent and
+ * move it to the ptrace list.
+ *
+ * Must be called with the tasklist lock write-held.
+ */
+void __ptrace_link(task_t *child, task_t *new_parent)
+{
+	if (!list_empty(&child->ptrace_list))
+		BUG();
+	if (child->parent == new_parent)
+		BUG();
+	list_add(&child->ptrace_list, &child->parent->ptrace_children);
+	REMOVE_LINKS(child);
+	child->parent = new_parent;
+	SET_LINKS(child);
+}
+ 
+/*
+ * unptrace a task: move it back to its original parent and
+ * remove it from the ptrace list.
+ *
+ * Must be called with the tasklist lock write-held.
+ */
+void __ptrace_unlink(task_t *child)
+{
+	if (!child->ptrace)
+		BUG();
+	child->ptrace = 0;
+	if (list_empty(&child->ptrace_list))
+		return;
+	list_del_init(&child->ptrace_list);
+	REMOVE_LINKS(child);
+	child->parent = child->real_parent;
+	SET_LINKS(child);
+}
+
+/*
  * Check that we have indeed attached to the thing..
  */
 int ptrace_check_attach(struct task_struct *child, int kill)
@@ -75,11 +113,7 @@
 	task_unlock(task);
 
 	write_lock_irq(&tasklist_lock);
-	if (task->parent != current) {
-		REMOVE_LINKS(task);
-		task->parent = current;
-		SET_LINKS(task);
-	}
+	__ptrace_link(task, current);
 	write_unlock_irq(&tasklist_lock);
 
 	send_sig(SIGSTOP, task, 1);
@@ -99,16 +133,15 @@
 	ptrace_disable(child);
 
 	/* .. re-parent .. */
-	child->ptrace = 0;
 	child->exit_code = data;
+
 	write_lock_irq(&tasklist_lock);
-	REMOVE_LINKS(child);
-	child->parent = child->real_parent;
-	SET_LINKS(child);
+	__ptrace_unlink(child);
+	/* .. and wake it up. */
+	if (child->state != TASK_ZOMBIE)
+		wake_up_process(child);
 	write_unlock_irq(&tasklist_lock);
 
-	/* .. and wake it up. */
-	wake_up_process(child);
 	return 0;
 }
 
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Tue Aug 27 12:28:02 2002
+++ b/kernel/sched.c	Tue Aug 27 12:28:02 2002
@@ -214,8 +214,7 @@
 
 static inline void rq_unlock(runqueue_t *rq)
 {
-	spin_unlock(&rq->lock);
-	local_irq_enable();
+	spin_unlock_irq(&rq->lock);
 }
 
 /*
@@ -1882,7 +1881,6 @@
 }
 
 #if CONFIG_SMP
-
 /*
  * This is how migration works:
  *
@@ -2064,11 +2062,25 @@
 {
 	/* Start one for boot CPU. */
 	migration_call(&migration_notifier, CPU_ONLINE,
-		       (void *)smp_processor_id());
+		       (void *)(long)smp_processor_id());
 	register_cpu_notifier(&migration_notifier);
 	return 0;
 }
 
+#endif
+
+#if CONFIG_SMP || CONFIG_PREEMPT
+/*
+ * The 'big kernel lock'
+ *
+ * This spinlock is taken and released recursively by lock_kernel()
+ * and unlock_kernel().  It is transparently dropped and reaquired
+ * over schedule().  It is used to protect legacy code that hasn't
+ * been migrated to a proper locking design yet.
+ *
+ * Don't use in new code.
+ */
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 #endif
 
 extern void init_timervecs(void);
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Tue Aug 27 12:28:02 2002
+++ b/kernel/signal.c	Tue Aug 27 12:28:02 2002
@@ -768,12 +768,15 @@
 /*
  * Let a parent know about a status change of a child.
  */
-
 void do_notify_parent(struct task_struct *tsk, int sig)
 {
 	struct siginfo info;
 	int why, status;
 
+	/* is the thread detached? */
+	if (sig == -1)
+		BUG();
+
 	info.si_signo = sig;
 	info.si_errno = 0;
 	info.si_pid = tsk->pid;
@@ -823,9 +826,11 @@
 void
 notify_parent(struct task_struct *tsk, int sig)
 {
-	read_lock(&tasklist_lock);
-	do_notify_parent(tsk, sig);
-	read_unlock(&tasklist_lock);
+	if (sig != -1) {
+		read_lock(&tasklist_lock);
+		do_notify_parent(tsk, sig);
+		read_unlock(&tasklist_lock);
+	}
 }
 
 #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Tue Aug 27 12:28:02 2002
+++ b/kernel/softirq.c	Tue Aug 27 12:28:02 2002
@@ -151,16 +151,16 @@
 
 /* Some compilers disobey section attribute on statics when not
    initialized -- RR */
-static struct tasklet_head tasklet_vec __per_cpu_data = { NULL };
-static struct tasklet_head tasklet_hi_vec __per_cpu_data = { NULL };
+static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
+static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL };
 
 void __tasklet_schedule(struct tasklet_struct *t)
 {
 	unsigned long flags;
 
 	local_irq_save(flags);
-	t->next = this_cpu(tasklet_vec).list;
-	this_cpu(tasklet_vec).list = t;
+	t->next = __get_cpu_var(tasklet_vec).list;
+	__get_cpu_var(tasklet_vec).list = t;
 	cpu_raise_softirq(smp_processor_id(), TASKLET_SOFTIRQ);
 	local_irq_restore(flags);
 }
@@ -170,8 +170,8 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	t->next = this_cpu(tasklet_hi_vec).list;
-	this_cpu(tasklet_hi_vec).list = t;
+	t->next = __get_cpu_var(tasklet_hi_vec).list;
+	__get_cpu_var(tasklet_hi_vec).list = t;
 	cpu_raise_softirq(smp_processor_id(), HI_SOFTIRQ);
 	local_irq_restore(flags);
 }
@@ -181,8 +181,8 @@
 	struct tasklet_struct *list;
 
 	local_irq_disable();
-	list = this_cpu(tasklet_vec).list;
-	this_cpu(tasklet_vec).list = NULL;
+	list = __get_cpu_var(tasklet_vec).list;
+	__get_cpu_var(tasklet_vec).list = NULL;
 	local_irq_enable();
 
 	while (list) {
@@ -202,8 +202,8 @@
 		}
 
 		local_irq_disable();
-		t->next = this_cpu(tasklet_vec).list;
-		this_cpu(tasklet_vec).list = t;
+		t->next = __get_cpu_var(tasklet_vec).list;
+		__get_cpu_var(tasklet_vec).list = t;
 		__cpu_raise_softirq(smp_processor_id(), TASKLET_SOFTIRQ);
 		local_irq_enable();
 	}
@@ -214,8 +214,8 @@
 	struct tasklet_struct *list;
 
 	local_irq_disable();
-	list = this_cpu(tasklet_hi_vec).list;
-	this_cpu(tasklet_hi_vec).list = NULL;
+	list = __get_cpu_var(tasklet_hi_vec).list;
+	__get_cpu_var(tasklet_hi_vec).list = NULL;
 	local_irq_enable();
 
 	while (list) {
@@ -235,8 +235,8 @@
 		}
 
 		local_irq_disable();
-		t->next = this_cpu(tasklet_hi_vec).list;
-		this_cpu(tasklet_hi_vec).list = t;
+		t->next = __get_cpu_var(tasklet_hi_vec).list;
+		__get_cpu_var(tasklet_hi_vec).list = t;
 		__cpu_raise_softirq(smp_processor_id(), HI_SOFTIRQ);
 		local_irq_enable();
 	}
@@ -412,7 +412,7 @@
 
 __init int spawn_ksoftirqd(void)
 {
-	cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)smp_processor_id());
+	cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)(long)smp_processor_id());
 	register_cpu_notifier(&cpu_nfb);
 	return 0;
 }
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Tue Aug 27 12:27:59 2002
+++ b/kernel/sys.c	Tue Aug 27 12:27:59 2002
@@ -37,6 +37,12 @@
 #ifndef GET_FPEMU_CTL
 # define GET_FPEMU_CTL(a,b)	(-EINVAL)
 #endif
+#ifndef SET_FPEXC_CTL
+# define SET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_FPEXC_CTL
+# define GET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -61,6 +67,7 @@
 int C_A_D = 1;
 int cad_pid = 1;
 
+extern int system_running;
 
 /*
  *	Notifier list for kernel code which wants to be called
@@ -317,6 +324,7 @@
 	switch (cmd) {
 	case LINUX_REBOOT_CMD_RESTART:
 		notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+		system_running = 0;
 		device_shutdown();
 		printk(KERN_EMERG "Restarting system.\n");
 		machine_restart(NULL);
@@ -332,6 +340,7 @@
 
 	case LINUX_REBOOT_CMD_HALT:
 		notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
+		system_running = 0;
 		device_shutdown();
 		printk(KERN_EMERG "System halted.\n");
 		machine_halt();
@@ -340,6 +349,7 @@
 
 	case LINUX_REBOOT_CMD_POWER_OFF:
 		notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+		system_running = 0;
 		device_shutdown();
 		printk(KERN_EMERG "Power down.\n");
 		machine_power_off();
@@ -354,6 +364,7 @@
 		buffer[sizeof(buffer) - 1] = '\0';
 
 		notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
+		system_running = 0;
 		device_shutdown();
 		printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
 		machine_restart(buffer);
@@ -1283,6 +1294,13 @@
 		case PR_GET_FPEMU:
 			error = GET_FPEMU_CTL(current, arg2);
 			break;
+		case PR_SET_FPEXC:
+			error = SET_FPEXC_CTL(current, arg2);
+			break;
+		case PR_GET_FPEXC:
+			error = GET_FPEXC_CTL(current, arg2);
+			break;
+
 
 		case PR_GET_KEEPCAPS:
 			if (current->keep_capabilities)
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Tue Aug 27 12:28:02 2002
+++ b/mm/filemap.c	Tue Aug 27 12:28:02 2002
@@ -21,6 +21,7 @@
 #include <linux/iobuf.h>
 #include <linux/hash.h>
 #include <linux/writeback.h>
+#include <linux/pagevec.h>
 #include <linux/security.h>
 /*
  * This is needed for the following functions:
@@ -52,7 +53,6 @@
 /*
  * Lock ordering:
  *
- *  pagemap_lru_lock
  *  ->i_shared_lock		(vmtruncate)
  *    ->private_lock		(__free_pte->__set_page_dirty_buffers)
  *      ->swap_list_lock
@@ -61,7 +61,7 @@
  *      ->inode_lock		(__mark_inode_dirty)
  *        ->sb_lock		(fs/fs-writeback.c)
  */
-spinlock_t pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+spinlock_t _pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /*
  * Remove a page from the page cache and free it. Caller has to make
@@ -117,10 +117,10 @@
 	struct list_head *head, *curr;
 	struct page * page;
 	struct address_space *mapping = inode->i_mapping;
+	struct pagevec lru_pvec;
 
 	head = &mapping->clean_pages;
-
-	spin_lock(&pagemap_lru_lock);
+	pagevec_init(&lru_pvec);
 	write_lock(&mapping->page_lock);
 	curr = head->next;
 
@@ -142,10 +142,10 @@
 		if (page_count(page) != 1)
 			goto unlock;
 
-		__lru_cache_del(page);
 		__remove_from_page_cache(page);
 		unlock_page(page);
-		page_cache_release(page);
+		if (!pagevec_add(&lru_pvec, page))
+			__pagevec_lru_del(&lru_pvec);
 		continue;
 unlock:
 		unlock_page(page);
@@ -153,7 +153,7 @@
 	}
 
 	write_unlock(&mapping->page_lock);
-	spin_unlock(&pagemap_lru_lock);
+	pagevec_lru_del(&lru_pvec);
 }
 
 static int do_invalidatepage(struct page *page, unsigned long offset)
@@ -173,16 +173,14 @@
 }
 
 /*
- * If truncate can remove the fs-private metadata from the page, it
- * removes the page from the LRU immediately.  This because some other thread
- * of control (eg, sendfile) may have a reference to the page.  But dropping
- * the final reference to an LRU page in interrupt context is illegal - it may
- * deadlock over pagemap_lru_lock.
+ * If truncate cannot remove the fs-private metadata from the page, the page
+ * becomes anonymous.  It will be left on the LRU and may even be mapped into
+ * user pagetables if we're racing with filemap_nopage().
  */
 static void truncate_complete_page(struct page *page)
 {
-	if (!PagePrivate(page) || do_invalidatepage(page, 0))
-		lru_cache_del(page);
+	if (PagePrivate(page))
+		do_invalidatepage(page, 0);
 
 	ClearPageDirty(page);
 	ClearPageUptodate(page);
@@ -203,8 +201,10 @@
 	struct list_head *curr;
 	struct page * page;
 	int unlocked = 0;
+	struct pagevec release_pvec;
 
- restart:
+	pagevec_init(&release_pvec);
+restart:
 	curr = head->next;
 	while (curr != head) {
 		unsigned long offset;
@@ -224,18 +224,17 @@
 				list_add_tail(head, curr);
 				write_unlock(&mapping->page_lock);
 				wait_on_page_writeback(page);
-				page_cache_release(page);
+				if (!pagevec_add(&release_pvec, page))
+					__pagevec_release(&release_pvec);
 				unlocked = 1;
 				write_lock(&mapping->page_lock);
 				goto restart;
 			}
 
 			list_del(head);
-			if (!failed)
-				/* Restart after this page */
+			if (!failed)		/* Restart after this page */
 				list_add(head, curr);
-			else
-				/* Restart on this page */
+			else			/* Restart on this page */
 				list_add_tail(head, curr);
 
 			write_unlock(&mapping->page_lock);
@@ -245,25 +244,27 @@
 				if (*partial && (offset + 1) == start) {
 					truncate_partial_page(page, *partial);
 					*partial = 0;
-				} else 
+				} else {
 					truncate_complete_page(page);
-
+				}
 				unlock_page(page);
-			} else
+			} else {
  				wait_on_page_locked(page);
-
-			page_cache_release(page);
-
-			if (need_resched()) {
-				__set_current_state(TASK_RUNNING);
-				schedule();
 			}
-
+			if (!pagevec_add(&release_pvec, page))
+				__pagevec_release(&release_pvec);
+			cond_resched();
 			write_lock(&mapping->page_lock);
 			goto restart;
 		}
 		curr = curr->next;
 	}
+	if (pagevec_count(&release_pvec)) {
+		write_unlock(&mapping->page_lock);
+		pagevec_release(&release_pvec);
+		write_lock(&mapping->page_lock);
+		unlocked = 1;
+	}
 	return unlocked;
 }
 
@@ -361,8 +362,10 @@
 	struct list_head *curr;
 	struct page * page;
 	int unlocked = 0;
+	struct pagevec release_pvec;
 
- restart:
+	pagevec_init(&release_pvec);
+restart:
 	curr = head->prev;
 	while (curr != head) {
 		page = list_entry(curr, struct page, list);
@@ -379,7 +382,8 @@
 				goto restart;
 			}
 
-			__unlocked = invalidate_this_page2(mapping, page, curr, head);
+			__unlocked = invalidate_this_page2(mapping,
+						page, curr, head);
 			unlock_page(page);
 			unlocked |= __unlocked;
 			if (!__unlocked) {
@@ -397,15 +401,18 @@
 			wait_on_page_locked(page);
 		}
 
-		page_cache_release(page);
-		if (need_resched()) {
-			__set_current_state(TASK_RUNNING);
-			schedule();
-		}
-
+		if (!pagevec_add(&release_pvec, page))
+			__pagevec_release(&release_pvec);
+		cond_resched();
 		write_lock(&mapping->page_lock);
 		goto restart;
 	}
+	if (pagevec_count(&release_pvec)) {
+		write_unlock(&mapping->page_lock);
+		pagevec_release(&release_pvec);
+		write_lock(&mapping->page_lock);
+		unlocked = 1;
+	}
 	return unlocked;
 }
 
@@ -530,26 +537,37 @@
  * In the case of swapcache, try_to_swap_out() has already locked the page, so
  * SetPageLocked() is ugly-but-OK there too.  The required page state has been
  * set up by swap_out_add_to_swap_cache().
+ *
+ * This function does not add the page to the LRU.  The caller must do that.
  */
 int add_to_page_cache(struct page *page,
-		struct address_space *mapping, unsigned long offset)
+		struct address_space *mapping, pgoff_t offset)
 {
 	int error;
 
+	page_cache_get(page);
 	write_lock(&mapping->page_lock);
 	error = radix_tree_insert(&mapping->page_tree, offset, page);
 	if (!error) {
 		SetPageLocked(page);
 		ClearPageDirty(page);
 		___add_to_page_cache(page, mapping, offset);
-		page_cache_get(page);
+	} else {
+		page_cache_release(page);
 	}
 	write_unlock(&mapping->page_lock);
-	if (!error)
-		lru_cache_add(page);
 	return error;
 }
 
+int add_to_page_cache_lru(struct page *page,
+		struct address_space *mapping, pgoff_t offset)
+{
+	int ret = add_to_page_cache(page, mapping, offset);
+	if (ret == 0)
+		lru_cache_add(page);
+	return ret;
+}
+
 /*
  * This adds the requested page to the page cache if it isn't already there,
  * and schedules an I/O to read in its contents from disk.
@@ -565,7 +583,7 @@
 	if (!page)
 		return -ENOMEM;
 
-	error = add_to_page_cache(page, mapping, offset);
+	error = add_to_page_cache_lru(page, mapping, offset);
 	if (!error) {
 		error = mapping->a_ops->readpage(file, page);
 		page_cache_release(page);
@@ -796,7 +814,7 @@
 			if (!cached_page)
 				return NULL;
 		}
-		err = add_to_page_cache(cached_page, mapping, index);
+		err = add_to_page_cache_lru(cached_page, mapping, index);
 		if (!err) {
 			page = cached_page;
 			cached_page = NULL;
@@ -829,7 +847,7 @@
 		return NULL;
 	}
 	page = alloc_pages(mapping->gfp_mask & ~__GFP_FS, 0);
-	if (page && add_to_page_cache(page, mapping, index)) {
+	if (page && add_to_page_cache_lru(page, mapping, index)) {
 		page_cache_release(page);
 		page = NULL;
 	}
@@ -993,7 +1011,7 @@
 				break;
 			}
 		}
-		error = add_to_page_cache(cached_page, mapping, index);
+		error = add_to_page_cache_lru(cached_page, mapping, index);
 		if (error) {
 			if (error == -EEXIST)
 				goto find_page;
@@ -1109,7 +1127,7 @@
 	return written;
 }
 
-ssize_t generic_file_sendfile(struct file *in_file, struct file *out_file,
+ssize_t generic_file_sendfile(struct file *out_file, struct file *in_file,
 			      loff_t *ppos, size_t count)
 {
 	read_descriptor_t desc;
@@ -1703,7 +1721,7 @@
 			if (!cached_page)
 				return ERR_PTR(-ENOMEM);
 		}
-		err = add_to_page_cache(cached_page, mapping, index);
+		err = add_to_page_cache_lru(cached_page, mapping, index);
 		if (err == -EEXIST)
 			goto repeat;
 		if (err < 0) {
@@ -1763,8 +1781,14 @@
 	return page;
 }
 
-static inline struct page * __grab_cache_page(struct address_space *mapping,
-				unsigned long index, struct page **cached_page)
+/*
+ * If the page was newly created, increment its refcount and add it to the
+ * caller's lru-buffering pagevec.  This function is specifically for
+ * generic_file_write().
+ */
+static inline struct page *
+__grab_cache_page(struct address_space *mapping, unsigned long index,
+			struct page **cached_page, struct pagevec *lru_pvec)
 {
 	int err;
 	struct page *page;
@@ -1781,6 +1805,9 @@
 			goto repeat;
 		if (err == 0) {
 			page = *cached_page;
+			page_cache_get(page);
+			if (!pagevec_add(lru_pvec, page))
+				__pagevec_lru_add(lru_pvec);
 			*cached_page = NULL;
 		}
 	}
@@ -1812,9 +1839,8 @@
  * it for writing by marking it dirty.
  *							okir@monad.swb.de
  */
-ssize_t
-generic_file_write(struct file *file, const char *buf,
-		size_t count, loff_t *ppos)
+ssize_t generic_file_write_nolock(struct file *file, const char *buf,
+				  size_t count, loff_t *ppos)
 {
 	struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
 	struct address_space_operations *a_ops = mapping->a_ops;
@@ -1828,19 +1854,19 @@
 	int		err;
 	unsigned	bytes;
 	time_t		time_now;
+	struct pagevec	lru_pvec;
 
-	if (unlikely((ssize_t) count < 0))
+	if (unlikely((ssize_t)count < 0))
 		return -EINVAL;
 
 	if (unlikely(!access_ok(VERIFY_READ, buf, count)))
 		return -EFAULT;
 
-	down(&inode->i_sem);
 	pos = *ppos;
-	if (unlikely(pos < 0)) {
-		err = -EINVAL;
-		goto out;
-	}
+	if (unlikely(pos < 0))
+		return -EINVAL;
+
+	pagevec_init(&lru_pvec);
 
 	if (unlikely(file->f_error)) {
 		err = file->f_error;
@@ -1975,7 +2001,7 @@
 			__get_user(dummy, buf+bytes-1);
 		}
 
-		page = __grab_cache_page(mapping, index, &cached_page);
+		page = __grab_cache_page(mapping, index, &cached_page, &lru_pvec);
 		if (!page) {
 			status = -ENOMEM;
 			break;
@@ -2037,6 +2063,19 @@
 out_status:	
 	err = written ? written : status;
 out:
+	pagevec_lru_add(&lru_pvec);
+	return err;
+}
+
+ssize_t generic_file_write(struct file *file, const char *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct inode	*inode = file->f_dentry->d_inode->i_mapping->host;
+	int		err;
+
+	down(&inode->i_sem);
+	err = generic_file_write_nolock(file, buf, count, ppos);
 	up(&inode->i_sem);
+
 	return err;
 }
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Tue Aug 27 12:28:05 2002
+++ b/mm/memory.c	Tue Aug 27 12:28:05 2002
@@ -1180,6 +1180,7 @@
 		KERNEL_STAT_INC(pgmajfault);
 	}
 
+	mark_page_accessed(page);
 	lock_page(page);
 
 	/*
@@ -1257,6 +1258,7 @@
 		flush_page_to_ram(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		lru_cache_add(page);
+		mark_page_accessed(page);
 	}
 
 	set_pte(page_table, entry);
diff -Nru a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c	Tue Aug 27 12:27:59 2002
+++ b/mm/mempool.c	Tue Aug 27 12:27:59 2002
@@ -189,7 +189,9 @@
 	int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
 
 repeat_alloc:
+	current->flags |= PF_NOWARN;
 	element = pool->alloc(gfp_nowait, pool->pool_data);
+	current->flags &= ~PF_NOWARN;
 	if (likely(element != NULL))
 		return element;
 
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Tue Aug 27 12:28:01 2002
+++ b/mm/page-writeback.c	Tue Aug 27 12:28:01 2002
@@ -22,6 +22,8 @@
 #include <linux/sysrq.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -34,10 +36,9 @@
 
 /*
  * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
- * will look to see if it needs to force writeback or throttling.  Probably
- * should be scaled by memory size.
+ * will look to see if it needs to force writeback or throttling.
  */
-#define RATELIMIT_PAGES		((512 * 1024) / PAGE_SIZE)
+static int ratelimit_pages = 32;
 
 /*
  * When balance_dirty_pages decides that the caller needs to perform some
@@ -45,8 +46,10 @@
  * It should be somewhat larger than RATELIMIT_PAGES to ensure that reasonably
  * large amounts of I/O are submitted.
  */
-#define SYNC_WRITEBACK_PAGES	((RATELIMIT_PAGES * 3) / 2)
-
+static inline int sync_writeback_pages(void)
+{
+	return ratelimit_pages + ratelimit_pages / 2;
+}
 
 /* The following parameters are exported via /proc/sys/vm */
 
@@ -119,12 +122,12 @@
 	bdi = mapping->backing_dev_info;
 
 	if (dirty_and_writeback > sync_thresh) {
-		int nr_to_write = SYNC_WRITEBACK_PAGES;
+		int nr_to_write = sync_writeback_pages();
 
 		writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_LAST, NULL);
 		get_page_state(&ps);
 	} else if (dirty_and_writeback > async_thresh) {
-		int nr_to_write = SYNC_WRITEBACK_PAGES;
+		int nr_to_write = sync_writeback_pages();
 
 		writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_NONE, NULL);
 		get_page_state(&ps);
@@ -133,6 +136,7 @@
 	if (!writeback_in_progress(bdi) && ps.nr_dirty > background_thresh)
 		pdflush_operation(background_writeout, 0);
 }
+EXPORT_SYMBOL_GPL(balance_dirty_pages);
 
 /**
  * balance_dirty_pages_ratelimited - balance dirty memory state
@@ -152,7 +156,7 @@
 	int cpu;
 
 	cpu = get_cpu();
-	if (ratelimits[cpu].count++ >= RATELIMIT_PAGES) {
+	if (ratelimits[cpu].count++ >= ratelimit_pages) {
 		ratelimits[cpu].count = 0;
 		put_cpu();
 		balance_dirty_pages(mapping);
@@ -246,16 +250,56 @@
 
 }
 
-static int __init wb_timer_init(void)
+/*
+ * If ratelimit_pages is too high then we can get into dirty-data overload
+ * if a large number of processes all perform writes at the same time.
+ * If it is too low then SMP machines will call the (expensive) get_page_state
+ * too often.
+ *
+ * Here we set ratelimit_pages to a level which ensures that when all CPUs are
+ * dirtying in parallel, we cannot go more than 3% (1/32) over the dirty memory
+ * thresholds before writeback cuts in.
+ *
+ * But the limit should not be set too high.  Because it also controls the
+ * amount of memory which the balance_dirty_pages() caller has to write back.
+ * If this is too large then the caller will block on the IO queue all the
+ * time.  So limit it to four megabytes - the balance_dirty_pages() caller
+ * will write six megabyte chunks, max.
+ */
+
+static void set_ratelimit(void)
+{
+	ratelimit_pages = nr_free_pagecache_pages() / (num_online_cpus() * 32);
+	if (ratelimit_pages < 16)
+		ratelimit_pages = 16;
+	if (ratelimit_pages * PAGE_CACHE_SIZE > 4096 * 1024)
+		ratelimit_pages = (4096 * 1024) / PAGE_CACHE_SIZE;
+}
+
+static int
+ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
+{
+	set_ratelimit();
+	return 0;
+}
+
+static struct notifier_block ratelimit_nb = {
+	.notifier_call	= ratelimit_handler,
+	.next		= NULL,
+};
+
+static int __init page_writeback_init(void)
 {
 	init_timer(&wb_timer);
 	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
 	wb_timer.data = 0;
 	wb_timer.function = wb_timer_fn;
 	add_timer(&wb_timer);
+	set_ratelimit();
+	register_cpu_notifier(&ratelimit_nb);
 	return 0;
 }
-module_init(wb_timer_init);
+module_init(page_writeback_init);
 
 /*
  * A library function, which implements the vm_writeback a_op.  It's fairly
@@ -480,3 +524,5 @@
 	return ret;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
+
+
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Tue Aug 27 12:27:59 2002
+++ b/mm/page_alloc.c	Tue Aug 27 12:27:59 2002
@@ -22,6 +22,7 @@
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
+#include <linux/pagevec.h>
 
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
@@ -79,8 +80,7 @@
  * -- wli
  */
 
-static void FASTCALL(__free_pages_ok (struct page *page, unsigned int order));
-static void __free_pages_ok (struct page *page, unsigned int order)
+void __free_pages_ok (struct page *page, unsigned int order)
 {
 	unsigned long index, page_idx, mask, flags;
 	free_area_t *area;
@@ -89,6 +89,7 @@
 
 	KERNEL_STAT_ADD(pgfree, 1<<order);
 
+	BUG_ON(PageLRU(page));
 	BUG_ON(PagePrivate(page));
 	BUG_ON(page->mapping != NULL);
 	BUG_ON(PageLocked(page));
@@ -449,13 +450,12 @@
 	return 0;
 }
 
-void page_cache_release(struct page *page)
+void __pagevec_free(struct pagevec *pvec)
 {
-	if (!PageReserved(page) && put_page_testzero(page)) {
-		if (PageLRU(page))
-			lru_cache_del(page);
-		__free_pages_ok(page, 0);
-	}
+	int i = pagevec_count(pvec);
+
+	while (--i >= 0)
+		__free_pages_ok(pvec->pages[i], 0);
 }
 
 void __free_pages(struct page *page, unsigned int order)
diff -Nru a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c	Tue Aug 27 12:27:59 2002
+++ b/mm/readahead.c	Tue Aug 27 12:27:59 2002
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
+#include <linux/pagevec.h>
 
 struct backing_dev_info default_backing_dev_info = {
 	.ra_pages	= (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
@@ -36,6 +37,9 @@
 		struct list_head *pages, unsigned nr_pages)
 {
 	unsigned page_idx;
+	struct pagevec lru_pvec;
+
+	pagevec_init(&lru_pvec);
 
 	if (mapping->a_ops->readpages)
 		return mapping->a_ops->readpages(mapping, pages, nr_pages);
@@ -43,10 +47,15 @@
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
 		struct page *page = list_entry(pages->prev, struct page, list);
 		list_del(&page->list);
-		if (!add_to_page_cache(page, mapping, page->index))
+		if (!add_to_page_cache(page, mapping, page->index)) {
+			if (!pagevec_add(&lru_pvec, page))
+				__pagevec_lru_add(&lru_pvec);
 			mapping->a_ops->readpage(file, page);
-		page_cache_release(page);
+		} else {
+			page_cache_release(page);
+		}
 	}
+	pagevec_lru_add(&lru_pvec);
 	return 0;
 }
 
diff -Nru a/mm/rmap.c b/mm/rmap.c
--- a/mm/rmap.c	Tue Aug 27 12:28:08 2002
+++ b/mm/rmap.c	Tue Aug 27 12:28:08 2002
@@ -28,7 +28,6 @@
 
 #include <asm/pgalloc.h>
 #include <asm/rmap.h>
-#include <asm/smplock.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
@@ -53,9 +52,45 @@
 };
 
 static kmem_cache_t	*pte_chain_cache;
-static inline struct pte_chain * pte_chain_alloc(void);
-static inline void pte_chain_free(struct pte_chain *, struct pte_chain *,
-		struct page *);
+
+/**
+ * pte_chain_alloc - allocate a pte_chain struct
+ *
+ * Returns a pointer to a fresh pte_chain structure. Allocates new
+ * pte_chain structures as required.
+ * Caller needs to hold the page's pte_chain_lock.
+ */
+static inline struct pte_chain *pte_chain_alloc(void)
+{
+	return kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC);
+}
+
+/**
+ * pte_chain_free - free pte_chain structure
+ * @pte_chain: pte_chain struct to free
+ * @prev_pte_chain: previous pte_chain on the list (may be NULL)
+ * @page: page this pte_chain hangs off (may be NULL)
+ *
+ * This function unlinks pte_chain from the singly linked list it
+ * may be on and adds the pte_chain to the free list. May also be
+ * called for new pte_chain structures which aren't on any list yet.
+ * Caller needs to hold the pte_chain_lock if the page is non-NULL.
+ */
+static inline void pte_chain_free(struct pte_chain * pte_chain,
+		struct pte_chain * prev_pte_chain, struct page * page)
+{
+	if (prev_pte_chain)
+		prev_pte_chain->next = pte_chain->next;
+	else if (page)
+		page->pte.chain = pte_chain->next;
+
+	kmem_cache_free(pte_chain_cache, pte_chain);
+}
+
+
+/**
+ ** VM stuff below this comment
+ **/
 
 /**
  * page_referenced - test if the page was referenced
@@ -328,7 +363,7 @@
 				case SWAP_SUCCESS:
 					/* Free the pte_chain struct. */
 					pte_chain_free(pc, prev_pc, page);
-					break;
+					continue;
 				case SWAP_AGAIN:
 					/* Skip this pte, remembering status. */
 					prev_pc = pc;
@@ -336,12 +371,13 @@
 					continue;
 				case SWAP_FAIL:
 					ret = SWAP_FAIL;
-					break;
+					goto give_up;
 				case SWAP_ERROR:
 					ret = SWAP_ERROR;
-					break;
+					goto give_up;
 			}
 		}
+give_up:
 		/* Check whether we can convert to direct pte pointer */
 		pc = page->pte.chain;
 		if (pc && !pc->next) {
@@ -357,41 +393,6 @@
  ** No more VM stuff below this comment, only pte_chain helper
  ** functions.
  **/
-
-
-/**
- * pte_chain_free - free pte_chain structure
- * @pte_chain: pte_chain struct to free
- * @prev_pte_chain: previous pte_chain on the list (may be NULL)
- * @page: page this pte_chain hangs off (may be NULL)
- *
- * This function unlinks pte_chain from the singly linked list it
- * may be on and adds the pte_chain to the free list. May also be
- * called for new pte_chain structures which aren't on any list yet.
- * Caller needs to hold the pte_chain_lock if the page is non-NULL.
- */
-static inline void pte_chain_free(struct pte_chain * pte_chain,
-		struct pte_chain * prev_pte_chain, struct page * page)
-{
-	if (prev_pte_chain)
-		prev_pte_chain->next = pte_chain->next;
-	else if (page)
-		page->pte.chain = pte_chain->next;
-
-	kmem_cache_free(pte_chain_cache, pte_chain);
-}
-
-/**
- * pte_chain_alloc - allocate a pte_chain struct
- *
- * Returns a pointer to a fresh pte_chain structure. Allocates new
- * pte_chain structures as required.
- * Caller needs to hold the page's pte_chain_lock.
- */
-static inline struct pte_chain *pte_chain_alloc(void)
-{
-	return kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC);
-}
 
 void __init pte_chain_init(void)
 {
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Tue Aug 27 12:28:02 2002
+++ b/mm/shmem.c	Tue Aug 27 12:28:02 2002
@@ -668,7 +668,7 @@
 		page = page_cache_alloc(mapping);
 		if (!page)
 			goto no_mem;
-		error = add_to_page_cache(page, mapping, idx);
+		error = add_to_page_cache_lru(page, mapping, idx);
 		if (error < 0) {
 			page_cache_release(page);
 			goto no_mem;
diff -Nru a/mm/swap.c b/mm/swap.c
--- a/mm/swap.c	Tue Aug 27 12:28:02 2002
+++ b/mm/swap.c	Tue Aug 27 12:28:02 2002
@@ -17,11 +17,9 @@
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/pagevec.h>
 #include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/uaccess.h> /* for copy_to/from_user */
-#include <asm/pgtable.h>
+#include <linux/prefetch.h>
 
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
@@ -38,53 +36,201 @@
 	}
 }
 
+/*
+ * FIXME: speed this up?
+ */
 void activate_page(struct page * page)
 {
-	spin_lock(&pagemap_lru_lock);
+	spin_lock_irq(&_pagemap_lru_lock);
 	activate_page_nolock(page);
-	spin_unlock(&pagemap_lru_lock);
+	spin_unlock_irq(&_pagemap_lru_lock);
 }
 
 /**
  * lru_cache_add: add a page to the page lists
  * @page: the page to add
  */
-void lru_cache_add(struct page * page)
+static struct pagevec lru_add_pvecs[NR_CPUS];
+
+void lru_cache_add(struct page *page)
 {
-	if (!TestSetPageLRU(page)) {
-		spin_lock(&pagemap_lru_lock);
-		add_page_to_inactive_list(page);
-		spin_unlock(&pagemap_lru_lock);
-	}
+	struct pagevec *pvec = &lru_add_pvecs[get_cpu()];
+
+	page_cache_get(page);
+	if (!pagevec_add(pvec, page))
+		__pagevec_lru_add(pvec);
+	put_cpu();
 }
 
-/**
- * __lru_cache_del: remove a page from the page lists
- * @page: the page to add
- *
- * This function is for when the caller already holds
- * the pagemap_lru_lock.
+void lru_add_drain(void)
+{
+	struct pagevec *pvec = &lru_add_pvecs[get_cpu()];
+
+	if (pagevec_count(pvec))
+		__pagevec_lru_add(pvec);
+	put_cpu();
+}
+
+/*
+ * This path almost never happens - pages are normally freed via pagevecs.
  */
-void __lru_cache_del(struct page * page)
+void __page_cache_release(struct page *page)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&_pagemap_lru_lock, flags);
 	if (TestClearPageLRU(page)) {
-		if (PageActive(page)) {
+		if (PageActive(page))
 			del_page_from_active_list(page);
-		} else {
+		else
 			del_page_from_inactive_list(page);
+	}
+	if (page_count(page) != 0)
+		page = NULL;
+	spin_unlock_irqrestore(&_pagemap_lru_lock, flags);
+	if (page)
+		__free_pages_ok(page, 0);
+}
+
+/*
+ * Batched page_cache_release().  Decrement the reference count on all the
+ * pagevec's pages.  If it fell to zero then remove the page from the LRU and
+ * free it.
+ *
+ * Avoid taking pagemap_lru_lock if possible, but if it is taken, retain it
+ * for the remainder of the operation.
+ *
+ * The locking in this function is against shrink_cache(): we recheck the
+ * page count inside the lock to see whether shrink_cache grabbed the page
+ * via the LRU.  If it did, give up: shrink_cache will free it.
+ *
+ * This function reinitialises the caller's pagevec.
+ */
+void __pagevec_release(struct pagevec *pvec)
+{
+	int i;
+	int lock_held = 0;
+	struct pagevec pages_to_free;
+
+	pagevec_init(&pages_to_free);
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		if (PageReserved(page) || !put_page_testzero(page))
+			continue;
+
+		if (!lock_held) {
+			spin_lock_irq(&_pagemap_lru_lock);
+			lock_held = 1;
+		}
+
+		if (TestClearPageLRU(page)) {
+			if (PageActive(page))
+				del_page_from_active_list(page);
+			else
+				del_page_from_inactive_list(page);
 		}
+		if (page_count(page) == 0)
+			pagevec_add(&pages_to_free, page);
 	}
+	if (lock_held)
+		spin_unlock_irq(&_pagemap_lru_lock);
+
+	pagevec_free(&pages_to_free);
+	pagevec_init(pvec);
 }
 
-/**
- * lru_cache_del: remove a page from the page lists
- * @page: the page to remove
+/*
+ * pagevec_release() for pages which are known to not be on the LRU
+ *
+ * This function reinitialises the caller's pagevec.
+ */
+void __pagevec_release_nonlru(struct pagevec *pvec)
+{
+	int i;
+	struct pagevec pages_to_free;
+
+	pagevec_init(&pages_to_free);
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		BUG_ON(PageLRU(page));
+		if (put_page_testzero(page))
+			pagevec_add(&pages_to_free, page);
+	}
+	pagevec_free(&pages_to_free);
+	pagevec_init(pvec);
+}
+
+/*
+ * Move all the inactive pages to the head of the inactive list
+ * and release them.  Reinitialises the caller's pagevec.
  */
-void lru_cache_del(struct page * page)
+void pagevec_deactivate_inactive(struct pagevec *pvec)
 {
-	spin_lock(&pagemap_lru_lock);
-	__lru_cache_del(page);
-	spin_unlock(&pagemap_lru_lock);
+	int i;
+	int lock_held = 0;
+
+	if (pagevec_count(pvec) == 0)
+		return;
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		if (!lock_held) {
+			if (PageActive(page) || !PageLRU(page))
+				continue;
+			spin_lock_irq(&_pagemap_lru_lock);
+			lock_held = 1;
+		}
+		if (!PageActive(page) && PageLRU(page))
+			list_move(&page->lru, &inactive_list);
+	}
+	if (lock_held)
+		spin_unlock_irq(&_pagemap_lru_lock);
+	__pagevec_release(pvec);
+}
+
+/*
+ * Add the passed pages to the inactive_list, then drop the caller's refcount
+ * on them.  Reinitialises the caller's pagevec.
+ */
+void __pagevec_lru_add(struct pagevec *pvec)
+{
+	int i;
+
+	spin_lock_irq(&_pagemap_lru_lock);
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		if (TestSetPageLRU(page))
+			BUG();
+		add_page_to_inactive_list(page);
+	}
+	spin_unlock_irq(&_pagemap_lru_lock);
+	pagevec_release(pvec);
+}
+
+/*
+ * Remove the passed pages from the LRU, then drop the caller's refcount on
+ * them.  Reinitialises the caller's pagevec.
+ */
+void __pagevec_lru_del(struct pagevec *pvec)
+{
+	int i;
+
+	spin_lock_irq(&_pagemap_lru_lock);
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		if (!TestClearPageLRU(page))
+			BUG();
+		if (PageActive(page))
+			del_page_from_active_list(page);
+		else
+			del_page_from_inactive_list(page);
+	}
+	spin_unlock_irq(&_pagemap_lru_lock);
+	pagevec_release(pvec);
 }
 
 /*
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Tue Aug 27 12:28:05 2002
+++ b/mm/swap_state.c	Tue Aug 27 12:28:05 2002
@@ -71,6 +71,9 @@
 		return -ENOENT;
 	}
 	error = add_to_page_cache(page, &swapper_space, entry.val);
+	/*
+	 * Anon pages are already on the LRU, we don't run lru_cache_add here.
+	 */
 	if (error != 0) {
 		swap_free(entry);
 		if (error == -EEXIST)
@@ -275,8 +278,7 @@
 		SetPageDirty(page);
 		___add_to_page_cache(page, mapping, index);
 		/* fix that up */
-		list_del(&page->list);
-		list_add(&page->list, &mapping->dirty_pages);
+		list_move(&page->list, &mapping->dirty_pages);
 		write_unlock(&mapping->page_lock);
 		write_unlock(&swapper_space.page_lock);
 
@@ -381,6 +383,7 @@
 			/*
 			 * Initiate read into locked page and return.
 			 */
+			lru_cache_add(new_page);
 			swap_readpage(NULL, new_page);
 			return new_page;
 		}
diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c
--- a/mm/vmalloc.c	Tue Aug 27 12:27:54 2002
+++ b/mm/vmalloc.c	Tue Aug 27 12:27:54 2002
@@ -4,27 +4,28 @@
  *  Copyright (C) 1993  Linus Torvalds
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
  *  SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
+ *  Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002
  */
 
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
+
 rwlock_t vmlist_lock = RW_LOCK_UNLOCKED;
-struct vm_struct * vmlist;
+struct vm_struct *vmlist;
 
-static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
+static inline void unmap_area_pte(pmd_t *pmd, unsigned long address,
+				  unsigned long size)
 {
-	pte_t * pte;
 	unsigned long end;
+	pte_t *pte;
 
 	if (pmd_none(*pmd))
 		return;
@@ -33,11 +34,13 @@
 		pmd_clear(pmd);
 		return;
 	}
+
 	pte = pte_offset_kernel(pmd, address);
 	address &= ~PMD_MASK;
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+
 	do {
 		pte_t page;
 		page = ptep_get_and_clear(pte);
@@ -45,24 +48,17 @@
 		pte++;
 		if (pte_none(page))
 			continue;
-		if (pte_present(page)) {
-			struct page *ptpage;
-			unsigned long pfn = pte_pfn(page);
-			if (!pfn_valid(pfn))
-				continue;
-			ptpage = pfn_to_page(pfn);
-			if (!PageReserved(ptpage))
-				__free_page(ptpage);
+		if (pte_present(page))
 			continue;
-		}
 		printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
 	} while (address < end);
 }
 
-static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size)
+static inline void unmap_area_pmd(pgd_t *dir, unsigned long address,
+				  unsigned long size)
 {
-	pmd_t * pmd;
 	unsigned long end;
+	pmd_t *pmd;
 
 	if (pgd_none(*dir))
 		return;
@@ -71,36 +67,23 @@
 		pgd_clear(dir);
 		return;
 	}
+
 	pmd = pmd_offset(dir, address);
 	address &= ~PGDIR_MASK;
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+
 	do {
-		free_area_pte(pmd, address, end - address);
+		unmap_area_pte(pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
 }
 
-void vmfree_area_pages(unsigned long start, unsigned long size)
-{
-	pgd_t * dir;
-	unsigned long address = start;
-	unsigned long end = start + size;
-
-	dir = pgd_offset_k(address);
-	flush_cache_all();
-	do {
-		free_area_pmd(dir, address, end - address);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	flush_tlb_kernel_range(start, end);
-}
-
-static inline int alloc_area_pte (pte_t * pte, unsigned long address,
-			unsigned long size, int gfp_mask, pgprot_t prot)
+static inline int map_area_pte(pte_t *pte, unsigned long address,
+			       unsigned long size, pgprot_t prot,
+			       struct page ***pages)
 {
 	unsigned long end;
 
@@ -108,23 +91,26 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+
 	do {
-		struct page * page;
-		spin_unlock(&init_mm.page_table_lock);
-		page = alloc_page(gfp_mask);
-		spin_lock(&init_mm.page_table_lock);
+		struct page *page = **pages;
+
 		if (!pte_none(*pte))
 			printk(KERN_ERR "alloc_area_pte: page already exists\n");
 		if (!page)
 			return -ENOMEM;
+
 		set_pte(pte, mk_pte(page, prot));
 		address += PAGE_SIZE;
 		pte++;
+		(*pages)++;
 	} while (address < end);
 	return 0;
 }
 
-static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot)
+static inline int map_area_pmd(pmd_t *pmd, unsigned long address,
+			       unsigned long size, pgprot_t prot,
+			       struct page ***pages)
 {
 	unsigned long end;
 
@@ -132,76 +118,113 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+
 	do {
 		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		if (alloc_area_pte(pte, address, end - address, gfp_mask, prot))
+		if (map_area_pte(pte, address, end - address, prot, pages))
 			return -ENOMEM;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
+
 	return 0;
 }
 
-inline int vmalloc_area_pages (unsigned long address, unsigned long size,
-                               int gfp_mask, pgprot_t prot)
+void unmap_vm_area(struct vm_struct *area)
 {
-	pgd_t * dir;
-	unsigned long end = address + size;
-	int ret;
+	unsigned long address = VMALLOC_VMADDR(area->addr);
+	unsigned long end = (address + area->size);
+	pgd_t *dir;
+
+	dir = pgd_offset_k(address);
+	flush_cache_all();
+	do {
+		unmap_area_pmd(dir, address, end - address);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	flush_tlb_kernel_range(VMALLOC_VMADDR(area->addr), end);
+}
+
+int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
+{
+	unsigned long address = VMALLOC_VMADDR(area->addr);
+	unsigned long end = address + (area->size-PAGE_SIZE);
+	pgd_t *dir;
+	int err = 0;
 
 	dir = pgd_offset_k(address);
 	spin_lock(&init_mm.page_table_lock);
 	do {
-		pmd_t *pmd;
-		
-		pmd = pmd_alloc(&init_mm, dir, address);
-		ret = -ENOMEM;
-		if (!pmd)
+		pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
+		if (!pmd) {
+			err = -ENOMEM;
 			break;
-
-		ret = -ENOMEM;
-		if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
+		}
+		if (map_area_pmd(pmd, address, end - address, prot, pages)) {
+			err = -ENOMEM;
 			break;
+		}
 
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-
-		ret = 0;
 	} while (address && (address < end));
+
 	spin_unlock(&init_mm.page_table_lock);
 	flush_cache_all();
-	return ret;
+	return err;
 }
 
-struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
+
+/**
+ *	get_vm_area  -  reserve a contingous kernel virtual area
+ *
+ *	@size:		size of the area
+ *	@flags:		%VM_IOREMAP for I/O mappings or VM_ALLOC
+ *
+ *	Search an area of @size in the kernel virtual mapping area,
+ *	and reserved it for out purposes.  Returns the area descriptor
+ *	on success or %NULL on failure.
+ */
+struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
-	unsigned long addr;
 	struct vm_struct **p, *tmp, *area;
+	unsigned long addr = VMALLOC_START;
 
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area)
+	area = kmalloc(sizeof(*area), GFP_KERNEL);
+	if (unlikely(!area))
 		return NULL;
+
+	/*
+	 * We always allocate a guard page.
+	 */
 	size += PAGE_SIZE;
-	addr = VMALLOC_START;
+
 	write_lock(&vmlist_lock);
-	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+	for (p = &vmlist; (tmp = *p) ;p = &tmp->next) {
 		if ((size + addr) < addr)
 			goto out;
-		if (size + addr <= (unsigned long) tmp->addr)
-			break;
-		addr = tmp->size + (unsigned long) tmp->addr;
+		if (size + addr <= (unsigned long)tmp->addr)
+			goto found;
+		addr = tmp->size + (unsigned long)tmp->addr;
 		if (addr > VMALLOC_END-size)
 			goto out;
 	}
-	area->phys_addr = 0;
+
+found:
+	area->next = *p;
+	*p = area;
+
 	area->flags = flags;
 	area->addr = (void *)addr;
 	area->size = size;
-	area->next = *p;
-	*p = area;
+	area->pages = NULL;
+	area->nr_pages = 0;
+	area->phys_addr = 0;
 	write_unlock(&vmlist_lock);
+
 	return area;
 
 out:
@@ -210,87 +233,209 @@
 	return NULL;
 }
 
-struct vm_struct *remove_kernel_area(void *addr) 
+/**
+ *	remove_vm_area  -  find and remove a contingous kernel virtual area
+ *
+ *	@addr:		base address
+ *
+ *	Search for the kernel VM area starting at @addr, and remove it.
+ *	This function returns the found VM area, but using it is NOT safe
+ *	on SMP machines.
+ */
+struct vm_struct *remove_vm_area(void *addr)
 {
 	struct vm_struct **p, *tmp;
-	write_lock(&vmlist_lock);
-	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
-		if (tmp->addr == addr) {
-			*p = tmp->next;
-			write_unlock(&vmlist_lock);
-			return tmp;
-		}
 
+	write_lock(&vmlist_lock);
+	for (p = &vmlist ; (tmp = *p) ;p = &tmp->next) {
+		 if (tmp->addr == addr)
+			 goto found;
 	}
 	write_unlock(&vmlist_lock);
 	return NULL;
-} 
 
-void vfree(void * addr)
+found:
+	*p = tmp->next;
+	write_unlock(&vmlist_lock);
+	return tmp;
+}
+
+void __vunmap(void *addr, int deallocate_pages)
 {
-	struct vm_struct *tmp;
+	struct vm_struct *area;
 
 	if (!addr)
 		return;
-	if ((PAGE_SIZE-1) & (unsigned long) addr) {
+
+	if ((PAGE_SIZE-1) & (unsigned long)addr) {
 		printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
 		return;
 	}
-	tmp = remove_kernel_area(addr); 
-	if (tmp) { 
-			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
-			kfree(tmp);
-			return;
+
+	area = remove_vm_area(addr);
+	if (unlikely(!area)) {
+		printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
+				addr);
+		return;
+	}
+
+	unmap_vm_area(area);
+	
+	if (deallocate_pages) {
+		int i;
+
+		for (i = 0; i < area->nr_pages; i++) {
+			if (unlikely(!area->pages[i]))
+				BUG();
+			__free_page(area->pages[i]);
 		}
-	printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
+
+		kfree(area->pages);
+	}
+
+	kfree(area);
+	return;
 }
 
-/*
- *	Allocate any pages
+/**
+ *	vfree  -  release memory allocated by vmalloc()
+ *
+ *	@addr:		memory base address
+ *
+ *	Free the virtually continguos memory area starting at @addr, as
+ *	obtained from vmalloc(), vmalloc_32() or __vmalloc().
+ *
+ *	May not be called in interrupt context.
  */
-
-void * vmalloc (unsigned long size)
+void vfree(void *addr)
 {
-	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+	__vunmap(addr, 1);
 }
 
-/*
- *	Allocate ISA addressable pages for broke crap
+/**
+ *	vunmap  -  release virtual mapping obtained by vmap()
+ *
+ *	@addr:		memory base address
+ *
+ *	Free the virtually continguos memory area starting at @addr,
+ *	which was created from the page array passed to vmap().
+ *
+ *	May not be called in interrupt context.
  */
-
-void * vmalloc_dma (unsigned long size)
+void vunmap(void *addr)
 {
-	return __vmalloc(size, GFP_KERNEL|GFP_DMA, PAGE_KERNEL);
+	__vunmap(addr, 0);
 }
 
-/*
- *	vmalloc 32bit PA addressable pages - eg for PCI 32bit devices
+/**
+ *	vmap  -  map an array of pages into virtually continguos space
+ *
+ *	@pages:		array of page pointers
+ *	@count:		number of pages to map
+ *
+ *	Maps @count pages from @pages into continguos kernel virtual
+ *	space.
  */
-
-void * vmalloc_32(unsigned long size)
+void *vmap(struct page **pages, unsigned int count)
 {
-	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
+	struct vm_struct *area;
+
+	if (count > num_physpages)
+		return NULL;
+
+	area = get_vm_area((count << PAGE_SHIFT), VM_MAP);
+	if (!area)
+		return NULL;
+	if (map_vm_area(area, PAGE_KERNEL, &pages)) {
+		vunmap(area->addr);
+		return NULL;
+	}
+
+	return area->addr;
 }
 
-void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot)
+/**
+ *	__vmalloc  -  allocate virtually continguos memory
+ *
+ *	@size:		allocation size
+ *	@gfp_mask:	flags for the page level allocator
+ *	@prot:		protection mask for the allocated pages
+ *
+ *	Allocate enough pages to cover @size from the page level
+ *	allocator with @gfp_mask flags.  Map them into continguos
+ *	kernel virtual space, using a pagetable protection of @prot.
+ */
+void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot)
 {
-	void * addr;
 	struct vm_struct *area;
+	struct page **pages;
+	unsigned int nr_pages, array_size, i;
 
 	size = PAGE_ALIGN(size);
-	if (!size || (size >> PAGE_SHIFT) > num_physpages) {
-		BUG();
+	if (!size || (size >> PAGE_SHIFT) > num_physpages)
 		return NULL;
-	}
+
 	area = get_vm_area(size, VM_ALLOC);
 	if (!area)
 		return NULL;
-	addr = area->addr;
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) {
-		vfree(addr);
+
+	nr_pages = (size+PAGE_SIZE) >> PAGE_SHIFT;
+	array_size = (nr_pages * sizeof(struct page *));
+
+	area->nr_pages = nr_pages;
+	area->pages = pages = kmalloc(array_size, (gfp_mask & ~__GFP_HIGHMEM));
+	if (!area->pages) {
+		remove_vm_area(area->addr);
+		kfree(area);
 		return NULL;
 	}
-	return addr;
+	memset(area->pages, 0, array_size);
+
+	for (i = 0; i < area->nr_pages; i++) {
+		area->pages[i] = alloc_page(gfp_mask);
+		if (unlikely(!area->pages[i])) {
+			/* Successfully allocated i pages, free them in __vunmap() */
+			area->nr_pages = i;
+			goto fail;
+		}
+	}
+	
+	if (map_vm_area(area, prot, &pages))
+		goto fail;
+	return area->addr;
+
+fail:
+	vfree(area->addr);
+	return NULL;
+}
+
+/**
+ *	vmalloc  -  allocate virtually continguos memory
+ *
+ *	@size:		allocation size
+ *
+ *	Allocate enough pages to cover @size from the page level
+ *	allocator and map them into continguos kernel virtual space.
+ *
+ *	For tight cotrol over page level allocator and protection flags
+ *	use __vmalloc() instead.
+ */
+void *vmalloc(unsigned long size)
+{
+       return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+/**
+ *	vmalloc_32  -  allocate virtually continguos memory (32bit addressable)
+ *
+ *	@size:		allocation size
+ *
+ *	Allocate enough 32bit PA addressable pages to cover @size from the
+ *	page level allocator and map them into continguos kernel virtual space.
+ */
+void *vmalloc_32(unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
 }
 
 long vread(char *buf, char *addr, unsigned long count)
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Tue Aug 27 12:28:01 2002
+++ b/mm/vmscan.c	Tue Aug 27 12:28:01 2002
@@ -23,6 +23,7 @@
 #include <linux/writeback.h>
 #include <linux/suspend.h>
 #include <linux/buffer_head.h>		/* for try_to_release_page() */
+#include <linux/pagevec.h>
 
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -36,10 +37,35 @@
  */
 #define DEF_PRIORITY (6)
 
-static inline int is_page_cache_freeable(struct page * page)
-{
-	return page_count(page) - !!PagePrivate(page) == 1;
-}
+#ifdef ARCH_HAS_PREFETCH
+#define prefetch_prev_lru_page(_page, _base, _field)			\
+	do {								\
+		if ((_page)->lru.prev != _base) {			\
+			struct page *prev;				\
+									\
+			prev = list_entry(_page->lru.prev,		\
+					struct page, lru);		\
+			prefetch(&prev->_field);			\
+		}							\
+	} while (0)
+#else
+#define prefetch_prev_lru_page(_page, _base, _field) do { } while (0)
+#endif
+
+#ifdef ARCH_HAS_PREFETCHW
+#define prefetchw_prev_lru_page(_page, _base, _field)			\
+	do {								\
+		if ((_page)->lru.prev != _base) {			\
+			struct page *prev;				\
+									\
+			prev = list_entry(_page->lru.prev,		\
+					struct page, lru);		\
+			prefetchw(&prev->_field);			\
+		}							\
+	} while (0)
+#else
+#define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0)
+#endif
 
 /* Must be called with page's pte_chain_lock held. */
 static inline int page_mapping_inuse(struct page * page)
@@ -61,110 +87,63 @@
 	return 0;
 }
 
-static int
-shrink_cache(int nr_pages, zone_t *classzone,
-		unsigned int gfp_mask, int priority, int max_scan)
+static inline int is_page_cache_freeable(struct page *page)
+{
+	return page_count(page) - !!PagePrivate(page) == 2;
+}
+
+static /* inline */ int
+shrink_list(struct list_head *page_list, int nr_pages, zone_t *classzone,
+		unsigned int gfp_mask, int priority, int *max_scan)
 {
-	struct list_head * entry;
 	struct address_space *mapping;
+	LIST_HEAD(ret_pages);
+	struct pagevec freed_pvec;
+	const int nr_pages_in = nr_pages;
+	int pgactivate = 0;
 
-	spin_lock(&pagemap_lru_lock);
-	while (--max_scan >= 0 &&
-			(entry = inactive_list.prev) != &inactive_list) {
+	pagevec_init(&freed_pvec);
+	while (!list_empty(page_list)) {
 		struct page *page;
 		int may_enter_fs;
 
-		if (need_resched()) {
-			spin_unlock(&pagemap_lru_lock);
-			__set_current_state(TASK_RUNNING);
-			schedule();
-			spin_lock(&pagemap_lru_lock);
-			continue;
-		}
-
-		page = list_entry(entry, struct page, lru);
-
-		if (unlikely(!PageLRU(page)))
-			BUG();
-		if (unlikely(PageActive(page)))
-			BUG();
-
-		list_del(entry);
-		list_add(entry, &inactive_list);
-		KERNEL_STAT_INC(pgscan);
-
-		/*
-		 * Zero page counts can happen because we unlink the pages
-		 * _after_ decrementing the usage count..
-		 */
-		if (unlikely(!page_count(page)))
-			continue;
-
+		page = list_entry(page_list->prev, struct page, lru);
+		list_del(&page->lru);
 		if (!memclass(page_zone(page), classzone))
-			continue;
-
-		/*
-		 * swap activity never enters the filesystem and is safe
-		 * for GFP_NOFS allocations.
-		 */
-		may_enter_fs = (gfp_mask & __GFP_FS) ||
-				(PageSwapCache(page) && (gfp_mask & __GFP_IO));
-
-		/*
-		 * IO in progress? Leave it at the back of the list.
-		 */
-		if (unlikely(PageWriteback(page))) {
-			if (may_enter_fs) {
-				page_cache_get(page);
-				spin_unlock(&pagemap_lru_lock);
-				wait_on_page_writeback(page);
-				page_cache_release(page);
-				spin_lock(&pagemap_lru_lock);
-			}
-			continue;
-		}
+			goto keep;
 
 		if (TestSetPageLocked(page))
-			continue;
+			goto keep;
 
-		if (PageWriteback(page)) {	/* The non-racy check */
-			unlock_page(page);
-			continue;
+		BUG_ON(PageActive(page));
+		may_enter_fs = (gfp_mask & __GFP_FS) ||
+				(PageSwapCache(page) && (gfp_mask & __GFP_IO));
+		if (PageWriteback(page)) {
+			if (may_enter_fs)
+				wait_on_page_writeback(page);  /* throttling */
+			else
+				goto keep_locked;
 		}
 
-		/*
-		 * The page is in active use or really unfreeable. Move to
-		 * the active list.
-		 */
 		pte_chain_lock(page);
 		if (page_referenced(page) && page_mapping_inuse(page)) {
-			del_page_from_inactive_list(page);
-			add_page_to_active_list(page);
+			/* In active use or really unfreeable.  Activate it. */
 			pte_chain_unlock(page);
-			unlock_page(page);
-			KERNEL_STAT_INC(pgactivate);
-			continue;
+			goto activate_locked;
 		}
 
+		mapping = page->mapping;
+
 		/*
 		 * Anonymous process memory without backing store. Try to
 		 * allocate it some swap space here.
 		 *
 		 * XXX: implement swap clustering ?
 		 */
-		if (page->pte.chain && !page->mapping && !PagePrivate(page)) {
-			page_cache_get(page);
+		if (page->pte.chain && !mapping && !PagePrivate(page)) {
 			pte_chain_unlock(page);
-			spin_unlock(&pagemap_lru_lock);
-			if (!add_to_swap(page)) {
-				activate_page(page);
-				unlock_page(page);
-				page_cache_release(page);
-				spin_lock(&pagemap_lru_lock);
-				continue;
-			}
-			page_cache_release(page);
-			spin_lock(&pagemap_lru_lock);
+			if (!add_to_swap(page))
+				goto activate_locked;
 			pte_chain_lock(page);
 		}
 
@@ -172,32 +151,29 @@
 		 * The page is mapped into the page tables of one or more
 		 * processes. Try to unmap it here.
 		 */
-		if (page->pte.chain) {
+		if (page->pte.chain && mapping) {
 			switch (try_to_unmap(page)) {
-				case SWAP_ERROR:
-				case SWAP_FAIL:
-					goto page_active;
-				case SWAP_AGAIN:
-					pte_chain_unlock(page);
-					unlock_page(page);
-					continue;
-				case SWAP_SUCCESS:
-					; /* try to free the page below */
+			case SWAP_ERROR:
+			case SWAP_FAIL:
+				pte_chain_unlock(page);
+				goto activate_locked;
+			case SWAP_AGAIN:
+				pte_chain_unlock(page);
+				goto keep_locked;
+			case SWAP_SUCCESS:
+				; /* try to free the page below */
 			}
 		}
 		pte_chain_unlock(page);
-		mapping = page->mapping;
 
+		/*
+		 * FIXME: this is CPU-inefficient for shared mappings.
+		 * try_to_unmap() will set the page dirty and ->vm_writeback
+		 * will write it.  So we're back to page-at-a-time writepage
+		 * in LRU order.
+		 */
 		if (PageDirty(page) && is_page_cache_freeable(page) &&
-				page->mapping && may_enter_fs) {
-			/*
-			 * It is not critical here to write it only if
-			 * the page is unmapped beause any direct writer
-			 * like O_DIRECT would set the page's dirty bitflag
-			 * on the physical page after having successfully
-			 * pinned it and after the I/O to the page is finished,
-			 * so the direct writes to the page cannot get lost.
-			 */
+					mapping && may_enter_fs) {
 			int (*writeback)(struct page *, int *);
 			const int cluster_size = SWAP_CLUSTER_MAX;
 			int nr_to_write = cluster_size;
@@ -205,13 +181,9 @@
 			writeback = mapping->a_ops->vm_writeback;
 			if (writeback == NULL)
 				writeback = generic_vm_writeback;
-			page_cache_get(page);
-			spin_unlock(&pagemap_lru_lock);
 			(*writeback)(page, &nr_to_write);
-			max_scan -= (cluster_size - nr_to_write);
-			page_cache_release(page);
-			spin_lock(&pagemap_lru_lock);
-			continue;
+			*max_scan -= (cluster_size - nr_to_write);
+			goto keep;
 		}
 
 		/*
@@ -227,162 +199,298 @@
 		 * will do this, as well as the blockdev mapping. 
 		 * try_to_release_page() will discover that cleanness and will
 		 * drop the buffers and mark the page clean - it can be freed.
+		 *
+		 * Rarely, pages can have buffers and no ->mapping.  These are
+		 * the pages which were not successfully invalidated in
+		 * truncate_complete_page().  We try to drop those buffers here
+		 * and if that worked, and the page is no longer mapped into
+		 * process address space (page_count == 0) it can be freed.
+		 * Otherwise, leave the page on the LRU so it is swappable.
 		 */
 		if (PagePrivate(page)) {
-			spin_unlock(&pagemap_lru_lock);
-
-			/* avoid to free a locked page */
-			page_cache_get(page);
+			if (!try_to_release_page(page, 0))
+				goto keep_locked;
+			if (!mapping && page_count(page) == 1)
+				goto free_it;
+		}
 
-			if (try_to_release_page(page, gfp_mask)) {
-				if (!mapping) {
-					/* effectively free the page here */
-					unlock_page(page);
-					page_cache_release(page);
-
-					spin_lock(&pagemap_lru_lock);
-					if (--nr_pages)
-						continue;
-					break;
-				} else {
-					/*
-					 * The page is still in pagecache so undo the stuff
-					 * before the try_to_release_page since we've not
-					 * finished and we can now try the next step.
-					 */
-					page_cache_release(page);
-
-					spin_lock(&pagemap_lru_lock);
-				}
-			} else {
-				/* failed to drop the buffers so stop here */
-				unlock_page(page);
-				page_cache_release(page);
+		if (!mapping)
+			goto keep_locked;	/* truncate got there first */
 
-				spin_lock(&pagemap_lru_lock);
-				continue;
-			}
-		}
+		write_lock(&mapping->page_lock);
 
 		/*
-		 * This is the non-racy check for busy page.
+		 * The non-racy check for busy page.  It is critical to check
+		 * PageDirty _after_ making sure that the page is freeable and
+		 * not in use by anybody. 	(pagecache + us == 2)
 		 */
-		if (mapping) {
-			write_lock(&mapping->page_lock);
-			if (is_page_cache_freeable(page))
-				goto page_freeable;
+		if (page_count(page) != 2 || PageDirty(page)) {
 			write_unlock(&mapping->page_lock);
-		}
-		unlock_page(page);
-		continue;
-page_freeable:
-		/*
-		 * It is critical to check PageDirty _after_ we made sure
-		 * the page is freeable* so not in use by anybody.
-		 */
-		if (PageDirty(page)) {
-			write_unlock(&mapping->page_lock);
-			unlock_page(page);
-			continue;
+			goto keep_locked;
 		}
 
-		/* point of no return */
-		if (likely(!PageSwapCache(page))) {
-			__remove_from_page_cache(page);
-			write_unlock(&mapping->page_lock);
-		} else {
-			swp_entry_t swap;
-			swap.val = page->index;
+		if (PageSwapCache(page)) {
+			swp_entry_t swap = { .val = page->index };
 			__delete_from_swap_cache(page);
 			write_unlock(&mapping->page_lock);
 			swap_free(swap);
+		} else {
+			__remove_from_page_cache(page);
+			write_unlock(&mapping->page_lock);
 		}
-
-		__lru_cache_del(page);
+		__put_page(page);	/* The pagecache ref */
+free_it:
 		unlock_page(page);
+		nr_pages--;
+		if (!pagevec_add(&freed_pvec, page))
+			__pagevec_release_nonlru(&freed_pvec);
+		continue;
 
-		/* effectively free the page here */
-		page_cache_release(page);
-		KERNEL_STAT_INC(pgsteal);
-		if (--nr_pages)
-			continue;
-		goto out;
-page_active:
-		/*
-		 * OK, we don't know what to do with the page.
-		 * It's no use keeping it here, so we move it to
-		 * the active list.
-		 */
-		del_page_from_inactive_list(page);
-		add_page_to_active_list(page);
-		pte_chain_unlock(page);
+activate_locked:
+		SetPageActive(page);
+		pgactivate++;
+keep_locked:
 		unlock_page(page);
-		KERNEL_STAT_INC(pgactivate);
+keep:
+		list_add(&page->lru, &ret_pages);
+		BUG_ON(PageLRU(page));
 	}
-out:	spin_unlock(&pagemap_lru_lock);
+	list_splice(&ret_pages, page_list);
+	if (pagevec_count(&freed_pvec))
+		__pagevec_release_nonlru(&freed_pvec);
+	KERNEL_STAT_ADD(pgsteal, nr_pages_in - nr_pages);
+	KERNEL_STAT_ADD(pgactivate, pgactivate);
 	return nr_pages;
 }
 
 /*
- * This moves pages from the active list to
- * the inactive list.
+ * pagemap_lru_lock is heavily contented.  We relieve it by quickly privatising
+ * a batch of pages and working on them outside the lock.  Any pages which were
+ * not freed will be added back to the LRU.
+ *
+ * shrink_cache() is passed the number of pages to try to free, and returns
+ * the number which are yet-to-free.
  *
- * We move them the other way if the page is 
- * referenced by one or more processes, from rmap
+ * For pagecache intensive workloads, the first loop here is the hottest spot
+ * in the kernel (apart from the copy_*_user functions).
  */
-static void refill_inactive(int nr_pages)
+static /* inline */ int
+shrink_cache(int nr_pages, zone_t *classzone,
+		unsigned int gfp_mask, int priority, int max_scan)
 {
-	struct list_head * entry;
+	LIST_HEAD(page_list);
+	struct pagevec pvec;
+	int nr_to_process;
+
+	/*
+	 * Try to ensure that we free `nr_pages' pages in one pass of the loop.
+	 */
+	nr_to_process = nr_pages;
+	if (nr_to_process < SWAP_CLUSTER_MAX)
+		nr_to_process = SWAP_CLUSTER_MAX;
+
+	pagevec_init(&pvec);
+
+	lru_add_drain();
+	spin_lock_irq(&_pagemap_lru_lock);
+	while (max_scan > 0 && nr_pages > 0) {
+		struct page *page;
+		int n = 0;
 
-	spin_lock(&pagemap_lru_lock);
-	entry = active_list.prev;
-	while (nr_pages-- && entry != &active_list) {
-		struct page * page;
+		while (n < nr_to_process && !list_empty(&inactive_list)) {
+			page = list_entry(inactive_list.prev, struct page, lru);
 
-		page = list_entry(entry, struct page, lru);
-		entry = entry->prev;
+			prefetchw_prev_lru_page(page, &inactive_list, flags);
 
-		KERNEL_STAT_INC(pgscan);
+			if (!TestClearPageLRU(page))
+				BUG();
+			list_del(&page->lru);
+			if (page_count(page) == 0) {
+				/* It is currently in pagevec_release() */
+				SetPageLRU(page);
+				list_add(&page->lru, &inactive_list);
+				continue;
+			}
+			list_add(&page->lru, &page_list);
+			page_cache_get(page);
+			n++;
+		}
+		spin_unlock_irq(&_pagemap_lru_lock);
 
-		pte_chain_lock(page);
-		if (page->pte.chain && page_referenced(page)) {
+		if (list_empty(&page_list))
+			goto done;
+
+		max_scan -= n;
+		mod_page_state(nr_inactive, -n);
+		KERNEL_STAT_ADD(pgscan, n);
+		nr_pages = shrink_list(&page_list, nr_pages, classzone,
+					gfp_mask, priority, &max_scan);
+
+		if (nr_pages <= 0 && list_empty(&page_list))
+			goto done;
+
+		spin_lock_irq(&_pagemap_lru_lock);
+		/*
+		 * Put back any unfreeable pages.
+		 */
+		while (!list_empty(&page_list)) {
+			page = list_entry(page_list.prev, struct page, lru);
+			if (TestSetPageLRU(page))
+				BUG();
 			list_del(&page->lru);
+			if (PageActive(page))
+				__add_page_to_active_list(page);
+			else
+				add_page_to_inactive_list(page);
+			if (!pagevec_add(&pvec, page)) {
+				spin_unlock_irq(&_pagemap_lru_lock);
+				__pagevec_release(&pvec);
+				spin_lock_irq(&_pagemap_lru_lock);
+			}
+		}
+  	}
+	spin_unlock_irq(&_pagemap_lru_lock);
+done:
+	pagevec_release(&pvec);
+	return nr_pages;	
+}
+
+/*
+ * This moves pages from the active list to the inactive list.
+ *
+ * We move them the other way if the page is referenced by one or more
+ * processes, from rmap.
+ *
+ * If the pages are mostly unmapped, the processing is fast and it is
+ * appropriate to hold pagemap_lru_lock across the whole operation.  But if
+ * the pages are mapped, the processing is slow (page_referenced()) so we
+ * should drop pagemap_lru_lock around each page.  It's impossible to balance
+ * this, so instead we remove the pages from the LRU while processing them.
+ * It is safe to rely on PG_active against the non-LRU pages in here because
+ * nobody will play with that bit on a non-LRU page.
+ *
+ * The downside is that we have to touch page->count against each page.
+ * But we had to alter page->flags anyway.
+ */
+static /* inline */ void refill_inactive(const int nr_pages_in)
+{
+	int pgdeactivate = 0;
+	int nr_pages = nr_pages_in;
+	LIST_HEAD(l_hold);	/* The pages which were snipped off */
+	LIST_HEAD(l_inactive);	/* Pages to go onto the inactive_list */
+	LIST_HEAD(l_active);	/* Pages to go onto the active_list */
+	struct page *page;
+	struct pagevec pvec;
+
+	lru_add_drain();
+	spin_lock_irq(&_pagemap_lru_lock);
+	while (nr_pages && !list_empty(&active_list)) {
+		page = list_entry(active_list.prev, struct page, lru);
+		prefetchw_prev_lru_page(page, &active_list, flags);
+		if (!TestClearPageLRU(page))
+			BUG();
+		list_del(&page->lru);
+		if (page_count(page) == 0) {
+			/* It is currently in pagevec_release() */
+			SetPageLRU(page);
 			list_add(&page->lru, &active_list);
-			pte_chain_unlock(page);
 			continue;
 		}
-		del_page_from_active_list(page);
-		add_page_to_inactive_list(page);
-		pte_chain_unlock(page);
-		KERNEL_STAT_INC(pgdeactivate);
+		page_cache_get(page);
+		list_add(&page->lru, &l_hold);
+		nr_pages--;
+	}
+	spin_unlock_irq(&_pagemap_lru_lock);
+
+	while (!list_empty(&l_hold)) {
+		page = list_entry(l_hold.prev, struct page, lru);
+		list_del(&page->lru);
+		if (page->pte.chain) {
+			pte_chain_lock(page);
+			if (page->pte.chain && page_referenced(page)) {
+				pte_chain_unlock(page);
+				list_add(&page->lru, &l_active);
+				continue;
+			}
+			pte_chain_unlock(page);
+		}
+		list_add(&page->lru, &l_inactive);
+		pgdeactivate++;
+	}
+
+	pagevec_init(&pvec);
+	spin_lock_irq(&_pagemap_lru_lock);
+	while (!list_empty(&l_inactive)) {
+		page = list_entry(l_inactive.prev, struct page, lru);
+		prefetchw_prev_lru_page(page, &l_inactive, flags);
+		if (TestSetPageLRU(page))
+			BUG();
+		if (!TestClearPageActive(page))
+			BUG();
+		list_move(&page->lru, &inactive_list);
+		if (!pagevec_add(&pvec, page)) {
+			spin_unlock_irq(&_pagemap_lru_lock);
+			__pagevec_release(&pvec);
+			spin_lock_irq(&_pagemap_lru_lock);
+		}
+	}
+	while (!list_empty(&l_active)) {
+		page = list_entry(l_active.prev, struct page, lru);
+		prefetchw_prev_lru_page(page, &l_active, flags);
+		if (TestSetPageLRU(page))
+			BUG();
+		BUG_ON(!PageActive(page));
+		list_move(&page->lru, &active_list);
+		if (!pagevec_add(&pvec, page)) {
+			spin_unlock_irq(&_pagemap_lru_lock);
+			__pagevec_release(&pvec);
+			spin_lock_irq(&_pagemap_lru_lock);
+		}
 	}
-	spin_unlock(&pagemap_lru_lock);
+	spin_unlock_irq(&_pagemap_lru_lock);
+	pagevec_release(&pvec);
+
+	mod_page_state(nr_active, -pgdeactivate);
+	mod_page_state(nr_inactive, pgdeactivate);
+	KERNEL_STAT_ADD(pgscan, nr_pages_in - nr_pages);
+	KERNEL_STAT_ADD(pgdeactivate, pgdeactivate);
 }
 
-static int FASTCALL(shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages));
-static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages)
+static /* inline */ int
+shrink_caches(zone_t *classzone, int priority,
+		unsigned int gfp_mask, int nr_pages)
 {
-	int chunk_size = nr_pages;
 	unsigned long ratio;
 	struct page_state ps;
 	int max_scan;
+	static atomic_t nr_to_refill = ATOMIC_INIT(0);
 
-	nr_pages -= kmem_cache_reap(gfp_mask);
-	if (nr_pages <= 0)
-		return 0;
-
-	nr_pages = chunk_size;
+	if (kmem_cache_reap(gfp_mask) >= nr_pages)
+  		return 0;
 
 	/*
-	 * Try to keep the active list 2/3 of the size of the cache
+	 * Try to keep the active list 2/3 of the size of the cache.  And
+	 * make sure that refill_inactive is given a decent number of pages.
+	 *
+	 * The "ratio+1" here is important.  With pagecache-intensive workloads
+	 * the inactive list is huge, and `ratio' evaluates to zero all the
+	 * time.  Which pins the active list memory.  So we add one to `ratio'
+	 * just to make sure that the kernel will slowly sift through the
+	 * active list.
 	 */
 	get_page_state(&ps);
 	ratio = (unsigned long)nr_pages * ps.nr_active /
 				((ps.nr_inactive | 1) * 2);
-	refill_inactive(ratio);
+	atomic_add(ratio+1, &nr_to_refill);
+	if (atomic_read(&nr_to_refill) > SWAP_CLUSTER_MAX) {
+		atomic_sub(SWAP_CLUSTER_MAX, &nr_to_refill);
+		refill_inactive(SWAP_CLUSTER_MAX);
+	}
+
 	max_scan = ps.nr_inactive / priority;
 	nr_pages = shrink_cache(nr_pages, classzone,
 				gfp_mask, priority, max_scan);
+
 	if (nr_pages <= 0)
 		return 0;
 
diff -Nru a/net/802/p8022.c b/net/802/p8022.c
--- a/net/802/p8022.c	Tue Aug 27 12:28:01 2002
+++ b/net/802/p8022.c	Tue Aug 27 12:28:01 2002
@@ -23,103 +23,48 @@
 #include <linux/in.h>
 #include <linux/init.h>
 #include <net/p8022.h>
+#include <net/llc_sap.h>
 
-extern void llc_register_sap(unsigned char sap,
-			     int (*rcvfunc)(struct sk_buff *,
-					    struct net_device *,
-					    struct packet_type *));
-extern void llc_unregister_sap(unsigned char sap);
-
-static struct datalink_proto *p8022_list;
-/*
- *	We don't handle the loopback SAP stuff, the extended
- *	802.2 command set, multicast SAP identifiers and non UI
- *	frames. We have the absolute minimum needed for IPX,
- *	IP and Appletalk phase 2. See the llc_* routines for
- *	support libraries if your protocol needs these.
- */
-static struct datalink_proto *find_8022_client(unsigned char type)
-{
-	struct datalink_proto *proto = p8022_list;
-
-	while (proto && *(proto->type) != type)
-		proto = proto->next;
-	return proto;
-}
-
-int p8022_rcv(struct sk_buff *skb, struct net_device *dev,
-	      struct packet_type *pt)
-{
-	struct datalink_proto *proto;
-	int rc = 0;
-
-	proto = find_8022_client(*(skb->h.raw));
-	if (!proto) {
-		skb->sk = NULL;
-		kfree_skb(skb);
-		goto out;
-	}
-	skb->h.raw += 3;
-	skb->nh.raw += 3;
-	skb_pull(skb, 3);
-	rc = proto->rcvfunc(skb, dev, pt);
-out:	return rc;
-}
-
-static void p8022_datalink_header(struct datalink_proto *dl,
-				  struct sk_buff *skb, unsigned char *dest_node)
+static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
+			 unsigned char *dest)
 {
-	struct net_device *dev = skb->dev;
-	unsigned char *rawp = skb_push(skb, 3);
+	union llc_u_prim_data prim_data;
+	struct llc_prim_if_block prim;
 
-	*rawp++ = dl->type[0];
-	*rawp++ = dl->type[0];
-	*rawp	= 0x03;	/* UI */
-	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
+	prim.data                 = &prim_data;
+	prim.sap                  = dl->sap;
+	prim.prim                 = LLC_DATAUNIT_PRIM;
+	prim_data.test.skb        = skb;
+	prim_data.test.saddr.lsap = dl->sap->laddr.lsap;
+	prim_data.test.daddr.lsap = dl->sap->laddr.lsap;
+	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
+	memcpy(prim_data.test.daddr.mac, dest, IFHWADDRLEN);
+	return dl->sap->req(&prim);
 }
 
 struct datalink_proto *register_8022_client(unsigned char type,
-					    int (*rcvfunc)(struct sk_buff *,
-						    	   struct net_device *,
-							  struct packet_type *))
+			  int (*indicate)(struct llc_prim_if_block *prim))
 {
-	struct datalink_proto *proto = NULL;
+	struct datalink_proto *proto;
 
-	if (find_8022_client(type))
-		goto out;
 	proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
 	if (proto) {
 		proto->type[0]		= type;
-		proto->type_len		= 1;
-		proto->rcvfunc		= rcvfunc;
 		proto->header_length	= 3;
-		proto->datalink_header	= p8022_datalink_header;
-		proto->string_name	= "802.2";
-		proto->next		= p8022_list;
-		p8022_list		= proto;
-		llc_register_sap(type, p8022_rcv);
+		proto->request		= p8022_request;
+		proto->sap = llc_sap_open(indicate, NULL, type);
+		if (!proto->sap) {
+			kfree(proto);
+			proto = NULL;
+		}
 	}
-out:	return proto;
+	return proto;
 }
 
-void unregister_8022_client(unsigned char type)
+void unregister_8022_client(struct datalink_proto *proto)
 {
-	struct datalink_proto *tmp, **clients = &p8022_list;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	while (*clients) {
-		tmp = *clients;
-		if (tmp->type[0] == type) {
-			*clients = tmp->next;
-			kfree(tmp);
-			llc_unregister_sap(type);
-			break;
-		}
-		clients = &tmp->next;
-	}
-	restore_flags(flags);
+	llc_sap_close(proto->sap);
+	kfree(proto);
 }
 
 EXPORT_SYMBOL(register_8022_client);
diff -Nru a/net/802/p8023.c b/net/802/p8023.c
--- a/net/802/p8023.c	Tue Aug 27 12:27:59 2002
+++ b/net/802/p8023.c	Tue Aug 27 12:27:59 2002
@@ -24,11 +24,12 @@
  *	addresses, we just need to give it the buffer length.
  */
  
-static void p8023_datalink_header(struct datalink_proto *dl, 
+static int p8023_request(struct datalink_proto *dl, 
 		struct sk_buff *skb, unsigned char *dest_node)
 {
 	struct net_device	*dev = skb->dev;
 	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
+	return dev_queue_xmit(skb);
 }
 
 /*
@@ -42,10 +43,8 @@
 	proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
 	if (proto != NULL) 
 	{
-		proto->type_len = 0;
 		proto->header_length = 0;
-		proto->datalink_header = p8023_datalink_header;
-		proto->string_name = "802.3";
+		proto->request = p8023_request;
 	}
 	return proto;
 }
diff -Nru a/net/802/psnap.c b/net/802/psnap.c
--- a/net/802/psnap.c	Tue Aug 27 12:28:05 2002
+++ b/net/802/psnap.c	Tue Aug 27 12:28:05 2002
@@ -15,61 +15,90 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/datalink.h>
-#include <net/p8022.h>
 #include <net/psnap.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
 #include <linux/mm.h>
 #include <linux/in.h>
 #include <linux/init.h>
+#include <linux/brlock.h>
 
-static struct datalink_proto *snap_list;
-static struct datalink_proto *snap_dl;		/* 802.2 DL for SNAP */
+LIST_HEAD(snap_list);
+static struct llc_sap *snap_sap;
 
 /*
  *	Find a snap client by matching the 5 bytes.
  */
 static struct datalink_proto *find_snap_client(unsigned char *desc)
 {
-	struct datalink_proto *proto = snap_list;
+	struct list_head *entry;
+	struct datalink_proto *proto = NULL, *p;
 
-	for (; proto && memcmp(proto->type, desc, 5); proto = proto->next);
+	if (list_empty(&snap_list))
+		goto out;
 
+	list_for_each(entry, &snap_list) {
+		p = list_entry(entry, struct datalink_proto, node);
+		if (!memcmp(p->type, desc, 5)) {
+			proto = p;
+			break;
+		}
+	}
+out:
 	return proto;
 }
 
 /*
  *	A SNAP packet has arrived
  */
-int snap_rcv(struct sk_buff *skb, struct net_device *dev,
-	     struct packet_type *pt)
+static int snap_indicate(struct llc_prim_if_block *prim)
 {
+	struct sk_buff *skb;
+	struct datalink_proto *proto;
+	int rc = 1;
 	static struct packet_type psnap_packet_type = {
 		.type = __constant_htons(ETH_P_SNAP),
-		.func = snap_rcv,
 	};
 
-	struct datalink_proto *proto = find_snap_client(skb->h.raw);
+	if (prim->prim != LLC_DATAUNIT_PRIM)
+		goto out;
+
+	skb = prim->data->udata.skb;
+	proto = find_snap_client(skb->h.raw);
 
 	if (proto) {
 		/* Pass the frame on. */
 		skb->h.raw  += 5;
-		skb->nh.raw += 5;
 		skb_pull(skb, 5);
-
-		return proto->rcvfunc(skb, dev, &psnap_packet_type);
+		rc = proto->rcvfunc(skb, skb->dev, &psnap_packet_type);
+	} else {
+		skb->sk = NULL;
+		kfree_skb(skb);
+		rc = 1;
 	}
-	skb->sk = NULL;
-	kfree_skb(skb);
-	return 0;
+out:
+	return rc;
 }
 
 /*
  *	Put a SNAP header on a frame and pass to 802.2
  */
-static void snap_datalink_header(struct datalink_proto *dl,
-				 struct sk_buff *skb, unsigned char *dest_node)
+static int snap_request(struct datalink_proto *dl,
+			struct sk_buff *skb, u8 *dest)
 {
+	union llc_u_prim_data prim_data;
+	struct llc_prim_if_block prim;
+
 	memcpy(skb_push(skb, 5), dl->type, 5);
-	snap_dl->datalink_header(snap_dl, skb, dest_node);
+	prim.data                 = &prim_data;
+	prim.sap                  = snap_sap;
+	prim.prim                 = LLC_DATAUNIT_PRIM;
+	prim_data.test.skb        = skb;
+	prim_data.test.saddr.lsap = snap_sap->laddr.lsap;
+	prim_data.test.daddr.lsap = snap_sap->laddr.lsap;
+	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
+	memcpy(prim_data.test.daddr.mac, dest, IFHWADDRLEN);
+	return snap_sap->req(&prim);
 }
 
 /*
@@ -80,9 +109,9 @@
 
 static int __init snap_init(void)
 {
-	snap_dl = register_8022_client(0xAA, snap_rcv);
+	snap_sap = llc_sap_open(snap_indicate, NULL, 0xAA);
 
-	if (!snap_dl)
+	if (!snap_sap)
 		printk(KERN_CRIT "SNAP - unable to register with 802.2\n");
 
 	return 0;
@@ -90,6 +119,14 @@
 
 module_init(snap_init);
 
+static void __exit snap_exit(void)
+{
+	llc_sap_close(snap_sap);
+}
+
+module_exit(snap_exit);
+
+
 /*
  *	Register SNAP clients. We don't yet use this for IP.
  */
@@ -100,46 +137,35 @@
 {
 	struct datalink_proto *proto = NULL;
 
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+
 	if (find_snap_client(desc))
 		goto out;
 
 	proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
 	if (proto) {
 		memcpy(proto->type, desc,5);
-		proto->type_len		= 5;
 		proto->rcvfunc		= rcvfunc;
-		proto->header_length	= 5 + snap_dl->header_length;
-		proto->datalink_header	= snap_datalink_header;
-		proto->string_name	= "SNAP";
-		proto->next		= snap_list;
-		snap_list		= proto;
+		proto->header_length	= 5 + 3; /* snap + 802.2 */
+		proto->request		= snap_request;
+		list_add(&proto->node, &snap_list);
 	}
 out:
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
 	return proto;
 }
 
 /*
  *	Unregister SNAP clients. Protocols no longer want to play with us ...
  */
-void unregister_snap_client(unsigned char *desc)
+void unregister_snap_client(struct datalink_proto *proto)
 {
-	struct datalink_proto **clients = &snap_list;
-	struct datalink_proto *tmp;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	while ((tmp = *clients) != NULL) {
-		if (!memcmp(tmp->type, desc, 5)) {
-			*clients = tmp->next;
-			kfree(tmp);
-			break;
-		} else
-			clients = &tmp->next;
-	}
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+
+	list_del(&proto->node);
+	kfree(proto);
 
-	restore_flags(flags);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
 MODULE_LICENSE("GPL");
diff -Nru a/net/Config.in b/net/Config.in
--- a/net/Config.in	Tue Aug 27 12:28:02 2002
+++ b/net/Config.in	Tue Aug 27 12:28:02 2002
@@ -44,13 +44,17 @@
 fi
 tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q
 
-comment ' '
-tristate 'The IPX protocol' CONFIG_IPX
+tristate 'ANSI/IEEE 802.2 Data link layer protocol' CONFIG_LLC
+if [ "$CONFIG_LLC" != "n" ]; then
+   tristate '  LLC sockets interface' CONFIG_LLC_UI
+fi
+
+dep_tristate 'The IPX protocol' CONFIG_IPX $CONFIG_LLC
 if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
 
-tristate 'Appletalk protocol support' CONFIG_ATALK
+dep_tristate 'Appletalk protocol support' CONFIG_ATALK $CONFIG_LLC
 source drivers/net/appletalk/Config.in
 
 tristate 'DECnet Support' CONFIG_DECNET
@@ -61,11 +65,6 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-   tristate 'ANSI/IEEE 802.2 Data link layer protocol' CONFIG_LLC
-   if [ "$CONFIG_LLC" != "n" ]; then
-	# When NETBEUI is added the following line will be a tristate
-	define_bool CONFIG_LLC_UI y
-   fi
    bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT
    if [ "$CONFIG_INET" = "y" ]; then
       tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET
diff -Nru a/net/appletalk/aarp.c b/net/appletalk/aarp.c
--- a/net/appletalk/aarp.c	Tue Aug 27 12:28:02 2002
+++ b/net/appletalk/aarp.c	Tue Aug 27 12:28:02 2002
@@ -163,11 +163,8 @@
 	eah->pa_dst_net	 = a->target_addr.s_net;
 	eah->pa_dst_node = a->target_addr.s_node;
 	
-	/* Add ELAP headers and set target to the AARP multicast */
-	aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);	
-
 	/* Send it */	
-	dev_queue_xmit(skb);
+	aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
 	/* Update the sending count */
 	a->xmit_count++;
 }
@@ -213,10 +210,8 @@
 	eah->pa_dst_net	 = them->s_net;
 	eah->pa_dst_node = them->s_node;
 	
-	/* Add ELAP headers and set target to the AARP multicast */
-	aarp_dl->datalink_header(aarp_dl, skb, sha);	
 	/* Send it */	
-	dev_queue_xmit(skb);
+	aarp_dl->request(aarp_dl, skb, sha);
 }
 
 /*
@@ -261,10 +256,8 @@
 	eah->pa_dst_net	 = us->s_net;
 	eah->pa_dst_node = us->s_node;
 
-	/* Add ELAP headers and set target to the AARP multicast */
-	aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);
 	/* Send it */
-	dev_queue_xmit(skb);
+	aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
 }
 	
 /*
@@ -602,8 +595,9 @@
 	
 	/* Do we have a resolved entry? */
 	if (sa->s_node == ATADDR_BCAST) {
-		ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast);
-		goto sendit;
+		/* Send it */
+		ddp_dl->request(ddp_dl, skb, ddp_eth_multicast);
+		goto sent;
 	}
 
 	spin_lock_bh(&aarp_lock);
@@ -611,9 +605,9 @@
 
 	if (a) { /* Return 1 and fill in the address */
 		a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
-		ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
+		ddp_dl->request(ddp_dl, skb, a->hwaddr);
 		spin_unlock_bh(&aarp_lock);
-		goto sendit;
+		goto sent;
 	}
 
 	/* Do we have an unresolved entry: This is the less common path */
@@ -663,6 +657,7 @@
 	if (skb->sk)
 		skb->priority = skb->sk->priority;
 	dev_queue_xmit(skb);
+sent:
 	return 1;
 }
 
@@ -690,10 +685,7 @@
 			while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
 				a->expires_at = jiffies +
 						sysctl_aarp_expiry_time * 10;
-				ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
-				if (skb->sk)
-					skb->priority = skb->sk->priority;
-				dev_queue_xmit(skb);
+				ddp_dl->request(ddp_dl, skb, a->hwaddr);
 			}
 		} else 
 			list = &((*list)->next);
@@ -989,7 +981,7 @@
 {
 	del_timer(&aarp_timer);
 	unregister_netdevice_notifier(&aarp_notifier);
-	unregister_snap_client(aarp_snap_id);
+	unregister_snap_client(aarp_dl);
 }
 #endif  /* MODULE */
 #ifdef CONFIG_PROC_FS
diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c	Tue Aug 27 12:28:08 2002
+++ b/net/appletalk/ddp.c	Tue Aug 27 12:28:08 2002
@@ -1782,13 +1782,7 @@
 		SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
 		/* loop back */
 		skb_orphan(skb);
-		ddp_dl->datalink_header(ddp_dl, skb, dev->dev_addr);
-		skb->mac.raw = skb->data;
-		skb->h.raw   = skb->data + ddp_dl->header_length +
-				dev->hard_header_len;
-		skb_pull(skb, dev->hard_header_len);
-		skb_pull(skb, ddp_dl->header_length);
-		atalk_rcv(skb, dev, NULL);
+		ddp_dl->request(ddp_dl, skb, dev->dev_addr);
 	} else {
 		SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
 		if (rt->flags & RTF_GATEWAY) {
@@ -2040,7 +2034,7 @@
 	unregister_netdevice_notifier(&ddp_notifier);
 	dev_remove_pack(&ltalk_packet_type);
 	dev_remove_pack(&ppptalk_packet_type);
-	unregister_snap_client(ddp_snap_id);
+	unregister_snap_client(ddp_dl);
 	sock_unregister(PF_APPLETALK);
 }
 module_exit(atalk_exit);
diff -Nru a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile	Tue Aug 27 12:28:08 2002
+++ b/net/core/Makefile	Tue Aug 27 12:28:08 2002
@@ -2,8 +2,6 @@
 # Makefile for the Linux networking core.
 #
 
-export-objs := ext8022.o
-
 obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
 
 ifeq ($(CONFIG_SYSCTL),y)
@@ -15,11 +13,6 @@
 obj-$(CONFIG_FILTER) += filter.o
 
 obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
-
-# See p8022 in net/802/Makefile for config options to check
-ifneq ($(CONFIG_LLC)$(CONFIG_TR)$(CONFIG_IPX)$(CONFIG_ATALK),)
-obj-y += ext8022.o
-endif
 
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
diff -Nru a/net/core/ext8022.c b/net/core/ext8022.c
--- a/net/core/ext8022.c	Tue Aug 27 12:28:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,76 +0,0 @@
-/*
- * (ext8022.c)
- * 
- * Copyright (c) 1997 by Procom Technology, Inc.
- * 		 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * This program can be redistributed or modified under the terms of the 
- * GNU General Public License as published by the Free Software Foundation.
- * This program is distributed without any warranty or implied warranty
- * of merchantability or fitness for a particular purpose.
- *
- * See the GNU General Public License for more details.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/brlock.h>
-
-typedef int (*func_type)(struct sk_buff *skb, struct net_device *dev,
-			 struct packet_type *pt);
-static int llc_rcv(struct sk_buff *skb, struct net_device *dev,
-		   struct packet_type *);
-
-static func_type llc_sap_table[128];
-static int llc_users;
-
-static struct packet_type llc_packet_type = {
-	.type =	__constant_htons(ETH_P_802_2),
-	.func =	llc_rcv,
-};
-static struct packet_type llc_tr_packet_type = {
-	.type =	__constant_htons(ETH_P_TR_802_2),
-	.func =	llc_rcv,
-};
-
-static int llc_rcv(struct sk_buff *skb, struct net_device *dev,
-		   struct packet_type *pt)
-{
- 	unsigned char n = (*(skb->h.raw)) >> 1;
-
-	br_read_lock(BR_LLC_LOCK);
-	if (llc_sap_table[n])
-            llc_sap_table[n](skb, dev, pt);
-        else
-            kfree_skb(skb);
-	br_read_unlock(BR_LLC_LOCK);
-        return 0;
-}
-
-void llc_register_sap(unsigned char sap, func_type rcvfunc)
-{
-	sap >>= 1;
-	br_write_lock_bh(BR_LLC_LOCK);
-	llc_sap_table[sap] = rcvfunc;            
-	if (!llc_users) {
-		dev_add_pack(&llc_packet_type);
-		dev_add_pack(&llc_tr_packet_type);
-        }
-	llc_users++;
-	br_write_unlock_bh(BR_LLC_LOCK);
-}
-
-void llc_unregister_sap(unsigned char sap)
-{
-	sap >>= 1;
-	br_write_lock_bh(BR_LLC_LOCK);
-        llc_sap_table[sap] = NULL;
-	if (!--llc_users) {
-		dev_remove_pack(&llc_packet_type);
-		dev_remove_pack(&llc_tr_packet_type);
-        } 
-	br_write_unlock_bh(BR_LLC_LOCK);
-}
-
-EXPORT_SYMBOL(llc_register_sap);
-EXPORT_SYMBOL(llc_unregister_sap);
diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
--- a/net/decnet/af_decnet.c	Tue Aug 27 12:28:07 2002
+++ b/net/decnet/af_decnet.c	Tue Aug 27 12:28:07 2002
@@ -2238,7 +2238,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.20-pre1s (C) 1995-2002 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c
--- a/net/decnet/dn_route.c	Tue Aug 27 12:28:08 2002
+++ b/net/decnet/dn_route.c	Tue Aug 27 12:28:08 2002
@@ -35,6 +35,8 @@
  *                                 are numbered!
  *              Steve Whitehouse : Added return-to-sender functions. Added
  *                                 backlog congestion level return codes.
+ *		Steve Whitehouse : Fixed bug where routes were set up with
+ *                                 no ref count on net devices.
  *                                 
  */
 
@@ -801,6 +803,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dn_output;
 	rt->u.dst.input  = dn_rt_bug;
@@ -978,6 +982,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dnrt_output;
 	rt->u.dst.input = dnrt_input;
diff -Nru a/net/ethernet/pe2.c b/net/ethernet/pe2.c
--- a/net/ethernet/pe2.c	Tue Aug 27 12:28:08 2002
+++ b/net/ethernet/pe2.c	Tue Aug 27 12:28:08 2002
@@ -4,8 +4,7 @@
 #include <linux/mm.h>
 #include <linux/in.h>
 
-static void
-pEII_datalink_header(struct datalink_proto *dl, 
+static int pEII_request(struct datalink_proto *dl, 
 		struct sk_buff *skb, unsigned char *dest_node)
 {
 	struct net_device	*dev = skb->dev;
@@ -13,6 +12,7 @@
 	skb->protocol = htons (ETH_P_IPX);
 	if(dev->hard_header)
 		dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
+	return dev_queue_xmit(skb);
 }
 
 struct datalink_proto *
@@ -22,10 +22,8 @@
 
 	proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
 	if (proto != NULL) {
-		proto->type_len = 0;
 		proto->header_length = 0;
-		proto->datalink_header = pEII_datalink_header;
-		proto->string_name = "EtherII";
+		proto->request = pEII_request;
 	}
 
 	return proto;
diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
--- a/net/ipv4/ipconfig.c	Tue Aug 27 12:27:57 2002
+++ b/net/ipv4/ipconfig.c	Tue Aug 27 12:27:57 2002
@@ -26,6 +26,9 @@
  *
  *  Merged changes from 2.2.19 into 2.4.3
  *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
+ *
+ *  Multipe Nameservers in /proc/net/pnp
+ *              --  Josef Siemes <jsiemes@web.de>, Aug 2002
  */
 
 #include <linux/config.h>
@@ -91,6 +94,8 @@
 #define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
 #define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
 #define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
+#define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers  
+                                           - '3' from resolv.h */
 
 
 /*
@@ -132,7 +137,7 @@
 /* Persistent data: */
 
 int ic_proto_used;			/* Protocol used, if any */
-u32 ic_nameserver = INADDR_NONE;	/* DNS Server IP address */
+u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
 u8 ic_domain[64];		/* DNS (not NIS) domain name */
 
 /*
@@ -625,6 +630,11 @@
  */
 static inline void ic_bootp_init(void)
 {
+	int i;
+
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
+		ic_nameservers[i] = INADDR_NONE;
+
 	dev_add_pack(&bootp_packet_type);
 }
 
@@ -729,6 +739,9 @@
  */
 static void __init ic_do_bootp_ext(u8 *ext)
 {
+       u8 servers;
+       int i;
+
 #ifdef IPCONFIG_DEBUG
 	u8 *c;
 
@@ -748,8 +761,13 @@
 				memcpy(&ic_gateway, ext+1, 4);
 			break;
 		case 6:		/* DNS server */
-			if (ic_nameserver == INADDR_NONE)
-				memcpy(&ic_nameserver, ext+1, 4);
+			servers= *ext/4;
+			if (servers > CONF_NAMESERVERS_MAX)
+				servers = CONF_NAMESERVERS_MAX;
+			for (i = 0; i < servers; i++) {
+				if (ic_nameservers[i] == INADDR_NONE)
+					memcpy(&ic_nameservers[i], ext+1+4*i, 4);
+			}
 			break;
 		case 12:	/* Host name */
 			ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
@@ -914,8 +932,8 @@
 	ic_servaddr = b->server_ip;
 	if (ic_gateway == INADDR_NONE && b->relay_ip)
 		ic_gateway = b->relay_ip;
-	if (ic_nameserver == INADDR_NONE)
-		ic_nameserver = ic_servaddr;
+	if (ic_nameservers[0] == INADDR_NONE)
+		ic_nameservers[0] = ic_servaddr;
 	ic_got_reply = IC_BOOTP;
 
 drop:
@@ -1078,6 +1096,7 @@
 			off_t offset, int length)
 {
 	int len;
+       int i;
 
 	if (ic_proto_used & IC_PROTO)
 	    sprintf(buffer, "#PROTO: %s\n",
@@ -1090,9 +1109,12 @@
 	if (ic_domain[0])
 		len += sprintf(buffer + len,
 			       "domain %s\n", ic_domain);
-	if (ic_nameserver != INADDR_NONE)
-		len += sprintf(buffer + len,
-			       "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameserver));
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
+		if (ic_nameservers[i] != INADDR_NONE)
+			len += sprintf(buffer + len,
+				       "nameserver %u.%u.%u.%u\n",
+				       NIPQUAD(ic_nameservers[i]));
+	}
 
 	if (offset > len)
 		offset = len;
diff -Nru a/net/ipv4/netfilter/Config.help b/net/ipv4/netfilter/Config.help
--- a/net/ipv4/netfilter/Config.help	Tue Aug 27 12:28:08 2002
+++ b/net/ipv4/netfilter/Config.help	Tue Aug 27 12:28:08 2002
@@ -56,6 +56,16 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+CONFIG_IP_NF_MATCH_PKTTYPE
+  This patch allows you to match packet in accrodance
+  to its "class", eg. BROADCAST, MULTICAST, ...
+  
+  Typical usage:
+  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+  
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 CONFIG_IP_NF_MATCH_MAC
   MAC matching allows you to match packets based on the source
   Ethernet address of the packet.
@@ -100,6 +110,22 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+CONFIG_IP_NF_TARGET_DSCP
+  This option adds a `DSCP' match, which allows you to match against
+  the IPv4 header DSCP field (DSCP codepoint).
+
+  The DSCP codepoint can have any value between 0x0 and 0x4f.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_ECN
+  This option adds a `ECN' match, which allows you to match against
+  the IPv4 and TCP header ECN fields.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
   Service fields of the IP packet.
@@ -107,6 +133,16 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+CONFIG_IP_NF_MATCH_CONNTRACK
+  This is a general conntrack match module, a superset of the state match.
+
+  It allows matching on additional conntrack information, which is
+  useful in complex configurations, such as NAT gateways with multiple
+  internet links or tunnels.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 CONFIG_IP_NF_MATCH_STATE
   Connection state matching allows you to match packets based on their
   relationship to a tracked connection (ie. previous packets).  This
@@ -211,6 +247,30 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+CONFIG_IP_NF_TARGET_DSCP
+  This option adds a `DSCP' target, which allows you to create rules in
+  the iptables mangle table. The selected packet has the DSCP field set
+  to the hex value provided on the command line; unlike the TOS target
+  which will only set the legal values within ip.h.
+
+  The DSCP field can be set to any value between 0x0 and 0x4f. It does
+  take into account that bits 6 and 7 are used by ECN.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_ECN
+  This option adds a `ECN' target, which can be used in the iptables mangle
+  table.  
+
+  You can use this target to remove the ECN bits from the IPv4 header of
+  an IP packet.  This is particularly useful, if you need to work around
+  existing ECN blackholes on the internet, but don't want to disable
+  ECN support in general.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 CONFIG_IP_NF_TARGET_TOS
   This option adds a `TOS' target, which allows you to create rules in
   the `mangle' table which alter the Type Of Service field of an IP
@@ -229,6 +289,13 @@
 
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_HELPER
+  Helper matching allows you to match packets in dynamic connections
+  tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `Y'.
 
 CONFIG_IP_NF_TARGET_TCPMSS
   This option adds a `TCPMSS' target, which allows you to alter the
diff -Nru a/net/ipv4/netfilter/Config.in b/net/ipv4/netfilter/Config.in
--- a/net/ipv4/netfilter/Config.in	Tue Aug 27 12:28:06 2002
+++ b/net/ipv4/netfilter/Config.in	Tue Aug 27 12:28:06 2002
@@ -18,15 +18,24 @@
 # The simple matches.
   dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
+ 
+  dep_tristate '  DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES
+ 
   dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+    dep_tristate '  Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES
+  fi
+  if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
+    dep_tristate '  Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
@@ -73,6 +82,10 @@
   dep_tristate '  Packet mangling' CONFIG_IP_NF_MANGLE $CONFIG_IP_NF_IPTABLES 
   if [ "$CONFIG_IP_NF_MANGLE" != "n" ]; then
     dep_tristate '    TOS target support' CONFIG_IP_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
+    dep_tristate '    ECN target support' CONFIG_IP_NF_TARGET_ECN $CONFIG_IP_NF_MANGLE
+ 
+    dep_tristate '    DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
+ 
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
diff -Nru a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
--- a/net/ipv4/netfilter/Makefile	Tue Aug 27 12:28:01 2002
+++ b/net/ipv4/netfilter/Makefile	Tue Aug 27 12:28:01 2002
@@ -3,8 +3,7 @@
 #
 
 export-objs  := ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o \
-		ip_tables.o arp_tables.o ip_conntrack_ftp.o \
-		ip_conntrack_irc.o
+		ip_tables.o arp_tables.o
 
 # objects for the conntrack and NAT core (used by standalone and backw. compat)
 ip_nf_conntrack-objs	:= ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
@@ -25,7 +24,13 @@
 
 # connection tracking helpers
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ifdef CONFIG_IP_NF_NAT_FTP
+	export-objs += ip_conntrack_ftp.o
+endif
 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ifdef CONFIG_IP_NF_NAT_IRC
+	export-objs += ip_conntrack_irc.o
+endif
 
 # NAT helpers 
 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
@@ -40,18 +45,24 @@
 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 
 # matches
+obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+
+obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 
@@ -59,6 +70,8 @@
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
 obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c	Tue Aug 27 12:27:42 2002
+++ b/net/ipv4/netfilter/ip_conntrack_core.c	Tue Aug 27 12:27:42 2002
@@ -8,6 +8,9 @@
  * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
  * 	- new API and handling of conntrack/nat helpers
  * 	- now capable of multiple expectations for one master
+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
+ * 	- add usage/reference counts to ip_conntrack_expect
+ *	- export ip_conntrack[_expect]_{find_get,put} functions
  * */
 
 #ifdef MODULE
@@ -43,7 +46,7 @@
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define IP_CONNTRACK_VERSION	"2.0"
+#define IP_CONNTRACK_VERSION	"2.1"
 
 #if 0
 #define DEBUGP printk
@@ -55,7 +58,7 @@
 DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-LIST_HEAD(expect_list);
+LIST_HEAD(ip_conntrack_expect_list);
 LIST_HEAD(protocol_list);
 static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
@@ -95,7 +98,8 @@
 	return p;
 }
 
-static inline void ip_conntrack_put(struct ip_conntrack *ct)
+inline void 
+ip_conntrack_put(struct ip_conntrack *ct)
 {
 	IP_NF_ASSERT(ct);
 	IP_NF_ASSERT(ct->infos[0].master);
@@ -159,26 +163,109 @@
 	return protocol->invert_tuple(inverse, orig);
 }
 
-/* remove one specific expectation from all lists and free it */
-static void unexpect_related(struct ip_conntrack_expect *expect)
+
+/* ip_conntrack_expect helper functions */
+
+/* Compare tuple parts depending on mask. */
+static inline int expect_cmp(const struct ip_conntrack_expect *i,
+			     const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+}
+
+static void
+destroy_expect(struct ip_conntrack_expect *exp)
+{
+	DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use));
+	IP_NF_ASSERT(atomic_read(exp->use));
+	IP_NF_ASSERT(!timer_pending(&exp->timeout));
+
+	kfree(exp);
+}
+
+
+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
+{
+	IP_NF_ASSERT(exp);
+
+	if (atomic_dec_and_test(&exp->use)) {
+		/* usage count dropped to zero */
+		destroy_expect(exp);
+	}
+}
+
+static inline struct ip_conntrack_expect *
+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
+			 struct ip_conntrack_expect *, tuple);
+}
+
+/* Find a expectation corresponding to a tuple. */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
+{
+	struct ip_conntrack_expect *exp;
+
+	READ_LOCK(&ip_conntrack_lock);
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
+	exp = __ip_ct_expect_find(tuple);
+	if (exp)
+		atomic_inc(&exp->use);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+	READ_UNLOCK(&ip_conntrack_lock);
+
+	return exp;
+}
+
+/* remove one specific expectation from all lists and drop refcount,
+ * does _NOT_ delete the timer. */
+static void __unexpect_related(struct ip_conntrack_expect *expect)
 {
-	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
 	DEBUGP("unexpect_related(%p)\n", expect);
+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+
+	/* we're not allowed to unexpect a confirmed expectation! */
+	IP_NF_ASSERT(!expect->sibling);
+
 	/* delete from global and local lists */
 	list_del(&expect->list);
 	list_del(&expect->expected_list);
-	if (!expect->sibling)
+
+	/* decrement expect-count of master conntrack */
+	if (expect->expectant)
 		expect->expectant->expecting--;
-	kfree(expect);
+
+	ip_conntrack_expect_put(expect);
+}
+
+/* remove one specific expecatation from all lists, drop refcount
+ * and expire timer. 
+ * This function can _NOT_ be called for confirmed expects! */
+static void unexpect_related(struct ip_conntrack_expect *expect)
+{
+	IP_NF_ASSERT(expect->expectant);
+	IP_NF_ASSERT(expect->expectant->helper);
+	/* if we are supposed to have a timer, but we can't delete
+	 * it: race condition.  __unexpect_related will
+	 * be calledd by timeout function */
+	if (expect->expectant->helper->timeout
+	    && !del_timer(&expect->timeout))
+		return;
+
+	__unexpect_related(expect);
 }
 
-/* delete all expectations for this conntrack */
-static void destroy_expectations(struct ip_conntrack *ct)
+/* delete all unconfirmed expectations for this conntrack */
+static void remove_expectations(struct ip_conntrack *ct)
 {
 	struct list_head *exp_entry, *next;
 	struct ip_conntrack_expect *exp;
 
-	DEBUGP("destroy_expectations(%p)\n", ct);
+	DEBUGP("remove_expectations(%p)\n", ct);
 
 	for (exp_entry = ct->sibling_list.next;
 	     exp_entry != &ct->sibling_list; exp_entry = next) {
@@ -189,19 +276,13 @@
 		/* we skip established expectations, as we want to delete
 		 * the un-established ones only */
 		if (exp->sibling) {
-			DEBUGP("destroy_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
 			continue;
 		}
 
-		IP_NF_ASSERT(list_inlist(&expect_list, exp));
+		IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
 		IP_NF_ASSERT(exp->expectant == ct);
 
-		if (exp->expectant->helper->timeout
-		    && ! del_timer(&exp->timeout)) {
-		    	DEBUGP("destroy_expectations: skipping dying expectation %p of %p\n", exp, ct);
-		    	continue;
-		}
-		
 		/* delete expectation from global and private lists */
 		unexpect_related(exp);
 	}
@@ -223,7 +304,7 @@
 		    &ct->tuplehash[IP_CT_DIR_REPLY]);
 
 	/* Destroy all un-established, pending expectations */
-	destroy_expectations(ct);
+	remove_expectations(ct);
 }
 
 static void
@@ -250,15 +331,15 @@
 		ip_conntrack_destroyed(ct);
 
 	WRITE_LOCK(&ip_conntrack_lock);
-	/* Delete our master expectation from the local list
-	 * and destroy it, if we've been expected */
+	/* Delete our master expectation */
 	if (ct->master) {
+		/* can't call __unexpect_related here,
+		 * since it would screw up expect_list */
 		list_del(&ct->master->expected_list);
 		kfree(ct->master);
 	}
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
-	
 	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
@@ -383,7 +464,7 @@
 			     &ct->tuplehash[IP_CT_DIR_REPLY]);
 		/* Timer relative to confirmation time, not original
 		   setting time, otherwise we'd get timer wrap in
-		   wierd delay cases. */
+		   weird delay cases. */
 		ct->timeout.expires += jiffies;
 		add_timer(&ct->timeout);
 		atomic_inc(&ct->ct_general.use);
@@ -544,14 +625,6 @@
 			 tuple);
 }
 
-/* Compare parts depending on mask. */
-static inline int expect_cmp(const struct ip_conntrack_expect *i,
-			     const struct ip_conntrack_tuple *tuple)
-{
-	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
-	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
-}
-
 /* Allocate a new conntrack: we return -ENOMEM if classification
    failed due to stress.  Otherwise it really is unclassifiable. */
 static struct ip_conntrack_tuple_hash *
@@ -573,9 +646,9 @@
 		/* Try dropping from random chain, or else from the
                    chain about to put into (in case they're trying to
                    bomb one hash chain). */
-		if (drop_next >= ip_conntrack_htable_size)
-			drop_next = 0;
-		if (!early_drop(&ip_conntrack_hash[drop_next++])
+		unsigned int next = (drop_next++)%ip_conntrack_htable_size;
+
+		if (!early_drop(&ip_conntrack_hash[next])
 		    && !early_drop(&ip_conntrack_hash[hash])) {
 			if (net_ratelimit())
 				printk(KERN_WARNING
@@ -624,7 +697,7 @@
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Need finding and deleting of expected ONLY if we win race */
 	READ_LOCK(&ip_conntrack_expect_tuple_lock);
-	expected = LIST_FIND(&expect_list, expect_cmp,
+	expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
 			     struct ip_conntrack_expect *, tuple);
 	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
 
@@ -651,7 +724,7 @@
 		conntrack->status = IPS_EXPECTED;
 		conntrack->master = expected;
 		expected->sibling = conntrack;
-		LIST_DELETE(&expect_list, expected);
+		LIST_DELETE(&ip_conntrack_expect_list, expected);
 		expected->expectant->expecting--;
 		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
 	}
@@ -835,7 +908,7 @@
 	return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
 }
 
-void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
 {
 	WRITE_LOCK(&ip_conntrack_lock);
 	unexpect_related(expect);
@@ -847,14 +920,16 @@
 	struct ip_conntrack_expect *expect = (void *) ul_expect;
 
 	DEBUGP("expectation %p timed out\n", expect);	
-	ip_conntrack_unexpect_related(expect);
+	WRITE_LOCK(&ip_conntrack_lock);
+	__unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
 }
 
 /* Add a related connection. */
 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
 				struct ip_conntrack_expect *expect)
 {
-	struct ip_conntrack_expect *new;
+	struct ip_conntrack_expect *old, *new;
 	int ret = 0;
 
 	WRITE_LOCK(&ip_conntrack_lock);
@@ -865,78 +940,88 @@
 	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
 	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
 
-	new = LIST_FIND(&expect_list, resent_expect,
-		        struct ip_conntrack_expect *, &expect->tuple, &expect->mask);
-	if (new) {
+	old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
+		        struct ip_conntrack_expect *, &expect->tuple, 
+			&expect->mask);
+	if (old) {
 		/* Helper private data may contain offsets but no pointers
 		   pointing into the payload - otherwise we should have to copy 
 		   the data filled out by the helper over the old one */
 		DEBUGP("expect_related: resent packet\n");
 		if (related_to->helper->timeout) {
-			/* Refresh timer, if possible... */
-			if (del_timer(&new->timeout)) {
-				new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
-				add_timer(&new->timeout);
-				WRITE_UNLOCK(&ip_conntrack_lock);
-				return -EEXIST;
+			if (!del_timer(&old->timeout)) {
+				/* expectation is dying. Fall through */
+				old = NULL;
+			} else {
+				old->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
+				add_timer(&old->timeout);
 			}
-			/* ... otherwise expectation is dying. Fall over and create a new one. */
-			new = NULL;
-		} else {
+		}
+
+		if (old) {
 			WRITE_UNLOCK(&ip_conntrack_lock);
 			return -EEXIST;
 		}
-	} else if (related_to->helper->max_expected
-	    	   && related_to->expecting >= related_to->helper->max_expected) {
+	} else if (related_to->helper->max_expected && 
+		   related_to->expecting >= related_to->helper->max_expected) {
+		struct list_head *cur_item;
+		/* old == NULL */
 	    	if (net_ratelimit())
 		    	printk(KERN_WARNING 
-		    	       "ip_conntrack: max number of expected connections %i of %s reached for %u.%u.%u.%u->%u.%u.%u.%u%s\n",
+		    	       "ip_conntrack: max number of expected "
+			       "connections %i of %s reached for "
+			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
 		    	       related_to->helper->max_expected, 
 		    	       related_to->helper->name,
 		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
 		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
 		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
 		    	       ", reusing" : "");
-	    	if (related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT) {
-		    	struct list_head *cur_item;
-
-		    	/* Let's choose the the oldest expectation to overwrite */
-			list_for_each(cur_item, &related_to->sibling_list) { 
-				new = list_entry(cur_item, struct ip_conntrack_expect,
-						 expected_list);
-				if (new->sibling == NULL)
-					break;
-			}
-			IP_NF_ASSERT(new);
-			if (related_to->helper->timeout 
-			    &&  !del_timer(&new->timeout)) {
-				/* Expectation is dying. Fall over and create a new one */
-				new = NULL;
-			} else {
-				list_del(&new->list);
-				list_del(&new->expected_list);
-				related_to->expecting--;
-				ret = -EPERM;
-			}
-		} else {
+		if (!(related_to->helper->flags & 
+		      IP_CT_HELPER_F_REUSE_EXPECT)) {
 			WRITE_UNLOCK(&ip_conntrack_lock);
 			return -EPERM;
 		}
-	} else if (LIST_FIND(&expect_list, expect_clash,
-		      struct ip_conntrack_expect *, &expect->tuple, &expect->mask)) {
+
+		/* choose the the oldest expectation to evict */
+		list_for_each(cur_item, &related_to->sibling_list) { 
+			struct ip_conntrack_expect *cur;
+
+			cur = list_entry(cur_item, 
+					 struct ip_conntrack_expect,
+					 expected_list);
+			if (cur->sibling == NULL) {
+				old = cur;
+				break;
+			}
+		}
+
+		/* (!old) cannot happen, since related_to->expecting is the
+		 * number of unconfirmed expects */
+		IP_NF_ASSERT(old);
+
+		/* newnat14 does not reuse the real allocated memory
+		 * structures but rather unexpects the old and
+		 * allocates a new.  unexpect_related will decrement
+		 * related_to->expecting. 
+		 */
+		unexpect_related(old);
+		ret = -EPERM;
+	} else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+			     struct ip_conntrack_expect *, &expect->tuple, 
+			     &expect->mask)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
 		DEBUGP("expect_related: busy!\n");
 		return -EBUSY;
 	}
 	
+	new = (struct ip_conntrack_expect *) 
+	      kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
 	if (!new) {
-		new = (struct ip_conntrack_expect *) 
-		      kmalloc(sizeof(*expect), GFP_ATOMIC);
-		if (!new) {
-			WRITE_UNLOCK(&ip_conntrack_lock);
-			DEBUGP("expect_relaed: OOM allocating expect\n");
-			return -ENOMEM;
-		}
+		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_relaed: OOM allocating expect\n");
+		return -ENOMEM;
 	}
 	
 	/* Zero out the new structure, then fill out it with the data */
@@ -947,17 +1032,22 @@
 	memcpy(new, expect, sizeof(*expect));
 	new->expectant = related_to;
 	new->sibling = NULL;
+	/* increase usage count. This sucks. The memset above overwrites
+	 * old usage count [if still present] and we increase to one.  Only
+	 * works because everything is done under ip_conntrack_lock() */
+	atomic_inc(&new->use);
 	
 	/* add to expected list for this connection */	
 	list_add(&new->expected_list, &related_to->sibling_list);
 	/* add to global list of expectations */
-	list_prepend(&expect_list, &new->list);
+	list_prepend(&ip_conntrack_expect_list, &new->list);
 	/* add and start timer if required */
 	if (related_to->helper->timeout) {
 		init_timer(&new->timeout);
 		new->timeout.data = (unsigned long)new;
 		new->timeout.function = expectation_timed_out;
-		new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
+		new->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
 		add_timer(&new->timeout);
 	}
 	related_to->expecting++;
@@ -981,7 +1071,7 @@
 		/* Never seen before */
 		DEBUGP("change expect: never seen before\n");
 		if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
-		    && LIST_FIND(&expect_list, expect_clash,
+		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
 			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
 			/* Force NAT to find an unused tuple */
 			return -1;
@@ -1048,7 +1138,7 @@
 {
 	if (i->ctrack->helper == me) {
 		/* Get rid of any expected. */
-		destroy_expectations(i->ctrack);
+		remove_expectations(i->ctrack);
 		/* And *then* set helper to NULL */
 		i->ctrack->helper = NULL;
 	}
@@ -1340,14 +1430,16 @@
 	       sizeof(struct ip_conntrack));
 
 	ret = nf_register_sockopt(&so_getorigdst);
-	if (ret != 0)
+	if (ret != 0) {
+		printk(KERN_ERR "Unable to register netfilter socket option\n");
 		return ret;
+	}
 
 	ip_conntrack_hash = vmalloc(sizeof(struct list_head)
 				    * ip_conntrack_htable_size);
 	if (!ip_conntrack_hash) {
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
+		goto err_unreg_sockopt;
 	}
 
 	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
@@ -1355,11 +1447,8 @@
 	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!ip_conntrack_cachep) {
 		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_hash;
 	}
-	
 	/* Don't NEED lock here, but good form anyway. */
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Sew in builtin protocols. */
@@ -1378,14 +1467,20 @@
 	ip_conntrack_sysctl_header
 		= register_sysctl_table(ip_conntrack_root_table, 0);
 	if (ip_conntrack_sysctl_header == NULL) {
-		kmem_cache_destroy(ip_conntrack_cachep);
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_ct_cachep;
 	}
 #endif /*CONFIG_SYSCTL*/
 
 	/* For use by ipt_REJECT */
 	ip_ct_attach = ip_conntrack_attach;
 	return ret;
+
+err_free_ct_cachep:
+	kmem_cache_destroy(ip_conntrack_cachep);
+err_free_hash:
+	vfree(ip_conntrack_hash);
+err_unreg_sockopt:
+	nf_unregister_sockopt(&so_getorigdst);
+
+	return -ENOMEM;
 }
diff -Nru a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c	Tue Aug 27 12:28:08 2002
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c	Tue Aug 27 12:28:08 2002
@@ -16,7 +16,7 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_c;
+static int ports_c = 0;
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 #endif
@@ -389,7 +389,7 @@
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
 				ports[i]);
 		ip_conntrack_helper_unregister(&ftp[i]);
diff -Nru a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
--- a/net/ipv4/netfilter/ip_conntrack_irc.c	Tue Aug 27 12:28:08 2002
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c	Tue Aug 27 12:28:08 2002
@@ -35,7 +35,7 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_n_c = 0;
+static int ports_c = 0;
 static int max_dcc_channels = 8;
 static unsigned int dcc_timeout = 300;
 
@@ -288,7 +288,7 @@
 			fini();
 			return -EBUSY;
 		}
-		ports_n_c++;
+		ports_c++;
 	}
 	return 0;
 }
@@ -298,7 +298,7 @@
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("unregistering port %d\n",
 		       ports[i]);
 		ip_conntrack_helper_unregister(&irc_helpers[i]);
diff -Nru a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Aug 27 12:28:05 2002
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Aug 27 12:28:05 2002
@@ -68,8 +68,8 @@
 			      ? (expect->timeout.expires - jiffies)/HZ : 0);
 	else
 		len = sprintf(buffer, "EXPECTING: - ");
-	len += sprintf(buffer + len, "proto=%u ",
-		      expect->tuple.dst.protonum);
+	len += sprintf(buffer + len, "use=%u proto=%u ",
+		      atomic_read(&expect->use), expect->tuple.dst.protonum);
 	len += print_tuple(buffer + len, &expect->tuple,
 			   __find_proto(expect->tuple.dst.protonum));
 	len += sprintf(buffer + len, "\n");
@@ -153,7 +153,8 @@
 	}
 
 	/* Now iterate through expecteds. */
-	for (e = expect_list.next; e != &expect_list; e = e->next) {
+	for (e = ip_conntrack_expect_list.next; 
+	     e != &ip_conntrack_expect_list; e = e->next) {
 		unsigned int last_len;
 		struct ip_conntrack_expect *expect
 			= (struct ip_conntrack_expect *)e;
@@ -364,7 +365,13 @@
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_change_expect);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
 EXPORT_SYMBOL(ip_conntrack_htable_size);
+EXPORT_SYMBOL(ip_conntrack_expect_list);
 EXPORT_SYMBOL(ip_conntrack_lock);
+EXPORT_SYMBOL(ip_conntrack_hash);
+EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_put);
diff -Nru a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c
--- a/net/ipv4/netfilter/ip_fw_compat.c	Tue Aug 27 12:28:02 2002
+++ b/net/ipv4/netfilter/ip_fw_compat.c	Tue Aug 27 12:28:02 2002
@@ -18,6 +18,7 @@
 
 /* Theoretically, we could one day use 2.4 helpers, but for now it
    just confuses depmod --RR */
+EXPORT_NO_SYMBOLS;
 
 static struct firewall_ops *fwops;
 
diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c	Tue Aug 27 12:28:01 2002
+++ b/net/ipv4/netfilter/ip_nat_core.c	Tue Aug 27 12:28:01 2002
@@ -738,11 +738,10 @@
 	struct ip_conntrack_protocol *proto;
 	int ret = 1;
 
-	READ_LOCK(&ip_conntrack_lock);
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
 	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
 	if (proto->exp_matches_pkt)
 		ret = proto->exp_matches_pkt(exp, pskb);
-	READ_UNLOCK(&ip_conntrack_lock);
 
 	return ret;
 }
@@ -999,4 +998,5 @@
 {
 	ip_ct_selective_cleanup(&clean_nat, NULL);
 	ip_conntrack_destroyed = NULL;
+	vfree(bysource);
 }
diff -Nru a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
--- a/net/ipv4/netfilter/ip_nat_ftp.c	Tue Aug 27 12:27:59 2002
+++ b/net/ipv4/netfilter/ip_nat_ftp.c	Tue Aug 27 12:27:59 2002
@@ -291,7 +291,7 @@
 {
 	int i;
 
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
 		ip_nat_helper_unregister(&ftp[i]);
 	}
diff -Nru a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c	Tue Aug 27 12:28:02 2002
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c	Tue Aug 27 12:28:02 2002
@@ -52,11 +52,10 @@
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
 #include <linux/brlock.h>
 #include <linux/types.h>
-#include <linux/in.h>
 #include <linux/ip.h>
 #include <net/udp.h>
 #include <asm/uaccess.h>
-#include <net/checksum.h>
+#include <asm/checksum.h>
 
 
 
diff -Nru a/net/ipv4/netfilter/ipfwadm_core.c b/net/ipv4/netfilter/ipfwadm_core.c
--- a/net/ipv4/netfilter/ipfwadm_core.c	Tue Aug 27 12:28:02 2002
+++ b/net/ipv4/netfilter/ipfwadm_core.c	Tue Aug 27 12:28:02 2002
@@ -122,8 +122,10 @@
 #include <net/icmp.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <linux/netfilter_ipv4/ipfwadm_core.h>
 #include <linux/netfilter_ipv4/compat_firewall.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
 
 #include <net/checksum.h>
 #include <linux/proc_fs.h>
@@ -154,6 +156,8 @@
 #define dprint_ip(a)
 #endif
 
+static rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED;
+
 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 
 struct ip_fw *ip_fw_fwd_chain;
@@ -442,6 +446,11 @@
 	dprintf1("\n");
 #endif
 
+	if (mode == IP_FW_MODE_CHK)
+		READ_LOCK(&ip_fw_lock);
+	else
+		WRITE_LOCK(&ip_fw_lock);
+	
 	for (f=chain;f;f=f->fw_next)
 	{
 		/*
@@ -646,7 +655,8 @@
 #ifdef CONFIG_IP_FIREWALL_NETLINK
 		if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK))
 		{
-			struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC);
+			struct sk_buff *skb=alloc_skb(128, (mode == IP_FW_MODE_CHK) ?
+							GFP_KERNEL : GFP_ATOMIC);
 			if(skb)
 			{
 				int len = min_t(unsigned int,
@@ -659,29 +669,36 @@
 			}
 		}
 #endif
-		return answer;
 	} else
 		/* we're doing accounting, always ok */
-		return 0;
+		answer = 0;
+	
+	if (mode == IP_FW_MODE_CHK)
+		READ_UNLOCK(&ip_fw_lock);
+	else
+		WRITE_UNLOCK(&ip_fw_lock);
+
+	return answer;
 }
 
 
 static void zero_fw_chain(struct ip_fw *chainptr)
 {
 	struct ip_fw *ctmp=chainptr;
+	
+	WRITE_LOCK(&ip_fw_lock);
 	while(ctmp)
 	{
 		ctmp->fw_pcnt=0L;
 		ctmp->fw_bcnt=0L;
 		ctmp=ctmp->fw_next;
 	}
+	WRITE_UNLOCK(&ip_fw_lock);
 }
 
 static void free_fw_chain(struct ip_fw *volatile* chainptr)
 {
-	unsigned long flags;
-	save_flags(flags);
-	cli();
+	WRITE_LOCK(&ip_fw_lock);
 	while ( *chainptr != NULL )
 	{
 		struct ip_fw *ftmp;
@@ -690,7 +707,7 @@
 		kfree(ftmp);
 		MOD_DEC_USE_COUNT;
 	}
-	restore_flags(flags);
+	WRITE_UNLOCK(&ip_fw_lock);
 }
 
 /* Volatiles to keep some of the compiler versions amused */
@@ -698,11 +715,8 @@
 static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
 {
 	struct ip_fw *ftmp;
-	unsigned long flags;
-
-	save_flags(flags);
 
-	ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
+	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
 #ifdef DEBUG_IP_FIREWALL
@@ -721,7 +735,7 @@
 	ftmp->fw_pcnt=0L;
 	ftmp->fw_bcnt=0L;
 
-	cli();
+	WRITE_LOCK(&ip_fw_lock);
 
 	if ((ftmp->fw_vianame)[0]) {
 		if (!(ftmp->fw_viadev = dev_get_by_name(ftmp->fw_vianame)))
@@ -731,7 +745,7 @@
 
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
-	restore_flags(flags);
+	WRITE_UNLOCK(&ip_fw_lock);
 	MOD_INC_USE_COUNT;
 	return(0);
 }
@@ -741,11 +755,8 @@
 	struct ip_fw *ftmp;
 	struct ip_fw *chtmp=NULL;
 	struct ip_fw *volatile chtmp_prev=NULL;
-	unsigned long flags;
 
-	save_flags(flags);
-
-	ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
+	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
 #ifdef DEBUG_IP_FIREWALL
@@ -766,7 +777,7 @@
 
 	ftmp->fw_next = NULL;
 
-	cli();
+	WRITE_LOCK(&ip_fw_lock);
 
 	if ((ftmp->fw_vianame)[0]) {
 		if (!(ftmp->fw_viadev = dev_get_by_name(ftmp->fw_vianame)))
@@ -782,7 +793,7 @@
 		chtmp_prev->fw_next=ftmp;
 	else
         	*chainptr=ftmp;
-	restore_flags(flags);
+	WRITE_UNLOCK(&ip_fw_lock);
 	MOD_INC_USE_COUNT;
 	return(0);
 }
@@ -792,10 +803,8 @@
 	struct ip_fw 	*ftmp,*ltmp;
 	unsigned short	tport1,tport2,tmpnum;
 	char		matches,was_found;
-	unsigned long 	flags;
 
-	save_flags(flags);
-	cli();
+	WRITE_LOCK(&ip_fw_lock);
 
 	ftmp=*chainptr;
 
@@ -804,7 +813,7 @@
 #ifdef DEBUG_IP_FIREWALL
 		printk("ip_fw_ctl:  chain is empty\n");
 #endif
-		restore_flags(flags);
+		WRITE_UNLOCK(&ip_fw_lock);
 		return( EINVAL );
 	}
 
@@ -856,7 +865,7 @@
 			ftmp = ftmp->fw_next;
 		 }
 	}
-	restore_flags(flags);
+	WRITE_UNLOCK(&ip_fw_lock);
 	if (was_found) {
 		MOD_DEC_USE_COUNT;
 		return 0;
@@ -1110,7 +1119,6 @@
 {
 	off_t pos=0, begin=0;
 	struct ip_fw *i;
-	unsigned long flags;
 	int len, p;
 	int last_len = 0;
 
@@ -1147,8 +1155,7 @@
 			break;
 	}
 
-	save_flags(flags);
-	cli();
+	READ_LOCK(&ip_fw_lock);
 
 	while(i!=NULL)
 	{
@@ -1177,16 +1184,19 @@
 			len = last_len;
 			break;
 		}
+/* Not possible in 2.3.29+, also allowing read lock instead of write -- JM */
+#if 0
 		else if(reset)
 		{
 			/* This needs to be done at this specific place! */
 			i->fw_pcnt=0L;
 			i->fw_bcnt=0L;
 		}
+#endif
 		last_len = len;
 		i=i->fw_next;
 	}
-	restore_flags(flags);
+	READ_UNLOCK(&ip_fw_lock);
 	*start=buffer+(offset-begin);
 	len-=(offset-begin);
 	if(len>length)
@@ -1329,12 +1339,10 @@
 {
 	struct net_device *dev=ptr;
 	char *devname = dev->name;
-	unsigned long flags;
 	struct ip_fw *fw;
 	int chn;
 
-	save_flags(flags);
-	cli();
+	WRITE_LOCK(&ip_fw_lock);
 
 	if (event == NETDEV_UP) {
 		for (chn = 0; chn < IP_FW_CHAINS; chn++)
@@ -1351,7 +1359,7 @@
 					fw->fw_viadev = (struct net_device*)-1;
 	}
 
-	restore_flags(flags);
+	WRITE_UNLOCK(&ip_fw_lock);
 	return NOTIFY_DONE;
 }
 
diff -Nru a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_DSCP.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,108 @@
+/* iptables module for setting the IPv4 DSCP field, Version 1.8
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_DSCP_info *dinfo = targinfo;
+	u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+
+	if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp;
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+	}
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
+		printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if ((dscp > IPT_DSCP_MAX)) {
+		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_dscp_reg
+= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_dscp_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_dscp_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_ECN.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,184 @@
+/* iptables module for the IPv4 and TCP ECN bits, Version 1.5
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ECN.h>
+
+MODULE_LICENSE("GPL");
+
+/* set ECT codepoint from IP header.
+ * 	return 0 in case there was no ECT codepoint
+ * 	return 1 in case ECT codepoint has been overwritten
+ * 	return < 0 in case there was error */
+static int inline
+set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
+	   const struct ipt_ECN_info *einfo)
+{
+	if ((iph->tos & IPT_ECN_IP_MASK)
+	    != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
+		iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	} 
+	return 0;
+}
+
+static int inline
+set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
+	    const struct ipt_ECN_info *einfo)
+{
+
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
+	u_int16_t diffs[2];
+
+	/* raw socket (tcpdump) may have clone of incoming
+	 * skb: don't disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+		iph = (*pskb)->nh.iph;
+	}
+
+	diffs[0] = *tcpflags;
+
+	if (einfo->operation & IPT_ECN_OP_SET_ECE
+	    && tcph->ece != einfo->proto.tcp.ece) {
+		tcph->ece = einfo->proto.tcp.ece;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_SET_CWR
+	    && tcph->cwr != einfo->proto.tcp.cwr) {
+		tcph->cwr = einfo->proto.tcp.cwr;
+	}
+	
+	if (diffs[0] != *tcpflags) {
+		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
+		diffs[1] = htons(*tcpflags);
+		tcph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    tcph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_ECN_info *einfo = targinfo;
+
+	if (einfo->operation & IPT_ECN_OP_SET_IP)
+		set_ect_ip(pskb, iph, einfo);
+
+	if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
+	    && iph->protocol == IPPROTO_TCP)
+		set_ect_tcp(pskb, iph, einfo);
+
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
+		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_ECN_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MASK) {
+		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
+			einfo->operation);
+		return 0;
+	}
+	if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
+		printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
+			einfo->ip_ect);
+		return 0;
+	}
+
+	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
+	    && e->ip.proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
+		       "non-tcp rule\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ecn_reg
+= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_ecn_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_ecn_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
--- a/net/ipv4/netfilter/ipt_REJECT.c	Tue Aug 27 12:28:02 2002
+++ b/net/ipv4/netfilter/ipt_REJECT.c	Tue Aug 27 12:28:02 2002
@@ -39,7 +39,8 @@
 	struct tcphdr *otcph, *tcph;
 	struct rtable *rt;
 	unsigned int otcplen;
-	u_int16_t tmp;
+	u_int16_t tmp_port;
+	u_int32_t tmp_addr;
 	int needs_ack;
 
 	/* IP header checks: fragment, too short. */
@@ -74,14 +75,17 @@
 #ifdef CONFIG_NETFILTER_DEBUG
 	nskb->nf_debug = 0;
 #endif
+	nskb->nfmark = 0;
 
 	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
 
 	/* Swap source and dest */
-	nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
-	tmp = tcph->source;
+	tmp_addr = nskb->nh.iph->saddr;
+	nskb->nh.iph->saddr = nskb->nh.iph->daddr;
+	nskb->nh.iph->daddr = tmp_addr;
+	tmp_port = tcph->source;
 	tcph->source = tcph->dest;
-	tcph->dest = tmp;
+	tcph->dest = tmp_port;
 
 	/* Truncate to length (no data) */
 	tcph->doff = sizeof(struct tcphdr)/4;
diff -Nru a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
--- a/net/ipv4/netfilter/ipt_ah.c	Tue Aug 27 12:28:07 2002
+++ b/net/ipv4/netfilter/ipt_ah.c	Tue Aug 27 12:28:07 2002
@@ -5,6 +5,7 @@
 #include <linux/netfilter_ipv4/ipt_ah.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
+EXPORT_NO_SYMBOLS;
 MODULE_LICENSE("GPL");
 
 #ifdef DEBUG_CONNTRACK
@@ -90,12 +91,12 @@
 static struct ipt_match ah_match
 = { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
 
-int __init init(void)
+static int __init init(void)
 {
 	return ipt_register_match(&ah_match);
 }
 
-void __exit cleanup(void)
+static void __exit cleanup(void)
 {
 	ipt_unregister_match(&ah_match);
 }
diff -Nru a/net/ipv4/netfilter/ipt_conntrack.c b/net/ipv4/netfilter/ipt_conntrack.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_conntrack.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,123 @@
+/* Kernel module to match connection tracking information.
+ * Superset of Rusty's minimalistic state match.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_conntrack.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_conntrack_info *sinfo = matchinfo;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned int statebit;
+
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+	statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo);
+	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+		if (ct) {
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
+				statebit |= IPT_CONNTRACK_STATE_SNAT;
+
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
+				statebit |= IPT_CONNTRACK_STATE_DNAT;
+		}
+
+		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+                	return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+		unsigned long expires;
+
+		if(!ct)
+			return 0;
+
+		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match conntrack_match
+= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&conntrack_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&conntrack_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_dscp.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,58 @@
+/* IP tables module for matching the value of the IPv4 DSCP field
+ *
+ * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms  GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP matching module");
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_dscp_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&dscp_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&dscp_match);
+
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_ecn.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,118 @@
+/* IP tables module for matching the value of the IPv4 and TCP ECN bits
+ *
+ * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms GNU GPL v2
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ecn.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables ECN matching module");
+MODULE_LICENSE("GPL");
+
+static inline int match_ip(const struct sk_buff *skb,
+			   const struct iphdr *iph,
+			   const struct ipt_ecn_info *einfo)
+{
+	return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
+}
+
+static inline int match_tcp(const struct sk_buff *skb,
+			    const struct iphdr *iph,
+			    const struct ipt_ecn_info *einfo)
+{
+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
+			if (tcph->ece == 1)
+				return 0;
+		} else {
+			if (tcph->ece == 0)
+				return 0;
+		}
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
+			if (tcph->cwr == 1)
+				return 0;
+		} else {
+			if (tcph->cwr == 0)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	if (info->operation & IPT_ECN_OP_MATCH_IP)
+		if (!match_ip(skb, iph, info))
+			return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
+		if (iph->protocol != IPPROTO_TCP)
+			return 0;
+		if (!match_tcp(skb, iph, info))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
+		return 0;
+
+	if (info->operation & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->invert & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
+	    && ip->proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
+		       " non-tcp packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&ecn_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&ecn_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
--- a/net/ipv4/netfilter/ipt_esp.c	Tue Aug 27 12:28:06 2002
+++ b/net/ipv4/netfilter/ipt_esp.c	Tue Aug 27 12:28:06 2002
@@ -5,6 +5,7 @@
 #include <linux/netfilter_ipv4/ipt_esp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
+EXPORT_NO_SYMBOLS;
 MODULE_LICENSE("GPL");
 
 #ifdef DEBUG_CONNTRACK
diff -Nru a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_helper.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,112 @@
+/*
+ * iptables module to match on related connections
+ *   (c) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * Released under the terms of GNU GPLv2.
+ *
+ *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *   		 - Port to newnat infrastructure
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_helper.h>
+
+MODULE_LICENSE("GPL");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_helper_info *info = matchinfo;
+	struct ip_conntrack_expect *exp;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+	if (!ct) {
+		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		return 0;
+	}
+
+	if (!ct->master) {
+		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		return 0;
+	}
+
+	exp = ct->master;
+	if (!exp->expectant) {
+		DEBUGP("ipt_helper: expectation %p without expectant !?!\n", 
+			exp);
+		return 0;
+	}
+
+	if (!exp->expectant->helper) {
+		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+			exp->expectant);
+		return 0;
+	}
+
+	DEBUGP("master's name = %s , info->name = %s\n", 
+		exp->expectant->helper->name, info->name);
+
+	return !strncmp(exp->expectant->helper->name, info->name, 
+			strlen(exp->expectant->helper->name)) ^ info->invert;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	struct ipt_helper_info *info = matchinfo;
+
+	info->name[29] = '\0';
+
+	/* verify size */
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
+		return 0;
+
+	/* verify that we actually should match anything */
+	if ( strlen(info->name) == 0 )
+		return 0;
+	
+	return 1;
+}
+
+static struct ipt_match helper_match
+= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&helper_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&helper_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+
diff -Nru a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
--- a/net/ipv4/netfilter/ipt_owner.c	Tue Aug 27 12:28:08 2002
+++ b/net/ipv4/netfilter/ipt_owner.c	Tue Aug 27 12:28:08 2002
@@ -12,6 +12,38 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 static int
+match_comm(const struct sk_buff *skb, const char *comm)
+{
+	struct task_struct *p;
+	struct files_struct *files;
+	int i;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(strncmp(p->comm, comm, sizeof(p->comm)))
+			continue;
+
+		task_lock(p);
+		files = p->files;
+		if(files) {
+			read_lock(&files->file_lock);
+			for (i=0; i < files->max_fds; i++) {
+				if (fcheck_files(files, i) == skb->sk->socket->file) {
+					read_unlock(&files->file_lock);
+					task_unlock(p);
+					read_unlock(&tasklist_lock);
+					return 1;
+				}
+			}
+			read_unlock(&files->file_lock);
+		}
+		task_unlock(p);
+	}
+	read_unlock(&tasklist_lock);
+	return 0;
+}
+
+static int
 match_pid(const struct sk_buff *skb, pid_t pid)
 {
 	struct task_struct *p;
@@ -112,6 +144,12 @@
 	if(info->match & IPT_OWNER_SID) {
 		if (!match_sid(skb, info->sid) ^
 		    !!(info->invert & IPT_OWNER_SID))
+			return 0;
+	}
+
+	if(info->match & IPT_OWNER_COMM) {
+		if (!match_comm(skb, info->comm) ^
+		    !!(info->invert & IPT_OWNER_COMM))
 			return 0;
 	}
 
diff -Nru a/net/ipv4/netfilter/ipt_pkttype.c b/net/ipv4/netfilter/ipt_pkttype.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ipt_pkttype.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,59 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <linux/netfilter_ipv4/ipt_pkttype.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+    const struct ipt_pkttype_info *info = matchinfo;
+
+    return (skb->pkt_type == info->pkttype) ^ info->invert;
+}
+
+static int checkentry(const char *tablename,
+		   const struct ipt_ip *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+/*
+	if (hook_mask
+	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
+		| (1 << NF_IP_FORWARD))) {
+		printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+*/
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match pkttype_match
+= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&pkttype_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&pkttype_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
--- a/net/ipv4/tcp_diag.c	Tue Aug 27 12:27:51 2002
+++ b/net/ipv4/tcp_diag.c	Tue Aug 27 12:27:51 2002
@@ -66,7 +66,8 @@
 	r->tcpdiag_retrans = 0;
 
 	r->id.tcpdiag_if = sk->bound_dev_if;
-	*((struct sock **)&r->id.tcpdiag_cookie) = sk;
+	r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk;
+	r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
 
 	if (r->tcpdiag_state == TCP_TIME_WAIT) {
 		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
@@ -237,7 +238,8 @@
 	err = -ESTALE;
 	if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
 	     req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
-	    sk != *((struct sock **)&req->id.tcpdiag_cookie[0]))
+	    ((u32)(unsigned long)sk != req->id.tcpdiag_cookie[0] ||
+	     (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.tcpdiag_cookie[1]))
 		goto out;
 
 	err = -ENOMEM;
diff -Nru a/net/ipv6/netfilter/Config.help b/net/ipv6/netfilter/Config.help
--- a/net/ipv6/netfilter/Config.help	Tue Aug 27 12:28:01 2002
+++ b/net/ipv6/netfilter/Config.help	Tue Aug 27 12:28:01 2002
@@ -1,9 +1,24 @@
+CONFIG_IP6_NF_MATCH_EUI64
+  This module performs checking on the IPv6 source address
+  Compares the last 64 bits with the EUI64 (delivered
+  from the MAC address) address
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 CONFIG_IP6_NF_MATCH_MAC
   mac matching allows you to match packets based on the source
   Ethernet address of the packet.
 
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_MATCH_LENGTH
+  This option allows you to match the length of a packet against a
+  specific value or range of values.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
 
 CONFIG_IP6_NF_MATCH_MARK
   Netfilter mark matching allows you to match packets based on the
diff -Nru a/net/ipv6/netfilter/Config.in b/net/ipv6/netfilter/Config.in
--- a/net/ipv6/netfilter/Config.in	Tue Aug 27 12:27:59 2002
+++ b/net/ipv6/netfilter/Config.in	Tue Aug 27 12:27:59 2002
@@ -24,6 +24,10 @@
   fi
 #  dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES
+  dep_tristate '  Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES
+  fi
 #  dep_tristate '  Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
 #  dep_tristate '  TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
 #  if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
diff -Nru a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
--- a/net/ipv6/netfilter/Makefile	Tue Aug 27 12:27:57 2002
+++ b/net/ipv6/netfilter/Makefile	Tue Aug 27 12:27:57 2002
@@ -8,7 +8,9 @@
 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
+obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
diff -Nru a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
--- a/net/ipv6/netfilter/ip6_queue.c	Tue Aug 27 12:28:02 2002
+++ b/net/ipv6/netfilter/ip6_queue.c	Tue Aug 27 12:28:02 2002
@@ -15,7 +15,7 @@
  *             real coder of this.
  *             Few changes needed, mainly the hard_routing code and
  *             the netlink socket protocol (we're NETLINK_IP6_FW).
- *
+ * 2002-06-25: Code cleanup. [JM: ported cleanup over from ip_queue.c]
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -26,18 +26,12 @@
 #include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
-
-/* We're still usign the following structs. No need to change them: */
-/*   ipq_packet_msg                                                 */
-/*   ipq_mode_msg                                                   */
-/*   ipq_verdict_msg                                                */
-/*   ipq_peer_msg                                                   */
 #include <linux/netfilter_ipv4/ip_queue.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
@@ -47,184 +41,289 @@
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
-typedef struct ip6q_rt_info {
+struct ipq_rt_info {
 	struct in6_addr daddr;
 	struct in6_addr saddr;
-} ip6q_rt_info_t;
+};
 
-typedef struct ip6q_queue_element {
-	struct list_head list;		/* Links element into queue */
-	int verdict;			/* Current verdict */
-	struct nf_info *info;		/* Extra info from netfilter */
-	struct sk_buff *skb;		/* Packet inside */
-	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
-} ip6q_queue_element_t;
-
-typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
-
-typedef struct ip6q_peer {
-	pid_t pid;			/* PID of userland peer */
-	unsigned char died;		/* We think the peer died */
-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
-	size_t copy_range;		/* Range past metadata to copy */
-	ip6q_send_cb_t send;		/* Callback for sending data to peer */
-} ip6q_peer_t;
-
-typedef struct ip6q_queue {
- 	int len;			/* Current queue len */
- 	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char flushing;		/* If queue is being flushed */
- 	unsigned char terminate;	/* If the queue is being terminated */
- 	struct list_head list;		/* Head of packet queue */
- 	spinlock_t lock;		/* Queue spinlock */
- 	ip6q_peer_t peer;		/* Userland peer */
-} ip6q_queue_t;
+struct ipq_queue_entry {
+	struct list_head list;
+	struct nf_info *info;
+	struct sk_buff *skb;
+	struct ipq_rt_info rt_info;
+};
 
-/****************************************************************************
- *
- * Packet queue
- *
- ****************************************************************************/
-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
-static ip6q_queue_element_t *
-ip6q_dequeue(ip6q_queue_t *q,
-            int (*cmp)(ip6q_queue_element_t *, unsigned long),
-            unsigned long data)
-{
-	struct list_head *i;
-
-	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
-		
-		if (!cmp || cmp(e, data)) {
-			list_del(&e->list);
-			q->len--;
-			spin_unlock_bh(&q->lock);
-			return e;
-		}
+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+static unsigned char copy_mode = IPQ_COPY_NONE;
+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
+static int peer_pid;
+static unsigned int copy_range;
+static unsigned int queue_total;
+static struct sock *ipqnl;
+static LIST_HEAD(queue_list);
+static DECLARE_MUTEX(ipqnl_sem);
+
+static void
+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
+{
+	nf_reinject(entry->skb, entry->info, verdict);
+	kfree(entry);
+}
+
+static inline int
+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+{
+       if (queue_total >= queue_maxlen) {
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip6_queue: full at %d entries, "
+                              "dropping packet(s).\n", queue_total);
+               return -ENOSPC;
+       }
+       list_add(&entry->list, &queue_list);
+       queue_total++;
+       return 0;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct ipq_queue_entry *
+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct list_head *p;
+
+	list_for_each_prev(p, &queue_list) {
+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
+		
+		if (!cmpfn || cmpfn(entry, data))
+			return entry;
 	}
-	spin_unlock_bh(&q->lock);
 	return NULL;
 }
 
-/* Flush all packets */
-static void ip6q_flush(ip6q_queue_t *q)
+static inline void
+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
 {
-	ip6q_queue_element_t *e;
-	
-	spin_lock_bh(&q->lock);
-	q->flushing = 1;
-	spin_unlock_bh(&q->lock);
-	while ((e = ip6q_dequeue(q, NULL, 0))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-	spin_lock_bh(&q->lock);
-	q->flushing = 0;
-	spin_unlock_bh(&q->lock);
-}
-
-static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
-                                     ip6q_send_cb_t send_cb,
-                                     int *errp, int *sysctl_qmax)
+	list_del(&entry->list);
+	queue_total--;
+}
+
+static inline struct ipq_queue_entry *
+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
 {
-	int status;
-	ip6q_queue_t *q;
+	struct ipq_queue_entry *entry;
 
-	*errp = 0;
-	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
-	if (q == NULL) {
-		*errp = -ENOMEM;
+	entry = __ipq_find_entry(cmpfn, data);
+	if (entry == NULL)
 		return NULL;
+
+	__ipq_dequeue_entry(entry);
+	return entry;
+}
+
+
+static inline void
+__ipq_flush(int verdict)
+{
+	struct ipq_queue_entry *entry;
+	
+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
+		ipq_issue_verdict(entry, verdict);
+}
+
+static inline int
+__ipq_set_mode(unsigned char mode, unsigned int range)
+{
+	int status = 0;
+	
+	switch(mode) {
+	case IPQ_COPY_NONE:
+	case IPQ_COPY_META:
+		copy_mode = mode;
+		copy_range = 0;
+		break;
+		
+	case IPQ_COPY_PACKET:
+		copy_mode = mode;
+		copy_range = range;
+		if (copy_range > 0xFFFF)
+			copy_range = 0xFFFF;
+		break;
+		
+	default:
+		status = -EINVAL;
+
 	}
-	q->peer.pid = 0;
-	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_NONE;
-	q->peer.copy_range = 0;
-	q->peer.send = send_cb;
-	q->len = 0;
-	q->maxlen = sysctl_qmax;
-	q->flushing = 0;
-	q->terminate = 0;
-	INIT_LIST_HEAD(&q->list);
-	spin_lock_init(&q->lock);
-	status = nf_register_queue_handler(PF_INET6, outfn, q);
-	if (status < 0) {
-		*errp = -EBUSY;
-		kfree(q);
+	return status;
+}
+
+static inline void
+__ipq_reset(void)
+{
+	peer_pid = 0;
+	__ipq_set_mode(IPQ_COPY_NONE, 0);
+	__ipq_flush(NF_DROP);
+}
+
+static struct ipq_queue_entry *
+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct ipq_queue_entry *entry;
+	
+	write_lock_bh(&queue_lock);
+	entry = __ipq_find_dequeue_entry(cmpfn, data);
+	write_unlock_bh(&queue_lock);
+	return entry;
+}
+
+static void
+ipq_flush(int verdict)
+{
+	write_lock_bh(&queue_lock);
+	__ipq_flush(verdict);
+	write_unlock_bh(&queue_lock);
+}
+
+static struct sk_buff *
+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct ipq_packet_msg *pmsg;
+	struct nlmsghdr *nlh;
+
+	read_lock_bh(&queue_lock);
+	
+	switch (copy_mode) {
+	case IPQ_COPY_META:
+	case IPQ_COPY_NONE:
+		size = NLMSG_SPACE(sizeof(*pmsg));
+		data_len = 0;
+		break;
+	
+	case IPQ_COPY_PACKET:
+		if (copy_range == 0 || copy_range > entry->skb->len)
+			data_len = entry->skb->len;
+		else
+			data_len = copy_range;
+		
+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
+		break;
+	
+	default:
+		*errp = -EINVAL;
+		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
-	return q;
+
+	read_unlock_bh(&queue_lock);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+		
+	old_tail= skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pmsg = NLMSG_DATA(nlh);
+	memset(pmsg, 0, sizeof(*pmsg));
+
+	pmsg->packet_id       = (unsigned long )entry;
+	pmsg->data_len        = data_len;
+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+	pmsg->mark            = entry->skb->nfmark;
+	pmsg->hook            = entry->info->hook;
+	pmsg->hw_protocol     = entry->skb->protocol;
+	
+	if (entry->info->indev)
+		strcpy(pmsg->indev_name, entry->info->indev->name);
+	else
+		pmsg->indev_name[0] = '\0';
+	
+	if (entry->info->outdev)
+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
+	else
+		pmsg->outdev_name[0] = '\0';
+	
+	if (entry->info->indev && entry->skb->dev) {
+		pmsg->hw_type = entry->skb->dev->type;
+		if (entry->skb->dev->hard_header_parse)
+			pmsg->hw_addrlen =
+				entry->skb->dev->hard_header_parse(entry->skb,
+				                                   pmsg->hw_addr);
+	}
+	
+	if (data_len)
+		memcpy(pmsg->payload, entry->skb->data, data_len);
+		
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -EINVAL;
+	printk(KERN_ERR "ip6_queue: error creating packet message\n");
+	return NULL;
 }
 
-static int ip6q_enqueue(ip6q_queue_t *q,
-                       struct sk_buff *skb, struct nf_info *info)
+static int
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
 {
-	ip6q_queue_element_t *e;
-	int status;
-	
-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
-	if (e == NULL) {
-		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+	int status = -EINVAL;
+	struct sk_buff *nskb;
+	struct ipq_queue_entry *entry;
+
+	if (copy_mode == IPQ_COPY_NONE)
+		return -EAGAIN;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n");
 		return -ENOMEM;
 	}
 
-	e->verdict = NF_DROP;
-	e->info = info;
-	e->skb = skb;
+	entry->info = info;
+	entry->skb = skb;
 
-	if (e->info->hook == NF_IP_LOCAL_OUT) {
+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
 		struct ipv6hdr *iph = skb->nh.ipv6h;
 
-		e->rt_info.daddr = iph->daddr;
-		e->rt_info.saddr = iph->saddr;
+		entry->rt_info.daddr = iph->daddr;
+		entry->rt_info.saddr = iph->saddr;
 	}
 
-	spin_lock_bh(&q->lock);
-	if (q->len >= *q->maxlen) {
-		spin_unlock_bh(&q->lock);
-		if (net_ratelimit()) 
-			printk(KERN_WARNING "ip6_queue: full at %d entries, "
-			       "dropping packet(s).\n", q->len);
-		goto free_drop;
-	}
-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
-		spin_unlock_bh(&q->lock);
-		goto free_drop;
-	}
-	status = q->peer.send(e);
-	if (status > 0) {
-		list_add(&e->list, &q->list);
-		q->len++;
-		spin_unlock_bh(&q->lock);
-		return status;
-	}
-	spin_unlock_bh(&q->lock);
-	if (status == -ECONNREFUSED) {
-		printk(KERN_INFO "ip6_queue: peer %d died, "
-		       "resetting state and flushing queue\n", q->peer.pid);
-			q->peer.died = 1;
-			q->peer.pid = 0;
-			q->peer.copy_mode = IPQ_COPY_NONE;
-			q->peer.copy_range = 0;
-			ip6q_flush(q);
-	}
-free_drop:
-	kfree(e);
-	return -EBUSY;
-}
+	nskb = ipq_build_packet_message(entry, &status);
+	if (nskb == NULL)
+		goto err_out_free;
+		
+	write_lock_bh(&queue_lock);
+	
+	if (!peer_pid)
+		goto err_out_unlock;
 
-static void ip6q_destroy_queue(ip6q_queue_t *q)
-{
-	nf_unregister_queue_handler(PF_INET6);
-	spin_lock_bh(&q->lock);
-	q->terminate = 1;
-	spin_unlock_bh(&q->lock);
-	ip6q_flush(q);
-	kfree(q);
+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
+	if (status < 0)
+		goto err_out_unlock;
+	
+	status = __ipq_enqueue_entry(entry);
+	if (status < 0)
+		goto err_out_unlock;
+
+	write_unlock_bh(&queue_lock);
+	return status;
+	
+err_out_unlock:
+	write_unlock_bh(&queue_lock);
+
+err_out_free:
+	kfree(entry);
+	return status;
 }
 
 /*
@@ -236,7 +335,8 @@
  *
  * If that one is modified, this one should be modified too.
  */
-static int route6_me_harder(struct sk_buff *skb)
+static int
+route6_me_harder(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = skb->nh.ipv6h;
 	struct dst_entry *dst;
@@ -264,7 +364,9 @@
 	skb->dst = dst;
 	return 0;
 }
-static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+
+static int
+ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
 	int diff;
 	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
@@ -319,344 +421,255 @@
 	return 0;
 }
 
-static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+static inline int
+id_cmp(struct ipq_queue_entry *e, unsigned long id)
 {
 	return (id == (unsigned long )e);
 }
 
-static int ip6q_set_verdict(ip6q_queue_t *q,
-                           ipq_verdict_msg_t *v, unsigned int len)
+static int
+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 
-	if (v->value > NF_MAX_VERDICT)
+	if (vmsg->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	e = ip6q_dequeue(q, id_cmp, v->id);
-	if (e == NULL)
+
+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
+	if (entry == NULL)
 		return -ENOENT;
 	else {
-		e->verdict = v->value;
-		if (v->data_len && v->data_len == len)
-			if (ip6q_mangle_ipv6(v, e) < 0)
-				e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
+		int verdict = vmsg->value;
+		
+		if (vmsg->data_len && vmsg->data_len == len)
+			if (ipq_mangle_ipv6(vmsg, entry) < 0)
+				verdict = NF_DROP;
+		
+		ipq_issue_verdict(entry, verdict);
 		return 0;
 	}
 }
 
-static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
-                            unsigned char type, unsigned int len)
+static int
+ipq_set_mode(unsigned char mode, unsigned int range)
 {
+	int status;
+
+	write_lock_bh(&queue_lock);
+	status = __ipq_set_mode(mode, range);
+	write_unlock_bh(&queue_lock);
+	return status;
+}
 
+static int
+ipq_receive_peer(struct ipq_peer_msg *pmsg,
+                 unsigned char type, unsigned int len)
+{
 	int status = 0;
-	int busy;
-		
-	spin_lock_bh(&q->lock);
-	busy = (q->terminate || q->flushing);
-	spin_unlock_bh(&q->lock);
-	if (busy)
-		return -EBUSY;
-	if (len < sizeof(ipq_peer_msg_t))
+
+	if (len < sizeof(*pmsg))
 		return -EINVAL;
+
 	switch (type) {
-		case IPQM_MODE:
-			switch (m->msg.mode.value) {
-				case IPQ_COPY_META:
-					q->peer.copy_mode = IPQ_COPY_META;
-					q->peer.copy_range = 0;
-					break;
-				case IPQ_COPY_PACKET:
-					q->peer.copy_mode = IPQ_COPY_PACKET;
-					q->peer.copy_range = m->msg.mode.range;
-					if (q->peer.copy_range > 0xFFFF)
-						q->peer.copy_range = 0xFFFF;
-					break;
-				default:
-					status = -EINVAL;
-			}
-			break;
-		case IPQM_VERDICT:
-			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				status = -EINVAL;
-			else
-				status = ip6q_set_verdict(q,
-				                         &m->msg.verdict,
-				                         len - sizeof(*m));
+	case IPQM_MODE:
+		status = ipq_set_mode(pmsg->msg.mode.value,
+		                      pmsg->msg.mode.range);
+		break;
+		
+	case IPQM_VERDICT:
+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
+			status = -EINVAL;
+		else
+			status = ipq_set_verdict(&pmsg->msg.verdict,
+			                         len - sizeof(*pmsg));
 			break;
-		default:
-			 status = -EINVAL;
+	default:
+		status = -EINVAL;
 	}
 	return status;
 }
 
-static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+static int
+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
 {
-	if (e->info->indev)
-		if (e->info->indev->ifindex == ifindex)
+	if (entry->info->indev)
+		if (entry->info->indev->ifindex == ifindex)
 			return 1;
-	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex)
+			
+	if (entry->info->outdev)
+		if (entry->info->outdev->ifindex == ifindex)
 			return 1;
+
 	return 0;
 }
 
-/* Drop any queued packets associated with device ifindex */
-static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+static void
+ipq_dev_drop(int ifindex)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 	
-	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-}
-
-/****************************************************************************
- *
- * Netfilter interface
- *
- ****************************************************************************/
-
-/*
- * Packets arrive here from netfilter for queuing to userspace.
- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
- */
-static int netfilter6_receive(struct sk_buff *skb,
-                             struct nf_info *info, void *data)
-{
-	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
-}
-
-/****************************************************************************
- *
- * Netlink interface.
- *
- ****************************************************************************/
-
-static struct sock *nfnl = NULL;
-/* This is not a static one, so we should not repeat its name */
-ip6q_queue_t *nlq6 = NULL;
-
-static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
-{
-	unsigned char *old_tail;
-	size_t size = 0;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	ipq_packet_msg_t *pm;
-	struct nlmsghdr *nlh;
-
-	switch (nlq6->peer.copy_mode) {
-		size_t copy_range;
-
-		case IPQ_COPY_META:
-			size = NLMSG_SPACE(sizeof(*pm));
-			data_len = 0;
-			break;
-		case IPQ_COPY_PACKET:
-			copy_range = nlq6->peer.copy_range;
-			if (copy_range == 0 || copy_range > e->skb->len)
-				data_len = e->skb->len;
-			else
-				data_len = copy_range;
-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
-			
-			break;
-		case IPQ_COPY_NONE:
-		default:
-			*errp = -EINVAL;
-			return NULL;
-	}
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
-	pm = NLMSG_DATA(nlh);
-	memset(pm, 0, sizeof(*pm));
-	pm->packet_id = (unsigned long )e;
-	pm->data_len = data_len;
-	pm->timestamp_sec = e->skb->stamp.tv_sec;
-	pm->timestamp_usec = e->skb->stamp.tv_usec;
-	pm->mark = e->skb->nfmark;
-	pm->hook = e->info->hook;
-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
-	else pm->indev_name[0] = '\0';
-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
-	else pm->outdev_name[0] = '\0';
-	pm->hw_protocol = e->skb->protocol;
-	if (e->info->indev && e->skb->dev) {
-		pm->hw_type = e->skb->dev->type;
-		if (e->skb->dev->hard_header_parse)
-			pm->hw_addrlen =
-				e->skb->dev->hard_header_parse(e->skb,
-				                               pm->hw_addr);
-	}
-	if (data_len)
-		memcpy(pm->payload, e->skb->data, data_len);
-	nlh->nlmsg_len = skb->tail - old_tail;
-	NETLINK_CB(skb).dst_groups = 0;
-	return skb;
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-	*errp = 0;
-	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
-	return NULL;
-}
-
-static int netlink_send_peer(ip6q_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
+		ipq_issue_verdict(entry, NF_DROP);
 }
 
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+static inline void
+ipq_rcv_skb(struct sk_buff *skb)
 {
-	int status, type;
+	int status, type, pid, flags, nlmsglen, skblen;
 	struct nlmsghdr *nlh;
 
-	if (skb->len < sizeof(struct nlmsghdr))
+	skblen = skb->len;
+	if (skblen < sizeof(*nlh))
 		return;
 
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-	    || skb->len < nlh->nlmsg_len)
-	    	return;
-
-	if(nlh->nlmsg_pid <= 0
-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
-	    || nlh->nlmsg_flags & NLM_F_MULTI)
+	nlmsglen = nlh->nlmsg_len;
+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
+		return;
+
+	pid = nlh->nlmsg_pid;
+	flags = nlh->nlmsg_flags;
+	
+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
-	if (nlh->nlmsg_flags & MSG_TRUNC)
+		
+	if (flags & MSG_TRUNC)
 		RCV_SKB_FAIL(-ECOMM);
+		
 	type = nlh->nlmsg_type;
 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
 		RCV_SKB_FAIL(-EINVAL);
+		
 	if (type <= IPQM_BASE)
 		return;
+		
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
-	if (nlq6->peer.pid && !nlq6->peer.died
-	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
-	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
-	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
-		ip6q_flush(nlq6);
-	}	
-	nlq6->peer.pid = nlh->nlmsg_pid;
-	nlq6->peer.died = 0;
-	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
-	                          type, skb->len - NLMSG_LENGTH(0));
+	
+	write_lock_bh(&queue_lock);
+	
+	if (peer_pid) {
+		if (peer_pid != pid) {
+			write_unlock_bh(&queue_lock);
+			RCV_SKB_FAIL(-EBUSY);
+		}
+	}
+	else
+		peer_pid = pid;
+		
+	write_unlock_bh(&queue_lock);
+	
+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
+	                          skblen - NLMSG_LENGTH(0));
 	if (status < 0)
 		RCV_SKB_FAIL(status);
-	if (nlh->nlmsg_flags & NLM_F_ACK)
+		
+	if (flags & NLM_F_ACK)
 		netlink_ack(skb, nlh, 0);
         return;
 }
 
-/* Note: we are only dealing with single part messages at the moment. */
-static void netlink_receive_user_sk(struct sock *sk, int len)
+static void
+ipq_rcv_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
+		if (down_trylock(&ipqnl_sem))
 			return;
+			
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			netlink_receive_user_skb(skb);
+			ipq_rcv_skb(skb);
 			kfree_skb(skb);
 		}
-		up(&rtnl_sem);
-	} while (nfnl && nfnl->receive_queue.qlen);
-}
+		
+		up(&ipqnl_sem);
 
-/****************************************************************************
- *
- * System events
- *
- ****************************************************************************/
+	} while (ipqnl && ipqnl->receive_queue.qlen);
+}
 
-static int receive_event(struct notifier_block *this,
-                         unsigned long event, void *ptr)
+static int
+ipq_rcv_dev_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
 
 	/* Drop any packets associated with the downed device */
 	if (event == NETDEV_DOWN)
-		ip6q_dev_drop(nlq6, dev->ifindex);
+		ipq_dev_drop(dev->ifindex);
 	return NOTIFY_DONE;
 }
 
-struct notifier_block ip6q_dev_notifier = {
-	receive_event,
+static struct notifier_block ipq_dev_notifier = {
+	ipq_rcv_dev_event,
 	NULL,
 	0
 };
 
-/****************************************************************************
- *
- * Sysctl - queue tuning.
- *
- ****************************************************************************/
+static int
+ipq_rcv_nl_event(struct notifier_block *this,
+                 unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE &&
+	    n->protocol == NETLINK_IP6_FW && n->pid) {
+		write_lock_bh(&queue_lock);
+		if (n->pid == peer_pid)
+			__ipq_reset();
+		write_unlock_bh(&queue_lock);
+	}
+	return NOTIFY_DONE;
+}
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct notifier_block ipq_nl_notifier = {
+	ipq_rcv_nl_event,
+	NULL,
+	0
+};
 
-static struct ctl_table_header *ip6q_sysctl_header;
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct ctl_table_header *ipq_sysctl_header;
 
-static ctl_table ip6q_table[] = {
+static ctl_table ipq_table[] = {
 	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
 	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
  	{ 0 }
 };
 
-static ctl_table ip6q_dir_table[] = {
-	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ipq_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-static ctl_table ip6q_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ipq_dir_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-/****************************************************************************
- *
- * Procfs - debugging info.
- *
- ****************************************************************************/
-
-static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+static int
+ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
-	spin_lock_bh(&nlq6->lock);
+	read_lock_bh(&queue_lock);
+	
 	len = sprintf(buffer,
-	              "Peer pid            : %d\n"
-	              "Peer died           : %d\n"
-	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %Zu\n"
-	              "Queue length        : %d\n"
-	              "Queue max. length   : %d\n"
-	              "Queue flushing      : %d\n"
-	              "Queue terminate     : %d\n",
-	              nlq6->peer.pid,
-	              nlq6->peer.died,
-	              nlq6->peer.copy_mode,
-	              nlq6->peer.copy_range,
-	              nlq6->len,
-	              *nlq6->maxlen,
-	              nlq6->flushing,
-	              nlq6->terminate);
-	spin_unlock_bh(&nlq6->lock);
+	              "Peer PID          : %d\n"
+	              "Copy mode         : %hu\n"
+	              "Copy range        : %u\n"
+	              "Queue length      : %u\n"
+	              "Queue max. length : %u\n",
+	              peer_pid,
+	              copy_mode,
+	              copy_range,
+	              queue_total,
+	              queue_maxlen);
+
+	read_unlock_bh(&queue_lock);
+	
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
@@ -666,52 +679,70 @@
 	return len;
 }
 
-/****************************************************************************
- *
- * Module stuff.
- *
- ****************************************************************************/
-
-static int __init init(void)
+static int
+init_or_cleanup(int init)
 {
-	int status = 0;
+	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-        /* We must create the NETLINK_IP6_FW protocol service */
-	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
-	if (nfnl == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create kernel netlink socket\n");
-		return -ENOMEM;
+	if (!init)
+		goto cleanup;
+
+	netlink_register_notifier(&ipq_nl_notifier);
+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
+	if (ipqnl == NULL) {
+		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
 	}
-	nlq6 = ip6q_create_queue(netfilter6_receive,
-	                       netlink_send_peer, &status, &sysctl_maxlen);
-	if (nlq6 == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create queue\n");
-		sock_release(nfnl->socket);
-		return status;
-	}
-        /* The file will be /proc/net/ip6_queue */
-	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
-	if (proc) proc->owner = THIS_MODULE;
+
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
+	if (proc)
+		proc->owner = THIS_MODULE;
 	else {
-		ip6q_destroy_queue(nlq6);
-		sock_release(nfnl->socket);
-		return -ENOMEM;
+		printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
+		goto cleanup_ipqnl;
+	}
+	
+	register_netdevice_notifier(&ipq_dev_notifier);
+	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
+	
+	status = nf_register_queue_handler(PF_INET6, ipq_enqueue_packet, NULL);
+	if (status < 0) {
+		printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
+		goto cleanup_sysctl;
 	}
-	register_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+
+cleanup:
+	nf_unregister_queue_handler(PF_INET6);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ipq_flush(NF_DROP);
+	
+cleanup_sysctl:
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	
+cleanup_ipqnl:
+	sock_release(ipqnl->socket);
+	down(&ipqnl_sem);
+	up(&ipqnl_sem);
+	
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&ipq_nl_notifier);
 	return status;
 }
 
+static int __init init(void)
+{
+	
+	return init_or_cleanup(1);
+}
+
 static void __exit fini(void)
 {
-	unregister_sysctl_table(ip6q_sysctl_header);
-	proc_net_remove(IPQ_PROC_FS_NAME);
-	unregister_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_destroy_queue(nlq6);
-	sock_release(nfnl->socket);
+	init_or_cleanup(0);
 }
 
 MODULE_DESCRIPTION("IPv6 packet queue handler");
diff -Nru a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
--- a/net/ipv6/netfilter/ip6_tables.c	Tue Aug 27 12:28:08 2002
+++ b/net/ipv6/netfilter/ip6_tables.c	Tue Aug 27 12:28:08 2002
@@ -7,6 +7,8 @@
  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  * 	- increase module usage count as soon as we have rules inside
  * 	  a table
+ * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
+ *      - new extension header parser code
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -25,6 +27,7 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
 #define IPV6_HDR_LEN	(sizeof(struct ipv6hdr))
+#define IPV6_OPTHDR_LEN	(sizeof(struct ipv6_opt_hdr))
 
 /*#define DEBUG_IP_FIREWALL*/
 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
@@ -133,43 +136,23 @@
 	return 0;
 }
 
-/* takes in current header and pointer to the header */
-/* if another header exists, sets hdrptr to the next header
-   and returns the new header value, else returns 0 */
-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t *hdrptr)
-{
-	int i;
-	u_int8_t hdrlen, nexthdr = 0;
-	switch(currenthdr){
-		case IPPROTO_AH:
-		/* whoever decided to do the length of AUTH for ipv6
-		in 32bit units unlike other headers should be beaten...
-		repeatedly...with a large stick...no, an even LARGER
-		stick...no, you're still not thinking big enough */
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[i] * 4 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		/*stupid rfc2402 */
-		case IPPROTO_DSTOPTS:
-		case IPPROTO_ROUTING:
-		case IPPROTO_HOPOPTS:
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[1] * 8 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		case IPPROTO_FRAGMENT:
-			nexthdr = *hdrptr;
-			hdrptr = hdrptr + 8;
-			break;
-	}	
-	return nexthdr;
-
+/* Check for an extension */
+int 
+ip6t_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == IPPROTO_HOPOPTS)   ||
+                 (nexthdr == IPPROTO_ROUTING)   ||
+                 (nexthdr == IPPROTO_FRAGMENT)  ||
+                 (nexthdr == IPPROTO_ESP)       ||
+                 (nexthdr == IPPROTO_AH)        ||
+                 (nexthdr == IPPROTO_NONE)      ||
+                 (nexthdr == IPPROTO_DSTOPTS) );
 }
 
 /* Returns whether matches rule or not. */
 static inline int
-ip6_packet_match(const struct ipv6hdr *ipv6,
+ip6_packet_match(const struct sk_buff *skb,
+		 const struct ipv6hdr *ipv6,
 		 const char *indev,
 		 const char *outdev,
 		 const struct ip6t_ip6 *ip6info,
@@ -227,17 +210,58 @@
 	/* look for the desired protocol header */
 	if((ip6info->flags & IP6T_F_PROTO)) {
 		u_int8_t currenthdr = ipv6->nexthdr;
-		u_int8_t *hdrptr;
-		hdrptr = (u_int8_t *)(ipv6 + 1);
-		do {
-			if (ip6info->proto == currenthdr) {
-				if(ip6info->invflags & IP6T_INV_PROTO)
-					return 0;
-				return 1;
+		struct ipv6_opt_hdr *hdrptr;
+		u_int16_t ptr;		/* Header offset in skb */
+		u_int16_t hdrlen;	/* Header */
+
+		ptr = IPV6_HDR_LEN;
+
+		while (ip6t_ext_hdr(currenthdr)) {
+	                /* Is there enough space for the next ext header? */
+	                if (skb->len - ptr < IPV6_OPTHDR_LEN)
+	                        return 0;
+
+			/* NONE or ESP: there isn't protocol part */
+			/* If we want to count these packets in '-p all',
+			 * we will change the return 0 to 1*/
+			if ((currenthdr == IPPROTO_NONE) || 
+				(currenthdr == IPPROTO_ESP))
+				return 0;
+
+	                hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
+
+			/* Size calculation */
+	                if (currenthdr == IPPROTO_FRAGMENT) {
+	                        hdrlen = 8;
+	                } else if (currenthdr == IPPROTO_AH)
+	                        hdrlen = (hdrptr->hdrlen+2)<<2;
+	                else
+	                        hdrlen = ipv6_optlen(hdrptr);
+
+			currenthdr = hdrptr->nexthdr;
+	                ptr += hdrlen;
+			/* ptr is too large */
+	                if ( ptr > skb->len ) 
+				return 0;
+		}
+
+		/* currenthdr contains the protocol header */
+
+		dprintf("Packet protocol %hi ?= %s%hi.\n",
+				currenthdr, 
+				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
+				ip6info->proto);
+
+		if (ip6info->proto == currenthdr) {
+			if(ip6info->invflags & IP6T_INV_PROTO) {
+				return 0;
 			}
-			currenthdr = ip6_nexthdr(currenthdr, hdrptr);
-		} while(currenthdr);
-		if (!(ip6info->invflags & IP6T_INV_PROTO))
+			return 1;
+		}
+
+		/* We need match for the '-p all', too! */
+		if ((ip6info->proto != 0) &&
+			!(ip6info->invflags & IP6T_INV_PROTO))
 			return 0;
 	}
 	return 1;
@@ -359,7 +383,8 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		(*pskb)->nfcache |= e->nfcache;
-		if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
+		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
+			&e->ipv6, offset)) {
 			struct ip6t_entry_target *t;
 
 			if (IP6T_MATCH_ITERATE(e, do_match,
@@ -1826,6 +1851,7 @@
 EXPORT_SYMBOL(ip6t_unregister_match);
 EXPORT_SYMBOL(ip6t_register_target);
 EXPORT_SYMBOL(ip6t_unregister_target);
+EXPORT_SYMBOL(ip6t_ext_hdr);
 
 module_init(init);
 module_exit(fini);
diff -Nru a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv6/netfilter/ip6t_eui64.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,89 @@
+/* Kernel module to match EUI64 address parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/if_ether.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+
+    unsigned char eui64[8];
+    int i=0;
+
+     if ( !(skb->mac.raw >= skb->head
+                && (skb->mac.raw + ETH_HLEN) <= skb->data)
+                && offset != 0) {
+                        *hotdrop = 1;
+                        return 0;
+                }
+    
+    memset(eui64, 0, sizeof(eui64));
+
+    if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) {
+      if (skb->nh.ipv6h->version == 0x6) { 
+         memcpy(eui64, skb->mac.ethernet->h_source, 3);
+         memcpy(eui64 + 5, skb->mac.ethernet->h_source + 3, 3);
+	 eui64[3]=0xff;
+	 eui64[4]=0xfe;
+	 eui64[0] |= 0x02;
+
+	 i=0;
+	 while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
+			 eui64[i]) && (i<8)) i++;
+
+	 if ( i == 8 )
+	 	return 1;
+      }
+    }
+
+    return 0;
+}
+
+static int
+ip6t_eui64_checkentry(const char *tablename,
+		   const struct ip6t_ip6 *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+	if (hook_mask
+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
+		(1 << NF_IP6_PRE_ROUTING) )) {
+		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+
+	if (matchsize != IP6T_ALIGN(sizeof(int)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match eui64_match
+= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&eui64_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&eui64_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
diff -Nru a/net/ipv6/netfilter/ip6t_length.c b/net/ipv6/netfilter/ip6t_length.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv6/netfilter/ip6t_length.c	Tue Aug 27 12:28:08 2002
@@ -0,0 +1,51 @@
+/* Length Match - IPv6 Port */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6t_length.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ip6t_length_info *info = matchinfo;
+	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+	
+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ip6t_ip6 *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match length_match
+= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&length_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&length_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c	Tue Aug 27 12:28:01 2002
+++ b/net/ipx/af_ipx.c	Tue Aug 27 12:28:01 2002
@@ -777,10 +777,9 @@
 	/* set up data link and physical headers */
 	skb->dev	= dev;
 	skb->protocol	= htons(ETH_P_IPX);
-	dl->datalink_header(dl, skb, dest_node);
 
 	/* Send it out */
-	dev_queue_xmit(skb);
+	dl->request(dl, skb, dest_node);
 out:	return 0;
 }
 
@@ -2253,6 +2252,22 @@
 out:	return ret;
 }
 
+static int ipx_8022_indicate(struct llc_prim_if_block *prim)
+{
+	int rc = 1;
+	static struct packet_type p8022_packet_type = {
+		.type = __constant_htons(ETH_P_802_2),
+	};
+
+	if (prim->prim == LLC_DATAUNIT_PRIM) {
+		struct sk_buff *skb = prim->data->udata.skb;
+
+		rc = ipx_rcv(skb, skb->dev, &p8022_packet_type);
+	}
+						
+	return rc;
+}
+
 static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 	struct scm_cookie *scm)
 {
@@ -2545,7 +2560,7 @@
 	else
 		printk(ipx_8023_err_msg);
 
-	p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv);
+	p8022_datalink = register_8022_client(ipx_8022_type, ipx_8022_indicate);
 	if (!p8022_datalink)
 		printk(ipx_llc_err_msg);
 
@@ -2593,10 +2608,10 @@
 
 	unregister_netdevice_notifier(&ipx_dev_notifier);
 
-	unregister_snap_client(ipx_snap_id);
+	unregister_snap_client(pSNAP_datalink);
 	pSNAP_datalink = NULL;
 
-	unregister_8022_client(ipx_8022_type);
+	unregister_8022_client(p8022_datalink);
 	p8022_datalink = NULL;
 
 	dev_remove_pack(&ipx_8023_packet_type);
diff -Nru a/net/llc/llc_actn.c b/net/llc/llc_actn.c
--- a/net/llc/llc_actn.c	Tue Aug 27 12:28:02 2002
+++ b/net/llc/llc_actn.c	Tue Aug 27 12:28:02 2002
@@ -27,7 +27,7 @@
 static void llc_station_ack_tmr_callback(unsigned long timeout_data);
 
 int llc_station_ac_start_ack_timer(struct llc_station *station,
-				   struct llc_station_state_ev *ev)
+				   struct sk_buff *skb)
 {
 	del_timer(&station->ack_timer);
 	station->ack_timer.expires  = jiffies + LLC_ACK_TIME * HZ;
@@ -39,98 +39,94 @@
 }
 
 int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
-				   struct llc_station_state_ev *ev)
+				   struct sk_buff *skb)
 {
 	station->retry_count = 0;
 	return 0;
 }
 
 int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
-				      struct llc_station_state_ev *ev)
+				      struct sk_buff *skb)
 {
 	station->retry_count++;
 	return 0;
 }
 
 int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
-				   struct llc_station_state_ev *ev)
+				   struct sk_buff *skb)
 {
 	station->xid_r_count = 0;
 	return 0;
 }
 
 int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
-				      struct llc_station_state_ev *ev)
+				      struct sk_buff *skb)
 {
 	station->xid_r_count++;
 	return 0;
 }
 
 int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
-					struct llc_station_state_ev *ev)
+					struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (!skb)
+	if (!nskb)
 		goto out;
 	rc = 0;
-	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
-	llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 127);
-	lan_hdrs_init(skb, station->mac_sa, station->mac_sa);
-	llc_station_send_pdu(station, skb);
+	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
+	llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127);
+	lan_hdrs_init(nskb, station->mac_sa, station->mac_sa);
+	llc_station_send_pdu(station, nskb);
 out:
 	return rc;
 }
 
 int llc_station_ac_send_xid_r(struct llc_station *station,
-			      struct llc_station_state_ev *ev)
+			      struct sk_buff *skb)
 {
 	u8 mac_da[ETH_ALEN], dsap;
 	int rc = 1;
-	struct sk_buff *ev_skb;
-	struct sk_buff* skb = llc_alloc_frame();
+	struct sk_buff* nskb = llc_alloc_frame();
 
-	if (!skb)
+	if (!nskb)
 		goto out;
 	rc = 0;
-	ev_skb = ev->data.pdu.skb;
-	skb->dev = ev_skb->dev;
-	llc_pdu_decode_sa(ev_skb, mac_da);
-	llc_pdu_decode_ssap(ev_skb, &dsap);
-	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
-	llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 127);
-	lan_hdrs_init(skb, station->mac_sa, mac_da);
-	llc_station_send_pdu(station, skb);
+	nskb->dev = skb->dev;
+	llc_pdu_decode_sa(skb, mac_da);
+	llc_pdu_decode_ssap(skb, &dsap);
+	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
+	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
+	lan_hdrs_init(nskb, station->mac_sa, mac_da);
+	llc_station_send_pdu(station, nskb);
 out:
 	return rc;
 }
 
 int llc_station_ac_send_test_r(struct llc_station *station,
-			       struct llc_station_state_ev *ev)
+			       struct sk_buff *skb)
 {
 	u8 mac_da[ETH_ALEN], dsap;
 	int rc = 1;
-	struct sk_buff *ev_skb;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (!skb)
+	if (!nskb)
 		goto out;
 	rc = 0;
-	ev_skb = ev->data.pdu.skb;
-	skb->dev = ev_skb->dev;
-	llc_pdu_decode_sa(ev_skb, mac_da);
-	llc_pdu_decode_ssap(ev_skb, &dsap);
-	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
-       	llc_pdu_init_as_test_rsp(skb, ev_skb);
-	lan_hdrs_init(skb, station->mac_sa, mac_da);
-	llc_station_send_pdu(station, skb);
+	nskb->dev = skb->dev;
+	llc_pdu_decode_sa(skb, mac_da);
+	llc_pdu_decode_ssap(skb, &dsap);
+	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
+       	llc_pdu_init_as_test_rsp(nskb, skb);
+	lan_hdrs_init(nskb, station->mac_sa, mac_da);
+	llc_station_send_pdu(station, nskb);
 out:
 	return rc;
 }
 
 int llc_station_ac_report_status(struct llc_station *station,
-				 struct llc_station_state_ev *ev)
+				 struct sk_buff *skb)
 {
 	return 0;
 }
@@ -138,13 +134,14 @@
 static void llc_station_ack_tmr_callback(unsigned long timeout_data)
 {
 	struct llc_station *station = (struct llc_station *)timeout_data;
-	struct llc_station_state_ev *ev;
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
 
 	station->ack_tmr_running = 0;
-	ev = llc_station_alloc_ev(station);
-	if (ev) {
+	if (skb) {
+		struct llc_station_state_ev *ev = llc_station_ev(skb);
+
 		ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
 		ev->data.tmr.timer_specific = NULL;
-		llc_station_send_ev(station, ev);
+		llc_station_send_ev(station, skb);
 	}
 }
diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
--- a/net/llc/llc_c_ac.c	Tue Aug 27 12:28:08 2002
+++ b/net/llc/llc_c_ac.c	Tue Aug 27 12:28:08 2002
@@ -32,22 +32,19 @@
 static void llc_conn_ack_tmr_cb(unsigned long timeout_data);
 static void llc_conn_rej_tmr_cb(unsigned long timeout_data);
 static void llc_conn_busy_tmr_cb(unsigned long timeout_data);
-static int llc_conn_ac_inc_vs_by_1(struct sock *sk,
-				   struct llc_conn_state_ev *ev);
-static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev);
-static int llc_conn_ac_data_confirm(struct sock *sk,
-				    struct llc_conn_state_ev *ev);
+static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
+static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
+static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev);
 
 #define INCORRECT 0
 
-int llc_conn_ac_clear_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
 	if (llc->remote_busy_flag) {
 		u8 nr;
-		struct llc_pdu_sn *pdu =
-				(struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 		llc->remote_busy_flag = 0;
 		del_timer(&llc->busy_state_timer.timer);
@@ -58,18 +55,21 @@
 	return 0;
 }
 
-int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = ev->data.pdu.skb;
-	union llc_u_prim_data *prim_data = llc_ind_prim.data;
-	struct llc_prim_if_block *prim = &llc_ind_prim;
+	u8 dsap;
 	struct llc_sap *sap;
-	struct llc_opt *llc = llc_sk(sk);
 
-	llc_pdu_decode_dsap(skb, &prim_data->conn.daddr.lsap);
-	sap = llc_sap_find(prim_data->conn.daddr.lsap);
+	llc_pdu_decode_dsap(skb, &dsap);
+	sap = llc_sap_find(dsap);
 	if (sap) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+		struct llc_prim_if_block *prim = &sap->llc_ind_prim;
+		union llc_u_prim_data *prim_data = prim->data;
+		struct llc_opt *llc = llc_sk(sk);
+
+		prim_data->conn.daddr.lsap = dsap;
 		llc_pdu_decode_sa(skb, llc->daddr.mac);
 		llc_pdu_decode_da(skb, llc->laddr.mac);
 		llc->dev = skb->dev;
@@ -88,25 +88,19 @@
 	return rc;
 }
 
-int llc_conn_ac_conn_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
 {
-	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
-	struct sk_buff *skb = ev->data.pdu.skb;
-	/* FIXME: wtf, this is global, so the whole thing is really
-	 *	  non reentrant...
-	 */
-	struct llc_prim_if_block *prim = &llc_cfm_prim;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 	struct llc_opt *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
+	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 
 	prim_data->conn.sk     = sk;
 	prim_data->conn.pri    = 0;
 	prim_data->conn.status = ev->status;
 	prim_data->conn.link   = llc->link;
-	if (skb)
-		prim_data->conn.dev    = skb->dev;
-	else
-		printk(KERN_ERR __FUNCTION__ "ev->data.pdu.skb == NULL\n");
+	prim_data->conn.dev    = skb->dev;
 	prim->data   = prim_data;
 	prim->prim   = LLC_CONN_PRIM;
 	prim->sap    = sap;
@@ -115,41 +109,41 @@
 	return 0;
 }
 
-static int llc_conn_ac_data_confirm(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_prim_if_block *prim = &llc_cfm_prim;
-	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 
 	prim_data->data.sk     = sk;
 	prim_data->data.pri    = 0;
-	prim_data->data.link   = llc_sk(sk)->link;
+	prim_data->data.link   = llc->link;
 	prim_data->data.status = LLC_STATUS_RECEIVED;
 	prim_data->data.skb    = NULL;
 	prim->data	       = prim_data;
 	prim->prim	       = LLC_DATA_PRIM;
-	prim->sap	       = llc_sk(sk)->sap;
+	prim->sap	       = sap;
 	ev->flag	       = 1;
 	ev->cfm_prim	       = prim;
 	return 0;
 }
 
-int llc_conn_ac_data_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_data_ind(struct sock *sk, struct sk_buff *skb)
 {
-	llc_conn_rtn_pdu(sk, ev->data.pdu.skb, ev);
+	llc_conn_rtn_pdu(sk, skb);
 	return 0;
 }
 
-int llc_conn_ac_disc_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 	u8 reason = 0;
 	int rc = 1;
-	union llc_u_prim_data *prim_data = llc_ind_prim.data;
-	struct llc_prim_if_block *prim = &llc_ind_prim;
 
 	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
-		struct llc_pdu_un *pdu =
-				(struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+		struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 		if (!LLC_PDU_IS_RSP(pdu) &&
 		    !LLC_PDU_TYPE_IS_U(pdu) &&
@@ -170,41 +164,48 @@
 		rc = 1;
 	}
 	if (!rc) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		struct llc_prim_if_block *prim = &sap->llc_ind_prim;
+		union llc_u_prim_data *prim_data = prim->data;
+
 		prim_data->disc.sk     = sk;
 		prim_data->disc.reason = reason;
-		prim_data->disc.link   = llc_sk(sk)->link;
+		prim_data->disc.link   = llc->link;
 		prim->data	       = prim_data;
 		prim->prim	       = LLC_DISC_PRIM;
-		prim->sap	       = llc_sk(sk)->sap;
+		prim->sap	       = llc->sap;
 		ev->flag	       = 1;
 		ev->ind_prim	       = prim;
 	}
 	return rc;
 }
 
-int llc_conn_ac_disc_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
 {
-	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
-	struct llc_prim_if_block *prim = &llc_cfm_prim;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 
 	prim_data->disc.sk     = sk;
 	prim_data->disc.reason = ev->status;
-	prim_data->disc.link   = llc_sk(sk)->link;
+	prim_data->disc.link   = llc->link;
 	prim->data	       = prim_data;
 	prim->prim	       = LLC_DISC_PRIM;
-	prim->sap	       = llc_sk(sk)->sap;
+	prim->sap	       = sap;
 	ev->flag	       = 1;
 	ev->cfm_prim	       = prim;
 	return 0;
 }
 
-int llc_conn_ac_rst_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
 {
 	u8 reason = 0;
 	int rc = 1;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
-	union llc_u_prim_data *prim_data = llc_ind_prim.data;
-	struct llc_prim_if_block *prim = &llc_ind_prim;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 	struct llc_opt *llc = llc_sk(sk);
 
 	switch (ev->type) {
@@ -237,237 +238,235 @@
 			break;
 	}
 	if (!rc) {
+		struct llc_sap *sap = llc->sap;
+		struct llc_prim_if_block *prim = &sap->llc_ind_prim;
+		union llc_u_prim_data *prim_data = prim->data;
+
 		prim_data->res.sk     = sk;
 		prim_data->res.reason = reason;
 		prim_data->res.link   = llc->link;
 		prim->data	      = prim_data;
 		prim->prim	      = LLC_RESET_PRIM;
-		prim->sap	      = llc->sap;
+		prim->sap	      = sap;
 		ev->flag	      = 1;
 		ev->ind_prim	      = prim;
 	}
 	return rc;
 }
 
-int llc_conn_ac_rst_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
 {
-	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
-	struct llc_prim_if_block *prim = &llc_cfm_prim;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 
 	prim_data->res.sk   = sk;
-	prim_data->res.link = llc_sk(sk)->link;
+	prim_data->res.link = llc->link;
 	prim->data	    = prim_data;
 	prim->prim	    = LLC_RESET_PRIM;
-	prim->sap	    = llc_sk(sk)->sap;
+	prim->sap	    = sap;
 	ev->flag	    = 1;
 	ev->cfm_prim	    = prim;
 	return 0;
 }
 
-int llc_conn_ac_report_status(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_report_status(struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
 int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk,
-					struct llc_conn_state_ev *ev)
+					    struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	if (!LLC_PDU_IS_RSP(pdu) &&
 	    !LLC_PDU_TYPE_IS_I(pdu) &&
 	    !LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf)
-		llc_conn_ac_clear_remote_busy(sk, ev);
+		llc_conn_ac_clear_remote_busy(sk, skb);
 	return 0;
 }
 
 int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
-						 struct llc_conn_state_ev *ev)
+					       struct sk_buff *skb)
 {
-	if (llc_sk(sk)->data_flag == 2) {
-		del_timer(&llc_sk(sk)->rej_sent_timer.timer);
-		llc_sk(sk)->rej_sent_timer.running = 0;
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (llc->data_flag == 2) {
+		del_timer(&llc->rej_sent_timer.timer);
+		llc->rej_sent_timer.running = 0;
 	}
 	return 0;
 }
 
-int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 p_bit = 1;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_disc_cmd(skb, p_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_disc_cmd(nskb, p_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
-	llc_conn_ac_set_p_flag_1(sk, ev);
+	llc_conn_ac_set_p_flag_1(sk, skb);
 	return rc;
 }
 
-int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
-		struct sk_buff *rx_skb = ev->data.pdu.skb;
 		u8 f_bit;
 
-		skb->dev = llc->dev;
-		llc_pdu_decode_pf_bit(rx_skb, &f_bit);
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_decode_pf_bit(skb, &f_bit);
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_dm_rsp(skb, f_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_dm_rsp(nskb, f_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_dm_rsp(skb, f_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_dm_rsp(nskb, f_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = llc->f_flag;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_dm_rsp(skb, f_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_dm_rsp(nskb, f_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
 {
 	u8 f_bit;
 	int rc = 1;
-	struct sk_buff *skb, *ev_skb = ev->data.pdu.skb;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev_skb->nh.raw;
+	struct sk_buff *nskb;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	struct llc_opt *llc = llc_sk(sk);
 
 	llc->rx_pdu_hdr = *((u32 *)pdu);
 	if (!LLC_PDU_IS_CMD(pdu))
-		llc_pdu_decode_pf_bit(ev_skb, &f_bit);
+		llc_pdu_decode_pf_bit(skb, &f_bit);
 	else
 		f_bit = 0;
-	skb = llc_alloc_frame();
-	if (skb) {
+	nskb = llc_alloc_frame();
+	if (nskb) {
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_frmr_rsp(skb, pdu, f_bit, llc->vS,
+		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
 					 llc->vR, INCORRECT);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk,
-					struct llc_conn_state_ev *ev)
+int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 f_bit = 0;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)&llc->rx_pdu_hdr;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_frmr_rsp(skb, pdu, f_bit, llc->vS,
+		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
 					 llc->vR, INCORRECT);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk,
-					struct llc_conn_state_ev *ev)
+int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
 {
 	u8 f_bit;
 	int rc = 1;
-	struct sk_buff *skb;
+	struct sk_buff *nskb;
 
-	llc_pdu_decode_pf_bit(ev->data.pdu.skb, &f_bit);
-	skb = llc_alloc_frame();
-	if (skb) {
+	llc_pdu_decode_pf_bit(skb, &f_bit);
+	nskb = llc_alloc_frame();
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
-		struct llc_pdu_sn *pdu =
-				(struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_frmr_rsp(skb, pdu, f_bit, llc->vS,
+		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
 					 llc->vR, INCORRECT);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	u8 p_bit = 1;
-	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
 	struct llc_opt *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
@@ -476,15 +475,13 @@
 	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
 	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
 	llc_conn_send_pdu(sk, skb);
-	llc_conn_ac_inc_vs_by_1(sk, ev);
+	llc_conn_ac_inc_vs_by_1(sk, skb);
 	return 0;
 }
 
-int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	u8 p_bit = 0;
-	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
 	struct llc_opt *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
@@ -493,14 +490,13 @@
 	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
 	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
 	llc_conn_send_pdu(sk, skb);
-	llc_conn_ac_inc_vs_by_1(sk, ev);
+	llc_conn_ac_inc_vs_by_1(sk, skb);
 	return 0;
 }
 
-int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 nr = LLC_I_GET_NR(pdu);
 
 	llc_conn_resend_i_pdu_as_cmd(sk, nr, 1);
@@ -508,22 +504,20 @@
 }
 
 int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock *sk,
-						struct llc_conn_state_ev *ev)
+						struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 nr = LLC_I_GET_NR(pdu);
-	int rc = llc_conn_ac_send_rr_cmd_p_set_1(sk, ev);
+	int rc = llc_conn_ac_send_rr_cmd_p_set_1(sk, skb);
 
 	if (!rc)
 		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
 	return rc;
 }
 
-int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	u8 p_bit = 0;
-	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
 	struct llc_opt *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
@@ -532,14 +526,13 @@
 	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
 	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
 	llc_conn_send_pdu(sk, skb);
-	llc_conn_ac_inc_vs_by_1(sk, ev);
+	llc_conn_ac_inc_vs_by_1(sk, skb);
 	return 0;
 }
 
-int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 nr = LLC_I_GET_NR(pdu);
 
 	llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
@@ -547,25 +540,25 @@
 }
 
 int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
-						struct llc_conn_state_ev *ev)
+						struct sk_buff *skb)
 {
 	u8 nr;
 	u8 f_bit = 0;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	if (rc) {
 		nr = LLC_I_GET_NR(pdu);
@@ -575,149 +568,142 @@
 	return rc;
 }
 
-int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 nr = LLC_I_GET_NR(pdu);
 
 	llc_conn_resend_i_pdu_as_rsp(sk, nr, 1);
 	return 0;
 }
 
-int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 p_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_rej_cmd(skb, p_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rej_cmd(nskb, p_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 f_bit = 1;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 0;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 p_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_rnr_cmd(skb, p_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rnr_cmd(nskb, p_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 f_bit = 0;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_set_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -733,246 +719,234 @@
 	return 0;
 }
 
-int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 0;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 p_bit = 1;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_cmd(nskb, p_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		u8 p_bit = 1;
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_cmd(nskb, p_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 0;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 0;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 	struct llc_opt *llc = llc_sk(sk);
 	u8 p_bit = 1;
 
-	if (skb) {
+	if (nskb) {
 		struct llc_sap *sap = llc->sap;
 		u8 *dmac = llc->daddr.mac;
 
 		if (llc->dev->flags & IFF_LOOPBACK)
 			dmac = llc->dev->dev_addr;
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_CMD);
-		llc_pdu_init_as_sabme_cmd(skb, p_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, dmac);
+		llc_pdu_init_as_sabme_cmd(nskb, p_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, dmac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	llc->p_flag = p_bit;
 	return rc;
 }
 
-int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = llc->f_flag;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_ua_rsp(skb, f_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_ua_rsp(nskb, f_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
 {
 	u8 f_bit;
 	int rc = 1;
-	struct sk_buff *rx_skb = ev->data.pdu.skb;
-	struct sk_buff *skb;
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	llc_pdu_decode_pf_bit(rx_skb, &f_bit);
-	skb = llc_alloc_frame();
-	if (skb) {
+	llc_pdu_decode_pf_bit(skb, &f_bit);
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_ua_rsp(skb, f_bit);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_ua_rsp(nskb, f_bit);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
 
-int llc_conn_ac_set_s_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->s_flag = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_s_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_s_flag_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->s_flag = 1;
 	return 0;
 }
 
-int llc_conn_ac_start_p_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -990,18 +964,16 @@
 /**
  *	llc_conn_ac_send_ack_if_needed - check if ack is needed
  *	@sk: current connection structure
- *	@ev: current event
+ *	@skb: current event
  *
  *	Checks number of received PDUs which have not been acknowledged, yet,
  *	If number of them reaches to "npta"(Number of PDUs To Acknowledge) then
  *	sends an RR response as acknowledgement for them.  Returns 0 for
  *	success, 1 otherwise.
  */
-int llc_conn_ac_send_ack_if_needed(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb)
 {
 	u8 pf_bit;
-	struct sk_buff *skb = ev->data.pdu.skb;
 	struct llc_opt *llc = llc_sk(sk);
 
 	llc_pdu_decode_pf_bit(skb, &pf_bit);
@@ -1012,10 +984,10 @@
 		llc->ack_pf = pf_bit & 1;
 	}
 	if (((llc->vR - llc->first_pdu_Ns + 129) % 128) >= llc->npta) {
-		llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, ev);
+		llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, skb);
 		llc->ack_must_be_send	= 0;
 		llc->ack_pf		= 0;
-		llc_conn_ac_inc_npta_value(sk, ev);
+		llc_conn_ac_inc_npta_value(sk, skb);
 	}
 	return 0;
 }
@@ -1023,14 +995,13 @@
 /**
  *	llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag
  *	@sk: current connection structure
- *	@ev: current event
+ *	@skb: current event
  *
  *	This action resets ack_must_be_send flag of given connection, this flag
  *	indicates if there is any PDU which has not been acknowledged yet.
  *	Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_rst_sendack_flag(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0;
 	return 0;
@@ -1039,17 +1010,15 @@
 /**
  *	llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs
  *	@sk: current connection structure
- *	@ev: current event
+ *	@skb: current event
  *
  *	Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to
  *	all received PDUs which have not been acknowledged, yet. ack_pf flag is
  *	set to one if one PDU with p-bit set to one is received.  Returns 0 for
  *	success, 1 otherwise.
  */
-int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb)
 {
-	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
 	struct llc_opt *llc = llc_sk(sk);
 	u8 p_bit = llc->ack_pf;
 	struct llc_sap *sap = llc->sap;
@@ -1059,61 +1028,60 @@
 	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
 	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
 	llc_conn_send_pdu(sk, skb);
-	llc_conn_ac_inc_vs_by_1(sk, ev);
+	llc_conn_ac_inc_vs_by_1(sk, skb);
 	return 0;
 }
 
 /**
  *	llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	This action sends an I-format PDU as acknowledge to received PDUs which
  *	have not been acknowledged, yet, if there is any. By using of this
  *	action number of acknowledgements decreases, this technic is called
  *	piggy backing. Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_send_i_as_ack(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
 	if (llc->ack_must_be_send) {
-		llc_conn_ac_send_i_rsp_f_set_ackpf(sk, ev);
+		llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
 		llc->ack_must_be_send = 0 ;
 		llc->ack_pf = 0;
 	} else
-		llc_conn_ac_send_i_cmd_p_set_0(sk, ev);
+		llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
 	return 0;
 }
 
 /**
  *	llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	This action sends an RR response with f-bit set to ack_pf flag as
  *	acknowledge to all received PDUs which have not been acknowledged, yet,
  *	if there is any. ack_pf flag indicates if a PDU has been received with
  *	p-bit set to one. Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
-					struct llc_conn_state_ev *ev)
+int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct sk_buff *skb = llc_alloc_frame();
+	struct sk_buff *nskb = llc_alloc_frame();
 
-	if (skb) {
+	if (nskb) {
 		struct llc_opt *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = llc->ack_pf;
 
-		skb->dev = llc->dev;
-		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+		nskb->dev = llc->dev;
+		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
 				    llc->daddr.lsap, LLC_PDU_RSP);
-		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
-		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
+		lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
 		rc = 0;
-		llc_conn_send_pdu(sk, skb);
+		llc_conn_send_pdu(sk, nskb);
 	}
 	return rc;
 }
@@ -1121,14 +1089,14 @@
 /**
  *	llc_conn_ac_inc_npta_value - tries to make value of npta greater
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	After "inc_cntr" times calling of this action, "npta" increase by one.
  *	this action tries to make vale of "npta" greater as possible; number of
  *	acknowledgements decreases by increasing of "npta". Returns 0 for
  *	success, 1 otherwise.
  */
-int llc_conn_ac_inc_npta_value(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1146,12 +1114,12 @@
 /**
  *	llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	After receiving "dec_cntr" times RR command, this action decreases
  *	"npta" by one. Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1172,13 +1140,12 @@
 /**
  *	llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	After receiving "dec_cntr" times RNR command, this action decreases
  *	"npta" by one. Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1197,13 +1164,13 @@
 /**
  *	llc_conn_ac_dec_tx_win_size - decreases tx window size
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	After receiving of a REJ command or response, transmit window size is
  *	decreased by number of PDUs which are outstanding yet. Returns 0 for
  *	success, 1 otherwise.
  */
-int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 	u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
@@ -1217,12 +1184,12 @@
 /**
  *	llc_conn_ac_inc_tx_win_size - tx window size is inc by 1
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	After receiving an RR response with f-bit set to one, transmit window
  *	size is increased by one. Returns 0 for success, 1 otherwise.
  */
-int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1232,7 +1199,7 @@
 	return 0;
 }
 
-int llc_conn_ac_stop_all_timers(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1249,7 +1216,7 @@
 	return 0;
 }
 
-int llc_conn_ac_stop_other_timers(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_stop_other_timers(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1264,7 +1231,7 @@
 	return 0;
 }
 
-int llc_conn_ac_start_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1277,7 +1244,7 @@
 	return 0;
 }
 
-int llc_conn_ac_start_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1292,7 +1259,7 @@
 }
 
 int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
-					     struct llc_conn_state_ev *ev)
+					     struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1307,14 +1274,14 @@
 	return 0;
 }
 
-int llc_conn_ac_stop_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_stop_ack_timer(struct sock *sk, struct sk_buff *skb)
 {
 	del_timer(&llc_sk(sk)->ack_timer.timer);
 	llc_sk(sk)->ack_timer.running = 0;
 	return 0;
 }
 
-int llc_conn_ac_stop_p_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_stop_p_timer(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -1324,20 +1291,19 @@
 	return 0;
 }
 
-int llc_conn_ac_stop_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_stop_rej_timer(struct sock *sk, struct sk_buff *skb)
 {
 	del_timer(&llc_sk(sk)->rej_sent_timer.timer);
 	llc_sk(sk)->rej_sent_timer.running = 0;
 	return 0;
 }
 
-int llc_conn_ac_upd_nr_received(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
 {
 	int acked;
 	u16 unacked = 0;
 	u8 fbit;
-	struct sk_buff *skb = ev->data.pdu.skb;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	struct llc_opt *llc = llc_sk(sk);
 
 	llc->last_nr = PDU_SUPV_GET_Nr(pdu);
@@ -1353,7 +1319,7 @@
 			 * can send data and must inform to upper layer.
 			 */
 			llc->failed_data_req = 0;
-			llc_conn_ac_data_confirm(sk, ev);
+			llc_conn_ac_data_confirm(sk, skb);
 		}
 		if (unacked) {
 			llc->ack_timer.timer.expires  = jiffies +
@@ -1367,201 +1333,203 @@
 		llc_pdu_decode_pf_bit(skb, &fbit);
 		if (fbit == 1) {
 			llc->failed_data_req = 0;
-			llc_conn_ac_data_confirm(sk, ev);
+			llc_conn_ac_data_confirm(sk, skb);
 		}
 	}
 	return 0;
 }
 
-int llc_conn_ac_upd_p_flag(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb)
 {
-	struct sk_buff *skb = ev->data.pdu.skb;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 f_bit;
 
 	if (!LLC_PDU_IS_RSP(pdu) &&
 	    !llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) {
 		llc_sk(sk)->p_flag = 0;
-		llc_conn_ac_stop_p_timer(sk, ev);
+		llc_conn_ac_stop_p_timer(sk, skb);
 	}
 	return 0;
 }
 
-int llc_conn_ac_set_data_flag_2(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_data_flag_2(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->data_flag = 2;
 	return 0;
 }
 
-int llc_conn_ac_set_data_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_data_flag_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->data_flag = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_data_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_data_flag_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->data_flag = 1;
 	return 0;
 }
 
 int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk,
-						  struct llc_conn_state_ev *ev)
+						  struct sk_buff *skb)
 {
 	if (!llc_sk(sk)->data_flag)
 		llc_sk(sk)->data_flag = 1;
 	return 0;
 }
 
-int llc_conn_ac_set_p_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_p_flag_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->p_flag = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_p_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->p_flag = 1;
 	return 0;
 }
 
-int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->remote_busy_flag = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->cause_flag = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->cause_flag = 1;
 	return 0;
 }
 
-int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->retry_count = 0;
 	return 0;
 }
 
-int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->retry_count++;
 	return 0;
 }
 
-int llc_conn_ac_set_vr_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_vr_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->vR = 0;
 	return 0;
 }
 
-int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR);
 	return 0;
 }
 
-int llc_conn_ac_set_vs_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_vs_0(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->vS = 0;
 	return 0;
 }
 
-int llc_conn_ac_set_vs_nr(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->vS = llc_sk(sk)->last_nr;
 	return 0;
 }
 
-int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % 128;
 	return 0;
 }
 
-int llc_conn_ac_set_f_flag_p(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb)
 {
-	llc_pdu_decode_pf_bit(ev->data.pdu.skb, &llc_sk(sk)->f_flag);
+	llc_pdu_decode_pf_bit(skb, &llc_sk(sk)->f_flag);
 	return 0;
 }
 
 void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
 
 	llc_sk(sk)->pf_cycle_timer.running = 0;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type = LLC_CONN_EV_TYPE_P_TMR;
 		ev->data.tmr.timer_specific = NULL;
-		llc_process_tmr_ev(sk, ev);
+		llc_process_tmr_ev(sk, skb);
 	}
 }
 
 static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
 
 	llc_sk(sk)->busy_state_timer.running = 0;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type = LLC_CONN_EV_TYPE_BUSY_TMR;
 		ev->data.tmr.timer_specific = NULL;
-		llc_process_tmr_ev(sk, ev);
+		llc_process_tmr_ev(sk, skb);
 	}
 }
 
 void llc_conn_ack_tmr_cb(unsigned long timeout_data)
 {
 	struct sock* sk = (struct sock *)timeout_data;
-	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
 
 	llc_sk(sk)->ack_timer.running = 0;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type = LLC_CONN_EV_TYPE_ACK_TMR;
 		ev->data.tmr.timer_specific = NULL;
-		llc_process_tmr_ev(sk, ev);
+		llc_process_tmr_ev(sk, skb);
 	}
 }
 
 static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
 
 	llc_sk(sk)->rej_sent_timer.running = 0;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type = LLC_CONN_EV_TYPE_REJ_TMR;
 		ev->data.tmr.timer_specific = NULL;
-		llc_process_tmr_ev(sk, ev);
+		llc_process_tmr_ev(sk, skb);
 	}
 }
 
-int llc_conn_ac_rst_vs(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sk(sk)->X = llc_sk(sk)->vS;
-	llc_conn_ac_set_vs_nr(sk, ev);
+	llc_conn_ac_set_vs_nr(sk, skb);
 	return 0;
 }
 
-int llc_conn_ac_upd_vs(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 nr = PDU_SUPV_GET_Nr(pdu);
 
 	if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X))
-		llc_conn_ac_set_vs_nr(sk, ev);
+		llc_conn_ac_set_vs_nr(sk, skb);
 	return 0;
 }
 
@@ -1572,11 +1540,11 @@
 /**
  *	llc_conn_disc - removes connection from SAP list and frees it
  *	@sk: closed connection
- *	@ev: occurred event
+ *	@skb: occurred event
  *
  *	Returns 2, to indicate the state machine that the connection was freed.
  */
-int llc_conn_disc(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sap_unassign_sock(llc_sk(sk)->sap, sk);
 	llc_sock_free(sk);
@@ -1586,11 +1554,11 @@
 /**
  *	llc_conn_reset - resets connection
  *	@sk : reseting connection.
- *	@ev: occurred event.
+ *	@skb: occurred event.
  *
  *	Stop all timers, empty all queues and reset all flags.
  */
-int llc_conn_reset(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
 {
 	llc_sock_reset(sk);
 	return 0;
@@ -1616,7 +1584,7 @@
 /**
  *	llc_process_tmr_ev - timer backend
  *	@sk: active connection
- *	@ev: occurred event
+ *	@skb: occurred event
  *
  *	This function is called from timer callback functions. When connection
  *	is busy (during sending a data frame) timer expiration event must be
@@ -1624,25 +1592,20 @@
  *	Queued events will process by process_rxframes_events function after
  *	sending data frame. Returns 0 for success, 1 otherwise.
  */
-static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev)
+static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
 {
 	bh_lock_sock(sk);
 	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
-		printk(KERN_WARNING "timer called on closed connection\n");
-		llc_conn_free_ev(ev);
+		printk(KERN_WARNING "%s: timer called on closed connection\n",
+		       __FUNCTION__);
+		llc_conn_free_ev(skb);
 		goto out;
 	}
 	if (!sk->lock.users)
-		llc_conn_send_ev(sk, ev);
+		llc_conn_send_ev(sk, skb);
 	else {
-		struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
-
-		if (skb) {
-			skb->cb[0] = LLC_EVENT;
-			skb->data = (void *)ev;
-			sk_add_backlog(sk, skb);
-		} else
-			llc_conn_free_ev(ev);
+		llc_set_backlog_type(skb, LLC_EVENT);
+		sk_add_backlog(sk, skb);
 	}
 out:
 	bh_unlock_sock(sk);
diff -Nru a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
--- a/net/llc/llc_c_ev.c	Tue Aug 27 12:27:59 2002
+++ b/net/llc/llc_c_ev.c	Tue Aug 27 12:27:59 2002
@@ -40,7 +40,7 @@
 #include <net/llc_c_ev.h>
 #include <net/llc_pdu.h>
 
-#if 0
+#if 1
 #define dprintk(args...) printk(KERN_DEBUG args)
 #else
 #define dprintk(args...)
@@ -87,112 +87,121 @@
 	if (!skb_queue_len(&llc->pdu_unack_q))
 		goto out;
 	skb = skb_peek(&llc->pdu_unack_q);
-	pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	pdu = llc_pdu_sn_hdr(skb);
 	nr1 = LLC_I_GET_NS(pdu);
 	skb = skb_peek_tail(&llc->pdu_unack_q);
-	pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	pdu = llc_pdu_sn_hdr(skb);
 	nr2 = LLC_I_GET_NS(pdu);
 	rc = !llc_circular_between(nr1, nr, (nr2 + 1) % LLC_2_SEQ_NBR_MODULO);
 out:
 	return rc;
 }
 
-int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_CONN_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_conn_resp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_CONN_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1;
 }
 
-int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_DATA_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_DISC_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_RESET_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rst_resp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->data.prim.prim == LLC_RESET_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1;
 }
 
-int llc_conn_ev_local_busy_detected(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1;
 }
 
-int llc_conn_ev_local_busy_cleared(struct sock *sk,
-				   struct llc_conn_state_ev *ev)
+int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1;
 }
 
-int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb)
 {
 	return 1;
 }
 
-int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1;
 }
 
-int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1;
 }
 
-int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_0(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_1(pdu) &&
@@ -200,9 +209,9 @@
 }
 
 int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk,
-					      struct llc_conn_state_ev *ev)
+					      struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 
@@ -212,9 +221,9 @@
 }
 
 int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk,
-					      struct llc_conn_state_ev *ev)
+					      struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 
@@ -224,9 +233,9 @@
 }
 
 int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
-					     struct llc_conn_state_ev *ev)
+					     struct sk_buff *skb)
 {
-	struct llc_pdu_sn * pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn * pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 	u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
@@ -238,39 +247,36 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_0(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_1(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
 
 int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk,
-					      struct llc_conn_state_ev *ev)
+					      struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 
@@ -280,9 +286,9 @@
 }
 
 int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk,
-					      struct llc_conn_state_ev *ev)
+					      struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 
@@ -292,9 +298,9 @@
 }
 
 int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk,
-					      struct llc_conn_state_ev *ev)
+					      struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 
@@ -303,9 +309,9 @@
 }
 
 int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
-					     struct llc_conn_state_ev *ev)
+					     struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vr = llc_sk(sk)->vR;
 	u8 ns = LLC_I_GET_NS(pdu);
 	u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
@@ -317,158 +323,142 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
 }
 
-int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk,
-					struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1;
 }
 
-int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1;
 }
 
-int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	if (!LLC_PDU_IS_CMD(pdu)) {
 		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
@@ -480,11 +470,10 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	if (!LLC_PDU_IS_CMD(pdu)) {
 		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
@@ -502,11 +491,10 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	if (!LLC_PDU_IS_CMD(pdu)) {
 		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
@@ -522,11 +510,10 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	if (!LLC_PDU_IS_RSP(pdu)) {
 		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
@@ -545,11 +532,10 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	if (!LLC_PDU_IS_RSP(pdu)) {
 		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
@@ -567,10 +553,10 @@
 	return rc;
 }
 
-int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
 		rc = 0;
@@ -588,77 +574,79 @@
 }
 
 int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
-					       struct llc_conn_state_ev *ev)
+					       struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vs = llc_sk(sk)->vS;
 	u8 nr = LLC_I_GET_NR(pdu);
 
-	if (!LLC_PDU_IS_CMD(pdu)) {
-		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
-			if (nr != vs &&
-			    llc_util_nr_inside_tx_window(sk, nr)) {
-				dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr "
-					"matched, state = %d, vs = %d, "
-					"nr = %d\n", llc_sk(sk)->state, vs, nr);
-				rc = 0;
-			}
-		}
+	if (!LLC_PDU_IS_CMD(pdu) &&
+	    (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
+	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
+		dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr matched, state = "
+				 "%d, vs = %d, nr = %d\n",
+				 llc_sk(sk)->state, vs, nr);
+		rc = 0;
 	}
 	return rc;
 }
 
 int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
-					       struct llc_conn_state_ev *ev)
+					       struct sk_buff *skb)
 {
 	u16 rc = 1;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	u8 vs = llc_sk(sk)->vS;
 	u8 nr = LLC_I_GET_NR(pdu);
 
-	if (!LLC_PDU_IS_RSP(pdu)) {
-		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
-			if (nr != vs &&
-			    llc_util_nr_inside_tx_window(sk, nr)) {
-				rc = 0;
-				dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set"
-					"_x_inval_nr matched, state = %d, "
-					"vs = %d, nr = %d\n",
-					llc_sk(sk)->state, vs, nr);
-			}
-		}
+	if (!LLC_PDU_IS_RSP(pdu) &&
+	    (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
+	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
+		rc = 0;
+		dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set_x_inval_nr matched, "
+				 "state = %d, vs = %d, nr = %d\n",
+			llc_sk(sk)->state, vs, nr);
 	}
 	return rc;
 }
 
-int llc_conn_ev_rx_any_frame(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rx_any_frame(struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
-int llc_conn_ev_p_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_p_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type != LLC_CONN_EV_TYPE_P_TMR;
 }
 
-int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type != LLC_CONN_EV_TYPE_ACK_TMR;
 }
 
-int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type != LLC_CONN_EV_TYPE_REJ_TMR;
 }
 
-int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type != LLC_CONN_EV_TYPE_BUSY_TMR;
 }
 
-int llc_conn_ev_any_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_any_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
 	return ev->type == LLC_CONN_EV_TYPE_P_TMR ||
 	       ev->type == LLC_CONN_EV_TYPE_ACK_TMR ||
@@ -666,13 +654,15 @@
 	       ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ? 0 : 1;
 }
 
-int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct sk_buff *skb)
 {
 	return 1;
 }
 
-int llc_conn_ev_tx_buffer_full(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1;
 }
@@ -683,26 +673,22 @@
  * the connection and return either a 0 for success or a non-zero value
  * for not-success; verify the event is the type we expect
  */
-int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->data_flag != 1;
 }
 
-int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->data_flag;
 }
 
-int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->data_flag != 2;
 }
 
-int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk,
-				 struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->p_flag != 1;
 }
@@ -710,7 +696,7 @@
 /**
  *	conn_ev_qlfy_last_frame_eq_1 - checks if frame is last in tx window
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	This function determines when frame which is sent, is last frame of
  *	transmit window, if it is then this function return zero else return
@@ -718,8 +704,7 @@
  *	as I-format command with p-bit set to one. Returns 0 if frame is last
  *	frame, 1 otherwise.
  */
-int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return !(skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k);
 }
@@ -727,147 +712,144 @@
 /**
  *	conn_ev_qlfy_last_frame_eq_0 - checks if frame isn't last in tx window
  *	@sk: current connection structure.
- *	@ev: current event.
+ *	@skb: current event.
  *
  *	This function determines when frame which is sent, isn't last frame of
  *	transmit window, if it isn't then this function return zero else return
  *	one. Returns 0 if frame isn't last frame, 1 otherwise.
  */
-int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k;
 }
 
-int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->p_flag;
 }
 
-int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct sk_buff *skb)
 {
 	u8 f_bit;
-	struct sk_buff *skb;
 
-	if (ev->type == LLC_CONN_EV_TYPE_PDU)
-		skb = ev->data.pdu.skb;
-	else
-		skb = ev->data.prim.data->data->conn.skb;
 	llc_pdu_decode_pf_bit(skb, &f_bit);
 	return llc_sk(sk)->p_flag == f_bit ? 0 : 1;
 }
 
-int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->remote_busy_flag;
 }
 
-int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return !llc_sk(sk)->remote_busy_flag;
 }
 
-int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk, struct sk_buff *skb)
 {
 	return !(llc_sk(sk)->retry_count < llc_sk(sk)->n2);
 }
 
-int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk,
-				      struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk, struct sk_buff *skb)
 {
 	return !(llc_sk(sk)->retry_count >= llc_sk(sk)->n2);
 }
 
-int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return !llc_sk(sk)->s_flag;
 }
 
-int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->s_flag;
 }
 
-int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk, struct sk_buff *skb)
 {
 	return !llc_sk(sk)->cause_flag;
 }
 
-int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk, struct sk_buff *skb)
 {
 	return llc_sk(sk)->cause_flag;
 }
 
-int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk,
-				    struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_conn(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_conn(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_CONN;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_disc(struct sock *sk,
-				     struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_DISC;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk,
-					   struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_IMPOSSIBLE;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_failed(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_FAILED;
 	return 0;
 }
 
 int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk,
-					    struct llc_conn_state_ev *ev)
+					    struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_REMOTE_BUSY;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_received(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_received(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_RECEIVED;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk,
-				       struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_REFUSE;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_CONFLICT;
 	return 0;
 }
 
-int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
-					 struct llc_conn_state_ev *ev)
+int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	ev->status = LLC_STATUS_RESET_DONE;
 	return 0;
 }
diff -Nru a/net/llc/llc_c_st.c b/net/llc/llc_c_st.c
--- a/net/llc/llc_c_st.c	Tue Aug 27 12:28:02 2002
+++ b/net/llc/llc_c_st.c	Tue Aug 27 12:28:02 2002
@@ -347,7 +347,7 @@
  * Common dummy state transition; must be last entry for all state
  * transition groups - it'll be on .bss, so will be zeroed.
  */
-static struct llc_conn_state_trans llc_common_state_trans_n;
+static struct llc_conn_state_trans llc_common_state_trans_end;
 
 /* LLC_CONN_STATE_ADM transitions */
 /* State transitions for LLC_CONN_EV_CONN_REQ event */
@@ -432,15 +432,15 @@
  */
 static struct llc_conn_state_trans *llc_adm_state_transitions[] = {
 	[0] = &llc_adm_state_trans_1,		/* Request */
-	[1] = &llc_common_state_trans_n,
-	[2] = &llc_common_state_trans_n,	/* local_busy */
-	[3] = &llc_common_state_trans_n,	/* init_pf_cycle */
-	[4] = &llc_common_state_trans_n,	/* timer */
+	[1] = &llc_common_state_trans_end,
+	[2] = &llc_common_state_trans_end,	/* local_busy */
+	[3] = &llc_common_state_trans_end,	/* init_pf_cycle */
+	[4] = &llc_common_state_trans_end,	/* timer */
 	[5] = &llc_adm_state_trans_2,		/* Receive frame */
 	[6] = &llc_adm_state_trans_3,
 	[7] = &llc_adm_state_trans_4,
 	[8] = &llc_adm_state_trans_5,
-	[9] = &llc_common_state_trans_n,
+	[9] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_SETUP transitions */
@@ -593,18 +593,18 @@
  * one to each transition
  */
 static struct llc_conn_state_trans *llc_setup_state_transitions[] = {
-	 [0] = &llc_common_state_trans_n,	/* Request */
-	 [1] = &llc_common_state_trans_n,	/* local busy */
-	 [2] = &llc_common_state_trans_n,	/* init_pf_cycle */
+	 [0] = &llc_common_state_trans_end,	/* Request */
+	 [1] = &llc_common_state_trans_end,	/* local busy */
+	 [2] = &llc_common_state_trans_end,	/* init_pf_cycle */
 	 [3] = &llc_setup_state_trans_3,	/* Timer */
 	 [4] = &llc_setup_state_trans_7,
 	 [5] = &llc_setup_state_trans_8,
-	 [6] = &llc_common_state_trans_n,
+	 [6] = &llc_common_state_trans_end,
 	 [7] = &llc_setup_state_trans_1,	/* Receive frame */
 	 [8] = &llc_setup_state_trans_2,
 	 [9] = &llc_setup_state_trans_4,
 	[10] = &llc_setup_state_trans_5,
-	[11] = &llc_common_state_trans_n,
+	[11] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_NORMAL transitions */
@@ -1287,13 +1287,13 @@
 	 [2] = &llc_normal_state_trans_2_1,
 	 [3] = &llc_common_state_trans_1,
 	 [4] = &llc_common_state_trans_2,
-	 [5] = &llc_common_state_trans_n,
+	 [5] = &llc_common_state_trans_end,
 	 [6] = &llc_normal_state_trans_21,
 	 [7] = &llc_normal_state_trans_3,	/* Local busy */
 	 [8] = &llc_normal_state_trans_4,
-	 [9] = &llc_common_state_trans_n,
+	 [9] = &llc_common_state_trans_end,
 	[10] = &llc_normal_state_trans_18,	/* Init pf cycle */
-	[11] = &llc_common_state_trans_n,
+	[11] = &llc_common_state_trans_end,
 	[12] = &llc_common_state_trans_11a,	/* Timers */
 	[13] = &llc_common_state_trans_11b,
 	[14] = &llc_common_state_trans_11c,
@@ -1301,7 +1301,7 @@
 	[16] = &llc_normal_state_trans_19,
 	[17] = &llc_normal_state_trans_20a,
 	[18] = &llc_normal_state_trans_20b,
-	[19] = &llc_common_state_trans_n,
+	[19] = &llc_common_state_trans_end,
 	[20] = &llc_normal_state_trans_8b,	/* Receive frames */
 	[21] = &llc_normal_state_trans_9b,
 	[22] = &llc_normal_state_trans_10,
@@ -1337,7 +1337,7 @@
 	[52] = &llc_common_state_trans_8c,
 	[53] = &llc_common_state_trans_9,
 	/* [54] = &llc_common_state_trans_10, */
-	[54] = &llc_common_state_trans_n,
+	[54] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_BUSY transitions */
@@ -2096,16 +2096,16 @@
 	 [2] = &llc_busy_state_trans_1,
 	 [3] = &llc_busy_state_trans_2,
 	 [4] = &llc_busy_state_trans_2_1,
-	 [5] = &llc_common_state_trans_n,
+	 [5] = &llc_common_state_trans_end,
 	 [6] = &llc_busy_state_trans_3,		/* Local busy */
 	 [7] = &llc_busy_state_trans_4,
 	 [8] = &llc_busy_state_trans_5,
 	 [9] = &llc_busy_state_trans_6,
 	[10] = &llc_busy_state_trans_7,
 	[11] = &llc_busy_state_trans_8,
-	[12] = &llc_common_state_trans_n,
+	[12] = &llc_common_state_trans_end,
 	[13] = &llc_busy_state_trans_22,	/* Initiate PF cycle */
-	[14] = &llc_common_state_trans_n,
+	[14] = &llc_common_state_trans_end,
 	[15] = &llc_common_state_trans_11a,	/* Timer */
 	[16] = &llc_common_state_trans_11b,
 	[17] = &llc_common_state_trans_11c,
@@ -2115,7 +2115,7 @@
 	[21] = &llc_busy_state_trans_24b,
 	[22] = &llc_busy_state_trans_25,
 	[23] = &llc_busy_state_trans_26,
-	[24] = &llc_common_state_trans_n,
+	[24] = &llc_common_state_trans_end,
 	[25] = &llc_busy_state_trans_9a,	/* Receive frame */
 	[26] = &llc_busy_state_trans_9b,
 	[27] = &llc_busy_state_trans_10a,
@@ -2150,7 +2150,7 @@
 	[56] = &llc_common_state_trans_8c,
 	[57] = &llc_common_state_trans_9,
 	/* [58] = &llc_common_state_trans_10, */
-	[58] = &llc_common_state_trans_n,
+	[58] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_REJ transitions */
@@ -2770,15 +2770,15 @@
 static struct llc_conn_state_trans *llc_reject_state_transitions[] = {
 	 [0] = &llc_common_state_trans_1,	/* Request */
 	 [1] = &llc_common_state_trans_2,
-	 [2] = &llc_common_state_trans_n,
+	 [2] = &llc_common_state_trans_end,
 	 [3] = &llc_reject_state_trans_1,
 	 [4] = &llc_reject_state_trans_2,
 	 [5] = &llc_reject_state_trans_2_1,
 	 [6] = &llc_reject_state_trans_3,	/* Local busy */
 	 [7] = &llc_reject_state_trans_4,
-	 [8] = &llc_common_state_trans_n,
+	 [8] = &llc_common_state_trans_end,
 	 [9] = &llc_reject_state_trans_17,	/* Initiate PF cycle */
-	[10] = &llc_common_state_trans_n,
+	[10] = &llc_common_state_trans_end,
 	[11] = &llc_common_state_trans_11a,	/* Timer */
 	[12] = &llc_common_state_trans_11b,
 	[13] = &llc_common_state_trans_11c,
@@ -2787,7 +2787,7 @@
 	[16] = &llc_reject_state_trans_19,
 	[17] = &llc_reject_state_trans_20a,
 	[18] = &llc_reject_state_trans_20b,
-	[19] = &llc_common_state_trans_n,
+	[19] = &llc_common_state_trans_end,
 	[20] = &llc_common_state_trans_3,	/* Receive frame */
 	[21] = &llc_common_state_trans_4,
 	[22] = &llc_common_state_trans_5,
@@ -2821,7 +2821,7 @@
 	[49] = &llc_reject_state_trans_15a,
 	[50] = &llc_reject_state_trans_15b,
 	[51] = &llc_reject_state_trans_16,
-	[52] = &llc_common_state_trans_n,
+	[52] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_AWAIT transitions */
@@ -3209,16 +3209,16 @@
 	 [0] = &llc_common_state_trans_1,	/* Request */
 	 [1] = &llc_common_state_trans_2,
 	 [2] = &llc_await_state_trans_1_0,
-	 [3] = &llc_common_state_trans_n,
+	 [3] = &llc_common_state_trans_end,
 	 [4] = &llc_await_state_trans_1,	/* Local busy */
-	 [5] = &llc_common_state_trans_n,
-	 [6] = &llc_common_state_trans_n,	/* Initiate PF Cycle */
+	 [5] = &llc_common_state_trans_end,
+	 [6] = &llc_common_state_trans_end,	/* Initiate PF Cycle */
 	 [7] = &llc_common_state_trans_11a,	/* Timer */
 	 [8] = &llc_common_state_trans_11b,
 	 [9] = &llc_common_state_trans_11c,
 	[10] = &llc_common_state_trans_11d,
 	[11] = &llc_await_state_trans_14,
-	[12] = &llc_common_state_trans_n,
+	[12] = &llc_common_state_trans_end,
 	[13] = &llc_common_state_trans_3,	/* Receive frame */
 	[14] = &llc_common_state_trans_4,
 	[15] = &llc_common_state_trans_5,
@@ -3250,7 +3250,7 @@
 	[40] = &llc_await_state_trans_12a,
 	[41] = &llc_await_state_trans_12b,
 	[42] = &llc_await_state_trans_13,
-	[43] = &llc_common_state_trans_n,
+	[43] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_AWAIT_BUSY transitions */
@@ -3683,18 +3683,18 @@
 	 [0] = &llc_common_state_trans_1,		/* Request */
 	 [1] = &llc_common_state_trans_2,
 	 [2] = &llc_await_busy_state_trans_1_0,
-	 [3] = &llc_common_state_trans_n,
+	 [3] = &llc_common_state_trans_end,
 	 [4] = &llc_await_busy_state_trans_1,		/* Local busy */
 	 [5] = &llc_await_busy_state_trans_2,
 	 [6] = &llc_await_busy_state_trans_3,
-	 [7] = &llc_common_state_trans_n,
-	 [8] = &llc_common_state_trans_n,		/* Initiate PF cycle */
+	 [7] = &llc_common_state_trans_end,
+	 [8] = &llc_common_state_trans_end,		/* Initiate PF cycle */
 	 [9] = &llc_common_state_trans_11a,		/* Timer */
 	[10] = &llc_common_state_trans_11b,
 	[11] = &llc_common_state_trans_11c,
 	[12] = &llc_common_state_trans_11d,
 	[13] = &llc_await_busy_state_trans_16,
-	[14] = &llc_common_state_trans_n,
+	[14] = &llc_common_state_trans_end,
 	[15] = &llc_await_busy_state_trans_4,		/* Receive frame */
 	[16] = &llc_await_busy_state_trans_5a,
 	[17] = &llc_await_busy_state_trans_5b,
@@ -3726,7 +3726,7 @@
 	[43] = &llc_common_state_trans_8c,
 	[44] = &llc_common_state_trans_9,
 	/* [45] = &llc_common_state_trans_10, */
-	[45] = &llc_common_state_trans_n,
+	[45] = &llc_common_state_trans_end,
 };
 
 /* ----------------- LLC_CONN_STATE_AWAIT_REJ transitions --------------- */
@@ -4110,16 +4110,16 @@
 	 [0] = &llc_await_reject_state_trans_1_0,
 	 [1] = &llc_common_state_trans_1,		/* requests */
 	 [2] = &llc_common_state_trans_2,
-	 [3] = &llc_common_state_trans_n,
+	 [3] = &llc_common_state_trans_end,
 	 [4] = &llc_await_rejct_state_trans_1,		/* local busy */
-	 [5] = &llc_common_state_trans_n,
-	 [6] = &llc_common_state_trans_n,		/* Initiate PF cycle */
+	 [5] = &llc_common_state_trans_end,
+	 [6] = &llc_common_state_trans_end,		/* Initiate PF cycle */
 	 [7] = &llc_await_rejct_state_trans_13,	/* timers */
 	 [8] = &llc_common_state_trans_11a,
 	 [9] = &llc_common_state_trans_11b,
 	[10] = &llc_common_state_trans_11c,
 	[11] = &llc_common_state_trans_11d,
-	[12] = &llc_common_state_trans_n,
+	[12] = &llc_common_state_trans_end,
 	[13] = &llc_await_rejct_state_trans_2a,	/* receive frames */
 	[14] = &llc_await_rejct_state_trans_2b,
 	[15] = &llc_await_rejct_state_trans_3,
@@ -4151,7 +4151,7 @@
 	[41] = &llc_common_state_trans_8c,
 	[42] = &llc_common_state_trans_9,
 	/* [43] = &llc_common_state_trans_10, */
-	[43] = &llc_common_state_trans_n,
+	[43] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_D_CONN transitions */
@@ -4392,13 +4392,13 @@
  */
 static struct llc_conn_state_trans *llc_d_conn_state_transitions[] = {
 	 [0] = &llc_d_conn_state_trans_5,	/* Request */
-	 [1] = &llc_common_state_trans_n,
-	 [2] = &llc_common_state_trans_n,	/* Local busy */
-	 [3] = &llc_common_state_trans_n,	/* Initiate PF cycle */
+	 [1] = &llc_common_state_trans_end,
+	 [2] = &llc_common_state_trans_end,	/* Local busy */
+	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */
 	 [4] = &llc_d_conn_state_trans_6,	/* Timer */
 	 [5] = &llc_d_conn_state_trans_7,
 	 [6] = &llc_d_conn_state_trans_8,
-	 [7] = &llc_common_state_trans_n,
+	 [7] = &llc_common_state_trans_end,
 	 [8] = &llc_d_conn_state_trans_1,	/* Receive frame */
 	 [9] = &llc_d_conn_state_trans_1_1,
 	[10] = &llc_d_conn_state_trans_2,
@@ -4406,7 +4406,7 @@
 	[12] = &llc_d_conn_state_trans_3,
 	[13] = &llc_d_conn_state_trans_4,
 	[14] = &llc_d_conn_state_trans_4_1,
-	[15] = &llc_common_state_trans_n,
+	[15] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_RESET transitions */
@@ -4678,14 +4678,14 @@
  */
 static struct llc_conn_state_trans *llc_rst_state_transitions[] = {
 	 [0] = &llc_rst_state_trans_6,		/* Request */
-	 [1] = &llc_common_state_trans_n,
-	 [2] = &llc_common_state_trans_n,	/* Local busy */
-	 [3] = &llc_common_state_trans_n,	/* Initiate PF cycle */
+	 [1] = &llc_common_state_trans_end,
+	 [2] = &llc_common_state_trans_end,	/* Local busy */
+	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */
 	 [4] = &llc_rst_state_trans_3,		/* Timer */
 	 [5] = &llc_rst_state_trans_7,
 	 [6] = &llc_rst_state_trans_8,
 	 [7] = &llc_rst_state_trans_8_1,
-	 [8] = &llc_common_state_trans_n,
+	 [8] = &llc_common_state_trans_end,
 	 [9] = &llc_rst_state_trans_1,		/* Receive frame */
 	[10] = &llc_rst_state_trans_2,
 	[11] = &llc_rst_state_trans_2_1,
@@ -4693,7 +4693,7 @@
 	[13] = &llc_rst_state_trans_4_1,
 	[14] = &llc_rst_state_trans_5,
 	[15] = &llc_rst_state_trans_5_1,
-	[16] = &llc_common_state_trans_n,
+	[16] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_ERROR transitions */
@@ -4849,19 +4849,19 @@
  */
 static struct llc_conn_state_trans *llc_error_state_transitions[] = {
 	 [0] = &llc_error_state_trans_9,	/* Request */
-	 [1] = &llc_common_state_trans_n,
-	 [2] = &llc_common_state_trans_n,	/* Local busy */
-	 [3] = &llc_common_state_trans_n,	/* Initiate PF cycle */
+	 [1] = &llc_common_state_trans_end,
+	 [2] = &llc_common_state_trans_end,	/* Local busy */
+	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */
 	 [4] = &llc_error_state_trans_7,	/* Timer */
 	 [5] = &llc_error_state_trans_8,
-	 [6] = &llc_common_state_trans_n,
+	 [6] = &llc_common_state_trans_end,
 	 [7] = &llc_error_state_trans_1,	/* Receive frame */
 	 [8] = &llc_error_state_trans_2,
 	 [9] = &llc_error_state_trans_3,
 	[10] = &llc_error_state_trans_4,
 	[11] = &llc_error_state_trans_5,
 	[12] = &llc_error_state_trans_6,
-	[13] = &llc_common_state_trans_n,
+	[13] = &llc_common_state_trans_end,
 };
 
 /* LLC_CONN_STATE_TEMP transitions */
@@ -4886,61 +4886,61 @@
  */
 static struct llc_conn_state_trans *llc_temp_state_transitions[] = {
 	[0] = &llc_temp_state_trans_1,		/* requests */
-	[1] = &llc_common_state_trans_n,
-	[2] = &llc_common_state_trans_n,	/* local busy */
-	[3] = &llc_common_state_trans_n,	/* init_pf_cycle */
-	[4] = &llc_common_state_trans_n,	/* timer */
-	[5] = &llc_common_state_trans_n,	/* receive */
+	[1] = &llc_common_state_trans_end,
+	[2] = &llc_common_state_trans_end,	/* local busy */
+	[3] = &llc_common_state_trans_end,	/* init_pf_cycle */
+	[4] = &llc_common_state_trans_end,	/* timer */
+	[5] = &llc_common_state_trans_end,	/* receive */
 };
 
 /* Connection State Transition Table */
-struct llc_conn_state llc_conn_state_table[] = {
-	{
-		.current_state =LLC_CONN_STATE_ADM,
-		.transitions =	llc_adm_state_transitions,
+struct llc_conn_state llc_conn_state_table[NBR_CONN_STATES] = {
+	[LLC_CONN_STATE_ADM - 1] = {
+		.current_state	= LLC_CONN_STATE_ADM,
+		.transitions	= llc_adm_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_SETUP,
-		.transitions =	llc_setup_state_transitions,
+	[LLC_CONN_STATE_SETUP - 1] = {
+		.current_state	= LLC_CONN_STATE_SETUP,
+		.transitions	= llc_setup_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_NORMAL,
-		.transitions =	llc_normal_state_transitions,
+	[LLC_CONN_STATE_NORMAL - 1] = {
+		.current_state	= LLC_CONN_STATE_NORMAL,
+		.transitions	= llc_normal_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_BUSY,
-		.transitions =	llc_busy_state_transitions,
+	[LLC_CONN_STATE_BUSY - 1] = {
+		.current_state	= LLC_CONN_STATE_BUSY,
+		.transitions	= llc_busy_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_REJ,
-		.transitions =	llc_reject_state_transitions,
+	[LLC_CONN_STATE_REJ - 1] = {
+		.current_state	= LLC_CONN_STATE_REJ,
+		.transitions	= llc_reject_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_AWAIT,
-		.transitions =	llc_await_state_transitions,
+	[LLC_CONN_STATE_AWAIT - 1] = {
+		.current_state	= LLC_CONN_STATE_AWAIT,
+		.transitions	= llc_await_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_AWAIT_BUSY,
-		.transitions =	llc_await_busy_state_transitions,
+	[LLC_CONN_STATE_AWAIT_BUSY - 1] = {
+		.current_state	= LLC_CONN_STATE_AWAIT_BUSY,
+		.transitions	= llc_await_busy_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_AWAIT_REJ,
-		.transitions =	llc_await_rejct_state_transitions,
+	[LLC_CONN_STATE_AWAIT_REJ - 1] = {
+		.current_state	= LLC_CONN_STATE_AWAIT_REJ,
+		.transitions	= llc_await_rejct_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_D_CONN,
-		.transitions =	llc_d_conn_state_transitions,
+	[LLC_CONN_STATE_D_CONN - 1] = {
+		.current_state	= LLC_CONN_STATE_D_CONN,
+		.transitions	= llc_d_conn_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_RESET,
-		.transitions =	llc_rst_state_transitions,
+	[LLC_CONN_STATE_RESET - 1] = {
+		.current_state	= LLC_CONN_STATE_RESET,
+		.transitions	= llc_rst_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_ERROR,
-		.transitions =	llc_error_state_transitions,
+	[LLC_CONN_STATE_ERROR - 1] = {
+		.current_state	= LLC_CONN_STATE_ERROR,
+		.transitions	= llc_error_state_transitions,
 	},
-	{
-		.current_state =LLC_CONN_STATE_TEMP,
-		.transitions =	llc_temp_state_transitions,
+	[LLC_CONN_STATE_TEMP - 1] = {
+		.current_state	= LLC_CONN_STATE_TEMP,
+		.transitions	= llc_temp_state_transitions,
 	},
 };
diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c
--- a/net/llc/llc_conn.c	Tue Aug 27 12:27:59 2002
+++ b/net/llc/llc_conn.c	Tue Aug 27 12:27:59 2002
@@ -28,61 +28,42 @@
 
 static int llc_find_offset(int state, int ev_type);
 static void llc_conn_send_pdus(struct sock *sk);
-static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev);
+static int llc_conn_service(struct sock *sk, struct sk_buff *skb);
 static int llc_exec_conn_trans_actions(struct sock *sk,
 				       struct llc_conn_state_trans *trans,
-				       struct llc_conn_state_ev *ev);
-static struct llc_conn_state_trans *
-	     llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev);
+				       struct sk_buff *ev);
+static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
+							struct sk_buff *skb);
 
 /* Offset table on connection states transition diagram */
 static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
 
 /**
- *	llc_conn_alloc_event: allocates an event
- *	@sk: socket that event is associated
- *
- *	Returns pointer to allocated connection on success, %NULL on failure.
- */
-struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk)
-{
-	struct llc_conn_state_ev *ev = NULL;
-
-	/* verify connection is valid, active and open */
-	if (llc_sk(sk)->state != LLC_CONN_OUT_OF_SVC) {
-		/* get event structure to build a station event */
-		ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
-		if (ev)
-			memset(ev, 0, sizeof(*ev));
-	}
-	return ev;
-}
-
-/**
  *	llc_conn_send_event - sends event to connection state machine
  *	@sk: connection
- *	@ev: occurred event
+ *	@skb: occurred event
  *
  *	Sends an event to connection state machine. after processing event
  *	(executing it's actions and changing state), upper layer will be
  *	indicated or confirmed, if needed. Returns 0 for success, 1 for
  *	failure. The socket lock has to be held before calling this function.
  */
-int llc_conn_send_ev(struct sock *sk, struct llc_conn_state_ev *ev)
+int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb)
 {
 	/* sending event to state machine */
-	int rc = llc_conn_service(sk, ev);
+	int rc = llc_conn_service(sk, skb);
 	struct llc_opt *llc = llc_sk(sk);
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 	u8 flag = ev->flag;
 	struct llc_prim_if_block *ind_prim = ev->ind_prim;
 	struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
 
-	llc_conn_free_ev(ev);
+	llc_conn_free_ev(skb);
 #ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY
 	/* check if the connection was freed by the state machine by
 	 * means of llc_conn_disc */
 	if (rc == 2) {
-		printk(KERN_INFO __FUNCTION__ ": rc == 2\n");
+		printk(KERN_INFO "%s: rc == 2\n", __FUNCTION__);
 		rc = -ECONNABORTED;
 		goto out;
 	}
@@ -125,25 +106,26 @@
  *	llc_conn_rtn_pdu - sends received data pdu to upper layer
  *	@sk: Active connection
  *	@skb: Received data frame
- *	@ev: Occurred event
  *
  *	Sends received data pdu to upper layer (by using indicate function).
  *	Prepares service parameters (prim and prim_data). calling indication
  *	function will be done in llc_conn_send_ev.
  */
-void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb,
-		      struct llc_conn_state_ev *ev)
+void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_prim_if_block *prim = &llc_ind_prim;
-	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+	struct llc_prim_if_block *prim = &sap->llc_ind_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 
 	prim_data->data.sk   = sk;
 	prim_data->data.pri  = 0;
 	prim_data->data.skb  = skb;
-	prim_data->data.link = llc_sk(sk)->link;
+	prim_data->data.link = llc->link;
 	prim->data	     = prim_data;
 	prim->prim	     = LLC_DATA_PRIM;
-	prim->sap	     = llc_sk(sk)->sap;
+	prim->sap	     = sap;
 	ev->flag	     = 1;
 	/* saving prepd prim in event for future use in llc_conn_send_ev */
 	ev->ind_prim	     = prim;
@@ -289,34 +271,37 @@
 
 /**
  *	llc_conn_free_ev - free event
- *	@ev: event to free
+ *	@skb: event to free
  *
  *	Free allocated event.
  */
-void llc_conn_free_ev(struct llc_conn_state_ev *ev)
+void llc_conn_free_ev(struct sk_buff *skb)
 {
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
-		/* free the frame that binded to this event */
-		struct llc_pdu_sn *pdu =
-				(struct llc_pdu_sn *)ev->data.pdu.skb->nh.raw;
+		/* free the frame that is bound to this event */
+		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 		if (LLC_PDU_TYPE_IS_I(pdu) || !ev->flag || !ev->ind_prim)
-			kfree_skb(ev->data.pdu.skb);
-	}
-	/* free event structure to free list of the same */
-	kfree(ev);
+			kfree_skb(skb);
+	} else if (ev->type == LLC_CONN_EV_TYPE_PRIM &&
+		   ev->data.prim.prim != LLC_DATA_PRIM)
+		kfree_skb(skb);
+	else if (ev->type == LLC_CONN_EV_TYPE_P_TMR)
+		kfree_skb(skb);
 }
 
 /**
  *	llc_conn_service - finds transition and changes state of connection
  *	@sk: connection
- *	@ev: happened event
+ *	@skb: happened event
  *
  *	This function finds transition that matches with happened event, then
  *	executes related actions and finally changes state of connection.
  *	Returns 0 for success, 1 for failure.
  */
-static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev)
+static int llc_conn_service(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
 	struct llc_conn_state_trans *trans;
@@ -324,9 +309,9 @@
 	if (llc_sk(sk)->state > NBR_CONN_STATES)
 		goto out;
 	rc = 0;
-	trans = llc_qualify_conn_ev(sk, ev);
+	trans = llc_qualify_conn_ev(sk, skb);
 	if (trans) {
-		rc = llc_exec_conn_trans_actions(sk, trans, ev);
+		rc = llc_exec_conn_trans_actions(sk, trans, skb);
 		if (!rc && trans->next_state != NO_STATE_CHANGE)
 			llc_sk(sk)->state = trans->next_state;
 	}
@@ -337,26 +322,28 @@
 /**
  *	llc_qualify_conn_ev - finds transition for event
  *	@sk: connection
- *	@ev: happened event
+ *	@skb: happened event
  *
  *	This function finds transition that matches with happened event.
  *	Returns pointer to found transition on success, %NULL otherwise.
  */
-static struct llc_conn_state_trans *
-	     llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev)
+static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
+							struct sk_buff *skb)
 {
 	struct llc_conn_state_trans **next_trans;
 	llc_conn_ev_qfyr_t *next_qualifier;
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
 	struct llc_conn_state *curr_state =
-				&llc_conn_state_table[llc_sk(sk)->state - 1];
+					&llc_conn_state_table[llc->state - 1];
 
 	/* search thru events for this state until
 	 * list exhausted or until no more
 	 */
 	for (next_trans = curr_state->transitions +
-		llc_find_offset(llc_sk(sk)->state - 1, ev->type);
+		llc_find_offset(llc->state - 1, ev->type);
 	     (*next_trans)->ev; next_trans++) {
-		if (!((*next_trans)->ev)(sk, ev)) {
+		if (!((*next_trans)->ev)(sk, skb)) {
 			/* got POSSIBLE event match; the event may require
 			 * qualification based on the values of a number of
 			 * state flags; if all qualifications are met (i.e.,
@@ -365,7 +352,7 @@
 			 */
 			for (next_qualifier = (*next_trans)->ev_qualifiers;
 			     next_qualifier && *next_qualifier &&
-			     !(*next_qualifier)(sk, ev); next_qualifier++)
+			     !(*next_qualifier)(sk, skb); next_qualifier++)
 				/* nothing */;
 			if (!next_qualifier || !*next_qualifier)
 				/* all qualifiers executed successfully; this is
@@ -382,7 +369,7 @@
  *	llc_exec_conn_trans_actions - executes related actions
  *	@sk: connection
  *	@trans: transition that it's actions must be performed
- *	@ev: happened event
+ *	@skb: happened event
  *
  *	Executes actions that is related to happened event. Returns 0 for
  *	success, 1 to indicate failure of at least one action or 2 if the
@@ -390,14 +377,14 @@
  */
 static int llc_exec_conn_trans_actions(struct sock *sk,
 				       struct llc_conn_state_trans *trans,
-				       struct llc_conn_state_ev *ev)
+				       struct sk_buff *skb)
 {
 	int rc = 0;
 	llc_conn_action_t *next_action;
 
 	for (next_action = trans->ev_actions;
 	     next_action && *next_action; next_action++) {
-		int rc2 = (*next_action)(sk, ev);
+		int rc2 = (*next_action)(sk, skb);
 
 		if (rc2 == 2) {
 			rc = rc2;
diff -Nru a/net/llc/llc_evnt.c b/net/llc/llc_evnt.c
--- a/net/llc/llc_evnt.c	Tue Aug 27 12:28:01 2002
+++ b/net/llc/llc_evnt.c	Tue Aug 27 12:28:01 2002
@@ -24,39 +24,48 @@
 #include <net/llc_pdu.h>
 
 int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
-					   struct llc_station_state_ev *ev)
+					   struct sk_buff *skb)
 {
+	struct llc_station_state_ev *ev = llc_station_ev(skb);	
+	
 	return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev ==
 	       		      LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
 }
 
 int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
-					      struct llc_station_state_ev *ev)
+					      struct sk_buff *skb)
 {
+	struct llc_station_state_ev *ev = llc_station_ev(skb);	
+	
 	return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev ==
 			LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
 }
 
 int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *station,
-						struct llc_station_state_ev *ev)
+						   struct sk_buff *skb)
 {
+	struct llc_station_state_ev *ev = llc_station_ev(skb);	
+	
 	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
 	       station->retry_count < station->maximum_retry ? 0 : 1;
 }
 
 int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
-						struct llc_station_state_ev *ev)
+						   struct sk_buff *skb)
 {
+	struct llc_station_state_ev *ev = llc_station_ev(skb);	
+	
 	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
 		station->retry_count == station->maximum_retry ? 0 : 1;
 }
 
 int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
-				   struct llc_station_state_ev *ev)
+				   struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_station_state_ev *ev = llc_station_ev(skb);	
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_STATION_EV_TYPE_PDU &&
 	       !LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
@@ -66,9 +75,10 @@
 }
 
 int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
-					        struct llc_station_state_ev *ev)
+						  struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_STATION_EV_TYPE_PDU &&
 	       !LLC_PDU_IS_RSP(pdu) &&			/* response PDU */
@@ -79,9 +89,10 @@
 }
 
 int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
-					        struct llc_station_state_ev *ev)
+						  struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_STATION_EV_TYPE_PDU &&
 	       !LLC_PDU_IS_RSP(pdu) &&			/* response PDU */
@@ -92,9 +103,10 @@
 }
 
 int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
-				    struct llc_station_state_ev *ev)
+				    struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_STATION_EV_TYPE_PDU &&
 	       !LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
@@ -103,9 +115,10 @@
 	       !pdu->dsap ? 0 : 1;			/* NULL DSAP */
 }
 
-int llc_stat_ev_disable_req(struct llc_station *station,
-			    struct llc_station_state_ev *ev)
+int llc_stat_ev_disable_req(struct llc_station *station, struct sk_buff *skb)
 {
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
+
 	return ev->type == LLC_STATION_EV_TYPE_PRIM &&
 	       ev->data.prim.prim == LLC_DISABLE_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
diff -Nru a/net/llc/llc_if.c b/net/llc/llc_if.c
--- a/net/llc/llc_if.c	Tue Aug 27 12:28:06 2002
+++ b/net/llc/llc_if.c	Tue Aug 27 12:28:06 2002
@@ -41,12 +41,6 @@
 static int llc_rst_rsp_handler(struct llc_prim_if_block *prim);
 static int llc_no_rsp_handler(struct llc_prim_if_block *prim);
 
-extern void llc_register_sap(unsigned char sap,
-			     int (*rcvfunc)(struct sk_buff *skb,
-					    struct net_device *dev,
-					    struct packet_type *pt));
-extern void llc_unregister_sap(unsigned char sap);
-
 /* table of request handler functions */
 static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = {
 	[LLC_DATAUNIT_PRIM]	= llc_unitdata_req_handler,
@@ -105,7 +99,6 @@
 	sap->parent_station = llc_station_get();
 	/* initialized SAP; add it to list of SAPs this station manages */
 	llc_sap_save(sap);
-	llc_register_sap(lsap, mac_indicate);
 out:
 	return sap;
 err:
@@ -122,7 +115,6 @@
  */
 void llc_sap_close(struct llc_sap *sap)
 {
-	llc_unregister_sap(sap->laddr.lsap);
 	llc_free_sap(sap);
 	MOD_DEC_USE_COUNT;
 }
@@ -141,7 +133,7 @@
 	int rc = 1;
 
 	if (prim->prim > 8 || prim->prim == 6) {
-		printk(KERN_ERR __FUNCTION__ ": invalid primitive %d\n",
+		printk(KERN_ERR "%s: invalid primitive %d\n", __FUNCTION__,
 			prim->prim);
 		goto out;
 	}
@@ -176,15 +168,13 @@
 
 	if (!sap)
 		goto out;
-	ev = llc_sap_alloc_ev(sap);
-	if (!ev)
-		goto out;
+	ev = llc_sap_ev(prim->data->udata.skb);
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_DATAUNIT_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 	ev->data.prim.data = prim;
 	rc = 0;
-	llc_sap_send_ev(sap, ev);
+	llc_sap_send_ev(sap, prim->data->udata.skb);
 out:
 	return rc;
 }
@@ -204,15 +194,13 @@
 	struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
 	if (!sap)
 		goto out;
-	ev = llc_sap_alloc_ev(sap);
-	if (!ev)
-		goto out;
+	ev = llc_sap_ev(prim->data->udata.skb);
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_TEST_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 	ev->data.prim.data = prim;
 	rc = 0;
-	llc_sap_send_ev(sap, ev);
+	llc_sap_send_ev(sap, prim->data->udata.skb);
 out:
 	return rc;
 }
@@ -233,15 +221,13 @@
 
 	if (!sap)
 		goto out;
-	ev = llc_sap_alloc_ev(sap);
-	if (!ev)
-		goto out;
+	ev = llc_sap_ev(prim->data->udata.skb);
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_XID_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 	ev->data.prim.data = prim;
 	rc = 0;
-	llc_sap_send_ev(sap, ev);
+	llc_sap_send_ev(sap, prim->data->udata.skb);
 out:
 	return rc;
 }
@@ -281,29 +267,26 @@
 		llc->failed_data_req = 1;
 		goto out;
 	}
-	rc = -ENOMEM;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
-		ev->type	   = LLC_CONN_EV_TYPE_PRIM;
-		ev->data.prim.prim = LLC_DATA_PRIM;
-		ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-		ev->data.prim.data = prim;
-		prim->data->data.skb->dev = llc->dev;
-		rc = llc_conn_send_ev(sk, ev);
-	}
+	ev = llc_conn_ev(prim->data->data.skb);
+	ev->type		  = LLC_CONN_EV_TYPE_PRIM;
+	ev->data.prim.prim	  = LLC_DATA_PRIM;
+	ev->data.prim.type	  = LLC_PRIM_TYPE_REQ;
+	ev->data.prim.data	  = prim;
+	prim->data->data.skb->dev = llc->dev;
+	rc = llc_conn_send_ev(sk, prim->data->data.skb);
 out:
 	release_sock(sk);
 	return rc;
 }
 
 /**
- *	confirm_impossible - Informs upper layer about failed connection
+ *	llc_confirm_impossible - Informs upper layer about failed connection
  *	@prim: pointer to structure that contains confirmation data.
  *
  *	Informs upper layer about failing in connection establishment. This
  *	function is called by llc_conn_req_handler.
  */
-static void confirm_impossible(struct llc_prim_if_block *prim)
+static void llc_confirm_impossible(struct llc_prim_if_block *prim)
 {
 	prim->data->conn.status = LLC_STATUS_IMPOSSIBLE;
 	prim->sap->conf(prim);
@@ -324,7 +307,7 @@
 	int rc = -EBUSY;
 	struct llc_opt *llc;
 	struct llc_sap *sap = prim->sap;
-	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb;
 	struct net_device *ddev = mac_dev_peer(prim->data->conn.dev,
 					       prim->data->conn.dev->type,
 					       prim->data->conn.daddr.mac),
@@ -338,11 +321,11 @@
 
 	memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac));
 	laddr.lsap = prim->data->conn.saddr.lsap;
-	memcpy(daddr.mac, ddev->dev_addr, sizeof(daddr.mac));
+	memcpy(daddr.mac, prim->data->conn.daddr.mac, sizeof(daddr.mac));
 	daddr.lsap = prim->data->conn.daddr.lsap;
 	sk = llc_find_sock(sap, &daddr, &laddr);
 	if (sk) {
-		confirm_impossible(prim);
+		llc_confirm_impossible(prim);
 		goto out_put;
 	}
 	rc = -ENOMEM; 
@@ -353,7 +336,7 @@
 	} else {
 		sk = llc_sock_alloc();
 		if (!sk) {
-			confirm_impossible(prim);
+			llc_confirm_impossible(prim);
 			goto out;
 		}
 		prim->data->conn.sk = sk;
@@ -368,18 +351,20 @@
 	llc->dev     = ddev;
 	llc->link    = prim->data->conn.link;
 	llc->handler = prim->data->conn.handler;
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	skb = alloc_skb(1, GFP_ATOMIC);
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type	   = LLC_CONN_EV_TYPE_PRIM;
 		ev->data.prim.prim = LLC_CONN_PRIM;
 		ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, ev);
+		rc = llc_conn_send_ev(sk, skb);
 	}
 	if (rc) {
 		llc_sap_unassign_sock(sap, sk);
 		llc_sock_free(sk);
-		confirm_impossible(prim);
+		llc_confirm_impossible(prim);
 	}
 	release_sock(sk);
 out_put:
@@ -401,6 +386,7 @@
 {
 	u16 rc = 1;
 	struct llc_conn_state_ev *ev;
+	struct sk_buff *skb;
 	struct sock* sk = prim->data->disc.sk;
 
 	sock_hold(sk);
@@ -408,17 +394,19 @@
 	if (llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
 	    llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
 		goto out;
-	/* postpone unassigning the connection from its SAP and returning the
+	/*
+	 * Postpone unassigning the connection from its SAP and returning the
 	 * connection until all ACTIONs have been completely executed
 	 */
-	ev = llc_conn_alloc_ev(sk);
-	if (!ev)
+	skb = alloc_skb(1, GFP_ATOMIC);
+	if (!skb)
 		goto out;
-	ev->type = LLC_CONN_EV_TYPE_PRIM;
+	ev = llc_conn_ev(skb);
+	ev->type	   = LLC_CONN_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_DISC_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 	ev->data.prim.data = prim;
-	rc = llc_conn_send_ev(sk, ev);
+	rc = llc_conn_send_ev(sk, skb);
 out:
 	release_sock(sk);
 	sock_put(sk);
@@ -436,18 +424,20 @@
  */
 static int llc_rst_req_handler(struct llc_prim_if_block *prim)
 {
+	struct sk_buff *skb;
 	int rc = 1;
 	struct sock *sk = prim->data->res.sk;
-	struct llc_conn_state_ev *ev;
 
 	lock_sock(sk);
-	ev = llc_conn_alloc_ev(sk);
-	if (ev) {
+	skb = alloc_skb(1, GFP_ATOMIC);
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+
 		ev->type = LLC_CONN_EV_TYPE_PRIM;
 		ev->data.prim.prim = LLC_RESET_PRIM;
 		ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, ev);
+		rc = llc_conn_send_ev(sk, skb);
 	}
 	release_sock(sk);
 	return rc;
@@ -505,18 +495,21 @@
 static int llc_rst_rsp_handler(struct llc_prim_if_block *prim)
 {
 	int rc = 1;
-	/* network layer supplies connection handle; map it to a connection;
+	/*
+	 * Network layer supplies connection handle; map it to a connection;
 	 * package as event and send it to connection event handler
 	 */
 	struct sock *sk = prim->data->res.sk;
-	struct llc_conn_state_ev *ev = llc_conn_alloc_ev(sk);
+	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+
+	if (skb) {
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
-	if (ev) {
 		ev->type	   = LLC_CONN_EV_TYPE_PRIM;
 		ev->data.prim.prim = LLC_RESET_PRIM;
 		ev->data.prim.type = LLC_PRIM_TYPE_RESP;
 		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, ev);
+		rc = llc_conn_send_ev(sk, skb);
 	}
 	return rc;
 }
diff -Nru a/net/llc/llc_mac.c b/net/llc/llc_mac.c
--- a/net/llc/llc_mac.c	Tue Aug 27 12:28:08 2002
+++ b/net/llc/llc_mac.c	Tue Aug 27 12:28:08 2002
@@ -27,6 +27,12 @@
 #include <net/llc_s_ev.h>
 #include <linux/trdevice.h>
 
+#if 1
+#define dprintk(args...) printk(KERN_DEBUG args)
+#else
+#define dprintk(args...)
+#endif
+
 /* function prototypes */
 static void fix_up_incoming_skb(struct sk_buff *skb);
 
@@ -46,7 +52,7 @@
 	int pri = GFP_ATOMIC, rc = -1;
 
 	if (!skb->dev) {
-		printk(KERN_ERR __FUNCTION__ ": skb->dev == NULL!");
+		dprintk(KERN_ERR "%s: skb->dev == NULL!", __FUNCTION__);
 		goto out;
 	}
 	if (skb->sk)
@@ -83,27 +89,30 @@
 	 * receives, do not try to analyse it.
 	 */
 	if (skb->pkt_type == PACKET_OTHERHOST) {
-		printk(KERN_INFO __FUNCTION__ ": PACKET_OTHERHOST\n");
+		dprintk(KERN_INFO "%s: PACKET_OTHERHOST\n", __FUNCTION__);
 		goto drop;
 	}
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (!skb)
 		goto out;
 	fix_up_incoming_skb(skb);
-	pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	pdu = llc_pdu_sn_hdr(skb);
 	if (!pdu->dsap) { /* NULL DSAP, refer to station */
-		llc_pdu_router(NULL, NULL, skb, 0);
+		if (llc_pdu_router(NULL, NULL, skb, 0))
+			goto drop;
 		goto out;
 	}
 	sap = llc_sap_find(pdu->dsap);
 	if (!sap) /* unknown SAP */
 		goto drop;
 	llc_decode_pdu_type(skb, &dest);
-	if (dest == LLC_DEST_SAP) /* type 1 services */
-		llc_pdu_router(sap, NULL, skb, LLC_TYPE_1);
-	else if (dest == LLC_DEST_CONN) {
+	if (dest == LLC_DEST_SAP) { /* type 1 services */
+		if (llc_pdu_router(sap, NULL, skb, LLC_TYPE_1))
+			goto drop;
+	} else if (dest == LLC_DEST_CONN) {
 		struct llc_addr saddr, daddr;
 		struct sock *sk;
+		int rc;
 
 		llc_pdu_decode_sa(skb, saddr.mac);
 		llc_pdu_decode_ssap(skb, &saddr.lsap);
@@ -134,14 +143,18 @@
 			 * in the llc_req_prim (llc_data_req_handler, etc) and
 			 * add the request to the backlog, well see...
 			 */
-			llc_pdu_router(llc_sk(sk)->sap, sk, skb, LLC_TYPE_2);
-			bh_unlock_sock(sk);
+			rc = llc_pdu_router(llc_sk(sk)->sap, sk, skb,
+					    LLC_TYPE_2);
 		} else {
-			skb->cb[0] = LLC_PACKET;
+			dprintk(KERN_INFO "%s: add to backlog\n", __FUNCTION__);
+			llc_set_backlog_type(skb, LLC_PACKET);
 			sk_add_backlog(sk, skb);
-			bh_unlock_sock(sk);
+			rc = 0;
 		}
+		bh_unlock_sock(sk);
 		sock_put(sk);
+		if (rc)
+			goto drop;
 	} else /* unknown or not supported pdu */
  		goto drop;
 out:
@@ -196,41 +209,34 @@
 int llc_pdu_router(struct llc_sap *sap, struct sock* sk,
 		   struct sk_buff *skb, u8 type)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 	int rc = 0;
 
 	if (!pdu->dsap) {
 		struct llc_station *station = llc_station_get();
-		struct llc_station_state_ev *stat_ev =
-						  llc_station_alloc_ev(station);
-		if (stat_ev) {
-			stat_ev->type		 = LLC_STATION_EV_TYPE_PDU;
-			stat_ev->data.pdu.skb	 = skb;
-			stat_ev->data.pdu.reason = 0;
-			llc_station_send_ev(station, stat_ev);
-		}
+		struct llc_station_state_ev *ev = llc_station_ev(skb);
+
+		ev->type	    = LLC_STATION_EV_TYPE_PDU;
+		ev->data.pdu.reason = 0;
+		llc_station_send_ev(station, skb);
 	} else if (type == LLC_TYPE_1) {
-		struct llc_sap_state_ev *sap_ev = llc_sap_alloc_ev(sap);
+		struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 
-		if (sap_ev) {
-			sap_ev->type		= LLC_SAP_EV_TYPE_PDU;
-			sap_ev->data.pdu.skb	= skb;
-			sap_ev->data.pdu.reason = 0;
-			llc_sap_send_ev(sap, sap_ev);
-		}
+		ev->type	    = LLC_SAP_EV_TYPE_PDU;
+		ev->data.pdu.reason = 0;
+		llc_sap_send_ev(sap, skb);
 	} else if (type == LLC_TYPE_2) {
-		struct llc_conn_state_ev *conn_ev = llc_conn_alloc_ev(sk);
+		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 		struct llc_opt *llc = llc_sk(sk);
 
 		if (!llc->dev)
 			llc->dev = skb->dev;
-		if (conn_ev) {
-			conn_ev->type		 = LLC_CONN_EV_TYPE_PDU;
-			conn_ev->data.pdu.skb	 = skb;
-			conn_ev->data.pdu.reason = 0;
-			rc = llc_conn_send_ev(sk, conn_ev);
-		}
-	}
+
+		ev->type	    = LLC_CONN_EV_TYPE_PDU;
+		ev->data.pdu.reason = 0;
+		rc = llc_conn_send_ev(sk, skb);
+	} else
+		rc = -EINVAL;
 	return rc;
 }
 
diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c
--- a/net/llc/llc_main.c	Tue Aug 27 12:28:02 2002
+++ b/net/llc/llc_main.c	Tue Aug 27 12:28:02 2002
@@ -38,27 +38,19 @@
 /* static function prototypes */
 static void llc_station_service_events(struct llc_station *station);
 static void llc_station_free_ev(struct llc_station *station,
-				struct llc_station_state_ev *ev);
+				struct sk_buff *skb);
 static void llc_station_send_pdus(struct llc_station *station);
 static u16 llc_station_next_state(struct llc_station *station,
-			      struct llc_station_state_ev *ev);
+				  struct sk_buff *skb);
 static u16 llc_exec_station_trans_actions(struct llc_station *station,
 					  struct llc_station_state_trans *trans,
-					  struct llc_station_state_ev *ev);
+					  struct sk_buff *skb);
 static struct llc_station_state_trans *
 			     llc_find_station_trans(struct llc_station *station,
-					       struct llc_station_state_ev *ev);
+						    struct sk_buff *skb);
 static int llc_rtn_all_conns(struct llc_sap *sap);
 
-extern void llc_register_sap(unsigned char sap,
-			     int (*rcvfunc)(struct sk_buff *skb,
-					    struct net_device *dev,
-					    struct packet_type *pt));
-extern void llc_unregister_sap(unsigned char sap);
-
 static struct llc_station llc_main_station;	/* only one of its kind */
-struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
-static union llc_u_prim_data llc_ind_data_prim, llc_cfm_data_prim;
 
 /**
  *	llc_sap_alloc - allocates and initializes sap.
@@ -76,6 +68,8 @@
 		spin_lock_init(&sap->sk_list.lock);
 		INIT_LIST_HEAD(&sap->sk_list.list);
 		skb_queue_head_init(&sap->mac_pdu_q);
+		sap->llc_ind_prim.data = &sap->llc_ind_data_prim;
+		sap->llc_cfm_prim.data = &sap->llc_cfm_data_prim;
 	}
 	return sap;
 }
@@ -150,21 +144,23 @@
 	int rc = 0;
 	struct llc_opt *llc = llc_sk(sk);
 
-	if (skb->cb[0] == LLC_PACKET) {
+	if (llc_backlog_type(skb) == LLC_PACKET) {
 		if (llc->state > 1) /* not closed */
 			rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2);
 		else
 			kfree_skb(skb);
-	} else if (skb->cb[0] == LLC_EVENT) {
-		struct llc_conn_state_ev *ev =
-					(struct llc_conn_state_ev *)skb->data;
+	} else if (llc_backlog_type(skb) == LLC_EVENT) {
 		/* timer expiration event */
 		if (llc->state > 1)  /* not closed */
-			rc = llc_conn_send_ev(sk, ev);
+			rc = llc_conn_send_ev(sk, skb);
 		else
-			llc_conn_free_ev(ev);
+			llc_conn_free_ev(skb);
+		kfree_skb(skb);
+	} else {
+		printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);
 		kfree_skb(skb);
 	}
+
 	return rc;
 }
 
@@ -238,9 +234,11 @@
 	/* stop all (possibly) running timers */
 	llc_conn_ac_stop_all_timers(sk, NULL);
 	/* handle return of frames on lists */
-	printk(KERN_INFO __FUNCTION__ ": unackq=%d, txq=%d\n",
+#if 0
+	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
 		skb_queue_len(&llc->pdu_unack_q),
 		skb_queue_len(&sk->write_queue));
+#endif
 	skb_queue_purge(&sk->write_queue);
 	skb_queue_purge(&llc->pdu_unack_q);
 	if (free)
@@ -322,34 +320,17 @@
 }
 
 /**
- *	llc_station_alloc_ev - allocates an event
- *	@station: Address of the station
- *
- *	Allocates an event in this station. Returns the allocated event on
- *	success, %NULL otherwise.
- */
-struct llc_station_state_ev *llc_station_alloc_ev(struct llc_station *station)
-{
-	struct llc_station_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
-
-	if (ev)
-		memset(ev, 0, sizeof(*ev));
-	return ev;
-}
-
-/**
  *	llc_station_send_ev: queue event and try to process queue.
  *	@station: Address of the station
- *	@ev: Address of the event
+ *	@skb: Address of the event
  *
  *	Queues an event (on the station event queue) for handling by the
  *	station state machine and attempts to process any queued-up events.
  */
-void llc_station_send_ev(struct llc_station *station,
-			 struct llc_station_state_ev *ev)
+void llc_station_send_ev(struct llc_station *station, struct sk_buff *skb)
 {
 	spin_lock_bh(&station->ev_q.lock);
-	list_add_tail(&ev->node, &station->ev_q.list);
+	skb_queue_tail(&station->ev_q.list, skb);
 	llc_station_service_events(station);
 	spin_unlock_bh(&station->ev_q.lock);
 }
@@ -390,18 +371,17 @@
 /**
  *	llc_station_free_ev - frees an event
  *	@station: Address of the station
- *	@event: Address of the event
+ *	@skb: Address of the event
  *
  *	Frees an event.
  */
 static void llc_station_free_ev(struct llc_station *station,
-				struct llc_station_state_ev *ev)
+				struct sk_buff *skb)
 {
-	struct sk_buff *skb = ev->data.pdu.skb;
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
 
 	if (ev->type == LLC_STATION_EV_TYPE_PDU)
 		kfree_skb(skb);
-	kfree(ev);
 }
 
 /**
@@ -418,39 +398,35 @@
  */
 static void llc_station_service_events(struct llc_station *station)
 {
-	struct llc_station_state_ev *ev;
-	struct list_head *entry, *tmp;
+	struct sk_buff *skb;
 
-	list_for_each_safe(entry, tmp, &station->ev_q.list) {
-		ev = list_entry(entry, struct llc_station_state_ev, node);
-		list_del(&ev->node);
-		llc_station_next_state(station, ev);
-	}
+	while ((skb = skb_dequeue(&station->ev_q.list)) != NULL)
+		llc_station_next_state(station, skb);
 }
 
 /**
  *	llc_station_next_state - processes event and goes to the next state
  *	@station: Address of the station
- *	@ev: Address of the event
+ *	@skb: Address of the event
  *
  *	Processes an event, executes any transitions related to that event and
  *	updates the state of the station.
  */
 static u16 llc_station_next_state(struct llc_station *station,
-			      struct llc_station_state_ev *ev)
+				  struct sk_buff *skb)
 {
 	u16 rc = 1;
 	struct llc_station_state_trans *trans;
 
 	if (station->state > LLC_NBR_STATION_STATES)
 		goto out;
-	trans = llc_find_station_trans(station, ev);
+	trans = llc_find_station_trans(station, skb);
 	if (trans) {
 		/* got the state to which we next transition; perform the
 		 * actions associated with this transition before actually
 		 * transitioning to the next state
 		 */
-		rc = llc_exec_station_trans_actions(station, trans, ev);
+		rc = llc_exec_station_trans_actions(station, trans, skb);
 		if (!rc)
 			/* transition station to next state if all actions
 			 * execute successfully; done; wait for next event
@@ -462,22 +438,22 @@
 		 */
 		rc = 0;
 out:
-	llc_station_free_ev(station, ev);
+	llc_station_free_ev(station, skb);
 	return rc;
 }
 
 /**
  *	llc_find_station_trans - finds transition for this event
  *	@station: Address of the station
- *	@ev: Address of the event
+ *	@skb: Address of the event
  *
  *	Search thru events of the current state of the station until list
  *	exhausted or it's obvious that the event is not valid for the current
  *	state. Returns the address of the transition if cound, %NULL otherwise.
  */
 static struct llc_station_state_trans *
-	llc_find_station_trans(struct llc_station *station,
-				struct llc_station_state_ev *ev)
+			llc_find_station_trans(struct llc_station *station,
+					       struct sk_buff *skb)
 {
 	int i = 0;
 	struct llc_station_state_trans *rc = NULL;
@@ -486,7 +462,7 @@
 				&llc_station_state_table[station->state - 1];
 
 	for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
-		if (!next_trans[i]->ev(station, ev)) {
+		if (!next_trans[i]->ev(station, skb)) {
 			rc = next_trans[i];
 			break;
 		}
@@ -497,21 +473,20 @@
  *	llc_exec_station_trans_actions - executes actions for transition
  *	@station: Address of the station
  *	@trans: Address of the transition
- *	@ev: Address of the event that caused the transition
+ *	@skb: Address of the event that caused the transition
  *
  *	Executes actions of a transition of the station state machine. Returns
  *	0 if all actions complete successfully, nonzero otherwise.
  */
 static u16 llc_exec_station_trans_actions(struct llc_station *station,
 					  struct llc_station_state_trans *trans,
-					  struct llc_station_state_ev *ev)
+					  struct sk_buff *skb)
 {
 	u16 rc = 0;
-	llc_station_action_t *next_action;
+	llc_station_action_t *next_action = trans->ev_actions;
 
-	for (next_action = trans->ev_actions;
-	     next_action && *next_action; next_action++)
-		if ((*next_action)(station, ev))
+	for (; next_action && *next_action; next_action++)
+		if ((*next_action)(station, skb))
 			rc = 1;
 	return rc;
 }
@@ -580,6 +555,18 @@
 	return len;
 }
 
+static struct packet_type llc_packet_type = {
+	.type = __constant_htons(ETH_P_802_2),
+	.func = mac_indicate,
+	.data = (void *)1,
+};
+
+static struct packet_type llc_tr_packet_type = {
+	.type = __constant_htons(ETH_P_TR_802_2),
+	.func = mac_indicate,
+	.data = (void *)1,
+};
+
 static char llc_banner[] __initdata =
 		KERN_INFO "LLC 2.0 by Procom, 1997, Arnaldo C. Melo, 2001\n"
 		KERN_INFO "NET4.0 IEEE 802.2 extended support\n";
@@ -589,21 +576,24 @@
 static int __init llc_init(void)
 {
 	u16 rc = 0;
+	struct sk_buff *skb;
 	struct llc_station_state_ev *ev;
 
 	printk(llc_banner);
-	INIT_LIST_HEAD(&llc_main_station.ev_q.list);
-	spin_lock_init(&llc_main_station.ev_q.lock);
 	INIT_LIST_HEAD(&llc_main_station.sap_list.list);
 	spin_lock_init(&llc_main_station.sap_list.lock);
 	skb_queue_head_init(&llc_main_station.mac_pdu_q);
-	ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
-	if (!ev)
+	skb_queue_head_init(&llc_main_station.ev_q.list);
+	spin_lock_init(&llc_main_station.ev_q.lock);
+	skb = alloc_skb(1, GFP_ATOMIC);
+	if (!skb)
 		goto err;
 	llc_build_offset_table();
+	ev = llc_station_ev(skb);
 	memset(ev, 0, sizeof(*ev));
-	if(dev_base->next)
-		memcpy(llc_main_station.mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+	if (dev_base->next)
+		memcpy(llc_main_station.mac_sa,
+		       dev_base->next->dev_addr, ETH_ALEN);
 	else
 		memset(llc_main_station.mac_sa, 0, ETH_ALEN);
 	llc_main_station.ack_timer.expires = jiffies + 3 * HZ;
@@ -611,13 +601,11 @@
 	llc_main_station.state		= LLC_STATION_STATE_DOWN;
 	ev->type	= LLC_STATION_EV_TYPE_SIMPLE;
 	ev->data.a.ev	= LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
-	rc = llc_station_next_state(&llc_main_station, ev);
-	llc_ind_prim.data = &llc_ind_data_prim;
-	llc_cfm_prim.data = &llc_cfm_data_prim;
+	rc = llc_station_next_state(&llc_main_station, skb);
 	proc_net_create("802.2", 0, llc_proc_get_info);
-	/* initialize the station component */
-	llc_register_sap(0, mac_indicate);
 	llc_ui_init();
+	dev_add_pack(&llc_packet_type);
+	dev_add_pack(&llc_tr_packet_type);
 out:
 	return rc;
 err:
@@ -629,7 +617,8 @@
 static void __exit llc_exit(void)
 {
 	llc_ui_exit();
-	llc_unregister_sap(0);
+	dev_remove_pack(&llc_packet_type);
+	dev_remove_pack(&llc_tr_packet_type);
 	proc_net_remove("802.2");
 }
 
diff -Nru a/net/llc/llc_pdu.c b/net/llc/llc_pdu.c
--- a/net/llc/llc_pdu.c	Tue Aug 27 12:28:01 2002
+++ b/net/llc/llc_pdu.c	Tue Aug 27 12:28:01 2002
@@ -19,26 +19,23 @@
 #include <net/llc_main.h>
 
 static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
-static int llc_get_llc_hdr_length(u8 pdu_type);
+static __inline__ int llc_get_hdr_len(u8 pdu_type);
 static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu);
 
 /**
  *	llc_pdu_header_init - initializes pdu header
  *	@skb: input skb that header must be set into it.
- *	@pdu_type: type of PDU (U, I or S).
+ *	@type: type of PDU (U, I or S).
  *	@ssap: source sap.
  *	@dsap: destination sap.
  *	@cr: command/response bit (0 or 1).
  *
  *	This function sets DSAP, SSAP and command/Response bit in LLC header.
  */
-void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap,
-			 u8 dsap, u8 cr)
+void llc_pdu_header_init(struct sk_buff *skb, u8 type, u8 ssap, u8 dsap, u8 cr)
 {
-	struct llc_pdu_un *pdu;
-
-	skb->nh.raw = skb_push(skb, llc_get_llc_hdr_length(pdu_type));
-	pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu =
+		     llc_set_pdu_hdr(skb, skb_push(skb, llc_get_hdr_len(type)));
 	pdu->dsap = dsap;
 	pdu->ssap = ssap;
 	pdu->ssap |= cr;
@@ -46,7 +43,7 @@
 
 void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type)
 {
-	((struct llc_pdu_un *)skb->nh.raw)->ssap |= pdu_type;
+	llc_pdu_un_hdr(skb)->ssap |= pdu_type;
 }
 
 /**
@@ -66,7 +63,7 @@
 	if (llc_pdu_decode_pdu_type(skb, &pdu_type))
 		goto out;
 
-	pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	pdu = llc_pdu_sn_hdr(skb);
 	
 	switch (pdu_type) {
 		case LLC_PDU_TYPE_I:
@@ -98,7 +95,7 @@
 	if (rc)
 		goto out;
 
-	pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	pdu = llc_pdu_sn_hdr(skb);
 
 	switch (pdu_type) {
 		case LLC_PDU_TYPE_I:
@@ -123,8 +120,7 @@
  */
 int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit)
 {
-	*cr_bit = ((struct llc_pdu_un *)skb->nh.raw)->ssap &
-		  LLC_PDU_CMD_RSP_MASK;
+	*cr_bit = llc_pdu_un_hdr(skb)->ssap & LLC_PDU_CMD_RSP_MASK;
 	return 0;
 }
 
@@ -170,7 +166,7 @@
  */
 int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap)
 {
-	*dsap = ((struct llc_pdu_un *)skb->nh.raw)->dsap & 0xFE;
+	*dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE;
 	return 0;
 }
 
@@ -184,7 +180,7 @@
  */
 int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
 {
-	*ssap = ((struct llc_pdu_un *)skb->nh.raw)->ssap & 0xFE;
+	*ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE;
 	return 0;
 }
 
@@ -196,7 +192,7 @@
  */
 int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_1_PDU_CMD_UI;
@@ -214,7 +210,7 @@
 			    u8 rx_window)
 {
 	struct llc_xid_info *xid_info;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1	 = LLC_PDU_TYPE_U;
 	pdu->ctrl_1	|= LLC_1_PDU_CMD_XID;
@@ -235,7 +231,7 @@
  */
 int llc_pdu_init_as_test_cmd(struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST;
@@ -252,7 +248,7 @@
  */
 int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC;
@@ -271,7 +267,7 @@
  */
 int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_I;
 	pdu->ctrl_2  = 0;
@@ -291,7 +287,7 @@
  */
 int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ;
@@ -312,7 +308,7 @@
  */
 int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR;
@@ -333,7 +329,7 @@
  */
 int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RR;
@@ -352,7 +348,7 @@
  */
 int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME;
@@ -369,7 +365,7 @@
  */
 int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_DM;
@@ -389,7 +385,7 @@
 			    u8 rx_window)
 {
 	struct llc_xid_info *xid_info;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1	 = LLC_PDU_TYPE_U;
 	pdu->ctrl_1	|= LLC_1_PDU_CMD_XID;
@@ -413,15 +409,16 @@
 int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
 {
 	int dsize;
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST;
 	pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
 	if (ev_skb->protocol == ntohs(ETH_P_802_2)) {
+		struct llc_pdu_un *ev_pdu = llc_pdu_un_hdr(ev_skb);
+
 		dsize = ntohs(((struct ethhdr *)ev_skb->mac.raw)->h_proto) - 3;
-		memcpy(((u8 *)skb->nh.raw) + 3,
-		       ((u8 *)ev_skb->nh.raw) + 3, dsize);
+		memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize);
 		skb_put(skb, dsize);
 	}
 	return 0;
@@ -444,7 +441,7 @@
 	struct llc_frmr_info *frmr_info;
 	u8 prev_pf = 0;
 	u8 *ctrl;
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR;
@@ -476,7 +473,7 @@
  */
 int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RR;
@@ -497,7 +494,7 @@
  */
 int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ;
@@ -518,7 +515,7 @@
  */
 int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR;
@@ -538,7 +535,7 @@
  */
 int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_UA;
@@ -555,7 +552,7 @@
  */
 static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)skb->nh.raw;
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	if (pdu->ctrl_1 & 1) {
 		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
@@ -577,7 +574,7 @@
 int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
 {
 	u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */
-	struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
+	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
 	if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U)
 		goto out;
@@ -603,26 +600,21 @@
 }
 
 /**
- *	get_llc_hdr_len - designates LLC header length
- *	@pdu_type: type of PDU.
+ *	llc_get_hdr_len - designates LLC header length
+ *	@type: type of PDU.
  *
  *	This function designates LLC header length of PDU. header length for I
  *	and S PDU is 4 and for U is 3 bytes. Returns the length of header.
  */
-static int llc_get_llc_hdr_length(u8 pdu_type)
+static __inline__ int llc_get_hdr_len(u8 type)
 {
-	int rtn_val = 0;
+	static int hdr_len[] = {
+		[LLC_PDU_TYPE_U] = 3,
+		[LLC_PDU_TYPE_I] = 4,
+		[LLC_PDU_TYPE_S] = 4,
+	};
 
-	switch (pdu_type) {
-		case LLC_PDU_TYPE_I:
-		case LLC_PDU_TYPE_S:
-			rtn_val = 4;
-			break;
-		case LLC_PDU_TYPE_U:
-			rtn_val = 3;
-			break;
-	}
-	return rtn_val;
+	return hdr_len[type];
 }
 
 /**
diff -Nru a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c
--- a/net/llc/llc_s_ac.c	Tue Aug 27 12:28:02 2002
+++ b/net/llc/llc_s_ac.c	Tue Aug 27 12:28:02 2002
@@ -28,32 +28,31 @@
 /**
  *	llc_sap_action_unit_data_ind - forward UI PDU to network layer
  *	@sap: SAP
- *	@ev: the event to forward
+ *	@skb: the event to forward
  *
  *	Received a UI PDU from MAC layer; forward to network layer as a
  *	UNITDATA INDICATION; verify our event is the kind we expect
  */
-int llc_sap_action_unitdata_ind(struct llc_sap *sap,
-				struct llc_sap_state_ev *ev)
+int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb)
 {
-	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	llc_sap_rtn_pdu(sap, skb);
 	return 0;
 }
 
 /**
  *	llc_sap_action_send_ui - sends UI PDU resp to UNITDATA REQ to MAC layer
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Sends a UI PDU to the MAC layer in response to a UNITDATA REQUEST
  *	primitive from the network layer. Verifies event is a primitive type of
  *	event. Verify the primitive is a UNITDATA REQUEST.
  */
-int llc_sap_action_send_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 	struct llc_prim_if_block *prim = ev->data.prim.data;
 	struct llc_prim_unit_data *prim_data = &prim->data->udata;
-	struct sk_buff *skb = prim->data->udata.skb;
 	int rc;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
@@ -71,17 +70,17 @@
 /**
  *	llc_sap_action_send_xid_c - send XID PDU as response to XID REQ
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Send a XID command PDU to MAC layer in response to a XID REQUEST
  *	primitive from the network layer. Verify event is a primitive type
  *	event. Verify the primitive is a XID REQUEST.
  */
-int llc_sap_action_send_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 	struct llc_prim_if_block *prim = ev->data.prim.data;
 	struct llc_prim_xid *prim_data = &prim->data->xid;
-	struct sk_buff *skb = prim_data->skb;
 	int rc;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
@@ -99,33 +98,32 @@
 /**
  *	llc_sap_action_send_xid_r - send XID PDU resp to MAC for received XID
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Send XID response PDU to MAC in response to an earlier received XID
  *	command PDU. Verify event is a PDU type event
  */
-int llc_sap_action_send_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
 {
 	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap;
 	int rc = 1;
-	struct sk_buff *ev_skb = ev->data.pdu.skb;
-	struct sk_buff *skb;
+	struct sk_buff *nskb;
 
-	llc_pdu_decode_sa(ev_skb, mac_da);
-	llc_pdu_decode_da(ev_skb, mac_sa);
-	llc_pdu_decode_ssap(ev_skb, &dsap);
-	skb = llc_alloc_frame();
-	if (!skb)
+	llc_pdu_decode_sa(skb, mac_da);
+	llc_pdu_decode_da(skb, mac_sa);
+	llc_pdu_decode_ssap(skb, &dsap);
+	nskb = llc_alloc_frame();
+	if (!nskb)
 		goto out;
-	skb->dev = ev_skb->dev;
-	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
+	nskb->dev = skb->dev;
+	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
 			    LLC_PDU_RSP);
-	rc = llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 0);
+	rc = llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0);
 	if (rc)
 		goto out;
-	rc = lan_hdrs_init(skb, mac_sa, mac_da);
+	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
-		llc_sap_send_pdu(sap, skb);
+		llc_sap_send_pdu(sap, nskb);
 out:
 	return rc;
 }
@@ -133,17 +131,17 @@
 /**
  *	llc_sap_action_send_test_c - send TEST PDU to MAC in resp to TEST REQ
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Send a TEST command PDU to the MAC layer in response to a TEST REQUEST
  *	primitive from the network layer. Verify event is a primitive type
  *	event; verify the primitive is a TEST REQUEST.
  */
-int llc_sap_action_send_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 	struct llc_prim_if_block *prim = ev->data.prim.data;
 	struct llc_prim_test *prim_data = &prim->data->test;
-	struct sk_buff *skb = prim_data->skb;
 	int rc;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
@@ -158,28 +156,27 @@
 	return rc;
 }
 
-int llc_sap_action_send_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
 {
 	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap;
+	struct sk_buff *nskb;
 	int rc = 1;
-	struct sk_buff *ev_skb = ev->data.pdu.skb;
-	struct sk_buff *skb;
 
-	llc_pdu_decode_sa(ev_skb, mac_da);
-	llc_pdu_decode_da(ev_skb, mac_sa);
-	llc_pdu_decode_ssap(ev_skb, &dsap);
-	skb = llc_alloc_frame();
-	if (!skb)
+	llc_pdu_decode_sa(skb, mac_da);
+	llc_pdu_decode_da(skb, mac_sa);
+	llc_pdu_decode_ssap(skb, &dsap);
+	nskb = llc_alloc_frame();
+	if (!nskb)
 		goto out;
-	skb->dev = ev_skb->dev;
-	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
+	nskb->dev = skb->dev;
+	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
 			    LLC_PDU_RSP);
-	rc = llc_pdu_init_as_test_rsp(skb, ev_skb);
+	rc = llc_pdu_init_as_test_rsp(nskb, skb);
 	if (rc)
 		goto out;
-	rc = lan_hdrs_init(skb, mac_sa, mac_da);
+	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
-		llc_sap_send_pdu(sap, skb);
+		llc_sap_send_pdu(sap, nskb);
 out:
 	return rc;
 }
@@ -187,13 +184,12 @@
 /**
  *	llc_sap_action_report_status - report data link status to layer mgmt
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Report data link status to layer management. Verify our event is the
  *	kind we expect.
  */
-int llc_sap_action_report_status(struct llc_sap *sap,
-				 struct llc_sap_state_ev *ev)
+int llc_sap_action_report_status(struct llc_sap *sap, struct sk_buff *skb)
 {
 	return 0;
 }
@@ -201,27 +197,27 @@
 /**
  *	llc_sap_action_xid_ind - send XID PDU resp to net layer via XID IND
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Send a XID response PDU to the network layer via a XID INDICATION
  *	primitive.
  */
-int llc_sap_action_xid_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_xid_ind(struct llc_sap *sap, struct sk_buff *skb)
 {
-	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	llc_sap_rtn_pdu(sap, skb);
 	return 0;
 }
 
 /**
  *	llc_sap_action_test_ind - send TEST PDU to net layer via TEST IND
  *	@sap: SAP
- *	@ev: the event to send
+ *	@skb: the event to send
  *
  *	Send a TEST response PDU to the network layer via a TEST INDICATION
  *	primitive. Verify our event is a PDU type event.
  */
-int llc_sap_action_test_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_action_test_ind(struct llc_sap *sap, struct sk_buff *skb)
 {
-	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	llc_sap_rtn_pdu(sap, skb);
 	return 0;
 }
diff -Nru a/net/llc/llc_s_ev.c b/net/llc/llc_s_ev.c
--- a/net/llc/llc_s_ev.c	Tue Aug 27 12:28:01 2002
+++ b/net/llc/llc_s_ev.c	Tue Aug 27 12:28:01 2002
@@ -20,82 +20,96 @@
 #include <net/llc_s_ev.h>
 #include <net/llc_pdu.h>
 
-int llc_sap_ev_activation_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
 	return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1;
 }
 
-int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
 	       !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1;
 }
 
-int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
 	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
 	       ev->data.prim.prim == LLC_DATAUNIT_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 
 }
 
-int llc_sap_ev_xid_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
 	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
 	       ev->data.prim.prim == LLC_XID_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
 	       !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1;
 }
 
-int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) &&
 	       !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1;
 }
 
-int llc_sap_ev_test_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
 	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
 	       ev->data.prim.prim == LLC_TEST_PRIM &&
 	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
 }
 
-int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
 	       !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1;
 }
 
-int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_pdu_un *pdu = (struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) &&
 	       !LLC_PDU_TYPE_IS_U(pdu) &&
 	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1;
 }
 
-int llc_sap_ev_deactivation_req(struct llc_sap *sap,
-				struct llc_sap_state_ev *ev)
+int llc_sap_ev_deactivation_req(struct llc_sap *sap, struct sk_buff *skb)
 {
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
 	return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
 	       ev->data.a.ev == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1;
 }
diff -Nru a/net/llc/llc_s_st.c b/net/llc/llc_s_st.c
--- a/net/llc/llc_s_st.c	Tue Aug 27 12:27:57 2002
+++ b/net/llc/llc_s_st.c	Tue Aug 27 12:27:57 2002
@@ -24,7 +24,7 @@
  * last entry for this state
  * all members are zeros, .bss zeroes it
  */
-static struct llc_sap_state_trans llc_sap_state_trans_n;
+static struct llc_sap_state_trans llc_sap_state_trans_end;
 
 /* state LLC_SAP_STATE_INACTIVE transition for
  * LLC_SAP_EV_ACTIVATION_REQ event
@@ -43,7 +43,7 @@
 /* array of pointers; one to each transition */
 static struct llc_sap_state_trans *llc_sap_inactive_state_transitions[] = {
 	[0] = &llc_sap_inactive_state_trans_1,
-	[1] = &llc_sap_state_trans_n,
+	[1] = &llc_sap_state_trans_end,
 };
 
 /* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_UI event */
@@ -167,17 +167,17 @@
 	[6] = &llc_sap_active_state_trans_7,
 	[7] = &llc_sap_active_state_trans_8,
 	[8] = &llc_sap_active_state_trans_9,
-	[9] = &llc_sap_state_trans_n,
+	[9] = &llc_sap_state_trans_end,
 };
 
 /* SAP state transition table */
-struct llc_sap_state llc_sap_state_table[] = {
-	{
-		.curr_state =	LLC_SAP_STATE_INACTIVE,
-		.transitions =	llc_sap_inactive_state_transitions,
+struct llc_sap_state llc_sap_state_table[LLC_NR_SAP_STATES] = {
+	[LLC_SAP_STATE_INACTIVE - 1] = {
+		.curr_state	= LLC_SAP_STATE_INACTIVE,
+		.transitions	= llc_sap_inactive_state_transitions,
        	},
-	{
-		.curr_state =	LLC_SAP_STATE_ACTIVE,
-		.transitions =	llc_sap_active_state_transitions,
+	[LLC_SAP_STATE_ACTIVE - 1] = {
+		.curr_state	= LLC_SAP_STATE_ACTIVE,
+		.transitions	= llc_sap_active_state_transitions,
 	},
 };
diff -Nru a/net/llc/llc_sap.c b/net/llc/llc_sap.c
--- a/net/llc/llc_sap.c	Tue Aug 27 12:28:08 2002
+++ b/net/llc/llc_sap.c	Tue Aug 27 12:28:08 2002
@@ -23,13 +23,13 @@
 #include <net/llc_pdu.h>
 #include <linux/if_tr.h>
 
-static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev);
-static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb);
+static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb);
 static int llc_exec_sap_trans_actions(struct llc_sap *sap,
 				      struct llc_sap_state_trans *trans,
-				      struct llc_sap_state_ev *ev);
+				      struct sk_buff *skb);
 static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
-						  struct llc_sap_state_ev *ev);
+						      struct sk_buff *skb);
 
 /**
  *	llc_sap_assign_sock - adds a connection to a SAP
@@ -64,56 +64,36 @@
 }
 
 /**
- *	llc_sap_alloc_ev - allocates sap event
- *	@sap: pointer to SAP
- *	@ev: allocated event (output argument)
- *
- *	Returns the allocated sap event or %NULL when out of memory.
- */
-struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap)
-{
-	struct llc_sap_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
-
-	if (ev)
-		memset(ev, 0, sizeof(*ev));
-	return ev;
-}
-
-/**
  *	llc_sap_send_ev - sends event to SAP state machine
  *	@sap: pointer to SAP
- *	@ev: pointer to occurred event
+ *	@skb: pointer to occurred event
  *
  *	After executing actions of the event, upper layer will be indicated
  *	if needed(on receiving an UI frame).
  */
-void llc_sap_send_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb)
 {
-	struct llc_prim_if_block *prim;
-	u8 flag;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 
-	llc_sap_next_state(sap, ev);
-	flag = ev->ind_cfm_flag;
-	prim = ev->prim;
-	if (flag == LLC_IND) {
-		skb_get(ev->data.pdu.skb);
-		sap->ind(prim);
+	llc_sap_next_state(sap, skb);
+	if (ev->ind_cfm_flag == LLC_IND) {
+		skb_get(skb);
+		sap->ind(ev->prim);
 	}
-	llc_sap_free_ev(sap, ev);
+	llc_sap_free_ev(sap, skb);
 }
 
 /**
  *	llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu.
  *	@sap: pointer to SAP
  *	@skb: received pdu
- *	@ev: pointer to occurred event
  */
-void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb,
-		     struct llc_sap_state_ev *ev)
+void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
 {
 	struct llc_pdu_un *pdu;
-	struct llc_prim_if_block *prim = &llc_ind_prim;
-	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+	struct llc_prim_if_block *prim = &sap->llc_ind_prim;
+	union llc_u_prim_data *prim_data = prim->data;
 	u8 lfb;
 
 	llc_pdu_decode_sa(skb, prim_data->udata.saddr.mac);
@@ -122,7 +102,7 @@
 	llc_pdu_decode_ssap(skb, &prim_data->udata.saddr.lsap);
 	prim_data->udata.pri = 0;
 	prim_data->udata.skb = skb;
-	pdu = (struct llc_pdu_un *)skb->nh.raw;
+	pdu = llc_pdu_un_hdr(skb);
 	switch (LLC_U_PDU_RSP(pdu)) {
 		case LLC_1_PDU_CMD_TEST:
 			prim->prim = LLC_TEST_PRIM;
@@ -165,42 +145,38 @@
 /**
  *	llc_sap_free_ev - frees an sap event
  *	@sap: pointer to SAP
- *	@ev: released event
+ *	@skb: released event
  */
-static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb)
 {
-	if (ev->type == LLC_SAP_EV_TYPE_PDU) {
-		struct llc_pdu_un *pdu =
-				(struct llc_pdu_un *)ev->data.pdu.skb->nh.raw;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 
-		if (LLC_U_PDU_CMD(pdu) != LLC_1_PDU_CMD_UI)
-			kfree_skb(ev->data.pdu.skb);
-	}
-	kfree(ev);
+	if (ev->type == LLC_SAP_EV_TYPE_PDU)
+		kfree_skb(skb);
 }
 
 /**
  *	llc_sap_next_state - finds transition, execs actions & change SAP state
  *	@sap: pointer to SAP
- *	@ev: happened event
+ *	@skb: happened event
  *
  *	This function finds transition that matches with happened event, then
  *	executes related actions and finally changes state of SAP. It returns
  *	0 on success and 1 for failure.
  */
-static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb)
 {
 	int rc = 1;
 	struct llc_sap_state_trans *trans;
 
-	if (sap->state <= LLC_NBR_SAP_STATES) {
-		trans = llc_find_sap_trans(sap, ev);
+	if (sap->state <= LLC_NR_SAP_STATES) {
+		trans = llc_find_sap_trans(sap, skb);
 		if (trans) {
 			/* got the state to which we next transition; perform
 			 * the actions associated with this transition before
 			 * actually transitioning to the next state
 			 */
-			rc = llc_exec_sap_trans_actions(sap, trans, ev);
+			rc = llc_exec_sap_trans_actions(sap, trans, skb);
 			if (!rc)
 				/* transition SAP to next state if all actions
 				 * execute successfully
@@ -214,14 +190,14 @@
 /**
  *	llc_find_sap_trans - finds transition for event
  *	@sap: pointer to SAP
- *	@ev: happened event
+ *	@skb: happened event
  *
  *	This function finds transition that matches with happened event.
  *	Returns the pointer to found transition on success or %NULL for
  *	failure.
  */
 static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
-						    struct llc_sap_state_ev* ev)
+						      struct sk_buff* skb)
 {
 	int i = 0;
 	struct llc_sap_state_trans *rc = NULL;
@@ -231,7 +207,7 @@
 	 * its obvious the event is not valid for the current state
 	 */
 	for (next_trans = curr_state->transitions; next_trans [i]->ev; i++)
-		if (!next_trans[i]->ev(sap, ev)) {
+		if (!next_trans[i]->ev(sap, skb)) {
 			/* got event match; return it */
 			rc = next_trans[i];
 			break;
@@ -243,21 +219,20 @@
  *	llc_exec_sap_trans_actions - execute actions related to event
  *	@sap: pointer to SAP
  *	@trans: pointer to transition that it's actions must be performed
- *	@ev: happened event.
+ *	@skb: happened event.
  *
  *	This function executes actions that is related to happened event.
  *	Returns 0 for success and 1 for failure of at least one action.
  */
 static int llc_exec_sap_trans_actions(struct llc_sap *sap,
 				      struct llc_sap_state_trans *trans,
-				      struct llc_sap_state_ev *ev)
+				      struct sk_buff *skb)
 {
 	int rc = 0;
-	llc_sap_action_t *next_action;
+	llc_sap_action_t *next_action = trans->ev_actions;
 
-	for (next_action = trans->ev_actions;
-	     next_action && *next_action; next_action++)
-		if ((*next_action)(sap, ev))
+	for (; next_action && *next_action; next_action++)
+		if ((*next_action)(sap, skb))
 			rc = 1;
 	return rc;
 }
diff -Nru a/net/llc/llc_sock.c b/net/llc/llc_sock.c
--- a/net/llc/llc_sock.c	Tue Aug 27 12:27:45 2002
+++ b/net/llc/llc_sock.c	Tue Aug 27 12:27:45 2002
@@ -43,8 +43,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/init.h>
 
-#define dprintk(format, a...) printk(KERN_INFO __FUNCTION__ ": " format, ##a)
-
 /* remember: uninitialized global data is zeroed because its in .bss */
 static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
 static u16 llc_ui_sap_link_no_max[256];
@@ -527,8 +525,6 @@
 	llc_ui_remove_socket(sk);
 	if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap))
 		llc_sap_close(llc_ui->sap);
-	dprintk("rxq=%d, txq=%d\n", skb_queue_len(&sk->receive_queue),
-		skb_queue_len(&sk->write_queue));
 	sock_orphan(sk);
 	sock->sk = NULL;
 	if (!atomic_read(&sk->wmem_alloc) &&
@@ -1416,10 +1412,8 @@
 	llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap;
 	sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr,
 				    &prim_data->saddr, prim_data->dev);
-	if (!sk) {
-		dprintk("llc_ui_find_sk_by_addr failed\n");
+	if (!sk)
 		goto out;
-	}
 	if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN)
 		goto out_put;
 	if (prim->data->conn.status)
@@ -1469,10 +1463,8 @@
 	memcpy(llc_ui->sllc_smac, llc_sk(prim_data->sk)->daddr.mac,
 	       IFHWADDRLEN);
 	/* queue skb to the user. */
-	if (sock_queue_rcv_skb(sk, skb)) {
-		dprintk("sock_queue_rcv_skb failed!\n");
+	if (sock_queue_rcv_skb(sk, skb))
 		kfree_skb(skb);
-	}
 out_put:
 	sock_put(sk);
 out:;
@@ -1547,13 +1539,11 @@
 {
 	struct llc_prim_conn *prim_data = &prim->data->conn;
 	struct llc_opt *llc_core = llc_sk(prim_data->sk);
-	struct llc_ui_opt *llc_ui = llc_ui_sk(prim_data->sk);
 	struct sock* sk = llc_core->handler;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
 
-	if (!sk) {
-		dprintk("llc_core->handler == NULL!\n");
+	if (!sk)
 		goto out;
-	}
 	sock_hold(sk);
 	if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
 		goto out_put;
@@ -1562,8 +1552,6 @@
 		sk->state	  = TCP_ESTABLISHED;
 		llc_ui->core_sk   = prim_data->sk;
 	} else {
-		dprintk("prim->data->conn.status = %d\n",
-			prim->data->conn.status);
 		sk->socket->state = SS_UNCONNECTED;
 		sk->state	  = TCP_CLOSE;
 		llc_ui->core_sk	  = NULL;
@@ -1633,7 +1621,7 @@
 			llc_ui_conf_disc(prim);		break;
 		case LLC_RESET_PRIM:			break;
 		default:
-			printk(KERN_ERR __FUNCTION__ ": unknown prim %d\n",
+			printk(KERN_ERR "%s: unknown prim %d\n", __FUNCTION__,
 			       prim->prim);
 			break;
 	}
@@ -1641,6 +1629,13 @@
 }
 
 #ifdef CONFIG_PROC_FS
+#define MAC_FORMATTED_SIZE 17
+static void llc_ui_format_mac(char *bf, unsigned char *mac)
+{
+	sprintf(bf, "%02X:%02X:%02X:%02X:%02X:%02X",
+		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
 /**
  *	llc_ui_get_info - return info to procfs
  *	@buffer: where to put the formatted output
@@ -1668,41 +1663,25 @@
 		if (llc_ui->sap) {
 			if (llc_ui->dev &&
 			    llc_ui_mac_null(llc_ui->addr.sllc_mmac))
-				len += sprintf(buffer + len,
-					"%02X:%02X:%02X:%02X:%02X:%02X",
-					llc_ui->dev->dev_addr[0],
-					llc_ui->dev->dev_addr[1],
-					llc_ui->dev->dev_addr[2],
-					llc_ui->dev->dev_addr[3],
-					llc_ui->dev->dev_addr[4],
-					llc_ui->dev->dev_addr[5]);
+				llc_ui_format_mac(buffer + len,
+						  llc_ui->dev->dev_addr);
 			else {
 				if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac))
-					len += sprintf(buffer + len,
-						"%02X:%02X:%02X:%02X:%02X:%02X",
-						llc_ui->addr.sllc_mmac[0],
-						llc_ui->addr.sllc_mmac[1],
-						llc_ui->addr.sllc_mmac[2],
-						llc_ui->addr.sllc_mmac[3],
-						llc_ui->addr.sllc_mmac[4],
-						llc_ui->addr.sllc_mmac[5]);
+					llc_ui_format_mac(buffer + len,
+							llc_ui->addr.sllc_mmac);
 				else
-					len += sprintf(buffer + len,
-							"00:00:00:00:00:00");
+					sprintf(buffer + len,
+						"00:00:00:00:00:00");
 			}
+			len += MAC_FORMATTED_SIZE;
 			len += sprintf(buffer + len, "@%02X ",
 					llc_ui->sap->laddr.lsap);
 		} else
 			len += sprintf(buffer + len, "00:00:00:00:00:00@00 ");
+		llc_ui_format_mac(buffer + len, llc_ui->addr.sllc_dmac);
+		len += MAC_FORMATTED_SIZE;
 		len += sprintf(buffer + len,
-				"%02X:%02X:%02X:%02X:%02X:%02X@%02X "
-				"%08X:%08X %02X %-3d ",
-				llc_ui->addr.sllc_dmac[0],
-				llc_ui->addr.sllc_dmac[1],
-				llc_ui->addr.sllc_dmac[2],
-				llc_ui->addr.sllc_dmac[3],
-				llc_ui->addr.sllc_dmac[4],
-				llc_ui->addr.sllc_dmac[5],
+				"@%02X %08d:%08d %02d %-3d ",
 				llc_ui->addr.sllc_dsap,
 				atomic_read(&s->wmem_alloc),
 				atomic_read(&s->rmem_alloc), s->state,
diff -Nru a/net/llc/llc_stat.c b/net/llc/llc_stat.c
--- a/net/llc/llc_stat.c	Tue Aug 27 12:28:01 2002
+++ b/net/llc/llc_stat.c	Tue Aug 27 12:28:01 2002
@@ -24,7 +24,7 @@
  * last entry for this state
  * all members are zeros, .bss zeroes it
  */
-static struct llc_station_state_trans llc_stat_state_trans_n;
+static struct llc_station_state_trans llc_stat_state_trans_end;
 
 /* DOWN STATE transitions */
 
@@ -59,7 +59,7 @@
 static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = {
 	[0] = &llc_stat_down_state_trans_1,
 	[1] = &llc_stat_down_state_trans_2,
-	[2] = &llc_stat_state_trans_n,
+	[2] = &llc_stat_state_trans_end,
 };
 
 /* UP STATE transitions */
@@ -104,7 +104,7 @@
 	[0] = &llc_stat_up_state_trans_1,
 	[1] = &llc_stat_up_state_trans_2,
 	[2] = &llc_stat_up_state_trans_3,
-	[3] = &llc_stat_state_trans_n,
+	[3] = &llc_stat_state_trans_end,
 };
 
 /* DUP ADDR CHK STATE transitions */
@@ -162,7 +162,7 @@
 static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = {
 	.ev	    = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry,
 	.next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
-	.ev_actions = llc_stat_dupaddr_state_actions_4
+	.ev_actions = llc_stat_dupaddr_state_actions_4,
 };
 
 /* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY
@@ -199,20 +199,20 @@
 	[3] = &llc_stat_dupaddr_state_trans_1,	/* Receive frame */
 	[4] = &llc_stat_dupaddr_state_trans_2,
 	[5] = &llc_stat_dupaddr_state_trans_3,
-	[6] = &llc_stat_state_trans_n
+	[6] = &llc_stat_state_trans_end,
 };
 
 struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = {
-	{
+	[LLC_STATION_STATE_DOWN - 1] = {
 		.curr_state  = LLC_STATION_STATE_DOWN,
 		.transitions = llc_stat_dwn_state_trans,
 	},
-	{
+	[LLC_STATION_STATE_DUP_ADDR_CHK - 1] = {
 		.curr_state  = LLC_STATION_STATE_DUP_ADDR_CHK,
 		.transitions = llc_stat_dupaddr_state_trans,
 	},
-	{
+	[LLC_STATION_STATE_UP - 1] = {
 		.curr_state  = LLC_STATION_STATE_UP,
 		.transitions = llc_stat_up_state_trans,
-	}
+	},
 };
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Tue Aug 27 12:28:02 2002
+++ b/net/sunrpc/clnt.c	Tue Aug 27 12:28:02 2002
@@ -43,6 +43,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
 
+static void	call_start(struct rpc_task *task);
 static void	call_reserve(struct rpc_task *task);
 static void	call_reserveresult(struct rpc_task *task);
 static void	call_allocate(struct rpc_task *task);
@@ -137,19 +138,27 @@
 int
 rpc_shutdown_client(struct rpc_clnt *clnt)
 {
-	dprintk("RPC: shutting down %s client for %s\n",
-		clnt->cl_protname, clnt->cl_server);
-	while (atomic_read(&clnt->cl_users)) {
-#ifdef RPC_DEBUG
-		dprintk("RPC: rpc_shutdown_client: client %s, tasks=%d\n",
-			clnt->cl_protname, atomic_read(&clnt->cl_users));
-#endif
+	dprintk("RPC: shutting down %s client for %s, tasks=%d\n",
+			clnt->cl_protname, clnt->cl_server,
+			atomic_read(&clnt->cl_users));
+
+	while (atomic_read(&clnt->cl_users) > 0) {
 		/* Don't let rpc_release_client destroy us */
 		clnt->cl_oneshot = 0;
 		clnt->cl_dead = 0;
 		rpc_killall_tasks(clnt);
 		sleep_on_timeout(&destroy_wait, 1*HZ);
 	}
+
+	if (atomic_read(&clnt->cl_users) < 0) {
+		printk(KERN_ERR "RPC: rpc_shutdown_client clnt %p tasks=%d\n",
+				clnt, atomic_read(&clnt->cl_users));
+#ifdef RPC_DEBUG
+		rpc_show_tasks();
+#endif
+		BUG();
+	}
+
 	return rpc_destroy_client(clnt);
 }
 
@@ -326,13 +335,9 @@
 		rpcauth_bindcred(task);
 
 	if (task->tk_status == 0)
-		task->tk_action = call_reserve;
+		task->tk_action = call_start;
 	else
 		task->tk_action = NULL;
-
-	/* Increment call count */
-	if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
-		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 void
@@ -359,26 +364,46 @@
 	if (RPC_ASSASSINATED(task))
 		return;
 
-	task->tk_action = call_reserve;
-	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
+	task->tk_action = call_start;
 }
 
 /*
- * 1.	Reserve an RPC call slot
+ * 0.  Initial state
+ *
+ *     Other FSM states can be visited zero or more times, but
+ *     this state is visited exactly once for each RPC.
  */
 static void
-call_reserve(struct rpc_task *task)
+call_start(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 
 	if (task->tk_msg.rpc_proc > clnt->cl_maxproc) {
-		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
-			clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
+		printk(KERN_ERR "%s (vers %d): bad procedure number %d\n",
+				clnt->cl_protname, clnt->cl_vers,
+				task->tk_msg.rpc_proc);
 		rpc_exit(task, -EIO);
 		return;
 	}
 
+	dprintk("RPC: %4d call_start %s%d proc %d (%s)\n", task->tk_pid,
+		clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc,
+		(RPC_IS_ASYNC(task) ? "async" : "sync"));
+
+	/* Increment call count */
+	rpcproc_count(clnt, task->tk_msg.rpc_proc)++;
+	clnt->cl_stats->rpccnt++;
+	task->tk_action = call_reserve;
+}
+
+/*
+ * 1.	Reserve an RPC call slot
+ */
+static void
+call_reserve(struct rpc_task *task)
+{
 	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
+
 	if (!rpcauth_uptodatecred(task)) {
 		task->tk_action = call_refresh;
 		return;
@@ -386,8 +411,6 @@
 
 	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
-	task->tk_timeout = clnt->cl_timeout.to_resrvval;
-	clnt->cl_stats->rpccnt++;
 	xprt_reserve(task);
 }
 
@@ -401,38 +424,46 @@
 
 	dprintk("RPC: %4d call_reserveresult (status %d)\n",
 				task->tk_pid, task->tk_status);
+
 	/*
 	 * After a call to xprt_reserve(), we must have either
 	 * a request slot or else an error status.
 	 */
-	if ((task->tk_status >= 0 && !task->tk_rqstp) ||
-	    (task->tk_status < 0 && task->tk_rqstp))
-		printk(KERN_ERR "call_reserveresult: status=%d, request=%p??\n",
-		 task->tk_status, task->tk_rqstp);
+	task->tk_status = 0;
+	if (status >= 0) {
+		if (task->tk_rqstp) {
+			task->tk_action = call_allocate;
+			return;
+		}
 
-	if (task->tk_status >= 0) {
-		task->tk_action = call_allocate;
+		printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
+				__FUNCTION__, status);
+		rpc_exit(task, -EIO);
 		return;
 	}
 
-	task->tk_status = 0;
+	/*
+	 * Even though there was an error, we may have acquired
+	 * a request slot somehow.  Make sure not to leak it.
+	 */
+	if (task->tk_rqstp) {
+		printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
+				__FUNCTION__, status);
+		xprt_release(task);
+	}
+
 	switch (status) {
-	case -EAGAIN:
-	case -ENOBUFS:
-		task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
+	case -EAGAIN:	/* woken up; retry */
 		task->tk_action = call_reserve;
-		break;
-	case -ETIMEDOUT:
-		dprintk("RPC: task timed out\n");
-		task->tk_action = call_timeout;
+		return;
+	case -EIO:	/* probably a shutdown */
 		break;
 	default:
-		if (!task->tk_rqstp) {
-			printk(KERN_INFO "RPC: task has no request, exit EIO\n");
-			rpc_exit(task, -EIO);
-		} else
-			rpc_exit(task, status);
+		printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
+				__FUNCTION__, status);
+		break;
 	}
+	rpc_exit(task, status);
 }
 
 /*
@@ -527,6 +558,9 @@
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_xprt *xprt = clnt->cl_xprt;
 
+	dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid,
+			xprt, (xprt_connected(xprt) ? "is" : "is not"));
+
 	task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_reconnect;
 
 	if (!clnt->cl_port) {
@@ -645,7 +679,6 @@
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
-		clnt->cl_stats->rpcretrans++;
 		break;
 	default:
 		if (clnt->cl_chatty)
@@ -664,20 +697,15 @@
 call_timeout(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
-	struct rpc_rqst	*req = task->tk_rqstp;
+	struct rpc_timeout *to = &task->tk_rqstp->rq_timeout;
 
-	if (req) {
-		struct rpc_timeout *to = &req->rq_timeout;
-
-		if (xprt_adjust_timeout(to)) {
-			dprintk("RPC: %4d call_timeout (minor timeo)\n",
-				task->tk_pid);
-			goto minor_timeout;
-		}
-		to->to_retries = clnt->cl_timeout.to_retries;
+	if (xprt_adjust_timeout(to)) {
+		dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid);
+		goto retry;
 	}
+	to->to_retries = clnt->cl_timeout.to_retries;
 
-	dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid);
+	dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);
 	if (clnt->cl_softrtry) {
 		if (clnt->cl_chatty && !task->tk_exit)
 			printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
@@ -685,33 +713,18 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
+
 	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) {
 		task->tk_flags |= RPC_CALL_MAJORSEEN;
-		if (req)
-			printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-				clnt->cl_protname, clnt->cl_server);
-#ifdef RPC_DEBUG				
-		else
-			printk(KERN_NOTICE "%s: task %d can't get a request slot\n",
-				clnt->cl_protname, task->tk_pid);
-#endif				
+		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
+			clnt->cl_protname, clnt->cl_server);
 	}
 	if (clnt->cl_autobind)
 		clnt->cl_port = 0;
 
-minor_timeout:
-	if (!req)
-		task->tk_action = call_reserve;
-	else if (!clnt->cl_port) {
-		task->tk_action = call_bind;
-		clnt->cl_stats->rpcretrans++;
-	} else if (!xprt_connected(clnt->cl_xprt)) {
-		task->tk_action = call_reconnect;
-		clnt->cl_stats->rpcretrans++;
-	} else {
-		task->tk_action = call_transmit;
-		clnt->cl_stats->rpcretrans++;
-	}
+retry:
+	clnt->cl_stats->rpcretrans++;
+	task->tk_action = call_bind;
 	task->tk_status = 0;
 }
 
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Tue Aug 27 12:27:59 2002
+++ b/net/sunrpc/svcsock.c	Tue Aug 27 12:27:59 2002
@@ -140,7 +140,7 @@
 	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
 	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
 		/* Don't enqueue while not enough space for reply */
-		dprintk("svc: socket %p  no space, %d > %ld, not enqueued\n",
+		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
 			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
 			sock_wspace(svsk->sk_sk));
 		goto out_unlock;
@@ -481,6 +481,16 @@
 	u32		*data;
 	int		err, len;
 
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+	    /* udp sockets need large rcvbuf as all pending
+	     * requests are still in that buffer.  sndbuf must
+	     * also be large enough that there is enough space
+	     * for one reply per thread.
+	     */
+	    svc_sock_setbufsize(svsk->sk_sock,
+				(serv->sv_nrthreads+3) * serv->sv_bufsz,
+				(serv->sv_nrthreads+3) * serv->sv_bufsz);
+
 	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
 		svc_sock_received(svsk);
@@ -564,6 +574,16 @@
 	svsk->sk_recvfrom = svc_udp_recvfrom;
 	svsk->sk_sendto = svc_udp_sendto;
 
+	/* initialise setting must have enough space to
+	 * receive and respond to one request.  
+	 * svc_udp_recvfrom will re-adjust if necessary
+	 */
+	svc_sock_setbufsize(svsk->sk_sock,
+			    3 * svsk->sk_server->sv_bufsz,
+			    3 * svsk->sk_server->sv_bufsz);
+
+	set_bit(SK_CHNGBUF, &svsk->sk_flags);
+
 	return 0;
 }
 
@@ -667,6 +687,8 @@
 		goto failed;		/* aborted connection or whatever */
 	}
 	set_bit(SK_CONN, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
+
 	slen = sizeof(sin);
 	err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
 	if (err < 0) {
@@ -771,6 +793,18 @@
 		return 0;
 	}
 
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+		/* sndbuf needs to have room for one request
+		 * per thread, otherwise we can stall even when the
+		 * network isn't a bottleneck.
+		 * rcvbuf just needs to be able to hold a few requests.
+		 * Normally they will be removed from the queue 
+		 * as soon a a complete request arrives.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    (serv->sv_nrthreads+3) * serv->sv_bufsz,
+				    3 * serv->sv_bufsz);
+
 	clear_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Receive data. If we haven't got the record length yet, get
@@ -787,6 +821,9 @@
 			goto error;
 		svsk->sk_tcplen += len;
 
+		if (len < want)
+			return 0;
+
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
 		if (!(svsk->sk_reclen & 0x80000000)) {
 			/* FIXME: technically, a record can be fragmented,
@@ -887,8 +924,9 @@
 
 	sent = svc_sendto(rqstp, bufp->iov, bufp->nriov);
 	if (sent != bufp->len<<2) {
-		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - should shutdown socket\n",
+		printk(KERN_NOTICE "rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
 		       rqstp->rq_sock->sk_server->sv_name,
+		       (sent<0)?"got error":"sent only",
 		       sent, bufp->len << 2);
 		svc_delete_socket(rqstp->rq_sock);
 		sent = -EAGAIN;
@@ -916,17 +954,15 @@
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
 
-		/* sndbuf needs to have room for one request
-		 * per thread, otherwise we can stall even when the
-		 * network isn't a bottleneck.
-		 * rcvbuf just needs to be able to hold a few requests.
-		 * Normally they will be removed from the queue 
-		 * as soon a a complete request arrives.
+		/* initialise setting must have enough space to
+		 * receive and respond to one request.  
+		 * svc_tcp_recvfrom will re-adjust if necessary
 		 */
 		svc_sock_setbufsize(svsk->sk_sock,
-				    (svsk->sk_server->sv_nrthreads+3) *
-				    svsk->sk_server->sv_bufsz,
+				    3 * svsk->sk_server->sv_bufsz,
 				    3 * svsk->sk_server->sv_bufsz);
+
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 
 	return 0;
@@ -945,30 +981,12 @@
 	list_for_each(le, &serv->sv_permsocks) {
 		struct svc_sock *svsk = 
 			list_entry(le, struct svc_sock, sk_list);
-		struct socket *sock = svsk->sk_sock;
-		if (sock->type == SOCK_DGRAM) {
-			/* udp sockets need large rcvbuf as all pending
-			 * requests are still in that buffer.
-			 */
-			svc_sock_setbufsize(sock,
-					    (serv->sv_nrthreads+3) * serv->sv_bufsz,
-					    (serv->sv_nrthreads+3) * serv->sv_bufsz);
-		} else if (svsk->sk_sk->state != TCP_LISTEN) {
-			printk(KERN_ERR "RPC update_bufs: permanent sock neither UDP or TCP_LISTEN\n");
-		}
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 	list_for_each(le, &serv->sv_tempsocks) {
 		struct svc_sock *svsk =
 			list_entry(le, struct svc_sock, sk_list);
-		struct socket *sock = svsk->sk_sock;
-		if (sock->type == SOCK_STREAM) {
-			/* See svc_tcp_init above for rationale on buffer sizes */
-			svc_sock_setbufsize(sock,
-					    (serv->sv_nrthreads+3) *
-					    serv->sv_bufsz,
-					    3 * serv->sv_bufsz);
-		} else 
-			printk(KERN_ERR "RPC update_bufs: temp sock not TCP\n");
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 	spin_unlock_bh(&serv->sv_lock);
 }
@@ -1212,6 +1230,7 @@
 		return error;
 
 	if (sin != NULL) {
+		sock->sk->reuse = 1; /* allow address reuse */
 		error = sock->ops->bind(sock, (struct sockaddr *) sin,
 						sizeof(*sin));
 		if (error < 0)
@@ -1219,7 +1238,7 @@
 	}
 
 	if (protocol == IPPROTO_TCP) {
-		if ((error = sock->ops->listen(sock, 5)) < 0)
+		if ((error = sock->ops->listen(sock, 64)) < 0)
 			goto bummer;
 	}
 
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Tue Aug 27 12:28:01 2002
+++ b/net/sunrpc/xprt.c	Tue Aug 27 12:28:01 2002
@@ -84,7 +84,7 @@
  */
 static void	xprt_request_init(struct rpc_task *, struct rpc_xprt *);
 static void	do_xprt_transmit(struct rpc_task *);
-static void	xprt_reserve_status(struct rpc_task *task);
+static inline void	do_xprt_reserve(struct rpc_task *);
 static void	xprt_disconnect(struct rpc_xprt *);
 static void	xprt_reconn_status(struct rpc_task *task);
 static struct socket *xprt_create_socket(int, struct rpc_timeout *);
@@ -478,7 +478,7 @@
 		if (inet->state != TCP_ESTABLISHED) {
 			task->tk_timeout = xprt->timeout.to_maxval;
 			/* if the socket is already closing, delay 5 secs */
-			if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
+			if ((1<<inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
 				task->tk_timeout = 5*HZ;
 			rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL);
 			release_sock(inet);
@@ -1179,61 +1179,39 @@
 /*
  * Reserve an RPC call slot.
  */
-int
+void
 xprt_reserve(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
 
-	/* We already have an initialized request. */
-	if (task->tk_rqstp)
-		return 0;
-
-	spin_lock(&xprt->xprt_lock);
-	xprt_reserve_status(task);
-	if (task->tk_rqstp) {
-		task->tk_timeout = 0;
-	} else if (!task->tk_timeout) {
-		task->tk_status = -ENOBUFS;
-	} else {
-		dprintk("RPC:      xprt_reserve waiting on backlog\n");
-		task->tk_status = -EAGAIN;
-		rpc_sleep_on(&xprt->backlog, task, NULL, NULL);
+	task->tk_status = -EIO;
+	if (!xprt->shutdown) {
+		spin_lock(&xprt->xprt_lock);
+		do_xprt_reserve(task);
+		spin_unlock(&xprt->xprt_lock);
 	}
-	spin_unlock(&xprt->xprt_lock);
-	dprintk("RPC: %4d xprt_reserve returns %d\n",
-				task->tk_pid, task->tk_status);
-	return task->tk_status;
 }
 
-/*
- * Reservation callback
- */
-static void
-xprt_reserve_status(struct rpc_task *task)
+static inline void
+do_xprt_reserve(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
-	struct rpc_rqst	*req;
 
-	if (xprt->shutdown) {
-		task->tk_status = -EIO;
-	} else if (task->tk_status < 0) {
-		/* NOP */
-	} else if (task->tk_rqstp) {
-		/* We've already been given a request slot: NOP */
-	} else {
-		if (!(req = xprt->free))
-			goto out_nofree;
-		/* OK: There's room for us. Grab a free slot */
-		xprt->free     = req->rq_next;
-		req->rq_next   = NULL;
+	task->tk_status = 0;
+	if (task->tk_rqstp)
+		return;
+	if (xprt->free) {
+		struct rpc_rqst	*req = xprt->free;
+		xprt->free = req->rq_next;
+		req->rq_next = NULL;
 		task->tk_rqstp = req;
 		xprt_request_init(task, xprt);
+		return;
 	}
-
-	return;
-
-out_nofree:
+	dprintk("RPC:      waiting for request slot\n");
 	task->tk_status = -EAGAIN;
+	task->tk_timeout = 0;
+	rpc_sleep_on(&xprt->backlog, task, NULL, NULL);
 }
 
 /*
@@ -1249,7 +1227,6 @@
 		xid = CURRENT_TIME << 12;
 
 	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid);
-	task->tk_status = 0;
 	req->rq_timeout = xprt->timeout;
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
@@ -1311,7 +1288,6 @@
 	to->to_initval   = 
 	to->to_increment = incr;
 	to->to_maxval    = incr * retr;
-	to->to_resrvval  = incr * retr;
 	to->to_retries   = retr;
 	to->to_exponential = 0;
 }
@@ -1352,7 +1328,6 @@
 	if (to) {
 		xprt->timeout = *to;
 		xprt->timeout.to_current = to->to_initval;
-		xprt->timeout.to_resrvval = to->to_maxval << 1;
 	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
 
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Tue Aug 27 12:28:07 2002
+++ b/net/unix/af_unix.c	Tue Aug 27 12:28:07 2002
@@ -618,6 +618,9 @@
 		if (!u)
 			goto put_fail;
 
+		if (u->type == type)
+			UPDATE_ATIME(nd.dentry->d_inode);
+
 		path_release(&nd);
 
 		err=-EPROTOTYPE;
@@ -628,7 +631,12 @@
 	} else {
 		err = -ECONNREFUSED;
 		u=unix_find_socket_byname(sunname, len, type, hash);
-		if (!u)
+		if (u) {
+			struct dentry *dentry;
+			dentry = unix_sk(u)->dentry;
+			if (dentry)
+				UPDATE_ATIME(dentry->d_inode);
+		} else
 			goto fail;
 	}
 	return u;
@@ -1400,7 +1408,7 @@
 {
 	struct unix_sock *u = unix_sk(sk);
 
-	msg->msg_namelen = sizeof(short);
+	msg->msg_namelen = 0;
 	if (u->addr) {
 		msg->msg_namelen = u->addr->len;
 		memcpy(msg->msg_name, u->addr->name, u->addr->len);
@@ -1909,8 +1917,4 @@
 module_init(af_unix_init);
 module_exit(af_unix_exit);
 
-/*
- * Local variables:
- *  compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c"
- * End:
- */
+MODULE_LICENSE("GPL");
diff -Nru a/scripts/Makefile b/scripts/Makefile
--- a/scripts/Makefile	Tue Aug 27 12:28:07 2002
+++ b/scripts/Makefile	Tue Aug 27 12:28:07 2002
@@ -1,58 +1,65 @@
-
-# always needed
+###
+# scripts contains sources for various helper programs used throughout
+# the kernel for the build process.
 # ---------------------------------------------------------------------------
+# fix-dep: 	 Used to generate dependency information during build process
+# split-include: Divide all config symbols up in a number of files in
+#                include/config/...
+# docproc: 	 Preprocess .tmpl file in order to generate .sgml documentation
+# conmakehash:	 Create arrays for initializing the kernel console tables
+# tkparse: 	 Used by xconfig
+
+all: fixdep split-include docproc conmakehash __chmod
 
 # The following temporary rule will make sure that people's
 # trees get updated to the right permissions, since patch(1)
 # can't do it
-CHMOD_FILES := kernel-doc mkcompile_h makelst
+# ---------------------------------------------------------------------------
 
-all: fixdep split-include docproc $(CHMOD_FILES)
+.PHONY: __chmod
 
-$(CHMOD_FILES): FORCE
-	@chmod a+x $@
+__chmod: kernel-doc mkcompile_h makelst
+	@chmod a+x $^
 
-# xconfig
-# ---------------------------------------------------------------------------
+host-progs := fixdep split-include conmakehash docproc tkparse
+tkparse-objs := tkparse.o tkcond.o tkgen.o
 
-HEADER=header.tk
-TAIL=tail.tk
-# Previous versions always remade kconfig.tk because they always depended
-# on soundscript.  This runs fairly fast, and I can't find all the
-# Config.in files to depend on anyways.  So I'll force it to remake.
+include $(TOPDIR)/Rules.make
 
-kconfig.tk: $(TOPDIR)/arch/$(ARCH)/config.in tkparse $(HEADER) $(TAIL) FORCE
+# In reality kconfig.tk should depend on all Config.in files,
+# but it is not worth the effort to generate the dependencies.
+# The alternative solution to always generate it is fairly fast.
+# FORCE it to remake
+$(obj)/kconfig.tk: $(srctree)/arch/$(ARCH)/config.in tkparse FORCE
 	@echo '  Generating $@'
 	@(                                                      \
-	  if [ -f /usr/local/bin/wish ];	then            \
+	if [ -f /usr/local/bin/wish ];        then              \
 		echo '#!'"/usr/local/bin/wish -f";              \
-	  else                                                  \
+	else                                                    \
 		echo '#!'"/usr/bin/wish -f";                    \
-	  fi;                                                   \
-	  cat $(HEADER);                                        \
-	  ./tkparse < $<;                                       \
-	  echo "set defaults \"arch/${ARCH}/defconfig\"";       \
-	  echo "set ARCH \"${ARCH}\"";                          \
-	  cat $(TAIL)                                           \
+	fi;                                                     \
+	cat $(src)/header.tk;                                   \
+	$(obj)/tkparse < $<;                                    \
+	echo "set defaults \"arch/${ARCH}/defconfig\"";         \
+	echo "set ARCH \"${ARCH}\"";                            \
+	cat $(src)/tail.tk;                                     \
 	) > $@
-	chmod 755 $@
+	@chmod 755 $@
 
-# ---------------------------------------------------------------------------
 
+# ---------------------------------------------------------------------------
+# Targets hardcoded and wellknow in top-level makefile
 .PHONY: lxdialog
-
 lxdialog:
 	$(MAKE) -C lxdialog all
 
-# ---------------------------------------------------------------------------
-
-host-progs := fixdep split-include docproc tkparse
-
-tkparse-objs := tkparse.o tkcond.o tkgen.o
-
 # fixdep is needed to compile other host programs
+$(obj)/split-include $(obj)/docproc $(addprefix $(obj)/,$(tkparse-objs)) \
+$(obj)/conmakehash lxdialog: $(obj)/fixdep
 
-split-include docproc $(tkparse-objs) lxdialog: fixdep
+mrproper:
+	@echo 'Making mrproper (scripts)'
+	@rm -f $(tkparse-objs) $(obj)/kconfig.tk
+	@rm -f core $(host-progs)
+	@$(MAKE) -C lxdialog mrproper
 
-
-include $(TOPDIR)/Rules.make
diff -Nru a/scripts/conmakehash.c b/scripts/conmakehash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/conmakehash.c	Tue Aug 27 12:27:42 2002
@@ -0,0 +1,293 @@
+/*
+ * conmakehash.c
+ *
+ * Create arrays for initializing the kernel folded tables (using a hash
+ * table turned out to be to limiting...)  Unfortunately we can't simply
+ * preinitialize the tables at compile time since kfree() cannot accept
+ * memory not allocated by kmalloc(), and doing our own memory management
+ * just for this seems like massive overkill.
+ *
+ * Copyright (C) 1995-1997 H. Peter Anvin
+ *
+ * This program is a part of the Linux kernel, and may be freely
+ * copied under the terms of the GNU General Public License (GPL),
+ * version 2, or at your option any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAX_FONTLEN 256
+
+typedef unsigned short unicode;
+
+void usage(char *argv0)
+{
+  fprintf(stderr, "Usage: \n"
+         "        %s chartable [hashsize] [hashstep] [maxhashlevel]\n", argv0);
+  exit(EX_USAGE);
+}
+
+int getunicode(char **p0)
+{
+  char *p = *p0;
+
+  while (*p == ' ' || *p == '\t')
+    p++;
+  if (*p != 'U' || p[1] != '+' ||
+      !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
+      !isxdigit(p[5]) || isxdigit(p[6]))
+    return -1;
+  *p0 = p+6;
+  return strtol(p+2,0,16);
+}
+
+unicode unitable[MAX_FONTLEN][255];
+				/* Massive overkill, but who cares? */
+int unicount[MAX_FONTLEN];
+
+void addpair(int fp, int un)
+{
+  int i;
+
+  if ( un <= 0xfffe )
+    {
+      /* Check it isn't a duplicate */
+
+      for ( i = 0 ; i < unicount[fp] ; i++ )
+	if ( unitable[fp][i] == un )
+	  return;
+
+      /* Add to list */
+
+      if ( unicount[fp] > 254 )
+	{
+	  fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
+	  exit(EX_DATAERR);
+	}
+
+      unitable[fp][unicount[fp]] = un;
+      unicount[fp]++;
+    }
+
+  /* otherwise: ignore */
+}
+
+int main(int argc, char *argv[])
+{
+  FILE *ctbl;
+  char *tblname;
+  char buffer[65536];
+  int fontlen;
+  int i, nuni, nent;
+  int fp0, fp1, un0, un1;
+  char *p, *p1;
+
+  if ( argc < 2 || argc > 5 )
+    usage(argv[0]);
+
+  if ( !strcmp(argv[1],"-") )
+    {
+      ctbl = stdin;
+      tblname = "stdin";
+    }
+  else
+    {
+      ctbl = fopen(tblname = argv[1], "r");
+      if ( !ctbl )
+	{
+	  perror(tblname);
+	  exit(EX_NOINPUT);
+	}
+    }
+
+  /* For now we assume the default font is always 256 characters. */    
+  fontlen = 256;
+
+  /* Initialize table */
+
+  for ( i = 0 ; i < fontlen ; i++ )
+    unicount[i] = 0;
+
+  /* Now we come to the tricky part.  Parse the input table. */
+
+  while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
+    {
+      if ( (p = strchr(buffer, '\n')) != NULL )
+	*p = '\0';
+      else
+	fprintf(stderr, "%s: Warning: line too long\n", tblname);
+
+      p = buffer;
+
+/*
+ * Syntax accepted:
+ *	<fontpos>	<unicode> <unicode> ...
+ *	<range>		idem
+ *	<range>		<unicode range>
+ *
+ * where <range> ::= <fontpos>-<fontpos>
+ * and <unicode> ::= U+<h><h><h><h>
+ * and <h> ::= <hexadecimal digit>
+ */
+
+      while (*p == ' ' || *p == '\t')
+	p++;
+      if (!*p || *p == '#')
+	continue;	/* skip comment or blank line */
+
+      fp0 = strtol(p, &p1, 0);
+      if (p1 == p)
+	{
+	  fprintf(stderr, "Bad input line: %s\n", buffer);
+	  exit(EX_DATAERR);
+        }
+      p = p1;
+
+      while (*p == ' ' || *p == '\t')
+	p++;
+      if (*p == '-')
+	{
+	  p++;
+	  fp1 = strtol(p, &p1, 0);
+	  if (p1 == p)
+	    {
+	      fprintf(stderr, "Bad input line: %s\n", buffer);
+	      exit(EX_DATAERR);
+	    }
+	  p = p1;
+        }
+      else
+	fp1 = 0;
+
+      if ( fp0 < 0 || fp0 >= fontlen )
+	{
+	    fprintf(stderr,
+		    "%s: Glyph number (0x%x) larger than font length\n",
+		    tblname, fp0);
+	    exit(EX_DATAERR);
+	}
+      if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
+	{
+	    fprintf(stderr,
+		    "%s: Bad end of range (0x%x)\n",
+		    tblname, fp1);
+	    exit(EX_DATAERR);
+	}
+
+      if (fp1)
+	{
+	  /* we have a range; expect the word "idem" or a Unicode range of the
+	     same length */
+	  while (*p == ' ' || *p == '\t')
+	    p++;
+	  if (!strncmp(p, "idem", 4))
+	    {
+	      for (i=fp0; i<=fp1; i++)
+		addpair(i,i);
+	      p += 4;
+	    }
+	  else
+	    {
+	      un0 = getunicode(&p);
+	      while (*p == ' ' || *p == '\t')
+		p++;
+	      if (*p != '-')
+		{
+		  fprintf(stderr,
+"%s: Corresponding to a range of font positions, there should be a Unicode range\n",
+			  tblname);
+		  exit(EX_DATAERR);
+	        }
+	      p++;
+	      un1 = getunicode(&p);
+	      if (un0 < 0 || un1 < 0)
+		{
+		  fprintf(stderr,
+"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
+			  tblname, fp0, fp1);
+		  exit(EX_DATAERR);
+	        }
+	      if (un1 - un0 != fp1 - fp0)
+		{
+		  fprintf(stderr,
+"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n",
+			  tblname, un0, un1, fp0, fp1);
+		  exit(EX_DATAERR);
+	        }
+	      for(i=fp0; i<=fp1; i++)
+		addpair(i,un0-fp0+i);
+	    }
+        }
+      else
+	{
+	    /* no range; expect a list of unicode values for a single font position */
+
+	    while ( (un0 = getunicode(&p)) >= 0 )
+	      addpair(fp0, un0);
+	}
+      while (*p == ' ' || *p == '\t')
+	p++;
+      if (*p && *p != '#')
+	fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
+    }
+
+  /* Okay, we hit EOF, now output hash table */
+  
+  fclose(ctbl);
+  
+
+  /* Compute total size of Unicode list */
+  nuni = 0;
+  for ( i = 0 ; i < fontlen ; i++ )
+    nuni += unicount[i];
+  
+  printf("\
+/*\n\
+ * Do not edit this file; it was automatically generated by\n\
+ *\n\
+ * conmakehash %s > [this file]\n\
+ *\n\
+ */\n\
+\n\
+#include <linux/types.h>\n\
+\n\
+u8 dfont_unicount[%d] = \n\
+{\n\t", argv[1], fontlen);
+
+  for ( i = 0 ; i < fontlen ; i++ )
+    {
+      printf("%3d", unicount[i]);
+      if ( i == fontlen-1 )
+        printf("\n};\n");
+      else if ( i % 8 == 7 )
+        printf(",\n\t");
+      else
+        printf(", ");
+    }
+  
+  printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni);
+  
+  fp0 = 0;
+  nent = 0;
+  for ( i = 0 ; i < nuni ; i++ )
+    {
+      while ( nent >= unicount[fp0] )
+	{
+	  fp0++;
+	  nent = 0;
+	}
+      printf("0x%04x", unitable[fp0][nent++]);
+      if ( i == nuni-1 )
+         printf("\n};\n");
+       else if ( i % 8 == 7 )
+         printf(",\n\t");
+       else
+         printf(", ");
+    }
+
+  exit(EX_OK);
+}
diff -Nru a/scripts/lxdialog/Makefile b/scripts/lxdialog/Makefile
--- a/scripts/lxdialog/Makefile	Tue Aug 27 12:28:02 2002
+++ b/scripts/lxdialog/Makefile	Tue Aug 27 12:28:02 2002
@@ -39,5 +39,5 @@
 		exit 1 ;\
 	fi
 
-clean:
-	rm -f core *.o *~ lxdialog
+mrproper:
+	@rm -f core $(host-progs) $(lxdialog-objs) ncurses
diff -Nru a/sound/oss/Config.in b/sound/oss/Config.in
--- a/sound/oss/Config.in	Tue Aug 27 12:28:08 2002
+++ b/sound/oss/Config.in	Tue Aug 27 12:28:08 2002
@@ -11,7 +11,6 @@
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
     bool '    Enable legacy FM' CONFIG_SOUND_CMPCI_FM
     if [ "$CONFIG_SOUND_CMPCI_FM" = "y" ]; then
-	define_hex CONFIG_SOUND_CMPCI_FMIO 388
         hex '    FM I/O 388, 3C8, 3E0, 3E8' CONFIG_SOUND_CMPCI_FMIO 388
     fi
     bool '    Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI
diff -Nru a/sound/oss/es1371.c b/sound/oss/es1371.c
--- a/sound/oss/es1371.c	Tue Aug 27 12:28:01 2002
+++ b/sound/oss/es1371.c	Tue Aug 27 12:28:01 2002
@@ -1597,12 +1597,12 @@
         case SNDCTL_DSP_RESET:
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac2(s);
-			synchronize_irq();
+			synchronize_irq(s->irq);
 			s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(s);
-			synchronize_irq();
+			synchronize_irq(s->irq);
 			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
 		}
 		return 0;
@@ -2162,7 +2162,7 @@
 		
         case SNDCTL_DSP_RESET:
 		stop_dac1(s);
-		synchronize_irq();
+		synchronize_irq(s->irq);
 		s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0;
 		return 0;
 
@@ -3006,7 +3006,7 @@
 #endif /* ES1371_DEBUG */
 	outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
 	outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
-	synchronize_irq();
+	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
 	if (s->gameport.io) {
 		gameport_unregister_port(&s->gameport);
