]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.20pre12 2.2.20pre12
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:59 +0000 (15:23 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:59 +0000 (15:23 -0500)
o Update davicom driver to fix oopses (Sten Wang)
o Updated PC300 driver - fix SCA-II DMA bugs
(Daniela  P. R. Magri Squassoni)
o Make syn cookies per socket (Andi Kleen)
o Computone driver fixes for fast PC's (Michael Warfield)
| Follow on devfs patches didnt apply so dropped
o DAC960 update (Leonard Zubkoff)

21 files changed:
Documentation/README.DAC960
Documentation/computone.txt
MAINTAINERS
Makefile
drivers/block/DAC960.c
drivers/block/DAC960.h
drivers/char/README.computone
drivers/char/ip2.c
drivers/char/ip2/i2ellis.c
drivers/char/ip2/i2ellis.h
drivers/char/ip2/i2lib.c
drivers/char/ip2/ip2.h
drivers/char/ip2main.c
drivers/net/dmfe.c
drivers/net/falc-lh.h
drivers/net/hd64572.h
drivers/net/pc300.c
drivers/net/pc300.h
include/net/sock.h
init/main.c
net/ipv4/syncookies.c

index dbda5d27734b24a216decdf71567a750bd50cbd7..b6b770ee8dd6f784fbf869b78f686dcdf4e8e988 100644 (file)
@@ -1,11 +1,11 @@
    Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-                       Version 2.2.10 for Linux 2.2.18
-                       Version 2.4.10 for Linux 2.4.1
+                       Version 2.2.11 for Linux 2.2.19
+                       Version 2.4.11 for Linux 2.4.12
 
                              PRODUCTION RELEASE
 
-                              1 February 2001
+                               11 October 2001
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -20,7 +20,7 @@ Mylex, Inc. designs and manufactures a variety of high performance PCI RAID
 controllers.  Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont,
 California 94555, USA and can be reached at 510.796.6100 or on the World Wide
 Web at http://www.mylex.com.  Mylex Technical Support can be reached by
-electronic mail at support@mylex.com, by voice at 510.608.2400, or by FAX at
+electronic mail at mylexsup@us.ibm.com, by voice at 510.608.2400, or by FAX at
 510.745.7715.  Contact information for offices in Europe and Japan is available
 on their Web site.
 
@@ -120,7 +120,7 @@ AcceleRAID 170
            100MHz Intel i960RM RISC Processor
            16MB/32MB/64MB ECC SDRAM Memory
 
-AcceleRAID 160
+AcceleRAID 160 (AcceleRAID 170LP)
            1 Wide Ultra-160 LVD SCSI channel
            100MHz Intel i960RS RISC Processor
            Built in 16M ECC SDRAM Memory
@@ -170,6 +170,10 @@ DAC960PL    1/2/3 Wide Fast SCSI-2 Channels
            Intel i960 RISC Processor
            2MB/4MB/8MB/16MB/32MB DRAM Memory
 
+DAC960P            1/2/3 Wide Fast SCSI-2 Channels
+           Intel i960 RISC Processor
+           2MB/4MB/8MB/16MB/32MB DRAM Memory
+
 For the eXtremeRAID 2000/3000 and AcceleRAID 352/170/160, firmware version
 6.00-01 or above is required.
 
@@ -180,36 +184,29 @@ required.
 
 For the DAC960PJ and DAC960PG, firmware version 4.06-0-00 or above is required.
 
-For the DAC960PU, DAC960PD, and DAC960PL, firmware version 3.51-0-04 or above
-is required.
-
-Note that earlier revisions of the DAC960PU, DAC960PD, and DAC960PL controllers
-were delivered with version 2.xx firmware.  Version 2.xx firmware is not
-supported by this driver and no support is envisioned.  Contact Mylex RAID
-Technical Support to inquire about upgrading controllers with version 2.xx
-firmware to version 3.51-0-04.  Upgrading to version 3.xx firmware requires
-installation of higher capacity Flash ROM chips, and not all DAC960PD and
-DAC960PL controllers can be upgraded.
+For the DAC960PU, DAC960PD, DAC960PL, and DAC960P, either firmware version
+3.51-0-04 or above is required (for dual Flash ROM controllers), or firmware
+version 2.73-0-00 or above is required (for single Flash ROM controllers)
 
 Please note that not all SCSI disk drives are suitable for use with DAC960
 controllers, and only particular firmware versions of any given model may
 actually function correctly.  Similarly, not all motherboards have a BIOS that
 properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150,
 DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device.
-If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify
-compatibility.  Mylex makes available a hard disk compatibility list at
+If in doubt, contact Mylex RAID Technical Support (mylexsup@us.ibm.com) to
+verify compatibility.  Mylex makes available a hard disk compatibility list at
 http://www.mylex.com/support/hdcomp/hd-lists.html.
 
 
                              DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.18 or 2.4.1.
+This distribution was prepared for Linux kernel version 2.2.19 or 2.4.12.
 
 To install the DAC960 RAID driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf DAC960-2.2.10.tar.gz (or DAC960-2.4.10.tar.gz)
+  tar -xvzf DAC960-2.2.11.tar.gz (or DAC960-2.4.11.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
   patch -p0 < DAC960.patch (if DAC960.patch is included)
@@ -374,11 +371,14 @@ commands are:
 
     The "make-online" command changes the physical drive <channel>:<target-id>
     from status DEAD to status ONLINE.  In cases where multiple physical drives
-    have been killed simultaneously, this command may be used to bring them
-    back online, after which a consistency check is advisable.
+    have been killed simultaneously, this command may be used to bring all but
+    one of them back online, after which a rebuild to the final drive is
+    necessary.
 
     Warning: make-online should only be used on a dead physical drive that is
-    an active part of a drive group, never on a standby drive.
+    an active part of a drive group, never on a standby drive.  The command
+    should never be used on a dead drive that is part of a critical logical
+    drive; rebuild should be used if only a single drive is dead.
 
   make-standby <channel>:<target-id>
 
index de281aa84464faf1f418cbb123f27e92d3ba040a..3ef6db35ffd5a2969293cc362c6f5852e6855dd7 100644 (file)
@@ -4,16 +4,15 @@ Computone Intelliport II/Plus Multiport Serial Driver
 
 Release Notes For Linux Kernel 2.2 and higher.
 These notes are for the drivers which have already been integrated into the
-kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3.
+kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
 
-Version: 1.2.9
-Date: 04/12/2000
-Author: Andrew Manison <amanison@america.net>
+Version: 1.2.11
+Date: 10/21/2001
+Historical Author: Andrew Manison <amanison@america.net>
+Primary Author: Doug McNash <dougm@computone.com>
 Testing: larryg@computone.com
 Support: support@computone.com
-Fixes and Updates: Doug McNash <dougm@computone.com>
-Proc Filesystem and Kernel Integration: Mike Warfield <mhw@wittsend.com>
-
+Fixes and Updates: Mike Warfield <mhw@wittsend.com>
 
 This file assumes that you are using the Computone drivers which are
 integrated into the kernel sources.  For updating the drivers or installing
@@ -42,7 +41,7 @@ Hardware - If you have an ISA card, find a free interrupt and io port.
                   before or after drivers installation.
 
        Note the hardware address from the Computone ISA cards installed into
-               the system.  These are required for editing ip2.h or editing
+               the system.  These are required for editing ip2.c or editing
                /etc/modules.conf, or for specification on the modprobe
                command line.
 
@@ -58,7 +57,7 @@ b) Run "make config" or "make menuconfig" or "make xconfig"
    Select (m) module for CONFIG_COMPUTONE under character
    devices.  CONFIG_PCI and CONFIG_MODULES also may need to be set.
 c) Set address on ISA cards then:
-   edit /usr/src/linux/drivers/char/ip2/ip2.h if needed 
+   edit /usr/src/linux/drivers/char/ip2.c if needed 
        or
    edit /etc/modules.conf if needed (module).
        or both to match this setting.
@@ -77,7 +76,8 @@ b) Run "make config" or "make menuconfig" or "make xconfig"
    Select (y) kernel for CONFIG_COMPUTONE under character
    devices.  CONFIG_PCI may need to be set if you have PCI bus.
 c) Set address on ISA cards then:
-          edit /usr/src/linux/drivers/char/ip2/ip2.h  
+          edit /usr/src/linux/drivers/char/ip2.c  
+           (Optional - may be specified on kernel command line now)
 d) Run "make dep"
 e) Run "make zImage" or whatever target you prefer.
 f) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
@@ -86,6 +86,41 @@ g) Add new config for this kernel into /etc/lilo.conf, run "lilo"
 h) Reboot using this kernel
 i) run ip2mkdev (either the script below or the binary version)
 
+Kernel command line options:
+
+When compiling the driver into the kernel, io and irq may be
+compiled into the driver by editing ip2.c and setting the values for
+io and irq in the appropriate array.  An alternative is to specify
+a command line parameter to the kernel at boot up.
+
+        ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+
+Note that this order is very different from the specifications for the
+modload parameters which have separate IRQ and IO specifiers.
+
+The io port also selects PCI (1) and EISA (2) boards.
+
+        io=0    No board
+        io=1    PCI board
+        io=2    EISA board
+        else    ISA board io address
+
+You only need to specify the boards which are present.
+
+        Examples:
+
+                2 PCI boards:
+
+                        ip2=1,0,1,0
+
+                1 ISA board at 0x310 irq 5:
+
+                        ip2=0x310,5
+
+This can be added to and "append" option in lilo.conf similar to this:
+
+        append="ip2=1,0,1,0"
+
 
 3. INSTALLATION
 
@@ -100,7 +135,7 @@ running patch -p1 < ThePatchFile.  Otherwise run ip2build.
 The driver can be installed as a module (recommended) or built into the 
 kernel. This is selected as for other drivers through the `make config`
 command from the root of the Linux source tree. If the driver is built 
-into the kernel you will need to edit the file ip2.h to match the boards 
+into the kernel you will need to edit the file ip2.c to match the boards 
 you are installing. See that file for instructions. If the driver is 
 installed as a module the configuration can also be specified on the
 modprobe command line as follows:
@@ -109,13 +144,13 @@ modprobe command line as follows:
 
 where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
 12,15) and addr1-4 are the base addresses for up to four controllers. If 
-the irqs are not specified the driver uses the default in ip2/ip2.h (which 
+the irqs are not specified the driver uses the default in ip2.c (which 
 selects polled mode). If no base addresses are specified the defaults in 
-ip2.h are used. If you are autoloading the driver module with kerneld or
-kmod the base addresses and interrupt number must also be set in ip2/ip2.h
+ip2.c are used. If you are autoloading the driver module with kerneld or
+kmod the base addresses and interrupt number must also be set in ip2.c
 and recompile or just insert and options line in /etc/modules.conf or both. 
 The options line is equivalent to the command line and takes precidence over 
-what is in ip2.h
+what is in ip2.c
 
 /etc/modules.conf sample:
        options ip2 io=1,0x328 irq=1,10
@@ -123,22 +158,18 @@ what is in ip2.h.
        alias char-major-72 ip2
        alias char-major-73 ip2
 
-equivelant ip2.h:
-static ip2config_t ip2config =
-{
-       {1,10,0,0},
-       {
-               0x0001,    // Board 0, ttyF0   - ttyF63         /* PCI card */
-               0x0328,    // Board 1, ttyF64  - ttyF127        /* ISA card */
-               0x0000,    // Board 2, ttyF128 - ttyF191        /* empty */
-               0x0000     // Board 3, ttyF192 - ttyF255        /* empty */
-       }
-};
+The equivalent in ip2.c:
+
+static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 };
+static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 }; 
+
+The equivalent for the kernel command line (in lilo.conf):
+
+        append="ip2=1,1,0x328,10"
 
 
 Note:  Both io and irq should be updated to reflect YOUR system.  An "io"
-       address of "1/2" indicates a PCI/EISA card in the board table.  The
-       PCI or EISA irq will be assigned automatically.
+       address of 1 or 2 indicates a PCI or EISA card in the board table.              The PCI or EISA irq will be assigned automatically.
 
 Specifying an invalid or in-use irq will default the driver into
 running in polled mode for that card.  If all irq entries are 0 then
index 402866d2ab5a5cef9076eef52d9121b2c8b1e51a..d7b914986999280d552bb8fdcf386b0e4f129068 100644 (file)
@@ -199,9 +199,7 @@ W:  ftp.compaq.com/pub/products/drivers/linux
 S:      Supported
 
 COMPUTONE INTELLIPORT MULTIPORT CARD
-P:     Doug McNash
 P:     Michael H. Warfield
-M:     Doug McNash <dmcnash@computone.com>
 M:     Michael H. Warfield <mhw@wittsend.com>
 W:     http://www.computone.com/
 W:     http://www.wittsend.com/computone.html
index eb755f03ab8aa67fed990a2678144b2b635bcbaa..fe47f8706b6277d0c6d0ca1129ad08301b71516b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 20
-EXTRAVERSION = pre11
+EXTRAVERSION = pre12
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 6ec0e3d9c6a591af9632a2e18f935951ef04b383..f8a0e229ed54c5ffc755007cf9193420349ad6ee 100644 (file)
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion                   "2.2.10"
-#define DAC960_DriverDate                      "1 February 2001"
+#define DAC960_DriverVersion                   "2.2.11"
+#define DAC960_DriverDate                      "11 October 2001"
 
 
 #include <linux/version.h>
@@ -107,7 +107,7 @@ static PROC_DirectoryEntry_T
 */
 
 static NotifierBlock_T
-  DAC960_NotifierBlock =    { DAC960_Finalize, NULL, 0 };
+  DAC960_NotifierBlock =    { DAC960_Notifier, NULL, 0 };
 
 
 /*
@@ -277,7 +277,9 @@ static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command)
 
 /*
   DAC960_AllocateCommand allocates a Command structure from Controller's
-  free list.
+  free list.  During driver initialization, a special initialization command
+  has been placed on the free list to guarantee that command allocation can
+  never fail.
 */
 
 static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
@@ -487,6 +489,52 @@ static void DAC960_PD_QueueCommand(DAC960_Command_T *Command)
 }
 
 
+/*
+  DAC960_P_QueueCommand queues Command for DAC960 P Series Controllers.
+*/
+
+static void DAC960_P_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  switch (CommandMailbox->Common.CommandOpcode)
+    {
+    case DAC960_V1_Enquiry:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old;
+      break;
+    case DAC960_V1_GetDeviceState:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old;
+      break;
+    case DAC960_V1_Read:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_Write:
+      CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_ReadWithScatterGather:
+      CommandMailbox->Common.CommandOpcode =
+       DAC960_V1_ReadWithScatterGather_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    case DAC960_V1_WriteWithScatterGather:
+      CommandMailbox->Common.CommandOpcode =
+       DAC960_V1_WriteWithScatterGather_Old;
+      DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+      break;
+    default:
+      break;
+    }
+  while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+    udelay(1);
+  DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+  DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
 /*
   DAC960_ExecuteCommand executes Command and waits for completion.
 */
@@ -529,6 +577,32 @@ static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
 }
 
 
+/*
+  DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B
+  Command and waits for completion.  It returns true on success and false
+  on failure.
+*/
+
+static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
+                                      DAC960_V1_CommandOpcode_T CommandOpcode,
+                                      unsigned char CommandOpcode2,
+                                      void *DataPointer)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Type3B.CommandOpcode = CommandOpcode;
+  CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2;
+  CommandMailbox->Type3B.BusAddress = Virtual_to_Bus32(DataPointer);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V1_NormalCompletion);
+}
+
+
 /*
   DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
   Command and waits for completion.  It returns true on success and false
@@ -1063,7 +1137,17 @@ static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
     DAC1164P               5.06 and above
     DAC960PTL/PRL/PJ/PG            4.06 and above
     DAC960PU/PD/PL         3.51 and above
+    DAC960PU/PD/PL/P       2.73 and above
   */
+  if (Enquiry2.FirmwareID.MajorVersion == 0)
+    {
+      Enquiry2.FirmwareID.MajorVersion =
+       Controller->V1.Enquiry.MajorFirmwareVersion;
+      Enquiry2.FirmwareID.MinorVersion =
+       Controller->V1.Enquiry.MinorFirmwareVersion;
+      Enquiry2.FirmwareID.FirmwareType = '0';
+      Enquiry2.FirmwareID.TurnID = 0;
+    }
   sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
          Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
          Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
@@ -1072,7 +1156,9 @@ static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
        (Controller->FirmwareVersion[0] == '4' &&
         strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
        (Controller->FirmwareVersion[0] == '3' &&
-        strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
+        strcmp(Controller->FirmwareVersion, "3.51") >= 0) ||
+       (Controller->FirmwareVersion[0] == '2' &&
+        strcmp(Controller->FirmwareVersion, "2.73") >= 0)))
     {
       DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
       DAC960_Error("Firmware Version = '%s'\n", Controller,
@@ -1127,6 +1213,20 @@ static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
     default:
       return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
     }
+  /*
+    Initialize the Background Initialization Status.
+  */
+  if ((Controller->FirmwareVersion[0] == '4' &&
+      strcmp(Controller->FirmwareVersion, "4.08") >= 0) ||
+      (Controller->FirmwareVersion[0] == '5' &&
+       strcmp(Controller->FirmwareVersion, "5.08") >= 0))
+    {
+      Controller->V1.BackgroundInitializationStatusSupported = true;
+      DAC960_V1_ExecuteType3B(Controller,
+                             DAC960_V1_BackgroundInitializationControl, 0x20,
+                             &Controller->
+                              V1.LastBackgroundInitializationStatus);
+    }
   /*
     Initialize the Logical Drive Initially Accessible flag.
   */
@@ -1581,7 +1681,7 @@ static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
            DeviceState->DeviceType == DAC960_V1_DiskType)
          {
            if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
-             DAC960_Info("         Disk Status: %s, %d blocks, %d resets\n",
+             DAC960_Info("         Disk Status: %s, %u blocks, %d resets\n",
                          Controller,
                          (DeviceState->DeviceState == DAC960_V1_Device_Dead
                           ? "Dead"
@@ -1594,7 +1694,7 @@ static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
                          DeviceState->DiskSize,
                          Controller->V1.DeviceResetCount[Channel][TargetID]);
            else
-             DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+             DAC960_Info("         Disk Status: %s, %u blocks\n", Controller,
                          (DeviceState->DeviceState == DAC960_V1_Device_Dead
                           ? "Dead"
                           : DeviceState->DeviceState
@@ -1623,7 +1723,7 @@ static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
     {
       DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
        &Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
-      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n",
                  Controller, Controller->ControllerNumber, LogicalDriveNumber,
                  LogicalDriveInformation->RAIDLevel,
                  (LogicalDriveInformation->LogicalDriveState
@@ -1689,18 +1789,32 @@ static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
       if (PhysicalDeviceInfo->PhysicalDeviceState ==
          DAC960_V2_Device_Unconfigured)
        continue;
-      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+      DAC960_Info("         Disk Status: %s, %u blocks\n", Controller,
                  (PhysicalDeviceInfo->PhysicalDeviceState
                   == DAC960_V2_Device_Online
                   ? "Online"
                   : PhysicalDeviceInfo->PhysicalDeviceState
-                    == DAC960_V2_Device_WriteOnly
-                    ? "Write-Only"
+                    == DAC960_V2_Device_Rebuild
+                    ? "Rebuild"
                     : PhysicalDeviceInfo->PhysicalDeviceState
-                      == DAC960_V2_Device_Dead
-                      ? "Dead" : "Standby"),
-                 PhysicalDeviceInfo
-                 ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+                      == DAC960_V2_Device_Missing
+                      ? "Missing"
+                      : PhysicalDeviceInfo->PhysicalDeviceState
+                        == DAC960_V2_Device_Critical
+                        ? "Critical"
+                        : PhysicalDeviceInfo->PhysicalDeviceState
+                          == DAC960_V2_Device_Dead
+                          ? "Dead"
+                          : PhysicalDeviceInfo->PhysicalDeviceState
+                            == DAC960_V2_Device_SuspectedDead
+                            ? "Suspected-Dead"
+                            : PhysicalDeviceInfo->PhysicalDeviceState
+                              == DAC960_V2_Device_CommandedOffline
+                              ? "Commanded-Offline"
+                              : PhysicalDeviceInfo->PhysicalDeviceState
+                                == DAC960_V2_Device_Standby
+                                ? "Standby" : "Unknown"),
+                 PhysicalDeviceInfo->ConfigurableDeviceSize);
       if (PhysicalDeviceInfo->ParityErrors == 0 &&
          PhysicalDeviceInfo->SoftErrors == 0 &&
          PhysicalDeviceInfo->HardErrors == 0 &&
@@ -1742,7 +1856,7 @@ static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
                                            "-", "-", "-", "-" };
       unsigned char *GeometryTranslation;
       if (LogicalDeviceInfo == NULL) continue;
-      switch(LogicalDeviceInfo->DriveGeometry)
+      switch (LogicalDeviceInfo->DriveGeometry)
        {
        case DAC960_V2_Geometry_128_32:
          GeometryTranslation = "128/32";
@@ -1756,7 +1870,7 @@ static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
                       Controller, LogicalDeviceInfo->DriveGeometry);
          break;
        }
-      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks\n",
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %u blocks\n",
                  Controller, Controller->ControllerNumber, LogicalDriveNumber,
                  LogicalDeviceInfo->RAIDLevel,
                  (LogicalDeviceInfo->LogicalDeviceState
@@ -1765,7 +1879,7 @@ static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
                   : LogicalDeviceInfo->LogicalDeviceState
                     == DAC960_V2_LogicalDevice_Critical
                     ? "Critical" : "Offline"),
-                 LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+                 LogicalDeviceInfo->ConfigurableDeviceSize);
       DAC960_Info("                  Logical Device %s, BIOS Geometry: %s\n",
                  Controller,
                  (LogicalDeviceInfo->LogicalDeviceControl
@@ -1843,12 +1957,11 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
   blk_dev[MajorNumber].request_fn =
     RequestFunctions[Controller->ControllerNumber];
   /*
-    Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
-    array, Max Sectors per Request array, and Max Segments per Request array.
+    Initialize the Disk Partitions array, Partition Sizes array, Max Sectors
+    per Request array, and Max Segments per Request array.
   */
   for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
     {
-      Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
       Controller->MaxSectorsPerRequest[MinorNumber] =
        Controller->MaxBlocksPerCommand;
       Controller->MaxSegmentsPerRequest[MinorNumber] =
@@ -1871,8 +1984,8 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
   Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
   Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
   Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
-  Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
+  Controller->GenericDiskInfo.init = DAC960_ComputeGenericDiskInfo;
+  Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
   Controller->GenericDiskInfo.real_devices = Controller;
   Controller->GenericDiskInfo.next = NULL;
   /*
@@ -1935,35 +2048,65 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
 
 
 /*
-  DAC960_GenericDiskInit is the Generic Disk Information Initialization
-  Function for the DAC960 Driver.
+  DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk
+  Information Partition Sector Counts and Block Sizes.
 */
 
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
 {
   DAC960_Controller_T *Controller =
     (DAC960_Controller_T *) GenericDiskInfo->real_devices;
-  int LogicalDriveNumber;
+  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;
+       }
+      for (i = 0; i < DAC960_MaxPartitions; i++)
+       if (GenericDiskInfo->part[MinorNumber].nr_sects > 0)
+         Controller->BlockSizes[MinorNumber + i] = BLOCK_SIZE;
+       else Controller->BlockSizes[MinorNumber + i] = 0;
+    }
+}
+
+
+/*
+  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)
+{
   if (Controller->FirmwareType == DAC960_V1_Controller)
-    for (LogicalDriveNumber = 0;
-        LogicalDriveNumber < Controller->LogicalDriveCount;
-        LogicalDriveNumber++)
-      GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
-                     .nr_sects =
-       Controller->V1.LogicalDriveInformation
-                      [LogicalDriveNumber].LogicalDriveSize;
+    {
+      if (LogicalDriveNumber > Controller->LogicalDriveCount - 1) return;
+      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+    }
   else
-    for (LogicalDriveNumber = 0;
-        LogicalDriveNumber < DAC960_MaxLogicalDrives;
-        LogicalDriveNumber++)
-      {
-       DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
-         Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
-       if (LogicalDeviceInfo != NULL)
-         GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
-                         .nr_sects =
-           LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
-      }
+    {
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+       Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+      if (LogicalDeviceInfo == NULL) return;
+      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+    }
 }
 
 
@@ -2073,6 +2216,13 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
       InterruptHandler = DAC960_PD_InterruptHandler;
       MemoryWindowSize = DAC960_PD_RegisterWindowSize;
       break;
+    case DAC960_P_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_P;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_P_InterruptHandler;
+      MemoryWindowSize = DAC960_PD_RegisterWindowSize;
+      break;
     }
   while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
     {
@@ -2114,6 +2264,10 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
          IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
          PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
          break;
+       case DAC960_P_Controller:
+         IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+         PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+         break;
        }
       if (DAC960_ControllerCount == DAC960_MaxControllers)
        {
@@ -2309,6 +2463,32 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
          Controller->QueueReadWriteCommand =
            DAC960_V1_QueueReadWriteCommand;
          break;
+       case DAC960_P_Controller:
+         request_region(Controller->IO_Address, 0x80,
+                        Controller->FullModelName);
+         DAC960_PD_DisableInterrupts(BaseAddress);
+         DAC960_PD_AcknowledgeStatus(BaseAddress);
+         udelay(1000);
+         while (DAC960_PD_InitializationInProgressP(BaseAddress))
+           {
+             if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
+                                           &Parameter0, &Parameter1) &&
+                 DAC960_ReportErrorStatus(Controller, ErrorStatus,
+                                          Parameter0, Parameter1))
+               goto Failure;
+             udelay(10);
+           }
+         DAC960_PD_EnableInterrupts(Controller->BaseAddress);
+         Controller->QueueCommand = DAC960_P_QueueCommand;
+         Controller->ReadControllerConfiguration =
+           DAC960_V1_ReadControllerConfiguration;
+         Controller->ReadDeviceConfiguration =
+           DAC960_V1_ReadDeviceConfiguration;
+         Controller->ReportDeviceConfiguration =
+           DAC960_V1_ReportDeviceConfiguration;
+         Controller->QueueReadWriteCommand =
+           DAC960_V1_QueueReadWriteCommand;
+         break;
        }
       /*
        Acquire shared access to the IRQ Channel.
@@ -2480,7 +2660,7 @@ static void DAC960_FinalizeController(DAC960_Controller_T *Controller)
   DAC960_Initialize initializes the DAC960 Driver.
 */
 
-void DAC960_Initialize(void)
+int DAC960_Initialize(void)
 {
   int ControllerNumber;
   DAC960_DetectControllers(DAC960_BA_Controller);
@@ -2488,15 +2668,28 @@ void DAC960_Initialize(void)
   DAC960_DetectControllers(DAC960_LA_Controller);
   DAC960_DetectControllers(DAC960_PG_Controller);
   DAC960_DetectControllers(DAC960_PD_Controller);
+  DAC960_DetectControllers(DAC960_P_Controller);
   DAC960_SortControllers();
-  if (DAC960_ActiveControllerCount == 0) return;
+  if (DAC960_ActiveControllerCount == 0) return -ENODEV;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
-    if (DAC960_Controllers[ControllerNumber] != NULL)
-      DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
+    {
+      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+      int LogicalDriveNumber;
+      if (Controller == NULL) continue;
+      DAC960_InitializeController(Controller);
+      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+#ifdef MODULE
+      for (LogicalDriveNumber = 0;
+          LogicalDriveNumber < DAC960_MaxLogicalDrives;
+          LogicalDriveNumber++)
+       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
+#endif
+    }
   DAC960_CreateProcEntries();
   register_reboot_notifier(&DAC960_NotifierBlock);
+  return 0;
 }
 
 
@@ -2504,14 +2697,10 @@ void DAC960_Initialize(void)
   DAC960_Finalize finalizes the DAC960 Driver.
 */
 
-static int DAC960_Finalize(NotifierBlock_T *NotifierBlock,
-                          unsigned long Event,
-                          void *Buffer)
+static void DAC960_Finalize(void)
 {
   int ControllerNumber;
-  if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF))
-    return NOTIFY_DONE;
-  if (DAC960_ActiveControllerCount == 0) return NOTIFY_OK;
+  if (DAC960_ActiveControllerCount == 0) return;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
@@ -2519,6 +2708,20 @@ static int DAC960_Finalize(NotifierBlock_T *NotifierBlock,
       DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]);
   DAC960_DestroyProcEntries();
   unregister_reboot_notifier(&DAC960_NotifierBlock);
+}
+
+
+/*
+  DAC960_Notifier is the notifier for the DAC960 Driver.
+*/
+
+static int DAC960_Notifier(NotifierBlock_T *NotifierBlock,
+                          unsigned long Event,
+                          void *Buffer)
+{
+  if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF))
+    return NOTIFY_DONE;
+  DAC960_Finalize();
   return NOTIFY_OK;
 }
 
