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. !Edrivers/usb/core/hcd.c +!Edrivers/usb/core/hcd-pci.c +!Edrivers/usb/core/buffer.c 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 +------------------------------------------------------- + +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 --> #include + +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 + #include + +-#include ++#include + #include + #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 "); @@ -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 + +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 - -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 #include #include -#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 = ¤t->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 +#include +#include +#include + +#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. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + 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 +#include +#include +#include +#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. + The starting (base) address of the region. + 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, <ype); + 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(¢aur_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 + Initial register-setting code (from proform-1.0). + 19971216 Richard Gooch + Original version for /proc/mtrr interface, SMP-safe. + v1.0 + 19971217 Richard Gooch + Bug fix for ioctls()'s. + Added sample code in Documentation/mtrr.txt + v1.1 + 19971218 Richard Gooch + Disallow overlapping regions. + 19971219 Jens Maurer + Register-setting fixups. + v1.2 + 19971222 Richard Gooch + Fixups for kernel 2.1.75. + v1.3 + 19971229 David Wragg + Register-setting fixups and conformity with Intel conventions. + 19971229 Richard Gooch + Cosmetic changes and wrote this ChangeLog ;-) + 19980106 Richard Gooch + Fixups for kernel 2.1.78. + v1.4 + 19980119 David Wragg + Included passive-release enable code (elsewhere in PCI setup). + v1.5 + 19980131 Richard Gooch + Replaced global kernel lock with private spinlock. + v1.6 + 19980201 Richard Gooch + Added wait for other CPUs to complete changes. + v1.7 + 19980202 Richard Gooch + Bug fix in definition of for UP. + v1.8 + 19980319 Richard Gooch + Fixups for kernel 2.1.90. + 19980323 Richard Gooch + Move SMP BIOS fixup before secondary CPUs call + v1.9 + 19980325 Richard Gooch + Fixed test for overlapping regions: confused by adjacent regions + 19980326 Richard Gooch + Added wbinvd in . + 19980401 Richard Gooch + Bug fix for non-SMP compilation. + 19980418 David Wragg + Fixed-MTRR synchronisation for SMP and use atomic operations + instead of spinlocks. + 19980418 Richard Gooch + Differentiate different MTRR register classes for BIOS fixup. + v1.10 + 19980419 David Wragg + Bug fix in variable MTRR synchronisation. + v1.11 + 19980419 Richard Gooch + Fixups for kernel 2.1.97. + v1.12 + 19980421 Richard Gooch + Safer synchronisation across CPUs when changing MTRRs. + v1.13 + 19980423 Richard Gooch + Bugfix for SMP systems without MTRR support. + v1.14 + 19980427 Richard Gooch + Trap calls to and on non-MTRR machines. + v1.15 + 19980427 Richard Gooch + Use atomic bitops for setting SMP change mask. + v1.16 + 19980428 Richard Gooch + Removed spurious diagnostic message. + v1.17 + 19980429 Richard Gooch + Moved register-setting macros into this file. + Moved setup code from init/main.c to i386-specific areas. + v1.18 + 19980502 Richard Gooch + Moved MTRR detection outside conditionals in . + v1.19 + 19980502 Richard Gooch + Documentation improvement: mention Pentium II and AGP. + v1.20 + 19980521 Richard Gooch + Only manipulate interrupt enable flag on local CPU. + Allow enclosed uncachable regions. + v1.21 + 19980611 Richard Gooch + Always define . + v1.22 + 19980901 Richard Gooch + Removed module support in order to tidy up code. + Added sanity check for / before . + Created addition queue for prior to SMP commence. + v1.23 + 19980902 Richard Gooch + Ported patch to kernel 2.1.120-pre3. + v1.24 + 19980910 Richard Gooch + Removed sanity checks and addition queue: Linus prefers an OOPS. + v1.25 + 19981001 Richard Gooch + 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 + Added devfs support. + v1.27 + 19990123 Richard Gooch + Changed locking to spin with reschedule. + Made use of new . + v1.28 + 19990201 Zoltán Böszörményi + Extended the driver to be able to use Cyrix style ARRs. + 19990204 Richard Gooch + Restructured Cyrix support. + v1.29 + 19990204 Zoltán Böszörményi + Refined ARR support: enable MAPEN in set_mtrr_prepare() + and disable MAPEN in set_mtrr_done(). + 19990205 Richard Gooch + Minor cleanups. + v1.30 + 19990208 Zoltán Böszörményi + 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 + Turned and into function pointers. + v1.31 + 19990212 Zoltán Böszörményi + 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 + 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 + 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 + 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 + Added MTRRIOC_KILL_ENTRY ioctl(2) + Trap for counter underflow in . + Trap for 4 MiB aligned regions for PPro, stepping <= 7. + 19990301 Richard Gooch + Created hook. + 19990305 Richard Gooch + Temporarily disable AMD support now MTRR capability flag is set. + v1.32 + 19990308 Zoltán Böszörményi + Adjust my changes (19990212-19990218) to Richard Gooch's + latest changes. (19990228-19990305) + v1.33 + 19990309 Richard Gooch + Fixed typo in message. + 19990310 Richard Gooch + Support K6-II/III based on Alan Cox's patches. + v1.34 + 19990511 Bart Hartgers + Support Centaur C6 MCR's. + 19990512 Richard Gooch + Minor cleanups. + v1.35 + 19990707 Zoltán Böszörményi + 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 + 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 + 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 + Double check for Intel in mtrr_add()'s big switch() because + that revision check is only valid for Intel CPUs. + 19990819 Alan Cox + Tested Zoltan's changes on a pre production Athlon - 100% + success. + 19991008 Manfred Spraul + replaced spin_lock_reschedule() with a normal semaphore. + v1.36 + 20000221 Richard Gooch + Compile fix if procfs and devfs not enabled. + Formatting changes. + v1.37 + 20001109 H. Peter Anvin + Use the new centralized CPU feature detects. + + v1.38 + 20010309 Dave Jones + Add support for Cyrix III. + + v1.39 + 20010312 Dave Jones + Ugh, I broke AMD support. + Reworked fix by Troels Walsted Hansen + + v1.40 + 20010327 Dave Jones + Adapted Cyrix III support to include VIA C3. + + v2.0 + 20020306 Patrick Mochel + 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 +#include +#include +#include +#include +#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. + The starting (base) address of the region. + 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, <ype); + if (lsize == 0) + return 7; + /* Else try ARR0-ARR6 first */ + } else { + for (i = 0; i < 7; i++) { + cyrix_get_arr(i, &lbase, &lsize, <ype); + 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, <ype); + 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 +#include +#include +#include +#include +#include +#include "mtrr.h" + + +int generic_get_free_region(unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + 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, <ype); + 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. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + 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 +#include +#include +#include +#include +#include + +/* What kind of fucking hack is this? */ +#define MTRR_NEED_STRINGS + +#include +#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 + on 6-7 March 2002. + Source: Intel Architecture Software Developers Manual, Volume 3: + System Programming Guide; Section 9.11. (1997 edition - PPro). +*/ + +#include +#include +#include +#include + +#define MTRR_NEED_STRINGS +#include + +#include +#include +#include +#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, <ype); + 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, <ype); + 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, <ype); + 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 +#include +#include +#include +#include +#include +#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. + The MTRR state information to read. + 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 #include #include -#include #include #include @@ -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 -#include #include #include #include @@ -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 -#include #include #include #include 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: µcode_fops, + .minor = MICROCODE_MINOR, + .name = "microcode", + .fops = µcode_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 - Initial register-setting code (from proform-1.0). - 19971216 Richard Gooch - Original version for /proc/mtrr interface, SMP-safe. - v1.0 - 19971217 Richard Gooch - Bug fix for ioctls()'s. - Added sample code in Documentation/mtrr.txt - v1.1 - 19971218 Richard Gooch - Disallow overlapping regions. - 19971219 Jens Maurer - Register-setting fixups. - v1.2 - 19971222 Richard Gooch - Fixups for kernel 2.1.75. - v1.3 - 19971229 David Wragg - Register-setting fixups and conformity with Intel conventions. - 19971229 Richard Gooch - Cosmetic changes and wrote this ChangeLog ;-) - 19980106 Richard Gooch - Fixups for kernel 2.1.78. - v1.4 - 19980119 David Wragg - Included passive-release enable code (elsewhere in PCI setup). - v1.5 - 19980131 Richard Gooch - Replaced global kernel lock with private spinlock. - v1.6 - 19980201 Richard Gooch - Added wait for other CPUs to complete changes. - v1.7 - 19980202 Richard Gooch - Bug fix in definition of for UP. - v1.8 - 19980319 Richard Gooch - Fixups for kernel 2.1.90. - 19980323 Richard Gooch - Move SMP BIOS fixup before secondary CPUs call - v1.9 - 19980325 Richard Gooch - Fixed test for overlapping regions: confused by adjacent regions - 19980326 Richard Gooch - Added wbinvd in . - 19980401 Richard Gooch - Bug fix for non-SMP compilation. - 19980418 David Wragg - Fixed-MTRR synchronisation for SMP and use atomic operations - instead of spinlocks. - 19980418 Richard Gooch - Differentiate different MTRR register classes for BIOS fixup. - v1.10 - 19980419 David Wragg - Bug fix in variable MTRR synchronisation. - v1.11 - 19980419 Richard Gooch - Fixups for kernel 2.1.97. - v1.12 - 19980421 Richard Gooch - Safer synchronisation across CPUs when changing MTRRs. - v1.13 - 19980423 Richard Gooch - Bugfix for SMP systems without MTRR support. - v1.14 - 19980427 Richard Gooch - Trap calls to and on non-MTRR machines. - v1.15 - 19980427 Richard Gooch - Use atomic bitops for setting SMP change mask. - v1.16 - 19980428 Richard Gooch - Removed spurious diagnostic message. - v1.17 - 19980429 Richard Gooch - Moved register-setting macros into this file. - Moved setup code from init/main.c to i386-specific areas. - v1.18 - 19980502 Richard Gooch - Moved MTRR detection outside conditionals in . - v1.19 - 19980502 Richard Gooch - Documentation improvement: mention Pentium II and AGP. - v1.20 - 19980521 Richard Gooch - Only manipulate interrupt enable flag on local CPU. - Allow enclosed uncachable regions. - v1.21 - 19980611 Richard Gooch - Always define . - v1.22 - 19980901 Richard Gooch - Removed module support in order to tidy up code. - Added sanity check for / before . - Created addition queue for prior to SMP commence. - v1.23 - 19980902 Richard Gooch - Ported patch to kernel 2.1.120-pre3. - v1.24 - 19980910 Richard Gooch - Removed sanity checks and addition queue: Linus prefers an OOPS. - v1.25 - 19981001 Richard Gooch - 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 - Added devfs support. - v1.27 - 19990123 Richard Gooch - Changed locking to spin with reschedule. - Made use of new . - v1.28 - 19990201 Zoltán Böszörményi - Extended the driver to be able to use Cyrix style ARRs. - 19990204 Richard Gooch - Restructured Cyrix support. - v1.29 - 19990204 Zoltán Böszörményi - Refined ARR support: enable MAPEN in set_mtrr_prepare() - and disable MAPEN in set_mtrr_done(). - 19990205 Richard Gooch - Minor cleanups. - v1.30 - 19990208 Zoltán Böszörményi - 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 - Turned and into function pointers. - v1.31 - 19990212 Zoltán Böszörményi - 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 - 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 - 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 - 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 - Added MTRRIOC_KILL_ENTRY ioctl(2) - Trap for counter underflow in . - Trap for 4 MiB aligned regions for PPro, stepping <= 7. - 19990301 Richard Gooch - Created hook. - 19990305 Richard Gooch - Temporarily disable AMD support now MTRR capability flag is set. - v1.32 - 19990308 Zoltán Böszörményi - Adjust my changes (19990212-19990218) to Richard Gooch's - latest changes. (19990228-19990305) - v1.33 - 19990309 Richard Gooch - Fixed typo in message. - 19990310 Richard Gooch - Support K6-II/III based on Alan Cox's patches. - v1.34 - 19990511 Bart Hartgers - Support Centaur C6 MCR's. - 19990512 Richard Gooch - Minor cleanups. - v1.35 - 19990707 Zoltán Böszörményi - 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 - 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 - 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 - Double check for Intel in mtrr_add()'s big switch() because - that revision check is only valid for Intel CPUs. - 19990819 Alan Cox - Tested Zoltan's changes on a pre production Athlon - 100% - success. - 19991008 Manfred Spraul - replaced spin_lock_reschedule() with a normal semaphore. - v1.36 - 20000221 Richard Gooch - Compile fix if procfs and devfs not enabled. - Formatting changes. - v1.37 - 20001109 H. Peter Anvin - Use the new centralized CPU feature detects. - - v1.38 - 20010309 Dave Jones - Add support for Cyrix III. - - v1.39 - 20010312 Dave Jones - Ugh, I broke AMD support. - Reworked fix by Troels Walsted Hansen - - v1.40 - 20010327 Dave Jones - Adapted Cyrix III support to include VIA C3. - -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define MTRR_NEED_STRINGS -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - 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. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - 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<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. - The MTRR state information to read. - 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. - The starting (base) address of the region. - 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, <ype); - 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. - The starting (base) address of the region. - 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< The starting (base) address of the region. - 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, <ype); - if (lsize == 0) return 7; - /* Else try ARR0-ARR6 first */ - } - else - { - for (i = 0; i < 7; i++) - { - cyrix_get_arr (i, &lbase, &lsize, <ype); - 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, <ype); - 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. - The starting (base, in pages) address of the region. - The size of the region. (in pages) - The type of the new region. - 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, <ype); - 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. - The starting (base) address of the region. - The size (in bytes) of the region. - The type of the new region. - 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. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> 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, <ype); - 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, <ype); - 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. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> 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<= 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 #include #include -#include #include #include #include @@ -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 = ¤t->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 = ¤t->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 #include #include -#include #include #include #include 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 #include #include +#include #include #include @@ -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(¤t->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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 + * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co + * David Mosberger-Tang * Copyright (C) 1999 Vijay Chander */ +#include #include +#include #include +#include #include +#include #include #include -#include -#include -#include #include #include @@ -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 @@ -31,6 +32,7 @@ #include #include +#include #include #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 -#define MACHVEC_PLATFORM_NAME hpzx1 -#include 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 #include #include -#include + +#include #include +#include -#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 #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 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 -EXPORT_SYMBOL(kernel_flag); - -/* #include */ -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(" "); - 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 #include +#ifdef CONFIG_PERFMON +# include +#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 + */ + +#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 + */ + +#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 /* - * 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 + * Copyright (C) 1998-2002 Hewlett-Packard Co + * David Mosberger-Tang * * 01/05/16 Rohit Seth Moved SMP booting functions from smp.c to here. * 01/04/27 David Mosberger Added ITC synching code. + * 02/07/31 David Mosberger 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=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . - */ - -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<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 + */ +#include +#include +#include + +#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 #include +#include #include #include #include @@ -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 -EXPORT_SYMBOL(kernel_flag); - #include 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 #include #include -#include #include +#include #include #include #include @@ -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 #include #include -#include #include #include #include @@ -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 #include #include -#include #include #include #include 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 #include #include +#include #include #include 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, ¤t->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 #include #include -#include #include #include 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 #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include #include @@ -53,22 +51,18 @@ #include 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(®s, 0, sizeof(struct pt_regs)); + p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 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(®s, 0, sizeof(struct pt_regs)); - - p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 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 #include -/* 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, ×->actime) || __get_user(t.modtime, ×->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(¤t->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(¤t->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 #include +#include 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 = ¤t->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 #include -#include #include +#include +/* + * 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 #include +#include 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 +#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 -#include #include #include #include #include #include +#include #include #include #include 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 -#include #include #include #include #include #include +#include #include #include #include @@ -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 -#include #include #include #include #include #include +#include #include #include #include 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 #include +#include #include #include #include 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 +/* + * 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 @@ -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 +#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 #include #include +#include #include @@ -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 #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 .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 #include +#include #include #include #include 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 #include +#include #include #include @@ -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 #include - /* 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 @@ -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 #include -/* 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 #include -#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 *) ¤t_node->name, current_node)); + (char *) &simple_name, (char *) ¤t_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; idevices.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; itrips.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 +#include +#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 #include #include -#include #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 #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 +#include +#include +#include +#include +#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//devices/ -> + * root// + * So, the link looks like: + * ../../../root// + */ +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 : + * to prevent naming conflicts. + * + * We're creating + * class//drivers/ -> + * bus//drivers// + * So, the link looks like: + * ../../../bus//drivers/ + */ +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 #include #include +#include #include #include #include #include +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 +#include +#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 +#include +#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 #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 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<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<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; igendisk.part[ i<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<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; ihighest_lun; i++) - { + for(i=0; ihighest_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<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; jgendisk), - mk_kdev(MAJOR_NR+i, j <<4), - MAX_PART, &cciss_fops, - hba[i]->drv[j].nr_blocks); + + for(j=0; jdrv[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<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 #include #include +#include #include /* for invalidate_bdev() */ #include @@ -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<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<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<major,disk->first_minor), + 1<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 . -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 - . - - 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 - ) solves this problem, or you can get - the "mconv2" utility from . - 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 . + +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 . 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 -#include -#include -#include -#include - -#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: - * ... - * idem - * - * - * where ::= - - * and ::= U+ - * and ::= - */ - - 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 \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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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 @@ -32,22 +33,18 @@ #include #include #include - -#include -#include +#include #include #include #include #include -#include #include -#include +#include +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<= 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<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 1998-10-08. - * - * Code fixes to handle mouse ACKs properly. - * C. Scott Ananian 1999-01-29. - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -/* Some configuration switches are present in the include file... */ - -#include - -/* 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 and even Frodo Looijaard */ -/* $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 #include @@ -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 and + Frodo Looijaard ,and also from Martin Bailey + + + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "i2c-algo-ibm_ocp.h" +//ACC#include + +#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; imdbuf, + 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; imdbuf, 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; iIssued 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; imdbuf); + // 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 "); +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 and even + Frodo Looijaard */ + +/* 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 + +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 . - All SMBus-related things are written by Frodo Looijaard */ + All SMBus-related things are written by Frodo Looijaard + SMBus 2.0 support by Mark Studebaker */ -/* $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 #include @@ -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 */ -/* $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 #include @@ -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 "); 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 + * + * 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 +#include +#include + +#include +#include +#include + +#include + +#include +#include + +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 "); +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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +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 "); +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 +# +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 +#include +#include +#include +#include +#include +#include + +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 * - * 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 , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include +#include #include +#include +#include +#include #include #include +#include + +#include #include #include -#include #include + #include +#include -#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 +#include -/* - * 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, ®49h); + 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, ®54h); + 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 #include -#include +#include +#include +#include +#include +#include #include #include +#include #include -#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 #include #include -#include #include #include +#include #include -#include "timing.h" -#include "pcihost.h" +#include "ide_modes.h" + +#define DISPLAY_ALI_TIMINGS + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +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, ®53h); + p += sprintf(p, "PCI Clock: %d.\n", reg53h); + + pci_read_config_byte(bmide_dev, 0x53, ®53h); + 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, ®53h); + 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, ®53h); + 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, ®53h); + p += sprintf(p, + "Channel state: %s %s\n", + channel_status[reg53h & 0x07], + channel_status[(reg53h & 0x70) >> 4] ); + + pci_read_config_byte(bmide_dev, 0x58, ®5xh); + pci_read_config_byte(bmide_dev, 0x5c, ®5yh); + 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, ®5xh); + pci_read_config_byte(bmide_dev, 0x5d, ®5yh); + 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, ®5xh); + pci_read_config_byte(bmide_dev, 0x55, ®5yh); + 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, ®5xh); + pci_read_config_byte(bmide_dev, 0x5b, ®5xh1); + pci_read_config_byte(bmide_dev, 0x5e, ®5yh); + pci_read_config_byte(bmide_dev, 0x5f, ®5yh1); + + 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, ®5xh); + pci_read_config_byte(bmide_dev, 0x57, ®5yh); + 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 + * 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 , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include +#include #include +#include +#include +#include #include #include -#include -#include #include + +#include +#include +#include #include #include +#include -#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 +#include -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 \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 , or by paper mail: Vojtech Pavlik, - * Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include - -#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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * 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 - - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 - - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 @@ -106,14 +109,13 @@ #include #include #include -#include #include #include -#include +#include #include -#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 - * Copyright (C) 1998 David S. Miller * Copyright (C) 1999-2002 Andre Hedrick */ @@ -18,19 +18,22 @@ #include #include #include -#include #include #include +#include #include -#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 +#include + +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, ®50); + (void) pci_read_config_byte(dev, ARTTIM0, ®53); + (void) pci_read_config_byte(dev, DRWTIM0, ®54); + (void) pci_read_config_byte(dev, ARTTIM1, ®55); + (void) pci_read_config_byte(dev, DRWTIM1, ®56); + (void) pci_read_config_byte(dev, ARTTIM2, ®57); + (void) pci_read_config_byte(dev, DRWTIM2, ®58); + (void) pci_read_config_byte(dev, DRWTIM3, ®5b); + (void) pci_read_config_byte(dev, MRDMODE, ®71); + (void) pci_read_config_byte(dev, BMIDESR0, ®72); + (void) pci_read_config_byte(dev, UDIDETCR0, ®73); + (void) pci_read_config_byte(dev, BMIDESR1, ®7a); + (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); + + 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, ®D); - pci_read_config_byte(dev, pciU, ®U); +#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, ®D); + (void) pci_read_config_byte(dev, pciU, ®U); 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, ®D); + (void) pci_read_config_byte(dev, pciU, ®U); +#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, ®D); - pci_read_config_byte(dev, pciU, ®U); - - 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 @@ -20,29 +19,74 @@ #include #include #include +#include #include #include #include -#include #include - #include #include -#include "timing.h" -#include "pcihost.h" +#include "ide_modes.h" + +#define DISPLAY_CS5530_TIMINGS + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +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 #include #include -#include -#include #include +#include #include -#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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * 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 #include #include @@ -9,13 +13,13 @@ #include #include #include -#include #include #include +#include #include -#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 #include #include +#include #include #include @@ -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 * 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 #include #include +#include #include #include #include -#include #include #include #include +#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 +#include + +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, ®1); pci_read_config_dword(dev, 0x48, ®2); - 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, ®1); + pci_read_config_dword(dev, 0x48, ®2); + 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 + * Copyright (C) 1999-2002 Andre Hedrick * 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 + * Adrian Sun * * 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 + * Duncan Laurie * * fixup /proc output for multiple controllers * Tim Hockin * - * On hpt366: + * On hpt366: * Reset the hpt366 on error, reset on dma * Fix disabling Fast Interrupt hpt366. - * Mike Waychison - * - * 02 May 2002 - HPT374 support (Andre Hedrick ) + * Mike Waychison */ + #include #include #include @@ -53,26 +50,32 @@ #include #include #include +#include + #include #include #include -#include #include #include #include #include -#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 +#include +#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, ®1); 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, ®1); 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, ®5a); - 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, ®50h); - pci_read_config_byte(dev, 0x52, ®52h); - pci_read_config_byte(dev, 0x5a, ®5ah); - 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, ®50h); + pci_read_config_byte(dev, 0x52, ®52h); + pci_read_config_byte(dev, 0x5a, ®5ah); + 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, ®59h); - 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, ®59h); + 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, ®59h); pci_read_config_byte(dev, state_reg, ®XXh); 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, ®5ah); + /* 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, ®5bh); 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, ®1); - + /* 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, ®5ah); - 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 - - Based on work - Copyleft (C) 2001 by Wilfried Weissmann - Copyright (C) 1994-96 Marc ZYNGIER - Based on work done by Søren Schmidt for FreeBSD - - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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, §); - - if (p) { - memcpy(buf, p, 512); - put_dev_sector(§); - 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 - * 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 #include #include @@ -38,13 +45,13 @@ #include #include #include -#include #include #include +#include #include -#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 #include #include -#include /* * 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 + * + * 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 * Copyright (C) 1996-1998 Erik Andersen * Copyright (C) 1998-2000 Jens Axboe @@ -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 for diagnosing this. + * showed up if the drive returned data in 512 byte + * blocks (like Pioneer drives). Thanks to + * Richard Hirst 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 ). + * from Holger Dietze ). * 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 .) * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers - * from Ben Galliart with - * special help from Jeff Lightfoot - * + * from Ben Galliart with + * special help from Jeff Lightfoot + * * 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 + * Erik B. Andersen * -- 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 - * 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 - * , a patch for 2.0.33 - * by Toni Giorgino , the SCSI - * version, and my own efforts. -erik + * based on a patch for 2.0.33 by Jelle Foks + * , a patch for 2.0.33 + * by Toni Giorgino , 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" + * 4.15 Aug 25, 1998 -- Updated ide-cd.h to respect mechine endianess, + * patch thanks to "Eddie C. Dost" * * 4.50 Oct 19, 1998 -- New maintainers! - * Jens Axboe - * Chris Zwilling + * Jens Axboe + * Chris Zwilling * * 4.51 Dec 23, 1998 -- Jens Axboe * - 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 * *************************************************************************/ - + #define IDECD_VERSION "4.59" #include @@ -305,9 +306,8 @@ #include #include #include -#include -#include #include +#include #include #include @@ -315,7 +315,6 @@ #include #include -#include #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; ic); 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<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 " #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 " #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 " #endif - u8 page_length; + byte page_length; #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved2 : 2; @@ -435,9 +435,9 @@ #error "Please fix " #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 " #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 #include @@ -54,12 +54,12 @@ #include #include -#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<vcc.param[CISTPL_POWER_VNOM]/10000) + goto next_entry; + } else if (dflt.vcc.present & (1<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<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<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 + * * - * Copyright (C) 1994-1998,2002 Linus Torvalds and authors: + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + */ + +/* + * Mostly written by Mark Lord + * and Gadi Oxman + * and Andre Hedrick * - * Mark Lord - * Gadi Oxman - * Andre Hedrick - * Jens Axboe - * Marcin Dalecki + * 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 #include #include @@ -24,9 +57,9 @@ #include #include #include -#include /* for invalidate_bdev() */ -#include #include +#include +#include #include #include @@ -34,31 +67,24 @@ #include #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; ihandler) && (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; ichannel; - unit = drive - channel->drives; - disk = channel->gd[unit]; - disk->minor_shift = PARTN_BITS; - register_disk(disk, mk_kdev(disk->major, disk->first_minor), - 1<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; ihandler = 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; ihandler != 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 + * 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 for researching this). + * + * Thanks to "Christopher J. Reimer" for + * fixing the problem with the BIOS on some Acer motherboards. + * + * Thanks to "Benoit Poulot-Cazajous" for testing + * "TX" chipset compatibility and for providing patches for the "TX" chipset. + * + * Thanks to Christian Brunner for taking a good first crack + * at generic DMA -- his patches were referred to when preparing this code. + * + * Most importantly, thanks to Robert Bringman + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * 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 * Copyright (C) 2000 - 2002 Paul Bristow */ @@ -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 #include @@ -94,10 +96,7 @@ #include #include #include -#include -#include #include -#include #include #include @@ -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<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 +#include +#include +#include + +#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 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 #include #include -#include -#include #include +#include #include #include @@ -44,15 +43,14 @@ #include #include -#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 - * Copyright (C) 1998-2000 Andre Hedrick - * Copyright (C) 1995-1998 Mark Lord + * Copyright (c) 1998-2000 Andre Hedrick * + * 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 @@ -20,125 +27,621 @@ #include #include #include -#include #include #include #include -#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 " + ".\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 #include #include -#include +#include #include #include -#include -#include #include +#include +#include +#include #include #include @@ -52,9 +42,11 @@ #include #include #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; iio_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 < 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; dndrives[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; dndrives[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 #include #include @@ -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 + * and Gadi Oxman + * and Andre Hedrick + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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<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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 * + * $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, , - * Nov 2000, Jan 2001 Marcel Mol, - * Apr 2001 Willem Riede, + * 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 #include @@ -34,13 +417,9 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#include #include #include @@ -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 + * Copyright (C) 2000-2002 Andre Hedrick + * Copyright (C) 2001-2002 Klaus Smolin + * IBM Storage Technology Division + * + * The big the bad and the ugly. * - * Copyright (C) 2002 Marcin Dalecki - * Copyright (C) 2000 Michael Cornwell - * Copyright (C) 2000 Andre Hedrick + * 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 @@ -20,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -33,201 +51,2734 @@ #include #include +#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. + */ +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, + */ +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. + */ + 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. + */ +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. + */ +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<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 , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +#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 - * Gadi Oxman - * Andre Hedrick - * Jens Axboe - * Marcin Dalecki + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + */ + +/* + * Mostly written by Mark Lord + * and Gadi Oxman + * and Andre Hedrick * * 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 - * Mika Liljeberg - * Delman Lee - * Scott Snyder + * 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 */ +#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 #include #include @@ -40,22 +136,21 @@ #include #include #include +#include #include #include #include #include #ifndef MODULE -# include -#endif +#include +#endif /* MODULE */ #include #include +#include #include +#include #include #include -#include -#include -#include -#include #include #include @@ -63,87 +158,249 @@ #include #include -#include "timing.h" -#include "pcihost.h" -#include "ioctl.h" +#include "ide_modes.h" + +#ifdef CONFIG_KMOD +#include +#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<forced_geom && drive->noprobe) ? 1 : +#endif /* CONFIG_BLK_DEV_ISAPNP */ + 1<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)<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<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<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 + +/* + * 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 - * - * 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 #include #include -#include -#include #include #include +#include +#include #include #include -#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, ®48); - pci_read_config_byte(dev, 0x4a, ®4a); +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, ®48); + pci_read_config_byte(dev, 0x4a, ®4a); /* * 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 - * Gadi Oxman - * Andre Hedrick - * Jens Axboe - * Marcin Dalecki - * - * See linux/MAINTAINERS for address of current maintainer. - */ - -/* - * Handle overall infrastructure of the driver - */ - -#define VERSION "7.0.0" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef MODULE -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#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<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 #include #include -#include #include +#include #include -#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 , * Jan Harkes , @@ -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 @@ -99,8 +103,7 @@ #include -#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 - * - * Based on previous work by: - * - * Copyright (c) 1999-2000 Andre Hedrick - * 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 -#define __NO_VERSION__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "timing.h" - -#include -#include - -#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 - * - * 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 - * Copyright (C) 2002 BartÅ^Âomiej Å»oÅ^Ânierkiewicz - * - * Portions Copyright (C) 1999-2002 Promise Technology, Inc. - * Author: Frank Tiernan - * Hank Yang +/* + * 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 * * 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 @@ -48,21 +36,260 @@ #include #include #include +#include #include #include #include -#include #include #include #include -#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 +#include + +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, ®50h); + pci_read_config_dword(dev, 0x60, ®60h); + pci_read_config_dword(dev, 0x64, ®64h); + pci_read_config_dword(dev, 0x68, ®68h); + pci_read_config_dword(dev, 0x6c, ®6ch); + + 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 #include @@ -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 + * May be copied or modified under the terms of the GNU General Public License + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#undef DISPLAY_PDCADMA_TIMINGS + +#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +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 - - Based on work done by Søren Schmidt for FreeBSD - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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, §); - if (!p) { - printk(KERN_ERR - "pdcraid: Error reading superblock.\n"); - return -1; - } - memcpy(buffer, q, 512); - put_dev_sector(§); - } - 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 + * 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, ®40); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); * - * 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 , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include +#include #include #include -#include #include -#include #include #include +#include +#include #include -#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 +#include -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, ®40); + pci_read_config_word(bmide_dev, 0x42, ®42); + pci_read_config_byte(bmide_dev, 0x44, ®44); + pci_read_config_byte(bmide_dev, 0x48, ®48); + pci_read_config_byte(bmide_dev, 0x4a, ®4a); + pci_read_config_byte(bmide_dev, 0x4b, ®4b); + pci_read_config_byte(bmide_dev, 0x54, ®54); + pci_read_config_byte(bmide_dev, 0x55, ®55); + + 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, ®4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); - 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, ®54h); + pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - 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 - * and Gadi Oxman - * and Andre Hedrick - * - * See linux/MAINTAINERS for address of current maintainer. - * - */ - -/* - * This is roughly the code related to device detection and - * device id handling. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -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 " -# 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 by * Samuel Thibault */ -#include +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + #include #include #include @@ -27,13 +34,12 @@ #include #include #include -#include #include #include - +#include #include -#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 - * - * Copyright (c) 1999-2000 Andre Hedrick - * 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 -#define __NO_VERSION__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 /* for CONFIG_PCI */ +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include /* for CONFIG_BLK_DEV_IDEPCI */ #include #include #include @@ -22,85 +27,61 @@ #include #include #include -#include #include +#include #include -#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, ®) - && !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, ®) && + !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 & PCI_COMMAND_IO)) { + if (!pci_read_config_word (dev, PCI_COMMAND, ®) && + !(reg & PCI_COMMAND_IO)) { printk("%s: buggy IDE controller disabled (BIOS)\n", name); return; } - if (!pci_read_config_word (dev, 0x40, ®) - && !pci_write_config_word(dev, 0x40, reg & 0xdfff)) - { + if (!pci_read_config_word (dev, 0x40, ®) && + !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- SERR- TAbort- SERR- #include #include -#include -#include #include #include +#include +#include #include -#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 +#include -#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, ®40); + pci_read_config_dword(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_word(dev, 0x56, ®56); + + /* + * 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, ®); + 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, ®4c); + 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 #include #include +#include #include #include #include -#include #include #include #include -#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 +#include + +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, ®00); + 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, ®00); + pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01); + pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10); + pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11); + +/* 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, ®); + 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, ®); + 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, ®); + 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, ®2); + pci_read_config_word(bmide_dev, 0x4e, ®3); + 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, ®4bh); @@ -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, ®48h); 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 #include #include #include @@ -19,39 +17,27 @@ #include #include #include -#include #include +#include #include #include #include -#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 + * 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- SERR- +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ide_modes.h" + +#define SLC90E66_DEBUG_DRIVE_INFO 0 + +#define DISPLAY_SLC90E66_TIMINGS + +#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +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, ®40); + pci_read_config_word(bmide_dev, 0x42, ®42); + pci_read_config_byte(bmide_dev, 0x44, ®44); + pci_read_config_byte(bmide_dev, 0x47, ®47); + pci_read_config_byte(bmide_dev, 0x48, ®48); + pci_read_config_byte(bmide_dev, 0x4a, ®4a); + pci_read_config_byte(bmide_dev, 0x4b, ®4b); + + 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, ®4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + + 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, ®4a); + 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, ®47); + 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * 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 -#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 #include #include -#include #include #include +#include #include -#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 #include #include -#include #include - #include -#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 +#include + +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 #include #include -#include #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 . -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 . - 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 . - -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 . 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 #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); 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 #include #include +#include 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 #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); 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 #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); 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 . -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 . 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 #include +#include MODULE_AUTHOR("Vojtech Pavlik "); 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 , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -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 #include #include +#include #include #include @@ -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 . + + +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 . 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 +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +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 + * + * Changes/Revisions: + * 0.1 20/06/2002 + * - first public version + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include +#include #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #include #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 #include #include +#include #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 - * - * Changes/Revisions: - * 0.1 20/06/2002 - * - first public version - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 #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 #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 #include #include -#include #include #include @@ -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 @@ -16,36 +16,14 @@ #include -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<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<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<faulty = 1; kick_rdev_from_array(rdev); } else if (desc->state & (1<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<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<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; pathraid_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<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 #include #include +#include #include #include @@ -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<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<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<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 #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include @@ -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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include +#include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include @@ -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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include @@ -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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include #include -#include #include #include #include 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 #include - -#ifndef MODULE -#include -#endif - #include #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 #include #include /* printk(), and other useful stuff */ -#include #include /* offsetof(), etc. */ #include /* return codes */ #include /* 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 #include #include -#include #include #include #include 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<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<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 #include #include -#ifdef CONFIG_SPARC32 -#include /* 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 + * linux/drivers/scsi/ide-scsi.c Version 0.9 Jul 4, 1999 * + * Copyright (C) 1996 - 1999 Gadi Oxman + */ + +/* * 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 #include #include @@ -18,23 +43,40 @@ #include #include #include -#include #include #include #include -#include - #include "scsi.h" #include "hosts.h" #include "sd.h" +#include + +#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 @@ -46,7 +47,12 @@ #include #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; } /* <> */ -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" + " 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" + " delay response 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 +#include 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 @@ -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 #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 -#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 -#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 */ - 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 */ + 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 */ - /* 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 */ + /* 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 */ - 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 */ + 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(¤t->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(¤t->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("\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("\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("\n"); - strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) : - (shp->hostt->name ? shp->hostt->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("\n"); + strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) : + (shp->hostt->name ? shp->hostt->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 Devfs support */ -static char *verstr = "20020722"; +static char *verstr = "20020822"; #include @@ -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(¤t->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(¤t->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 - * Copyright (c) 1999 Pavel Machek - * Copyright (c) 2000 Randy Dunlap - * Copyright (c) 2000 Vojtech Pavlik - # Copyright (c) 2001 Pete Zaitcev - # Copyright (c) 2001 David Paschal - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef DEBUG -#include - -/* - * 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<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<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 + * Copyright (c) 1999 Pavel Machek + * Copyright (c) 2000 Randy Dunlap + * Copyright (c) 2000 Vojtech Pavlik + # Copyright (c) 2001 Pete Zaitcev + # Copyright (c) 2001 David Paschal + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef DEBUG +#include + +/* + * 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<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<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 +#include +#include +#include +#include +#include + + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#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 #include +#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 #include #include /* for UTS_SYSNAME */ +#include /* for hcd->pdev and dma addressing */ #include @@ -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 #include +#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 #include +#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 @@ -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 #include #include +#include #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 "); 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 . + +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 + . + + 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 + . + 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 + - 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 + +Version 0.2.3: + - Fixed wrong allocation size. caused memory corruption in some + cases. Reported by Vladimir Dergachev + - Added some comments + +Version 0.2.2: + - Fixed CRCASM (patch from Linus Flannagan ) + - Fixed problem when user did NOT use the ATMSAR_USE_53BYTE_CELL flag. + (reported by Piers Scannell ) + - 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 +#include + +#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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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 #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 * + * * + * 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 +#include +#include +#include +#include +#include +#include + +#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 "); +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 + * 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 ) 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 ) 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 - +#include