]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.0.36pre16 2.0.36pre16
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:12:03 +0000 (15:12 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:12:03 +0000 (15:12 -0500)
This has taken some time in order to get internal testing of the tcp state
machine fix done. Will people stress the following bits particularly in this
pre-patch

Booting on a 1Gig+ machine (I dont have one alas)
TCP
Weird CPUs (Cyrix/TI 486DLC etc)

31 files changed:
Documentation/Configure.help
Documentation/networking/rcpci45 [new file with mode: 0644]
Documentation/specialix.txt
arch/i386/kernel/head.S
arch/i386/kernel/setup.c
drivers/char/mem.c
drivers/char/specialix.c
drivers/char/specialix_io8.h
drivers/net/Config.in
drivers/net/Makefile
drivers/net/de4x5.c
drivers/net/rcif.h [new file with mode: 0644]
drivers/net/rcmtl.c [new file with mode: 0644]
drivers/net/rcmtl.h [new file with mode: 0644]
drivers/net/rcpci45.c [new file with mode: 0644]
drivers/net/shaper.c
drivers/pci/pci.c
fs/buffer.c
fs/fat/file.c
fs/vfat/namei.c
include/asm-i386/bugs.h
include/linux/pci.h
ipc/shm.c
mm/vmscan.c
net/core/firewall.c
net/core/sock.c
net/ipv4/tcp_input.c
net/rose/af_rose.c
net/rose/rose_subr.c
net/socket.c
net/unix/garbage.c

index 5223614d56c5de40f3043753e2d3ecbd80b97b05..6e0d12f1dacc76a2efec8c2c8aa03fad8d82a979 100644 (file)
@@ -3903,6 +3903,24 @@ CONFIG_RISCOM8
   read the file Documentation/riscom8.txt. Also it's possible to say
   M here and compile this driver as kernel loadable module.
 
+Specialix IO8+ card support
+CONFIG_SPECIALIX
+  This is a driver for the Specialix IO8+ multiport card (both the
+  ISA and the PCI version), that gives you 8 serial ports. You would 
+  need a card like this to connect more than two modems to your linux 
+  box, for instance in order to become a BBS. If you have a card like 
+  that, say Y here and read the file Documentation/specialix.txt. Also 
+  it's possible to say M here and compile this driver as kernel 
+  loadable module.
+
+Specialix DTR/RTS pin is RTS
+CONFIG_SPECIALIX_RTSCTS
+  The Specialix card can only support either RTS or DTR. When this
+  option is off, the driver will use the pin as "DTR" when the tty is
+  in software handshake mode. When this option is on or hardware 
+  handshake is on, it will always be RTS. Read the file 
+  Documentation/specialix.txt for more information. 
+
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a driver for a card that gives you many serial ports. You
diff --git a/Documentation/networking/rcpci45 b/Documentation/networking/rcpci45
new file mode 100644 (file)
index 0000000..abbbaf9
--- /dev/null
@@ -0,0 +1,85 @@
+\r
+\r
+Application Information\r
+\r
+The included application, called "rcc" (for RedCreek Control), is an \r
+example of a user-space application (i.e., not running within kernel\r
+space).  It issues ioctl commands to communicate with the PCI driver.  \r
+It is intended for reference only.  It can currently report any of \r
+the following information:\r
+\r
+   - PCI driver information ("getinfo")\r
+   - card statistics ("getstats")\r
+   - card's ip address & netmask ("getipnmask")\r
+   - card's mac address ("getmac")\r
+   - current speed ("getspeed")\r
+   - firmware version string ("getfirmware")\r
+   - status of the link (up or down) ("getstatus")\r
+\r
+This program needs to run as root, to avoid encountering permission \r
+problems.  An alternative is to change the permission and ownership\r
+so that it runs as a setuid root process (for example, "chown \r
+root.root rcc; chmod u+s rcc").\r
+\r
+\r
+Quick PCI driver background\r
+\r
+The adapter has its own IP and mac addresses which you have to\r
+assign using the RedCreek manager (assuming the adapter is\r
+running 3.X firmware).  Your linux box will not know anything \r
+about the adapter's IP address -- ie, the adapter will show up \r
+as a regular nic.  You will assign the linux box IP address using \r
+the "ifconfig" command, as mentioned below.\r
+\r
+To compile the driver, simply type "make".  \r
+This, of course, assumes that you have GNU compiler environment\r
+already setup on a linux box.  The .c and .h files were copied \r
+to a dos filesystem (the floppy), so you may have to use "dos2unix" to \r
+convert it back to a unix text file.  Keep in mind that the driver\r
+currently works with kernels 2.0.X only.  Furthermore, it was only\r
+tested with kernel 2.0.34.  There is work being done on porting the\r
+driver to the 2.1.X kernel, however, it's still incomplete.\r
+\r
+When the compile is done, you'll send up with three object files\r
+related to the driver: rcmtl.o, rcpci45.o, and rc.o;  rcmtl.o\r
+is the RedCreek API message layer; rcpci45.o is the upper level\r
+Linux driver which contains the interface to the kernel.  Finally,\r
+since the driver is compiled as a loadable module, rcmtl.o and\r
+rcpci45.o are linked together into a third file, rc.o, which is the\r
+actual driver.  \r
+\r
+To load the driver:\r
+\r
+"insmod rc"\r
+\r
+If you are in console mode, you'll see a few messages send by the\r
+driver.  One of the messages will indicated how many adapters were\r
+found; the messages are also stored in /var/log/messages, so they\r
+can be viewed later.  If you are running X, then you'll have to \r
+view the messages by examining /var/log/messages.\r
+\r
+The adapter will show up as a regular nic.  Thus, if you have only\r
+one nic (the pci card) in your box, you would at this point configure\r
+it with the following commands:\r
+\r
+mandatory:\r
+"ifconfig eth0 <your linux box IP address (NOT the IP address of the \r
+                adapter!>"\r
+"route add -net <your network address> eth0"\r
+\r
+optional (if you want to be able to access other networks):\r
+"route add default gw <your default gateway IP address> eth0"\r
+\r
+Done.  Type "ifconfig" to see "eth0" and the packet count, as well\r
+as the IP address, net mask, etc.\r
+\r
+To unload the driver, you first have to shutdown the interface:\r
+\r
+"ifconfig eth0 down"\r
+\r
+Then you unload the driver with "rmmod rc".\r
+\r
+\r
+For technical support, please send email to Pete Popov at \r
+ppopov@redcreek.com.  Please have as complete of a description of\r
+the problem as possible.\r
index cb4eeb7cb7424f3c1ee2f8c6ec73655e7a7a5c8c..75e80cde8c2c2c0f3e3b4500f6864cd25dd97836 100644 (file)
       written by Dmitry Gorodchanin. The specialix IO8+ card
       programming information was obtained from the CL-CD1865 Data
       Book, and Specialix document number 6200059: IO8+ Hardware
-      Functional Specification.
+      Functional Specification, augmented by document number 6200088:
+      Merak Hardware Functional Specification. (IO8+/PCI is also 
+      called Merak)
+
 
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License as
@@ -44,10 +47,10 @@ instead of in a manual that can get lost. Ever misplace your Linux
 kernel sources?  And the manual of one of the boards in your computer?
 
 
-Adresses and interrupts
-=======================
+Addresses and interrupts
+========================
 
-Addres dip switch settings:
+Address dip switch settings:
 The dip switch sets bits 2-9 of the IO address. 
 
        9 8 7 6 5 4 3 2 
@@ -67,6 +70,9 @@ haven't the foggiest why. My Specialix card is now at 0x180.  My
 other computer runs just fine with the Specialix card at 0x100....
 The card occupies 4 addresses, but actually only two are really used.
 
+The PCI version doesn't have any dip switches. The BIOS assigns
+an IO address. 
+
 The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260.  If
 that causes trouble for you, please report that. I'll remove
 autoprobing then.
@@ -75,6 +81,9 @@ The driver will tell the card what IRQ to use, so you don't have to
 change any jumpers to change the IRQ. Just use a command line
 argument (irq=xx) to the insmod program to set the interrupt.
 
+The BIOS assigns the IRQ on the PCI version. You have no say in what
+IRQ to use in that case. 
+
 If your specialix cards are not at the default locations, you can use
 the kernel command line argument "specialix=io0,irq0,io1,irq1...".
 Here "io0" is the io address for the first card, and "irq0" is the
@@ -99,6 +108,32 @@ to the command line. This would become
 
 in your /etc/lilo.conf file if you use lilo. 
 
+The Specialix driver is slightly odd: It allows you to have the second
+or third card detected without having a first card. This has
+advantages and disadvantages. A slot that isn't filled by an ISA card,
+might be filled if a PCI card is detected. Thus if you have an ISA
+card at 0x250 and a PCI card, you would get:
+
+sx0: specialix IO8+ Board at 0x100 not found.
+sx1: specialix IO8+ Board at 0x180 not found.
+sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B.
+sx3: specialix IO8+ Board at 0x260 not found.
+sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+This would happen if you don't give any probe hints to the driver. 
+If you would specify:
+
+   specialix=0x250,11
+
+you'd get the following messages:
+
+sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B.
+sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+ISA probing is aborted after the IO address you gave is exhausted, and
+the PCI card is now detected as the second card. The ISA card is now
+also forced to IRQ11....
+
 
 Baud rates
 ==========
@@ -111,27 +146,33 @@ The Specialix card uses a 25MHz crystal (in times two mode, which in
 fact is a divided by two mode). This is not enough to reach the rated
 115k2 on all ports at the same time. With this clock rate you can only
 do 37% of this rate. This means that at 115k2 on all ports you are
-going to loose characters (The chip cannot handle that many incoming
+going to lose characters (The chip cannot handle that many incoming
 bits at this clock rate.) (Yes, you read that correctly: there is a
 limit to the number of -=bits=- per second that the chip can handle.)
 
 If you near the "limit" you will first start to see a graceful
 degradation in that the chip cannot keep the transmitter busy at all
 times. However with a central clock this slow, you can also get it to
-miss incoming characters.
+miss incoming characters. The driver will print a warning message when
+you are outside the official specs. The messages usually show up in
+the file /var/log/messages .
 
 The specialix card cannot reliably do 115k2. If you use it, you have
 to do "extensive testing" (*) to verify if it actually works.
 
 When "mgetty" communicates with my modem at 115k2 it reports:
 got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a]
-                            ^^^^ ^^^^ ^^^^ 
+                            ^^^^ ^^^^    ^^^^ 
 
 The three characters that have the "^^^" under them have suffered a
 bit error in the highest bit. In conclusion: I've tested it, and found
-that it simply DOESN"T work for me. I also suspect that this is also
+that it simply DOESN'T work for me. I also suspect that this is also
 caused by the baud rate being just a little bit out of tune. 
 
+I upgraded the crystal to 66Mhz on one of my Specialix cards. Works
+great! Contact me for details. (Voids warranty, requires a steady hand
+and more such restrictions....)
+
 
 (*) Cirrus logic CD1864 databook, page 40.
 
@@ -248,7 +289,7 @@ for this.
 Ports and devices
 =================
 
-Port 0 is the one furthest from the ISA connector.
+Port 0 is the one furthest from the card-edge connector.
 
 Devices:
 
@@ -265,11 +306,21 @@ do
 done
 echo ""
 
+If your system doesn't come with these devices preinstalled, bug your
+linux-vendor about this. They have had ample time to get this
+implemented by now.
 
 You cannot have more than 4 boards in one computer. The card only
 supports 4 different interrupts. If you really want this, contact me
 about this and I'll give you a few tips (requires soldering iron)....
 
+If you have enough PCI slots, you can probably use more than 4 PCI
+versions of the card though.... 
+
+The PCI version of the card cannot adhere to the mechanical part of
+the PCI spec because the 8 serial connectors are simply too large. If
+it doesn't fit in your computer, bring back the card.
+
 
 ------------------------------------------------------------------------
 
index 3fd3af0be1fe7fd94c1ffd0901a068b95e8a4f65..d4164857cd21493fb119c42766d8876dd1a507ba 100644 (file)
@@ -216,15 +216,16 @@ is486x:   xor %ax,%ax
        orb $0x10,%bx           # by setting bit 4
        setCx86($0xc3,%bx)
 
+        getCx86($0xfe)          # DIR0 : let's check this is a 6x86(L)
+        andb $0xf0,%ax         # should be 3xh
+       cmpb $0x30,%ax          # 
+       jne n6x86
+
        getCx86($0xe8)          # now we can get CCR4
        orb $0x80,%ax           # and set bit 7 (CPUIDEN)
        movb %ax,%bx            # to enable CPUID execution
        setCx86($0xe8,%bx)
 
-        getCx86($0xfe)          # DIR0 : let's check this is a 6x86(L)
-        andb $0xf0,%ax         # should be 3xh
-       cmpb $0x30,%ax          # 
-       jne n6x86
         getCx86($0xe9)          # CCR5 : we reset the SLOP bit
         andb $0xfd,%ax         # so that udelay calculation
         movb %ax,%bx           # is correct on 6x86(L) CPUs
index bcebba70ad6332dbdd783c05f597c1af9bc6b4d7..7fb42bff3acbc6965dece1560c7be259d2c03597 100644 (file)
@@ -165,6 +165,17 @@ void setup_arch(char **cmdline_p,
        if (memory_end > 16*1024*1024)
                memory_end = 16*1024*1024;
 #endif
+
+       /*
+        *      The 1Gig sanity checker.
+        */
+        
+       if (memory_end > 980*1024*1024)
+       {
+               printk(KERN_WARNING "Warning only 980Mb will be used.\n");
+               memory_end = 980 * 1024 * 1024;
+       }
+       
        if (!MOUNT_ROOT_RDONLY)
                root_mountflags &= ~MS_RDONLY;
        memory_start = (unsigned long) &_end;
index 79387fbd1badbf2800b09f8b15e2ce28d624c60d..b2783a64d452a144795b1f5cdbc16a18bedabc83 100644 (file)
@@ -400,7 +400,7 @@ int chr_dev_init(void)
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || \
+    defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || defined(CONFIG_WDT) || \
     defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
        misc_init();
 #endif
index 3e772fca8abc537fa6a21b795db744c222948aea..cc988bb638310aacf876ecc53e092cc45486c626 100644 (file)
  *                Changed the specialix=... format to include interrupt.
  * Revision 1.7:  May 27 1997
  *                Made many more debug printk's a compile time option.
+ * Revision 1.8:  Port to 2.1 kernel. -- Not here.
+ *
+ * Revision 1.9:  October 1 1998
+ *                Support for the PCI version of the card.
  * 
  */
 
-#define VERSION "1.7"
+#define VERSION "1.9"
 
 
 /*
@@ -84,7 +88,8 @@
 #include <linux/delay.h>
 #include <linux/tqueue.h>
 #include <linux/version.h>
-
+#include <linux/pci.h>
+#include <linux/bios32.h>
 
 /* ************************************************************** */
 /* * This section can be removed when 2.0 becomes outdated....  * */
@@ -170,7 +175,6 @@ DECLARE_TASK_QUEUE(tq_specialix);
 #define SPECIALIX_TYPE_NORMAL  1
 #define SPECIALIX_TYPE_CALLOUT 2
 
-static struct specialix_board * IRQ_to_board[16] = { NULL, } ;
 static struct tty_driver specialix_driver, specialix_callout_driver;
 static int    specialix_refcount = 0;
 static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT] = { NULL, };
@@ -322,23 +326,28 @@ extern inline void sx_wait_CCR_off(struct specialix_board  * bp)
 
 extern inline int sx_check_io_range(struct specialix_board * bp)
 {
-       return check_region (bp->base, SX_IO_SPACE);
+       return check_region (bp->base, 
+                      bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
 }
 
 
 extern inline void sx_request_io_range(struct specialix_board * bp)
 {
-       request_region(bp->base, SX_IO_SPACE, "specialix IO8+" );
+       request_region(bp->base,
+                      bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE, 
+                      "specialix IO8+" );
 }
 
 
 extern inline void sx_release_io_range(struct specialix_board * bp)
 {
-       release_region(bp->base, SX_IO_SPACE);
+       release_region(bp->base,
+                      bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
 }
 
        
 /* Must be called with enabled interrupts */
+/* Ugly. Don't use this for anything else than initialization code */
 extern inline void sx_long_delay(unsigned long delay)
 {
        unsigned long i;
@@ -354,6 +363,8 @@ int sx_set_irq ( struct specialix_board *bp)
        int virq;
        int i;
 
+       if (bp->flags & SX_BOARD_IS_PCI) 
+               return 1;
        switch (bp->irq) {
        /* In the same order as in the docs... */
        case 15: virq = 0;break;
@@ -481,9 +492,14 @@ static int sx_probe(struct specialix_board *bp)
        printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n", 
                board_No(bp),  val1, val2);
 #endif
-       if (val1 != 0xb2) {
-               printk(KERN_INFO "sx%d: specialix IO8+ ID at 0x%03x not found.\n",
-                      board_No(bp), bp->base);
+       /* They managed to switch the bit order between the docs and
+          the IO8+ card. The new PCI card now conforms to old docs.
+          They changed the PCI docs to reflect the situation on the
+          old card. */
+       val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
+       if (val1 != val2) {
+               printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
+                      board_No(bp), val2, bp->base, val1);
                return 1;
        }
 
@@ -865,7 +881,7 @@ static void sx_interrupt(int irq, void * dev_id, struct pt_regs * regs)
        unsigned long loop = 0;
        int saved_reg;
 
-       bp = IRQ_to_board[irq];
+       bp = dev_id;
        
        if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
 #ifdef SPECIALIX_DEBUG 
@@ -921,6 +937,25 @@ static void sx_interrupt(int irq, void * dev_id, struct pt_regs * regs)
  *  Routines for open & close processing.
  */
 
+void turn_ints_off (struct specialix_board *bp)
+{
+       if (bp->flags & SX_BOARD_IS_PCI) {
+               /* This was intended for enabeling the interrupt on the
+                * PCI card. However it seems that it's already enabled
+                * and as PCI interrupts can be shared, there is no real
+                * reason to have to turn it off. */
+       }
+       (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+}
+
+void turn_ints_on (struct specialix_board *bp)
+{
+       if (bp->flags & SX_BOARD_IS_PCI) {
+               /* play with the PCI chip. See comment above */
+       }
+       (void) sx_in (bp, 0); /* Turn ON interrupts. */
+}
+
 
 /* Called with disabled interrupts */
 extern inline int sx_setup_board(struct specialix_board * bp)
@@ -930,14 +965,12 @@ extern inline int sx_setup_board(struct specialix_board * bp)
        if (bp->flags & SX_BOARD_ACTIVE) 
                return 0;
 
-       error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", NULL);
+       error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
 
        if (error) 
                return error;
 
-       IRQ_to_board[bp->irq] = bp;
-       (void) sx_in (bp, 0); /* Turn ON interrupts. */
-
+       turn_ints_on (bp);
        bp->flags |= SX_BOARD_ACTIVE;
 
        MOD_INC_USE_COUNT;
@@ -953,11 +986,13 @@ extern inline void sx_shutdown_board(struct specialix_board *bp)
        
        bp->flags &= ~SX_BOARD_ACTIVE;
        
-       free_irq(bp->irq, NULL);
-       (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+#if SPECIALIX_DEBUG > 2
+       printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
+#endif
+       free_irq(bp->irq, bp);
+
+       turn_ints_off (bp);
 
-       IRQ_to_board[bp->irq] = NULL;
-       
        MOD_DEC_USE_COUNT;
 }
 
@@ -1042,12 +1077,14 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
                /* Page 48 of version 2.0 of the CL-CD1865 databook */
                if (tmp >= 12) {
                        printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
-                               "Performance degradation is possible.\n",
+                               "Performance degradation is possible.\n"
+                               "Read specialix.txt for more info.\n",
                                port_No (port), tmp);
                } else {
                        printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
                                "Warning: overstressing Cirrus chip. "
-                                "This might not work.\n", 
+                               "This might not work.\n"
+                               "Read specialix.txt for more info.\n", 
                                port_No (port), tmp);
                }
        }
@@ -2150,7 +2187,6 @@ static int sx_init_drivers(void)
                return 1;
        }
        init_bh(SPECIALIX_BH, do_specialix_bh);
-       memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
        memset(&specialix_driver, 0, sizeof(specialix_driver));
        specialix_driver.magic = TTY_DRIVER_MAGIC;
        specialix_driver.name = "ttyW";
@@ -2240,7 +2276,7 @@ static void sx_release_drivers(void)
 void specialix_setup(char *str, int * ints)
 {
        int i;
-        
+       
        for (i=0;i<SX_NBOARD;i++) {
                sx_board[i].base = 0;
        }
@@ -2261,8 +2297,12 @@ int specialix_init(void)
 {
        int i;
        int found = 0;
+#ifdef CONFIG_PCI
+       int pci_index;
+       unsigned char pci_bus, pci_device_fn;
+#endif
 
-       printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997.\n");
+       printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
        printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
 #ifdef CONFIG_SPECIALIX_RTSCTS
        printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
@@ -2277,6 +2317,36 @@ int specialix_init(void)
                if (sx_board[i].base && !sx_probe(&sx_board[i]))
                        found++;
 
+#ifdef CONFIG_PCI
+       i=0;
+       pci_index = 0;
+       while ((i < SX_NBOARD) && (pci_index < 0xff)) {
+               unsigned char tbyte;
+               unsigned int tint;
+               if (sx_board[i].flags & SX_BOARD_PRESENT) {
+                       i++;
+                       continue;
+               }
+               if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+                                        PCI_DEVICE_ID_SPECIALIX_IO8,
+                                        pci_index, &pci_bus, &pci_device_fn)
+                   != PCIBIOS_SUCCESSFUL)
+                       break;
+               pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                        PCI_INTERRUPT_LINE, &tbyte);
+               sx_board[i].irq = tbyte;
+
+               pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                         PCI_BASE_ADDRESS_2, &tint);
+               /* Mask out the fact that it's IO-space */
+               sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; 
+               sx_board[i].flags |= SX_BOARD_IS_PCI;
+               if (!sx_probe(&sx_board[i]))
+                       found ++;
+               pci_index++;
+       }
+#endif
+
        if (!found) {
                sx_release_drivers();
                printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
@@ -2293,7 +2363,8 @@ int irq [SX_NBOARD] = {0,};
 
 /*
  * You can setup up to 4 boards.
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
+ * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
+ * You should specify the IRQs too in that case "irq=....,...". 
  * 
  * More than 4 boards in one computer is not possible, as the card can
  * only use 4 different interrupts. 
index e8fc54658facf150e48c0477d1bdca687c28cdfd..84172810327f2887e6d88633340131859a3b1d07 100644 (file)
 
 #ifdef __KERNEL__
 
-#define SX_NBOARD              4
+/* You can have max 4 ISA cards in one PC, and I recommend not much 
+more than a few  PCI versions of the card. */
+
+#define SX_NBOARD              8
+
 /* NOTE: Specialix decoder recognizes 4 addresses, but only two are used.... */
 #define SX_IO_SPACE             4
+/* The PCI version decodes 8 addresses, but still only 2 are used. */
+#define SX_PCI_IO_SPACE         8
+
 /* eight ports per board. */
 #define SX_NPORT               8
 #define SX_BOARD(line)         ((line) / SX_NPORT)
 #define SX_PORT(line)          ((line) & (SX_NPORT - 1))
 
-
 #define SX_DATA_REG 0     /* Base+0 : Data register */
 #define SX_ADDR_REG 1     /* base+1 : Address register. */
 
@@ -93,6 +99,7 @@ struct specialix_board {
 
 #define SX_BOARD_PRESENT       0x00000001
 #define SX_BOARD_ACTIVE                0x00000002
+#define SX_BOARD_IS_PCI                0x00000004
 
 
 struct specialix_port {
index 3b16f93b3ca859c55e7484cbff9920b363d40106..5078b58a4ba8bd26dfb9d9ae7bc8f38809fde99d 100644 (file)
@@ -147,4 +147,5 @@ fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
+  tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
 fi
index ce4e77944137d18ada6ede6d3033baa4f600ed9f..a084af63f6edb13604b0179fb0177059bcb4e50c 100644 (file)
@@ -667,11 +667,24 @@ else
   endif
 endif
 
+
+
+ifeq ($(CONFIG_RCPCI),y)
+L_OBJS += rcpci.o
+else
+  ifeq ($(CONFIG_RCPCI),m)
+  M_OBJS += rcpci.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
        rm -f core *.o *.a *.s
 
+rcpci.o: rcpci45.o rcmtl.o
+       $(LD) -r -o rcpci.o rcpci45.o rcmtl.o
+
 wd.o:  wd.c CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
 
index 6a3b590e7d5e21da7279dc7b7ef23ede80d48e16..b6364cd6c30bda76a27eb8f273f531a215354251 100644 (file)
@@ -982,7 +982,7 @@ static int     get_hw_addr(struct device *dev);
 static void    srom_repair(struct device *dev, int card);
 static int     test_bad_enet(struct device *dev, int status);
 static int     an_exception(struct bus_type *lp);
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static void    eisa_probe(struct device *dev, u_long iobase);
 #endif
 static void    pci_probe(struct device *dev, u_long iobase);
@@ -1033,7 +1033,7 @@ static int loading_module = 0;
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 static int lastEISA = 0;
 #else
@@ -1106,7 +1106,7 @@ de4x5_probe(struct device *dev))
 {
     u_long iobase = dev->base_addr;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
     eisa_probe(dev, iobase);
 #endif
     if (lastEISA == MAX_EISA_SLOTS) {
@@ -2034,7 +2034,7 @@ SetMulticastFilter(struct device *dev)
     return;
 }
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
@@ -2102,7 +2102,7 @@ eisa_probe(struct device *dev, u_long ioaddr))
 
     return;
 }
-#endif                         /* !(__sparc_v9__) && !(__powerpc__) */
+#endif          /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__)*/
 
 /*
 ** PCI bus I/O device probe
@@ -5882,7 +5882,7 @@ count_adapters(void)
     u_int class = DE4X5_CLASS_CODE;
     u_int device;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
     char name[DE4X5_STRLEN];
     u_long iobase = 0x1000;
 
diff --git a/drivers/net/rcif.h b/drivers/net/rcif.h
new file mode 100644 (file)
index 0000000..fd8168f
--- /dev/null
@@ -0,0 +1,235 @@
+/*\r
+** *************************************************************************\r
+**\r
+**\r
+**     R C I F . H\r
+**\r
+**\r
+**  RedCreek InterFace include file.\r
+**\r
+**  ---------------------------------------------------------------------\r
+**  ---     Copyright (c) 1998, RedCreek Communications Inc.          ---\r
+**  ---                   All rights reserved.                        ---\r
+**  ---------------------------------------------------------------------\r
+**\r
+** File Description:\r
+**\r
+** Header file private ioctl commands.\r
+**\r
+**\r
+**  This program is free software; you can redistribute it and/or modify\r
+**  it under the terms of the GNU General Public License as published by\r
+**  the Free Software Foundation; either version 2 of the License, or\r
+**  (at your option) any later version.\r
+\r
+**  This program is distributed in the hope that it will be useful,\r
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+**  GNU General Public License for more details.\r
+\r
+**  You should have received a copy of the GNU General Public License\r
+**  along with this program; if not, write to the Free Software\r
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+**\r
+***************************************************************************/\r
+\r
+#ifndef RCIF_H\r
+#define RCIF_H\r
+\r
+/* The following protocol revision # should be incremented every time\r
+   a new protocol or new structures are used in this file. */\r
+int USER_PROTOCOL_REV = 1;     /* used to track different protocol revisions */\r
+\r
+/* define a single TCB & buffer */\r
+typedef struct                  /* a single buffer */\r
+{\r
+     U32 context;               /* context */\r
+     U32 scount;                /* segment count */\r
+     U32 size;                  /* segment size */\r
+     U32 addr;                  /* segment physical address */\r
+}\r
+__attribute__((packed))\r
+singleB, *psingleB ;\r
+typedef struct                  /* a single TCB */\r
+{\r
+     /*\r
+     **  +-----------------------+\r
+     **  |         1             |  one buffer in the TCB\r
+     **  +-----------------------+\r
+     **  |  <user's Context>     |  user's buffer reference\r
+     **  +-----------------------+\r
+     **  |         1             |  one segment buffer\r
+     **  +-----------------------+                            _\r
+     **  |    <buffer size>      |  size                       \ \r
+     **  +-----------------------+                              \ segment descriptor\r
+     **  |  <physical address>   |  physical address of buffer  /\r
+     **  +-----------------------+                            _/\r
+     */\r
+     U32 bcount;                /* buffer count */\r
+     singleB b;                 /* buffer */\r
+\r
+}\r
+__attribute__((packed))\r
+singleTCB, *psingleTCB;\r
+\r
+/*\r
+   When adding new entries, please add all 5 related changes, since \r
+   it helps keep everything consistent:\r
+      1) User structure entry\r
+      2) User data entry\r
+      3) Structure short-cut entry\r
+      4) Data short-cut entry\r
+      5) Command identifier entry\r
+\r
+   For Example ("GETSPEED"):\r
+      1) struct  RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed;\r
+      2) struct  RCgetspeed_tag *getspeed;\r
+      3) #define RCUS_GETSPEED  data.RCgetspeed;\r
+      4) #define RCUD_GETSPEED  _RC_user_data.getspeed\r
+      5) #define RCUC_GETSPEED  0x02\r
+  \r
+   Notes for the "GETSPEED" entry, above:\r
+      1) RCgetspeed      - RC{name}\r
+         RCgetspeed_tag  - RC{name}_tag\r
+         LinkSpeedCode   - create any structure format desired (not too large,\r
+                           since memory will be unioned with all other entries)\r
+      2) RCgetspeed_tag  - RC{name}_tag chosen in #1\r
+         getspeed        - arbitrary name (ptr to structure in #1)\r
+      3) RCUS_GETSPEED   - RCUS_{NAME}   ("NAME" & "name" do not have to the same)\r
+         data.RCgetspeed - data.RC{name}  ("RC{name}" from #1)\r
+      4) RCUD_GETSPEED   - _RC_user_data.getspeed  ("getspeed" from #2)\r
+      5) RCUC_GETSPEED   - unique hex identifier entry.\r
+*/\r
+\r
+typedef struct RC_user_tag RCuser_struct;\r
+\r
+/* 1) User structure entry */\r
+struct RC_user_tag\r
+{\r
+    int cmd;\r
+    union\r
+    {\r
+        /* GETINFO structure */\r
+        struct RCgetinfo_tag {\r
+            unsigned long int mem_start;\r
+            unsigned long int mem_end;\r
+            unsigned long int base_addr;\r
+            unsigned char irq;\r
+            unsigned char dma;\r
+            unsigned char port;\r
+        } RCgetinfo;                    /* <---- RCgetinfo */\r
+     \r
+        /* GETSPEED structure */\r
+        struct  RCgetspeed_tag {\r
+            U32 LinkSpeedCode;\r
+        } RCgetspeed;                   /* <---- RCgetspeed */\r
+  \r
+        /* GETFIRMWAREVER structure */\r
+        #define FirmStringLen 80\r
+        struct RCgetfwver_tag {\r
+            U8 FirmString[FirmStringLen];\r
+        } RCgetfwver;                   /* <---- RCgetfwver */\r
+  \r
+        /* GETIPANDMASK structure */\r
+        struct RCgetipnmask_tag {\r
+            U32 IpAddr;\r
+            U32 NetMask;\r
+        } RCgetipandmask;               /* <---- RCgetipandmask */\r
+\r
+        /* GETMAC structure */\r
+        #define MAC_SIZE 10\r
+        struct RCgetmac_tag {\r
+            U8 mac[MAC_SIZE];\r
+        } RCgetmac;                     /* <---- RCgetmac */\r
+\r
+        /* GETLINKSTATUS structure */\r
+        struct RCgetlnkstatus_tag {\r
+            U32 ReturnStatus;\r
+        } RCgetlnkstatus;               /* <---- RCgetlnkstatus */\r
+\r
+        /* GETLINKSTATISTICS structure */\r
+        struct RCgetlinkstats_tag {\r
+            RCLINKSTATS StatsReturn;\r
+        } RCgetlinkstats;               /* <---- RCgetlinkstats */\r
+\r
+        /* DEFAULT structure (when no command was recognized) */\r
+        struct RCdefault_tag {\r
+            int rc;\r
+        } RCdefault;                    /* <---- RCdefault */\r
+\r
+    } data;\r
+\r
+};   /* struct RC_user_tag { ... } */\r
+\r
+/* 2) User data entry */\r
+/* RCUD = RedCreek User Data */\r
+union RC_user_data_tag {        /* structure tags used are taken from RC_user_tag structure above */\r
+    struct RCgetinfo_tag      *getinfo;\r
+    struct RCgetspeed_tag     *getspeed;\r
+    struct RCgetfwver_tag     *getfwver;\r
+    struct RCgetipnmask_tag   *getipandmask;\r
+    struct RCgetmac_tag       *getmac;\r
+    struct RCgetlnkstatus_tag *getlinkstatus;\r
+    struct RCgetlinkstats_tag *getlinkstatistics;\r
+    struct RCdefault_tag      *rcdefault;\r
+} _RC_user_data;  /* declare as a global, so the defines below will work */\r
+\r
+/* 3) Structure short-cut entry */\r
+/* define structure short-cuts */   /* structure names are taken from RC_user_tag structure above */\r
+#define RCUS_GETINFO           data.RCgetinfo;\r
+#define RCUS_GETSPEED          data.RCgetspeed;\r
+#define RCUS_GETFWVER          data.RCgetfwver;\r
+#define RCUS_GETIPANDMASK      data.RCgetipandmask;\r
+#define RCUS_GETMAC            data.RCgetmac;\r
+#define RCUS_GETLINKSTATUS     data.RCgetlnkstatus;\r
+#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;\r
+#define RCUS_DEFAULT           data.RCdefault;\r
+\r
+/* 4) Data short-cut entry */\r
+/* define data short-cuts */    /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */\r
+#define RCUD_GETINFO           _RC_user_data.getinfo\r
+#define RCUD_GETSPEED          _RC_user_data.getspeed\r
+#define RCUD_GETFWVER          _RC_user_data.getfwver\r
+#define RCUD_GETIPANDMASK      _RC_user_data.getipandmask\r
+#define RCUD_GETMAC            _RC_user_data.getmac\r
+#define RCUD_GETLINKSTATUS     _RC_user_data.getlinkstatus\r
+#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics\r
+#define RCUD_DEFAULT           _RC_user_data.rcdefault\r
+\r
+/* 5) Command identifier entry */\r
+/* define command identifiers */\r
+#define RCUC_GETINFO            0x01\r
+#define RCUC_GETSPEED           0x02\r
+#define RCUC_GETFWVER           0x03\r
+#define RCUC_GETIPANDMASK       0x04\r
+#define RCUC_GETMAC             0x05\r
+#define RCUC_GETLINKSTATUS      0x06\r
+#define RCUC_GETLINKSTATISTICS  0x07\r
+#define RCUC_DEFAULT            0xff\r
+\r
+/* define ioctl commands to use, when talking to RC 45/PCI driver */\r
+#define RCU_PROTOCOL_REV         SIOCDEVPRIVATE\r
+#define RCU_COMMAND              SIOCDEVPRIVATE+1\r
+\r
+/*\r
+   Intended use for the above defines is shown below (GETINFO, as this example):\r
+\r
+      RCuser_struct RCuser;           // declare RCuser structure\r
+      struct ifreq ifr;               // declare an interface request structure\r
+\r
+      RCuser.cmd = RCUC_GETINFO;           // set user command to GETINFO\r
+      ifr->ifr_data = (caddr_t) &RCuser;   // set point to user structure\r
+\r
+      sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);   // get a socket\r
+      ioctl(sock, RCU_COMMAND, &ifr);                  // do ioctl on socket\r
+\r
+      RCUD_GETINFO = &RCuser.RCUS_GETINFO;   // set data pointer for GETINFO\r
+\r
+      // print results\r
+      printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n",\r
+              RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end,\r
+              RCUD_GETINFO->base_addr, RCUD_GETINFO->irq);\r
+*/\r
+\r
+#endif   /* RCIF_H */\r
+\r
diff --git a/drivers/net/rcmtl.c b/drivers/net/rcmtl.c
new file mode 100644 (file)
index 0000000..db1509a
--- /dev/null
@@ -0,0 +1,2058 @@
+/*
+** *************************************************************************
+**
+**
+**     R C M T L . C             $Revision: 1.1 $
+**
+**
+**  RedCreek Message Transport Layer program module.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1997-1998, RedCreek Communications Inc.     ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Host side message transport layer.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+***************************************************************************/
+
+#undef DEBUG
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+
+#define dprintf kprintf
+
+extern int printk(const char * fmt, ...);
+
+ /* RedCreek LAN device Target ID */
+#define LAN_TARGET_ID  0x10 
+ /* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT  0xA17  
+
+
+/*
+** message structures
+*/
+
+#define    TID_SZ                                  12
+#define    FUNCTION_SZ                             8
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define    TRL_SINGLE_FIXED_LENGTH           0x00
+#define    TRL_SINGLE_VARIABLE_LENGTH        0x40
+#define    TRL_MULTIPLE_FIXED_LENGTH         0x80
+
+/* LAN Class specific functions */
+
+#define    LAN_PACKET_SEND                         0x3B
+#define    LAN_SDU_SEND                            0x3D
+#define    LAN_RECEIVE_POST                        0x3E
+#define    LAN_RESET                               0x35
+#define    LAN_SHUTDOWN                            0x37
+
+/* Private Class specfic function */
+#define    RC_PRIVATE                                 0xFF
+
+/*  RC Executive Function Codes.  */
+
+#define    RC_CMD_ADAPTER_ASSIGN                     0xB3
+#define    RC_CMD_ADAPTER_READ                       0xB2
+#define    RC_CMD_ADAPTER_RELEASE                    0xB5
+#define    RC_CMD_BIOS_INFO_SET                      0xA5
+#define    RC_CMD_BOOT_DEVICE_SET                    0xA7
+#define    RC_CMD_CONFIG_VALIDATE                    0xBB
+#define    RC_CMD_CONN_SETUP                         0xCA
+#define    RC_CMD_DEVICE_ASSIGN                      0xB7
+#define    RC_CMD_DEVICE_RELEASE                     0xB9
+#define    RC_CMD_HRT_GET                            0xA8
+#define    RC_CMD_ADAPTER_CLEAR                          0xBE
+#define    RC_CMD_ADAPTER_CONNECT                        0xC9
+#define    RC_CMD_ADAPTER_RESET                          0xBD
+#define    RC_CMD_LCT_NOTIFY                         0xA2
+#define    RC_CMD_OUTBOUND_INIT                      0xA1
+#define    RC_CMD_PATH_ENABLE                        0xD3
+#define    RC_CMD_PATH_QUIESCE                       0xC5
+#define    RC_CMD_PATH_RESET                         0xD7
+#define    RC_CMD_STATIC_MF_CREATE                   0xDD
+#define    RC_CMD_STATIC_MF_RELEASE                  0xDF
+#define    RC_CMD_STATUS_GET                         0xA0
+#define    RC_CMD_SW_DOWNLOAD                        0xA9
+#define    RC_CMD_SW_UPLOAD                          0xAB
+#define    RC_CMD_SW_REMOVE                          0xAD
+#define    RC_CMD_SYS_ENABLE                         0xD1
+#define    RC_CMD_SYS_MODIFY                         0xC1
+#define    RC_CMD_SYS_QUIESCE                        0xC3
+#define    RC_CMD_SYS_TAB_SET                        0xA3
+
+
+ /* Init Outbound Q status */
+#define    RC_CMD_OUTBOUND_INIT_IN_PROGRESS          0x01
+#define    RC_CMD_OUTBOUND_INIT_REJECTED             0x02
+#define    RC_CMD_OUTBOUND_INIT_FAILED               0x03
+#define    RC_CMD_OUTBOUND_INIT_COMPLETE             0x04
+
+
+#define    UTIL_NOP                                0x00
+
+
+/* RC Get Status State values */
+
+#define    ADAPTER_STATE_INITIALIZING                  0x01
+#define    ADAPTER_STATE_RESET                         0x02
+#define    ADAPTER_STATE_HOLD                          0x04
+#define    ADAPTER_STATE_READY                         0x05
+#define    ADAPTER_STATE_OPERATIONAL                   0x08
+#define    ADAPTER_STATE_FAILED                        0x10
+#define    ADAPTER_STATE_FAULTED                       0x11
+
+
+/* Defines for Request Status Codes:  Table 3-1 Reply Status Codes.  */
+
+#define    RC_REPLY_STATUS_SUCCESS                    0x00
+#define    RC_REPLY_STATUS_ABORT_DIRTY                0x01
+#define    RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    RC_REPLY_STATUS_ABORT_PARTIAL_TRANSFER     0x03
+#define    RC_REPLY_STATUS_ERROR_DIRTY                0x04
+#define    RC_REPLY_STATUS_ERROR_NO_DATA_TRANSFER     0x05
+#define    RC_REPLY_STATUS_ERROR_PARTIAL_TRANSFER     0x06
+#define    RC_REPLY_STATUS_PROCESS_ABORT_DIRTY        0x07
+#define    RC_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER   0x08
+#define    RC_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER   0x09
+#define    RC_REPLY_STATUS_TRANSACTION_ERROR          0x0A
+#define    RC_REPLY_STATUS_PROGRESS_REPORT            0x80
+
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
+
+#define    RC_DS_SUCCESS                        0x0000
+#define    RC_DS_BAD_KEY                        0x0001
+#define    RC_DS_CHAIN_BUFFER_TOO_LARGE         0x0002
+#define    RC_DS_DEVICE_BUSY                    0x0003
+#define    RC_DS_DEVICE_LOCKED                  0x0004
+#define    RC_DS_DEVICE_NOT_AVAILABLE           0x0005
+#define    RC_DS_DEVICE_RESET                   0x0006
+#define    RC_DS_INAPPROPRIATE_FUNCTION         0x0007
+#define    RC_DS_INSUFFICIENT_RESOURCE_HARD     0x0008
+#define    RC_DS_INSUFFICIENT_RESOURCE_SOFT     0x0009
+#define    RC_DS_INVALID_INITIATOR_ADDRESS      0x000A
+#define    RC_DS_INVALID_MESSAGE_FLAGS          0x000B
+#define    RC_DS_INVALID_OFFSET                 0x000C
+#define    RC_DS_INVALID_PARAMETER              0x000D
+#define    RC_DS_INVALID_REQUEST                0x000E
+#define    RC_DS_INVALID_TARGET_ADDRESS         0x000F
+#define    RC_DS_MESSAGE_TOO_LARGE              0x0010
+#define    RC_DS_MESSAGE_TOO_SMALL              0x0011
+#define    RC_DS_MISSING_PARAMETER              0x0012
+#define    RC_DS_NO_SUCH_PAGE                   0x0013
+#define    RC_DS_REPLY_BUFFER_FULL              0x0014
+#define    RC_DS_TCL_ERROR                      0x0015
+#define    RC_DS_TIMEOUT                        0x0016
+#define    RC_DS_UNKNOWN_ERROR                  0x0017
+#define    RC_DS_UNKNOWN_FUNCTION               0x0018
+#define    RC_DS_UNSUPPORTED_FUNCTION           0x0019
+#define    RC_DS_UNSUPPORTED_VERSION            0x001A
+
+ /* msg header defines for VersionOffset */
+#define RCMSGVER_1   0x0001
+#define SGL_OFFSET_0    RCMSGVER_1
+#define SGL_OFFSET_4    (0x0040 | RCMSGVER_1)
+#define TRL_OFFSET_5    (0x0050 | RCMSGVER_1)
+#define TRL_OFFSET_6    (0x0060 | RCMSGVER_1)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC      0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL        0x2000
+#define MSG_LAST        0x4000
+#define MSG_REPLY       0x8000
+
+  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST  (MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE  0x00040000
+#define FIVE_WORD_MSG_SIZE  0x00050000
+#define SIX_WORD_MSG_SIZE   0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE  0x00090000
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID   0
+#define HOST_TID  1
+
+ /* RedCreek private message codes */
+#define RC_PRIVATE_GET_MAC_ADDR     0x0001/**/ /* OBSOLETE */
+#define RC_PRIVATE_SET_MAC_ADDR     0x0002
+#define RC_PRIVATE_GET_LAN_STATS    0x0003
+#define RC_PRIVATE_GET_LINK_STATUS  0x0004
+#define RC_PRIVATE_SET_LINK_SPEED   0x0005
+#define RC_PRIVATE_SET_IP_AND_MASK  0x0006
+/* #define RC_PRIVATE_GET_IP_AND_MASK  0x0007 */ /* OBSOLETE */
+#define RC_PRIVATE_GET_LINK_SPEED   0x0008
+#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
+/* #define RC_PRIVATE_GET_MAC_ADDR     0x000A *//**/
+#define RC_PRIVATE_GET_IP_AND_MASK  0x000B /**/
+#define RC_PRIVATE_DEBUG_MSG        0x000C
+#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY  0x000D
+
+#define RC_PRIVATE_REBOOT           0x00FF
+
+
+/* RC message header */
+typedef struct _RC_MSG_FRAME 
+{
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:TID_SZ;
+   BF                          InitiatorAddress:TID_SZ;
+   BF                          Function:FUNCTION_SZ;
+   U32                         InitiatorContext;
+   /* SGL[] */ 
+}
+ RC_MSG_FRAME, *PRC_MSG_FRAME;
+
+
+ /* assumed a 16K minus 256 byte space for outbound queue message frames */
+#define MSG_FRAME_SIZE  512
+#define NMBR_MSG_FRAMES 30
+
+/*
+**  Message Unit CSR definitions for RedCreek PCI45 board
+*/
+typedef struct tag_rcatu 
+{
+    volatile unsigned long APICRegSel;  /* APIC Register Select */
+    volatile unsigned long reserved0;
+    volatile unsigned long APICWinReg;  /* APIC Window Register */
+    volatile unsigned long reserved1;
+    volatile unsigned long InMsgReg0;   /* inbound message register 0 */
+    volatile unsigned long InMsgReg1;   /* inbound message register 1 */
+    volatile unsigned long OutMsgReg0;  /* outbound message register 0 */
+    volatile unsigned long OutMsgReg1;  /* outbound message register 1 */
+    volatile unsigned long InDoorReg;   /* inbound doorbell register */
+    volatile unsigned long InIntStat;   /* inbound interrupt status register */
+    volatile unsigned long InIntMask;   /* inbound interrupt mask register */
+    volatile unsigned long OutDoorReg;  /* outbound doorbell register */
+    volatile unsigned long OutIntStat;  /* outbound interrupt status register */
+    volatile unsigned long OutIntMask;  /* outbound interrupt mask register */
+    volatile unsigned long reserved2;
+    volatile unsigned long reserved3;
+    volatile unsigned long InQueue;     /* inbound queue port */
+    volatile unsigned long OutQueue;    /* outbound queue port */
+    volatile unsigned long reserved4;
+    volatile unsigned long reserver5;
+     /* RedCreek extension */
+    volatile unsigned long EtherMacLow;
+    volatile unsigned long EtherMacHi;
+    volatile unsigned long IPaddr;
+    volatile unsigned long IPmask;
+}
+ ATU, *PATU;
+
+ /* 
+ ** typedef PAB
+ **
+ ** PCI Adapter Block - holds instance specific information and is located
+ ** in a reserved space at the start of the message buffer allocated by user.
+ */
+typedef struct
+{
+    PATU             p_atu;                /* ptr to  ATU register block */
+    PU8              pPci45LinBaseAddr;
+    PU8              pLinOutMsgBlock;
+    U32              outMsgBlockPhyAddr; 
+    PFNTXCALLBACK    pTransCallbackFunc;
+    PFNRXCALLBACK    pRecvCallbackFunc;
+    PFNCALLBACK      pRebootCallbackFunc;
+    PFNCALLBACK      pCallbackFunc;
+    U16              ADAPTERState;
+    U16              InboundMFrameSize;
+}
+ PAB, *PPAB;
+
+ /* 
+ ** in reserved space right after PAB in host memory is area for returning
+ ** values from card 
+ */
+
+ /* 
+ ** Array of pointers to PCI Adapter Blocks.
+ ** Indexed by a zero based (0-31) interface number.
+ */ 
+#define MAX_ADAPTERS 32
+static PPAB  PCIAdapterBlock[MAX_ADAPTERS] = 
+{
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+/*
+** typedef NICSTAT
+**
+** Data structure for NIC statistics retruned from PCI card.  Data copied from
+** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
+*/
+typedef struct tag_NicStat 
+{
+        unsigned long   TX_good; 
+        unsigned long   TX_maxcol;
+        unsigned long   TX_latecol;
+        unsigned long   TX_urun;
+        unsigned long   TX_crs;         /* lost carrier sense */
+        unsigned long   TX_def;         /* transmit deferred */
+        unsigned long   TX_singlecol;   /* single collisions */
+        unsigned long   TX_multcol;
+        unsigned long   TX_totcol;
+        unsigned long   Rcv_good;
+        unsigned long   Rcv_CRCerr;
+        unsigned long   Rcv_alignerr;
+        unsigned long   Rcv_reserr;     /* rnr'd pkts */
+        unsigned long   Rcv_orun;
+        unsigned long   Rcv_cdt;
+        unsigned long   Rcv_runt;
+        unsigned long   dump_status;    /* last field directly from the chip */
+} 
+ NICSTAT, *P_NICSTAT;
+
+#define DUMP_DONE   0x0000A005      /* completed statistical dump */
+#define DUMP_CLEAR  0x0000A007      /* completed stat dump and clear counters */
+
+
+static volatile int msgFlag;
+
+
+/* local function prototypes */
+static void ProcessOutboundAdapterMsg(PPAB pPab, U32 phyMsgAddr);
+static int FillAdapterMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
+static int GetAdapterStatus(PPAB pPab);
+static int SendAdapterOutboundQInitMsg(PPAB pPab);
+static int SendEnableSysMsg(PPAB pPab);
+
+
+ /* 1st 100h bytes of message block is reserved for messenger instance */
+#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
+
+/*
+** =========================================================================
+** InitRCApiMsgLayer()
+**
+** Initialize the RedCreek API Module and adapter.
+**
+** Inputs:  AdapterID - interface number from 0 to 15
+**          pciBaseAddr - virual base address of PCI (set by BIOS)
+**          p_msgbuf - virual address to private message block (min. 16K)
+**          p_phymsgbuf - physical address of private message block
+**          TransmitCallbackFunction - address of transmit callback function
+**          ReceiveCallbackFunction  - address of receive  callback function
+**
+** private message block is allocated by user.  It must be in locked pages.
+** p_msgbuf and p_phymsgbuf point to the same location.  Must be contigous
+** memory block of a minimum of 16K byte and long word aligned.
+** =========================================================================
+*/
+RC_RETURN
+InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr, 
+                  PU8 p_msgbuf,  PU8 p_phymsgbuf,
+                  PFNTXCALLBACK  TransmitCallbackFunction,
+                  PFNRXCALLBACK  ReceiveCallbackFunction,
+                  PFNCALLBACK    RebootCallbackFunction)
+{
+     int result;
+     PPAB pPab; 
+    
+#ifdef DEBUG
+     kprintf("InitAPI: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
+             "TransmitCallbackFunction:0x%08.8ulx  ReceiveCallbackFunction:0x%08.8ulx\n",
+             AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
+#endif /* DEBUG */
+
+    
+     /* Check if this interface already initialized - if so, shut it down */
+     if (PCIAdapterBlock[AdapterID] != NULL)
+     {
+          printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
+//        RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+          PCIAdapterBlock[AdapterID] = NULL;
+     }
+
+    /* 
+    ** store adapter instance values in adapter block.
+    ** Adapter block is at beginning of message buffer
+    */  
+    pPab = (PPAB)p_msgbuf;
+    
+    pPab->p_atu = (PATU)pciBaseAddr;
+    pPab->pPci45LinBaseAddr =  (PU8)pciBaseAddr;
+    
+     /* Set outbound message frame addr - skip over Adapter Block */
+    pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+    pPab->pLinOutMsgBlock    = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+
+     /* store callback function addresses */
+    pPab->pTransCallbackFunc = TransmitCallbackFunction;
+    pPab->pRecvCallbackFunc  = ReceiveCallbackFunction;
+    pPab->pRebootCallbackFunc  = RebootCallbackFunction;
+    pPab->pCallbackFunc  = (PFNCALLBACK)NULL;
+
+    /*
+    ** Initialize API 
+    */
+    result = GetAdapterStatus(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+        return result;
+
+    if (pPab->ADAPTERState == ADAPTER_STATE_OPERATIONAL)
+    {
+         printk("pPab->ADAPTERState == op: resetting adapter\n");
+         RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+    }
+        
+    result = SendAdapterOutboundQInitMsg(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+
+    result = SendEnableSysMsg(pPab);
+   
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+   
+    PCIAdapterBlock[AdapterID] = pPab;
+    return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** Disable and Enable Adapter interrupts.  Adapter interrupts are enabled at Init time
+** but can be disabled and re-enabled through these two function calls.
+** Packets will still be put into any posted received buffers and packets will
+** be sent through RCSendPacket() functions.  Disabling Adapter interrupts
+** will prevent hardware interrupt to host even though the outbound Adapter msg
+** queue is not emtpy.
+** =========================================================================
+*/
+#define i960_OUT_POST_Q_INT_BIT        0x0008 /* bit set masks interrupts */
+
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+        
+    pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
+
+    return RC_RTN_NO_ERROR;
+}
+
+RC_RETURN RCEnableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+         return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
+    
+    return RC_RTN_NO_ERROR;
+
+}
+
+
+/*
+** =========================================================================
+** RCSendPacket()
+** =========================================================================
+*/
+RC_RETURN
+RCSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCSendPacket()...\n");
+#endif /* DEBUG */
+    
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("RCSendPacket(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+        
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error processing TCB - send NOP msg */
+    {
+#ifdef DEBUG
+            kprintf("RCSendPacket(): Error Rrocess TCB!\n");
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_PACKET_SEND << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = InitiatorContext;
+        pMsg[3] = 0;  /* batch reply */
+         /* post to Inbound Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+
+/*
+** =========================================================================
+** RCPostRecvBuffer()
+**
+** inputs:  pBufrCntrlBlock - pointer to buffer control block
+**
+** returns TRUE if successful in sending message, else FALSE.
+** =========================================================================
+*/
+RC_RETURN
+RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCPostRecvBuffers()...\n");
+#endif /* DEBUG */
+    
+     /* search for DeviceHandle */
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+            kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+   
+    }
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
+    {
+#ifdef DEBUG
+        kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over size msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_RECEIVE_POST << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+        pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+
+
+/*
+** =========================================================================
+** RCProcMsgQ()
+**
+** Process outbound message queue until empty.
+** =========================================================================
+*/
+void 
+RCProcMsgQ(U16 AdapterID)
+{
+    U32 phyAddrMsg;
+    PU8 p8Msg;
+    PU32 p32;
+    U16 count;
+    PPAB pPab;
+    unsigned char debug_msg[20];
+    
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return;
+    
+    phyAddrMsg = pPab->p_atu->OutQueue;
+
+    while (phyAddrMsg != 0xFFFFFFFF)
+    {
+        p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+        p32 = (PU32)p8Msg;
+        
+        //printk(" msg: 0x%x  0x%x \n", p8Msg[7], p32[5]);
+
+     /* 
+     ** Send Packet Reply Msg
+     */
+        if (LAN_PACKET_SEND == p8Msg[7])  /* function code byte */
+        {
+            count = *(PU16)(p8Msg+2);
+            count -= p8Msg[0] >> 4;
+                                      /* status, count, context[], adapter */
+           (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
+        }             
+     /* 
+     ** Receive Packet Reply Msg */
+        else if (LAN_RECEIVE_POST == p8Msg[7])
+        {
+#ifdef DEBUG    
+    kprintf("RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
+    kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[0], p32[1], p32[2], p32[3]);
+    kprintf("     0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[4], p32[5], p32[6], p32[7]);
+    kprintf("     0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[8], p32[9], p32[10], p32[11]);
+#endif
+               /*  status, count, buckets remaining, packetParmBlock, adapter */
+          (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
+      
+      
+        }
+        else if (LAN_RESET == p8Msg[7] || LAN_SHUTDOWN == p8Msg[7])
+        {
+            if (pPab->pCallbackFunc)
+            {
+                (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
+            }
+            else
+            {
+                pPab->pCallbackFunc = (PFNCALLBACK) 1;
+            }
+            //PCIAdapterBlock[AdapterID] = 0;
+        }
+        else if (RC_PRIVATE == p8Msg[7])
+        {
+            //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
+          switch (p32[5])
+          {
+          case RC_PRIVATE_DEBUG_MSG:
+               msgFlag = 1;
+               /*printk("Received RC_PRIVATE msg\n");*/
+               debug_msg[15]  = (p32[6]&0xff000000) >> 24;
+               debug_msg[14]  = (p32[6]&0x00ff0000) >> 16;
+               debug_msg[13]  = (p32[6]&0x0000ff00) >> 8;
+               debug_msg[12]  = (p32[6]&0x000000ff);
+
+               debug_msg[11]  = (p32[7]&0xff000000) >> 24;
+               debug_msg[10]  = (p32[7]&0x00ff0000) >> 16;
+               debug_msg[ 9]  = (p32[7]&0x0000ff00) >> 8;
+               debug_msg[ 8]  = (p32[7]&0x000000ff);
+
+               debug_msg[ 7]  = (p32[8]&0xff000000) >> 24;
+               debug_msg[ 6]  = (p32[8]&0x00ff0000) >> 16;
+               debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
+               debug_msg[ 4] = (p32[8]&0x000000ff);
+
+               debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
+               debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
+               debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
+               debug_msg[ 0] = (p32[9]&0x000000ff);
+
+               debug_msg[16] = '\0';
+               printk (debug_msg);
+               break;
+          case RC_PRIVATE_REBOOT:
+               printk("Adapter reboot initiated...\n");
+               if (pPab->pRebootCallbackFunc)
+               {
+                    (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
+               }
+               break;
+          default:
+                printk("Unknown private msg received: 0x%x\n",
+                      p32[5]);
+               break;
+          }
+        }
+
+     /* 
+     ** Process other Msg's
+     */
+        else
+        {
+            ProcessOutboundAdapterMsg(pPab, phyAddrMsg);
+        }
+        
+         /* return MFA to outbound free Q*/
+        pPab->p_atu->OutQueue = phyAddrMsg;
+    
+         /* any more msgs? */
+        phyAddrMsg = pPab->p_atu->OutQueue;
+    }
+}
+
+
+/*
+** =========================================================================
+**  Returns LAN interface statistical counters to space provided by caller at
+**  StatsReturnAddr.  Returns 0 if success, else RC_RETURN code.
+**  This function will call the WaitCallback function provided by
+**  user while waiting for card to respond.
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatistics(U16 AdapterID, 
+                    P_RCLINKSTATS StatsReturnAddr,
+                    PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32, pReturnAddr;
+    P_NICSTAT pStats;
+    int i;
+    PPAB pPab;
+
+/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        kprintf("Get8255XStats(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LAN_STATS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+
+    pStats = (P_NICSTAT)p32;
+    pStats->dump_status = 0xFFFFFFFF;
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (pStats->dump_status != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
+        #endif
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    pReturnAddr = (PU32)StatsReturnAddr;
+    
+     /* copy Nic stats to user's structure */
+    for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
+        pReturnAddr[i] = p32[i];
+   
+    return RC_RTN_NO_ERROR;     
+}
+
+
+/*
+** =========================================================================
+** Get82558LinkStatus()
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    PPAB pPab;
+
+/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+    
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        U32 i;
+
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (*p32 != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("Timeout waiting for link status\n");
+        #endif    
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    *ReturnAddr = *p32; /* 1 = up 0 = down */
+    
+    return RC_RTN_NO_ERROR;
+    
+}
+
+/*
+** =========================================================================
+** RCGetMAC()
+**
+** get the MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
+{
+     unsigned i, timeout;
+     U32      off;
+     PU32     p;
+     U32      temp[2];
+     PPAB     pPab;
+     PATU     p_atu;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+    
+     if (pPab == NULL)
+          return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     p_atu = pPab->p_atu;
+
+     p_atu->EtherMacLow = 0;     /* first zero return data */
+     p_atu->EtherMacHi = 0;
+    
+     off = p_atu->InQueue;   /* get addresss of message */
+     if (0xFFFFFFFF == off)
+          return RC_RTN_FREE_Q_EMPTY;
+
+     p = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+     /* setup private message */
+     p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     p[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     p[2] = 0;               /* initiator context */
+     p[3] = 0x218;           /* transaction context */
+     p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
+
+
+     p_atu->InQueue = off;   /* send it to the device */
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+     timeout = 1000000;
+     while (0 == p_atu->EtherMacLow) 
+     {
+          if (WaitCallback)
+               (*WaitCallback)();
+    
+          for (i = 0; i < 1000; i++)
+               ;
+
+          if (!timeout--)
+          {
+               printk("rc_getmac: Timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+    
+     /* read the mac address  */
+     temp[0] = p_atu->EtherMacLow;
+     temp[1] = p_atu->EtherMacHi;
+     memcpy((char *)mac, (char *)temp, 6);
+
+
+#ifdef RCDEBUG
+//    printk("rc_getmac: 0x%X\n", ptr);
+#endif /* RCDEBUG */
+
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCSetMAC()
+**
+** set MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCSetMAC(U16 AdapterID, PU8 mac)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
+    pMsg[5] = *(unsigned *)mac;  /* first four bytes */
+    pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
+    
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetLinkSpeed()
+**
+** set ethernet link speed. 
+** input: speedControl - determines action to take as follows
+**          0 = reset and auto-negotiate (NWay)
+**          1 = Full Duplex 100BaseT
+**          2 = Half duplex 100BaseT
+**          3 = Full Duplex  10BaseT
+**          4 = Half duplex  10BaseT
+**          all other values are ignore (do nothing)
+** =========================================================================
+*/
+RC_RETURN
+RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
+    pMsg[5] = LinkSpeedCode;     /* link speed code */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetLinkSpeed()
+**
+** get ethernet link speed. 
+**
+** 0 = Unknown
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex  10BaseT
+** 4 = Half duplex  10BaseT
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     U8 AdapterLinkSpeed;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               kprintf("0x%08.8ulx\n", p32[0]);
+               return RC_RTN_NO_LINK_SPEED;
+          }
+     }
+
+     /* get Link speed */
+     AdapterLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+     *pLinkSpeedCode= AdapterLinkSpeed;
+
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE   0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
+    pMsg[5] = capability;
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+    
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+            
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               return RC_RTN_NO_FIRM_VER;
+          }
+     }
+
+     strcpy(pFirmString, (PU8)p32);
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCResetLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** reset is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** reset is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    unsigned long off;
+    unsigned long *pMsg;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pPab->pCallbackFunc = CallbackFunction;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_RESET << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+
+    return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCResetAdapter()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetAdapter(U16 AdapterID)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     PPAB pPab;
+     volatile PU32 p32;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+     msgOffset = pPab->p_atu->InQueue;
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID;
+     pMsg[2] = 0; /* universal context */
+     pMsg[3] = 0; /* universal context */
+     pMsg[4] = 0; /* universal context */
+     pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+     pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+     pMsg[7] = 0;
+     pMsg[8] = 1;  /*  return 1 byte */
+
+     /* virual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0;
+     p32[1] = 0;
+
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] || p32[1])
+               break;
+            
+          if (!timeout--)
+          {
+               printk("RCResetAdapter timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCShutdownLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** shutdown is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** shutdown is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    pPab->pCallbackFunc = CallbackFunction;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_SHUTDOWN << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetRavlinIPandMask()
+**
+** Set the Ravlin 45/PCI cards IP address and network mask.
+**
+** IP address and mask must be in network byte order.
+** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+** 0x04030201 and 0x00FFFFFF on a little endian machine.
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
+    pMsg[5] = ipAddr; 
+    pMsg[6] = netMask;
+
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+    return RC_RTN_NO_ERROR ;
+
+}
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+** 
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, 
+                        PFNWAITCALLBACK WaitCallback)
+{
+    unsigned i, timeout;
+    U32      off;
+    PU32     pMsg, p32;
+    PPAB     pPab;
+    PATU     p_atu;
+    
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    p_atu = pPab->p_atu;
+    off = p_atu->InQueue;   /* get addresss of message */
+   if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+    /* setup private message */
+    pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;               /* initiator context */
+    pMsg[3] = 0x218;           /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p_atu->InQueue = off;   /* send it to the device */
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+    timeout = 100000;
+    while (0xffffffff == *p32)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+    
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGetRavlinIPandMask: Timeout\n");
+        #endif /* DEBUG */
+             return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: after time out\n", \
+            "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);
+#endif /* DEBUG */
+    
+    /* send IP and mask to user's space  */
+    *pIpAddr  = p32[0];
+    *pNetMask = p32[1];
+
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    return RC_RTN_NO_ERROR;
+}
+
+/* 
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+**
+**                        local functions
+**
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+*/
+
+/*
+** =========================================================================
+** SendAdapterOutboundQInitMsg()
+**
+** =========================================================================
+*/
+static int 
+SendAdapterOutboundQInitMsg(PPAB pPab)
+{
+    U32 msgOffset, timeout, phyOutQFrames, i;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendAdapterOutboundQInitMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+    
+    
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendAdapterOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+    pMsg[1] = RC_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x106; /* transaction context */
+    pMsg[4] = 4096; /* Host page frame size */
+    pMsg[5] = MSG_FRAME_SIZE  << 16 | 0x80; /* outbound msg frame size and Initcode */
+    pMsg[6] = 0xD0000004;       /* simple sgl element LE, EOB */
+     /* phys address to return status - area right after PAB */
+    pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+  /* wait for response */
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ InPrgress status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] == RC_CMD_OUTBOUND_INIT_COMPLETE)
+            break;
+
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ Complete status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+     /* load PCI outbound free Q with MF physical addresses */
+    phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+    for (i = 0; i < NMBR_MSG_FRAMES; i++)
+    {
+        pPab->p_atu->OutQueue = phyOutQFrames;
+        phyOutQFrames += MSG_FRAME_SIZE;
+    }
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** GetAdapterStatus()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+static int 
+GetAdapterStatus(PPAB pPab)
+{
+    U32 msgOffset, timeout;
+    PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    msgOffset = pPab->p_atu->InQueue; 
+    printk("GetAdapterStatus: msg offset = 0x%x\n", msgOffset);
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("GetAdapterStatus(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = 0; /* universal context */
+    pMsg[3] = 0; /* universal context */
+    pMsg[4] = 0; /* universal context */
+    pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+    pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+    pMsg[7] = 0;
+    pMsg[8] = 88;  /*  return 88 bytes */
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    p32[1] = 0;
+
+#ifdef DEBUG
+kprintf("GetAdapterStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
+    pMsg, msgOffset, pMsg[1], pMsg[6]);
+#endif /* DEBUG */
+   
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+#ifdef DEBUG
+kprintf("Return status to p32 = 0x%08.8ulx\n", p32);
+#endif /* DEBUG */
+    
+     /* wait for response */
+    timeout = 1000000;
+    while(1)
+    {
+        int i;
+        
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] && p32[1])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout waiting for status from adapter\n");
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+            
+#ifdef DEBUG
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+    /* get adapter state */
+    pPab->ADAPTERState = ((volatile PU8)p32)[10];
+    pPab->InboundMFrameSize  = ((volatile PU16)p32)[6];
+    
+#ifdef DEBUG
+    kprintf("adapter state 0x%02.2x InFrameSize = 0x%04.4x\n", 
+                        pPab->ADAPTERState, pPab->InboundMFrameSize);
+#endif /* DEBUG */
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** SendEnableSysMsg()
+**
+**
+** =========================================================================
+*/
+static int 
+SendEnableSysMsg(PPAB pPab)
+{
+    U32 msgOffset; // timeout;
+    volatile PU32 pMsg;
+
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x110; /* transaction context */
+    pMsg[4] = 0x50657465; /*  RedCreek Private */
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** FillI12OMsgFromTCB()
+**
+** inputs   pMsgU32 - virual pointer (mapped to physical) of message frame
+**          pXmitCntrlBlock - pointer to caller buffer control block.
+**
+** fills in LAN SGL after Transaction Control Word or Bucket Count.
+** =========================================================================
+*/
+static int 
+FillAdapterMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
+{
+    unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
+    PU32 pTCB, pMsg;
+
+ /* SGL element flags */   
+#define EOB        0x40000000
+#define LE         0x80000000
+#define SIMPLE_SGL 0x10000000
+#define BC_PRESENT 0x01000000
+
+    pTCB = (PU32)pTransCtrlBlock;
+    pMsg = pMsgFrame;
+    nmbrDwords = 0;
+
+#ifdef DEBUG
+ kprintf("FillAdapterMsgSGLFromTCBX\n");
+kprintf("TCB  0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+               pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
+kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);
+#endif /* DEBUG */
+    
+    nmbrBuffers = *pTCB++;
+    
+    if (!nmbrBuffers)
+    {
+        return -1;
+    }
+
+    do
+    {
+        context = *pTCB++; /* buffer tag (context) */
+        nmbrSeg = *pTCB++; /* number of segments */
+
+        if (!nmbrSeg)
+        {
+            return -1;
+        }
+        
+        flags = SIMPLE_SGL | BC_PRESENT;
+
+        if (1 == nmbrSeg)
+        {
+            flags |= EOB;
+        
+            if (1 == nmbrBuffers)
+                flags |= LE;
+        }    
+
+         /* 1st SGL buffer element has context */
+        pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
+        pMsg[1] = context;
+        pMsg[2] = pTCB[1]; /* send buffer segment physical address */
+        nmbrDwords += 3;
+        pMsg += 3;
+        pTCB += 2;
+
+        
+        if (--nmbrSeg)
+        {
+            do
+            {
+                flags = SIMPLE_SGL;
+                
+                if (1 == nmbrSeg)
+                {
+                    flags |= EOB;
+                
+                    if (1 == nmbrBuffers)
+                        flags |= LE;
+                }    
+                
+                pMsg[0] = pTCB[0] | flags;  /* send over count */
+                pMsg[1] = pTCB[1];   /* send buffer segment physical address */
+                nmbrDwords += 2;
+                pTCB += 2;
+                pMsg += 2;
+        
+            } while (--nmbrSeg);
+        }
+        
+    } while (--nmbrBuffers);
+    
+    return nmbrDwords;
+}
+
+
+/*
+** =========================================================================
+** ProcessOutboundAdapterMsg()
+**
+** process reply message
+** * change to msg structure *
+** =========================================================================
+*/
+static void 
+ProcessOutboundAdapterMsg(PPAB pPab, U32 phyAddrMsg)
+{
+    PU8 p8Msg;
+    PU32 p32;
+  //  U16 count;
+    
+    
+    p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+    p32 = (PU32)p8Msg;
+    
+#ifdef DEBUG
+ kprintf("VXD: ProcessOutboundAdapterMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+#endif /* DEBUG */
+
+    if (p32[4] >> 24 != RC_REPLY_STATUS_SUCCESS)
+    {
+#ifdef DEBUG
+        kprintf("Message reply status not success\n");
+#endif /* DEBUG */
+        return;
+    }
+    
+    switch (p8Msg[7] )  /* function code byte */
+    {
+        case RC_CMD_SYS_TAB_SET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_TAB_SET reply\n");
+#endif /* DEBUG */
+            break;
+
+        case RC_CMD_HRT_GET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_HRT_GET reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_LCT_NOTIFY:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_LCT_NOTIFY reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_SYS_ENABLE:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_ENABLE reply\n");
+#endif /* DEBUG */
+            break;
+
+        default:    
+#ifdef DEBUG
+        kprintf("Received UNKNOWN reply\n");
+#endif /* DEBUG */
+            break;
+    }
+}
diff --git a/drivers/net/rcmtl.h b/drivers/net/rcmtl.h
new file mode 100644 (file)
index 0000000..77d8018
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+** *************************************************************************
+**
+**
+**     R C M T L . H             $Revision: 1.1 $
+**
+**
+**  RedCreek Message Transport Layer header file.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1997-1998, RedCreek Communications Inc.     ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Header file for host message transport layer API and data types.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+***************************************************************************/
+
+#ifndef RCMTL_H
+#define RCMTL_H
+
+/* Linux specific includes */
+#define kprintf printk
+#ifdef RC_LINUX_MODULE     /* linux modules need non-library version of string functions */
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID  0x4916
+#define RC_PCI45_DEVICE_ID  0x1960
+
+
+ /* RedCreek API function return values */
+#define RC_RTN_NO_ERROR             0
+#define RC_RTN_NOT_INIT             1
+#define RC_RTN_FREE_Q_EMPTY         2
+#define RC_RTN_TCB_ERROR            3
+#define RC_RTN_TRANSACTION_ERROR    4
+#define RC_RTN_ADAPTER_ALREADY_INIT 5
+#define RC_RTN_MALLOC_ERROR         6
+#define RC_RTN_ADPTR_NOT_REGISTERED 7
+#define RC_RTN_MSG_REPLY_TIMEOUT    8
+#define RC_RTN_NO_STATUS            9
+#define RC_RTN_NO_FIRM_VER         10
+#define RC_RTN_NO_LINK_SPEED       11
+
+/* Driver capability flags */
+#define WARM_REBOOT_CAPABLE      0x01
+
+ /* scalar data types */
+typedef unsigned char   U8;
+typedef unsigned char*  PU8;
+typedef unsigned short  U16;
+typedef unsigned short* PU16;
+typedef unsigned long   U32;
+typedef unsigned long*  PU32;
+typedef unsigned long   BF;
+typedef int             RC_RETURN;
+
+
+ /* 
+ ** type PFNWAITCALLBACK
+ **
+ ** pointer to void function - type used for WaitCallback in some functions 
+ */
+typedef void (*PFNWAITCALLBACK)(void);  /* void argument avoids compiler complaint */
+
+ /*
+ ** type PFNTXCALLBACK 
+ **
+ ** Pointer to user's transmit callback function.  This user function is
+ ** called from RCProcMsgQ() when packet have been transmitted from buffers
+ ** given in the RCSendPacket() function.  BufferContext is a pointer to
+ ** an array of 32 bit context values.  These are the values the user assigned
+ ** and passed in the TCB to the RCSendPacket() function.  PcktCount
+ ** indicates the number of buffer context values in the BufferContext[] array.
+ ** The User's TransmitCallbackFunction should recover (put back in free queue)
+ ** the packet buffers associated with the buffer context values.
+ */
+typedef void (*PFNTXCALLBACK)(U32  Status,
+                              U16  PcktCount,
+                              PU32 BufferContext,
+                              U16  AdaterID);
+
+ /* 
+ ** type PFNRXCALLBACK 
+ **
+ ** Pointer to user's receive callback function.  This user function
+ ** is called from RCProcMsgQ() when packets have been received into
+ ** previously posted packet buffers throught the RCPostRecvBuffers() function.
+ ** The received callback function should process the Packet Descriptor Block
+ ** pointed to by PacketDescBlock. See Packet Decription Block below.
+ */
+typedef void (*PFNRXCALLBACK)(U32  Status,
+                              U8   PktCount,
+                              U32  BucketsRemain,
+                              PU32 PacketDescBlock,
+                              U16  AdapterID);
+
+ /* 
+ ** type PFNCALLBACK 
+ **
+ ** Pointer to user's generic callback function.  This user function
+ ** can be passed to LANReset or LANShutdown and is called when the 
+ ** the reset or shutdown is complete.
+ ** Param1 and Param2 are invalid for LANReset and LANShutdown.
+ */
+typedef void (*PFNCALLBACK)(U32  Status,
+                              U32  Param1,
+                              U32  Param2,
+                              U16  AdapterID);
+
+/*
+** Status - Transmit and Receive callback status word 
+**
+** A 32 bit Status is returned to the TX and RX callback functions.  This value
+** contains both the reply status and the detailed status as follows:
+**
+**  32    24     16            0
+**  +------+------+------------+
+**  | Reply|      |  Detailed  |
+**  |Status|   0  |   Status   |
+**  +------+------+------------+
+**
+** Reply Status and Detailed Status of zero indicates No Errors.
+*/
+ /* reply message status defines */
+#define    RC_REPLY_STATUS_SUCCESS                    0x00
+#define    RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    RC_REPLY_STATUS_TRANSACTION_ERROR          0x0A
+
+
+/* DetailedStatusCode defines */
+#define    RC_DSC_SUCCESS                         0x0000
+#define    RC_DSC_DEVICE_FAILURE                  0x0001
+#define    RC_DSC_DESTINATION_NOT_FOUND           0x0002
+#define    RC_DSC_TRANSMIT_ERROR                  0x0003
+#define    RC_DSC_TRANSMIT_ABORTED                0x0004
+#define    RC_DSC_RECEIVE_ERROR                   0x0005
+#define    RC_DSC_RECEIVE_ABORTED                 0x0006
+#define    RC_DSC_DMA_ERROR                       0x0007
+#define    RC_DSC_BAD_PACKET_DETECTED             0x0008
+#define    RC_DSC_OUT_OF_MEMORY                   0x0009
+#define    RC_DSC_BUCKET_OVERRUN                  0x000A
+#define    RC_DSC_IOP_INTERNAL_ERROR              0x000B
+#define    RC_DSC_CANCELED                        0x000C
+#define    RC_DSC_INVALID_TRANSACTION_CONTEXT     0x000D
+#define    RC_DSC_DESTINATION_ADDRESS_DETECTED    0x000E
+#define    RC_DSC_DESTINATION_ADDRESS_OMITTED     0x000F
+#define    RC_DSC_PARTIAL_PACKET_RETURNED         0x0010
+
+
+/*
+** Packet Description Block   (Received packets)
+**
+** A pointer to this block structure is returned to the ReceiveCallback 
+** function.  It contains the list of packet buffers which have either been
+** filled with a packet or returned to host due to a LANReset function. 
+** Currently there will only be one packet per receive bucket (buffer) posted. 
+**
+**   32   24               0     
+**  +-----------------------+  -\
+**  |   Buffer 1 Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / First Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet 1 length |   / 
+**  +-----------------------+  -\
+**  |   Buffer 2 Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / Second Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet 2 length |   / 
+**  +-----+-----------------+  -
+**  |         ...           |  ----- more bucket descriptors
+**  +-----------------------+  -\
+**  |   Buffer n Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / Last Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet n length |   / 
+**  +-----+-----------------+  -
+**
+** Buffer Context values are those given to adapter in the TCB on calls to
+** RCPostRecvBuffers().
+**  
+*/
+
+
+
+/*
+** Transaction Control Block (TCB) structure
+**
+** A structure like this is filled in by the user and passed by reference to 
+** RCSendPacket() and RCPostRecvBuffers() functions.  Minimum size is five
+** 32-bit words for one buffer with one segment descriptor.  
+** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
+** that can be described in a given TCB.
+**
+**   32                    0
+**  +-----------------------+
+**  |   Buffer Count        |  Number of buffers in the TCB
+**  +-----------------------+
+**  |   Buffer 1 Context    |  first buffer reference
+**  +-----------------------+
+**  |   Buffer 1 Seg Count  |  number of segments in buffer
+**  +-----------------------+
+**  |   Buffer 1 Seg Desc 1 |  first segment descriptor (size, physical address)
+**  +-----------------------+
+**  |         ...           |  more segment descriptors (size, physical address)
+**  +-----------------------+
+**  |   Buffer 1 Seg Desc n |  last segment descriptor (size, physical address)
+**  +-----------------------+
+**  |   Buffer 2 Context    |  second buffer reference
+**  +-----------------------+
+**  |   Buffer 2 Seg Count  |  number of segments in buffer
+**  +-----------------------+
+**  |   Buffer 2 Seg Desc 1 |  segment descriptor (size, physical address)
+**  +-----------------------+
+**  |         ...           |  more segment descriptors (size, physical address)
+**  +-----------------------+
+**  |   Buffer 2 Seg Desc n |
+**  +-----------------------+
+**  |         ...           |  more buffer descriptor blocks ...
+**  +-----------------------+
+**  |   Buffer n Context    |
+**  +-----------------------+
+**  |   Buffer n Seg Count  |
+**  +-----------------------+
+**  |   Buffer n Seg Desc 1 |
+**  +-----------------------+
+**  |         ...           |
+**  +-----------------------+
+**  |   Buffer n Seg Desc n |
+**  +-----------------------+
+**
+**
+** A TCB for one contigous packet buffer would look like the following:
+**
+**   32                    0
+**  +-----------------------+
+**  |         1             |  one buffer in the TCB
+**  +-----------------------+
+**  |  <user's Context>     |  user's buffer reference
+**  +-----------------------+
+**  |         1             |  one segment buffer
+**  +-----------------------+                            _
+**  |    <buffer size>      |  size                       \ 
+**  +-----------------------+                              \ segment descriptor
+**  |  <physical address>   |  physical address of buffer  /
+**  +-----------------------+                            _/
+**
+*/
+
+ /* Buffer Segment Descriptor */
+typedef struct
+{
+    U32 size;
+    U32 phyAddress;
+}
+ BSD, *PBSD;
+typedef PU32 PRCTCB;
+/*
+** -------------------------------------------------------------------------
+** Exported functions comprising the API to the message transport layer
+** -------------------------------------------------------------------------
+*/
+
+
+ /*
+ ** InitRCApiMsgLayer()
+ ** 
+ ** Called once prior to using the API message transport layer.  User 
+ ** provides both the physical and virual address of a locked page buffer 
+ ** that is used as a private buffer for the RedCreek API message
+ ** transport layer.  This buffer must be a contigous memory block of a 
+ ** minimum of 16K bytes and long word aligned.  The user also must provide
+ ** the base address of the RedCreek PCI adapter assigned by BIOS or operating
+ ** system.  The user provided value AdapterID is a zero based index of the
+ ** Ravlin 45/PCI adapter.  This interface number is used in all subsequent API
+ ** calls to identify which adpapter for which the function is intended.  
+ ** Up to sixteen interfaces are supported with this API.
+ **
+ ** Inputs:  AdapterID - interface number from 0 to 15
+ **          pciBaseAddr - virual base address of PCI (set by BIOS)
+ **          p_msgbuf - virual address to private message block (min. 16K)
+ **          p_phymsgbuf - physical address of private message block
+ **          TransmitCallbackFunction - address of user's TX callback function
+ **          ReceiveCallbackFunction  - address of user's RX callback function
+ **
+ */
+RC_RETURN InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr, 
+                            PU8 p_msgbuf,  PU8 p_phymsgbuf,
+                            PFNTXCALLBACK TransmitCallbackFunction,
+                            PFNRXCALLBACK ReceiveCallbackFunction,
+                            PFNCALLBACK   RebootCallbackFunction);
+
+ /*
+ ** RCSetRavlinIPandMask()
+ **
+ ** Set the Ravlin 45/PCI cards IP address and network mask.
+ **
+ ** IP address and mask must be in network byte order.
+ ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+ ** 0x04030201 and 0x00FFFFFF on a little endian machine.
+ **
+ */
+RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask);
+
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+** 
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, 
+                        PFNWAITCALLBACK WaitCallback);
+
+ /* 
+ ** RCProcMsgQ()
+ ** 
+ ** Called from user's polling loop or Interrupt Service Routine for a PCI 
+ ** interrupt from the RedCreek PCI adapter.  User responsible for determining
+ ** and hooking the PCI interrupt. This function will call the registered
+ ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
+ ** if a TX or RX transaction has completed.
+ */
+void RCProcMsgQ(U16 AdapterID);
+
+
+ /*
+ ** Disable and Enable Adapter interrupts.  Adapter interrupts are enabled at 
+ ** Init time but can be disabled and re-enabled through these two function calls.
+ ** Packets will still be put into any posted recieved buffers and packets will
+ ** be sent through RCSendPacket() functions.  Disabling Adapter interrupts
+ ** will prevent hardware interrupt to host even though the outbound msg
+ ** queue is not emtpy.
+ */
+RC_RETURN RCEnableAdapterInterrupts(U16 adapterID);
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID);
+
+
+ /* 
+ ** RCPostRecvBuffers()
+ ** 
+ ** Post user's page locked buffers for use by the PCI adapter to
+ ** return ethernet packets received from the LAN.  Transaction Control Block,
+ ** provided by user, contains buffer descriptor(s) which includes a buffer
+ ** context number along with buffer size and physical address.  See TCB above.
+ ** The buffer context and actual packet length are returned to the 
+ ** ReceiveCallbackFunction when packets have been received.  Buffers posted
+ ** to the RedCreek adapter are considered owned by the adapter until the
+ ** context is return to user through the ReceiveCallbackFunction.
+ */
+RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock);
+#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
+
+ /*
+ ** RCSendPacket()
+ ** 
+ ** Send user's ethernet packet from a locked page buffer.  
+ ** Packet must have full MAC header, however without a CRC.  
+ ** Initiator context is a user provided value that is returned 
+ ** to the TransmitCallbackFunction when packet buffer is free.
+ ** Transmit buffer are considered owned by the adapter until context's
+ ** returned to user through the TransmitCallbackFunction.
+ */
+RC_RETURN RCSendPacket(U16 AdapterID, 
+                          U32 context, 
+                          PRCTCB pTransactionCtrlBlock);
+
+
+ /* Ethernet Link Statistics structure */
+typedef struct tag_RC_link_stats
+{
+    U32 TX_good;      /* good transmit frames */
+    U32 TX_maxcol;    /* frames not TX due to MAX collisions */
+    U32 TX_latecol;   /* frames not TX due to late collisions */
+    U32 TX_urun;      /* frames not TX due to DMA underrun */
+    U32 TX_crs;       /* frames TX with lost carrier sense */
+    U32 TX_def;       /* frames deferred due to activity on link */
+    U32 TX_singlecol; /* frames TX with one and only on collision */
+    U32 TX_multcol;   /* frames TX with more than one collision */
+    U32 TX_totcol;    /* total collisions detected during TX */
+    U32 Rcv_good;     /* good frames received */
+    U32 Rcv_CRCerr;   /* frames RX and discarded with CRC errors */
+    U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
+    U32 Rcv_reserr;   /* good frames discarded due to no RX buffer */
+    U32 Rcv_orun;     /* RX frames lost due to FIFO overrun */
+    U32 Rcv_cdt;      /* RX frames with collision during RX */
+    U32 Rcv_runt;     /* RX frames shorter than 64 bytes */
+}
+ RCLINKSTATS, *P_RCLINKSTATS;
+
+ /*
+ ** RCGetLinkStatistics()
+ **
+ ** Returns link statistics in user's structure at address StatsReturnAddr
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatistics(U16 AdapterID,
+                              P_RCLINKSTATS StatsReturnAddr,
+                              PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCGetLinkStatus()
+ **
+ ** Return link status, up or down, to user's location addressed by ReturnAddr.
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatus(U16 AdapterID, 
+                          PU32 pReturnStatus,
+                          PFNWAITCALLBACK WaitCallback);
+                               
+ /* Link Status defines - value returned in pReturnStatus */
+#define LAN_LINK_STATUS_DOWN     0
+#define LAN_LINK_STATUS_UP       1
+
+ /*
+ ** RCGetMAC()
+ **
+ ** Get the current MAC address assigned to user.  RedCreek Ravlin 45/PCI 
+ ** has two MAC addresses.  One which is private to the PCI Card, and 
+ ** another MAC which is given to the user as its link layer MAC address. The
+ ** adapter runs in promiscous mode because of the dual address requirement.
+ ** The MAC address is returned to the unsigned char array pointer to by mac.
+ */
+RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCSetMAC()
+ **
+ ** Set a new user port MAC address.  This address will be returned on
+ ** subsequent RCGetMAC() calls.
+ */
+RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac);
+
+ /*
+ ** RCSetLinkSpeed()
+ **
+ ** set adapter's link speed based on given input code.
+ */
+RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode);
+ /* Set link speed codes */
+#define LNK_SPD_AUTO_NEG_NWAY   0
+#define LNK_SPD_100MB_FULL      1
+#define LNK_SPD_100MB_HALF      2
+#define LNK_SPD_10MB_FULL       3
+#define LNK_SPD_10MB_HALF       4
+
+
+
+
+ /*
+ ** RCGetLinkSpeed()
+ **
+ ** Return link speed code.
+ */
+ /* Return link speed codes */
+#define LNK_SPD_UNKNOWN         0
+#define LNK_SPD_100MB_FULL      1
+#define LNK_SPD_100MB_HALF      2
+#define LNK_SPD_10MB_FULL       3
+#define LNK_SPD_10MB_HALF       4
+
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback);
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE   0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability);
+
+/*
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback);
+
+/*
+** ----------------------------------------------
+** LAN adapter Reset and Shutdown functions
+** ----------------------------------------------
+*/
+ /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
+#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS  0x0001 
+#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS    0x0002
+
+ /*
+ ** RCResetLANCard()
+ **
+ ** Reset LAN card operation.  Causes a software reset of the ethernet
+ ** controller and restarts the command and receive units. Depending on 
+ ** the ResourceFlags given, the buffers are either returned to the
+ ** host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
+ ** detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete.  If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset 
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** A call to RCPostRecvBuffers() is needed to return the ethernet to full
+ ** operation if the receive buffers were returned during LANReset.
+ ** Note: The IOP status is not affected by a LAN reset.
+ */
+RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+
+ /*
+ ** RCShutdownLANCard()
+ **
+ ** Shutdown LAN card operation and put into an idle (suspended) state.
+ ** The LAN card is restarted with RCResetLANCard() function.
+ ** Depending on the ResourceFlags given, the buffers are either returned 
+ ** to the host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 
+ ** and detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete.  If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset 
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** Note: The IOP status is not affected by a LAN shutdown.
+ */                                      
+RC_RETURN 
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+ /*
+ ** RCResetAdapter();
+ **     Initializes ADAPTERState to ADAPTER_STATE_RESET.
+ **     Stops access to outbound message Q.
+ **     Discards any outstanding transmit or posted receive buffers.
+ **     Clears outbound message Q. 
+ */
+RC_RETURN 
+RCResetAdapter(U16 AdapterID);
+
+#endif /* RCMTL_H */
diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c
new file mode 100644 (file)
index 0000000..b618345
--- /dev/null
@@ -0,0 +1,1345 @@
+
+/* 
+**  RCpci45.c  
+**
+**
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1998, RedCreek Communications Inc.          ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** This software is RedCreek Communications proprietary and confidential.
+** No further distribution or copying is allowed without the express
+** written consent of RedCreek Communications.
+**
+** Known Problems
+** 
+** Billions and Billions...  
+**
+** ... apparently added by Brian.  Pete knows of no bugs.
+**
+**  TODO:
+**      -Get rid of the wait loops in the API and replace them
+**       with system independent delays ...something like
+**       "delayms(2)".
+**      -Process the warm reboot in a timer callback routine,
+**       rather than at interrupt level.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+***************************************************************************/
+
+#define __NO_VERSION__ /* don't define kernel_verion in module.h */
+
+static char *version =
+"RedCreek Communications PCI linux driver version 1.31 Beta\n";
+
+
+#include <linux/config.h>
+#include <linux/modversions.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+char kernel_version [] = UTS_RELEASE;
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/timer.h>
+#include <asm/irq.h>            /* For NR_IRQS only. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+#include "rcif.h"
+
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+
+#define NEW_MULTICAST
+#include <linux/delay.h>
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID  0x4916
+#define RC_PCI45_DEVICE_ID  0x1960
+
+#define MAX_ETHER_SIZE        1520  
+#define MAX_NMBR_RCV_BUFFERS    96
+#define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16
+#define BD_SIZE 3           /* Bucket Descriptor size */
+#define BD_LEN_OFFSET 2     /* Bucket Descriptor offset to length field */
+
+
+/* RedCreek LAN device Target ID */
+#define RC_LAN_TARGET_ID  0x10 
+/* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT  0xA17  
+
+
+static U32 DriverControlWord =  0;
+
+/*
+ * Driver Private Area, DPA.
+ */
+typedef struct
+{
+
+     /* 
+      *    pointer to the device structure which is part
+      * of the interface to the Linux kernel.
+      */
+      struct device *dev;            
+     
+     char devname[8];                /* "ethN" string */
+     U8     id;                        /* the AdapterID */
+     U32    pci_addr;               /* the pci address of the adapter */
+     U32    bus;
+     U32    function;
+     struct enet_statistics  stats; /* the statistics structure */
+     struct device *next;            /* points to the next RC adapter */
+     unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/
+     unsigned char shutdown;
+     unsigned char reboot;
+     unsigned char nexus;
+     PU8    PLanApiPA;             /* Pointer to Lan Api Private Area */
+
+}
+DPA, *PDPA;
+
+#define MAX_ADAPTERS 32
+
+static PDPA  PCIAdapters[MAX_ADAPTERS] = 
+{
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+static int RCscan(void);
+static struct device 
+*RCfound_device(struct device *, int, int, int, int, int, int);
+
+static int RCprobe1(struct device *);
+static int RCopen(struct device *);
+static int RC_xmit_packet(struct sk_buff *, struct device *);
+static void RCinterrupt(int, void *, struct pt_regs *);
+static int RCclose(struct device *dev);
+static struct enet_statistics *RCget_stats(struct device *);
+static int RCioctl(struct device *, struct ifreq *, int);
+static int RCconfig(struct device *, struct ifmap *);
+static void RCxmit_callback(U32, U16, PU32, U16);
+static void RCrecv_callback(U32, U8, U32, PU32, U16);
+static void RCreset_callback(U32, U32, U32, U16);
+static void RCreboot_callback(U32, U32, U32, U16);
+static int RC_allocate_and_post_buffers(struct device *, int);
+
+
+/* A list of all installed RC devices, for removing the driver module. */
+static struct device *root_RCdev = NULL;
+
+int
+init_module(void)
+{
+     int cards_found;
+
+     printk(version);
+
+     root_RCdev = NULL;
+     cards_found = RCscan();
+     return cards_found ? 0 : -ENODEV;
+}
+
+static int RCscan()
+{
+     int cards_found = 0;
+     struct device *dev = 0;
+
+     if (pcibios_present()) 
+     {
+          static int pci_index = 0;
+          unsigned char pci_bus, pci_device_fn;
+          int scan_status;
+          int board_index = 0;
+
+          for (;pci_index < 0xff; pci_index++) 
+          {
+               unsigned char pci_irq_line;
+               unsigned short pci_command, vendor, device, class;
+               unsigned int pci_ioaddr;
+
+
+               scan_status =  
+                    (pcibios_find_device (RC_PCI45_VENDOR_ID, 
+                                          RC_PCI45_DEVICE_ID, 
+                                          pci_index, 
+                                          &pci_bus, 
+                                          &pci_device_fn));
+#ifdef RCDEBUG
+               printk("rc scan_status = 0x%X\n", scan_status);
+#endif
+               if (scan_status != PCIBIOS_SUCCESSFUL)
+                    break;
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn, 
+                                        PCI_VENDOR_ID, &vendor);
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_DEVICE_ID, &device);
+               pcibios_read_config_byte(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_INTERRUPT_LINE, &pci_irq_line);
+               pcibios_read_config_dword(pci_bus, 
+                                         pci_device_fn,
+                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_CLASS_DEVICE, &class);
+
+               pci_ioaddr &= ~0xf;
+
+#ifdef RCDEBUG
+               printk("rc: Found RedCreek PCI adapter\n");
+               printk("rc: pci class = 0x%x  0x%x \n", class, class>>8);
+               printk("rc: pci_bus = %d,  pci_device_fn = %d\n", pci_bus, pci_device_fn);
+               printk("rc: pci_irq_line = 0x%x \n", pci_irq_line);
+               printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr);
+#endif
+
+#if 0
+               if (check_region(pci_ioaddr, 32768))
+               {
+                    printk("rc: check_region failed\n");
+                    continue;
+               }
+               else
+               {
+                    printk("rc: check_region passed\n");
+               }
+#endif
+               
+                /*
+                 * Get and check the bus-master and latency values.
+                 * Some PCI BIOSes fail to set the master-enable bit.
+                 */
+
+                pcibios_read_config_word(pci_bus, 
+                                         pci_device_fn,
+                                         PCI_COMMAND, 
+                                         &pci_command);
+                if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+                     printk("rc: PCI Master Bit has not been set!\n");
+                            
+                     pci_command |= PCI_COMMAND_MASTER;
+                     pcibios_write_config_word(pci_bus, 
+                                               pci_device_fn,
+                                               PCI_COMMAND, 
+                                               pci_command);
+                }
+                if ( ! (pci_command & PCI_COMMAND_MEMORY)) {
+                               /*
+                                * If the BIOS did not set the memory enable bit, what else
+                                * did it not initialize?  Skip this adapter.
+                                */
+                     printk("rc: Adapter %d, PCI Memory Bit has not been set!\n",
+                                               cards_found);
+                     printk("rc: Bios problem? \n");
+                                        continue;
+                }
+                    
+               dev = RCfound_device(dev, pci_ioaddr, pci_irq_line,
+                                    pci_bus, pci_device_fn,
+                                    board_index++, cards_found);
+
+               if (dev) {
+                    dev = 0;
+                    cards_found++;
+               }
+          }
+     }
+     printk("rc: found %d cards \n", cards_found);
+     return cards_found;
+}
+
+static struct device *
+RCfound_device(struct device *dev, int memaddr, int irq, 
+               int bus, int function, int product_index, int card_idx)
+{
+     int dev_size = 32768;        
+     unsigned long *vaddr=0;
+     PDPA pDpa;
+     int init_status;
+
+     /* 
+      * Allocate and fill new device structure. 
+      * We need enough for struct device plus DPA plus the LAN API private
+      * area, which requires a minimum of 16KB.  The top of the allocated
+      * area will be assigned to struct device; the next chunk will be
+      * assigned to DPA; and finally, the rest will be assigned to the
+      * the LAN API layer.
+      */
+     dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+     memset(dev, 0, dev_size);
+#ifdef RCDEBUG
+     printk("rc: dev = 0x%08X\n", (uint)dev);
+#endif 
+
+     /*
+      * dev->priv will point to the start of DPA.
+      */
+     dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
+     pDpa = dev->priv;
+     dev->name = pDpa->devname;
+
+     pDpa->dev = dev;            /* this is just for easy reference */
+     pDpa->function = function;
+     pDpa->bus = bus;
+     pDpa->id = card_idx;        /* the device number */
+     pDpa->pci_addr = memaddr;
+     PCIAdapters[card_idx] = pDpa;
+#ifdef RCDEBUG
+     printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id);
+#endif
+
+     /*
+      * Save the starting address of the LAN API private area.  We'll
+      * pass that to InitRCApiMsgLayer().
+      */
+     pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff);
+#ifdef RCDEBUG
+     printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
+#endif
+    
+     /* The adapter is accessable through memory-access read/write, not
+      * I/O read/write.  Thus, we need to map it to some virtual address
+      * area in order to access the registers are normal memory.
+      */
+     vaddr = (ulong *) vremap (memaddr, 32768);
+#ifdef RCDEBUG
+     printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n", 
+            (uint)dev, (uint)dev->priv, (uint)vaddr);
+#endif
+     dev->base_addr = (unsigned long)vaddr;
+     dev->irq = irq;
+     dev->interrupt = 0;
+
+     /*
+      * Request a shared interrupt line.
+      */
+     if ( request_irq(dev->irq, (void *)RCinterrupt,
+                      SA_INTERRUPT|SA_SHIRQ, dev->name, dev) )
+     {
+          printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq );
+          vfree(vaddr);
+          kfree(dev);
+           return 0;
+     }
+
+     init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr, 
+                                     pDpa->PLanApiPA, pDpa->PLanApiPA,
+                                     (PFNTXCALLBACK)RCxmit_callback,
+                                     (PFNRXCALLBACK)RCrecv_callback,
+                                     (PFNCALLBACK)RCreboot_callback);
+#ifdef RCDEBUG
+     printk("rc: msg initted: status = 0x%x\n", init_status);
+#endif
+     if (init_status)
+     {
+          printk("rc: Unable to initialize msg layer\n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+     if (RCGetMAC(pDpa->id, dev->dev_addr, NULL))
+     {
+          printk("rc: Unable to get adapter MAC\n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+
+     DriverControlWord |= WARM_REBOOT_CAPABLE;
+     RCReportDriverCapability(pDpa->id, DriverControlWord);
+
+     dev->init = RCprobe1;
+     ether_setup(dev);            /* linux kernel interface */
+
+     pDpa->next = root_RCdev;
+     root_RCdev = dev;
+
+     if (register_netdev(dev) != 0) /* linux kernel interface */
+     {
+          printk("rc: unable to register device \n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+     return dev;
+}
+
+static int RCprobe1(struct device *dev)
+{
+     dev->open = RCopen;
+     dev->hard_start_xmit = RC_xmit_packet;
+     dev->stop = RCclose;
+     dev->get_stats = RCget_stats;
+     dev->do_ioctl = RCioctl;
+     dev->set_config = RCconfig;
+     return 0;
+}
+
+static int
+RCopen(struct device *dev)
+{
+    int post_buffers = MAX_NMBR_RCV_BUFFERS;
+    PDPA pDpa = (PDPA) dev->priv;
+    int count = 0;
+    int requested = 0;
+
+#ifdef RCDEBUG
+    printk("rc: RCopen\n");
+#endif
+    RCEnableAdapterInterrupts(pDpa->id);
+
+    if (pDpa->nexus)
+    {
+       /* This is not the first time RCopen is called.  Thus,
+        * the interface was previously opened and later closed
+        * by RCclose().  RCclose() does a Shutdown; to wake up
+        * the adapter, a reset is mandatory before we can post
+        * receive buffers.  However, if the adapter initiated 
+        * a reboot while the interface was closed -- and interrupts
+        * were turned off -- we need will need to reinitialize
+        * the adapter, rather than simply waking it up.  
+        */
+        printk("rc: Waking up adapter...\n");
+        RCResetLANCard(pDpa->id,0,0,0);
+    }
+    else
+    {
+       pDpa->nexus = 1;
+    }
+
+    while(post_buffers)
+    {
+        if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+            requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
+        else
+            requested = post_buffers;
+        count = RC_allocate_and_post_buffers(dev, requested);
+
+        if ( count < requested )
+        {
+             /*
+              * Check to see if we were able to post any buffers at all.
+              */
+             if (post_buffers == MAX_NMBR_RCV_BUFFERS)
+             {
+                  printk("rc: Error RCopen: not able to allocate any buffers\r\n");
+                  return(-ENOMEM);                    
+             }
+             printk("rc: Warning RCopen: not able to allocate all requested buffers\r\n");
+             break;            /* we'll try to post more buffers later */
+        }
+        else
+             post_buffers -= count;
+    }
+    pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
+    pDpa->shutdown = 0;        /* just in case */
+#ifdef RCDEBUG
+    printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers);
+#endif
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int
+RC_xmit_packet(struct sk_buff *skb, struct device *dev)
+{
+
+     PDPA pDpa = (PDPA) dev->priv;
+     singleTCB tcb;
+     psingleTCB ptcb = &tcb;
+     RC_RETURN status = 0;
+    
+     if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
+     {
+#ifdef RCDEBUG
+          printk("rc: RC_xmit_packet: tbusy!\n");
+#endif
+          return 1;
+     }
+      
+     if ( skb->len <= 0 ) 
+     {
+          printk("RC_xmit_packet: skb->len less than 0!\n");
+          return 0;
+     }
+
+     /*
+      * The user is free to reuse the TCB after RCSendPacket() returns, since
+      * the function copies the necessary info into its own private space.  Thus,
+      * our TCB can be a local structure.  The skb, on the other hand, will be
+      * freed up in our interrupt handler.
+      */
+     ptcb->bcount = 1;
+     /* 
+      * we'll get the context when the adapter interrupts us to tell us that
+      * the transmision is done. At that time, we can free skb.
+      */
+     ptcb->b.context = (U32)skb;    
+     ptcb->b.scount = 1;
+     ptcb->b.size = skb->len;
+     ptcb->b.addr = (U32)skb->data;
+
+#ifdef RCDEBUG
+     printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", 
+            (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb);
+#endif
+     if ( (status = RCSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb))
+          != RC_RTN_NO_ERROR)
+     {
+#ifdef RCDEBUG
+          printk("rc: RC send error 0x%x\n", (uint)status);
+#endif
+          dev->tbusy = 1;
+     }
+     else
+     {
+          dev->trans_start = jiffies;
+          //       dev->tbusy = 0;
+     }
+     /*
+      * That's it!
+      */
+     return 0;
+}
+
+/*
+ * RCxmit_callback()
+ *
+ * The transmit callback routine. It's called by RCProcMsgQ()
+ * because the adapter is done with one or more transmit buffers and
+ * it's returning them to us, or we asked the adapter to return the
+ * outstanding transmit buffers by calling RCResetLANCard() with 
+ * RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag. 
+ * All we need to do is free the buffers.
+ */
+static void 
+RCxmit_callback(U32 Status, 
+                U16 PcktCount, 
+                PU32 BufferContext, 
+                U16 AdapterID)
+{
+    struct sk_buff *skb;
+    PDPA pDpa;
+    struct device *dev;
+
+    pDpa = PCIAdapters[AdapterID];
+    if (!pDpa)
+    {
+        printk("rc: Fatal error: xmit callback, !pDpa\n");
+        return;
+    }
+    dev = pDpa->dev;
+
+        // printk("xmit_callback: Status = 0x%x\n", (uint)Status);
+    if (Status != RC_REPLY_STATUS_SUCCESS)
+    {
+        printk("rc: xmit_callback: Status = 0x%x\n", (uint)Status);
+    }
+#ifdef RCDEBUG
+    if (pDpa->shutdown || pDpa->reboot)
+        printk("rc: xmit callback: shutdown||reboot\n");
+#endif
+
+#ifdef RCDEBUG     
+    printk("rc: xmit_callback: PcktCount = %d, BC = 0x%x\n", 
+            (uint)PcktCount, (uint)BufferContext);
+#endif
+    while (PcktCount--)
+    {
+        skb = (struct sk_buff *)(BufferContext[0]);
+#ifdef RCDEBUG
+        printk("rc: skb = 0x%x\n", (uint)skb);
+#endif
+        BufferContext++;
+        dev_kfree_skb (skb, FREE_WRITE);
+    }
+    dev->tbusy = 0;
+
+}
+
+static void
+RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
+{
+     PDPA pDpa;
+     struct device *dev;
+     U32 watchdog = 0;
+     volatile unsigned int i, j;
+     RC_RETURN init_status = 1;
+     unsigned short pci_command, pci_int;
+     int post_buffers = MAX_NMBR_RCV_BUFFERS;
+     int count = 0;
+     int requested = 0;
+     
+     pDpa = PCIAdapters[AdapterID];
+     dev = pDpa->dev;
+#ifdef RCDEBUG
+      printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
+#endif
+      /*
+       * Check to see why we did a reset.
+       */
+      if (pDpa->shutdown)
+      {
+              /* shutdown overrides reboot */
+            printk("rc: Shutting down interface\n");
+      }
+      else if (pDpa->reboot)
+      {
+           char did_shutdown = 0;
+
+           watchdog = 0;
+           do {
+                /*
+                 * OK, we have to first wait for the bus master
+                 * bit to become 0, indicating that the adapter 
+                 * has initiated the shutdown. Then, in the next
+                 * loop, we'll wait for the adapter to turn on
+                 * the bus master bit, indicating that it is done
+                 * rebooting.
+                 */
+                watchdog++;
+                if (watchdog > 100)
+                     break;
+                pcibios_read_config_word(pDpa->bus, 
+                                         pDpa->function,
+                                         PCI_COMMAND, 
+                                         &pci_command);
+                //             printk("1: pci_command = 0x%x\n", pci_command);
+                if (!did_shutdown)
+                {
+                     /*
+                      * Yes, this is precisely where I want to
+                      * do the shutdown!!!  Right here, in this
+                      * do/while loop.
+                      */
+                     RCShutdownLANCard(pDpa->id, 0, 0, 0);
+                     did_shutdown = 1;
+                }
+           } while (pci_command & PCI_COMMAND_MASTER);
+
+            printk("rc: Adapter is rebooting...\n");
+            printk("rc: Waiting for adapter to become ready\n");
+
+            watchdog = 0;
+            while(watchdog < 10)
+            {
+                 watchdog++;
+                 for (i=0; i<1000000; i++)
+                      for (j=0; j<100; j++);
+                 pcibios_read_config_word(pDpa->bus, 
+                                          pDpa->function,
+                                          PCI_COMMAND, 
+                                          &pci_command);
+                 //printk("2: pci_command = 0x%x\n", pci_command);
+                 if (pci_command & PCI_COMMAND_MASTER) {
+                      break;
+                 }
+            }
+            pDpa->reboot = 0;
+            if (watchdog >= 10)
+            {
+                 printk("rc: Adapter ready timeout\n");
+                 printk("rc: releasing driver...\n");
+                 RCDisableAdapterInterrupts(AdapterID);
+                 dev->flags &= ~IFF_UP;
+            }
+            else
+            {
+                 pci_command |= PCI_COMMAND_MEMORY;
+                 pcibios_write_config_word(pDpa->bus,
+                                           pDpa->function,
+                                           PCI_COMMAND, 
+                                           pci_command);
+                 printk("rc: Adapter ready\n");
+                 printk("rc: Initializing ...\n");
+                 init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr, 
+                                                 pDpa->PLanApiPA, pDpa->PLanApiPA,
+                                                 (PFNTXCALLBACK)RCxmit_callback,
+                                                 (PFNRXCALLBACK)RCrecv_callback,
+                                                 (PFNCALLBACK)RCreboot_callback);
+
+                 printk("rc: status = 0x%x\n", init_status);
+                 if (init_status)
+                 {
+                      printk("rc: Unable to initialize adapter\n");
+                      printk("rc: releasing driver...\n");
+                 }
+                 else
+                 {
+                      pcibios_read_config_word(pDpa->bus, 
+                                               pDpa->function,
+                                               PCI_INTERRUPT_LINE,
+                                               &pci_int);
+                      if (dev->irq != (pci_int & 0xff))
+                      {
+                           printk("rc: Interrupt line set to 0x%x\n", pci_int);    
+                           printk("rc: Resetting to 0x%x\n", dev->irq);
+                           pcibios_write_config_word(pDpa->bus, 
+                                                     pDpa->function,
+                                                     PCI_INTERRUPT_LINE,
+                                                     dev->irq);
+                      }
+
+                      RCReportDriverCapability(pDpa->id, DriverControlWord);
+                      RCEnableAdapterInterrupts(pDpa->id);
+
+                      if (dev->flags & IFF_UP)
+                      {
+                           while(post_buffers)
+                           {
+                                if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+                                     requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
+                                else
+                                     requested = post_buffers;
+                                count = RC_allocate_and_post_buffers(dev, requested);
+                                post_buffers -= count;
+                                if ( count < requested )
+                                     break;
+                           }
+                           pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
+                           pDpa->shutdown = 0;        /* just in case */
+
+                           printk("rc: posted %d buffers \r\n", (uint)pDpa->numOutRcvBuffers);
+                      }
+                      printk("rc: Initialization done.\n");
+                      return;
+                 }
+            }
+      }
+      pDpa->shutdown = 0;
+      pDpa->reboot = 0;
+      //RCDisableAdapterInterrupts(AdapterID);
+
+      MOD_DEC_USE_COUNT; 
+
+}
+
+static void
+RCreboot_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
+{
+     PDPA pDpa;
+    
+     pDpa = PCIAdapters[AdapterID];
+#ifdef RCDEBUG
+     printk("rc: RCreboot: rcv buffers outstanding = %d\n", 
+            (uint)pDpa->numOutRcvBuffers);
+#endif
+     if (pDpa->shutdown)
+     {
+          printk("rc: skipping reboot sequence -- shutdown already initiated\n");
+          return;
+     }
+     pDpa->reboot = 1;
+     //RCShutdownLANCard(pDpa->id, 
+     RCResetLANCard(pDpa->id, 
+                    RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | 
+                    RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+                    (PFNCALLBACK)RCreset_callback);
+}
+
+int broadcast_packet(unsigned char * address)
+{
+    int i;
+    for (i=0; i<6; i++)
+        if (address[i] != 0xff) return 0;
+
+    return 1;
+}
+
+/*
+ * RCrecv_callback()
+ * 
+ * The receive packet callback routine.  This is called by
+ * RCProcMsgQ() after the adapter posts buffers which have been
+ * filled (one ethernet packet per buffer).
+ */
+static void
+RCrecv_callback(U32  Status, 
+                U8   PktCount, 
+                U32  BucketsRemain, 
+                PU32 PacketDescBlock, 
+                U16  AdapterID)
+{
+    U32 len, count;
+    PDPA pDpa;
+    struct sk_buff *skb;
+    struct device *dev;
+    singleTCB tcb;
+    psingleTCB ptcb = &tcb;
+
+
+    pDpa = PCIAdapters[AdapterID];
+    dev = pDpa->dev;
+
+    ptcb->bcount = 1;
+
+#ifdef RCDEBUG
+    printk("rc: RCrecv_callback: 0x%x, 0x%x, 0x%x\n",
+           (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock);
+#endif
+        
+#ifdef RCDEBUG
+    if ((pDpa->shutdown || pDpa->reboot) && !Status)
+         printk("shutdown||reboot && !Status: PktCount = %d\n",PktCount);
+#endif
+
+    if ( (Status != RC_REPLY_STATUS_SUCCESS) || pDpa->shutdown)
+    {
+        /*
+         * Free whatever buffers the adapter returned, but don't
+         * pass them to the kernel.
+         */
+        
+        if (!pDpa->shutdown && !pDpa->reboot)
+             printk("rc: RCrecv error: status = 0x%x\n", (uint)Status);
+        else
+             printk("rc: Returning %d buffers, status = 0x%x\n", 
+                    PktCount, (uint)Status);
+        /*
+         * TO DO: check the nature of the failure and put the adapter in
+         * failed mode if it's a hard failure.  Send a reset to the adapter
+         * and free all outstanding memory.
+         */
+        if (Status == RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER)
+        {
+   #ifdef RCDEBUG
+            printk("RCrecv status ABORT NO DATA TRANSFER\n");
+   #endif
+        }
+        /* check for reset status: RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ 
+        if (PacketDescBlock)
+        {
+            while(PktCount--)
+            {
+                skb = (struct sk_buff *)PacketDescBlock[0];
+                skb->free = 1;
+                skb->lock = 0;    
+   #ifdef RCDEBUG
+                printk("free skb 0x%p\n", skb);
+   #endif
+                dev_kfree_skb(skb, FREE_READ);
+                pDpa->numOutRcvBuffers--;
+                PacketDescBlock += BD_SIZE; /* point to next context field */
+            }
+        }
+        return;
+    }
+    else
+    {
+        while(PktCount--)
+        {
+            skb = (struct sk_buff *)PacketDescBlock[0];
+   #ifdef RCDEBUG
+            if (pDpa->shutdown)
+                printk("shutdown: skb=0x%x\n", (uint)skb);
+
+            printk("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint)skb,
+                   (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2],
+                   (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]);
+   #endif
+            if ( (memcmp(dev->dev_addr, skb->data, 6)) &&
+                 (!broadcast_packet(skb->data)))
+            {
+                /*
+                 * Re-post the buffer to the adapter.  Since the adapter usually
+                 * return 1 to 2 receive buffers at a time, it's not too inefficient
+                 * post one buffer at a time but ... may be that should be 
+                 * optimized at some point.
+                 */
+                ptcb->b.context = (U32)skb;    
+                ptcb->b.scount = 1;
+                ptcb->b.size = MAX_ETHER_SIZE;
+                ptcb->b.addr = (U32)skb->data;
+
+                if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR)
+                {
+                    printk("rc: RCrecv_callback: post buffer failed!\n");
+                    skb->free = 1;
+                    dev_kfree_skb(skb, FREE_READ);
+                }
+                else
+                {
+                    pDpa->numOutRcvBuffers++;
+                }
+            }
+            else
+            {
+                len = PacketDescBlock[2];
+                skb->dev = dev;
+                skb_put( skb, len ); /* adjust length and tail */
+                skb->protocol = eth_type_trans(skb, dev);
+                netif_rx(skb);    /* send the packet to the kernel */
+                dev->last_rx = jiffies;
+            }
+            pDpa->numOutRcvBuffers--;
+            PacketDescBlock += BD_SIZE; /* point to next context field */
+        }
+    } 
+    
+    /*
+     * Replenish the posted receive buffers. 
+     * DO NOT replenish buffers if the driver has already
+     * initiated a reboot or shutdown!
+     */
+
+    if (!pDpa->shutdown && !pDpa->reboot)
+       {
+               count = RC_allocate_and_post_buffers(dev, 
+                       MAX_NMBR_RCV_BUFFERS-pDpa->numOutRcvBuffers);
+               pDpa->numOutRcvBuffers += count;
+       }
+
+}
+
+/*
+ * RCinterrupt()
+ * 
+ * Interrupt handler. 
+ * This routine sets up a couple of pointers and calls
+ * RCProcMsgQ(), which in turn process the message and
+ * calls one of our callback functions.
+ */
+static void 
+RCinterrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+     PDPA pDpa;
+     struct device *dev = (struct device *)(dev_id);
+
+     pDpa = (PDPA) (dev->priv);
+     
+     if (pDpa->shutdown)
+         printk("rc: shutdown: service irq\n");
+
+#ifdef RCDEBUG
+     printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", 
+            (uint)pDpa, (uint)dev, (uint)pDpa->id);
+     printk("dev = 0x%x\n", (uint)dev);
+#endif
+     if (dev->interrupt)
+          printk("%s: Re-entering the interrupt handler.\n", dev->name);
+     dev->interrupt = 1;
+
+     RCProcMsgQ(pDpa->id);
+     dev->interrupt = 0;
+
+     return;
+}
+
+static int
+RCclose(struct device *dev)
+{
+
+     PDPA pDpa = (PDPA) dev->priv;
+
+#ifdef RCDEBUG
+     printk("rc: RCclose\r\n");
+#endif
+     if (pDpa->reboot)
+     {
+          printk("rc: skipping reset -- adapter already in reboot mode\n");
+          dev->flags &= ~IFF_UP;
+          pDpa->shutdown = 1;
+          return 0;
+     }
+#ifdef RCDEBUG
+     printk("rc: receive buffers outstanding: %d\n", 
+            (uint)pDpa->numOutRcvBuffers);
+#endif
+
+     pDpa->shutdown = 1;
+
+     /*
+      * We can't allow the driver to be unloaded until the adapter returns
+      * all posted receive buffers.  It doesn't hurt to tell the adapter
+      * to return all posted receive buffers and outstanding xmit buffers,
+      * even if there are none.
+      */
+
+     RCShutdownLANCard(pDpa->id, 
+                       RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | 
+                       RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+                       (PFNCALLBACK)RCreset_callback);
+
+     dev->flags &= ~IFF_UP;
+     return 0;
+}
+
+static struct enet_statistics *
+RCget_stats(struct device *dev)
+{
+    RCLINKSTATS    RCstats;
+   
+    PDPA pDpa = dev->priv;
+
+    if (!pDpa)
+    {
+        printk("rc: RCget_stats: !pDpa\n");
+        return 0;
+    }
+    else if (!(dev->flags & IFF_UP))    
+    {
+#ifdef RCDEBUG
+               printk("rc: RCget_stats: device down\n");
+#endif
+        return 0;
+    }
+
+    memset(&RCstats, 0, sizeof(RCLINKSTATS));
+    if ( (RCGetLinkStatistics(pDpa->id, &RCstats, (void *)0)) == RC_RTN_NO_ERROR )
+    {
+#ifdef RCDEBUG
+        printk("rc: TX_good 0x%x\n", (uint)RCstats.TX_good);
+        printk("rc: TX_maxcol 0x%x\n", (uint)RCstats.TX_maxcol);
+        printk("rc: TX_latecol 0x%x\n", (uint)RCstats.TX_latecol);
+        printk("rc: TX_urun 0x%x\n", (uint)RCstats.TX_urun);
+        printk("rc: TX_crs 0x%x\n", (uint)RCstats.TX_crs);
+        printk("rc: TX_def 0x%x\n", (uint)RCstats.TX_def);
+        printk("rc: TX_singlecol 0x%x\n", (uint)RCstats.TX_singlecol);
+        printk("rc: TX_multcol 0x%x\n", (uint)RCstats.TX_multcol);
+        printk("rc: TX_totcol 0x%x\n", (uint)RCstats.TX_totcol);
+
+        printk("rc: Rcv_good 0x%x\n", (uint)RCstats.Rcv_good);
+        printk("rc: Rcv_CRCerr 0x%x\n", (uint)RCstats.Rcv_CRCerr);
+        printk("rc: Rcv_alignerr 0x%x\n", (uint)RCstats.Rcv_alignerr);
+        printk("rc: Rcv_reserr 0x%x\n", (uint)RCstats.Rcv_reserr);
+        printk("rc: Rcv_orun 0x%x\n", (uint)RCstats.Rcv_orun);
+        printk("rc: Rcv_cdt 0x%x\n", (uint)RCstats.Rcv_cdt);
+        printk("rc: Rcv_runt 0x%x\n", (uint)RCstats.Rcv_runt);
+#endif
+
+        pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received    */
+        pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted    */
+
+        pDpa->stats.rx_errors = 
+            RCstats.Rcv_CRCerr +
+            RCstats.Rcv_alignerr + 
+            RCstats.Rcv_reserr + 
+            RCstats.Rcv_orun + 
+            RCstats.Rcv_cdt + 
+            RCstats.Rcv_runt; /* bad packets received        */
+
+        pDpa->stats.tx_errors = 
+            RCstats.TX_urun + 
+            RCstats.TX_crs + 
+            RCstats.TX_def + 
+            RCstats.TX_totcol; /* packet transmit problems    */
+
+        /*
+         * This needs improvement.
+         */
+        pDpa->stats.rx_dropped = 0;        /* no space in linux buffers    */
+        pDpa->stats.tx_dropped = 0;        /* no space available in linux    */
+        pDpa->stats.multicast = 0;        /* multicast packets received    */
+        pDpa->stats.collisions = RCstats.TX_totcol;
+
+        /* detailed rx_errors: */
+        pDpa->stats.rx_length_errors = 0;
+        pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow    */
+        pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr;    /* recved pkt with crc error    */
+        pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */
+        pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun        */
+        pDpa->stats.rx_missed_errors = 0; /* receiver missed packet    */
+
+        /* detailed tx_errors */
+        pDpa->stats.tx_aborted_errors = 0;
+        pDpa->stats.tx_carrier_errors = 0;
+        pDpa->stats.tx_fifo_errors = 0;
+        pDpa->stats.tx_heartbeat_errors = 0;
+        pDpa->stats.tx_window_errors = 0;
+
+        return ((struct enet_statistics *)&(pDpa->stats));
+    }
+    return 0;
+}
+
+static int RCioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+    RCuser_struct RCuser;
+    PDPA pDpa = dev->priv;
+
+#if RCDEBUG
+    printk("RCioctl: cmd = 0x%x\n", cmd);
+#endif
+    switch (cmd)  {
+        case RCU_PROTOCOL_REV:
+             /*
+              * Assign user protocol revision, to tell user-level
+              * controller program whether or not it's in sync.
+              */
+             rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
+             break;
+  
+
+        case RCU_COMMAND:
+        {
+            int error;
+
+            error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser));
+            if (error)  {
+                return error;
+            }
+            memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser));
+        
+#ifdef RCDEBUG
+            printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
+#endif
+  
+            switch(RCuser.cmd)
+            {
+                case RCUC_GETFWVER:
+                    printk("RC GETFWVER\n");
+                    RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
+                    RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL);
+                    break;
+                case RCUC_GETINFO:
+                    printk("RC GETINFO\n");
+                    RCUD_GETINFO = &RCuser.RCUS_GETINFO;
+                    RCUD_GETINFO -> mem_start = dev->base_addr;
+                    RCUD_GETINFO -> mem_end = dev->base_addr + 32768;
+                    RCUD_GETINFO -> base_addr = pDpa->pci_addr;
+                    RCUD_GETINFO -> irq = dev->irq;
+                    break;
+                case RCUC_GETIPANDMASK:
+                    printk("RC GETIPANDMASK\n");
+                    RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
+                    RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr,
+                        (PU32) &RCUD_GETIPANDMASK->NetMask, NULL);
+                    break;
+                case RCUC_GETLINKSTATISTICS:
+                    printk("RC GETLINKSTATISTICS\n");
+                    RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS;
+                    RCGetLinkStatistics(pDpa->id, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL);
+                    break;
+                case RCUC_GETLINKSTATUS:
+                    printk("RC GETLINKSTATUS\n");
+                    RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
+                    RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL);
+                    break;
+                case RCUC_GETMAC:
+                    printk("RC GETMAC\n");
+                    RCUD_GETMAC = &RCuser.RCUS_GETMAC;
+                    RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL);
+                    break;
+                case RCUC_GETSPEED:
+                    printk("RC GETSPEED\n");
+                    if (!(dev->flags & IFF_UP))    
+                    {
+                        printk("RCioctl, GETSPEED error: interface down\n");
+                        return -ENODATA;
+                    }
+                    RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
+                    RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL);
+                    printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode);
+                    break;
+                default:
+                    printk("RC command default\n");
+                    RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
+                    RCUD_DEFAULT -> rc = 0x11223344;
+                    break;
+            }
+            memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser));
+            break;
+        }   /* RCU_COMMAND */ 
+
+        default:
+            printk("RC default\n");
+            rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
+            break;
+    }
+    return 0;
+}
+
+static int RCconfig(struct device *dev, struct ifmap *map)
+{
+     /*
+      * To be completed ...
+      */
+      printk("rc: RCconfig\n");
+      return 0;
+      if (dev->flags & IFF_UP)    /* can't act on a running interface */
+           return -EBUSY;
+
+     /* Don't allow changing the I/O address */
+     if (map->base_addr != dev->base_addr) {
+          printk(KERN_WARNING "RC pci45: Change I/O address not implemented\n");
+          return -EOPNOTSUPP;
+     }
+     return 0;
+}
+
+void
+cleanup_module(void)
+{
+     PDPA pDpa;
+     struct device *next;
+
+
+#ifdef RCDEBUG
+     printk("rc: RC cleanup_module\n");
+     printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev);
+#endif
+
+
+     while (root_RCdev)
+     {
+          pDpa = (PDPA) root_RCdev->priv;
+#ifdef RCDEBUG
+          printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
+#endif
+          printk("Adapter reset: 0x%x\n", RCResetAdapter(pDpa->id));
+          unregister_netdev(root_RCdev);
+          next = pDpa->next;
+
+          vfree((unsigned long *)root_RCdev->base_addr); 
+          free_irq( root_RCdev->irq, root_RCdev );
+          kfree(root_RCdev);
+          root_RCdev = next;
+     }
+}
+
+static int
+RC_allocate_and_post_buffers(struct device *dev, int numBuffers)
+{
+
+     int i;
+     PDPA pDpa = (PDPA)dev->priv;
+     PU32 p;
+     psingleB pB;
+     struct sk_buff *skb;
+     RC_RETURN status;
+
+     if (!numBuffers)
+          return 0;
+     else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+     {
+#ifdef RCDEBUG
+          printk("rc: Too many buffers requested!\n");
+          printk("rc: attempting to allocate only 32 buffers\n");
+#endif
+          numBuffers = 32;
+     }
+    
+     p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
+
+#ifdef RCDEBUG
+     printk("rc: TCB = 0x%x\n", (uint)p);
+#endif
+
+     if (!p)
+     {
+          printk("rc: RCopen: unable to allocate TCB\n");
+          return 0;
+     }
+
+     p[0] = 0;                              /* Buffer Count */
+     pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+
+#ifdef RCDEBUG
+     printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB);
+     printk("rc: pB = 0x%x\n", (uint)pB);
+#endif
+
+     for (i=0; i<numBuffers; i++)
+     {
+          skb = dev_alloc_skb(MAX_ETHER_SIZE+2);
+          if (!skb)
+          {
+               printk("rc: Doh! RCopen: unable to allocate enough skbs!\n");
+               if (*p != 0)        /* did we allocate any buffers at all? */
+               {
+#ifdef RCDEBUG
+                    printk("rc: will post only %d buffers \n", (uint)(*p));
+#endif
+                    break;
+               }
+               else 
+               {
+                    kfree(p);    /* Free the TCB */
+                    return 0;
+               }
+          }
+#ifdef RCDEBUG
+          printk("post 0x%x\n", (uint)skb);
+#endif
+          skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+          pB->context = (U32)skb;
+          pB->scount = 1;        /* segment count */
+          pB->size = MAX_ETHER_SIZE;
+          pB->addr = (U32)skb->data;
+          p[0]++;
+          pB++;
+     }
+
+     if ( (status = RCPostRecvBuffers(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR)
+     {
+          printk("rc: Post buffer failed with error code 0x%x!\n", status);
+          pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+          while(p[0])
+          {
+               skb = (struct sk_buff *)pB->context;
+               skb->free = 1;    
+#ifdef RCDEBUG
+               printk("rc: freeing 0x%x\n", (uint)skb);
+#endif
+               dev_kfree_skb(skb, FREE_READ);
+               p[0]--;
+               pB++;
+          }
+#ifdef RCDEBUG
+           printk("rc: freed all buffers, p[0] = %ld\n", p[0]);
+#endif
+     }
+     kfree(p);
+     return(p[0]);                /* return the number of posted buffers */
+}
index 3422a88cb8dd3cb354fe1dd194f6c3dcb9338274..fc81c94c8010107f6265e9e77eb9fe53b8cca6f0 100644 (file)
@@ -483,7 +483,7 @@ static int shaper_ioctl(struct device *dev,  struct ifreq *ifr, int cmd)
                case SHAPER_GET_DEV:
                        if(sh->dev==NULL)
                                return -ENODEV;
-                       memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+                       memcpy(ss->ss_name, sh->dev->name, strlen(sh->dev->name)+1);
                        return 0;
                case SHAPER_SET_SPEED:
                        shaper_setspeed(sh,ss->ss_speed);
index b0688a1ae1dfa9604dcc479a81366a4cbf87f21b..6eabf8eba4563392d658b3c2d28821173a0702f6 100644 (file)
@@ -400,6 +400,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( LITEON,         LITEON_LNE100TX,"LNE100TX"),
        DEVICE( NP,             NP_PCI_FDDI,    "NP-PCI"),       
        DEVICE( ATT,            ATT_L56XMF,     "L56xMF"),
+       DEVICE( SPECIALIX,      SPECIALIX_IO8,  "IO8+/PCI"),
        DEVICE( SPECIALIX,      SPECIALIX_XIO,  "XIO/SIO host"),
        DEVICE( SPECIALIX,      SPECIALIX_RIO,  "RIO host"),
        DEVICE( AURAVISION,     AURAVISION_VXP524,"VXP524"),
@@ -835,6 +836,7 @@ const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_ATRONICS:      return "Atronics";
              case PCI_VENDOR_ID_ARK:           return "ARK Logic";
              case PCI_VENDOR_ID_ASIX:          return "ASIX";
+             case PCI_VENDOR_ID_LITEON:        return "Lite-on";
              default:                          return "Unknown vendor";
        }
 }