@@ -2552,11 +2755,9 @@ static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command)
       char *LastDataEndPointer = NULL;
       int SegmentNumber = 0;
       if (Command->CommandType == DAC960_ReadCommand)
-       CommandMailbox->Type5.CommandOpcode =
-         DAC960_V1_ReadWithOldScatterGather;
+       CommandMailbox->Type5.CommandOpcode = DAC960_V1_ReadWithScatterGather;
       else
-       CommandMailbox->Type5.CommandOpcode =
-         DAC960_V1_WriteWithOldScatterGather;
+       CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
@@ -2976,12 +3177,12 @@ static void DAC960_V1_ReadWriteError(DAC960_Command_T *Command)
                   Controller, Command->V1.CommandStatus, CommandName);
       break;
     }
-  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %u..%u\n",
               Controller, Controller->ControllerNumber,
               Command->LogicalDriveNumber, Command->BlockNumber,
               Command->BlockNumber + Command->BlockCount - 1);
   if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
-    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %u..%u\n",
                 Controller, Controller->ControllerNumber,
                 Command->LogicalDriveNumber,
                 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
@@ -3144,6 +3345,8 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
                                LogicalDriveNumber,
                                Controller->ControllerNumber,
                                LogicalDriveNumber);
+             Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
+             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
            }
          if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
            {
@@ -3154,8 +3357,9 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
                                LogicalDriveNumber,
                                Controller->ControllerNumber,
                                LogicalDriveNumber);
+             Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
+             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
            }
-         Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
          if (NewEnquiry->StatusFlags.DeferredWriteError !=
              OldEnquiry->StatusFlags.DeferredWriteError)
            DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -3181,6 +3385,8 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
              Controller->V1.NeedErrorTableInformation = true;
              Controller->V1.NeedDeviceStateInformation = true;
              Controller->V1.StartDeviceStateScan = true;
+             Controller->V1.NeedBackgroundInitializationStatus =
+               Controller->V1.BackgroundInitializationStatusSupported;
              Controller->SecondaryMonitoringTime = jiffies;
            }
          if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
@@ -3303,7 +3509,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
                           AdditionalSenseCodeQualifier == 0x02))))
                {
                  DAC960_Critical("Physical Device %d:%d Error Log: "
-                                 "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+                                 "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
                                  Controller,
                                  EventLogEntry->Channel,
                                  EventLogEntry->TargetID,
@@ -3513,6 +3719,77 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
              Controller->EphemeralProgressMessage = false;
            }
        }
+      else if (CommandOpcode == DAC960_V1_BackgroundInitializationControl)
+       {
+         unsigned int LogicalDriveNumber =
+           Controller->V1.BackgroundInitializationStatus.LogicalDriveNumber;
+         unsigned int LogicalDriveSize =
+           Controller->V1.BackgroundInitializationStatus.LogicalDriveSize;
+         unsigned int BlocksCompleted =
+           Controller->V1.BackgroundInitializationStatus.BlocksCompleted;
+         switch (CommandStatus)
+           {
+           case DAC960_V1_NormalCompletion:
+             switch (Controller->V1.BackgroundInitializationStatus.Status)
+               {
+               case DAC960_V1_BackgroundInitializationInvalid:
+                 break;
+               case DAC960_V1_BackgroundInitializationStarted:
+                 DAC960_Progress("Background Initialization Started\n",
+                                 Controller);
+                 break;
+               case DAC960_V1_BackgroundInitializationInProgress:
+                 if (BlocksCompleted ==
+                     Controller->V1.LastBackgroundInitializationStatus
+                                   .BlocksCompleted &&
+                     LogicalDriveNumber ==
+                     Controller->V1.LastBackgroundInitializationStatus
+                                   .LogicalDriveNumber)
+                   break;
+                 Controller->EphemeralProgressMessage = true;
+                 DAC960_Progress("Background Initialization in Progress: "
+                                 "Logical Drive %d (/dev/rd/c%dd%d) "
+                                 "%d%% completed\n",
+                                 Controller, LogicalDriveNumber,
+                                 Controller->ControllerNumber,
+                                 LogicalDriveNumber,
+                                 (100 * (BlocksCompleted >> 7))
+                                 / (LogicalDriveSize >> 7));
+                 Controller->EphemeralProgressMessage = false;
+                 break;
+               case DAC960_V1_BackgroundInitializationSuspended:
+                 DAC960_Progress("Background Initialization Suspended\n",
+                                 Controller);
+                 break;
+               case DAC960_V1_BackgroundInitializationCancelled:
+                 DAC960_Progress("Background Initialization Cancelled\n",
+                                 Controller);
+                 break;
+               }
+             memcpy(&Controller->V1.LastBackgroundInitializationStatus,
+                    &Controller->V1.BackgroundInitializationStatus,
+                    sizeof(DAC960_V1_BackgroundInitializationStatus_T));
+             break;
+           case DAC960_V1_BackgroundInitSuccessful:
+             if (Controller->V1.BackgroundInitializationStatus.Status ==
+                 DAC960_V1_BackgroundInitializationInProgress)
+               DAC960_Progress("Background Initialization "
+                               "Completed Successfully\n", Controller);
+             Controller->V1.BackgroundInitializationStatus.Status =
+               DAC960_V1_BackgroundInitializationInvalid;
+             break;
+           case DAC960_V1_BackgroundInitAborted:
+             if (Controller->V1.BackgroundInitializationStatus.Status ==
+                 DAC960_V1_BackgroundInitializationInProgress)
+               DAC960_Progress("Background Initialization Aborted\n",
+                               Controller);
+             Controller->V1.BackgroundInitializationStatus.Status =
+               DAC960_V1_BackgroundInitializationInvalid;
+             break;
+           case DAC960_V1_NoBackgroundInitInProgress:
+             break;
+           }
+       }
     }
   if (CommandType == DAC960_MonitoringCommand)
     {
@@ -3679,6 +3956,17 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
          DAC960_QueueCommand(Command);
          return;
        }
+      if (Controller->V1.NeedBackgroundInitializationStatus)
+       {
+         Controller->V1.NeedBackgroundInitializationStatus = false;
+         Command->V1.CommandMailbox.Type3B.CommandOpcode =
+           DAC960_V1_BackgroundInitializationControl;
+         Command->V1.CommandMailbox.Type3B.CommandOpcode2 = 0x20;
+         Command->V1.CommandMailbox.Type3B.BusAddress =
+           Virtual_to_Bus32(&Controller->V1.BackgroundInitializationStatus);
+         DAC960_QueueCommand(Command);
+         return;
+       }
       Controller->MonitoringTimerCount++;
       Controller->MonitoringTimer.expires =
        jiffies + DAC960_MonitoringTimerInterval;
@@ -3759,12 +4047,12 @@ static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command)
     }
   DAC960_Error("Error Condition %s on %s:\n", Controller,
               SenseErrors[Command->V2.RequestSense.SenseKey], CommandName);
-  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %u..%u\n",
               Controller, Controller->ControllerNumber,
               Command->LogicalDriveNumber, Command->BlockNumber,
               Command->BlockNumber + Command->BlockCount - 1);
   if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
-    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %u..%u\n",
                 Controller, Controller->ControllerNumber,
                 Command->LogicalDriveNumber,
                 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
@@ -3797,11 +4085,14 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
       { 0x000C, "S Offline" },
       { 0x000D, "P Found" },
-      { 0x000E, "P Gone" },
+      { 0x000E, "P Removed" },
       { 0x000F, "P Unconfigured" },
       { 0x0010, "P Expand Capacity Started" },
       { 0x0011, "P Expand Capacity Completed" },
       { 0x0012, "P Expand Capacity Failed" },
+      { 0x0013, "P Command Timed Out" },
+      { 0x0014, "P Command Aborted" },
+      { 0x0015, "P Command Retried" },
       { 0x0016, "P Parity Error" },
       { 0x0017, "P Soft Error" },
       { 0x0018, "P Miscellaneous Error" },
@@ -3832,6 +4123,8 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       { 0x0031, "P Failed because BDT Write Operation Failed" },
       { 0x0039, "P Missing at Startup" },
       { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
+      { 0x003C, "P Temporarily Offline Device Automatically Made Online" },
+      { 0x003D, "P Standby Rebuild Started" },
       /* Logical Device Events (0x0080 - 0x00FF) */
       { 0x0080, "M Consistency Check Started" },
       { 0x0081, "M Consistency Check Completed" },
@@ -3854,7 +4147,7 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       { 0x0092, "M Initialization Cancelled" },
       { 0x0093, "M Initialization Failed" },
       { 0x0094, "L Found" },
-      { 0x0095, "L Gone" },
+      { 0x0095, "L Deleted" },
       { 0x0096, "M Expand Capacity Started" },
       { 0x0097, "M Expand Capacity Completed" },
       { 0x0098, "M Expand Capacity Failed" },
@@ -3864,6 +4157,9 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       { 0x009C, "L Bad Data Block Found" },
       { 0x009E, "L Read of Data Block in BDT" },
       { 0x009F, "L Write Back Data for Disk Block Lost" },
+      { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" },
+      { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" },
+      { 0x00A2, "L Standby Rebuild Started" },
       /* Fault Management Events (0x0100 - 0x017F) */
       { 0x0140, "E Fan %d Failed" },
       { 0x0141, "E Fan %d OK" },
@@ -3871,24 +4167,31 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       { 0x0143, "E Power Supply %d Failed" },
       { 0x0144, "E Power Supply %d OK" },
       { 0x0145, "E Power Supply %d Not Present" },
-      { 0x0146, "E Temperature Sensor %d Failed" },
-      { 0x0147, "E Temperature Sensor %d Critical" },
-      { 0x0148, "E Temperature Sensor %d OK" },
+      { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" },
+      { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" },
+      { 0x0148, "E Temperature Sensor %d Temperature Normal" },
       { 0x0149, "E Temperature Sensor %d Not Present" },
-      { 0x014A, "E Unit %d Access Critical" },
-      { 0x014B, "E Unit %d Access OK" },
-      { 0x014C, "E Unit %d Access Offline" },
+      { 0x014A, "E Enclosure Management Unit %d Access Critical" },
+      { 0x014B, "E Enclosure Management Unit %d Access OK" },
+      { 0x014C, "E Enclosure Management Unit %d Access Offline" },
       /* Controller Events (0x0180 - 0x01FF) */
       { 0x0181, "C Cache Write Back Error" },
       { 0x0188, "C Battery Backup Unit Found" },
       { 0x0189, "C Battery Backup Unit Charge Level Low" },
       { 0x018A, "C Battery Backup Unit Charge Level OK" },
       { 0x0193, "C Installation Aborted" },
-      { 0x0195, "C Mirror Race Recovery In Progress" },
-      { 0x0196, "C Mirror Race on Critical Drive" },
-      { 0x019E, "C Memory Soft ECC Error" },
-      { 0x019F, "C Memory Hard ECC Error" },
+      { 0x0195, "C Battery Backup Unit Physically Removed" },
+      { 0x0196, "C Memory Error During Warm Boot" },
+      { 0x019E, "C Memory Soft ECC Error Corrected" },
+      { 0x019F, "C Memory Hard ECC Error Corrected" },
       { 0x01A2, "C Battery Backup Unit Failed" },
+      { 0x01AB, "C Mirror Race Recovery Failed" },
+      { 0x01AC, "C Mirror Race on Critical Drive" },
+      /* Controller Internal Processor Events */
+      { 0x0380, "C Internal Controller Hung" },
+      { 0x0381, "C Internal Controller Firmware Breakpoint" },
+      { 0x0390, "C Internal Controller i960 Processor Specific Error" },
+      { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" },
       { 0, "" } };
   int EventListIndex = 0, EventCode;
   unsigned char EventType, *EventMessage;
@@ -3938,7 +4241,7 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
       DAC960_Critical("Physical Device %d:%d %s\n", Controller,
                      Event->Channel, Event->TargetID, EventMessage);
       DAC960_Critical("Physical Device %d:%d Request Sense: "
-                     "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+                     "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
                      Controller,
                      Event->Channel,
                      Event->TargetID,
@@ -4265,22 +4568,34 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
            {
              if (NewPhysicalDeviceInfo->PhysicalDeviceState !=
                  PhysicalDeviceInfo->PhysicalDeviceState)
-               DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
-                               NewPhysicalDeviceInfo->Channel,
-                               NewPhysicalDeviceInfo->TargetID,
-                               (NewPhysicalDeviceInfo->PhysicalDeviceState
-                                == DAC960_V2_Device_Unconfigured
-                                ? "UNCONFIGURED"
-                                : NewPhysicalDeviceInfo->PhysicalDeviceState
-                                  == DAC960_V2_Device_Online
-                                  ? "ONLINE"
-                                  : NewPhysicalDeviceInfo->PhysicalDeviceState
-                                    == DAC960_V2_Device_WriteOnly
-                                    ? "WRITE-ONLY"
-                                    : NewPhysicalDeviceInfo
-                                      ->PhysicalDeviceState
-                                      == DAC960_V2_Device_Dead
-                                      ? "DEAD" : "STANDBY"));
+               DAC960_Critical(
+                 "Physical Device %d:%d is now %s\n", Controller,
+                 NewPhysicalDeviceInfo->Channel,
+                 NewPhysicalDeviceInfo->TargetID,
+                 (NewPhysicalDeviceInfo->PhysicalDeviceState
+                  == DAC960_V2_Device_Online
+                  ? "ONLINE"
+                  : NewPhysicalDeviceInfo->PhysicalDeviceState
+                    == DAC960_V2_Device_Rebuild
+                    ? "REBUILD"
+                    : NewPhysicalDeviceInfo->PhysicalDeviceState
+                      == DAC960_V2_Device_Missing
+                      ? "MISSING"
+                      : NewPhysicalDeviceInfo->PhysicalDeviceState
+                        == DAC960_V2_Device_Critical
+                        ? "CRITICAL"
+                        : NewPhysicalDeviceInfo->PhysicalDeviceState
+                          == DAC960_V2_Device_Dead
+                          ? "DEAD"
+                          : NewPhysicalDeviceInfo->PhysicalDeviceState
+                            == DAC960_V2_Device_SuspectedDead
+                            ? "SUSPECTED-DEAD"
+                            : NewPhysicalDeviceInfo->PhysicalDeviceState
+                              == DAC960_V2_Device_CommandedOffline
+                              ? "COMMANDED-OFFLINE"
+                              : NewPhysicalDeviceInfo->PhysicalDeviceState
+                                == DAC960_V2_Device_Standby
+                                ? "STANDBY" : "UNKNOWN"));
              if ((NewPhysicalDeviceInfo->ParityErrors !=
                   PhysicalDeviceInfo->ParityErrors) ||
                  (NewPhysicalDeviceInfo->SoftErrors !=
@@ -4386,13 +4701,16 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
                              (LogicalDeviceInfo != NULL
                               ? "" : " - Allocation Failed"));
              if (LogicalDeviceInfo != NULL)
-               memset(LogicalDeviceInfo, 0,
-                      sizeof(DAC960_V2_LogicalDeviceInfo_T));
+               {
+                 memset(LogicalDeviceInfo, 0,
+                        sizeof(DAC960_V2_LogicalDeviceInfo_T));
+                 DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+               }
            }
          if (LogicalDeviceInfo != NULL)
            {
              unsigned long LogicalDeviceSize =
-               NewLogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+               NewLogicalDeviceInfo->ConfigurableDeviceSize;
              if (NewLogicalDeviceInfo->LogicalDeviceState !=
                  LogicalDeviceInfo->LogicalDeviceState)
                DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -4503,6 +4821,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
              kfree(LogicalDeviceInfo);
              Controller->LogicalDriveInitiallyAccessible
                          [LogicalDriveNumber] = false;
+             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
            }
          Controller->V2.NeedLogicalDeviceInformation = false;
        }
@@ -4907,6 +5226,85 @@ static void DAC960_PD_InterruptHandler(int IRQ_Channel,
 }
 
 
+/*
+  DAC960_P_InterruptHandler handles hardware interrupts from DAC960 P Series
+  Controllers.
+*/
+
+static void DAC960_P_InterruptHandler(int IRQ_Channel,
+                                     void *DeviceIdentifier,
+                                     Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+       DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+      DAC960_V1_CommandOpcode_T CommandOpcode =
+       CommandMailbox->Common.CommandOpcode;
+      Command->V1.CommandStatus =
+       DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
+      switch (CommandOpcode)
+       {
+       case DAC960_V1_Enquiry_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Enquiry;
+         DAC960_P_To_PD_TranslateEnquiry(
+           Bus32_to_Virtual(CommandMailbox->Type3.BusAddress));
+         break;
+       case DAC960_V1_GetDeviceState_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode =
+           DAC960_V1_GetDeviceState;
+         DAC960_P_To_PD_TranslateDeviceState(
+           Bus32_to_Virtual(CommandMailbox->Type3.BusAddress));
+         break;
+       case DAC960_V1_Read_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Read;
+         DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+         break;
+       case DAC960_V1_Write_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Write;
+         DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+         break;
+       case DAC960_V1_ReadWithScatterGather_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode =
+           DAC960_V1_ReadWithScatterGather;
+         DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+         break;
+       case DAC960_V1_WriteWithScatterGather_Old:
+         Command->V1.CommandMailbox.Common.CommandOpcode =
+           DAC960_V1_WriteWithScatterGather;
+         DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
+         break;
+       default:
+         break;
+       }
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
 /*
   DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1
   Firmware Controllers.
@@ -5004,8 +5402,7 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
                Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
              if (LogicalDeviceInfo == NULL) continue;
              if (!LogicalDeviceInfo->LogicalDeviceControl
-                                    .LogicalDeviceInitialized &&
-                 Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 0)
+                                    .LogicalDeviceInitialized)
                {
                  ForceMonitoringCommand = true;
                  break;
@@ -5093,8 +5490,8 @@ static int DAC960_Open(Inode_T *Inode, File_T *File)
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
-      DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
-      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
   if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
     return -ENXIO;
@@ -5177,7 +5574,7 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
            Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
          if (LogicalDeviceInfo == NULL)
            return -EINVAL;
-         switch(LogicalDeviceInfo->DriveGeometry)
+         switch (LogicalDeviceInfo->DriveGeometry)
            {
            case DAC960_V2_Geometry_128_32:
              Geometry.heads = 128;
@@ -5193,7 +5590,7 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
              return -EINVAL;
            }
          Geometry.cylinders =
-           LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB
+           LogicalDeviceInfo->ConfigurableDeviceSize
            / (Geometry.heads * Geometry.sectors);
        }
       Geometry.start =
@@ -5202,10 +5599,10 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
                           sizeof(DiskGeometry_T)) ? -EFAULT : 0);
     case BLKGETSIZE:
       /* Get Device Size. */
-      if ((long *) Argument == NULL) return -EINVAL;
+      if ((unsigned long *) Argument == NULL) return -EINVAL;
       return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
                                                 .nr_sects,
-                     (long *) Argument);
+                     (unsigned long *) Argument);
     case BLKRAGET:
       /* Get Read-Ahead. */
       if ((int *) Argument == NULL) return -EINVAL;
@@ -5259,7 +5656,7 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
          */
          set_blocksize(Device, BLOCK_SIZE);
        }
-      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+      DAC960_RegisterDisk(Controller, LogicalDriveNumber);
       return 0;
     }
   return -EINVAL;
@@ -6491,6 +6888,43 @@ static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
                           == DAC960_V2_NormalCompletion
                           ? "Cancelled" : "Not Cancelled"));
     }
+  else if (strcmp(UserCommand, "perform-discovery") == 0)
+    {
+      CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Discovery %s\n", Controller,
+                         (Command->V2.CommandStatus
+                          == DAC960_V2_NormalCompletion
+                          ? "Initiated" : "Not Initiated"));
+      if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion)
+       {
+         CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+         CommandMailbox->ControllerInfo.CommandControlBits
+                                       .DataTransferControllerToHost = true;
+         CommandMailbox->ControllerInfo.CommandControlBits
+                                       .NoAutoRequestSense = true;
+         CommandMailbox->ControllerInfo.DataTransferSize =
+           sizeof(DAC960_V2_ControllerInfo_T);
+         CommandMailbox->ControllerInfo.ControllerNumber = 0;
+         CommandMailbox->ControllerInfo.IOCTL_Opcode =
+           DAC960_V2_GetControllerInfo;
+         CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+                                       .ScatterGatherSegments[0]
+                                       .SegmentDataPointer =
+           Virtual_to_Bus64(&Controller->V2.NewControllerInformation);
+         CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+                                       .ScatterGatherSegments[0]
+                                       .SegmentByteCount =
+           CommandMailbox->ControllerInfo.DataTransferSize;
+         DAC960_ExecuteCommand(Command);
+         while (Controller->V2.NewControllerInformation.PhysicalScanActive)
+           {
+             DAC960_ExecuteCommand(Command);
+             sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
+           }
+         DAC960_UserCritical("Discovery Completed\n", Controller);
+       }
+    }
   else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
     Controller->SuppressEnclosureMessages = true;
   else DAC960_UserCritical("Illegal User Command: '%s'\n",
@@ -6652,8 +7086,8 @@ static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer,
 
 
 /*
-  DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960
-  Driver.
+  DAC960_CreateProcEntries creates the /proc/rd/... entries for the
+  DAC960 Driver.
 */
 
 static void DAC960_CreateProcEntries(void)
@@ -6710,8 +7144,8 @@ static void DAC960_CreateProcEntries(void)
 
 
 /*
-  DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the DAC960
-  Driver.
+  DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the
+  DAC960 Driver.
 */
 
 static void DAC960_DestroyProcEntries(void)
@@ -6729,28 +7163,13 @@ static void DAC960_DestroyProcEntries(void)
 
 int init_module(void)
 {
-  int ControllerNumber, LogicalDriveNumber;
-  DAC960_Initialize();
-  if (DAC960_ActiveControllerCount == 0) return -1;
-  for (ControllerNumber = 0;
-       ControllerNumber < DAC960_ControllerCount;
-       ControllerNumber++)
-    {
-      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-      if (Controller == NULL) continue;
-      DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
-      for (LogicalDriveNumber = 0;
-          LogicalDriveNumber < Controller->LogicalDriveCount;
-          LogicalDriveNumber++)
-       resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
-    }
-  return 0;
+  return DAC960_Initialize();
 }
 
 
 void cleanup_module(void)
 {
-  DAC960_Finalize(&DAC960_NotifierBlock, SYS_RESTART, NULL);
+  DAC960_Finalize();
 }
 
 
index 35347bd37cecb0eb722f60808a5fdbf8263bc93d..b4364e8f6079d7f6541be408fb9a1865655aebdb 100644 (file)
@@ -224,9 +224,9 @@ typedef enum
   DAC960_V1_ReadExtendedWithScatterGather =    0xB3,
   DAC960_V1_WriteExtendedWithScatterGather =   0xB4,
   DAC960_V1_Read =                             0x36,
-  DAC960_V1_ReadWithOldScatterGather =         0xB6,
+  DAC960_V1_ReadWithScatterGather =            0xB6,
   DAC960_V1_Write =                            0x37,
-  DAC960_V1_WriteWithOldScatterGather =                0xB7,
+  DAC960_V1_WriteWithScatterGather =           0xB7,
   DAC960_V1_DCDB =                             0x04,
   DAC960_V1_DCDBWithScatterGather =            0x84,
   DAC960_V1_Flush =                            0x0A,
@@ -280,7 +280,14 @@ typedef enum
   DAC960_V1_RunDiagnostic =                    0x32,
   /* Subsystem Service Commands */
   DAC960_V1_GetSubsystemData =                 0x70,
-  DAC960_V1_SetSubsystemParameters =           0x71
+  DAC960_V1_SetSubsystemParameters =           0x71,
+  /* Version 2.xx Firmware Commands */
+  DAC960_V1_Enquiry_Old =                      0x05,
+  DAC960_V1_GetDeviceState_Old =               0x14,
+  DAC960_V1_Read_Old =                         0x02,
+  DAC960_V1_Write_Old =                                0x03,
+  DAC960_V1_ReadWithScatterGather_Old =                0x82,
+  DAC960_V1_WriteWithScatterGather_Old =       0x83
 }
 __attribute__ ((packed))
 DAC960_V1_CommandOpcode_T;
@@ -327,6 +334,9 @@ typedef unsigned char DAC960_V1_CommandIdentifier_T;
 #define DAC960_V1_RebuildFailed_NewDriveFailed 0x0004  /* Consistency */
 #define DAC960_V1_RebuildSuccessful            0x0100  /* Consistency */
 #define DAC960_V1_RebuildSuccessfullyTerminated        0x0107  /* Consistency */
+#define DAC960_V1_BackgroundInitSuccessful     0x0100  /* Consistency */
+#define DAC960_V1_BackgroundInitAborted                0x0005  /* Consistency */
+#define DAC960_V1_NoBackgroundInitInProgress   0x0105  /* Consistency */
 #define DAC960_V1_AddCapacityInProgress                0x0004  /* Consistency */
 #define DAC960_V1_AddCapacityFailedOrSuspended 0x00F4  /* Consistency */
 #define DAC960_V1_Config2ChecksumError         0x0002  /* Configuration */
@@ -634,6 +644,8 @@ DAC960_V1_PhysicalDeviceState_T;
 
 /*
   Define the DAC960 V1 Firmware Get Device State Command reply structure.
+  The structure is padded by 2 bytes for compatibility with Version 2.xx
+  Firmware.
 */
 
 typedef struct DAC960_V1_DeviceState
@@ -658,6 +670,7 @@ typedef struct DAC960_V1_DeviceState
   unsigned char SynchronousOffset:5;                   /* Byte 5 Bits 0-4 */
   unsigned char :3;                                    /* Byte 5 Bits 5-7 */
   unsigned int DiskSize __attribute__ ((packed));      /* Bytes 6-9 */
+  unsigned short :16;                                  /* Bytes 10-11 */
 }
 DAC960_V1_DeviceState_T;
 
@@ -675,6 +688,30 @@ typedef struct DAC960_V1_RebuildProgress
 DAC960_V1_RebuildProgress_T;
 
 
+/*
+  Define the DAC960 V1 Firmware Background Initialization Status Command
+  reply structure.
+*/
+
+typedef struct DAC960_V1_BackgroundInitializationStatus
+{
+  unsigned int LogicalDriveSize;                       /* Bytes 0-3 */
+  unsigned int BlocksCompleted;                                /* Bytes 4-7 */
+  unsigned char Reserved1[12];                         /* Bytes 8-19 */
+  unsigned int LogicalDriveNumber;                     /* Bytes 20-23 */
+  unsigned char RAIDLevel;                             /* Byte 24 */
+  enum {
+    DAC960_V1_BackgroundInitializationInvalid =            0x00,
+    DAC960_V1_BackgroundInitializationStarted =            0x02,
+    DAC960_V1_BackgroundInitializationInProgress =  0x04,
+    DAC960_V1_BackgroundInitializationSuspended =   0x05,
+    DAC960_V1_BackgroundInitializationCancelled =   0x06
+  } __attribute__ ((packed)) Status;                   /* Byte 25 */
+  unsigned char Reserved2[6];                          /* Bytes 26-31 */
+}
+DAC960_V1_BackgroundInitializationStatus_T;
+
+
 /*
   Define the DAC960 V1 Firmware Error Table Entry structure.
 */
@@ -850,6 +887,14 @@ typedef union DAC960_V1_CommandMailbox
     DAC960_BusAddress32_T BusAddress;                  /* Bytes 8-11 */
     unsigned char Dummy2[4];                           /* Bytes 12-15 */
   } __attribute__ ((packed)) Type3;
+  struct {
+    DAC960_V1_CommandOpcode_T CommandOpcode;           /* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;   /* Byte 1 */
+    unsigned char CommandOpcode2;                      /* Byte 2 */
+    unsigned char Dummy1[5];                           /* Bytes 3-7 */
+    DAC960_BusAddress32_T BusAddress;                  /* Bytes 8-11 */
+    unsigned char Dummy2[4];                           /* Bytes 12-15 */
+  } __attribute__ ((packed)) Type3B;
   struct {
     DAC960_V1_CommandOpcode_T CommandOpcode;           /* Byte 0 */
     DAC960_V1_CommandIdentifier_T CommandIdentifier;   /* Byte 1 */
@@ -956,6 +1001,7 @@ typedef enum
   DAC960_V2_GetPhysicalDeviceInfoValid =       0x05,
   DAC960_V2_GetHealthStatus =                  0x11,
   DAC960_V2_GetEvent =                         0x15,
+  DAC960_V2_StartDiscovery =                   0x81,
   DAC960_V2_SetDeviceState =                   0x82,
   DAC960_V2_RebuildDeviceStart =               0x88,
   DAC960_V2_RebuildDeviceStop =                        0x89,
@@ -982,7 +1028,10 @@ typedef unsigned short DAC960_V2_CommandIdentifier_T;
 
 #define DAC960_V2_NormalCompletion             0x00
 #define DAC960_V2_AbormalCompletion            0x02
+#define DAC960_V2_DeviceBusy                   0x08
 #define DAC960_V2_DeviceNonresponsive          0x0E
+#define DAC960_V2_DeviceNonresponsive2         0x0F
+#define DAC960_V2_DeviceRevervationConflict    0x18
 
 typedef unsigned char DAC960_V2_CommandStatus_T;
 
@@ -1056,7 +1105,8 @@ typedef struct DAC960_V2_ControllerInfo
     DAC960_V2_EXR2000P =                       0x1C,
     DAC960_V2_EXR3000P =                       0x1D,
     DAC960_V2_AcceleRAID352 =                  0x1E,
-    DAC960_V2_AcceleRAID351 =                  0x1F,
+    DAC960_V2_AcceleRAID170 =                  0x1F,
+    DAC960_V2_AcceleRAID160 =                  0x20,
     DAC960_V2_DAC960S =                                0x60,
     DAC960_V2_DAC960SU =                       0x61,
     DAC960_V2_DAC960SX =                       0x62,
@@ -1073,7 +1123,9 @@ typedef struct DAC960_V2_ControllerInfo
   unsigned char :8;                                    /* Byte 3 */
   unsigned short BusInterfaceSpeedMHz;                 /* Bytes 4-5 */
   unsigned char BusWidthBits;                          /* Byte 6 */
-  unsigned char Reserved1[9];                          /* Bytes 7-15 */
+  unsigned char FlashCodeTypeOrProductID;              /* Byte 7 */
+  unsigned char NumberOfHostPortsPresent;              /* Byte 8 */
+  unsigned char Reserved1[7];                          /* Bytes 9-15 */
   unsigned char BusInterfaceName[16];                  /* Bytes 16-31 */
   unsigned char ControllerName[16];                    /* Bytes 32-47 */
   unsigned char Reserved2[16];                         /* Bytes 48-63 */
@@ -1102,17 +1154,17 @@ typedef struct DAC960_V2_ControllerInfo
   unsigned char HardwareManufacturingMonth;            /* Byte 85 */
   unsigned char HardwareManufacturingYearHigh2Digits;  /* Byte 86 */
   unsigned char HardwareManufacturingYearLow2Digits;   /* Byte 87 */
-  unsigned char MaximumNumberOfPDDperXLDD;             /* Byte 88 */
-  unsigned char MaximumNumberOfILDDperXLDD;            /* Byte 89 */
+  unsigned char MaximumNumberOfPDDperXLD             /* Byte 88 */
+  unsigned char MaximumNumberOfILDperXLD;              /* Byte 89 */
   unsigned short NonvolatileMemorySizeKB;              /* Bytes 90-91 */
-  unsigned char MaximumNumberOfXLDD;                   /* Byte 92 */
+  unsigned char MaximumNumberOfXLD                   /* Byte 92 */
   unsigned int :24;                                    /* Bytes 93-95 */
   /* Unique Information per Controller */
   unsigned char ControllerSerialNumber[16];            /* Bytes 96-111 */
   unsigned char Reserved3[16];                         /* Bytes 112-127 */
   /* Vendor Information */
   unsigned int :24;                                    /* Bytes 128-130 */
-  unsigned char OEM_Information;                       /* Byte 131 */
+  unsigned char OEM_Code;                              /* Byte 131 */
   unsigned char VendorName[16];                                /* Bytes 132-147 */
   /* Other Physical/Controller/Operation Information */
   boolean BBU_Present:1;                               /* Byte 148 Bit 0 */
@@ -1193,12 +1245,14 @@ typedef struct DAC960_V2_ControllerInfo
   unsigned short PhysicalDeviceHostCommandAbortsDone;  /* Bytes 370-371 */
   unsigned short PhysicalDevicePredictedFailuresDetected; /* Bytes 372-373 */
   unsigned short PhysicalDeviceHostCommandsFailed;     /* Bytes 374-375 */
-  unsigned char Reserved9[8];                          /* Bytes 376-383 */
+  unsigned short PhysicalDeviceHardErrors;             /* Bytes 376-377 */
+  unsigned char Reserved9[6];                          /* Bytes 378-383 */
   /* Error Counters on Logical Devices */
   unsigned short LogicalDeviceSoftErrors;              /* Bytes 384-385 */
   unsigned short LogicalDeviceCommandsFailed;          /* Bytes 386-387 */
   unsigned short LogicalDeviceHostCommandAbortsDone;   /* Bytes 388-389 */
   unsigned short :16;                                  /* Bytes 390-391 */
+  /* Error Counters on Controller */
   unsigned short ControllerMemoryErrors;               /* Bytes 392-393 */
   unsigned short ControllerHostCommandAbortsDone;      /* Bytes 394-395 */
   unsigned int :32;                                    /* Bytes 396-399 */
@@ -1210,8 +1264,7 @@ typedef struct DAC960_V2_ControllerInfo
   unsigned short RebuildsActive;                       /* Bytes 408-409 */
   unsigned short OnlineExpansionsActive;               /* Bytes 410-411 */
   unsigned short PatrolActivitiesActive;               /* Bytes 412-413 */
-  unsigned char LongOperationStatus;                   /* Byte 414 */
-  unsigned char :8;                                    /* Byte 415 */
+  unsigned short :16;                                  /* Bytes 414-415 */
   /* Flash ROM Information */
   unsigned char FlashType;                             /* Byte 416 */
   unsigned char :8;                                    /* Byte 417 */
@@ -1234,8 +1287,7 @@ typedef struct DAC960_V2_ControllerInfo
   unsigned short NumberOfConfigurationGroups;          /* Bytes 474-475 */
   boolean InstallationAbortStatus:1;                   /* Byte 476 Bit 0 */
   boolean MaintenanceModeStatus:1;                     /* Byte 476 Bit 1 */
-  unsigned int :6;                                     /* Byte 476 Bits 2-7 */
-  unsigned int :24;                                    /* Bytes 477-479 */
+  unsigned int :24;                                    /* Bytes 476-479 */
   unsigned char Reserved10[32];                                /* Bytes 480-511 */
   unsigned char Reserved11[512];                       /* Bytes 512-1023 */
 }
@@ -1311,7 +1363,7 @@ typedef struct DAC960_V2_LogicalDeviceInfo
     DAC960_V2_Geometry_Reserved1 =             0x2,
     DAC960_V2_Geometry_Reserved2 =             0x3
   } __attribute__ ((packed)) DriveGeometry:2;          /* Byte 14 Bits 5-6 */
-  unsigned char :1;                                    /* Byte 14 Bit 7 */
+  boolean SuperReadAheadEnabled:1;                     /* Byte 14 Bit 7 */
   unsigned char :8;                                    /* Byte 15 */
   /* Error Counters */
   unsigned short SoftErrors;                           /* Bytes 16-17 */
@@ -1323,8 +1375,8 @@ typedef struct DAC960_V2_LogicalDeviceInfo
   /* Device Size Information */
   unsigned short :16;                                  /* Bytes 32-33 */
   unsigned short DeviceBlockSizeInBytes;               /* Bytes 34-35 */
-  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;  /* Bytes 36-39 */
-  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 40-43 */
+  unsigned int OriginalDeviceSize;                     /* Bytes 36-39 */
+  unsigned int ConfigurableDeviceSize;                 /* Bytes 40-43 */
   unsigned int :32;                                    /* Bytes 44-47 */
   unsigned char LogicalDeviceName[32];                 /* Bytes 48-79 */
   unsigned char SCSI_InquiryData[36];                  /* Bytes 80-115 */
@@ -1350,8 +1402,12 @@ typedef enum
 {
     DAC960_V2_Device_Unconfigured =            0x00,
     DAC960_V2_Device_Online =                  0x01,
-    DAC960_V2_Device_WriteOnly =               0x03,
+    DAC960_V2_Device_Rebuild =                 0x03,
+    DAC960_V2_Device_Missing =                 0x04,
+    DAC960_V2_Device_Critical =                        0x05,
     DAC960_V2_Device_Dead =                    0x08,
+    DAC960_V2_Device_SuspectedDead =           0x0C,
+    DAC960_V2_Device_CommandedOffline =                0x10,
     DAC960_V2_Device_Standby =                 0x21,
     DAC960_V2_Device_InvalidState =            0xFF
 }
@@ -1371,7 +1427,7 @@ typedef struct DAC960_V2_PhysicalDeviceInfo
   unsigned char LogicalUnit;                           /* Byte 3 */
   /* Configuration Status Bits */
   boolean PhysicalDeviceFaultTolerant:1;               /* Byte 4 Bit 0 */
-  boolean :1;                                          /* Byte 4 Bit 1 */
+  boolean PhysicalDeviceConnected:1;                   /* Byte 4 Bit 1 */
   boolean PhysicalDeviceLocalToController:1;           /* Byte 4 Bit 2 */
   unsigned char :5;                                    /* Byte 4 Bits 3-7 */
   /* Multiple Host/Controller Status Bits */
@@ -1407,15 +1463,15 @@ typedef struct DAC960_V2_PhysicalDeviceInfo
   unsigned int :32;                                    /* Bytes 44-47 */
   unsigned short :16;                                  /* Bytes 48-49 */
   unsigned short DeviceBlockSizeInBytes;               /* Bytes 50-51 */
-  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;  /* Bytes 52-55 */
-  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 56-59 */
+  unsigned int OriginalDeviceSize;                     /* Bytes 52-55 */
+  unsigned int ConfigurableDeviceSize;                 /* Bytes 56-59 */
   unsigned int :32;                                    /* Bytes 60-63 */
   unsigned char PhysicalDeviceName[16];                        /* Bytes 64-79 */
   unsigned char Reserved1[16];                         /* Bytes 80-95 */
   unsigned char Reserved2[32];                         /* Bytes 96-127 */
   unsigned char SCSI_InquiryData[36];                  /* Bytes 128-163 */
-  unsigned char Reserved3[12];                         /* Bytes 164-175 */
-  unsigned char Reserved4[16];                         /* Bytes 176-191 */
+  unsigned char Reserved3[20];                         /* Bytes 164-183 */
+  unsigned char Reserved4[8];                          /* Bytes 184-191 */
   DAC960_ByteCount64_T LastReadBlockNumber;            /* Bytes 192-199 */
   DAC960_ByteCount64_T LastWrittenBlockNumber;         /* Bytes 200-207 */
   DAC960_ByteCount64_T ConsistencyCheckBlockNumber;    /* Bytes 208-215 */
@@ -1549,7 +1605,8 @@ typedef enum
   DAC960_V2_RAID_Channel =                     0x03,
   DAC960_V2_Physical_Controller =              0x04,
   DAC960_V2_RAID_Controller =                  0x05,
-  DAC960_V2_Configuration_Group =              0x10
+  DAC960_V2_Configuration_Group =              0x10,
+  DAC960_V2_Enclosure =                                0x11
 }
 __attribute__ ((packed))
 DAC960_V2_OperationDevice_T;
@@ -1630,8 +1687,7 @@ typedef union DAC960_V2_CommandMailbox
     DAC960_V2_CommandIdentifier_T CommandIdentifier;   /* Bytes 0-1 */
     DAC960_V2_CommandOpcode_T CommandOpcode;           /* Byte 2 */
     DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
-    DAC960_ByteCount32_T DataTransferSize:24;          /* Bytes 4-6 */
-    unsigned char DataTransferPageNumber;              /* Byte 7 */
+    DAC960_ByteCount32_T DataTransferSize;             /* Bytes 4-7 */
     DAC960_BusAddress64_T RequestSenseBusAddress;      /* Bytes 8-15 */
     DAC960_V2_PhysicalDevice_T PhysicalDevice;         /* Bytes 16-18 */
     DAC960_V2_CommandTimeout_T CommandTimeout;         /* Byte 19 */
@@ -1645,8 +1701,7 @@ typedef union DAC960_V2_CommandMailbox
     DAC960_V2_CommandIdentifier_T CommandIdentifier;   /* Bytes 0-1 */
     DAC960_V2_CommandOpcode_T CommandOpcode;           /* Byte 2 */
     DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
-    DAC960_ByteCount32_T DataTransferSize:24;          /* Bytes 4-6 */
-    unsigned char DataTransferPageNumber;              /* Byte 7 */
+    DAC960_ByteCount32_T DataTransferSize;             /* Bytes 4-7 */
     DAC960_BusAddress64_T RequestSenseBusAddress;      /* Bytes 8-15 */
     DAC960_V2_PhysicalDevice_T PhysicalDevice;         /* Bytes 16-18 */
     DAC960_V2_CommandTimeout_T CommandTimeout;         /* Byte 19 */
@@ -1795,7 +1850,6 @@ typedef union DAC960_V2_CommandMailbox
       DataTransferMemoryAddress;                       /* Bytes 32-63 */
   } DeviceOperation;
 }
-__attribute__ ((packed))
 DAC960_V2_CommandMailbox_T;
 
 
@@ -2074,7 +2128,8 @@ typedef enum
   DAC960_LP_Controller =                       2,      /* AcceleRAID 352 */
   DAC960_LA_Controller =                       3,      /* DAC1164P */
   DAC960_PG_Controller =                       4,      /* DAC960PTL/PJ/PG */
-  DAC960_PD_Controller =                       5       /* DAC960PU/PD/PL */
+  DAC960_PD_Controller =                       5,      /* DAC960PU/PD/PL/P */
+  DAC960_P_Controller =                                6       /* DAC960PU/PD/PL/P */
 }
 DAC960_HardwareType_T;
 
@@ -2336,6 +2391,7 @@ typedef struct DAC960_Controller
       unsigned short DeviceStateChannel;
       unsigned short DeviceStateTargetID;
       boolean DualModeMemoryMailboxInterface;
+      boolean BackgroundInitializationStatusSupported;
       boolean SAFTE_EnclosureManagementEnabled;
       boolean NeedLogicalDriveInformation;
       boolean NeedErrorTableInformation;
@@ -2344,6 +2400,7 @@ typedef struct DAC960_Controller
       boolean NeedDeviceSerialNumberInformation;
       boolean NeedRebuildProgress;
       boolean NeedConsistencyCheckProgress;
+      boolean NeedBackgroundInitializationStatus;
       boolean StartDeviceStateScan;
       boolean RebuildProgressFirst;
       boolean RebuildFlagPending;
@@ -2367,6 +2424,10 @@ typedef struct DAC960_Controller
       DAC960_V1_CommandStatus_T PendingRebuildStatus;
       DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation;
       DAC960_V1_LogicalDriveInformationArray_T NewLogicalDriveInformation;
+      DAC960_V1_BackgroundInitializationStatus_T
+        BackgroundInitializationStatus;
+      DAC960_V1_BackgroundInitializationStatus_T
+        LastBackgroundInitializationStatus;
       DAC960_V1_DeviceState_T
        DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
       DAC960_V1_DeviceState_T NewDeviceState;
@@ -4144,13 +4205,46 @@ DAC960_PD_ReadErrorStatus(void *ControllerBaseAddress,
   return true;
 }
 
+static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry)
+{
+  memcpy(Enquiry + 132, Enquiry + 36, 64);
+  memset(Enquiry + 36, 0, 96);
+}
+
+static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState)
+{
+  memcpy(DeviceState + 2, DeviceState + 3, 1);
+  memcpy(DeviceState + 4, DeviceState + 5, 2);
+  memcpy(DeviceState + 6, DeviceState + 8, 4);
+}
+
+static inline
+void DAC960_PD_To_P_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
+                                             *CommandMailbox)
+{
+  int LogicalDriveNumber = CommandMailbox->Type5.LD.LogicalDriveNumber;
+  CommandMailbox->Bytes[3] &= 0x7;
+  CommandMailbox->Bytes[3] |= CommandMailbox->Bytes[7] << 6;
+  CommandMailbox->Bytes[7] = LogicalDriveNumber;
+}
+
+static inline
+void DAC960_P_To_PD_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
+                                             *CommandMailbox)
+{
+  int LogicalDriveNumber = CommandMailbox->Bytes[7];
+  CommandMailbox->Bytes[7] = CommandMailbox->Bytes[3] >> 6;
+  CommandMailbox->Bytes[3] &= 0x7;
+  CommandMailbox->Bytes[3] |= LogicalDriveNumber << 3;
+}
+
 
 /*
   Define prototypes for the forward referenced DAC960 Driver Internal Functions.
 */
 
 static void DAC960_FinalizeController(DAC960_Controller_T *);
-static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *);
+static int DAC960_Notifier(NotifierBlock_T *, unsigned long, void *);
 static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_RequestFunction0(void);
@@ -4166,6 +4260,7 @@ static void DAC960_LP_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_LA_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_PG_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_PD_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_P_InterruptHandler(int, void *, Registers_T *);
 static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_MonitoringTimerFunction(unsigned long);
@@ -4173,7 +4268,7 @@ static int DAC960_Open(Inode_T *, File_T *);
 static int DAC960_Release(Inode_T *, File_T *);
 static int DAC960_IOCTL(Inode_T *, File_T *, unsigned int, unsigned long);
 static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long);
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
+static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo);
 static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *,
                           DAC960_Controller_T *, ...);
 static void DAC960_CreateProcEntries(void);
index f7cd6e1f3d3f650be9424b616c92ffe74a72198c..d4d3f13b3a083cd1a0c1ffd95e91a2b10f29a720 100644 (file)
-
 Computone Intelliport II/Plus Multiport Serial Driver
 -----------------------------------------------------
 