index c57fcd003717a2a1eed8fca244dfa4df5f4ee8e1..446b3260ef84d1205541dd7efad0e72d1991672d 100644 (file)
@@ -1005,11 +1005,22 @@ static void get_more_buffer_heads(void)
                 * This is no longer true, it is GFP_BUFFER again, the
                 * swapping code now knows not to perform I/O when that
                 * GFP level is specified... -DaveM
+                * 
+                * Ouch, another bug!  get_free_page() does not call
+                * try_to_free_page() if priority == GFP_BUFFER.  This
+                * lets kswapd get into a lockup situation if there is
+                * no free space for buffer growth but we need more
+                * memory for a buffer_head for swapping.  If memory is
+                * full of recyclable buffers, we deadlock because
+                * kswapd won't recycle them!  Use GFP_IO instead: it
+                * still won't recurse (GFP_IO sets can_do_io to zero in
+                * try_to_free_page), but it lets us recover those
+                * buffer heads.  --sct
                 */
                /* we now use kmalloc() here instead of gfp as we want
                    to be able to easily release buffer heads - they
                    took up quite a bit of memory (tridge) */
-               bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_BUFFER);
+               bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_IO);
                if (bh) {
                        put_unused_buffer_head(bh);
                        nr_buffer_heads++;
index 37dab80bff5d68f8bb0f3077a3009949e5f07467..3d3942050cc93138531bf63e2ae65de3aae6f230 100644 (file)
@@ -324,6 +324,12 @@ int fat_file_write(struct inode *inode,struct file *filp,const char *buf,int cou
 #else
        if (count <= 0) return 0;
 #endif
+       if (filp->f_pos + count > 0x7FFFFFFFLL) {
+               count = 0x7FFFFFFFLL - filp->f_pos;
+               if (!count)
+                       return -EFBIG;
+       }
+
        error = carry = 0;
        for (start = buf; count || carry; count -= size) {
                while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
index 30db04cc74474c41ab73d7139a7c67630d117801..5e243023f67f270e9cfd8d30fd8930d1aa5922bf 100644 (file)
@@ -969,7 +969,6 @@ static int vfat_find(struct inode *dir,const char *name,int len,
                sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
                sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
                res = 0;
-               return 0;
        } else {
                res = -ENOENT;
        }
index 0f3c5b846b526213b3881e07f0712a322bccf6e1..6e26f6b28f2338ee00b48563be40cf41a7ade5bc 100644 (file)
@@ -289,14 +289,19 @@ static void check_cyrix_various(void)
                {       /* if has DIR0/DIR1 */
                
                        char ccr3;
+                       char dir0;
                        x86_model = 0;
 
                        /* Enable MAPEN */
                        ccr3 = getCx86(CX86_CCR3);
                        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
 
-                       /* try enabling cpuid */
-                       setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
+                       dir0 = getCx86(CX86_DIR0);
+                       if ((dir0 & 0xf0) == 0x30)      /* Use DIR0 to determine if this is a 6x86 class processor */
+                       {
+                               /* try enabling cpuid */
+                               setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
+                       }
 
                        if (test_cpuid()) 
                        {
@@ -315,6 +320,7 @@ static void check_cyrix_various(void)
                        /* disable MAPEN */
                        setCx86(CX86_CCR3, ccr3);
                } /* endif has DIR0/DIR1 */
+               sti();
                restore_flags(flags);   /* restore interrupt state */
        } /* endif it's a Cyrix */
 }
index ddd5f9d59b21b7438aa68720c1dcabb5c95ddb31..d9148fb47629fe8b8e122af8acc00de65b872e12 100644 (file)
 #define PCI_DEVICE_ID_ATT_L56XMF       0x0440
 
 #define PCI_VENDOR_ID_SPECIALIX                0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8    0x2000
 #define PCI_DEVICE_ID_SPECIALIX_XIO    0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO    0x8000
 
index a648cec6086f43441b9d6e88d348e7fbbd21b6d8..bcb6e79628fb82ab18e05c90726c009b1fcd9a46 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -658,6 +658,7 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
                        oom(current);
                        return BAD_PAGE;
                }
+       repeat:
                pte_val(pte) = shp->shm_pages[idx];
                if (pte_present(pte)) {
                        free_page (page); /* doesn't sleep */
@@ -665,11 +666,8 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
                }
                if (!pte_none(pte)) {
                        read_swap_page(pte_val(pte), (char *) page);
-                       pte_val(pte) = shp->shm_pages[idx];
-                       if (pte_present(pte))  {
-                               free_page (page); /* doesn't sleep */
-                               goto done;
-                       }
+                       if (pte_val(pte) != shp->shm_pages[idx])
+                               goto repeat;
                        swap_free(pte_val(pte));
                        shm_swp--;
                }
@@ -699,6 +697,7 @@ static unsigned long swap_idx = 0; /* next to swap */
 int shm_swap (int prio, int dma)
 {
        pte_t page;
+       struct page *page_map;
        struct shmid_ds *shp;
        struct vm_area_struct *shmd;
        unsigned long swap_nr;
@@ -733,7 +732,10 @@ int shm_swap (int prio, int dma)
        pte_val(page) = shp->shm_pages[idx];
        if (!pte_present(page))
                goto check_table;
-       if (dma && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
+       page_map = &mem_map[MAP_NR(pte_page(page))];
+       if (PageLocked(page_map))
+               goto check_table;
+       if (dma && !PageDMA(page_map))
                goto check_table;
        swap_attempts++;
 
index dd6e6a966e7fa5683a2a0e77ffdc16009fbf767e..59ff26a79799c38ed38ca270da65f1f0c9e941b9 100644 (file)
@@ -415,7 +415,7 @@ int try_to_free_page(int priority, int dma, int wait)
        switch (state) {
                do {
                case 0:
-                       if (shrink_mmap(i, dma, can_do_io))
+                       if (shrink_mmap(i, dma, 1))
                                return 1;
                        state = 1;
                case 1:
index 18bb37982d5b7f371fdc72bb19e2a278a2b225c4..e1d7e6fee7924710027dcc6623dc4bec3e5ada01 100644 (file)
@@ -6,8 +6,8 @@
  *     much hacked by: Alan Cox
  */
 
-#include <linux/config.h>
 #include <linux/module.h> 
+#include <linux/config.h>
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
 
index bb8760331375a5998e36e2ed3ad1cd0a4bf03c7c..ebbba979c7df0b860b1b52f19abc61ea86f82144 100644 (file)
@@ -241,6 +241,10 @@ int sock_setsockopt(struct sock *sk, int level, int optname,
                        /* Bind this socket to a particular device like "eth0",
                         * as specified in an ifreq structure.  If the device 
                         * is "", socket is NOT bound to a device. */
+                        
+                       if(!suser())
+                               return -EPERM;
+                               
                        if (!valbool) {
                                sk->bound_device = NULL;
                        } else {
index 12310ac8131630ed5ea49bf59896ed76c9ad15b1..e3d5268bcae8a6200c1812059315305dc995078c 100644 (file)
@@ -2637,7 +2637,7 @@ retry_search:
                        /*
                         *      SYN_RECV with data maybe.. drop through
                         */
-                       goto rfc_step6;
+                       goto rfc_step4;
                }
 
        /*
@@ -2696,6 +2696,8 @@ retry_search:
 #endif 
        }
 
+rfc_step4:             /* I'll clean this up later */
+
        /*
         *      We are now in normal data flow (see the step list in the RFC)
         *      Note most of these are inline now. I'll inline the lot when
@@ -2737,8 +2739,13 @@ retry_search:
         *      Process the ACK
         */
         
+       if(!th->ack)
+       {
+               kfree_skb(skb, FREE_WRITE);
+               return 0;
+       }
 
-       if(th->ack && !tcp_ack(sk,th,skb->ack_seq,len))
+       if(!tcp_ack(sk,th,skb->ack_seq,len))
        {
                /*
                 *      Our three way handshake failed.
@@ -2752,7 +2759,6 @@ retry_search:
                return 0;
        }
        
-rfc_step6:             /* I'll clean this up later */
 
        /*
         *      If the accepted buffer put us over our queue size we
index 368d7728ea2e9e7d7fbdc6a8dedd5bf06e691e84..948877a5a7b573883bd499b6f907c0e074427423 100644 (file)
@@ -1621,7 +1621,7 @@ void rose_proto_init(struct net_proto *pro)
 
        sock_register(rose_proto_ops.family, &rose_proto_ops);
        register_netdevice_notifier(&rose_dev_notifier);
-       printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.035 Linux 2.0\n");
+       printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.63 for AX25.035 Linux 2.0\n");
 
        if (!ax25_protocol_register(AX25_P_ROSE, rose_route_frame))
                printk(KERN_ERR "ROSE: unable to register protocol with AX.25\n");
index 9fcf94b198a6e49cc12aae12f60be376dd5bec25..4eeb2736fd604962c62a852e0c8c76a2d7800401 100644 (file)
@@ -48,12 +48,11 @@ void rose_clear_queues(struct sock *sk)
                kfree_skb(skb, FREE_WRITE);
 
        while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
-               kfree_skb(skb, FREE_READ);
+               kfree_skb(skb, FREE_WRITE);
 
 #ifdef M_BIT
-       while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+       while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL)
                kfree_skb(skb, FREE_READ);
-       }
 #endif
 }
 
index 7d73eac5c35c7064cf1882eeb613a7a4508dbe3b..3975c02f51dc5bfbe9ea46eb54aa42d4d916a3f5 100644 (file)
@@ -89,6 +89,7 @@ static int sock_write(struct inode *inode, struct file *file, const char *buf,
                      int size);
 
 static void sock_close(struct inode *inode, struct file *file);
+static int sock_no_open(struct inode *inode, struct file *file);
 static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
 static int sock_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, unsigned long arg);
@@ -108,7 +109,7 @@ static struct file_operations socket_file_ops = {
        sock_select,
        sock_ioctl,
        NULL,                   /* mmap */
-       NULL,                   /* no special open code... */
+       sock_no_open,           /* special open code... */
        sock_close,
        NULL,                   /* no fsync */
        sock_fasync
@@ -297,6 +298,17 @@ static inline void sock_release_peer(struct socket *peer)
        sock_wake_async(peer, 1);
 }
 
+/*
+ *     In theory you can't get an open on this inode, but /proc provides
+ *     a back door. Remember to keep it shut otherwise you'll let the
+ *     creepy crawlies in.
+ */
+  
+static int sock_no_open(struct inode *inode, struct file *file)
+{
+       return -ENXIO;
+}
+
 void sock_release(struct socket *sock)
 {
        int oldstate;
index 46ead621978aad7ec9d8365aac6faae11261f55c..b28b5a47c93a7e37a66263b567e876ba3a5cf9f8 100644 (file)
  *     2 of the License, or (at your option) any later version.
  *
  *  Fixes:
+ *     Al Viro         11 Oct 1998
+ *             Graph may have cycles. That is, we can send the descriptor
+ *             of foo to bar and vice versa. Current code chokes on that.
+ *             Fix: move SCM_RIGHTS ones into the separate list and then
+ *             kfree_skb() them all instead of doing explicit fput's.
+ *             Another problem: since fput() may block somebody may
+ *             create a new unix_socket when we are in the middle of sweep
+ *             phase. Fix: revert the logic wrt MARKED. Mark everything
+ *             upon the beginning and unmark non-junk ones.
+ *
+ *             [12 Oct 1998] AAARGH! New code purges all SCM_RIGHTS
+ *             sent to connect()'ed but still not accept()'ed sockets.
+ *             Fixed. Old code had slightly different problem here:
+ *             extra fput() in situation when we passed the descriptor via
+ *             such socket and closed it (descriptor). That would happen on
+ *             each unix_gc() until the accept(). Since the struct file in
+ *             question would go to the free list and might be reused...
+ *             That might be the reason of random oopses on close_fp() in
+ *             unrelated processes.
  *
  */
  
@@ -136,11 +155,11 @@ extern inline int empty_stack(void)
        return in_stack == 0;
 }
 
-extern inline void maybe_mark_and_push(unix_socket *x)
+extern inline void maybe_unmark_and_push(unix_socket *x)
 {
-       if (x->protinfo.af_unix.marksweep&MARKED)
+       if (!(x->protinfo.af_unix.marksweep&MARKED))
                return;
-       x->protinfo.af_unix.marksweep|=MARKED;
+       x->protinfo.af_unix.marksweep&=~MARKED;
        push_stack(x);
 }
 
@@ -151,8 +170,9 @@ void unix_gc(void)
 {
        static int in_unix_gc=0;
        unix_socket *s;
-       unix_socket *next;
-       
+       struct sk_buff *skb;
+       struct sk_buff_head hitlist;
+               
        /*
         *      Avoid a recursive GC.
         */
@@ -170,16 +190,21 @@ void unix_gc(void)
        }
        
        /*
-        *      Assume everything is now unmarked 
+        *      Everything is now marked
         */
 
+       for(s=unix_socket_list;s!=NULL;s=s->next)
+       {
+               s->protinfo.af_unix.marksweep|=MARKED;
+       }
+       
        /* Invariant to be maintained:
-               - everything marked is either:
+               - everything unmarked is either:
                -- (a) on the stack, or
-               -- (b) has all of its children marked
-               - everything on the stack is always marked
+               -- (b) has all of its children unmarked
+               - everything on the stack is always unmarked
                - nothing is ever pushed onto the stack twice, because:
-               -- nothing previously marked is ever pushed on the stack
+               -- nothing previously unmarked is ever pushed on the stack
         */
 
        /*
@@ -192,19 +217,19 @@ void unix_gc(void)
                 *      If all instances of the descriptor are not
                 *      in flight we are in use.
                 */
-               if(s->socket && s->socket->file && s->socket->file->f_count > s->protinfo.af_unix.inflight)
-                       maybe_mark_and_push(s);
+               if(s->socket && s->socket->file && 
+                       s->socket->file->f_count > s->protinfo.af_unix.inflight)
+                       maybe_unmark_and_push(s);
        }
 
        /*
-        *      Mark phase 
+        *      Mark phase
         */
 
        while (!empty_stack())
        {
                unix_socket *x = pop_stack();
                unix_socket *f=NULL,*sk;
-               struct sk_buff *skb;
 tail:          
                skb=skb_peek(&x->receive_queue);
                
@@ -233,27 +258,38 @@ tail:
                                        if((sk=unix_get_socket(*fp++))!=NULL)
                                        {
                                                /*
-                                                *      Remember the first, mark the
+                                                *      Remember the first, unmark the
                                                 *      rest.
                                                 */
                                                if(f==NULL)
                                                        f=sk;
                                                else
-                                                       maybe_mark_and_push(sk);
+                                                       maybe_unmark_and_push(sk);
                                        }
                                }
                        }
+                       /* 
+                        *      If we are connecting we need to handle this too
+                        */
+                       if(x->state == TCP_LISTEN)
+                       {
+                               if(f==NULL)
+                                       f=skb->sk;
+                               else
+                                       maybe_unmark_and_push(skb->sk);
+                       }                        
                        skb=skb->next;
                }
+
                /*
                 *      Handle first born specially 
                 */
 
                if (f) 
                {
-                       if (!(f->protinfo.af_unix.marksweep&MARKED))
+                       if (f->protinfo.af_unix.marksweep&MARKED)
                        {
-                               f->protinfo.af_unix.marksweep|=MARKED;
+                               f->protinfo.af_unix.marksweep&=~MARKED;
                                x=f;
                                f=NULL;
                                goto tail;
@@ -261,35 +297,44 @@ tail:
                }
        }
 
-       /*
-        *      Sweep phase.  NOTE: this part dominates the time complexity 
-        */
+       skb_queue_head_init(&hitlist);
 
-       for(s=unix_socket_list;s!=NULL;s=next)
+       for(s=unix_socket_list;s!=NULL;s=s->next)
        {
-               next=s->next;
-               if (!(s->protinfo.af_unix.marksweep&MARKED))
+               if (s->protinfo.af_unix.marksweep&MARKED)
                {
-                       /*
-                        *      We exist only in the passing tree of sockets
-                        *      that is no longer connected to active descriptors
-                        *      Time to die..
-                        *
-                        *      Subtle item: We will correctly sweep out the
-                        *      socket that has just been closed by the user.
-                        *      We must not close this as we are in the middle
-                        *      of its close at this moment. Skip that file
-                        *      using f_count==0 to spot it.
-                        */
-                        
-                       if(s->socket && s->socket->file && s->socket->file->f_count)
-                               close_fp(s->socket->file);
+                       struct sk_buff *nextsk;
+                       skb=skb_peek(&s->receive_queue);
+                       while(skb && skb != (struct sk_buff *)&s->receive_queue)
+                       {
+                               nextsk=skb->next;
+                               /*
+                                *      Do we have file descriptors ?
+                                */
+                               if(*(int *)(skb->h.filp))
+                               {
+                                       /* 
+                                        *      Pull these buffers out of line
+                                        *      so they will each be freed once
+                                        *      at the end.
+                                        */             
+                                       skb_unlink(skb);
+                                       skb_queue_tail(&hitlist,skb);
+                               }
+                               skb=nextsk;
+                       }
                }
-               else
-                       s->protinfo.af_unix.marksweep&=~MARKED; /* unmark everything for next collection */
        }
-       
+
+       /*
+        *      Here we are. Hitlist is filled. Die.
+        */
+
+       while ((skb=skb_dequeue(&hitlist))!=NULL) 
+       {
+               kfree_skb(skb, FREE_READ);
+       }
+
        in_unix_gc=0;
-       
        vfree(stack);
 }