-Release Notes For Linux Kernel 2.2
-These notes have been tested on Linux kernels 2.0 and 2.2.
-
-Please refer to Documentation/computone.txt for information on the driver
-that is included with the kernel sources.
-
-
-Version: 1.2.9
-Date: 04/12/2000
-Fixes and Updates: Doug McNash 
-Historical Author: Andrew Manison 
-Kernel Integration: Mike Warfield <mhw@wittsend.com>
-
-1. INTRODUCTION
-
-This driver supports the entire family of Intelliport II/Plus controllers
-with the exception of the MicroChannel controllers. 
-
-This driver was developed on the v2.0.x Linux source tree and has been 
-tested up to v2.2.14; it will probably not work with earlier v1.X kernels, 
-and has not yet been tested on the v2.1.x tree. The most likely problems 
-will be in patching the kernel sources to support the driver. For this
-reason there are 2 different patch files for 2.0.XX and 2.2.XX kernels.
-Make sure you use the right one!
-Note that a version (1.2.5) is included in the 2.2.12+ kernels so this
-will not be a new install but and upgrade.
-
-
-2. QUICK INSTALLATION
-
-Hardware - If you have an ISA card, find a free interrupt and io port. 
-                  List those in use with `cat /proc/interrupts` and 
-                  `cat /proc/ioports`.  Set the card dip switches to that free 
-                  address.  You may need to configure your BIOS to reserve the
-                  irq for the ISA card.  PCI and EISA parameters are set
-                  automagically and need only be set to nonzero values.
-                  Insert card into computer with the power off before or after
-                  driver installation.
-
-Software - New Installation
-
-Module installation:
-
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (m) module for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI and CONFIG_MODULES also may need to be set.
-e) Set address on ISA cards then:
-   edit /usr/src/linux/drivers/char/ip2/ip2.h if needed 
-       or
-   edit /etc/conf.modules (or /etc/modules.conf) if needed (module).
-       or both to match this setting.
-f) Run "make dep"
-g) Run "make modules"
-h) Run "make modules_install"
-i) Run "/sbin/depmod -a"
-i) install driver using `modprobe ip2 <options>` (options listed below)
-j) run mkip2dev
-
-
-Kernel installation:
-
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (y) kernel for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI may need to be set if you have PCI bus.
-e) Set address on ISA cards then:
-          edit /usr/src/linux/drivers/char/ip2/ip2.h  
-f) Run "make dep"
-g) Run "make zImage" or whatever target you prefer.
-h) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
-i) add new config for this kernel into /etc/lilo.conf, run "lilo"
-j) reboot using this kernel
-k) make and run ip2/mkip2dev
-
-Software - Upgrades
-
-a) Install new sources in proper location, usually /usr/src/linux/drivers/char
-b) Follow steps above to create new kernel or modules
-
-3. INSTALLATION
-
-Previously, the driver sources were packaged with a set of patch files
-to update the character drivers' makefile and configuration file, and other 
-kernel source files. A build script (ip2build) was included which applies 
-the patches if needed, and build any utilities needed.
-What you receive may be a single patch file in conventional kernel
-patch format build script. That form can also be applied by
-running patch -p1 < ThePatchFile.  Otherwise the drivers source may be
-a tar file, then untar and run ip2build if a new installation.
-The driver can be installed as a module (recommended) or built into the 
-kernel. This is selected as for other drivers through the `make config`
-command from the root of the Linux source tree. If the driver is built 
-into the kernel you will need to edit the file ip2.h to match the boards 
-you are installing. See that file for instructions. If the driver is 
-installed as a module the configuration can also be specified on the
-modprobe command line as follows:
-
-       modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
-
-where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
-12,15) and addr1-4 are the base addresses for up to four controllers. If 
-the irqs are not specified the driver uses the default in ip2/ip2.h (which 
-selects polled mode). The io addresses are set to io=1 for PCI cards,i
-io=2 for EISA cards or io=[some valid ISA address] for ISA cards.  If no
-base addresses are specified the defaults in ip2.h are used. If you are
-autoloading the driver module with kerneld or kmod the base addresses and
-interrupt number must also be set in ip2/ip2.h and recompile or just insert
-an options line in /etc/modules.conf or both.  The command line takes
-precidence over the options line which takes precidence over the defaults
-in ip2.h. 
-
-command line sample:
-       
-       modprobe ip2 io=1,0x328 irq=1,10
-
-/etc/modules.conf sample:
-
-       options ip2 io=1,0x328 irq=1,10
-       alias char-major-71 ip2
-       alias char-major-72 ip2
-       alias char-major-73 ip2
-
-the equivelant ip2.h:
-
-static ip2config_t ip2config =
-{
-       {1,10,0,0},
-       {
-               0x0001,    // Board 0, ttyF0   - ttyF63         /* PCI card */
-               0x0328,    // Board 1, ttyF64  - ttyF127        /* ISA card */
-               0x0000,    // Board 2, ttyF128 - ttyF191        /* empty */
-               0x0000     // Board 3, ttyF192 - ttyF255        /* empty */
-       }
-};
-
-Specifying an invalid or in-use ISA irq will default the driver into
-running in polled mode for that card.  If all irq entries are 0 then
-all cards will operate in polled mode.  Note that the PCI will be
-assigned it's irq by the BIOS and may not match what you specify.
-It must be non-zero otherwise it will be polled.
-
-Tarball Install:
-
-The whole tarfile should be untarred in the /usr/src/linux/drivers/char/
-directory. Most files required for the driver are placed in the ip2
-subdirectory. Then execute the script (for a new install only)
-
-       ip2build
-
-which will patch the files.
-
-Kernel Patch Install:
-
-       cd to the Linux source root, run patch -p1 < ThePatchFile. 
-
-Now return to the root directory of the Linux
-source tree and run make config or make menuconfig. You will be prompted
-for the Computone drivers, either as a module or part of the kernel. 
-If you have a PCI card you many need to select PCI bios support (CONFIG_PCI)
-if not enabled already.  Ditto for CONFIG_MODULES if you use modules.
-
-If you select the driver as part of the kernel run :
-
-       make depend
-       make bzImage(,zlilo or whatever you do to create a bootable kernel)
-
-If you selected a module run :
-
-       make modules && make modules_install
-
-The utility ip2mkdev creates all the device nodes required by the driver.
-For a device to be created it must be configured in the driver and the 
-board must be installed. Only devices corresponding to real IntelliPort II 
-ports are created. With multiple boards and expansion boxes this will 
-leave gaps in the sequence of device names. ip2mkdev uses Linux tty naming 
-conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for 
-callout devices.  Note that the callout devices are going away in the
-future and that is what the warning messages are trying to tell you.
-
-4. USING THE DRIVERS
-
-As noted above, the driver implements the ports in accordance with Linux
-conventions, and the devices should be interchangeable with the standard
-serial devices. (This is a key point for problem reporting: please make
-sure that what you are trying do works on the ttySx/cuax ports first; then 
-tell us what went wrong with the ip2 ports!)
-
-Higher speeds can be obtained using the setserial utility which remaps 
-38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. 
-Intelliport II installations using the PowerPort expansion module can
-use the custom speed setting to select the highest speeds: 153,600 bps,
-230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
-custom baud rate configuration is fixed at 921,600 for cards/expantion
-modules with ST654's and 115200 for those with Cirrus CD1400's.  This
-corresponds to the maximum bit rates those chips are capable.  
-For example if the baud base is 921600 and the baud divisor is 18 then
-the custom rate is 921600/18 = 51200 bps.  See the setserial man page for
-complete details. Of course, if stty accepts the higher rates now you can
-use that as well as the standard ioctls().
-
-5. NOTES
-
-This is a release version of the driver, but it is impossible to test it
-in all configurations of Linux. If there is any anomalous behaviour that 
-does not match the standard serial port's behaviour please let us know.
-
-Some installations report that characters fail to echo immediatly at a
-terminal if the kernel/modules are compiled with the CONFIG_M386 and
-the card is run in polling mode on a pentium class machine.  Compiling
-with a more appropriate processor flag or running on interrupt would be
-the fix as well as the wise thing to do.
+Release Notes For Linux Kernel 2.2 and higher
 
+This file is now deprecated and will be removed at some point.
 
+Please refer to the file Documentation/computone.txt instead.
 
-Author:  dougm@computone.com
-Testing: larryg@computone.com
-Support: support@computone.com
+Michael H. Warfield 08/12/2001
index 9d8b8f0b7da7ebe5e21fc830998b0bda583d7136..ab174b4fb82bb7904bafdb8ab229fc994ff901de 100644 (file)
 int
 ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 
+/* Note: Add compiled in defaults to these arrays, not to the structure
+       in ip2/ip2.h any longer.  That structure WILL get overridden
+       by these values, or command line values, or insmod values!!!  =mhw=
+*/
+static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
+static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
+static int poll_only = 0;
 #ifdef MODULE
-
 #include <linux/autoconf.h>
 #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
 #      define MODVERSIONS
@@ -38,9 +45,6 @@ ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 #      include <linux/modversions.h>
 #endif
 
-static int io[IP2_MAX_BOARDS]= { 0,};
-static int irq[IP2_MAX_BOARDS] = { 0,}; 
-
 #      if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
                MODULE_AUTHOR("Doug McNash");
                MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
@@ -48,6 +52,8 @@ static int irq[IP2_MAX_BOARDS] = { 0,};
                MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
                MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
                MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
+               MODULE_PARM(poll_only,"1i");
+               MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
 #      endif   /* LINUX_VERSION */
 
 
@@ -59,6 +65,11 @@ init_module(void)
 
        MOD_INC_USE_COUNT;      // hold till done 
                
+       if( poll_only ) {
+               /* Hard lock the interrupts to zero */
+               irq[0] = irq[1] = irq[2] = irq[3] = 0;
+       }
+
        rc = ip2_loadmain(io,irq,(unsigned char *)fip_firm,sizeof(fip_firm));
        // The call to lock and load main, create dep 
 
@@ -70,7 +81,7 @@ init_module(void)
 int
 ip2_init(void)
 {
-       // call to this is int tty_io.c so we need this
+       // call to this is in tty_io.c so we need this
        return 0;
 }
 
@@ -86,9 +97,66 @@ cleanup_module(void)
 # define NULL          ((void *) 0)
 #endif
 
+/******************************************************************************
+ *     ip2_setup:
+ *             str: kernel command line string
+ *
+ *     Can't autoprobe the boards so user must specify configuration on
+ *     kernel command line.  Sane people build it modular but the others
+ *     come here.
+ *
+ *     Alternating pairs of io,irq for up to 4 boards.
+ *             ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+ *
+ *             io=0 => No board
+ *             io=1 => PCI
+ *             io=2 => EISA
+ *             else => ISA I/O address
+ *
+ *             irq=0 or invalid for ISA will revert to polling mode
+ *
+ *             Any value = -1, do not overwrite compiled in value.
+ *
+ ******************************************************************************/
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
+void __init ip2_setup(char *str)
+{
+       int     ints[10];       /* 4 boards, 2 parameters + 2 */
+       int     i, j;
+
+       str = get_options (str, ARRAY_SIZE(ints), ints);
+#else
+void __init ip2_setup(char *str, int *ints)
+{
+       int     i, j;
+#endif
+
+       for( i = 0, j = 1; i < 4; i++ ) {
+               if( j > ints[0] ) {
+                       break;
+               }
+               if( ints[j] >= 0 ) {
+                       io[i] = ints[j];
+               }
+               j++;
+               if( j > ints[0] ) {
+                       break;
+               }
+               if( ints[j] >= 0 ) {
+                       irq[i] = ints[j];
+               }
+               j++;
+       }
+}
+
 int
 ip2_init(void) {
-       return ip2_loadmain(NULL,NULL,(unsigned char *)fip_firm,sizeof(fip_firm));
+       return ip2_loadmain(io,irq,(unsigned char *)fip_firm,sizeof(fip_firm));
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13))
+__setup("ip2=", ip2_setup);
+__initcall(ip2_init);
+#endif
+
 #endif /* !MODULE */
index 3717630eb199530d20ac9fa11fb5b94db78f6910..8d29dd44bfdb9b9dd3511fa46b02220a042835b0 100644 (file)
@@ -552,6 +552,9 @@ iiInitialize(i2eBordStrPtr pB)
 
        pB->i2eStartMail = iiGetMail(pB);
 
+       // Throw it away and clear the mailbox structure element
+       pB->i2eStartMail = NO_MAIL_HERE;
+
        // Everything is ok now, return with good status/
 
        pB->i2eValid = I2E_MAGIC;
@@ -592,14 +595,27 @@ ii2DelayWakeup(unsigned long id)
 static void
 ii2DelayTimer(unsigned int mseconds)
 {
+       wait_queue_t wait;
+
+       init_waitqueue_entry(&wait, current);
+
        init_timer ( pDelayTimer );
 
+       add_wait_queue(&pDelayWait, &wait);
+
+       set_current_state( TASK_INTERRUPTIBLE );
+
        pDelayTimer->expires  = jiffies + ( mseconds + 9 ) / 10;
        pDelayTimer->function = ii2DelayWakeup;
        pDelayTimer->data     = 0;
 
        add_timer ( pDelayTimer );
-       interruptible_sleep_on ( &pDelayWait );
+
+       schedule();
+
+       set_current_state( TASK_RUNNING );
+       remove_wait_queue(&pDelayWait, &wait);
+
        del_timer ( pDelayTimer );
 }
 
index 2b54571fc3cb29cd4eff0fb84daef3d0f51deb2f..f36c32d821f44afb05717123aba6bdbe67c8eccd 100644 (file)
@@ -399,6 +399,12 @@ typedef struct _i2eBordStr
        spinlock_t      read_fifo_spinlock;
        spinlock_t      write_fifo_spinlock;
 
+//     For queuing interupt bottom half handlers.      /\/\|=mhw=|\/\/
+       struct tq_struct        tqueue_interrupt;
+
+       struct timer_list  SendPendingTimer;   // Used by iiSendPending
+       unsigned int    SendPendingRetry;
+
 #ifdef CONFIG_DEVFS_FS
        /* Device handles into devfs */
        devfs_handle_t  devfs_ipl_handle;
index 3e566f083e563a2294dd2e23ae071d89fd7296a2..86051cc131c3d65fdd6dbf25bb2ef7aaa0b11e42 100644 (file)
@@ -174,6 +174,25 @@ iiSendPendingMail(i2eBordStrPtr pB)
                        pB->i2eWaitingForEmptyFifo |=
                                (pB->i2eOutMailWaiting & MB_OUT_STUFFED);
                        pB->i2eOutMailWaiting = 0;
+                       pB->SendPendingRetry = 0;
+               } else {
+/*             The only time we hit this area is when "iiTrySendMail" has
+               failed.  That only occurs when the outbound mailbox is
+               still busy with the last message.  We take a short breather
+               to let the board catch up with itself and then try again.
+               16 Retries is the limit - then we got a borked board.
+                       /\/\|=mhw=|\/\/                         */
+
+                       if( ++pB->SendPendingRetry < 16 ) {
+
+                               init_timer( &(pB->SendPendingTimer) );
+                               pB->SendPendingTimer.expires  = jiffies + 1;
+                               pB->SendPendingTimer.function = (void*)(unsigned long)iiSendPendingMail;
+                               pB->SendPendingTimer.data     = (unsigned long)pB;
+                               add_timer( &(pB->SendPendingTimer) );
+                       } else {
+                               printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" );
+                       }
                }
        }
 }
@@ -225,6 +244,8 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
        pB->i2Dbuf_strip = pB->i2Dbuf_stuff = 0;
        pB->i2Bbuf_strip = pB->i2Bbuf_stuff = 0;
 
+       pB->SendPendingRetry = 0;
+
        memset ( pCh, 0, sizeof (i2ChanStr) * nChannels );
 
        for (index = stuffIndex = 0, ppCh = (i2ChanStrPtr *)(pB->i2Fbuf);
@@ -311,13 +332,11 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
                pCh->ClosingDelay     = 5*HZ/10;
                pCh->ClosingWaitTime  = 30*HZ;
 
-#ifdef USE_IQ
                // Initialize task queue objects
                pCh->tqueue_input.routine = (void(*)(void*)) do_input;
                pCh->tqueue_input.data = pCh;
                pCh->tqueue_status.routine = (void(*)(void*)) do_status;
                pCh->tqueue_status.data = pCh;
-#endif
 
                pCh->trace = ip2trace;
 
@@ -1296,6 +1315,7 @@ i2DrainWakeup(i2ChanStrPtr pCh)
 static void
 i2DrainOutput(i2ChanStrPtr pCh, int timeout)
 {
+       wait_queue_t wait;
        i2eBordStrPtr pB;
 
 #ifdef IP2DEBUG_TRACE
@@ -1325,9 +1345,18 @@ i2DrainOutput(i2ChanStrPtr pCh, int timeout)
        }
        
        i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ );
+
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&(pCh->pBookmarkWait), &wait);
+       set_current_state( TASK_INTERRUPTIBLE );
+
        serviceOutgoingFifo( pB );
        
-       interruptible_sleep_on( &(pCh->pBookmarkWait) );
+       schedule();     // Now we take our interruptible sleep on
+
+       // Clean up the queue
+       set_current_state( TASK_RUNNING );
+       remove_wait_queue(&(pCh->pBookmarkWait), &wait);
 
        // if expires == 0 then timer poped, then do not need to del_timer
        if ((timeout > 0) && pCh->BookmarkTimer.expires && 
@@ -2215,7 +2244,11 @@ i2ServiceBoard ( i2eBordStrPtr pB )
        unsigned long flags;
 
 
-       inmail = iiGetMail(pB);
+       /* This should be atomic because of the way we are called... */
+       if (NO_MAIL_HERE == ( inmail = pB->i2eStartMail ) ) {
+               inmail = iiGetMail(pB);
+       }
+       pB->i2eStartMail = NO_MAIL_HERE;
 
 #ifdef IP2DEBUG_TRACE
        ip2trace (ITRC_NO_PORT, ITRC_INTR, 2, 1, inmail );
index 7236744b024510b6657345dd9a2adac7965e2a43..ec7e22010c823a92c9a59f79b75adf2685a6ed8f 100644 (file)
   * /etc/modules.conf or /etc/conf.modules and load with modprobe, kerneld or
   * kmod, the kernel module loader
   */
+
+ /* This structure is NOW always initialized when the driver is initialized.
+  * Compiled in defaults MUST be added to the io and irq arrays in
+  * ip2.c.  Those values are configurable from insmod parameters in the
+  * case of modules or from command line parameters (ip2=io,irq) when
+  * compiled in.
+  */
+
 static ip2config_t ip2config =
 {
        {0,0,0,0},              // irqs
        {                               // Addresses
+       /* Do NOT set compile time defaults HERE!  Use the arrays in
+               ip2.c!  These WILL be overwritten!  =mhw= */
                0x0000,         // Board 0, ttyF0   - ttyF63
                0x0000,         // Board 1, ttyF64  - ttyF127
                0x0000,         // Board 2, ttyF128 - ttyF191
index 8cd9636c1aa1f072a7ae2c403f7ffb3579c796f7..86834cdd5dc3308b312eb11b92653c085956ce19 100644 (file)
 //
 // Done:
 //
+// 1.2.11      /\/\|=mhw=|\/\/
+// Clean up potential NULL pointer dereferences
+// Clean up devfs registration
+// Add kernel command line parsing for io and irq
+//     Compile defaults for io and irq are now set in ip2.c not ip2/ip2.h!
+// Reworked poll_only hack for explicit parameter setting
+//     You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
+// Merged ip2_loadmain and old_ip2_init
+// Converted all instances of interruptible_sleep_on into queue calls
+//     Most of these had no race conditions but better to clean up now
+//
+// 1.2.10      /\/\|=mhw=|\/\/
+// Fixed the bottom half interrupt handler and enabled USE_IQI
+//     to split the interrupt handler into a formal top-half / bottom-half
+// Fixed timing window on high speed processors that queued messages to
+//     the outbound mail fifo faster than the board could handle.
+//
 // 1.2.9
 // Four box EX was barfing on >128k kmalloc, made structure smaller by
 // reducing output buffer size
@@ -213,7 +230,7 @@ struct proc_dir_entry ip2_proc_entry = {
 
 /* String constants to identify ourselves */
 static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.9";
+static char *pcVersion = "1.2.11";
 
 /* String constants for port names */
 static char *pcDriver_name   = "ip2";
@@ -245,8 +262,6 @@ int init_module(void);
 void cleanup_module(void);
 #endif
 
-int old_ip2_init(void);
-
 /* Private (static) functions */
 static int  ip2_open(PTTY, struct file *);
 static void ip2_close(PTTY, struct file *);
@@ -266,6 +281,7 @@ static void ip2_start(PTTY);
 static void ip2_hangup(PTTY);
 
 static void set_irq(int, int);
+static void ip2_interrupt_bh(i2eBordStrPtr pB);
 static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static void ip2_poll(unsigned long arg);
 static inline void service_all_boards(void);
@@ -340,11 +356,11 @@ ip2_ipl = {
        /* NULL, NULL 2.2 */
 }; 
 
-static long irq_counter = 0;
-static long bh_counter = 0;
+static unsigned long irq_counter = 0;
+static unsigned long bh_counter = 0;
 
 // Use immediate queue to service interrupts
-//#define USE_IQI      // PCI&2.2 needs work
+#define USE_IQI
 //#define USE_IQ       // PCI&2.2 needs work
 
 /* The timer_list entry for our poll routine. If interrupt operation is not
@@ -404,32 +420,6 @@ static int iindx = 0;
 static char rirqs[IP2_MAX_BOARDS] = {0,};
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
-/******************************************************************************/
-/* Initialisation Section                                                     */
-/******************************************************************************/
-int 
-ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) 
-{
-       int i;
-       /* process command line arguments to modprobe or insmod i.e. iop & irqp */
-       /* otherwise ip2config is initialized by what's in ip2/ip2.h */
-       /* command line trumps initialization in ip2.h */
-       /* first two args are null if builtin to kernel */
-       if ((irqp != NULL) || (iop != NULL)) {
-               for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-                       if (irqp && irqp[i]) {
-                               ip2config.irq[i] = irqp[i];
-                       }
-                       if (iop && iop[i]) {
-                               ip2config.addr[i] = iop[i];
-                       }
-               }
-       }
-       Fip_firmware = firmware;
-       Fip_firmware_size = firmsize;
-       return old_ip2_init();
-}
-
 // Some functions to keep track of what irq's we have
 
 __initfunc(static int 
@@ -449,6 +439,7 @@ mark_requested_irq( char irq ))
        rirqs[iindx++] = irq;
 }
 
+#ifdef MODULE
 __initfunc( static int
 clear_requested_irq( char irq ))
 {
@@ -461,6 +452,7 @@ clear_requested_irq( char irq ))
        }
        return 0;
 }
+#endif
 
 __initfunc( static int
 have_requested_irq( char irq )) 
@@ -490,7 +482,6 @@ init_module(void)
 #ifdef IP2DEBUG_INIT
        printk (KERN_DEBUG "Loading module ...\n" );
 #endif
-    //was      return old_ip2_init();
     return 0;
 }
 #endif /* MODULE */
@@ -590,8 +581,9 @@ cleanup_module(void)
 #endif /* MODULE */
 
 /******************************************************************************/
-/* Function:   old_ip2_init()                                                 */
+/* Function:   ip2_loadmain()                                                 */
 /* Parameters: irq, io from command line of insmod et. al.                    */
+/*             pointer to fip firmware and firmware size for boards          */
 /* Returns:    Success (0)                                                    */
 /*                                                                            */
 /* Description:                                                               */
@@ -606,7 +598,7 @@ cleanup_module(void)
 #define IP2_SA_FLAGS   0
 
 __initfunc( int
-old_ip2_init(void))
+ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) )
 {
 #ifdef CONFIG_DEVFS_FS
        static devfs_handle_t devfs_handle = NULL;
@@ -623,6 +615,39 @@ old_ip2_init(void))
        ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
 #endif
 
+       /* process command line arguments to modprobe or
+               insmod i.e. iop & irqp */
+       /* irqp and iop should ALWAYS be specified now...  But we check
+               them individually just to be sure, anyways... */
+       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+               if (iop) {
+                       ip2config.addr[i] = iop[i];
+                       if (irqp) {
+                               if( irqp[i] >= 0 ) {
+                                       ip2config.irq[i] = irqp[i];
+                               } else {
+                                       ip2config.irq[i] = 0;
+                               }
+       // This is a little bit of a hack.  If poll_only=1 on command
+       // line back in ip2.c OR all IRQs on all specified boards are
+       // explicitly set to 0, then drop to poll only mode and override
+       // PCI or EISA interrupts.  This superceeds the old hack of
+       // triggering if all interrupts were zero (like da default).
+       // Still a hack but less prone to random acts of terrorism.
+       //
+       // What we really should do, now that the IRQ default is set
+       // to -1, is to use 0 as a hard coded, do not probe.
+       //
+       //      /\/\|=mhw=|\/\/
+                               poll_only |= irqp[i];
+                       }
+               }
+       }
+       poll_only = !poll_only;
+
+       Fip_firmware = firmware;
+       Fip_firmware_size = firmsize;
+
        /* Announce our presence */
        printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
 
@@ -635,12 +660,6 @@ old_ip2_init(void))
        }
        loaded++;
 
-       /* if all irq config is zero we shall poll_only */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               poll_only |= ip2config.irq[i];
-       }
-       poll_only = !poll_only;
-
        /* Initialise the iiEllis subsystem. */
        iiEllisInit();
 
@@ -703,10 +722,13 @@ old_ip2_init(void))
                                        pcibios_read_config_byte(pci_bus, pci_devfn,
                                                                  PCI_INTERRUPT_LINE, &pci_irq);
 
-                                       if (!is_valid_irq(pci_irq)) {
-                                               printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-                                               pci_irq = 0;
-                                       }
+//             If the PCI BIOS assigned it, lets try and use it.  If we
+//             can't acquire it or it screws up, deal with it then.
+
+//                                     if (!is_valid_irq(pci_irq)) {
+//                                             printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+//                                             pci_irq = 0;
+//                                     }
                                        ip2config.irq[i] = pci_irq;
                                } else {        // ann error
                                        ip2config.addr[i] = 0;
@@ -737,10 +759,13 @@ old_ip2_init(void))
                                        status =
                                        pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
 
-                                       if (!is_valid_irq(pci_irq)) {
-                                               printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-                                               pci_irq = 0;
-                                       }
+//             If the PCI BIOS assigned it, lets try and use it.  If we
+//             can't acquire it or it screws up, deal with it then.
+
+//                                     if (!is_valid_irq(pci_irq)) {
+//                                             printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+//                                             pci_irq = 0;
+//                                     }
                                        ip2config.irq[i] = pci_irq;
                                } else {        // ann error
                                        ip2config.addr[i] = 0;
@@ -898,41 +923,45 @@ old_ip2_init(void))
                        }
 
 #ifdef CONFIG_DEVFS_FS
-                       sprintf( name, "ipl%d", i );
-                       i2BoardPtrTable[i]->devfs_ipl_handle =
-                               devfs_register (devfs_handle, name, 0,
-                                       DEVFS_FL_NONE,
-                                       IP2_IPL_MAJOR, 4 * i,
-                                       S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-                                       0, 0, &ip2_ipl, NULL);
-
-                       sprintf( name, "stat%d", i );
-                       i2BoardPtrTable[i]->devfs_stat_handle =
-                               devfs_register (devfs_handle, name, 0,
-                                       DEVFS_FL_NONE,
-                                       IP2_IPL_MAJOR, 4 * i + 1,
-                                       S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-                                       0, 0, &ip2_ipl, NULL);
-
-                       for ( box = 0; box < ABS_MAX_BOXES; ++box )
-                       {
-                           for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
+                       if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
+                               sprintf( name, "ipl%d", i );
+                               pB->devfs_ipl_handle =
+                                       devfs_register (devfs_handle, name, 0,
+                                               DEVFS_FL_NONE,
+                                               IP2_IPL_MAJOR, 4 * i,
+                                               S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+                                               0, 0, &ip2_ipl, NULL);
+
+                               sprintf( name, "stat%d", i );
+                               pB->devfs_stat_handle =
+                                       devfs_register (devfs_handle, name, 0,
+                                               DEVFS_FL_NONE,
+                                               IP2_IPL_MAJOR, 4 * i + 1,
+                                               S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+                                               0, 0, &ip2_ipl, NULL);
+
+                           for ( box = 0; box < ABS_MAX_BOXES; ++box )
                            {
-                               if ( pB->i2eChannelMap[box] & (1 << j) )
+                               for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
                                {
-                                   tty_register_devfs(&ip2_tty_driver,
-                                       0, j + ABS_BIGGEST_BOX *
+                                   if ( pB->i2eChannelMap[box] & (1 << j) )
+                                   {
+                                       tty_register_devfs(&ip2_tty_driver,
+                                           0, j + ABS_BIGGEST_BOX *
                                                (box+i*ABS_MAX_BOXES));
-                                   tty_register_devfs(&ip2_callout_driver,
-                                       0, j + ABS_BIGGEST_BOX *
+                                       tty_register_devfs(&ip2_callout_driver,
+                                           0, j + ABS_BIGGEST_BOX *
                                                (box+i*ABS_MAX_BOXES));
+                                   }
                                }
                            }
                        }
 #endif
 
                        if (poll_only) {
-                                       ip2config.irq[i] = CIR_POLL;
+//             Poll only forces driver to only use polling and
+//             to ignore the probed PCI or EISA interrupts.
+                               ip2config.irq[i] = CIR_POLL;
                        }
                        if ( ip2config.irq[i] == CIR_POLL ) {
 retry:
@@ -993,26 +1022,24 @@ ip2_init_board( int boardnum ))
        if ( !iiInitialize ( pB ) ) {
                printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
                         pB->i2eBase, pB->i2eError );
-               kfree ( pB );
-               i2BoardPtrTable[boardnum] = NULL;
-               return;
+               goto err_initialize;
        }
-       printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1,
+       printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
               ip2config.addr[boardnum], ip2config.irq[boardnum] );
 
        if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
-               i2BoardPtrTable[boardnum] = NULL;
-               printk(KERN_ERR "bad addr=0x%x rc = %d\n",
+               printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n",
                                ip2config.addr[boardnum], rc );
-               return;
+               goto err_initialize;
        }
        request_region( ip2config.addr[boardnum], 8, pcName );
 
        if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
            != II_DOWN_GOOD ) {
-               printk ( KERN_ERR "IP2:failed to download loadware " );
+               printk ( KERN_ERR "IP2: failed to download loadware\n" );
+               goto err_release_region;
        } else {
-               printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n",
+               printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
                         pB->i2ePom.e.porVersion,
                         pB->i2ePom.e.porRevision,
                         pB->i2ePom.e.porSubRev, pB->i2eLVersion,
@@ -1022,24 +1049,24 @@ ip2_init_board( int boardnum ))
        switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
 
        default:
-               printk( KERN_ERR "IP2: Unknown board type, ID = %x",
+               printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
                                pB->i2ePom.e.porID );
                nports = 0;
-               goto ex_exit;
+               goto err_release_region;
                break;
 
        case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
-               printk ( KERN_INFO "ISA-4" );
+               printk ( KERN_INFO "IP2: ISA-4\n" );
                nports = 4;
                break;
 
        case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
-               printk ( KERN_INFO "ISA-8 std" );
+               printk ( KERN_INFO "IP2: ISA-8 std\n" );
                nports = 8;
                break;
 
        case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
-               printk ( KERN_INFO "ISA-8 RJ11" );
+               printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
                nports = 8;
                break;
 
@@ -1060,8 +1087,14 @@ ip2_init_board( int boardnum ))
                }
                DevTableMem[boardnum] = pCh =
                        kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
+               if ( !pCh ) {
+                       printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
+                       goto err_release_region;
+               }
                if ( !i2InitChannels( pB, nports, pCh ) ) {
-                       printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError);
+                       printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
+                       kfree ( pCh );
+                       goto err_release_region;
                }
                pB->i2eChannelPtr = &DevTable[portnum];
                pB->i2eChannelCnt = ABS_MOST_PORTS;
@@ -1075,17 +1108,24 @@ ip2_init_board( int boardnum ))
                                }
                        }
                }
-               printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit",
+               printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
                        nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
                }
                goto ex_exit;
-               break;
        }
        DevTableMem[boardnum] = pCh =
                kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
+       if ( !pCh ) {
+               printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
+               goto err_release_region;
+       }
        pB->i2eChannelPtr = pCh;
        pB->i2eChannelCnt = nports;
-       i2InitChannels ( pB, pB->i2eChannelCnt, pCh );
+       if ( !i2InitChannels( pB, nports, pCh ) ) {
+               printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
+               kfree ( pCh );
+               goto err_release_region;
+       }
        pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
 
        for( i = 0; i < pB->i2eChannelCnt; ++i ) {
@@ -1094,7 +1134,17 @@ ip2_init_board( int boardnum ))
                pCh++;
        }
 ex_exit:
-       printk ( KERN_INFO "\n" );
+       pB->tqueue_interrupt.routine = (void(*)(void*)) ip2_interrupt_bh;
+       pB->tqueue_interrupt.data = pB;
+
+       return;
+
+err_release_region:
+       release_region(ip2config.addr[boardnum], 8);
+err_initialize:
+       kfree ( pB );
+       i2BoardPtrTable[boardnum] = NULL;
+       return;
 }
 
 /******************************************************************************/
@@ -1292,16 +1342,34 @@ service_all_boards()
 }
 
 
-#ifdef USE_IQI
-static struct tq_struct 
-senior_service =
-{      // it's the death that worse than fate
-       NULL,
-       0,
-       (void(*)(void*)) service_all_boards,
-       NULL,   //later - board address XXX
-};
-#endif
+/******************************************************************************/
+/* Function:   ip2_interrupt_bh(pB)                                           */
+/* Parameters: pB - pointer to the board structure                            */
+/* Returns:    Nothing                                                        */
+/*                                                                            */
+/* Description:                                                               */
+/*     Service the board in a bottom half interrupt handler and then         */
+/*     reenable the board's interrupts if it has an IRQ number               */
+/*                                                                            */
+/******************************************************************************/
+static void
+ip2_interrupt_bh(i2eBordStrPtr pB)
+{
+//     pB better well be set or we have a problem!  We can only get
+//     here from the IMMEDIATE queue.  Here, we process the boards.
+//     Checking pB doesn't cost much and it saves us from the sanity checkers.
+
+       bh_counter++; 
+
+       if ( pB ) {
+               i2ServiceBoard( pB );
+               if( pB->i2eUsingIrq ) {
+//                     Re-enable his interrupts
+                       iiEnableMailIrq(pB);
+               }
+       }
+}
+
 
 /******************************************************************************/
 /* Function:   ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)    */
@@ -1312,6 +1380,14 @@ senior_service =
 /*                                                                            */
 /* Description:                                                               */
 /*                                                                            */
+/*     Our task here is simply to identify each board which needs servicing. */
+/*     If we are queuing then, queue it to be serviced, and disable its irq  */
+/*     mask otherwise process the board directly.                            */
+/*                                                                            */
+/*     We could queue by IRQ but that just complicates things on both ends   */
+/*     with very little gain in performance (how many instructions does      */
+/*     it take to iterate on the immediate queue).                           */
+/*                                                                            */
 /*                                                                            */
 /******************************************************************************/
 static void
@@ -1324,22 +1400,36 @@ ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
 #endif
 
-#ifdef USE_IQI
-
-       queue_task(&senior_service, &tq_immediate);
-       mark_bh(IMMEDIATE_BH);
-
-#else
        /* Service just the boards on the list using this irq */
        for( i = 0; i < i2nBoards; ++i ) {
                pB = i2BoardPtrTable[i];
+
+//             Only process those boards which match our IRQ.
+//                     IRQ = 0 for polled boards, we won't poll "IRQ" boards
+
                if ( pB && (pB->i2eUsingIrq == irq) ) {
+#ifdef USE_IQI
+
+                   if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
+//                     Disable his interrupt (will be enabled when serviced)
+//                     This is mostly to protect from reentrancy.
+                       iiDisableMailIrq(pB);
+
+//                     Park the board on the immediate queue for processing.
+                       queue_task(&pB->tqueue_interrupt, &tq_immediate);
+
+//                     Make sure the immediate queue is flagged to fire.
+                       mark_bh(IMMEDIATE_BH);
+                   }
+#else
+//             We are using immediate servicing here.  This sucks and can
+//             cause all sorts of havoc with ppp and others.  The failsafe
+//             check on iiSendPendingMail could also throw a hairball.
                        i2ServiceBoard( pB );
+#endif /* USE_IQI */
                }
        }
 
-#endif /* USE_IQI */
-
        ++irq_counter;
 
 #ifdef IP2DEBUG_TRACE
@@ -1365,19 +1455,11 @@ ip2_poll(unsigned long arg)
 #endif
        TimerOn = 0; // it's the truth but not checked in service
 
-       bh_counter++; 
-
-#ifdef USE_IQI
-
-       queue_task(&senior_service, &tq_immediate);
-       mark_bh(IMMEDIATE_BH);
-
-#else
-       // Just polled boards, service_all might be better
+       // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
+       // It will NOT poll boards handled by hard interrupts.
+       // The issue of queued BH interrups is handled in ip2_interrupt().
        ip2_interrupt(0, NULL, NULL);
 
-#endif /* USE_IQI */
-
        PollTimer.expires = POLL_TIMEOUT;
        add_timer( &PollTimer );
        TimerOn = 1;
@@ -1546,6 +1628,7 @@ open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
 static int
 ip2_open( PTTY tty, struct file *pFile )
 {
+       wait_queue_t wait;
        int rc = 0;
        int do_clocal = 0;
        i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
@@ -1579,14 +1662,23 @@ ip2_open( PTTY tty, struct file *pFile )
         * 1. If the port is in the middle of closing wait for the completion
         *    and then return the appropriate error.
         */
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&pCh->close_wait, &wait);
+       set_current_state( TASK_INTERRUPTIBLE );
+
        if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
                if ( pCh->flags & ASYNC_CLOSING ) {
-                       interruptible_sleep_on( &pCh->close_wait);
+                       schedule();
                }
                if ( tty_hung_up_p(pFile) ) {
+                       set_current_state( TASK_RUNNING );
+                       remove_wait_queue(&pCh->close_wait, &wait);
                        return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
                }
        }
+       set_current_state( TASK_RUNNING );
+       remove_wait_queue(&pCh->close_wait, &wait);
+
        /*
         * 2. If this is a callout device, make sure the normal port is not in
         *    use, and that someone else doesn't have the callout device locked.
@@ -1639,13 +1731,20 @@ ip2_open( PTTY tty, struct file *pFile )
 #endif
 
        ++pCh->wopen;
+
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&pCh->open_wait, &wait);
+
        for(;;) {
                if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
                        i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
                        pCh->dataSetOut |= (I2_DTR | I2_RTS);
+                       set_current_state( TASK_INTERRUPTIBLE );
                        serviceOutgoingFifo( pCh->pMyBord );
                }
                if ( tty_hung_up_p(pFile) ) {
+                       set_current_state( TASK_RUNNING );
+                       remove_wait_queue(&pCh->dss_now_wait, &wait);
                        return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
                }
                if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
@@ -1671,8 +1770,11 @@ ip2_open( PTTY tty, struct file *pFile )
                        rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
                        break;
                }
-               interruptible_sleep_on(&pCh->open_wait);
+               schedule();
        }
+       set_current_state( TASK_RUNNING );
+       remove_wait_queue(&pCh->dss_now_wait, &wait);
+
        --pCh->wopen; //why count?
 #ifdef IP2DEBUG_TRACE
        ip2trace (CHANN, ITRC_OPEN, 4, 0 );
@@ -1846,6 +1948,10 @@ ip2_hangup ( PTTY tty )
 {
        i2ChanStrPtr  pCh = tty->driver_data;
 
+       if( !pCh ) {
+               return;
+       }
+
 #ifdef IP2DEBUG_TRACE
        ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
 #endif
@@ -1856,7 +1962,7 @@ ip2_hangup ( PTTY tty )
 
        i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
        i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
-       if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
+       if ( (tty->termios->c_cflag & HUPCL) ) {
                i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
                pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
                i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
@@ -2205,6 +2311,7 @@ ip2_stop ( PTTY tty )
 static int
 ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 {
+       wait_queue_t wait;
        i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
        struct async_icount cprev, cnow;        /* kernel counter temps */
        struct serial_icounter_struct *p_cuser; /* user space */
@@ -2323,8 +2430,18 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
                ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc );
 #endif
                i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
+
+               init_waitqueue_entry(&wait, current);
+               add_wait_queue(&pCh->dss_now_wait, &wait);
+               set_current_state( TASK_INTERRUPTIBLE );
+
                serviceOutgoingFifo( pCh->pMyBord );
-               interruptible_sleep_on(&pCh->dss_now_wait);
+
+               schedule();
+
+               set_current_state( TASK_RUNNING );
+               remove_wait_queue(&pCh->dss_now_wait, &wait);
+
                if (signal_pending(current)) {
                        return -EINTR;
                }
@@ -2358,12 +2475,16 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
                restore_flags(flags);
                i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, 
                                                CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
+               init_waitqueue_entry(&wait, current);
+               add_wait_queue(&pCh->delta_msr_wait, &wait);
+               set_current_state( TASK_INTERRUPTIBLE );
+
                serviceOutgoingFifo( pCh->pMyBord );
                for(;;) {
 #ifdef IP2DEBUG_TRACE
                        ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
 #endif
-                       interruptible_sleep_on(&pCh->delta_msr_wait);
+                       schedule();
 #ifdef IP2DEBUG_TRACE
                        ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
 #endif
@@ -2389,6 +2510,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
                        }
                        cprev = cnow;
                }
+               set_current_state( TASK_RUNNING );
+               remove_wait_queue(&pCh->delta_msr_wait, &wait);
+
                i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3, 
                                                 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
                if ( ! (pCh->flags      & ASYNC_CHECK_CD)) {
index a8ac5dcc2d0531a836b089de1fa692c67a773d31..82d92244631e31bc6c52f8dbdda92485c973cc27 100644 (file)
@@ -1,7 +1,8 @@
 /*
-   dmfe.c: Version 1.28 01/18/2000
+   dmfe.c: Version 1.36 04/20/2001
 
-   A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. 
+   A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
+   ethernet driver for Linux.
    Copyright (C) 1997  Sten Wang
 
    This program is free software; you can redistribute it and/or
 
 
    Compiler command:
-   "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall 
+   "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/include -Wall 
    -Wstrict-prototypes -O6 -c dmfe.c"
    OR
-   "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net -Wall 
-   -Wstrict-prototypes -O6 -c dmfe.c"
+   "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/include
+   -Wall -Wstrict-prototypes -O6 -c dmfe.c"
+   OR
+   "gcc -D__SMP__ -DMODULE -DMODVERSIONS -D__KERNEL__ 
+   -I/usr/src/linux/include -Wall -Wstrict-prototypes -O6 -c dmfe.c"
+
+   Note: "O" of -O6 is a capital 'o', not a '0' (zero)
+
 
    The following steps teach you how to active DM9102 board:
    1. Used the upper compiler command to compile dmfe.c
    "insmod dmfe mode=1" ;;Force 100M Half Duplex
    "insmod dmfe mode=4" ;;Force 10M Full Duplex
    "insmod dmfe mode=5" ;;Force 100M Full Duplex
+   "insmod dmfe mode=100" ;;Force 1M HomeRun(DM9801)
+   "insmod dmfe mode=200" ;;Force 1M LongRun(DM9802)
    3. config a dm9102 network interface
    "ifconfig eth0 172.22.3.18"
-   ^^^^^^^^^^^ your IP address
+                  ^^^^^^^^^^^ your IP address
    4. active the IP routing table
    "route add -net 172.22.3.0 eth0"
    5. Well done. Your DM9102 adapter actived now.
 
+
+   DAVICOM Web-Site: http://www.davicom.com.tw
+
    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
 
-   Date:   10/28,1998
+   Date:   03/08/2001
 
    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
-   
+
    Cleaned up for kernel merge by Alan Cox (alan@redhat.com)
-   
+
  */
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif /*  */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #define PCI_DM9132_ID   0x91321282     /* Davicom DM9132 ID */
 #define PCI_DM9102_ID   0x91021282     /* Davicom DM9102 ID */
 #define PCI_DM9100_ID   0x91001282     /* Davicom DM9100 ID */
+#define PCI_DM9009_ID   0x90091282     /* Davicom DM9009 ID */
 
 #define DMFE_SUCC       0
 #define DM9102_IO_SIZE  0x80
 #define DM9102A_IO_SIZE 0x100
-#define TX_FREE_DESC_CNT 0xc   /* Tx packet count */
 #define TX_MAX_SEND_CNT 0x1    /* Maximum tx packet per time */
 #define TX_DESC_CNT     0x10   /* Allocated Tx descriptors */
-#define RX_DESC_CNT     0x10   /* Allocated Rx descriptors */
-#define DESC_ALL_CNT    TX_DESC_CNT+RX_DESC_CNT
+#define RX_DESC_CNT     0x20   /* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT-2)       /* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT-3)       /* TX wakeup count */
+#define DESC_ALL_CNT    (TX_DESC_CNT+RX_DESC_CNT)
 #define TX_BUF_ALLOC    0x600
 #define RX_ALLOC_SIZE   0x620
 #define DM910X_RESET    1
-#define CR6_DEFAULT     0x00280000     /* SF, HD */
-#define CR7_DEFAULT     0x1a2cd
+#define CR0_DEFAULT     0x00E00000     /* TX & RX burst mode */
+#define CR6_DEFAULT     0x00080000     /* HD */
+#define CR7_DEFAULT     0x180c1
 #define CR15_DEFAULT    0x06   /* TxJabber RxWatchdog */
 #define TDES0_ERR_MASK  0x4302 /* TXJT, LC, EC, FUE */
 #define MAX_PACKET_SIZE 1514
 #define DMFE_MAX_MULTICAST 14
-#define RX_MAX_TRAFFIC  0x14000
+#define RX_COPY_SIZE   100
 #define MAX_CHECK_PACKET 0x8000
+#define DM9801_NOISE_FLOOR 8
+#define DM9802_NOISE_FLOOR 5
 
 #define DMFE_10MHF      0
 #define DMFE_100MHF     1
 #define DMFE_10MFD      4
 #define DMFE_100MFD     5
 #define DMFE_AUTO       8
+#define DMFE_1M_HPNA    0x10
+#define DMFE_1M_LONG    0x20
 
-#define DMFE_TIMER_WUT  jiffies+(HZ*2)/2       /* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT ((HZ*3)/2)     /* tx packet time-out time 1.5 s" */
+#define DMFE_TXTH_72   0x400000        /* TX TH 72 byte */
+#define DMFE_TXTH_96   0x404000        /* TX TH 96 byte */
+#define DMFE_TXTH_128  0x0000          /* TX TH 128 byte */
+#define DMFE_TXTH_256  0x4000          /* TX TH 256 byte */
+#define DMFE_TXTH_512  0x8000          /* TX TH 512 byte */
+#define DMFE_TXTH_1K   0xC000          /* TX TH 1K  byte */
 
-#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule)
+#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
+#define DMFE_TX_TIMEOUT (HZ * 1.5)     /* tx packet time-out time 1.5 s" */
+#define DMFE_TX_KICK   (HZ * 0.5)      /* tx packet Kick-out time 0.5 s" */
 
-#define DELAY_5US udelay(5)    /* udelay scale 1 usec */
+#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
 
-#define DELAY_1US udelay(1)    /* udelay scale 1 usec */
+#define DELAY_5US udelay(5)             /* udelay scale 1 usec */
 
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define DELAY_1US udelay(1)             /* udelay scale 1 usec */
 
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
 
 /* CR9 definition: SROM/MII */
 #define CR9_SROM_READ   0x4800
 #define PHY_DATA_0      0x00000
 #define MDCLKH          0x10000
 
+#define PHY_POWER_DOWN 0x800
+
+#define SROM_V41_CODE   0x14
+
 #define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;
 
 #define CHK_IO_SIZE(pci_id, dev_rev) ( (pci_id==PCI_DM9132_ID) || (dev_rev >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
@@ -145,21 +178,20 @@ struct rx_desc {
        u32 next_rx_desc;
        u32 reserved;
 };
-
 struct dmfe_board_info {
        u32 chip_id;            /* Chip vendor/Device ID */
-       u32 chip_revesion;      /* Chip revesion */
+       u32 chip_revision;      /* Chip revision */
        struct device *next_dev;        /* next device */
 
        struct pci_dev *net_dev;        /* PCI device */
 
-       unsigned long ioaddr;           /* I/O base address */
+       u32 ioaddr;             /* I/O base address */
        u32 cr0_data;
        u32 cr5_data;
        u32 cr6_data;
        u32 cr7_data;
        u32 cr15_data;
-       
+
        /* descriptor pointer */
        unsigned char *buf_pool_ptr;    /* Tx buffer pool memory */
        unsigned char *buf_pool_start;  /* Tx buffer pool align dword */
@@ -174,19 +206,33 @@ struct dmfe_board_info {
        u32 tx_queue_cnt;       /* wait to send packet count */
        u32 rx_avail_cnt;       /* available rx descriptor count */
        u32 interval_rx_cnt;    /* rx packet count a callback time */
-
-       u16 phy_id2;            /* Phyxcer ID2 */
-
+       u16 HPNA_command;       /* For HPNA register 16 */
+       u16 HPNA_timer; /* For HPNA remote device check */
+       u16 dbug_cnt;
+       u16 NIC_capability;     /* NIC media capability */
+       u16 PHY_reg4;           /* Saved Phyxcer register 4 value */
+       u8 HPNA_present;        /* 0:none, 1:DM9801, 2:DM9802 */
+       u8 chip_type;           /* Keep DM9102A chip type */
        u8 media_mode;          /* user specify media mode */
        u8 op_mode;             /* real work media mode */
        u8 phy_addr;
        u8 link_failed;         /* Ever link failed */
        u8 wait_reset;          /* Hardware failed, need to reset */
-       u8 in_reset_state;      /* Now driver in reset routine */
-       u8 rx_error_cnt;        /* received abnormal case count */
        u8 dm910x_chk_mode;     /* Operating mode check */
+       u8 first_in_callback;   /* Flag to record state */
        struct timer_list timer;
        struct enet_statistics stats;   /* statistic counter */
+/* Driver defined statistic counter */
+       unsigned long tx_fifo_underrun;
+       unsigned long tx_loss_carrier;
+       unsigned long tx_no_carrier;
+       unsigned long tx_late_collision;
+       unsigned long tx_excessive_collision;
+       unsigned long tx_jabber_timeout;
+       unsigned long reset_count;
+       unsigned long reset_cr8;
+       unsigned long reset_fatal;
+       unsigned long reset_TXtimeout;
        unsigned char srom[128];
 };
 
@@ -204,7 +250,7 @@ enum dmfe_CR6_bits {
 
 /* Global variable declaration ----------------------------- */
 static int dmfe_debug = 0;
-static unsigned char dmfe_media_mode = 8;
+static unsigned char dmfe_media_mode = DMFE_AUTO;
 static struct device *dmfe_root_dev = NULL;    /* First device */
 static u32 dmfe_cr6_user_set = 0;
 
@@ -214,6 +260,13 @@ static u32 cr6set = 0;
 static unsigned char mode = 8;
 static u8 chkmode = 1;
 
+static u8 HPNA_mode = 0;       /* Default: Low Power/High Speed */
+static u8 HPNA_rx_cmd = 0;     /* Default: Disable Rx remote command */
+static u8 HPNA_tx_cmd = 0;     /* Default: Don't issue remote command */
+static u8 HPNA_NoiseFloor = 0; /* Default: HPNA NoiseFloor */
+static u8 SF_mode = 0;         /* Special Function: 1:VLAN, 2:RX Flow Control
+                                  4: TX pause packet */
+
 static unsigned long CrcTable[256] =
 {
        0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
@@ -283,6 +336,7 @@ static unsigned long CrcTable[256] =
 };
 
 /* function declaration ------------------------------------- */
+int dmfe_reg_board(struct device *);
 int dmfe_probe(struct device *);
 static int dmfe_open(struct device *);
 static int dmfe_start_xmit(struct sk_buff *, struct device *);
@@ -301,24 +355,35 @@ static u16 phy_read(u32, u8, u8, u32);
 static void phy_write(u32, u8, u8, u16, u32);
 static void phy_write_1bit(u32, u32);
 static u16 phy_read_1bit(u32);
-static void dmfe_sense_speed(struct dmfe_board_info *);
+static u8 dmfe_sense_speed(struct dmfe_board_info *);
 static void dmfe_process_mode(struct dmfe_board_info *);
 static void dmfe_timer(unsigned long);
 static void dmfe_rx_packet(struct device *, struct dmfe_board_info *);
+static void dmfe_free_tx_pkt(struct device *, struct dmfe_board_info *);
 static void dmfe_reused_skb(struct dmfe_board_info *, struct sk_buff *);
 static void dmfe_dynamic_reset(struct device *);
 static void dmfe_free_rxbuffer(struct dmfe_board_info *);
 static void dmfe_init_dm910x(struct device *);
 static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static void dmfe_parse_srom(struct dmfe_board_info *);
+static void dmfe_program_DM9801(struct dmfe_board_info *, int);
+static void dmfe_program_DM9802(struct dmfe_board_info *);
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info *);
+static void dmfe_set_phyxcer(struct dmfe_board_info *);
 
 /* DM910X network baord routine ---------------------------- */
 
 /*
-   Search DM910X board ,allocate space and register it
+   Search DM910X boardallocate space and register it
  */
+int dmfe_reg_board(struct device *dev) /* For Kernel 2.2X */
+{
+       return dmfe_probe(dev);
+}
+
 int dmfe_probe(struct device *dev)
 {
-       unsigned long pci_iobase;
+       u32 pci_iobase;
        u16 dm9102_count = 0;
        u8 pci_irqline;
        static int index = 0;   /* For multiple call */
@@ -332,42 +397,40 @@ int dmfe_probe(struct device *dev)
                return -ENODEV;
 
        index = 0;
-       while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev)))
-       {
-               u32 pci_id;
-               u32 dev_rev;
+       while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev))) {
+               u32 pci_id, dev_rev, pci_pmr;
                u8 pci_cmd;
 
                index++;
                if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id) != DMFE_SUCC)
                        continue;
-
-               if ((pci_id != PCI_DM9102_ID) && (pci_id != PCI_DM9132_ID))
+               if ((pci_id != PCI_DM9102_ID) && (pci_id != PCI_DM9132_ID) && (pci_id != PCI_DM9009_ID))
                        continue;
 
                /* read PCI IO base address and IRQ to check */
-               pci_iobase = net_dev->base_address[0];
-               pci_irqline = net_dev->irq;
-               pci_iobase &= ~0x7f;    /* mask off bit0~6 */
+               pci_read_config_dword(net_dev, PCI_BASE_ADDRESS_0, &pci_iobase);
+               pci_read_config_byte(net_dev, PCI_INTERRUPT_LINE, &pci_irqline);
+               pci_read_config_byte(net_dev, PCI_COMMAND, &pci_cmd);
+               pci_read_config_dword(net_dev, 8, &dev_rev);    /* Read Chip revision */
+               pci_read_config_dword(net_dev, 0x50, &pci_pmr); /* Read PMR */
 
                /* Enable Master/IO access, Disable memory access */
-               pci_read_config_byte(net_dev, PCI_COMMAND, &pci_cmd);
                pci_cmd |= PCI_COMMAND_IO + PCI_COMMAND_MASTER;
                pci_cmd &= ~PCI_COMMAND_MEMORY;
-               pci_write_config_byte(net_dev, PCI_COMMAND, pci_cmd);
 
-               /* Set Latency Timer 80h */
+               /* Write back PCI command & Let latency timer = 0x80 */
+               pci_write_config_byte(net_dev, PCI_COMMAND, pci_cmd);
                pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80);
 
-               /* Read Chip revesion */
-               pci_read_config_dword(net_dev, PCI_REVISION_ID, &dev_rev);
-
                /* IO range check */
-               if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev))) 
+               pci_iobase &= ~0x7f;    /* mask off bit0~6 */
+               if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev))) {
+                       printk(KERN_ERR "dmfe: I/O conflict : IO=%x Range=%x\n", pci_iobase, CHK_IO_SIZE(pci_id, dev_rev));
                        continue;
+               }
 
                /* Interrupt check */
-               if (pci_irqline == 0) {
+               if ((pci_irqline == 0xff) || (pci_irqline == 0)) {
                        printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline);
                        continue;
                }
@@ -386,7 +449,7 @@ int dmfe_probe(struct device *dev)
 
                db->chip_id = pci_id;   /* keep Chip vandor/Device ID */
                db->ioaddr = pci_iobase;
-               db->chip_revesion = dev_rev;
+               db->chip_revision = dev_rev;
 
                db->net_dev = net_dev;
 
@@ -400,6 +463,14 @@ int dmfe_probe(struct device *dev)
                dev->do_ioctl = &dmfe_do_ioctl;
 
                request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name);
+               printk("dmfe: INDEX=%d ID=%x NAME=%s IO=%x IRQ=%d\n", index, pci_id, dev->name, pci_iobase, pci_irqline);
+
+               /* Check Chip type decision */
+               pci_pmr &= 0x070000;    /* Leave PMR revision */
+               if ((pci_pmr == 0x010000) && (dev_rev == 0x02000031))
+                       db->chip_type = 1;      /* DM9102A E3 */
+               else
+                       db->chip_type = 0;
 
                /* read 64 word srom data */
                for (i = 0; i < 64; i++)
@@ -411,6 +482,8 @@ int dmfe_probe(struct device *dev)
 
                dev = 0;        /* NULL device */
        }
+       if (!dm9102_count)
+               printk(KERN_ERR "dmfe: Can't find DM910X board or resource error\n");
        return dm9102_count ? 0 : -ENODEV;
 }
 
@@ -452,22 +525,24 @@ static int dmfe_open(struct device *dev)
        db->tx_packet_cnt = 0;
        db->tx_queue_cnt = 0;
        db->rx_avail_cnt = 0;
-       db->link_failed = 0;
+       db->link_failed = 1;
        db->wait_reset = 0;
-       db->in_reset_state = 0;
-       db->rx_error_cnt = 0;
-
-       if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revesion >= 0x02000030)) {
-               //db->cr6_data &= ~CR6_SFT;         /* Used Tx threshold */
-               //db->cr6_data |= CR6_NO_PURGE;     /* No purge if rx unavailable */
-               db->cr0_data = 0xc00000;        /* TX/RX desc burst mode */
+       db->first_in_callback = 0;
+       db->NIC_capability = 0xf;       /* All capability */
+       db->PHY_reg4 = 0x1e0;
+
+       /* CR6 operation mode decision */
+       if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) {
+               db->cr6_data |= DMFE_TXTH_256;
+               db->cr0_data = CR0_DEFAULT;     /* TX/RX desc burst mode */
                db->dm910x_chk_mode = 4;        /* Enter the normal mode */
        } else {
+               db->cr6_data |= CR6_SFT;        /* Store & Forward mode */
                db->cr0_data = 0;
                db->dm910x_chk_mode = 1;        /* Enter the check mode */
        }
 
-       /* Initilize DM910X board */
+       /* Initialize DM910X board */
        dmfe_init_dm910x(dev);
 
        /* Active System Interface */
@@ -477,7 +552,7 @@ static int dmfe_open(struct device *dev)
 
        /* set and active a timer process */
        init_timer(&db->timer);
-       db->timer.expires = DMFE_TIMER_WUT;
+       db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
        db->timer.data = (unsigned long) dev;
        db->timer.function = &dmfe_timer;
        add_timer(&db->timer);
@@ -485,9 +560,9 @@ static int dmfe_open(struct device *dev)
        return 0;
 }
 
-/* Initilize DM910X board
+/* Initialize DM910X board
    Reset DM910X board
-   Initilize TX/Rx descriptor chain structure
+   Initialize TX/Rx descriptor chain structure
    Send the set-up frame
    Enable Tx/Rx machine
  */
@@ -498,25 +573,37 @@ static void dmfe_init_dm910x(struct device *dev)
 
        DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
 
-       /* Reset DM910x board : need 32 PCI clock to complete */
+       /* Reset DM910x MAC controller */
        outl(DM910X_RESET, ioaddr + DCR0);      /* RESET MAC */
-       DELAY_5US;
+       udelay(100);
        outl(db->cr0_data, ioaddr + DCR0);
+       DELAY_5US;
 
+       /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
+       db->phy_addr = 1;
+
+       /* Parser SROM and media mode */
+       dmfe_parse_srom(db);
+       db->media_mode = dmfe_media_mode;
+
+       /* RESET Phyxcer Chip by GPR port bit 7 */
        outl(0x180, ioaddr + DCR12);    /* Let bit 7 output port */
-       outl(0x80, ioaddr + DCR12);     /* RESET DM9102 phyxcer */
+       if (db->chip_id == PCI_DM9009_ID) {
+               outl(0x80, ioaddr + DCR12);     /* Issue RESET signal */
+               mdelay(300);    /* Delay 300 ms */
+       }
        outl(0x0, ioaddr + DCR12);      /* Clear RESET signal */
 
-       /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
-       db->phy_addr = 1;
+       /* Process Phyxcer Media Mode */
+       if (!(db->media_mode & 0x10))   /* Force 1M mode */
+               dmfe_set_phyxcer(db);
 
        /* Media Mode Check */
-       db->media_mode = dmfe_media_mode;
-       if (db->media_mode & DMFE_AUTO)
-               dmfe_sense_speed(db);
-       else
-               db->op_mode = db->media_mode;
-       dmfe_process_mode(db);
+       /* Don't need now. We did Restart Auto-Negotiation in dmfe_set_phyxcer()
+          and it should not complete now. We check media mode and program in
+          dmfe_timer() later */
+       if (!(db->media_mode & DMFE_AUTO))
+               db->op_mode = db->media_mode;   /* Force Mode */
 
        /* Initiliaze Transmit/Receive decriptor and CR3/4 */
        dmfe_descriptor_init(db, ioaddr);
@@ -531,18 +618,15 @@ static void dmfe_init_dm910x(struct device *dev)
                send_filter_frame(dev, dev->mc_count);  /* DM9102/DM9102A */
 
        /* Init CR5/CR7, interrupt active bit */
-       outl(0xffffffff, ioaddr + DCR5);        /* clear all CR5 status */
        db->cr7_data = CR7_DEFAULT;
        outl(db->cr7_data, ioaddr + DCR7);
 
        /* Init CR15, Tx jabber and Rx watchdog timer */
-       db->cr15_data = CR15_DEFAULT;
        outl(db->cr15_data, ioaddr + DCR15);
 
        /* Enable DM910X Tx/Rx function */
-       db->cr6_data |= CR6_RXSC | CR6_TXSC;
+       db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
        update_cr6(db->cr6_data, ioaddr);
-
 }
 
 
@@ -558,20 +642,23 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct device *dev)
        DMFE_DBUG(0, "dmfe_start_xmit", 0);
 
        /* Resource flag check */
-       if (dev->tbusy == 1)    /* Resource Busy */
+       if (test_and_set_bit(0, (void *) &dev->tbusy))
                return 1;
 
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
-               printk(KERN_WARNING "%s: big packet, size=%d\n", dev->name, (u16) skb->len);
+               printk(KERN_ERR "dmfe: A big packet, size=%d\n", (u16) skb->len);
                dev_kfree_skb(skb);
                return 0;
        }
+
        /* No Tx resource check, it never happen normally */
-       if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
-               dev->tbusy = 1;
-               return 1;
-       }
+       if (db->tx_queue_cnt >= TX_FREE_DESC_CNT)
+               return -EBUSY;
+
+       /* Disable all interrupt */
+       outl(0, dev->base_addr + DCR7);
+
        /* transmit this packet */
        txptr = db->tx_insert_ptr;
        memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
@@ -581,7 +668,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct device *dev)
        db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
 
        /* Transmit Packet Process */
-       if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {
+       if ((!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT)) {
                txptr->tdes0 = 0x80000000;      /* set owner bit to DM910X */
                db->tx_packet_cnt++;    /* Ready to send count */
                outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling comand */
@@ -592,14 +679,19 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct device *dev)
        }
 
        /* Tx resource check */
-       if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
-               dev->tbusy = 1;
+       if (db->tx_queue_cnt < TX_FREE_DESC_CNT) {
+               dev->tbusy = 0;
        }
+
        /* free this SKB */
        dev_kfree_skb(skb);
+
+       /* Restore CR7 to enable interrupt */
+       outl(db->cr7_data, dev->base_addr + DCR7);
        return 0;
 }
 
+
 /*
    Stop the interface.
    The interface is stopped when it is brought.
@@ -612,16 +704,18 @@ static int dmfe_stop(struct device *dev)
        DMFE_DBUG(0, "dmfe_stop", 0);
 
        /* disable system */
-       dev->start = 0;         /* interface disable */
-       dev->tbusy = 1;         /* can't transmit */
+       dev->start = 0; /* interface disable */
+       dev->tbusy = 1; /* can't transmit */
 
-       /* Reset & stop DM910X board */
-       outl(DM910X_RESET, ioaddr + DCR0);
-       DELAY_5US;
 
        /* deleted timer */
        del_timer(&db->timer);
 
+       /* Reset & stop DM910X board */
+       outl(DM910X_RESET, ioaddr + DCR0);
+       DELAY_5US;
+       phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+
        /* free interrupt */
        free_irq(dev->irq, dev);
 
@@ -634,114 +728,142 @@ static int dmfe_stop(struct device *dev)
 
        MOD_DEC_USE_COUNT;
 
+#if 0
+       /* show statistic counter */
+       printk("<DM9XS>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", db->tx_fifo_underrun, db->tx_excessive_collision, db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, db->tx_jabber_timeout, db->reset_count, db->reset_cr8, db->reset_fatal, db->reset_TXtimeout);
+
+#endif /*  */
        return 0;
 }
 
+
 /*
-   DM9102 insterrupt handler
+   DM9102 interrupt handler
    receive the packet to upper layer, free the transmitted packet
  */
-
 static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct device *dev = dev_id;
-       struct tx_desc *txptr;
-       struct dmfe_board_info *db;
-       u32 ioaddr;
 
+       struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+       u32 ioaddr = dev->base_addr;
+       DMFE_DBUG(0, "dmfe_interrupt()", 0);
        if (!dev) {
                DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);
                return;
        }
-       if (dev->interrupt) {
-               DMFE_DBUG(1, "dmfe_interrupt() re-entry ", 0);
-               return;
-       }
-       /* A real interrupt coming */
-       dev->interrupt = 1;     /* Lock interrupt */
-       db = (struct dmfe_board_info *) dev->priv;
-       ioaddr = dev->base_addr;
-
-       DMFE_DBUG(0, "dmfe_interrupt()", 0);
 
-/* Disable all interrupt in CR7 to solve the interrupt edge problem */
-       outl(0, ioaddr + DCR7);
-
-/* Got DM910X status */
+       /* Got DM910X status */
        db->cr5_data = inl(ioaddr + DCR5);
        outl(db->cr5_data, ioaddr + DCR5);
-       /* printk("CR5=%x\n", db->cr5_data); */
+       if (!(db->cr5_data & 0xc1))
+               return;
+
+       /* Disable MAC interrupt in CR7 to solve the interrupt edge problem */
+       outl(0, ioaddr + DCR7);
 
        /* Check system status */
        if (db->cr5_data & 0x2000) {
                /* system bus error happen */
                DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
                dev->tbusy = 1;
+               db->reset_fatal++;
                db->wait_reset = 1;     /* Need to RESET */
-               outl(0, ioaddr + DCR7);         /* disable all interrupt */
-               dev->interrupt = 0;     /* unlock interrupt */
                return;
        }
+
+       /* Received the coming packet */
+       if ((db->cr5_data & 0x40) && db->rx_avail_cnt)
+               dmfe_rx_packet(dev, db);
+
+       /* reallocated rx descriptor buffer */
+       if (db->rx_avail_cnt < RX_DESC_CNT)
+               allocated_rx_buffer(db);
+
        /* Free the transmitted descriptor */
+       // if ( db->cr5_data & 0x01)
+       dmfe_free_tx_pkt(dev, db);
+
+       // mark_bh(NET_BH);     /* Active upper layer */
+
+       /* Mode Check */
+       if (db->dm910x_chk_mode & 0x2) {
+               db->dm910x_chk_mode = 0x4;
+               db->cr6_data |= 0x100;
+               update_cr6(db->cr6_data, db->ioaddr);
+       }
+
+       /* Restore CR7 to enable MAC interrupt mask */
+       outl(db->cr7_data, ioaddr + DCR7);
+}
+
+
+/*
+ *     Free TX resource after TX complete
+ */
+static void dmfe_free_tx_pkt(struct device *dev, struct dmfe_board_info *db)
+{
+       struct tx_desc *txptr;
+       u32 ioaddr = dev->base_addr;
        txptr = db->tx_remove_ptr;
        while (db->tx_packet_cnt) {
-               /* printk("tdes0=%x\n", txptr->tdes0); */
+               /* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
                if (txptr->tdes0 & 0x80000000)
                        break;
 
                /* A packet sent completed */
+               db->tx_packet_cnt--;
                db->stats.tx_packets++;
 
                /* Transmit statistic counter */
                if (txptr->tdes0 != 0x7fffffff) {
-                       /* printk("tdes0=%x\n", txptr->tdes0); */
+                       /* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
                        db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
+
                        db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
-                       if (txptr->tdes0 & TDES0_ERR_MASK)
+
+                       if (txptr->tdes0 & TDES0_ERR_MASK) {
                                db->stats.tx_errors++;
+                               if (txptr->tdes0 & 0x0002) {    /* UnderRun */
+                                       db->tx_fifo_underrun++;
+                                       if (!(db->cr6_data & CR6_SFT)) {
+                                               db->cr6_data = db->cr6_data | CR6_SFT;
+                                               update_cr6(db->cr6_data, db->ioaddr);
+                                       }
+                               }
+                               if (txptr->tdes0 & 0x0100)
+                                       db->tx_excessive_collision++;
+                               if (txptr->tdes0 & 0x0200)
+                                       db->tx_late_collision++;
+                               if (txptr->tdes0 & 0x0400)
+                                       db->tx_no_carrier++;
+                               if (txptr->tdes0 & 0x0800)
+                                       db->tx_loss_carrier++;
+                               if (txptr->tdes0 & 0x4000)
+                                       db->tx_jabber_timeout++;
+                       }
                }
                txptr = (struct tx_desc *) txptr->next_tx_desc;
-               db->tx_packet_cnt--;
-       }                       /* End of while */
+       }                        /* End of while */
 
        /* Update TX remove pointer to next */
        db->tx_remove_ptr = (struct tx_desc *) txptr;
 
        /* Send the Tx packet in queue */
        if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) {
-               txptr->tdes0 = 0x80000000;      /* set owner bit to DM910X */
-               db->tx_packet_cnt++;    /* Ready to send count */
-               outl(0x1, ioaddr + DCR1);       /* Issue Tx polling command */
-               dev->trans_start = jiffies;     /* saved the time stamp */
+               txptr->tdes0 = 0x80000000;      /* Set owner bit */
+               db->tx_packet_cnt++;    /* Ready to send */
                db->tx_queue_cnt--;
+               outl(0x1, ioaddr + DCR1);       /* Issue Tx polling */
+               dev->trans_start = jiffies;     /* saved time stamp */
        }
-       /* Resource available check */
-       if (dev->tbusy && (db->tx_queue_cnt < TX_FREE_DESC_CNT)) {
-               dev->tbusy = 0; /* free a resource */
-               mark_bh(NET_BH);        /* active bottom half */
-       }
-       /* Received the coming packet */
-       if (db->rx_avail_cnt)
-               dmfe_rx_packet(dev, db);
-
-       /* reallocated rx descriptor buffer */
-       if (db->rx_avail_cnt < RX_DESC_CNT)
-               allocated_rx_buffer(db);
 
-       /* Mode Check */
-       if (db->dm910x_chk_mode & 0x2) {
-               db->dm910x_chk_mode = 0x4;
-               db->cr6_data |= 0x100;
-               update_cr6(db->cr6_data, db->ioaddr);
-       }
-       dev->interrupt = 0;     /* release interrupt lock */
+       /* Resource available check */
+       if (db->tx_queue_cnt < TX_WAKE_DESC_CNT) {
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }                       /* Active upper layer */
 
-       /* Restore CR7 to enable interrupt mask */
-       if (db->interval_rx_cnt > RX_MAX_TRAFFIC)
-               db->cr7_data = 0x1a28d;
-       else
-               db->cr7_data = 0x1a2cd;
-       outl(db->cr7_data, ioaddr + DCR7);
 }
 
 /*
@@ -767,7 +889,6 @@ static void dmfe_rx_packet(struct device *dev, struct dmfe_board_info *db)
                        /* reused this SKB */
                        DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
                        dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
-                       /* db->rx_error_cnt++; */
                } else {
                        /* A packet with First/Last flag */
                        rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4;    /* skip CRC */
@@ -783,8 +904,7 @@ static void dmfe_rx_packet(struct device *dev, struct dmfe_board_info *db)
                                if (rxptr->rdes0 & 0x80)
                                        db->stats.rx_length_errors++;
                        }
-                       if (!(rxptr->rdes0 & 0x8000) ||
-                           ((db->cr6_data & CR6_PM) && (rxlen > 6))) {
+                       if (!(rxptr->rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen > 6))) {
                                skb = (struct sk_buff *) rxptr->rx_skb_ptr;
 
                                /* Received Packet CRC check need or not */
@@ -794,8 +914,18 @@ static void dmfe_rx_packet(struct device *dev, struct dmfe_board_info *db)
                                        db->dm910x_chk_mode = 3;
                                } else {
                                        /* A good packet coming, send to upper layer */
-                                       skb->dev = dev;
-                                       skb_put(skb, rxlen);
+                                       /* Shorst packet used new SKB */
+                                       if ((rxlen < RX_COPY_SIZE) && ((skb = dev_alloc_skb(rxlen + 2)) != NULL)) {
+                                               /* Rx packet size less than COPY_SIZE, allocated a rxlen SKB */
+                                               skb->dev = dev;
+                                               skb_reserve(skb, 2);    /* 16byte align */
+                                               memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen);
+                                               dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
+                                       } else {
+                                               /* Pass this Rx buffer to upper layer */
+                                               skb->dev = dev;
+                                               skb_put(skb, rxlen);
+                                       }
                                        skb->protocol = eth_type_trans(skb, dev);
                                        netif_rx(skb);  /* Send to upper layer */
                                        dev->last_rx = jiffies;
@@ -877,9 +1007,20 @@ static void dmfe_timer(unsigned long data)
 
        DMFE_DBUG(0, "dmfe_timer()", 0);
 
-       /* Do reset now */
-       if (db->in_reset_state)
-               return;
+       /* Media mode process when Link OK before enter this route */
+       if (db->first_in_callback == 0) {
+               db->first_in_callback = 1;
+               if (db->chip_type && (db->chip_id == PCI_DM9102_ID)) {
+                       db->cr6_data &= ~0x40000;
+                       update_cr6(db->cr6_data, db->ioaddr);
+                       phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+                       db->cr6_data |= 0x40000;
+                       update_cr6(db->cr6_data, db->ioaddr);
+                       db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
+                       add_timer(&db->timer);
+                       return;
+               }
+       }
 
        /* Operating Mode Check */
        if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET)) {
@@ -888,30 +1029,30 @@ static void dmfe_timer(unsigned long data)
        /* Dynamic reset DM910X : system error or transmit time-out */
        tmp_cr8 = inl(db->ioaddr + DCR8);
        if ((db->interval_rx_cnt == 0) && (tmp_cr8)) {
+               db->reset_cr8++;
                db->wait_reset = 1;
-               /* printk("CR8 %x, Interval Rx %x\n", tmp_cr8, db->interval_rx_cnt); */
        }
-       /* Receiving Traffic check */
-       if (db->interval_rx_cnt > RX_MAX_TRAFFIC)
-               db->cr7_data = 0x1a28d;
-       else
-               db->cr7_data = 0x1a2cd;
-       outl(db->cr7_data, db->ioaddr + DCR7);
-
        db->interval_rx_cnt = 0;
 
-       if (db->wait_reset | (db->tx_packet_cnt &&
-                             ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) {
-               /*
-                  printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);
-                */
+       /* TX polling kick monitor */
+       if (db->tx_packet_cnt && ((jiffies - dev->trans_start) > DMFE_TX_KICK)) {
+               outl(0x1, dev->base_addr + DCR1);       /* Tx polling again */
+
+               /* TX Timeout */
+               if (db->tx_packet_cnt && ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) {
+                       db->reset_TXtimeout++;
+                       db->wait_reset = 1;
+               }
+       }
+       if (db->wait_reset) {
                DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
+               db->reset_count++;
                dmfe_dynamic_reset(dev);
+               db->first_in_callback = 0;
                db->timer.expires = DMFE_TIMER_WUT;
                add_timer(&db->timer);
                return;
        }
-       db->rx_error_cnt = 0;   /* Clear previos counter */
 
        /* Link status check, Dynamic media type change */
        if (db->chip_id == PCI_DM9132_ID)
@@ -919,8 +1060,8 @@ static void dmfe_timer(unsigned long data)
        else
                tmp_cr12 = inb(db->ioaddr + DCR12);     /* DM9102/DM9102A */
 
-       if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revesion == 0x02000030)) ||
-           ((db->chip_id == PCI_DM9132_ID) && (db->chip_revesion == 0x02000010))) {
+       if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||
+           ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) {
                /* DM9102A Chip */
                if (tmp_cr12 & 2)
                        tmp_cr12 = 0x0;         /* Link failed */
@@ -931,35 +1072,39 @@ static void dmfe_timer(unsigned long data)
                /* Link Failed */
                DMFE_DBUG(0, "Link Failed", tmp_cr12);
                db->link_failed = 1;
-               phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);    /* reset Phy */
 
-               /* 10/100M link failed, used 1M Home-Net */
-               db->cr6_data |= 0x00040000;     /* CR6 bit18 = 1, select Home-Net */
-               db->cr6_data &= ~0x00000200;    /* CR6 bit9 =0, half duplex mode */
-               update_cr6(db->cr6_data, db->ioaddr);
+               /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
+               /* AUTO or force 1M Homerun/Longrun don't need */
+               if (!(db->media_mode & 0x38))
+                       phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+
+               /* In AUTO mode, if INT phyxcer link failed, select EXT device */
+               if (db->media_mode & DMFE_AUTO) {
+                       /* 10/100M link failed, used 1M Home-Net */
+                       db->cr6_data |= 0x00040000;     /* CR6 bit18 = 1, select Home-Net */
+                       db->cr6_data &= ~0x00000200;    /* CR6 bit9 =0, half duplex mode */
+                       update_cr6(db->cr6_data, db->ioaddr);
+               }
 
-               /* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */
-               db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
-               if (db->phy_id2 == 0xb900)
-                       phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id);
        } else if ((tmp_cr12 & 0x3) && db->link_failed) {
                DMFE_DBUG(0, "Link link OK", tmp_cr12);
                db->link_failed = 0;
 
-               /* CR6 bit18=0, select 10/100M */
-               db->cr6_data &= ~0x00040000;
-               update_cr6(db->cr6_data, db->ioaddr);
-
                /* Auto Sense Speed */
                if (db->media_mode & DMFE_AUTO)
-                       dmfe_sense_speed(db);
+                       if (dmfe_sense_speed(db))
+                               db->link_failed = 1;
                dmfe_process_mode(db);
-               update_cr6(db->cr6_data, db->ioaddr);
+
                /* SHOW_MEDIA_TYPE(db->op_mode); */
        }
-       /* reallocated rx descriptor buffer */
-       if (db->rx_avail_cnt < RX_DESC_CNT)
-               allocated_rx_buffer(db);
+
+       /* HPNA remote command check */
+       if (db->HPNA_command & 0xf00) {
+               db->HPNA_timer--;
+               if (!db->HPNA_timer)
+                       dmfe_HPNA_remote_cmd_chk(db);
+       }
 
        /* Timer active again */
        db->timer.expires = DMFE_TIMER_WUT;
@@ -979,15 +1124,15 @@ static void dmfe_dynamic_reset(struct device *dev)
 
        DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
 
-       /* Enter dynamic reset route */
-       db->in_reset_state = 1;
-
        /* Disable upper layer interface */
        dev->tbusy = 1;         /* transmit packet disable */
        dev->start = 0;         /* interface not ready */
 
-       db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);         /* Disable Tx/Rx */
+       /* Stop MAC controller */
+       db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
        update_cr6(db->cr6_data, dev->base_addr);
+       outl(0, dev->base_addr + DCR7);
+       outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
 
        /* Free Rx Allocate buffer */
        dmfe_free_rxbuffer(db);
@@ -996,9 +1141,8 @@ static void dmfe_dynamic_reset(struct device *dev)
        db->tx_packet_cnt = 0;
        db->tx_queue_cnt = 0;
        db->rx_avail_cnt = 0;
-       db->link_failed = 0;
+       db->link_failed = 1;
        db->wait_reset = 0;
-       db->rx_error_cnt = 0;
 
        /* Re-initilize DM910X board */
        dmfe_init_dm910x(dev);
@@ -1007,12 +1151,10 @@ static void dmfe_dynamic_reset(struct device *dev)
        dev->tbusy = 0;         /* Can transmit packet */
        dev->start = 1;         /* interface ready */
 
-       /* Leave dynamic reser route */
-       db->in_reset_state = 0;
 }
 
 /*
-   free all allocated rx buffer 
+   Free all allocated rx buffer
  */
 static void dmfe_free_rxbuffer(struct dmfe_board_info *db)
 {
@@ -1044,7 +1186,7 @@ static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb)
 }
 
 /*
-   Initialize transmit/Receive descriptor 
+   Initialize transmit/Receive descriptor
    Using Chain structure, and allocated Tx/Rx buffer
  */
 static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr)
@@ -1108,8 +1250,7 @@ static void update_cr6(u32 cr6_data, u32 ioaddr)
        outl(cr6_tmp, ioaddr + DCR6);
        DELAY_5US;
        outl(cr6_data, ioaddr + DCR6);
-       cr6_tmp = inl(ioaddr + DCR6);
-       /* printk("CR6 update %x ", cr6_tmp); */
+       DELAY_5US;
 }
 
 /* Send a setup frame for DM9132
@@ -1227,7 +1368,7 @@ static void allocated_rx_buffer(struct dmfe_board_info *db)
        rxptr = db->rx_insert_ptr;
 
        while (db->rx_avail_cnt < RX_DESC_CNT) {
-               if ((skb = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL)
+               if ((skb = dev_alloc_skb(RX_ALLOC_SIZE)) == NULL)
                        break;
                rxptr->rx_skb_ptr = (u32) skb;
                rxptr->rdes2 = virt_to_bus(skb->tail);
@@ -1279,19 +1420,16 @@ static u16 read_srom_word(long ioaddr, int offset)
 /*
    Auto sense the media mode
  */
-static void dmfe_sense_speed(struct dmfe_board_info *db)
+static u8 dmfe_sense_speed(struct dmfe_board_info *db)
 {
-       int i;
+       u8 ErrFlag = 0;
        u16 phy_mode;
 
-       for (i = 1000; i; i--) {
-               DELAY_5US;
-               phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-               if ((phy_mode & 0x24) == 0x24)
-                       break;
-       }
-
-       if (i) {
+       /* CR6 bit18=0, select 10/100M */
+       update_cr6((db->cr6_data & ~0x40000), db->ioaddr);
+       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       if ((phy_mode & 0x24) == 0x24) {
                if (db->chip_id == PCI_DM9132_ID)       /* DM9132 */
                        phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
                else            /* DM9102/DM9102A */
@@ -1313,14 +1451,74 @@ static void dmfe_sense_speed(struct dmfe_board_info *db)
                default:
                        db->op_mode = DMFE_10MHF;
                        DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode);
+                       ErrFlag = 1;
                        break;
                }
        } else {
                db->op_mode = DMFE_10MHF;
                DMFE_DBUG(0, "Link Failed :", phy_mode);
+               ErrFlag = 1;
+       }
+       return ErrFlag;
+}
+
+
+/*
+   Set 10/100 phyxcer capability
+   AUTO mode : phyxcer register4 is NIC capability
+   Force mode: phyxcer register4 is the force media
+ */
+static void dmfe_set_phyxcer(struct dmfe_board_info *db)
+{
+       u16 phy_reg;
+
+       /* Select 10/100M phyxcer */
+       db->cr6_data &= ~0x40000;
+       update_cr6(db->cr6_data, db->ioaddr);
+
+       /* DM9009 Chip: Phyxcer reg18 bit12=0 */
+       if (db->chip_id == PCI_DM9009_ID) {
+               phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
+               phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);
        }
+
+       /* Phyxcer capability setting */
+       phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+       if (!(db->media_mode & DMFE_AUTO)) {    /* AUTO/Force Mode Check */
+               /* Force Mode */
+               switch (db->media_mode) {
+               case DMFE_10MHF:
+                       phy_reg |= 0x20;
+                       break;
+               case DMFE_10MFD:
+                       phy_reg |= 0x40;
+                       break;
+               case DMFE_100MHF:
+                       phy_reg |= 0x80;
+                       break;
+               case DMFE_100MFD:
+                       phy_reg |= 0x100;
+                       break;
+               }
+               if (db->chip_id == PCI_DM9009_ID)
+                       phy_reg &= 0x61;
+       }
+
+       /* Write new capability to Phyxcer Reg4 */
+       if (!(phy_reg & 0x01e0)) {
+               phy_reg |= db->PHY_reg4;
+               db->media_mode |= DMFE_AUTO;
+       }
+       phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+       /* Restart Auto-Negotiation */
+       if (db->chip_type && (db->chip_id == PCI_DM9102_ID))
+               phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
+       if (!db->chip_type)
+               phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
 }
 
+
 /*
    Process op-mode
    AUTO mode : PHY controller in Auto-negotiation Mode
@@ -1332,34 +1530,26 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
        u16 phy_reg;
 
        /* Full Duplex Mode Check */
-       db->cr6_data &= ~CR6_FDM;       /* Clear Full Duplex Bit */
        if (db->op_mode & 0x4)
-               db->cr6_data |= CR6_FDM;
-
-       if (!(db->media_mode & DMFE_AUTO)) {    /* Force Mode Check */
-               /* User force the media type */
-               phy_reg = phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id);
-               /* printk("Nway phy_reg5 %x ",phy_reg); */
-               if (phy_reg & 0x1) {
-                       /* parter own the N-Way capability */
-                       phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x1e0;
-                       switch (db->op_mode) {
-                       case DMFE_10MHF:
-                               phy_reg |= 0x20;
-                               break;
-                       case DMFE_10MFD:
-                               phy_reg |= 0x40;
-                               break;
-                       case DMFE_100MHF:
-                               phy_reg |= 0x80;
-                               break;
-                       case DMFE_100MFD:
-                               phy_reg |= 0x100;
-                               break;
-                       }
-                       phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
-               } else {
-                       /* parter without the N-Way capability */
+               db->cr6_data |= CR6_FDM;        /* Set Full Duplex Bit */
+       else
+               db->cr6_data &= ~CR6_FDM;       /* Clear Full Duplex Bit */
+
+       /* Transceiver Selection */
+       if (db->op_mode & 0x10) /* 1M HomePNA */
+               db->cr6_data |= 0x40000;        /* External MII select */
+       else
+               db->cr6_data &= ~0x40000;       /* Internal 10/100 transciver */
+       update_cr6(db->cr6_data, db->ioaddr);
+
+       /* 10/100M phyxcer force mode need */
+       if (!(db->media_mode & 0x18)) {         /* Skip for AUTO mode or HomePNA */
+               /* Forece Mode */
+               phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+               if (!(phy_reg & 0x1)) {
+
+                       /* parter without N-Way capability */
+                       phy_reg = 0x0;
                        switch (db->op_mode) {
                        case DMFE_10MHF:
                                phy_reg = 0x0;
@@ -1375,6 +1565,9 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
                                break;
                        }
                        phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+                       if (db->chip_type && (db->chip_id == PCI_DM9102_ID))
+                               mdelay(20);
+                       phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
                }
        }
 }
@@ -1503,10 +1696,11 @@ static u16 phy_read_1bit(u32 ioaddr)
        return phy_data;
 }
 
+
 /*
-   Calculate the CRC valude of the Rx packet
+   Calculate the CRC value of the Rx packet
    flag = 1 : return the reverse CRC (for the received packet CRC)
-   0 : return the normal CRC (for Hash Table index)
+         0 : return the normal CRC (for Hash Table index)
  */
 unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
 {
@@ -1522,6 +1716,224 @@ unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
                return Crc;
 }
 
+
+/*
+  Parser SROM and media mode
+ */
+static void dmfe_parse_srom(struct dmfe_board_info *db)
+{
+       char *srom = db->srom;
+       int dmfe_mode, tmp_reg;
+       DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
+
+       /* Init CR15 */
+       db->cr15_data = CR15_DEFAULT;
+
+       /* Check SROM Version */
+       if (((int) srom[18] & 0xff) == SROM_V41_CODE) {
+               /* SROM V4.01 */
+
+               /* Get NIC support media mode */
+               db->NIC_capability = *(u16 *) (&srom[34]);
+               db->PHY_reg4 = 0;
+               for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
+                       switch (db->NIC_capability & tmp_reg) {
+                       case 0x1:
+                               db->PHY_reg4 |= 0x0020;
+                               break;
+                       case 0x2:
+                               db->PHY_reg4 |= 0x0040;
+                               break;
+                       case 0x4:
+                               db->PHY_reg4 |= 0x0080;
+                               break;
+                       case 0x8:
+                               db->PHY_reg4 |= 0x0100;
+                               break;
+                       }
+               }
+
+               /* Media Mode Force or not check */
+               dmfe_mode = *((int *) &srom[34]) & *((int *) &srom[36]);
+               switch (dmfe_mode) {
+               case 0x1:
+                       dmfe_media_mode = DMFE_10MHF;
+                       break;  /* Select 10MHF */
+               case 0x4:
+                       dmfe_media_mode = DMFE_100MHF;
+                       break;  /* Select 100MHF */
+               case 0x2:
+                       dmfe_media_mode = DMFE_10MFD;
+                       break;  /* Select 10MFD */
+               case 0x8:
+                       dmfe_media_mode = DMFE_100MFD;
+                       break;  /* Select 100MFD */
+               case 0x100:
+               case 0x200:
+                       dmfe_media_mode = DMFE_1M_HPNA;
+                       break;  /* Select HomePNA */
+               }
+
+               /* Special Function setting */
+               /* VLAN function */
+               if ((SF_mode & 0x1) || (srom[43] & 0x80))
+                       db->cr15_data |= 0x40;
+
+               /* Flow Control */
+               if ((SF_mode & 0x2) || (srom[40] & 0x1))
+                       db->cr15_data |= 0x400;
+
+               /* TX pause packet */
+               if ((SF_mode & 0x4) || (srom[40] & 0xe))
+                       db->cr15_data |= 0x9800;
+               }
+
+       /* Parse HPNA parameter */
+       db->HPNA_command = 1;
+
+       /* Accept remote command or not */
+       if (HPNA_rx_cmd == 0)
+               db->HPNA_command |= 0x8000;
+
+       /* Issue remote command & operation mode */
+       if (HPNA_tx_cmd == 1)
+               switch (HPNA_mode) {    /* Issue Remote Command */
+               case 0:
+                       db->HPNA_command |= 0x0904;
+                       break;
+               case 1:
+                       db->HPNA_command |= 0x0a00;
+                       break;
+               case 2:
+                       db->HPNA_command |= 0x0506;
+                       break;
+               case 3:
+                       db->HPNA_command |= 0x0602;
+                       break;
+               }
+       else
+               switch (HPNA_mode) {    /* Don't Issue */
+               case 0:
+                       db->HPNA_command |= 0x0004;
+                       break;
+               case 1:
+                       db->HPNA_command |= 0x0000;
+                       break;
+               case 2:
+                       db->HPNA_command |= 0x0006;
+                       break;
+               case 3:
+                       db->HPNA_command |= 0x0002;
+                       break;
+               }
+
+       /* Check DM9801 or DM9802 present or not */
+       db->HPNA_present = 0;
+       update_cr6(db->cr6_data | 0x40000, db->ioaddr);
+       tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+       if ((tmp_reg & 0xfff0) == 0xb900) {
+               /* DM9801 or DM9802 present */
+               db->HPNA_timer = 8;     /* Check remote device status after 8 second */
+               if (phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
+                        /* DM9801 HomeRun */
+                       db->HPNA_present = 1;
+                       dmfe_program_DM9801(db, tmp_reg);
+               } else {
+                       /* DM9802 LongRun */
+                       db->HPNA_present = 2;
+                       dmfe_program_DM9802(db);
+               }
+       }
+}
+
+
+/*
+   Description:
+   Init HomeRun DM9801
+ */
+static void dmfe_program_DM9801(struct dmfe_board_info *db, int HPNA_rev)
+{
+       uint reg17, reg25;
+       if (!HPNA_NoiseFloor)
+               HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
+       switch (HPNA_rev) {
+       case 0xb900:            /* DM9801 E3 */
+               db->HPNA_command |= 0x1000;
+               reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
+               reg25 = ((reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
+               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               break;
+       case 0xb901:            /* DM9801 E4 */
+               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
+               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
+               break;
+       case 0xb902:            /* DM9801 E5 */
+       case 0xb903:            /* DM9801 E6 */
+       default:
+               db->HPNA_command |= 0x1000;
+               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
+               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
+               break;
+       }
+       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
+       phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
+}
+
+
+/* Description:
+   Init HomeRun DM9802
+ */
+static void dmfe_program_DM9802(struct dmfe_board_info *db)
+{
+       uint phy_reg;
+       if (!HPNA_NoiseFloor)
+               HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
+       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+       phy_reg = (phy_reg & 0xff00) + HPNA_NoiseFloor;
+       phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
+}
+
+
+/* Description:
+   Check remote HPNA power and speed status. If not correct,
+   issue command again.
+ */
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info *db)
+{
+       uint phy_reg;
+
+       /* Got remote device status */
+       phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
+       switch (phy_reg) {
+       case 0x00:
+               phy_reg = 0x0a00;
+               break;          /* LP/LS */
+       case 0x20:
+               phy_reg = 0x0900;
+               break;          /* LP/HS */
+       case 0x40:
+               phy_reg = 0x0600;
+               break;          /* HP/LS */
+       case 0x60:
+               phy_reg = 0x0500;
+               break;          /* HP/HS */
+       }
+
+       /* Check remote device status match our setting ot not */
+       if (phy_reg != (db->HPNA_command & 0x0f00)) {
+               phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+               db->HPNA_timer = 8;
+       } else
+               db->HPNA_timer = 600;   /* Match, every 10 minutes, check */
+}
+
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
@@ -1530,8 +1942,13 @@ MODULE_PARM(debug, "i");
 MODULE_PARM(mode, "i");
 MODULE_PARM(cr6set, "i");
 MODULE_PARM(chkmode, "i");
+MODULE_PARM(HPNA_mode, "i");
+MODULE_PARM(HPNA_rx_cmd, "i");
+MODULE_PARM(HPNA_tx_cmd, "i");
+MODULE_PARM(HPNA_NoiseFloor, "i");
+MODULE_PARM(SF_mode, "i");
 
-/* Description: 
+/* Description:
    when user used insmod to add module, system invoked init_module()
    to initilize and register.
  */
@@ -1545,21 +1962,31 @@ int init_module(void)
                dmfe_cr6_user_set = cr6set;
 
        switch (mode) {
-       case 0:
-       case 1:
-       case 4:
-       case 5:
+       case DMFE_10MHF:
+       case DMFE_100MHF:
+       case DMFE_10MFD:
+       case DMFE_100MFD:
+       case DMFE_1M_HPNA:
                dmfe_media_mode = mode;
                break;
        default:
-               dmfe_media_mode = 8;
+               dmfe_media_mode = DMFE_AUTO;
                break;
        }
 
+       if (HPNA_mode > 4)
+               HPNA_mode = 0;  /* Default: LP/HS */
+       if (HPNA_rx_cmd > 1)
+               HPNA_rx_cmd = 0;        /* Default: Ignored remote command */
+       if (HPNA_tx_cmd > 1)
+               HPNA_tx_cmd = 0;        /* Default: Don't issue remote command */
+       if (HPNA_NoiseFloor > 15)
+               HPNA_NoiseFloor = 0;
        return dmfe_probe(0);   /* search board and register */
 }
 
-/* Description: 
+
+/* Description:
    when user used rmmod to delete module, system invoked clean_module()
    to  un-register device.
  */
@@ -1574,7 +2001,7 @@ void cleanup_module(void)
                next_dev = ((struct dmfe_board_info *) dmfe_root_dev->priv)->next_dev;
                unregister_netdev(dmfe_root_dev);
                db = dmfe_root_dev->priv;
-               release_region(dmfe_root_dev->base_addr, CHK_IO_SIZE(db->chip_id, db->chip_revesion));
+               release_region(dmfe_root_dev->base_addr, CHK_IO_SIZE(db->chip_id, db->chip_revision));
                kfree(db);      /* free board information */
                kfree(dmfe_root_dev);   /* free device structure */
                dmfe_root_dev = next_dev;
index c2eec3852266e492665fab969636ea2f27314175..cc4fb13f8d41b20f54b49fba5b77f23c43592b70 100644 (file)
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- * $Log: falc.h,v $
+ * $Log: falc-lh.h,v $
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:36  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
  * Revision 1.1 2000/05/15 ivan
  * Included DJA bits for the LIM2 register.
  *
index 21dedfbb50411e138cbbff38e53bdbf55d09464f..8fad9fdc1f1dd32a730c7b4e4cb0604795c1ceee 100644 (file)
  *     2 of the License, or (at your option) any later version.
  *
  * $Log: hd64572.h,v $
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:31  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
  * Revision 1.0 2000/01/25 ivan
  * Initial version.
  *
index 77fd853a4e243fc7dec32bf4e2e8b317437fc9be..875add3d390cb1c92d5ae3b6d32284627361f934 100644 (file)
@@ -1,6 +1,6 @@
 #define        USE_PCI_CLOCK
 static char rcsid[] =
-"$Revision: 3.1.0.6 $$Date: 2001/03/02 $";
+"Revision: 3.4.2 Date: 2001/10/11 ";
 
 /*
  * pc300.c     Cyclades-PC300(tm) Driver.
@@ -15,6 +15,27 @@ static char rcsid[] =
  *     2 of the License, or (at your option) any later version.
  * 
  * $Log: pc300.c,v $
+ * Revision 3.2 to 3.12  2001/10/11 20:26:04  daniela
+ * Fixes for noisy lines: return the size of bad frames in 
+ * dma_get_rx_frame_size, so that the Rx buffer descriptors can be cleaned by 
+ * dma_buf_read (called in cpc_net_rx); improved Rx statistics; created 
+ * rx_dma_start routine. 
+ * Changed file revision to the package revision, changed T1/E1 master clock 
+ * configuration, reviewed boot messages and default configuration. 
+ * Included new configuration parameters (line code, CRC calculation and clock)
+ * Changed the header of message trace to include the device name. New format:
+ * "hdlcX[R/T]: ".
+ *
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:25  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
+ * Revision 3.1.0.7 2001/06/08 daniela
+ * Did some changes in the DMA programming implementation to avoid the 
+ * occurrence of a SCA-II bug when CDA is accessed during a DMA transfer.
+ *
  * Revision 3.1.0.6 2001/03/02 daniela
  * Changed SIOCGPC300CONF ioctl, to give hw information to pc300util.
  *
@@ -167,6 +188,7 @@ static char rcsid[] =
 #undef PC300_DEBUG_INTR
 #undef PC300_DEBUG_TX
 #undef PC300_DEBUG_RX
+#undef PC300_DEBUG_OTHER
 
 /* Hardware configuration options.
  * These are arrays of configuration options used by verification routines.
@@ -327,8 +349,11 @@ dma_get_rx_frame_size(pc300_t *card, int ch)
     while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
        rcvd += cpc_readw(&ptdescr->len);
        first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);
-       if (status & DST_EOM)
+       if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) {
+           /* Return the size of a good frame or incomplete bad frame 
+            * (dma_buf_read will clean the buffer descriptors in this case). */
            return (rcvd);
+       }
        ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next));
     }
     return (-1);
@@ -389,7 +414,10 @@ dma_buf_read(pc300_t *card, int ch, struct sk_buff *skb)
     ptdescr = (pcsca_bd_t *)(card->hw.rambase + 
                             RX_BD_ADDR(ch, chan->rx_first_bd));
     while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
-       if (status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) {
+       nchar = cpc_readw(&ptdescr->len);
+       if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) ||
+                                                       (nchar > BD_DEF_LEN)) {
+           if (nchar > BD_DEF_LEN) status |= DST_RBIT;
            rcvd = -status;
            /* Discard remaining descriptors used by the bad frame */
            while(chan->rx_first_bd != chan->rx_last_bd) {
@@ -404,11 +432,13 @@ dma_buf_read(pc300_t *card, int ch, struct sk_buff *skb)
            }
            break;
        }
-       if ((nchar = cpc_readw(&ptdescr->len)) != 0) {
-           memcpy_fromio(skb_put(skb, nchar), 
-                         (void *)(card->hw.rambase + 
-                                  cpc_readl(&ptdescr->ptbuf)), 
-                         nchar);
+       if (nchar != 0) {
+           if (skb) {
+               memcpy_fromio(skb_put(skb, nchar), 
+                             (void *)(card->hw.rambase + 
+                                      cpc_readl(&ptdescr->ptbuf)), 
+                             nchar);
+           }
            rcvd += nchar;
        }
        cpc_writeb(&ptdescr->status, 0);
@@ -454,6 +484,29 @@ rx_dma_stop(pc300_t *card, int ch)
     cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
 }
 
+void 
+rx_dma_start(pc300_t *card, int ch)
+{
+    uclong scabase = card->hw.scabase;
+    pc300ch_t *chan = (pc300ch_t *)&card->chan[ch];
+
+    /* Start DMA */
+    cpc_writel(scabase + DRX_REG(CDAL, ch), 
+               RX_BD_ADDR(ch, chan->rx_first_bd));
+    if (cpc_readl(scabase + DRX_REG(CDAL,ch)) !=
+                  RX_BD_ADDR(ch, chan->rx_first_bd)) {
+       cpc_writel(scabase + DRX_REG(CDAL, ch),
+                   RX_BD_ADDR(ch, chan->rx_first_bd));
+    }
+    cpc_writel(scabase + DRX_REG(EDAL, ch), 
+               RX_BD_ADDR(ch, chan->rx_last_bd));
+    cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN);
+    cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+    if (!(cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+       cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+    }
+}
+
 /*************************/
 /***   FALC Routines   ***/
 /*************************/
@@ -684,7 +737,7 @@ falc_init_t1(pc300_t *card, int ch)
     cpc_writeb(falcbase + F_REG(SIC1, ch), SIC1_XBS0); 
        
     /* Clock mode */
-    if (conf->clkrate) {       /* Master mode */
+    if (conf->clktype == PC300_CLOCK_INT) {    /* Master mode */
        cpc_writeb(falcbase + F_REG(LIM0, ch), 
                   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS); 
     } else {   /* Slave mode */
@@ -851,7 +904,7 @@ falc_init_e1(pc300_t *card, int ch)
               cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_PMOD);
 
     /* Clock mode */
-    if (conf->clkrate) {       /* Master mode */
+    if (conf->clktype == PC300_CLOCK_INT) {    /* Master mode */
        cpc_writeb(falcbase + F_REG(LIM0, ch), 
                   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS); 
     } else {   /* Slave mode */
@@ -1620,27 +1673,31 @@ ucshort falc_pattern_test_error(pc300_t *card, int ch)
 /**********************************/
 /***   Net Interface Routines   ***/
 /**********************************/
+
 static void 
 cpc_trace (struct device *dev, struct sk_buff *skb_main, char rx_tx)
 {
     struct sk_buff *skb;
 
-    if ((skb = dev_alloc_skb(3 + skb_main->len)) == NULL) {
+    if ((skb = dev_alloc_skb(10 + skb_main->len)) == NULL) {
        printk("%s: out of memory\n", dev->name);
        return;
     }
-    skb_put (skb, 3 + skb_main->len);
+    skb_put (skb, 10 + skb_main->len);
     
     skb->dev = dev;
     skb->protocol = htons(ETH_P_CUST);
     skb->mac.raw  = skb->data;
     skb->pkt_type = PACKET_HOST;
-    skb->len = 3 + skb_main->len;
+    skb->len = 10 + skb_main->len;
 
-    skb->data[0] = rx_tx;
-    skb->data[1] = ':';
-    skb->data[2] = ' ';
-    memcpy(&skb->data[3], skb_main->data, skb_main->len);
+    memcpy(&skb->data[0], dev->name, 5);
+    skb->data[5] = '[';
+    skb->data[6] = rx_tx;
+    skb->data[7] = ']';
+    skb->data[8] = ':';
+    skb->data[9] = ' ';
+    memcpy(&skb->data[10], skb_main->data, skb_main->len);
 
     netif_rx(skb);
 }
@@ -1795,15 +1852,30 @@ cpc_net_rx(hdlc_device *hdlc)
     while (1) {
        if ((rxb = dma_get_rx_frame_size(card, ch)) == -1)
            return;
-
-       skb = dev_alloc_skb(rxb);
-       if (skb == NULL) {
-           printk("%s: Memory squeeze!!\n", dev->name);
-           return;
+       
+       if (rxb > (dev->mtu + 40)) {
+           printk("%s : MTU exceeded %d\n", dev->name, rxb); 
+           skb = NULL;
+       } else {
+           skb = dev_alloc_skb(rxb);
+           if (skb == NULL) {
+               printk("%s: Memory squeeze!!\n", dev->name);
+               return;
+           }
+           skb->dev = dev;
        }
-       skb->dev = dev;
 
-       if((rxb = dma_buf_read(card, ch, skb)) <= 0) {
+       if(((rxb = dma_buf_read(card, ch, skb)) <= 0) || (skb == NULL)) {
+#ifdef PC300_DEBUG_RX
+           printk("%s: rxb = %x\n", dev->name, rxb);
+#endif
+           if ((skb == NULL) && (rxb >= 0)) {
+               /* rxb > dev->mtu */
+               stats->rx_errors++;
+               stats->rx_length_errors++;
+               continue;
+           }
+
            if (rxb < 0) {      /* Invalid frame */
                rxb = -rxb;
                if (rxb & DST_OVR) {
@@ -1819,7 +1891,9 @@ cpc_net_rx(hdlc_device *hdlc)
                    stats->rx_frame_errors++;
                }
            }
-           dev_kfree_skb(skb);
+           if (skb) {
+               dev_kfree_skb(skb);
+           }
            continue;
        }
 
@@ -2018,19 +2092,21 @@ sca_intr(pc300_t *card)
                cpc_writeb(scabase + DSR_RX(ch), drx_stat | DSR_DWE);
 
 #ifdef PC300_DEBUG_INTR
-               printk("sca_intr: RX intr (st=0x%08lx, dsr=0x%02x)\n", 
-                      status, drx_stat);
+               printk("sca_intr: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n", 
+                      ch, status, drx_stat);
 #endif
                if (status & IR0_DRX(IR0_DMIA, ch)) {
                    if (drx_stat & DSR_BOF) {
+                       if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+                           rx_dma_stop(card, ch);
+                       }
+                       cpc_net_rx(hdlc);
+                       /* Discard invalid frames */
+                       hdlc->stats.rx_errors++;
+                       hdlc->stats.rx_over_errors++;
                        chan->rx_first_bd = 0;
                        chan->rx_last_bd = N_DMA_RX_BUF - 1;
-                       cpc_writel(scabase + DRX_REG(CDAL, ch), 
-                                  RX_BD_ADDR(ch, chan->rx_first_bd));
-                       cpc_writel(scabase + DRX_REG(EDAL, ch), 
-                                  RX_BD_ADDR(ch, chan->rx_last_bd));
-                       cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN);
-                       cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+                       rx_dma_start(card, ch);
                    }
                }
                if (status & IR0_DRX(IR0_DMIB, ch)) {
@@ -2060,8 +2136,8 @@ sca_intr(pc300_t *card)
                cpc_writeb(scabase + DSR_TX(ch), dtx_stat | DSR_DWE);
 
 #ifdef PC300_DEBUG_INTR
-               printk("sca_intr: TX intr (st=0x%08lx, dsr=0x%02x)\n", 
-                      status, dtx_stat);
+               printk("sca_intr: TX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n", 
+                      ch, status, dtx_stat);
 #endif
                if (status & IR0_DTX(IR0_EFT, ch)) {
                    if (dtx_stat & DSR_UDRF) {
@@ -2125,8 +2201,8 @@ sca_intr(pc300_t *card)
                cpc_writeb(scabase + M_REG(ST1, ch), st1);
                
 #ifdef PC300_DEBUG_INTR
-               printk("sca_intr: MSCI intr (st=0x%08lx, st1=0x%02x)\n", 
-                      status, st1);
+               printk("sca_intr: MSCI intr chan[%d] (st=0x%08lx, st1=0x%02x)\n"
+                       ,ch, status, st1);
 #endif
                if (st1 & ST1_CDCD) { /* DCD changed */
                    if (cpc_readb(scabase + M_REG(ST3, ch)) & ST3_DCD) {
@@ -2349,6 +2425,11 @@ cpc_intr(int irq, void *dev_id, struct pt_regs *regs)
         return; /* spurious intr */
     }
 
+    if (card->hw.rambase == 0) {
+        printk("cpc_intr: spurious intr2 %d\n", irq);
+        return; /* spurious intr */
+    }
+
     switch (card->hw.type) {
        case PC300_RSV:
        case PC300_X21:
@@ -2753,17 +2834,57 @@ ch_config(pc300dev_t *d)
     uclong plxbase = card->hw.plxbase;
     int ch = chan->channel;
     uclong clkrate = chan->conf.clkrate;
+    uclong clktype = chan->conf.clktype;
     ucchar loopback = (conf->loopback ? MD2_LOOP_MIR : MD2_F_DUPLEX);
+    ucshort encoding = chan->conf.encoding;
+    ucshort parity = chan->conf.parity;
     int tmc, br;
+    ucchar md0, md2;
 
     /* Reset the channel */
     cpc_writeb(scabase + M_REG(CMD, ch), CMD_CH_RST);
 
     /* Configure the SCA registers */
-    cpc_writeb(scabase + M_REG(MD0, ch),
-                (MD0_CRC_CCITT|MD0_CRCC0|MD0_BIT_SYNC));
+    switch (parity) {
+       case PC300_PARITY_NONE:
+           md0 = MD0_BIT_SYNC;
+           break;
+       case PC300_PARITY_CRC16_PR0:
+           md0 = MD0_CRC16_0|MD0_CRCC0|MD0_BIT_SYNC;
+           break;
+       case PC300_PARITY_CRC16_PR1:
+           md0 = MD0_CRC16_1|MD0_CRCC0|MD0_BIT_SYNC;
+           break;
+       case PC300_PARITY_CRC32_PR1_CCITT:
+           md0 = MD0_CRC32|MD0_CRCC0|MD0_BIT_SYNC;
+           break;
+       case PC300_PARITY_CRC16_PR1_CCITT:
+       default:
+           md0 = MD0_CRC_CCITT|MD0_CRCC0|MD0_BIT_SYNC;
+           break;
+    }
+    switch (encoding) {
+       case PC300_ENCODING_NRZI:
+           md2 = loopback|MD2_ADPLL_X8|MD2_NRZI;
+           break;
+       case PC300_ENCODING_FM_MARK:    /* FM1 */
+           md2 = loopback|MD2_ADPLL_X8|MD2_FM|MD2_FM1;
+           break;
+       case PC300_ENCODING_FM_SPACE:   /* FM0 */
+           md2 = loopback|MD2_ADPLL_X8|MD2_FM|MD2_FM0;
+           break;
+       case PC300_ENCODING_MANCHESTER: /* It's not working... */
+           md2 = loopback|MD2_ADPLL_X8|MD2_FM|MD2_MANCH;
+           break;
+       case PC300_ENCODING_NRZ:
+       default:
+           md2 = loopback|MD2_ADPLL_X8|MD2_NRZ;
+           break;
+    }
+
+    cpc_writeb(scabase + M_REG(MD0, ch), md0);
     cpc_writeb(scabase + M_REG(MD1, ch), 0);
-    cpc_writeb(scabase + M_REG(MD2, ch), (loopback|MD2_ADPLL_X8|MD2_NRZ));
+    cpc_writeb(scabase + M_REG(MD2, ch), md2);
     cpc_writeb(scabase + M_REG(IDL, ch), 0x7e);
     cpc_writeb(scabase + M_REG(CTL, ch), CTL_URSKP|CTL_IDLC);
 
@@ -2790,13 +2911,18 @@ ch_config(pc300dev_t *d)
     switch(card->hw.type) {
        case PC300_RSV:
        case PC300_X21:
-           if (clkrate) {
+           if (clktype == PC300_CLOCK_INT || clktype == PC300_CLOCK_TXINT) {
                /* Calculate the clkrate parameters */
                tmc = clock_rate_calc(clkrate, card->hw.clock, &br);
                cpc_writeb(scabase + M_REG(TMCT, ch), tmc);
                cpc_writeb(scabase + M_REG(TXS, ch), (TXS_DTRXC|TXS_IBRG|br));
-               cpc_writeb(scabase + M_REG(TMCR, ch), tmc);
-               cpc_writeb(scabase + M_REG(RXS, ch), (RXS_IBRG|br));
+               if (clktype == PC300_CLOCK_INT) {
+                   cpc_writeb(scabase + M_REG(TMCR, ch), tmc);
+                   cpc_writeb(scabase + M_REG(RXS, ch), (RXS_IBRG|br));
+               } else {
+                   cpc_writeb(scabase + M_REG(TMCR, ch), 1);
+                   cpc_writeb(scabase + M_REG(RXS, ch), 0);
+               }
                if (card->hw.type == PC300_X21) {
                    cpc_writeb(scabase + M_REG(GPO, ch), 1);
                    cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1|EXS_RES1);
@@ -2805,7 +2931,11 @@ ch_config(pc300dev_t *d)
                }
            } else {
                cpc_writeb(scabase + M_REG(TMCT, ch), 1);
-               cpc_writeb(scabase + M_REG(TXS, ch), TXS_DTRXC);
+               if (clktype == PC300_CLOCK_EXT) {
+                   cpc_writeb(scabase + M_REG(TXS, ch), TXS_DTRXC);
+               } else {
+                   cpc_writeb(scabase + M_REG(TXS, ch), TXS_DTRXC|TXS_RCLK);
+               }
                cpc_writeb(scabase + M_REG(TMCR, ch), 1);
                cpc_writeb(scabase + M_REG(RXS, ch), 0);
                if (card->hw.type == PC300_X21) {
@@ -2833,10 +2963,10 @@ ch_config(pc300dev_t *d)
               IR0_M(IR0_RXINTA, ch) |
               IR0_DRX(IR0_EFT|IR0_DMIA|IR0_DMIB, ch) |
               IR0_DTX(IR0_EFT|IR0_DMIA|IR0_DMIB, ch));
-    cpc_writel(scabase + M_REG(IE0, ch), 
-              cpc_readl(scabase + M_REG(IE0, ch)) | IE0_RXINTA);
-    cpc_writel(scabase + M_REG(IE1, ch), 
-              cpc_readl(scabase + M_REG(IE1, ch)) | IE1_CDCD);
+    cpc_writeb(scabase + M_REG(IE0, ch), 
+              cpc_readb(scabase + M_REG(IE0, ch)) | IE0_RXINTA);
+    cpc_writeb(scabase + M_REG(IE1, ch), 
+              cpc_readb(scabase + M_REG(IE1, ch)) | IE1_CDCD);
     return 0;
 }
 
@@ -2867,10 +2997,7 @@ rx_config(pc300dev_t *d)
     cpc_writeb(scabase + DIR_RX(ch), (DIR_EOM | DIR_BOF));
 
     /* Start DMA */
-    cpc_writel(scabase + DRX_REG(CDAL, ch), RX_BD_ADDR(ch, chan->rx_first_bd));
-    cpc_writel(scabase + DRX_REG(EDAL, ch), RX_BD_ADDR(ch, chan->rx_last_bd));
-    cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN);
-    cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+    rx_dma_start(card, ch);
 
     return 0;
 }
@@ -2945,6 +3072,9 @@ cpc_closech(pc300dev_t *d)
     int ch = chan->channel;
 
     cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_CH_RST);
+    rx_dma_stop(card, ch);
+    tx_dma_stop(card, ch);
+    
     if (card->hw.type == PC300_TE) {
        memset(pfalc, 0, sizeof(falc_t));
        cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
@@ -2969,6 +3099,10 @@ cpc_open(hdlc_device *hdlc)
     pc300dev_t *d = (pc300dev_t *)dev->priv;
     int err = -1;
 
+#ifdef PC300_DEBUG_OTHER
+    printk("pc300: cpc_open");
+#endif
+
     err = cpc_opench(d);
     if (err)
        return err;
@@ -3006,6 +3140,7 @@ cpc_open(hdlc_device *hdlc)
     dev->tbusy = 0;
     dev->interrupt = 0;
     dev->start = 1;
+
     MOD_INC_USE_COUNT;
     return 0;
 }
@@ -3019,6 +3154,10 @@ cpc_close(hdlc_device *hdlc)
     pc300_t *card = (pc300_t *)chan->card;
     uclong flags;
 
+#ifdef PC300_DEBUG_OTHER
+    printk("pc300: cpc_close");
+#endif
+
     CPC_LOCK(card, flags);
     switch(hdlc->mode & ~MODE_SOFT) {
 #ifdef CONFIG_PC300_X25
@@ -3319,8 +3458,8 @@ show_version(void)
     tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
     rcsdate = strchr(tmp, ' '); rcsdate++;
     tmp = strrchr(rcsdate, ' '); *tmp = '\0';
-    printk("Cyclades-PC300 driver %s %s\n", rcsvers, rcsdate);
-    printk("        built %s %s\n", __DATE__, __TIME__);
+    printk(KERN_INFO "Cyclades-PC300 driver %s %s (built %s %s)\n", 
+                    rcsvers, rcsdate, __DATE__, __TIME__);
 } /* show_version */
 
 __initfunc(int 
@@ -3350,8 +3489,11 @@ cpc_init(void))
 
                chan->card = card;
                chan->channel = j;
-               chan->conf.clkrate = 64000;
+               chan->conf.clkrate = 0;
+               chan->conf.clktype = PC300_CLOCK_EXT;
                chan->conf.loopback = 0;
+               chan->conf.encoding = PC300_ENCODING_NRZ;
+               chan->conf.parity = PC300_PARITY_CRC16_PR1_CCITT;
                switch(card->hw.type) {
                    case PC300_TE:
                        chan->conf.media = LINE_T1;
@@ -3368,7 +3510,7 @@ cpc_init(void))
 
                    case PC300_RSV:
                    default:
-                       chan->conf.media = LINE_RS232;
+                       chan->conf.media = LINE_V35;
                        break;
                }
                chan->tx_first_bd = 0;
@@ -3407,7 +3549,7 @@ cpc_init(void))
 
                if(register_hdlc_device(hdlc) == 0) {
                    dev->priv = d;      /* We need 'priv', hdlc doesn't */
-                   printk("%s: PC300/", hdlc->name);
+                   printk("%s: Cyclades-PC300/", hdlc->name);
                    switch(card->hw.type) {
                        case PC300_TE:
                            printk("TE ");
@@ -3455,6 +3597,10 @@ void cleanup_module (void)
        pc300_t *card = &cpc_card[i];
 
         if (card->hw.rambase != 0) {
+           /* Disable interrupts on the PCI bridge */
+           cpc_writew(card->hw.plxbase+0x4c, 
+               cpc_readw(card->hw.plxbase+0x4c) & ~(0x0040));
+
            for(j = 0 ; j < card->hw.nchan ; j++) {
                unregister_hdlc_device(card->chan[j].d.hdlc);
            }
index 377f432872f38bcf9d41b5aeba548bae8056595f..99843023a73629e3e4b22fcc9e61cea7f372fda2 100644 (file)
  *     2 of the License, or (at your option) any later version.
  *
  * $Log: pc300.h,v $
+ * Revision 3.2 to 3.6  2001/09/28 13:16:03  daniela
+ * Included kernel version.
+ * New configuration parameters (line code, CRC calculation and clock).
+ * Increased DEF_MTU and TX_QUEUE_LEN.
+ *
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:38  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
  * Revision 2.5 2001/03/02 daniela
  * Created struct pc300conf, to provide the hardware information to pc300util.
  * 
@@ -86,6 +97,8 @@ typedef       unsigned short  ucshort;        /* 16 bits, unsigned */
 typedef        unsigned char   ucchar;         /* 8 bits, unsigned */
 #endif /* CY_TYPES */
 
+#define PC300_KERNEL   "2.2.x" /* Kernel supported by this driver */
+
 #define        PC300_DEVNAME   "hdlc"  /* Dev. name base (for hdlc0, hdlc1, etc.) */
 #define        PC300_MAXINDEX  100     /* Max dev. name index (the '0' in hdlc0) */
 
@@ -329,9 +342,12 @@ typedef struct pc300hw {
 typedef struct pc300chconf {
        ucchar media;           /* HW media (RS232, V.35, etc.) */
        uclong proto;           /* Protocol (PPP, X.25, etc.) */
+       uclong clktype;         /* Clock type (ext, int, txint, txfromrx) */
        uclong clkrate;         /* Clock rate (in bps, 0 = ext. clock) */
        ucchar loopback;        /* Loopback mode */
        ucchar monitor;         /* Monitor mode (0 = off, !0 = on) */
+       ucshort encoding;       /* NRZ, NRZI, FM0, FM1 (FMi - only RSV/X.21) */
+       ucshort parity;         /* CRC calculation */
 
        /* TE-specific parameters */
        ucchar lcode;           /* Line Code (AMI, B8ZS, etc.) */
@@ -380,6 +396,7 @@ enum pc300_ioctl_cmds {
        SIOCSPC300TRACE,
        SIOCSPC300LOOPBACK,
        SIOCSPC300PATTERNTEST,
+       SIOCGPC300HARDWARE,
 };
 
 /* Loopback types - PC300/TE boards */
@@ -396,6 +413,24 @@ enum pc300_loopback_cmds {
 #define        PC300_X21       0x02
 #define        PC300_TE        0x03
 
+#define PC300_CLOCK_EXT                0  /* External TX and RX clock - DTE */
+#define PC300_CLOCK_INT                1  /* Internal TX and RX clock - DCE */
+#define PC300_CLOCK_TXINT      2  /* Internal TX and external RX clock */
+#define PC300_CLOCK_TXFROMRX   3  /* TX clock derived from external RX clock */
+
+#define PC300_ENCODING_NRZ             0x0000
+#define PC300_ENCODING_NRZI            0x0001
+#define PC300_ENCODING_FM_MARK         0x0002
+#define PC300_ENCODING_FM_SPACE                0x0003
+#define PC300_ENCODING_MANCHESTER      0x0004
+
+#define PC300_PARITY_NONE              0x0000
+#define PC300_PARITY_CRC16_PR0         0x0001
+#define PC300_PARITY_CRC16_PR1         0x0002
+#define PC300_PARITY_CRC16_PR0_CCITT   0x0003
+#define PC300_PARITY_CRC16_PR1_CCITT   0x0004
+#define PC300_PARITY_CRC32_PR1_CCITT   0x0005
+
 #define PC300_LC_AMI   0x01
 #define PC300_LC_B8ZS  0x02
 #define PC300_LC_NRZ   0x03
@@ -420,8 +455,8 @@ enum pc300_loopback_cmds {
 #define PC300_RX_SENS_LH       0x02
 
 #define PC300_TX_TIMEOUT       (2*HZ)
-#define PC300_TX_QUEUE_LEN     10
-#define        PC300_DEF_MTU           1500
+#define PC300_TX_QUEUE_LEN     100
+#define        PC300_DEF_MTU           1600
 
 #ifdef __KERNEL__
 /* Function Prototypes */
index ffeaf20d772ad1942f570e73e53da5723327d757..4853815d36bd072acdfe9e365fbbc0989bb6ee53 100644 (file)
@@ -306,6 +306,8 @@ struct tcp_opt {
        struct open_request     **syn_wait_last;
 
        int syn_backlog;        /* Backlog of received SYNs */
+
+       unsigned long last_synq_overflow; 
 };
 
        
index 1feddc15057cf4457ebfd7cd97e450279e98ce4f..23b0ffa4fa1129ff1aad7fa210668b6270614c3f 100644 (file)
@@ -357,6 +357,9 @@ extern void sm_setup(char *str, int *ints);
 #ifdef CONFIG_ADBMOUSE
 extern void adb_mouse_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_COMPUTONE
+extern void ip2_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_WDT
 extern void wdt_setup(char *str, int *ints);
 #endif
@@ -991,6 +994,9 @@ static struct kernel_param cooked_params[] __initdata = {
 #ifdef CONFIG_SOUNDMODEM
        { "soundmodem=", sm_setup },
 #endif
+#ifdef CONFIG_COMPUTONE
+       { "ip2=", ip2_setup };
+#endif
 #ifdef CONFIG_WDT
        { "wdt=", wdt_setup },
 #endif
index 154f479830d3879ba3d1f749f5a17932bcaf6aaf..9f532fa92e304859ddb03d6c7b500eafa8c08ae4 100644 (file)
@@ -23,8 +23,6 @@
 
 extern int sysctl_tcp_syncookies;
 
-static unsigned long tcp_lastsynq_overflow;
-
 /* 
  * This table has to be sorted and terminated with (__u16)-1.
  * XXX generate a better table.
@@ -54,7 +52,9 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
        int mssind;
        const __u16 mss = *mssp;
 
-       tcp_lastsynq_overflow = jiffies;
+       
+       sk->tp_pinfo.af_tcp.last_synq_overflow = jiffies;
+
        /* XXX sort msstab[] by probability?  Binary search? */
        for (mssind = 0; mss > msstab[mssind+1]; mssind++)
                ;
@@ -79,14 +79,11 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
  * Check if a ack sequence number is a valid syncookie. 
  * Return the decoded mss if it is, or 0 if not.
  */
-static inline int cookie_check(struct sk_buff *skb, __u32 cookie) 
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
 {
        __u32 seq; 
        __u32 mssind;
 
-       if ((jiffies - tcp_lastsynq_overflow) > TCP_TIMEOUT_INIT)
-               return 0; 
-
        seq = ntohl(skb->h.th->seq)-1; 
        mssind = check_tcp_syn_cookie(cookie,
                                      skb->nh.iph->saddr, skb->nh.iph->daddr,
@@ -134,6 +131,8 @@ cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt)
                return sk;
        if (!skb->h.th->ack)
                return sk; 
+       if (time_after(jiffies, sk->tp_pinfo.af_tcp.last_synq_overflow + TCP_TIMEOUT_INIT))
+               return 0; 
 
        mss = cookie_check(skb, cookie);
        if (mss == 0) {