Add ocf to 2.6.25 for ubsec ssb integration
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Tue, 15 Jul 2008 17:11:16 +0000 (17:11 +0000)
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Tue, 15 Jul 2008 17:11:16 +0000 (17:11 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11839 3c298f89-4303-0410-b956-a3cf2f4a3e73

target/linux/generic-2.6/patches-2.6.25/950-ocf-linux-26-20080704.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/951-ocf-scatterlist-inc.patch [new file with mode: 0644]

diff --git a/target/linux/generic-2.6/patches-2.6.25/950-ocf-linux-26-20080704.patch b/target/linux/generic-2.6/patches-2.6.25/950-ocf-linux-26-20080704.patch
new file mode 100644 (file)
index 0000000..59a84c2
--- /dev/null
@@ -0,0 +1,19499 @@
+Index: linux-2.6.x/crypto/Kconfig
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/crypto/Kconfig,v
+retrieving revision 1.1.1.29
+diff -u -r1.1.1.29 Kconfig
+--- linux-2.6.x/crypto/Kconfig 10 Oct 2007 00:54:29 -0000      1.1.1.29
++++ linux-2.6.x/crypto/Kconfig 15 Dec 2007 11:08:08 -0000
+@@ -471,3 +471,6 @@
+ source "drivers/crypto/Kconfig"
+ endif # if CRYPTO
++
++source "crypto/ocf/Kconfig"
++
+Index: linux-2.6.x/crypto/Makefile
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/crypto/Makefile,v
+retrieving revision 1.1.1.23
+diff -u -r1.1.1.23 Makefile
+--- linux-2.6.x/crypto/Makefile        10 Oct 2007 00:54:29 -0000      1.1.1.23
++++ linux-2.6.x/crypto/Makefile        15 Dec 2007 11:08:08 -0000
+@@ -51,6 +51,8 @@
+ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
++obj-$(CONFIG_OCF_OCF) += ocf/
++
+ #
+ # generic algorithms and the async_tx api
+ #
+Index: linux-2.6.x/drivers/char/random.c
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/drivers/char/random.c,v
+retrieving revision 1.1.1.41
+retrieving revision 1.6
+diff -u -r1.1.1.41 -r1.6
+--- linux-2.6.x/drivers/char/random.c  22 Apr 2008 01:36:57 -0000      1.1.1.41
++++ linux-2.6.x/drivers/char/random.c  22 Apr 2008 04:48:56 -0000      1.6
+@@ -129,6 +129,9 @@
+  *                                unsigned int value);
+  *    void add_interrupt_randomness(int irq);
+  *
++ *      void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
++ *      int random_input_wait(void);
++ *
+  * add_input_randomness() uses the input layer interrupt timing, as well as
+  * the event type information from the hardware.
+  *
+@@ -140,6 +143,13 @@
+  * a better measure, since the timing of the disk interrupts are more
+  * unpredictable.
+  *
++ * random_input_words() just provides a raw block of entropy to the input
++ * pool, such as from a hardware entropy generator.
++ *
++ * random_input_wait() suspends the caller until such time as the
++ * entropy pool falls below the write threshold, and returns a count of how
++ * much entropy (in bits) is needed to sustain the pool.
++ *
+  * All of these routines try to estimate how many bits of randomness a
+  * particular randomness source.  They do this by keeping track of the
+  * first and second order deltas of the event timings.
+@@ -669,6 +679,61 @@
+ }
+ #endif
++/*
++ * random_input_words - add bulk entropy to pool
++ *
++ * @buf: buffer to add
++ * @wordcount: number of __u32 words to add
++ * @ent_count: total amount of entropy (in bits) to credit
++ *
++ * this provides bulk input of entropy to the input pool
++ *
++ */
++void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
++{
++      add_entropy_words(&input_pool, buf, wordcount);
++
++      credit_entropy_store(&input_pool, ent_count);
++
++      DEBUG_ENT("crediting %d bits => %d\n",
++                ent_count, input_pool.entropy_count);
++      /*
++       * Wake up waiting processes if we have enough
++       * entropy.
++       */
++      if (input_pool.entropy_count >= random_read_wakeup_thresh)
++              wake_up_interruptible(&random_read_wait);
++}
++EXPORT_SYMBOL(random_input_words);
++
++/*
++ * random_input_wait - wait until random needs entropy
++ *
++ * this function sleeps until the /dev/random subsystem actually
++ * needs more entropy, and then return the amount of entropy
++ * that it would be nice to have added to the system.
++ */
++int random_input_wait(void)
++{
++      int count;
++
++      wait_event_interruptible(random_write_wait, 
++                       input_pool.entropy_count < random_write_wakeup_thresh);
++
++      count = random_write_wakeup_thresh - input_pool.entropy_count;
++
++        /* likely we got woken up due to a signal */
++      if (count <= 0) count = random_read_wakeup_thresh; 
++
++      DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n",
++                count,
++                input_pool.entropy_count, random_write_wakeup_thresh);
++
++      return count;
++}
++EXPORT_SYMBOL(random_input_wait);
++
++
+ #define EXTRACT_SIZE 10
+ /*********************************************************************
+Index: linux-2.6.x/fs/fcntl.c
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/fs/fcntl.c,v
+retrieving revision 1.1.1.39
+retrieving revision 1.5
+diff -u -r1.1.1.39 -r1.5
+--- linux-2.6.x/fs/fcntl.c     22 Apr 2008 01:37:55 -0000      1.1.1.39
++++ linux-2.6.x/fs/fcntl.c     22 Apr 2008 04:49:02 -0000      1.5
+@@ -202,6 +202,7 @@
+               ret = dupfd(file, 0, 0);
+       return ret;
+ }
++EXPORT_SYMBOL(sys_dup);
+ #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
+Index: linux-2.6.x/include/linux/miscdevice.h
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/include/linux/miscdevice.h,v
+retrieving revision 1.1.1.16
+retrieving revision 1.8
+diff -u -r1.1.1.16 -r1.8
+--- linux-2.6.x/include/linux/miscdevice.h     22 Apr 2008 01:36:52 -0000      1.1.1.16
++++ linux-2.6.x/include/linux/miscdevice.h     22 Apr 2008 04:49:10 -0000      1.8
+@@ -12,6 +12,7 @@
+ #define APOLLO_MOUSE_MINOR 7
+ #define PC110PAD_MINOR 9
+ /*#define ADB_MOUSE_MINOR 10  FIXME OBSOLETE */
++#define CRYPTODEV_MINOR               70      /* /dev/crypto */
+ #define WATCHDOG_MINOR                130     /* Watchdog timer     */
+ #define TEMP_MINOR            131     /* Temperature Sensor */
+ #define RTC_MINOR 135
+Index: linux-2.6.x/include/linux/random.h
+===================================================================
+RCS file: /cvs/sw/linux-2.6.x/include/linux/random.h,v
+retrieving revision 1.1.1.12
+retrieving revision 1.5
+diff -u -r1.1.1.12 -r1.5
+--- linux-2.6.x/include/linux/random.h 26 Apr 2007 11:16:52 -0000      1.1.1.12
++++ linux-2.6.x/include/linux/random.h 22 May 2008 03:31:38 -0000      1.5
+@@ -8,6 +8,7 @@
+ #define _LINUX_RANDOM_H
+ #include <linux/ioctl.h>
++#include <linux/types.h> /* for __u32 in user space */
+ /* ioctl()'s for the random number generator */
+@@ -32,6 +33,30 @@
+ /* Clear the entropy pool and associated counters.  (Superuser only.) */
+ #define RNDCLEARPOOL  _IO( 'R', 0x06 )
++#ifdef CONFIG_FIPS_RNG
++
++/* Size of seed value - equal to AES blocksize */
++#define AES_BLOCK_SIZE_BYTES  16
++#define SEED_SIZE_BYTES                       AES_BLOCK_SIZE_BYTES
++/* Size of AES key */
++#define KEY_SIZE_BYTES                16
++
++/* ioctl() structure used by FIPS 140-2 Tests */
++struct rand_fips_test {
++      unsigned char key[KEY_SIZE_BYTES];                      /* Input */
++      unsigned char datetime[SEED_SIZE_BYTES];        /* Input */
++      unsigned char seed[SEED_SIZE_BYTES];            /* Input */
++      unsigned char result[SEED_SIZE_BYTES];          /* Output */
++};
++
++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */
++#define RNDFIPSVST    _IOWR('R', 0x10, struct rand_fips_test)
++
++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */
++#define RNDFIPSMCT    _IOWR('R', 0x11, struct rand_fips_test)
++
++#endif /* #ifdef CONFIG_FIPS_RNG */
++
+ struct rand_pool_info {
+       int     entropy_count;
+       int     buf_size;
+@@ -48,6 +73,10 @@
+                                unsigned int value);
+ extern void add_interrupt_randomness(int irq);
++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count);
++extern int random_input_wait(void);
++#define HAS_RANDOM_INPUT_WAIT 1
++
+ extern void get_random_bytes(void *buf, int nbytes);
+ void generate_random_uuid(unsigned char uuid_out[16]);
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/Makefile     2007-07-25 11:02:33.000000000 +1000
+@@ -0,0 +1,13 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_HIFN)     += hifn7751.o
++obj-$(CONFIG_OCF_HIFNHIPP) += hifnHIPP.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/Makefile     2007-07-25 11:02:33.000000000 +1000
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_SAFE) += safe.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/Makefile  2008-07-04 14:48:17.000000000 +1000
+@@ -0,0 +1,120 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++OCF_OBJS = crypto.o criov.o
++
++ifdef CONFIG_OCF_RANDOMHARVEST
++      OCF_OBJS += random.o
++endif
++
++ifdef CONFIG_OCF_FIPS
++      OCF_OBJS += rndtest.o
++endif
++
++# Add in autoconf.h to get #defines for CONFIG_xxx
++AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h
++ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H)))
++      EXTRA_CFLAGS += -include $(AUTOCONF_H)
++      export EXTRA_CFLAGS
++endif
++
++ifndef obj
++      obj ?= .
++      _obj = subdir
++      mod-subdirs := safe hifn ixp4xx talitos ocfnull
++      export-objs += crypto.o criov.o random.o
++      list-multi += ocf.o
++      _slash :=
++else
++      _obj = obj
++      _slash := /
++endif
++
++EXTRA_CFLAGS += -I$(obj)/.
++
++obj-$(CONFIG_OCF_OCF)         += ocf.o
++obj-$(CONFIG_OCF_CRYPTODEV)   += cryptodev.o
++obj-$(CONFIG_OCF_CRYPTOSOFT)  += cryptosoft.o
++obj-$(CONFIG_OCF_BENCH)       += ocf-bench.o
++
++$(_obj)-$(CONFIG_OCF_SAFE)    += safe$(_slash)
++$(_obj)-$(CONFIG_OCF_HIFN)    += hifn$(_slash)
++$(_obj)-$(CONFIG_OCF_IXP4XX)  += ixp4xx$(_slash)
++$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash)
++$(_obj)-$(CONFIG_OCF_PASEMI)  += pasemi$(_slash)
++$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash)
++
++ocf-objs := $(OCF_OBJS)
++
++$(list-multi) dummy1: $(ocf-objs)
++      $(LD) -r -o $@ $(ocf-objs)
++
++.PHONY:
++clean:
++      rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c
++      rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
++#
++# release gen targets
++#
++
++.PHONY: patch
++patch:
++      REL=`date +%Y%m%d`; \
++              patch=ocf-linux-$$REL.patch; \
++              patch24=ocf-linux-24-$$REL.patch; \
++              patch26=ocf-linux-26-$$REL.patch; \
++              ( \
++                      find . -name Makefile; \
++                      find . -name Config.in; \
++                      find . -name Kconfig; \
++                      find . -name README; \
++                      find . -name '*.[ch]' | grep -v '.mod.c'; \
++              ) | while read t; do \
++                      diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \
++              done > $$patch; \
++              cat patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \
++              cat patches/linux-2.6.25-ocf.patch $$patch > $$patch26
++
++.PHONY: tarball
++tarball:
++      REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \
++              CURDIR=`pwd`; \
++              rm -rf /tmp/ocf-linux-$$REL*; \
++              mkdir -p $$RELDIR/tools; \
++              cp README* $$RELDIR; \
++              cp patches/openss*.patch $$RELDIR; \
++              cp patches/crypto-tools.patch $$RELDIR; \
++              cp tools/[!C]* $$RELDIR/tools; \
++              cd ..; \
++              tar cvf $$RELDIR/ocf-linux.tar \
++                                      --exclude=CVS \
++                                      --exclude=.* \
++                                      --exclude=*.o \
++                                      --exclude=*.ko \
++                                      --exclude=*.mod.* \
++                                      --exclude=README* \
++                                      --exclude=ocf-*.patch \
++                                      --exclude=ocf/patches/openss*.patch \
++                                      --exclude=ocf/patches/crypto-tools.patch \
++                                      --exclude=ocf/tools \
++                                      ocf; \
++              gzip -9 $$RELDIR/ocf-linux.tar; \
++              cd /tmp; \
++              tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \
++              gzip -9 ocf-linux-$$REL.tar; \
++              cd $$CURDIR/../../user; \
++              rm -rf /tmp/crypto-tools-$$REL*; \
++              tar cvf /tmp/crypto-tools-$$REL.tar \
++                                      --exclude=CVS \
++                                      --exclude=.* \
++                                      --exclude=*.o \
++                                      --exclude=cryptotest \
++                                      --exclude=cryptokeytest \
++                                      crypto-tools; \
++              gzip -9 /tmp/crypto-tools-$$REL.tar
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/talitos/Makefile  2007-07-25 11:02:33.000000000 +1000
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_TALITOS) += talitos.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ixp4xx/Makefile   2007-10-19 11:24:59.000000000 +1000
+@@ -0,0 +1,104 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++#
++# You will need to point this at your Intel ixp425 includes,  this portion
++# of the Makefile only really works under SGLinux with the appropriate libs
++# installed.  They can be downloaded from http://www.snapgear.org/
++#
++ifeq ($(CONFIG_CPU_IXP46X),y)
++IXPLATFORM = ixp46X
++else
++ifeq ($(CONFIG_CPU_IXP43X),y)
++IXPLATFORM = ixp43X
++else
++IXPLATFORM = ixp42X
++endif
++endif
++
++ifdef CONFIG_IXP400_LIB_2_4
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp400_xscale_sw
++OSAL_DIR     = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp_osal
++endif
++ifdef CONFIG_IXP400_LIB_2_1
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp400_xscale_sw
++OSAL_DIR     = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp_osal
++endif
++ifdef CONFIG_IXP400_LIB_2_0
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp400_xscale_sw
++OSAL_DIR     = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp_osal
++endif
++ifdef IX_XSCALE_SW
++ifdef CONFIG_IXP400_LIB_2_4
++IXP_CFLAGS = \
++      -I$(ROOTDIR)/. \
++      -I$(IX_XSCALE_SW)/src/include \
++      -I$(OSAL_DIR)/common/include/ \
++      -I$(OSAL_DIR)/common/include/modules/ \
++      -I$(OSAL_DIR)/common/include/modules/ddk/ \
++      -I$(OSAL_DIR)/common/include/modules/bufferMgt/ \
++      -I$(OSAL_DIR)/common/include/modules/ioMem/ \
++      -I$(OSAL_DIR)/common/os/linux/include/ \
++      -I$(OSAL_DIR)/common/os/linux/include/core/  \
++      -I$(OSAL_DIR)/common/os/linux/include/modules/ \
++      -I$(OSAL_DIR)/common/os/linux/include/modules/ddk/ \
++      -I$(OSAL_DIR)/common/os/linux/include/modules/bufferMgt/ \
++      -I$(OSAL_DIR)/common/os/linux/include/modules/ioMem/ \
++      -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/include/ \
++      -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/os/linux/include/ \
++      -DENABLE_IOMEM -DENABLE_BUFFERMGT -DENABLE_DDK \
++      -DUSE_IXP4XX_CRYPTO
++else
++IXP_CFLAGS = \
++      -I$(ROOTDIR)/. \
++      -I$(IX_XSCALE_SW)/src/include \
++      -I$(OSAL_DIR)/ \
++      -I$(OSAL_DIR)/os/linux/include/ \
++      -I$(OSAL_DIR)/os/linux/include/modules/ \
++      -I$(OSAL_DIR)/os/linux/include/modules/ioMem/ \
++      -I$(OSAL_DIR)/os/linux/include/modules/bufferMgt/ \
++      -I$(OSAL_DIR)/os/linux/include/core/  \
++      -I$(OSAL_DIR)/os/linux/include/platforms/ \
++      -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ \
++      -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp425 \
++      -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp465 \
++      -I$(OSAL_DIR)/os/linux/include/core/ \
++      -I$(OSAL_DIR)/include/ \
++      -I$(OSAL_DIR)/include/modules/ \
++      -I$(OSAL_DIR)/include/modules/bufferMgt/ \
++      -I$(OSAL_DIR)/include/modules/ioMem/ \
++      -I$(OSAL_DIR)/include/platforms/ \
++      -I$(OSAL_DIR)/include/platforms/ixp400/ \
++      -DUSE_IXP4XX_CRYPTO
++endif
++endif
++ifdef CONFIG_IXP400_LIB_1_4
++IXP_CFLAGS   = \
++      -I$(ROOTDIR)/. \
++      -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/include \
++      -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/linux \
++      -DUSE_IXP4XX_CRYPTO
++endif
++ifndef IXPDIR
++IXPDIR = ixp-version-is-not-supported
++endif
++
++ifeq ($(CONFIG_CPU_IXP46X),y)
++IXP_CFLAGS += -D__ixp46X
++else
++ifeq ($(CONFIG_CPU_IXP43X),y)
++IXP_CFLAGS += -D__ixp43X
++else
++IXP_CFLAGS += -D__ixp42X
++endif
++endif
++
++obj-$(CONFIG_OCF_IXP4XX) += ixp4xx.o
++
++obj ?= .
++EXTRA_CFLAGS += $(IXP_CFLAGS) -I$(obj)/.. -I$(obj)/.
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ocfnull/Makefile  2007-07-25 11:02:33.000000000 +1000
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_OCFNULL) += ocfnull.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/..
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/pasemi/Makefile   2007-12-12 11:36:18.000000000 +1000
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_PASEMI) += pasemi.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/Config.in 2008-06-23 10:09:55.000000000 +1000
+@@ -0,0 +1,32 @@
++#############################################################################
++
++mainmenu_option next_comment
++comment 'OCF Configuration'
++tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF
++dep_mbool '  enable fips RNG checks (fips check on RNG data before use)' \
++                              CONFIG_OCF_FIPS $CONFIG_OCF_OCF
++dep_mbool '  enable harvesting entropy for /dev/random' \
++                              CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF
++dep_tristate '  cryptodev (user space support)' \
++                              CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF
++dep_tristate '  cryptosoft (software crypto engine)' \
++                              CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF
++dep_tristate '  safenet (HW crypto engine)' \
++                              CONFIG_OCF_SAFE $CONFIG_OCF_OCF
++dep_tristate '  IXP4xx (HW crypto engine)' \
++                              CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF
++dep_mbool    '  Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \
++                              CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX
++dep_tristate '  hifn (HW crypto engine)' \
++                              CONFIG_OCF_HIFN $CONFIG_OCF_OCF
++dep_tristate '  talitos (HW crypto engine)' \
++                              CONFIG_OCF_TALITOS $CONFIG_OCF_OCF
++dep_tristate '  pasemi (HW crypto engine)' \
++                              CONFIG_OCF_PASEMI $CONFIG_OCF_OCF
++dep_tristate '  ocfnull (does no crypto)' \
++                              CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF
++dep_tristate '  ocf-bench (HW crypto in-kernel benchmark)' \
++                              CONFIG_OCF_BENCH $CONFIG_OCF_OCF
++endmenu
++
++#############################################################################
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/Kconfig   2008-06-23 10:10:33.000000000 +1000
+@@ -0,0 +1,95 @@
++menu "OCF Configuration"
++
++config OCF_OCF
++      tristate "OCF (Open Cryptograhic Framework)"
++      help
++        A linux port of the OpenBSD/FreeBSD crypto framework.
++
++config OCF_RANDOMHARVEST
++      bool "crypto random --- harvest entropy for /dev/random"
++      depends on OCF_OCF
++      help
++        Includes code to harvest random numbers from devices that support it.
++
++config OCF_FIPS
++      bool "enable fips RNG checks"
++      depends on OCF_OCF && OCF_RANDOMHARVEST
++      help
++        Run all RNG provided data through a fips check before
++        adding it /dev/random's entropy pool.
++
++config OCF_CRYPTODEV
++      tristate "cryptodev (user space support)"
++      depends on OCF_OCF
++      help
++        The user space API to access crypto hardware.
++
++config OCF_CRYPTOSOFT
++      tristate "cryptosoft (software crypto engine)"
++      depends on OCF_OCF
++      help
++        A software driver for the OCF framework that uses
++        the kernel CryptoAPI.
++
++config OCF_SAFE
++      tristate "safenet (HW crypto engine)"
++      depends on OCF_OCF
++      help
++        A driver for a number of the safenet Excel crypto accelerators.
++        Currently tested and working on the 1141 and 1741.
++
++config OCF_IXP4XX
++      tristate "IXP4xx (HW crypto engine)"
++      depends on OCF_OCF
++      help
++        XScale IXP4xx crypto accelerator driver.  Requires the
++        Intel Access library.
++
++config OCF_IXP4XX_SHA1_MD5
++      bool "IXP4xx SHA1 and MD5 Hashing"
++      depends on OCF_IXP4XX
++      help
++        Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing.
++        Note: this is MUCH slower than using cryptosoft (software crypto engine).
++
++config OCF_HIFN
++      tristate "hifn (HW crypto engine)"
++      depends on OCF_OCF
++      help
++        OCF driver for various HIFN based crypto accelerators.
++        (7951, 7955, 7956, 7751, 7811)
++
++config OCF_HIFNHIPP
++      tristate "Hifn HIPP (HW packet crypto engine)"
++      depends on OCF_OCF
++      help
++        OCF driver for various HIFN (HIPP) based crypto accelerators
++        (7855)
++
++config OCF_TALITOS
++      tristate "talitos (HW crypto engine)"
++      depends on OCF_OCF
++      help
++        OCF driver for Freescale's security engine (SEC/talitos).
++
++config OCF_PASEMI
++        tristate "pasemi (HW crypto engine)"
++        depends on OCF_OCF && PPC_PASEMI
++        help
++          OCF driver for for PA Semi PWRficient DMA Engine
++
++config OCF_OCFNULL
++      tristate "ocfnull (fake crypto engine)"
++      depends on OCF_OCF
++      help
++        OCF driver for measuring ipsec overheads (does no crypto)
++
++config OCF_BENCH
++      tristate "ocf-bench (HW crypto in-kernel benchmark)"
++      depends on OCF_OCF
++      help
++        A very simple encryption test for the in-kernel interface
++        of OCF.  Also includes code to benchmark the IXP Access library
++        for comparison.
++
++endmenu
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/README    2007-12-15 21:31:03.000000000 +1000
+@@ -0,0 +1,166 @@
++README - ocf-linux-20071215
++---------------------------
++
++This README provides instructions for getting ocf-linux compiled and
++operating in a generic linux environment.  For other information you
++might like to visit the home page for this project:
++
++    http://ocf-linux.sourceforge.net/
++
++Adding OCF to linux
++-------------------
++
++    Not much in this file for now,  just some notes.  I usually build
++    the ocf support as modules but it can be built into the kernel as
++    well.  To use it:
++
++    * mknod /dev/crypto c 10 70
++
++    * to add OCF to your kernel source,  you have two options.  Apply
++      the kernel specific patch:
++
++          cd linux-2.4*; gunzip < ocf-linux-24-XXXXXXXX.patch.gz | patch -p1
++          cd linux-2.6*; gunzip < ocf-linux-26-XXXXXXXX.patch.gz | patch -p1
++    
++      if you do one of the above,  then you can proceed to the next step,
++      or you can do the above process by hand with using the patches against
++      linux-2.4.35 and 2.6.23 to include the ocf code under crypto/ocf.
++      Here's how to add it:
++
++      for 2.4.35 (and later)
++
++          cd linux-2.4.35/crypto
++          tar xvzf ocf-linux.tar.gz
++          cd ..
++          patch -p1 < crypto/ocf/patches/linux-2.4.35-ocf.patch
++
++      for 2.6.23 (and later)
++
++          cd linux-2.6.23/crypto
++          tar xvzf ocf-linux.tar.gz
++          cd ..
++          patch -p1 < crypto/ocf/patches/linux-2.6.23-ocf.patch
++
++      It should be easy to take this patch and apply it to other more
++      recent versions of the kernels.  The same patches should also work
++      relatively easily on kernels as old as 2.6.11 and 2.4.18.
++      
++    * under 2.4 if you are on a non-x86 platform,  you may need to:
++
++        cp linux-2.X.x/include/asm-i386/kmap_types.h linux-2.X.x/include/asm-YYY
++
++      so that you can build the kernel crypto support needed for the cryptosoft
++      driver.
++
++    * For simplicity you should enable all the crypto support in your kernel
++      except for the test driver.  Likewise for the OCF options.  Do not
++      enable OCF crypto drivers for HW that you do not have (for example
++      ixp4xx will not compile on non-Xscale systems).
++
++    * make sure that cryptodev.h (from ocf-linux.tar.gz) is installed as
++      crypto/cryptodev.h in an include directory that is used for building
++      applications for your platform.  For example on a host system that
++      might be:
++
++              /usr/include/crypto/cryptodev.h
++
++    * patch your openssl-0.9.8g code with the openssl-0.9.8g.patch.
++      (NOTE: there is no longer a need to patch ssh). The patch is against:
++      openssl-0_9_8e
++
++      If you need a patch for an older version of openssl,  you should look
++      to older OCF releases.  This patch is unlikely to work on older
++      openssl versions.
++
++      openssl-0.9.8g.patch
++                - enables --with-cryptodev for non BSD systems
++                - adds -cpu option to openssl speed for calculating CPU load
++                  under linux
++                - fixes null pointer in openssl speed multi thread output.
++                - fixes test keys to work with linux crypto's more stringent
++                  key checking.
++                - adds MD5/SHA acceleration (Ronen Shitrit), only enabled
++                  with the --with-cryptodev-digests option
++                - fixes bug in engine code caching.
++
++    * build crypto-tools-XXXXXXXX.tar.gz if you want to try some of the BSD
++      tools for testing OCF (ie., cryptotest).
++
++How to load the OCF drivers
++---------------------------
++
++    First insert the base modules:
++
++        insmod ocf
++        insmod cryptodev
++
++    You can then install the software OCF driver with:
++
++        insmod cryptosoft
++
++    and one or more of the OCF HW drivers with:
++
++        insmod safe
++        insmod hifn7751
++        insmod ixp4xx
++        ...
++
++    all the drivers take a debug option to enable verbose debug so that
++    you can see what is going on.  For debug you load them as:
++
++        insmod ocf crypto_debug=1
++        insmod cryptodev cryptodev_debug=1
++        insmod cryptosoft swcr_debug=1
++
++    You may load more than one OCF crypto driver but then there is no guarantee
++    as to which will be used.
++
++    You can also enable debug at run time on 2.6 systems with the following:
++
++        echo 1 > /sys/module/ocf/parameters/crypto_debug
++        echo 1 > /sys/module/cryptodev/parameters/cryptodev_debug
++        echo 1 > /sys/module/cryptosoft/parameters/swcr_debug
++        echo 1 > /sys/module/hifn7751/parameters/hifn_debug
++        echo 1 > /sys/module/safe/parameters/safe_debug
++        echo 1 > /sys/module/ixp4xx/parameters/ixp_debug
++        ...
++
++Testing the OCF support
++-----------------------
++
++    run "cryptotest",  it should do a short test for a couple of
++    des packets.  If it does everything is working.
++
++    If this works,  then ssh will use the driver when invoked as:
++
++        ssh -c 3des username@host
++
++    to see for sure that it is operating, enable debug as defined above.
++
++    To get a better idea of performance run:
++
++        cryptotest 100 4096
++
++    There are more options to cryptotest,  see the help.
++
++    It is also possible to use openssl to test the speed of the crypto
++    drivers.
++
++        openssl speed -evp des -engine cryptodev -elapsed
++        openssl speed -evp des3 -engine cryptodev -elapsed
++        openssl speed -evp aes128 -engine cryptodev -elapsed
++
++    and multiple threads (10) with:
++
++        openssl speed -evp des -engine cryptodev -elapsed -multi 10
++        openssl speed -evp des3 -engine cryptodev -elapsed -multi 10
++        openssl speed -evp aes128 -engine cryptodev -elapsed -multi 10
++
++    for public key testing you can try:
++
++        cryptokeytest
++        openssl speed -engine cryptodev rsa -elapsed
++        openssl speed -engine cryptodev dsa -elapsed
++
++David McCullough
++david_mccullough@securecomputing.com
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifn7751reg.h        2007-06-20 09:15:58.000000000 +1000
+@@ -0,0 +1,540 @@
++/* $FreeBSD: src/sys/dev/hifn/hifn7751reg.h,v 1.7 2007/03/21 03:42:49 sam Exp $ */
++/*    $OpenBSD: hifn7751reg.h,v 1.35 2002/04/08 17:49:42 jason Exp $  */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ *                    http://www.netsec.net
++ *
++ * Please send any comments, feedback, bug-fixes, or feature requests to
++ * software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++#ifndef __HIFN_H__
++#define       __HIFN_H__
++
++/*
++ * Some PCI configuration space offset defines.  The names were made
++ * identical to the names used by the Linux kernel.
++ */
++#define       HIFN_BAR0               PCIR_BAR(0)     /* PUC register map */
++#define       HIFN_BAR1               PCIR_BAR(1)     /* DMA register map */
++#define       HIFN_TRDY_TIMEOUT       0x40
++#define       HIFN_RETRY_TIMEOUT      0x41
++
++/*
++ * PCI vendor and device identifiers
++ * (the names are preserved from their OpenBSD source).
++ */
++#define       PCI_VENDOR_HIFN         0x13a3          /* Hifn */
++#define       PCI_PRODUCT_HIFN_7751   0x0005          /* 7751 */
++#define       PCI_PRODUCT_HIFN_6500   0x0006          /* 6500 */
++#define       PCI_PRODUCT_HIFN_7811   0x0007          /* 7811 */
++#define       PCI_PRODUCT_HIFN_7855   0x001f          /* 7855 */
++#define       PCI_PRODUCT_HIFN_7951   0x0012          /* 7951 */
++#define       PCI_PRODUCT_HIFN_7955   0x0020          /* 7954/7955 */
++#define       PCI_PRODUCT_HIFN_7956   0x001d          /* 7956 */
++
++#define       PCI_VENDOR_INVERTEX     0x14e1          /* Invertex */
++#define       PCI_PRODUCT_INVERTEX_AEON 0x0005        /* AEON */
++
++#define       PCI_VENDOR_NETSEC       0x1660          /* NetSec */
++#define       PCI_PRODUCT_NETSEC_7751 0x7751          /* 7751 */
++
++/*
++ * The values below should multiple of 4 -- and be large enough to handle
++ * any command the driver implements.
++ *
++ * MAX_COMMAND = base command + mac command + encrypt command +
++ *                    mac-key + rc4-key
++ * MAX_RESULT  = base result + mac result + mac + encrypt result
++ *                    
++ *
++ */
++#define       HIFN_MAX_COMMAND        (8 + 8 + 8 + 64 + 260)
++#define       HIFN_MAX_RESULT         (8 + 4 + 20 + 4)
++
++/*
++ * hifn_desc_t
++ *
++ * Holds an individual descriptor for any of the rings.
++ */
++typedef struct hifn_desc {
++      volatile u_int32_t l;           /* length and status bits */
++      volatile u_int32_t p;
++} hifn_desc_t;
++
++/*
++ * Masks for the "length" field of struct hifn_desc.
++ */
++#define       HIFN_D_LENGTH           0x0000ffff      /* length bit mask */
++#define       HIFN_D_MASKDONEIRQ      0x02000000      /* mask the done interrupt */
++#define       HIFN_D_DESTOVER         0x04000000      /* destination overflow */
++#define       HIFN_D_OVER             0x08000000      /* overflow */
++#define       HIFN_D_LAST             0x20000000      /* last descriptor in chain */
++#define       HIFN_D_JUMP             0x40000000      /* jump descriptor */
++#define       HIFN_D_VALID            0x80000000      /* valid bit */
++
++
++/*
++ * Processing Unit Registers (offset from BASEREG0)
++ */
++#define       HIFN_0_PUDATA           0x00    /* Processing Unit Data */
++#define       HIFN_0_PUCTRL           0x04    /* Processing Unit Control */
++#define       HIFN_0_PUISR            0x08    /* Processing Unit Interrupt Status */
++#define       HIFN_0_PUCNFG           0x0c    /* Processing Unit Configuration */
++#define       HIFN_0_PUIER            0x10    /* Processing Unit Interrupt Enable */
++#define       HIFN_0_PUSTAT           0x14    /* Processing Unit Status/Chip ID */
++#define       HIFN_0_FIFOSTAT         0x18    /* FIFO Status */
++#define       HIFN_0_FIFOCNFG         0x1c    /* FIFO Configuration */
++#define       HIFN_0_PUCTRL2          0x28    /* Processing Unit Control (2nd map) */
++#define       HIFN_0_MUTE1            0x80
++#define       HIFN_0_MUTE2            0x90
++#define       HIFN_0_SPACESIZE        0x100   /* Register space size */
++
++/* Processing Unit Control Register (HIFN_0_PUCTRL) */
++#define       HIFN_PUCTRL_CLRSRCFIFO  0x0010  /* clear source fifo */
++#define       HIFN_PUCTRL_STOP        0x0008  /* stop pu */
++#define       HIFN_PUCTRL_LOCKRAM     0x0004  /* lock ram */
++#define       HIFN_PUCTRL_DMAENA      0x0002  /* enable dma */
++#define       HIFN_PUCTRL_RESET       0x0001  /* Reset processing unit */
++
++/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */
++#define       HIFN_PUISR_CMDINVAL     0x8000  /* Invalid command interrupt */
++#define       HIFN_PUISR_DATAERR      0x4000  /* Data error interrupt */
++#define       HIFN_PUISR_SRCFIFO      0x2000  /* Source FIFO ready interrupt */
++#define       HIFN_PUISR_DSTFIFO      0x1000  /* Destination FIFO ready interrupt */
++#define       HIFN_PUISR_DSTOVER      0x0200  /* Destination overrun interrupt */
++#define       HIFN_PUISR_SRCCMD       0x0080  /* Source command interrupt */
++#define       HIFN_PUISR_SRCCTX       0x0040  /* Source context interrupt */
++#define       HIFN_PUISR_SRCDATA      0x0020  /* Source data interrupt */
++#define       HIFN_PUISR_DSTDATA      0x0010  /* Destination data interrupt */
++#define       HIFN_PUISR_DSTRESULT    0x0004  /* Destination result interrupt */
++
++/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */
++#define       HIFN_PUCNFG_DRAMMASK    0xe000  /* DRAM size mask */
++#define       HIFN_PUCNFG_DSZ_256K    0x0000  /* 256k dram */
++#define       HIFN_PUCNFG_DSZ_512K    0x2000  /* 512k dram */
++#define       HIFN_PUCNFG_DSZ_1M      0x4000  /* 1m dram */
++#define       HIFN_PUCNFG_DSZ_2M      0x6000  /* 2m dram */
++#define       HIFN_PUCNFG_DSZ_4M      0x8000  /* 4m dram */
++#define       HIFN_PUCNFG_DSZ_8M      0xa000  /* 8m dram */
++#define       HIFN_PUNCFG_DSZ_16M     0xc000  /* 16m dram */
++#define       HIFN_PUCNFG_DSZ_32M     0xe000  /* 32m dram */
++#define       HIFN_PUCNFG_DRAMREFRESH 0x1800  /* DRAM refresh rate mask */
++#define       HIFN_PUCNFG_DRFR_512    0x0000  /* 512 divisor of ECLK */
++#define       HIFN_PUCNFG_DRFR_256    0x0800  /* 256 divisor of ECLK */
++#define       HIFN_PUCNFG_DRFR_128    0x1000  /* 128 divisor of ECLK */
++#define       HIFN_PUCNFG_TCALLPHASES 0x0200  /* your guess is as good as mine... */
++#define       HIFN_PUCNFG_TCDRVTOTEM  0x0100  /* your guess is as good as mine... */
++#define       HIFN_PUCNFG_BIGENDIAN   0x0080  /* DMA big endian mode */
++#define       HIFN_PUCNFG_BUS32       0x0040  /* Bus width 32bits */
++#define       HIFN_PUCNFG_BUS16       0x0000  /* Bus width 16 bits */
++#define       HIFN_PUCNFG_CHIPID      0x0020  /* Allow chipid from PUSTAT */
++#define       HIFN_PUCNFG_DRAM        0x0010  /* Context RAM is DRAM */
++#define       HIFN_PUCNFG_SRAM        0x0000  /* Context RAM is SRAM */
++#define       HIFN_PUCNFG_COMPSING    0x0004  /* Enable single compression context */
++#define       HIFN_PUCNFG_ENCCNFG     0x0002  /* Encryption configuration */
++
++/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */
++#define       HIFN_PUIER_CMDINVAL     0x8000  /* Invalid command interrupt */
++#define       HIFN_PUIER_DATAERR      0x4000  /* Data error interrupt */
++#define       HIFN_PUIER_SRCFIFO      0x2000  /* Source FIFO ready interrupt */
++#define       HIFN_PUIER_DSTFIFO      0x1000  /* Destination FIFO ready interrupt */
++#define       HIFN_PUIER_DSTOVER      0x0200  /* Destination overrun interrupt */
++#define       HIFN_PUIER_SRCCMD       0x0080  /* Source command interrupt */
++#define       HIFN_PUIER_SRCCTX       0x0040  /* Source context interrupt */
++#define       HIFN_PUIER_SRCDATA      0x0020  /* Source data interrupt */
++#define       HIFN_PUIER_DSTDATA      0x0010  /* Destination data interrupt */
++#define       HIFN_PUIER_DSTRESULT    0x0004  /* Destination result interrupt */
++
++/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */
++#define       HIFN_PUSTAT_CMDINVAL    0x8000  /* Invalid command interrupt */
++#define       HIFN_PUSTAT_DATAERR     0x4000  /* Data error interrupt */
++#define       HIFN_PUSTAT_SRCFIFO     0x2000  /* Source FIFO ready interrupt */
++#define       HIFN_PUSTAT_DSTFIFO     0x1000  /* Destination FIFO ready interrupt */
++#define       HIFN_PUSTAT_DSTOVER     0x0200  /* Destination overrun interrupt */
++#define       HIFN_PUSTAT_SRCCMD      0x0080  /* Source command interrupt */
++#define       HIFN_PUSTAT_SRCCTX      0x0040  /* Source context interrupt */
++#define       HIFN_PUSTAT_SRCDATA     0x0020  /* Source data interrupt */
++#define       HIFN_PUSTAT_DSTDATA     0x0010  /* Destination data interrupt */
++#define       HIFN_PUSTAT_DSTRESULT   0x0004  /* Destination result interrupt */
++#define       HIFN_PUSTAT_CHIPREV     0x00ff  /* Chip revision mask */
++#define       HIFN_PUSTAT_CHIPENA     0xff00  /* Chip enabled mask */
++#define       HIFN_PUSTAT_ENA_2       0x1100  /* Level 2 enabled */
++#define       HIFN_PUSTAT_ENA_1       0x1000  /* Level 1 enabled */
++#define       HIFN_PUSTAT_ENA_0       0x3000  /* Level 0 enabled */
++#define       HIFN_PUSTAT_REV_2       0x0020  /* 7751 PT6/2 */
++#define       HIFN_PUSTAT_REV_3       0x0030  /* 7751 PT6/3 */
++
++/* FIFO Status Register (HIFN_0_FIFOSTAT) */
++#define       HIFN_FIFOSTAT_SRC       0x7f00  /* Source FIFO available */
++#define       HIFN_FIFOSTAT_DST       0x007f  /* Destination FIFO available */
++
++/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */
++#define       HIFN_FIFOCNFG_THRESHOLD 0x0400  /* must be written as this value */
++
++/*
++ * DMA Interface Registers (offset from BASEREG1)
++ */
++#define       HIFN_1_DMA_CRAR         0x0c    /* DMA Command Ring Address */
++#define       HIFN_1_DMA_SRAR         0x1c    /* DMA Source Ring Address */
++#define       HIFN_1_DMA_RRAR         0x2c    /* DMA Result Ring Address */
++#define       HIFN_1_DMA_DRAR         0x3c    /* DMA Destination Ring Address */
++#define       HIFN_1_DMA_CSR          0x40    /* DMA Status and Control */
++#define       HIFN_1_DMA_IER          0x44    /* DMA Interrupt Enable */
++#define       HIFN_1_DMA_CNFG         0x48    /* DMA Configuration */
++#define       HIFN_1_PLL              0x4c    /* 7955/7956: PLL config */
++#define       HIFN_1_7811_RNGENA      0x60    /* 7811: rng enable */
++#define       HIFN_1_7811_RNGCFG      0x64    /* 7811: rng config */
++#define       HIFN_1_7811_RNGDAT      0x68    /* 7811: rng data */
++#define       HIFN_1_7811_RNGSTS      0x6c    /* 7811: rng status */
++#define       HIFN_1_DMA_CNFG2        0x6c    /* 7955/7956: dma config #2 */
++#define       HIFN_1_7811_MIPSRST     0x94    /* 7811: MIPS reset */
++#define       HIFN_1_REVID            0x98    /* Revision ID */
++
++#define       HIFN_1_PUB_RESET        0x204   /* Public/RNG Reset */
++#define       HIFN_1_PUB_BASE         0x300   /* Public Base Address */
++#define       HIFN_1_PUB_OPLEN        0x304   /* 7951-compat Public Operand Length */
++#define       HIFN_1_PUB_OP           0x308   /* 7951-compat Public Operand */
++#define       HIFN_1_PUB_STATUS       0x30c   /* 7951-compat Public Status */
++#define       HIFN_1_PUB_IEN          0x310   /* Public Interrupt enable */
++#define       HIFN_1_RNG_CONFIG       0x314   /* RNG config */
++#define       HIFN_1_RNG_DATA         0x318   /* RNG data */
++#define       HIFN_1_PUB_MODE         0x320   /* PK mode */
++#define       HIFN_1_PUB_FIFO_OPLEN   0x380   /* first element of oplen fifo */
++#define       HIFN_1_PUB_FIFO_OP      0x384   /* first element of op fifo */
++#define       HIFN_1_PUB_MEM          0x400   /* start of Public key memory */
++#define       HIFN_1_PUB_MEMEND       0xbff   /* end of Public key memory */
++
++/* DMA Status and Control Register (HIFN_1_DMA_CSR) */
++#define       HIFN_DMACSR_D_CTRLMASK  0xc0000000      /* Destinition Ring Control */
++#define       HIFN_DMACSR_D_CTRL_NOP  0x00000000      /* Dest. Control: no-op */
++#define       HIFN_DMACSR_D_CTRL_DIS  0x40000000      /* Dest. Control: disable */
++#define       HIFN_DMACSR_D_CTRL_ENA  0x80000000      /* Dest. Control: enable */
++#define       HIFN_DMACSR_D_ABORT     0x20000000      /* Destinition Ring PCIAbort */
++#define       HIFN_DMACSR_D_DONE      0x10000000      /* Destinition Ring Done */
++#define       HIFN_DMACSR_D_LAST      0x08000000      /* Destinition Ring Last */
++#define       HIFN_DMACSR_D_WAIT      0x04000000      /* Destinition Ring Waiting */
++#define       HIFN_DMACSR_D_OVER      0x02000000      /* Destinition Ring Overflow */
++#define       HIFN_DMACSR_R_CTRL      0x00c00000      /* Result Ring Control */
++#define       HIFN_DMACSR_R_CTRL_NOP  0x00000000      /* Result Control: no-op */
++#define       HIFN_DMACSR_R_CTRL_DIS  0x00400000      /* Result Control: disable */
++#define       HIFN_DMACSR_R_CTRL_ENA  0x00800000      /* Result Control: enable */
++#define       HIFN_DMACSR_R_ABORT     0x00200000      /* Result Ring PCI Abort */
++#define       HIFN_DMACSR_R_DONE      0x00100000      /* Result Ring Done */
++#define       HIFN_DMACSR_R_LAST      0x00080000      /* Result Ring Last */
++#define       HIFN_DMACSR_R_WAIT      0x00040000      /* Result Ring Waiting */
++#define       HIFN_DMACSR_R_OVER      0x00020000      /* Result Ring Overflow */
++#define       HIFN_DMACSR_S_CTRL      0x0000c000      /* Source Ring Control */
++#define       HIFN_DMACSR_S_CTRL_NOP  0x00000000      /* Source Control: no-op */
++#define       HIFN_DMACSR_S_CTRL_DIS  0x00004000      /* Source Control: disable */
++#define       HIFN_DMACSR_S_CTRL_ENA  0x00008000      /* Source Control: enable */
++#define       HIFN_DMACSR_S_ABORT     0x00002000      /* Source Ring PCI Abort */
++#define       HIFN_DMACSR_S_DONE      0x00001000      /* Source Ring Done */
++#define       HIFN_DMACSR_S_LAST      0x00000800      /* Source Ring Last */
++#define       HIFN_DMACSR_S_WAIT      0x00000400      /* Source Ring Waiting */
++#define       HIFN_DMACSR_ILLW        0x00000200      /* Illegal write (7811 only) */
++#define       HIFN_DMACSR_ILLR        0x00000100      /* Illegal read (7811 only) */
++#define       HIFN_DMACSR_C_CTRL      0x000000c0      /* Command Ring Control */
++#define       HIFN_DMACSR_C_CTRL_NOP  0x00000000      /* Command Control: no-op */
++#define       HIFN_DMACSR_C_CTRL_DIS  0x00000040      /* Command Control: disable */
++#define       HIFN_DMACSR_C_CTRL_ENA  0x00000080      /* Command Control: enable */
++#define       HIFN_DMACSR_C_ABORT     0x00000020      /* Command Ring PCI Abort */
++#define       HIFN_DMACSR_C_DONE      0x00000010      /* Command Ring Done */
++#define       HIFN_DMACSR_C_LAST      0x00000008      /* Command Ring Last */
++#define       HIFN_DMACSR_C_WAIT      0x00000004      /* Command Ring Waiting */
++#define       HIFN_DMACSR_PUBDONE     0x00000002      /* Public op done (7951 only) */
++#define       HIFN_DMACSR_ENGINE      0x00000001      /* Command Ring Engine IRQ */
++
++/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */
++#define       HIFN_DMAIER_D_ABORT     0x20000000      /* Destination Ring PCIAbort */
++#define       HIFN_DMAIER_D_DONE      0x10000000      /* Destination Ring Done */
++#define       HIFN_DMAIER_D_LAST      0x08000000      /* Destination Ring Last */
++#define       HIFN_DMAIER_D_WAIT      0x04000000      /* Destination Ring Waiting */
++#define       HIFN_DMAIER_D_OVER      0x02000000      /* Destination Ring Overflow */
++#define       HIFN_DMAIER_R_ABORT     0x00200000      /* Result Ring PCI Abort */
++#define       HIFN_DMAIER_R_DONE      0x00100000      /* Result Ring Done */
++#define       HIFN_DMAIER_R_LAST      0x00080000      /* Result Ring Last */
++#define       HIFN_DMAIER_R_WAIT      0x00040000      /* Result Ring Waiting */
++#define       HIFN_DMAIER_R_OVER      0x00020000      /* Result Ring Overflow */
++#define       HIFN_DMAIER_S_ABORT     0x00002000      /* Source Ring PCI Abort */
++#define       HIFN_DMAIER_S_DONE      0x00001000      /* Source Ring Done */
++#define       HIFN_DMAIER_S_LAST      0x00000800      /* Source Ring Last */
++#define       HIFN_DMAIER_S_WAIT      0x00000400      /* Source Ring Waiting */
++#define       HIFN_DMAIER_ILLW        0x00000200      /* Illegal write (7811 only) */
++#define       HIFN_DMAIER_ILLR        0x00000100      /* Illegal read (7811 only) */
++#define       HIFN_DMAIER_C_ABORT     0x00000020      /* Command Ring PCI Abort */
++#define       HIFN_DMAIER_C_DONE      0x00000010      /* Command Ring Done */
++#define       HIFN_DMAIER_C_LAST      0x00000008      /* Command Ring Last */
++#define       HIFN_DMAIER_C_WAIT      0x00000004      /* Command Ring Waiting */
++#define       HIFN_DMAIER_PUBDONE     0x00000002      /* public op done (7951 only) */
++#define       HIFN_DMAIER_ENGINE      0x00000001      /* Engine IRQ */
++
++/* DMA Configuration Register (HIFN_1_DMA_CNFG) */
++#define       HIFN_DMACNFG_BIGENDIAN  0x10000000      /* big endian mode */
++#define       HIFN_DMACNFG_POLLFREQ   0x00ff0000      /* Poll frequency mask */
++#define       HIFN_DMACNFG_UNLOCK     0x00000800
++#define       HIFN_DMACNFG_POLLINVAL  0x00000700      /* Invalid Poll Scalar */
++#define       HIFN_DMACNFG_LAST       0x00000010      /* Host control LAST bit */
++#define       HIFN_DMACNFG_MODE       0x00000004      /* DMA mode */
++#define       HIFN_DMACNFG_DMARESET   0x00000002      /* DMA Reset # */
++#define       HIFN_DMACNFG_MSTRESET   0x00000001      /* Master Reset # */
++
++/* DMA Configuration Register (HIFN_1_DMA_CNFG2) */
++#define       HIFN_DMACNFG2_PKSWAP32  (1 << 19)       /* swap the OPLEN/OP reg */
++#define       HIFN_DMACNFG2_PKSWAP8   (1 << 18)       /* swap the bits of OPLEN/OP */
++#define       HIFN_DMACNFG2_BAR0_SWAP32 (1<<17)       /* swap the bytes of BAR0 */
++#define       HIFN_DMACNFG2_BAR1_SWAP8 (1<<16)        /* swap the bits  of BAR0 */
++#define       HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT 12
++#define       HIFN_DMACNFG2_INIT_READ_BURST_SHIFT 8
++#define       HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT 4
++#define       HIFN_DMACNFG2_TGT_READ_BURST_SHIFT  0
++
++/* 7811 RNG Enable Register (HIFN_1_7811_RNGENA) */
++#define       HIFN_7811_RNGENA_ENA    0x00000001      /* enable RNG */
++
++/* 7811 RNG Config Register (HIFN_1_7811_RNGCFG) */
++#define       HIFN_7811_RNGCFG_PRE1   0x00000f00      /* first prescalar */
++#define       HIFN_7811_RNGCFG_OPRE   0x00000080      /* output prescalar */
++#define       HIFN_7811_RNGCFG_DEFL   0x00000f80      /* 2 words/ 1/100 sec */
++
++/* 7811 RNG Status Register (HIFN_1_7811_RNGSTS) */
++#define       HIFN_7811_RNGSTS_RDY    0x00004000      /* two numbers in FIFO */
++#define       HIFN_7811_RNGSTS_UFL    0x00001000      /* rng underflow */
++
++/* 7811 MIPS Reset Register (HIFN_1_7811_MIPSRST) */
++#define       HIFN_MIPSRST_BAR2SIZE   0xffff0000      /* sdram size */
++#define       HIFN_MIPSRST_GPRAMINIT  0x00008000      /* gpram can be accessed */
++#define       HIFN_MIPSRST_CRAMINIT   0x00004000      /* ctxram can be accessed */
++#define       HIFN_MIPSRST_LED2       0x00000400      /* external LED2 */
++#define       HIFN_MIPSRST_LED1       0x00000200      /* external LED1 */
++#define       HIFN_MIPSRST_LED0       0x00000100      /* external LED0 */
++#define       HIFN_MIPSRST_MIPSDIS    0x00000004      /* disable MIPS */
++#define       HIFN_MIPSRST_MIPSRST    0x00000002      /* warm reset MIPS */
++#define       HIFN_MIPSRST_MIPSCOLD   0x00000001      /* cold reset MIPS */
++
++/* Public key reset register (HIFN_1_PUB_RESET) */
++#define       HIFN_PUBRST_RESET       0x00000001      /* reset public/rng unit */
++
++/* Public operation register (HIFN_1_PUB_OP) */
++#define       HIFN_PUBOP_AOFFSET      0x0000003e      /* A offset */
++#define       HIFN_PUBOP_BOFFSET      0x00000fc0      /* B offset */
++#define       HIFN_PUBOP_MOFFSET      0x0003f000      /* M offset */
++#define       HIFN_PUBOP_OP_MASK      0x003c0000      /* Opcode: */
++#define       HIFN_PUBOP_OP_NOP       0x00000000      /*  NOP */
++#define       HIFN_PUBOP_OP_ADD       0x00040000      /*  ADD */
++#define       HIFN_PUBOP_OP_ADDC      0x00080000      /*  ADD w/carry */
++#define       HIFN_PUBOP_OP_SUB       0x000c0000      /*  SUB */
++#define       HIFN_PUBOP_OP_SUBC      0x00100000      /*  SUB w/carry */
++#define       HIFN_PUBOP_OP_MODADD    0x00140000      /*  Modular ADD */
++#define       HIFN_PUBOP_OP_MODSUB    0x00180000      /*  Modular SUB */
++#define       HIFN_PUBOP_OP_INCA      0x001c0000      /*  INC A */
++#define       HIFN_PUBOP_OP_DECA      0x00200000      /*  DEC A */
++#define       HIFN_PUBOP_OP_MULT      0x00240000      /*  MULT */
++#define       HIFN_PUBOP_OP_MODMULT   0x00280000      /*  Modular MULT */
++#define       HIFN_PUBOP_OP_MODRED    0x002c0000      /*  Modular Red */
++#define       HIFN_PUBOP_OP_MODEXP    0x00300000      /*  Modular Exp */
++
++/* Public operand length register (HIFN_1_PUB_OPLEN) */
++#define       HIFN_PUBOPLEN_MODLEN    0x0000007f
++#define       HIFN_PUBOPLEN_EXPLEN    0x0003ff80
++#define       HIFN_PUBOPLEN_REDLEN    0x003c0000
++
++/* Public status register (HIFN_1_PUB_STATUS) */
++#define       HIFN_PUBSTS_DONE        0x00000001      /* operation done */
++#define       HIFN_PUBSTS_CARRY       0x00000002      /* carry */
++#define       HIFN_PUBSTS_FIFO_EMPTY  0x00000100      /* fifo empty */
++#define       HIFN_PUBSTS_FIFO_FULL   0x00000200      /* fifo full */
++#define       HIFN_PUBSTS_FIFO_OVFL   0x00000400      /* fifo overflow */
++#define       HIFN_PUBSTS_FIFO_WRITE  0x000f0000      /* fifo write */
++#define       HIFN_PUBSTS_FIFO_READ   0x0f000000      /* fifo read */
++
++/* Public interrupt enable register (HIFN_1_PUB_IEN) */
++#define       HIFN_PUBIEN_DONE        0x00000001      /* operation done interrupt */
++
++/* Random number generator config register (HIFN_1_RNG_CONFIG) */
++#define       HIFN_RNGCFG_ENA         0x00000001      /* enable rng */
++
++/*
++ * Register offsets in register set 1
++ */
++
++#define       HIFN_UNLOCK_SECRET1     0xf4
++#define       HIFN_UNLOCK_SECRET2     0xfc
++
++/*
++ * PLL config register
++ *
++ * This register is present only on 7954/7955/7956 parts. It must be
++ * programmed according to the bus interface method used by the h/w.
++ * Note that the parts require a stable clock.  Since the PCI clock
++ * may vary the reference clock must usually be used.  To avoid
++ * overclocking the core logic, setup must be done carefully, refer
++ * to the driver for details.  The exact multiplier required varies
++ * by part and system configuration; refer to the Hifn documentation.
++ */
++#define       HIFN_PLL_REF_SEL        0x00000001      /* REF/HBI clk selection */
++#define       HIFN_PLL_BP             0x00000002      /* bypass (used during setup) */
++/* bit 2 reserved */
++#define       HIFN_PLL_PK_CLK_SEL     0x00000008      /* public key clk select */
++#define       HIFN_PLL_PE_CLK_SEL     0x00000010      /* packet engine clk select */
++/* bits 5-9 reserved */
++#define       HIFN_PLL_MBSET          0x00000400      /* must be set to 1 */
++#define       HIFN_PLL_ND             0x00003800      /* Fpll_ref multiplier select */
++#define       HIFN_PLL_ND_SHIFT       11
++#define       HIFN_PLL_ND_2           0x00000000      /* 2x */
++#define       HIFN_PLL_ND_4           0x00000800      /* 4x */
++#define       HIFN_PLL_ND_6           0x00001000      /* 6x */
++#define       HIFN_PLL_ND_8           0x00001800      /* 8x */
++#define       HIFN_PLL_ND_10          0x00002000      /* 10x */
++#define       HIFN_PLL_ND_12          0x00002800      /* 12x */
++/* bits 14-15 reserved */
++#define       HIFN_PLL_IS             0x00010000      /* charge pump current select */
++/* bits 17-31 reserved */
++
++/*
++ * Board configuration specifies only these bits.
++ */
++#define       HIFN_PLL_CONFIG         (HIFN_PLL_IS|HIFN_PLL_ND|HIFN_PLL_REF_SEL)
++
++/*
++ * Public Key Engine Mode Register
++ */
++#define       HIFN_PKMODE_HOSTINVERT  (1 << 0)        /* HOST INVERT */
++#define       HIFN_PKMODE_ENHANCED    (1 << 1)        /* Enable enhanced mode */
++
++
++/*********************************************************************
++ * Structs for board commands 
++ *
++ *********************************************************************/
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_base_command {
++      volatile u_int16_t masks;
++      volatile u_int16_t session_num;
++      volatile u_int16_t total_source_count;
++      volatile u_int16_t total_dest_count;
++} hifn_base_command_t;
++
++#define       HIFN_BASE_CMD_MAC               0x0400
++#define       HIFN_BASE_CMD_CRYPT             0x0800
++#define       HIFN_BASE_CMD_DECODE            0x2000
++#define       HIFN_BASE_CMD_SRCLEN_M          0xc000
++#define       HIFN_BASE_CMD_SRCLEN_S          14
++#define       HIFN_BASE_CMD_DSTLEN_M          0x3000
++#define       HIFN_BASE_CMD_DSTLEN_S          12
++#define       HIFN_BASE_CMD_LENMASK_HI        0x30000
++#define       HIFN_BASE_CMD_LENMASK_LO        0x0ffff
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_crypt_command {
++      volatile u_int16_t masks;
++      volatile u_int16_t header_skip;
++      volatile u_int16_t source_count;
++      volatile u_int16_t reserved;
++} hifn_crypt_command_t;
++
++#define       HIFN_CRYPT_CMD_ALG_MASK         0x0003          /* algorithm: */
++#define       HIFN_CRYPT_CMD_ALG_DES          0x0000          /*   DES */
++#define       HIFN_CRYPT_CMD_ALG_3DES         0x0001          /*   3DES */
++#define       HIFN_CRYPT_CMD_ALG_RC4          0x0002          /*   RC4 */
++#define       HIFN_CRYPT_CMD_ALG_AES          0x0003          /*   AES */
++#define       HIFN_CRYPT_CMD_MODE_MASK        0x0018          /* Encrypt mode: */
++#define       HIFN_CRYPT_CMD_MODE_ECB         0x0000          /*   ECB */
++#define       HIFN_CRYPT_CMD_MODE_CBC         0x0008          /*   CBC */
++#define       HIFN_CRYPT_CMD_MODE_CFB         0x0010          /*   CFB */
++#define       HIFN_CRYPT_CMD_MODE_OFB         0x0018          /*   OFB */
++#define       HIFN_CRYPT_CMD_CLR_CTX          0x0040          /* clear context */
++#define       HIFN_CRYPT_CMD_NEW_KEY          0x0800          /* expect new key */
++#define       HIFN_CRYPT_CMD_NEW_IV           0x1000          /* expect new iv */
++
++#define       HIFN_CRYPT_CMD_SRCLEN_M         0xc000
++#define       HIFN_CRYPT_CMD_SRCLEN_S         14
++
++#define       HIFN_CRYPT_CMD_KSZ_MASK         0x0600          /* AES key size: */
++#define       HIFN_CRYPT_CMD_KSZ_128          0x0000          /*   128 bit */
++#define       HIFN_CRYPT_CMD_KSZ_192          0x0200          /*   192 bit */
++#define       HIFN_CRYPT_CMD_KSZ_256          0x0400          /*   256 bit */
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_mac_command {
++      volatile u_int16_t masks;
++      volatile u_int16_t header_skip;
++      volatile u_int16_t source_count;
++      volatile u_int16_t reserved;
++} hifn_mac_command_t;
++
++#define       HIFN_MAC_CMD_ALG_MASK           0x0001
++#define       HIFN_MAC_CMD_ALG_SHA1           0x0000
++#define       HIFN_MAC_CMD_ALG_MD5            0x0001
++#define       HIFN_MAC_CMD_MODE_MASK          0x000c
++#define       HIFN_MAC_CMD_MODE_HMAC          0x0000
++#define       HIFN_MAC_CMD_MODE_SSL_MAC       0x0004
++#define       HIFN_MAC_CMD_MODE_HASH          0x0008
++#define       HIFN_MAC_CMD_MODE_FULL          0x0004
++#define       HIFN_MAC_CMD_TRUNC              0x0010
++#define       HIFN_MAC_CMD_RESULT             0x0020
++#define       HIFN_MAC_CMD_APPEND             0x0040
++#define       HIFN_MAC_CMD_SRCLEN_M           0xc000
++#define       HIFN_MAC_CMD_SRCLEN_S           14
++
++/*
++ * MAC POS IPsec initiates authentication after encryption on encodes
++ * and before decryption on decodes.
++ */
++#define       HIFN_MAC_CMD_POS_IPSEC          0x0200
++#define       HIFN_MAC_CMD_NEW_KEY            0x0800
++
++/*
++ * The poll frequency and poll scalar defines are unshifted values used
++ * to set fields in the DMA Configuration Register.
++ */
++#ifndef HIFN_POLL_FREQUENCY
++#define       HIFN_POLL_FREQUENCY     0x1
++#endif
++
++#ifndef HIFN_POLL_SCALAR
++#define       HIFN_POLL_SCALAR        0x0
++#endif
++
++#define       HIFN_MAX_SEGLEN         0xffff          /* maximum dma segment len */
++#define       HIFN_MAX_DMALEN         0x3ffff         /* maximum dma length */
++#endif /* __HIFN_H__ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifn7751var.h        2007-06-20 09:22:39.000000000 +1000
+@@ -0,0 +1,369 @@
++/* $FreeBSD: src/sys/dev/hifn/hifn7751var.h,v 1.9 2007/03/21 03:42:49 sam Exp $ */
++/*    $OpenBSD: hifn7751var.h,v 1.42 2002/04/08 17:49:42 jason Exp $  */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ *                    http://www.netsec.net
++ *
++ * Please send any comments, feedback, bug-fixes, or feature requests to
++ * software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef __HIFN7751VAR_H__
++#define __HIFN7751VAR_H__
++
++#ifdef __KERNEL__
++
++/*
++ * Some configurable values for the driver.  By default command+result
++ * descriptor rings are the same size.  The src+dst descriptor rings
++ * are sized at 3.5x the number of potential commands.  Slower parts
++ * (e.g. 7951) tend to run out of src descriptors; faster parts (7811)
++ * src+cmd/result descriptors.  It's not clear that increasing the size
++ * of the descriptor rings helps performance significantly as other
++ * factors tend to come into play (e.g. copying misaligned packets).
++ */
++#define       HIFN_D_CMD_RSIZE        24      /* command descriptors */
++#define       HIFN_D_SRC_RSIZE        ((HIFN_D_CMD_RSIZE * 7) / 2)    /* source descriptors */
++#define       HIFN_D_RES_RSIZE        HIFN_D_CMD_RSIZE        /* result descriptors */
++#define       HIFN_D_DST_RSIZE        HIFN_D_SRC_RSIZE        /* destination descriptors */
++
++/*
++ *  Length values for cryptography
++ */
++#define HIFN_DES_KEY_LENGTH           8
++#define HIFN_3DES_KEY_LENGTH          24
++#define HIFN_MAX_CRYPT_KEY_LENGTH     HIFN_3DES_KEY_LENGTH
++#define HIFN_IV_LENGTH                        8
++#define       HIFN_AES_IV_LENGTH              16
++#define HIFN_MAX_IV_LENGTH            HIFN_AES_IV_LENGTH
++
++/*
++ *  Length values for authentication
++ */
++#define HIFN_MAC_KEY_LENGTH           64
++#define HIFN_MD5_LENGTH                       16
++#define HIFN_SHA1_LENGTH              20
++#define HIFN_MAC_TRUNC_LENGTH         12
++
++#define MAX_SCATTER 64
++
++/*
++ * Data structure to hold all 4 rings and any other ring related data.
++ */
++struct hifn_dma {
++      /*
++       *  Descriptor rings.  We add +1 to the size to accomidate the
++       *  jump descriptor.
++       */
++      struct hifn_desc        cmdr[HIFN_D_CMD_RSIZE+1];
++      struct hifn_desc        srcr[HIFN_D_SRC_RSIZE+1];
++      struct hifn_desc        dstr[HIFN_D_DST_RSIZE+1];
++      struct hifn_desc        resr[HIFN_D_RES_RSIZE+1];
++
++      struct hifn_command     *hifn_commands[HIFN_D_RES_RSIZE];
++
++      u_char                  command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
++      u_char                  result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
++      u_int32_t               slop[HIFN_D_CMD_RSIZE];
++
++      u_int64_t               test_src, test_dst;
++
++      /*
++       *  Our current positions for insertion and removal from the desriptor
++       *  rings. 
++       */
++      int                     cmdi, srci, dsti, resi;
++      volatile int            cmdu, srcu, dstu, resu;
++      int                     cmdk, srck, dstk, resk;
++};
++
++struct hifn_session {
++      int hs_used;
++      int hs_mlen;
++      u_int8_t hs_iv[HIFN_MAX_IV_LENGTH];
++};
++
++#define       HIFN_RING_SYNC(sc, r, i, f)                                     \
++      /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++#define       HIFN_CMDR_SYNC(sc, i, f)        HIFN_RING_SYNC((sc), cmdr, (i), (f))
++#define       HIFN_RESR_SYNC(sc, i, f)        HIFN_RING_SYNC((sc), resr, (i), (f))
++#define       HIFN_SRCR_SYNC(sc, i, f)        HIFN_RING_SYNC((sc), srcr, (i), (f))
++#define       HIFN_DSTR_SYNC(sc, i, f)        HIFN_RING_SYNC((sc), dstr, (i), (f))
++
++#define       HIFN_CMD_SYNC(sc, i, f)                                         \
++      /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++#define       HIFN_RES_SYNC(sc, i, f)                                         \
++      /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++typedef int bus_size_t;
++
++/*
++ * Holds data specific to a single HIFN board.
++ */
++struct hifn_softc {
++      softc_device_decl                sc_dev;
++
++      struct pci_dev          *sc_pcidev;     /* PCI device pointer */
++      spinlock_t              sc_mtx;         /* per-instance lock */
++
++      int                     sc_num;         /* for multiple devs */
++
++      ocf_iomem_t             sc_bar0;
++      bus_size_t              sc_bar0_lastreg;/* bar0 last reg written */
++      ocf_iomem_t             sc_bar1;
++      bus_size_t              sc_bar1_lastreg;/* bar1 last reg written */
++
++      int                     sc_irq;
++
++      u_int32_t               sc_dmaier;
++      u_int32_t               sc_drammodel;   /* 1=dram, 0=sram */
++      u_int32_t               sc_pllconfig;   /* 7954/7955/7956 PLL config */
++
++      struct hifn_dma         *sc_dma;
++      dma_addr_t              sc_dma_physaddr;/* physical address of sc_dma */
++
++      int                     sc_dmansegs;
++      int32_t                 sc_cid;
++      int                     sc_maxses;
++      int                     sc_nsessions;
++      struct hifn_session     *sc_sessions;
++      int                     sc_ramsize;
++      int                     sc_flags;
++#define       HIFN_HAS_RNG            0x1     /* includes random number generator */
++#define       HIFN_HAS_PUBLIC         0x2     /* includes public key support */
++#define       HIFN_HAS_AES            0x4     /* includes AES support */
++#define       HIFN_IS_7811            0x8     /* Hifn 7811 part */
++#define       HIFN_IS_7956            0x10    /* Hifn 7956/7955 don't have SDRAM */
++
++      struct timer_list       sc_tickto;      /* for managing DMA */
++
++      int                     sc_rngfirst;
++      int                     sc_rnghz;       /* RNG polling frequency */
++
++      int                     sc_c_busy;      /* command ring busy */
++      int                     sc_s_busy;      /* source data ring busy */
++      int                     sc_d_busy;      /* destination data ring busy */
++      int                     sc_r_busy;      /* result ring busy */
++      int                     sc_active;      /* for initial countdown */
++      int                     sc_needwakeup;  /* ops q'd wating on resources */
++      int                     sc_curbatch;    /* # ops submitted w/o int */
++      int                     sc_suspended;
++#ifdef HIFN_VULCANDEV
++      struct cdev            *sc_pkdev;
++#endif
++};
++
++#define       HIFN_LOCK(_sc)          spin_lock_irqsave(&(_sc)->sc_mtx, l_flags)
++#define       HIFN_UNLOCK(_sc)        spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags)
++
++/*
++ *  hifn_command_t
++ *
++ *  This is the control structure used to pass commands to hifn_encrypt().
++ *
++ *  flags
++ *  -----
++ *  Flags is the bitwise "or" values for command configuration.  A single
++ *  encrypt direction needs to be set:
++ *
++ *    HIFN_ENCODE or HIFN_DECODE
++ *
++ *  To use cryptography, a single crypto algorithm must be included:
++ *
++ *    HIFN_CRYPT_3DES or HIFN_CRYPT_DES
++ *
++ *  To use authentication is used, a single MAC algorithm must be included:
++ *
++ *    HIFN_MAC_MD5 or HIFN_MAC_SHA1
++ *
++ *  By default MD5 uses a 16 byte hash and SHA-1 uses a 20 byte hash.
++ *  If the value below is set, hash values are truncated or assumed
++ *  truncated to 12 bytes:
++ *
++ *    HIFN_MAC_TRUNC
++ *
++ *  Keys for encryption and authentication can be sent as part of a command,
++ *  or the last key value used with a particular session can be retrieved
++ *  and used again if either of these flags are not specified.
++ *
++ *    HIFN_CRYPT_NEW_KEY, HIFN_MAC_NEW_KEY
++ *
++ *  session_num
++ *  -----------
++ *  A number between 0 and 2048 (for DRAM models) or a number between 
++ *  0 and 768 (for SRAM models).  Those who don't want to use session
++ *  numbers should leave value at zero and send a new crypt key and/or
++ *  new MAC key on every command.  If you use session numbers and
++ *  don't send a key with a command, the last key sent for that same
++ *  session number will be used.
++ *
++ *  Warning:  Using session numbers and multiboard at the same time
++ *            is currently broken.
++ *
++ *  mbuf
++ *  ----
++ *  Either fill in the mbuf pointer and npa=0 or
++ *     fill packp[] and packl[] and set npa to > 0
++ * 
++ *  mac_header_skip
++ *  ---------------
++ *  The number of bytes of the source_buf that are skipped over before
++ *  authentication begins.  This must be a number between 0 and 2^16-1
++ *  and can be used by IPsec implementers to skip over IP headers.
++ *  *** Value ignored if authentication not used ***
++ *
++ *  crypt_header_skip
++ *  -----------------
++ *  The number of bytes of the source_buf that are skipped over before
++ *  the cryptographic operation begins.  This must be a number between 0
++ *  and 2^16-1.  For IPsec, this number will always be 8 bytes larger
++ *  than the auth_header_skip (to skip over the ESP header).
++ *  *** Value ignored if cryptography not used ***
++ *
++ */
++struct hifn_operand {
++      union {
++              struct sk_buff *skb;
++              struct uio *io;
++              unsigned char *buf;
++      } u;
++      void            *map;
++      bus_size_t      mapsize;
++      int             nsegs;
++      struct {
++          dma_addr_t  ds_addr;
++          int         ds_len;
++      } segs[MAX_SCATTER];
++};
++
++struct hifn_command {
++      u_int16_t session_num;
++      u_int16_t base_masks, cry_masks, mac_masks;
++      u_int8_t iv[HIFN_MAX_IV_LENGTH], *ck, mac[HIFN_MAC_KEY_LENGTH];
++      int cklen;
++      int sloplen, slopidx;
++
++      struct hifn_operand src;
++      struct hifn_operand dst;
++
++      struct hifn_softc *softc;
++      struct cryptop *crp;
++      struct cryptodesc *enccrd, *maccrd;
++};
++
++#define       src_skb         src.u.skb
++#define       src_io          src.u.io
++#define       src_map         src.map
++#define       src_mapsize     src.mapsize
++#define       src_segs        src.segs
++#define       src_nsegs       src.nsegs
++#define       src_buf         src.u.buf
++
++#define       dst_skb         dst.u.skb
++#define       dst_io          dst.u.io
++#define       dst_map         dst.map
++#define       dst_mapsize     dst.mapsize
++#define       dst_segs        dst.segs
++#define       dst_nsegs       dst.nsegs
++#define       dst_buf         dst.u.buf
++
++/*
++ *  Return values for hifn_crypto()
++ */
++#define HIFN_CRYPTO_SUCCESS   0
++#define HIFN_CRYPTO_BAD_INPUT (-1)
++#define HIFN_CRYPTO_RINGS_FULL        (-2)
++
++/**************************************************************************
++ *
++ *  Function:  hifn_crypto
++ *
++ *  Purpose:   Called by external drivers to begin an encryption on the
++ *             HIFN board.
++ *
++ *  Blocking/Non-blocking Issues
++ *  ============================
++ *  The driver cannot block in hifn_crypto (no calls to tsleep) currently.
++ *  hifn_crypto() returns HIFN_CRYPTO_RINGS_FULL if there is not enough
++ *  room in any of the rings for the request to proceed.
++ *
++ *  Return Values
++ *  =============
++ *  0 for success, negative values on error
++ *
++ *  Defines for negative error codes are:
++ *  
++ *    HIFN_CRYPTO_BAD_INPUT  :  The passed in command had invalid settings.
++ *    HIFN_CRYPTO_RINGS_FULL :  All DMA rings were full and non-blocking
++ *                              behaviour was requested.
++ *
++ *************************************************************************/
++
++/*
++ * Convert back and forth from 'sid' to 'card' and 'session'
++ */
++#define HIFN_CARD(sid)                (((sid) & 0xf0000000) >> 28)
++#define HIFN_SESSION(sid)     ((sid) & 0x000007ff)
++#define HIFN_SID(crd,ses)     (((crd) << 28) | ((ses) & 0x7ff))
++
++#endif /* _KERNEL */
++
++struct hifn_stats {
++      u_int64_t hst_ibytes;
++      u_int64_t hst_obytes;
++      u_int32_t hst_ipackets;
++      u_int32_t hst_opackets;
++      u_int32_t hst_invalid;
++      u_int32_t hst_nomem;            /* malloc or one of hst_nomem_* */
++      u_int32_t hst_abort;
++      u_int32_t hst_noirq;            /* IRQ for no reason */
++      u_int32_t hst_totbatch;         /* ops submitted w/o interrupt */
++      u_int32_t hst_maxbatch;         /* max ops submitted together */
++      u_int32_t hst_unaligned;        /* unaligned src caused copy */
++      /*
++       * The following divides hst_nomem into more specific buckets.
++       */
++      u_int32_t hst_nomem_map;        /* bus_dmamap_create failed */
++      u_int32_t hst_nomem_load;       /* bus_dmamap_load_* failed */
++      u_int32_t hst_nomem_mbuf;       /* MGET* failed */
++      u_int32_t hst_nomem_mcl;        /* MCLGET* failed */
++      u_int32_t hst_nomem_cr;         /* out of command/result descriptor */
++      u_int32_t hst_nomem_sd;         /* out of src/dst descriptors */
++};
++
++#endif /* __HIFN7751VAR_H__ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifn7751.c   2008-02-14 14:59:01.000000000 +1000
+@@ -0,0 +1,2970 @@
++/*    $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $  */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ *                    http://www.netsec.net
++ * Copyright (c) 2003 Hifn Inc.
++ *
++ * This driver is based on a previous driver by Invertex, for which they
++ * requested:  Please send any comments, feedback, bug-fixes, or feature
++ * requests to software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ *
++__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.40 2007/03/21 03:42:49 sam Exp $");
++ */
++
++/*
++ * Driver for various Hifn encryption processors.
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++#include <hifn/hifn7751reg.h>
++#include <hifn/hifn7751var.h>
++
++#if 1
++#define       DPRINTF(a...)   if (hifn_debug) { \
++                                                      printk("%s: ", sc ? \
++                                                              device_get_nameunit(sc->sc_dev) : "hifn"); \
++                                                      printk(a); \
++                                              } else
++#else
++#define       DPRINTF(a...)
++#endif
++
++static inline int
++pci_get_revid(struct pci_dev *dev)
++{
++      u8 rid = 0;
++      pci_read_config_byte(dev, PCI_REVISION_ID, &rid);
++      return rid;
++}
++
++static        struct hifn_stats hifnstats;
++
++#define       debug hifn_debug
++int hifn_debug = 0;
++module_param(hifn_debug, int, 0644);
++MODULE_PARM_DESC(hifn_debug, "Enable debug");
++
++int hifn_maxbatch = 1;
++module_param(hifn_maxbatch, int, 0644);
++MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt");
++
++#ifdef MODULE_PARM
++char *hifn_pllconfig = NULL;
++MODULE_PARM(hifn_pllconfig, "s");
++#else
++char hifn_pllconfig[32]; /* This setting is RO after loading */
++module_param_string(hifn_pllconfig, hifn_pllconfig, 32, 0444);
++#endif
++MODULE_PARM_DESC(hifn_pllconfig, "PLL config, ie., pci66, ext33, ...");
++
++#ifdef HIFN_VULCANDEV
++#include <sys/conf.h>
++#include <sys/uio.h>
++
++static struct cdevsw vulcanpk_cdevsw; /* forward declaration */
++#endif
++
++/*
++ * Prototypes and count for the pci_device structure
++ */
++static        int  hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent);
++static        void hifn_remove(struct pci_dev *dev);
++
++static        int hifn_newsession(device_t, u_int32_t *, struct cryptoini *);
++static        int hifn_freesession(device_t, u_int64_t);
++static        int hifn_process(device_t, struct cryptop *, int);
++
++static device_method_t hifn_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, hifn_newsession),
++      DEVMETHOD(cryptodev_freesession,hifn_freesession),
++      DEVMETHOD(cryptodev_process,    hifn_process),
++};
++
++static        void hifn_reset_board(struct hifn_softc *, int);
++static        void hifn_reset_puc(struct hifn_softc *);
++static        void hifn_puc_wait(struct hifn_softc *);
++static        int hifn_enable_crypto(struct hifn_softc *);
++static        void hifn_set_retry(struct hifn_softc *sc);
++static        void hifn_init_dma(struct hifn_softc *);
++static        void hifn_init_pci_registers(struct hifn_softc *);
++static        int hifn_sramsize(struct hifn_softc *);
++static        int hifn_dramsize(struct hifn_softc *);
++static        int hifn_ramtype(struct hifn_softc *);
++static        void hifn_sessions(struct hifn_softc *);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hifn_intr(int irq, void *arg);
++#else
++static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs);
++#endif
++static        u_int hifn_write_command(struct hifn_command *, u_int8_t *);
++static        u_int32_t hifn_next_signature(u_int32_t a, u_int cnt);
++static        void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *);
++static        int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int);
++static        int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *);
++static        int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *);
++static        int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *);
++static        int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *);
++static        int hifn_init_pubrng(struct hifn_softc *);
++static        void hifn_tick(unsigned long arg);
++static        void hifn_abort(struct hifn_softc *);
++static        void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *);
++
++static        void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t);
++static        void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t);
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static        int hifn_read_random(void *arg, u_int32_t *buf, int len);
++#endif
++
++#define HIFN_MAX_CHIPS        8
++static struct hifn_softc *hifn_chip_idx[HIFN_MAX_CHIPS];
++
++static __inline u_int32_t
++READ_REG_0(struct hifn_softc *sc, bus_size_t reg)
++{
++      u_int32_t v = readl(sc->sc_bar0 + reg);
++      sc->sc_bar0_lastreg = (bus_size_t) -1;
++      return (v);
++}
++#define       WRITE_REG_0(sc, reg, val)       hifn_write_reg_0(sc, reg, val)
++
++static __inline u_int32_t
++READ_REG_1(struct hifn_softc *sc, bus_size_t reg)
++{
++      u_int32_t v = readl(sc->sc_bar1 + reg);
++      sc->sc_bar1_lastreg = (bus_size_t) -1;
++      return (v);
++}
++#define       WRITE_REG_1(sc, reg, val)       hifn_write_reg_1(sc, reg, val)
++
++/*
++ * map in a given buffer (great on some arches :-)
++ */
++
++static int
++pci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio)
++{
++      struct iovec *iov = uio->uio_iov;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      buf->mapsize = 0;
++      for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) {
++              buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev,
++                              iov->iov_base, iov->iov_len,
++                              PCI_DMA_BIDIRECTIONAL);
++              buf->segs[buf->nsegs].ds_len = iov->iov_len;
++              buf->mapsize += iov->iov_len;
++              iov++;
++              buf->nsegs++;
++      }
++      /* identify this buffer by the first segment */
++      buf->map = (void *) buf->segs[0].ds_addr;
++      return(0);
++}
++
++/*
++ * map in a given sk_buff
++ */
++
++static int
++pci_map_skb(struct hifn_softc *sc,struct hifn_operand *buf,struct sk_buff *skb)
++{
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      buf->mapsize = 0;
++
++      buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev,
++                      skb->data, skb_headlen(skb), PCI_DMA_BIDIRECTIONAL);
++      buf->segs[0].ds_len = skb_headlen(skb);
++      buf->mapsize += buf->segs[0].ds_len;
++
++      buf->nsegs = 1;
++
++      for (i = 0; i < skb_shinfo(skb)->nr_frags; ) {
++              buf->segs[buf->nsegs].ds_len = skb_shinfo(skb)->frags[i].size;
++              buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev,
++                              page_address(skb_shinfo(skb)->frags[i].page) +
++                                      skb_shinfo(skb)->frags[i].page_offset,
++                              buf->segs[buf->nsegs].ds_len, PCI_DMA_BIDIRECTIONAL);
++              buf->mapsize += buf->segs[buf->nsegs].ds_len;
++              buf->nsegs++;
++      }
++
++      /* identify this buffer by the first segment */
++      buf->map = (void *) buf->segs[0].ds_addr;
++      return(0);
++}
++
++/*
++ * map in a given contiguous buffer
++ */
++
++static int
++pci_map_buf(struct hifn_softc *sc,struct hifn_operand *buf, void *b, int len)
++{
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      buf->mapsize = 0;
++      buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev,
++                      b, len, PCI_DMA_BIDIRECTIONAL);
++      buf->segs[0].ds_len = len;
++      buf->mapsize += buf->segs[0].ds_len;
++      buf->nsegs = 1;
++
++      /* identify this buffer by the first segment */
++      buf->map = (void *) buf->segs[0].ds_addr;
++      return(0);
++}
++
++#if 0 /* not needed at this time */
++static void
++pci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf)
++{
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      for (i = 0; i < buf->nsegs; i++)
++              pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr,
++                              buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++}
++#endif
++
++static void
++pci_unmap_buf(struct hifn_softc *sc, struct hifn_operand *buf)
++{
++      int i;
++      DPRINTF("%s()\n", __FUNCTION__);
++      for (i = 0; i < buf->nsegs; i++) {
++              pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr,
++                              buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++              buf->segs[i].ds_addr = 0;
++              buf->segs[i].ds_len = 0;
++      }
++      buf->nsegs = 0;
++      buf->mapsize = 0;
++      buf->map = 0;
++}
++
++static const char*
++hifn_partname(struct hifn_softc *sc)
++{
++      /* XXX sprintf numbers when not decoded */
++      switch (pci_get_vendor(sc->sc_pcidev)) {
++      case PCI_VENDOR_HIFN:
++              switch (pci_get_device(sc->sc_pcidev)) {
++              case PCI_PRODUCT_HIFN_6500:     return "Hifn 6500";
++              case PCI_PRODUCT_HIFN_7751:     return "Hifn 7751";
++              case PCI_PRODUCT_HIFN_7811:     return "Hifn 7811";
++              case PCI_PRODUCT_HIFN_7951:     return "Hifn 7951";
++              case PCI_PRODUCT_HIFN_7955:     return "Hifn 7955";
++              case PCI_PRODUCT_HIFN_7956:     return "Hifn 7956";
++              }
++              return "Hifn unknown-part";
++      case PCI_VENDOR_INVERTEX:
++              switch (pci_get_device(sc->sc_pcidev)) {
++              case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON";
++              }
++              return "Invertex unknown-part";
++      case PCI_VENDOR_NETSEC:
++              switch (pci_get_device(sc->sc_pcidev)) {
++              case PCI_PRODUCT_NETSEC_7751:   return "NetSec 7751";
++              }
++              return "NetSec unknown-part";
++      }
++      return "Unknown-vendor unknown-part";
++}
++
++static u_int
++checkmaxmin(struct pci_dev *dev, const char *what, u_int v, u_int min, u_int max)
++{
++      struct hifn_softc *sc = pci_get_drvdata(dev);
++      if (v > max) {
++              device_printf(sc->sc_dev, "Warning, %s %u out of range, "
++                      "using max %u\n", what, v, max);
++              v = max;
++      } else if (v < min) {
++              device_printf(sc->sc_dev, "Warning, %s %u out of range, "
++                      "using min %u\n", what, v, min);
++              v = min;
++      }
++      return v;
++}
++
++/*
++ * Select PLL configuration for 795x parts.  This is complicated in
++ * that we cannot determine the optimal parameters without user input.
++ * The reference clock is derived from an external clock through a
++ * multiplier.  The external clock is either the host bus (i.e. PCI)
++ * or an external clock generator.  When using the PCI bus we assume
++ * the clock is either 33 or 66 MHz; for an external source we cannot
++ * tell the speed.
++ *
++ * PLL configuration is done with a string: "pci" for PCI bus, or "ext"
++ * for an external source, followed by the frequency.  We calculate
++ * the appropriate multiplier and PLL register contents accordingly.
++ * When no configuration is given we default to "pci66" since that
++ * always will allow the card to work.  If a card is using the PCI
++ * bus clock and in a 33MHz slot then it will be operating at half
++ * speed until the correct information is provided.
++ *
++ * We use a default setting of "ext66" because according to Mike Ham
++ * of HiFn, almost every board in existence has an external crystal
++ * populated at 66Mhz. Using PCI can be a problem on modern motherboards,
++ * because PCI33 can have clocks from 0 to 33Mhz, and some have
++ * non-PCI-compliant spread-spectrum clocks, which can confuse the pll.
++ */
++static void
++hifn_getpllconfig(struct pci_dev *dev, u_int *pll)
++{
++      const char *pllspec = hifn_pllconfig;
++      u_int freq, mul, fl, fh;
++      u_int32_t pllconfig;
++      char *nxt;
++
++      if (pllspec == NULL)
++              pllspec = "ext66";
++      fl = 33, fh = 66;
++      pllconfig = 0;
++      if (strncmp(pllspec, "ext", 3) == 0) {
++              pllspec += 3;
++              pllconfig |= HIFN_PLL_REF_SEL;
++              switch (pci_get_device(dev)) {
++              case PCI_PRODUCT_HIFN_7955:
++              case PCI_PRODUCT_HIFN_7956:
++                      fl = 20, fh = 100;
++                      break;
++#ifdef notyet
++              case PCI_PRODUCT_HIFN_7954:
++                      fl = 20, fh = 66;
++                      break;
++#endif
++              }
++      } else if (strncmp(pllspec, "pci", 3) == 0)
++              pllspec += 3;
++      freq = strtoul(pllspec, &nxt, 10);
++      if (nxt == pllspec)
++              freq = 66;
++      else
++              freq = checkmaxmin(dev, "frequency", freq, fl, fh);
++      /*
++       * Calculate multiplier.  We target a Fck of 266 MHz,
++       * allowing only even values, possibly rounded down.
++       * Multipliers > 8 must set the charge pump current.
++       */
++      mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12);
++      pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT;
++      if (mul > 8)
++              pllconfig |= HIFN_PLL_IS;
++      *pll = pllconfig;
++}
++
++/*
++ * Attach an interface that successfully probed.
++ */
++static int
++hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++      struct hifn_softc *sc = NULL;
++      char rbase;
++      u_int16_t ena, rev;
++      int rseg, rc;
++      unsigned long mem_start, mem_len;
++      static int num_chips = 0;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (pci_enable_device(dev) < 0)
++              return(-ENODEV);
++
++      if (pci_set_mwi(dev))
++              return(-ENODEV);
++
++      if (!dev->irq) {
++              printk("hifn: found device with no IRQ assigned. check BIOS settings!");
++              pci_disable_device(dev);
++              return(-ENODEV);
++      }
++
++      sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++      if (!sc)
++              return(-ENOMEM);
++      memset(sc, 0, sizeof(*sc));
++
++      softc_device_init(sc, "hifn", num_chips, hifn_methods);
++
++      sc->sc_pcidev = dev;
++      sc->sc_irq = -1;
++      sc->sc_cid = -1;
++      sc->sc_num = num_chips++;
++      if (sc->sc_num < HIFN_MAX_CHIPS)
++              hifn_chip_idx[sc->sc_num] = sc;
++
++      pci_set_drvdata(sc->sc_pcidev, sc);
++
++      spin_lock_init(&sc->sc_mtx);
++
++      /* XXX handle power management */
++
++      /*
++       * The 7951 and 795x have a random number generator and
++       * public key support; note this.
++       */
++      if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++          (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 ||
++           pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 ||
++           pci_get_device(dev) == PCI_PRODUCT_HIFN_7956))
++              sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC;
++      /*
++       * The 7811 has a random number generator and
++       * we also note it's identity 'cuz of some quirks.
++       */
++      if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++          pci_get_device(dev) == PCI_PRODUCT_HIFN_7811)
++              sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG;
++
++      /*
++       * The 795x parts support AES.
++       */
++      if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++          (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 ||
++           pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) {
++              sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES;
++              /*
++               * Select PLL configuration.  This depends on the
++               * bus and board design and must be manually configured
++               * if the default setting is unacceptable.
++               */
++              hifn_getpllconfig(dev, &sc->sc_pllconfig);
++      }
++
++      /*
++       * Setup PCI resources. Note that we record the bus
++       * tag and handle for each register mapping, this is
++       * used by the READ_REG_0, WRITE_REG_0, READ_REG_1,
++       * and WRITE_REG_1 macros throughout the driver.
++       */
++      mem_start = pci_resource_start(sc->sc_pcidev, 0);
++      mem_len   = pci_resource_len(sc->sc_pcidev, 0);
++      sc->sc_bar0 = (ocf_iomem_t) ioremap(mem_start, mem_len);
++      if (!sc->sc_bar0) {
++              device_printf(sc->sc_dev, "cannot map bar%d register space\n", 0);
++              goto fail;
++      }
++      sc->sc_bar0_lastreg = (bus_size_t) -1;
++
++      mem_start = pci_resource_start(sc->sc_pcidev, 1);
++      mem_len   = pci_resource_len(sc->sc_pcidev, 1);
++      sc->sc_bar1 = (ocf_iomem_t) ioremap(mem_start, mem_len);
++      if (!sc->sc_bar1) {
++              device_printf(sc->sc_dev, "cannot map bar%d register space\n", 1);
++              goto fail;
++      }
++      sc->sc_bar1_lastreg = (bus_size_t) -1;
++
++      /* fix up the bus size */
++      if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
++              device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n");
++              goto fail;
++      }
++      if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
++              device_printf(sc->sc_dev,
++                              "No usable consistent DMA configuration, aborting.\n");
++              goto fail;
++      }
++
++      hifn_set_retry(sc);
++
++      /*
++       * Setup the area where the Hifn DMA's descriptors
++       * and associated data structures.
++       */
++      sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev,
++                      sizeof(*sc->sc_dma),
++                      &sc->sc_dma_physaddr);
++      if (!sc->sc_dma) {
++              device_printf(sc->sc_dev, "cannot alloc sc_dma\n");
++              goto fail;
++      }
++      bzero(sc->sc_dma, sizeof(*sc->sc_dma));
++
++      /*
++       * Reset the board and do the ``secret handshake''
++       * to enable the crypto support.  Then complete the
++       * initialization procedure by setting up the interrupt
++       * and hooking in to the system crypto support so we'll
++       * get used for system services like the crypto device,
++       * IPsec, RNG device, etc.
++       */
++      hifn_reset_board(sc, 0);
++
++      if (hifn_enable_crypto(sc) != 0) {
++              device_printf(sc->sc_dev, "crypto enabling failed\n");
++              goto fail;
++      }
++      hifn_reset_puc(sc);
++
++      hifn_init_dma(sc);
++      hifn_init_pci_registers(sc);
++
++      pci_set_master(sc->sc_pcidev);
++
++      /* XXX can't dynamically determine ram type for 795x; force dram */
++      if (sc->sc_flags & HIFN_IS_7956)
++              sc->sc_drammodel = 1;
++      else if (hifn_ramtype(sc))
++              goto fail;
++
++      if (sc->sc_drammodel == 0)
++              hifn_sramsize(sc);
++      else
++              hifn_dramsize(sc);
++
++      /*
++       * Workaround for NetSec 7751 rev A: half ram size because two
++       * of the address lines were left floating
++       */
++      if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC &&
++          pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 &&
++          pci_get_revid(dev) == 0x61) /*XXX???*/
++              sc->sc_ramsize >>= 1;
++
++      /*
++       * Arrange the interrupt line.
++       */
++      rc = request_irq(dev->irq, hifn_intr, IRQF_SHARED, "hifn", sc);
++      if (rc) {
++              device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc);
++              goto fail;
++      }
++      sc->sc_irq = dev->irq;
++
++      hifn_sessions(sc);
++
++      /*
++       * NB: Keep only the low 16 bits; this masks the chip id
++       *     from the 7951.
++       */
++      rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff;
++
++      rseg = sc->sc_ramsize / 1024;
++      rbase = 'K';
++      if (sc->sc_ramsize >= (1024 * 1024)) {
++              rbase = 'M';
++              rseg /= 1024;
++      }
++      device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram",
++              hifn_partname(sc), rev,
++              rseg, rbase, sc->sc_drammodel ? 'd' : 's');
++      if (sc->sc_flags & HIFN_IS_7956)
++              printf(", pll=0x%x<%s clk, %ux mult>",
++                      sc->sc_pllconfig,
++                      sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci",
++                      2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11));
++      printf("\n");
++
++      sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++      if (sc->sc_cid < 0) {
++              device_printf(sc->sc_dev, "could not get crypto driver id\n");
++              goto fail;
++      }
++
++      WRITE_REG_0(sc, HIFN_0_PUCNFG,
++          READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID);
++      ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++      switch (ena) {
++      case HIFN_PUSTAT_ENA_2:
++              crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0);
++              if (sc->sc_flags & HIFN_HAS_AES)
++                      crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++              /*FALLTHROUGH*/
++      case HIFN_PUSTAT_ENA_1:
++              crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++              break;
++      }
++
++      if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG))
++              hifn_init_pubrng(sc);
++
++      init_timer(&sc->sc_tickto);
++      sc->sc_tickto.function = hifn_tick;
++      sc->sc_tickto.data = (unsigned long) sc->sc_num;
++      mod_timer(&sc->sc_tickto, jiffies + HZ);
++
++      return (0);
++
++fail:
++    if (sc->sc_cid >= 0)
++        crypto_unregister_all(sc->sc_cid);
++    if (sc->sc_irq != -1)
++        free_irq(sc->sc_irq, sc);
++    if (sc->sc_dma) {
++              /* Turn off DMA polling */
++              WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++                      HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++        pci_free_consistent(sc->sc_pcidev,
++                              sizeof(*sc->sc_dma),
++                sc->sc_dma, sc->sc_dma_physaddr);
++      }
++    kfree(sc);
++      return (-ENXIO);
++}
++
++/*
++ * Detach an interface that successfully probed.
++ */
++static void
++hifn_remove(struct pci_dev *dev)
++{
++      struct hifn_softc *sc = pci_get_drvdata(dev);
++      unsigned long l_flags;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      KASSERT(sc != NULL, ("hifn_detach: null software carrier!"));
++
++      /* disable interrupts */
++      HIFN_LOCK(sc);
++      WRITE_REG_1(sc, HIFN_1_DMA_IER, 0);
++      HIFN_UNLOCK(sc);
++
++      /*XXX other resources */
++      del_timer_sync(&sc->sc_tickto);
++
++      /* Turn off DMA polling */
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++      crypto_unregister_all(sc->sc_cid);
++
++      free_irq(sc->sc_irq, sc);
++
++      pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma),
++                sc->sc_dma, sc->sc_dma_physaddr);
++}
++
++
++static int
++hifn_init_pubrng(struct hifn_softc *sc)
++{
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if ((sc->sc_flags & HIFN_IS_7811) == 0) {
++              /* Reset 7951 public key/rng engine */
++              WRITE_REG_1(sc, HIFN_1_PUB_RESET,
++                  READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET);
++
++              for (i = 0; i < 100; i++) {
++                      DELAY(1000);
++                      if ((READ_REG_1(sc, HIFN_1_PUB_RESET) &
++                          HIFN_PUBRST_RESET) == 0)
++                              break;
++              }
++
++              if (i == 100) {
++                      device_printf(sc->sc_dev, "public key init failed\n");
++                      return (1);
++              }
++      }
++
++      /* Enable the rng, if available */
++#ifdef CONFIG_OCF_RANDOMHARVEST
++      if (sc->sc_flags & HIFN_HAS_RNG) {
++              if (sc->sc_flags & HIFN_IS_7811) {
++                      u_int32_t r;
++                      r = READ_REG_1(sc, HIFN_1_7811_RNGENA);
++                      if (r & HIFN_7811_RNGENA_ENA) {
++                              r &= ~HIFN_7811_RNGENA_ENA;
++                              WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
++                      }
++                      WRITE_REG_1(sc, HIFN_1_7811_RNGCFG,
++                          HIFN_7811_RNGCFG_DEFL);
++                      r |= HIFN_7811_RNGENA_ENA;
++                      WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
++              } else
++                      WRITE_REG_1(sc, HIFN_1_RNG_CONFIG,
++                          READ_REG_1(sc, HIFN_1_RNG_CONFIG) |
++                          HIFN_RNGCFG_ENA);
++
++              sc->sc_rngfirst = 1;
++              crypto_rregister(sc->sc_cid, hifn_read_random, sc);
++      }
++#endif
++
++      /* Enable public key engine, if available */
++      if (sc->sc_flags & HIFN_HAS_PUBLIC) {
++              WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
++              sc->sc_dmaier |= HIFN_DMAIER_PUBDONE;
++              WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++#ifdef HIFN_VULCANDEV
++              sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0, 
++                                      UID_ROOT, GID_WHEEL, 0666,
++                                      "vulcanpk");
++              sc->sc_pkdev->si_drv1 = sc;
++#endif
++      }
++
++      return (0);
++}
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static int
++hifn_read_random(void *arg, u_int32_t *buf, int len)
++{
++      struct hifn_softc *sc = (struct hifn_softc *) arg;
++      u_int32_t sts;
++      int i, rc = 0;
++
++      if (len <= 0)
++              return rc;
++
++      if (sc->sc_flags & HIFN_IS_7811) {
++              /* ONLY VALID ON 7811!!!! */
++              for (i = 0; i < 5; i++) {
++                      sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS);
++                      if (sts & HIFN_7811_RNGSTS_UFL) {
++                              device_printf(sc->sc_dev,
++                                            "RNG underflow: disabling\n");
++                              /* DAVIDM perhaps return -1 */
++                              break;
++                      }
++                      if ((sts & HIFN_7811_RNGSTS_RDY) == 0)
++                              break;
++
++                      /*
++                       * There are at least two words in the RNG FIFO
++                       * at this point.
++                       */
++                      if (rc < len)
++                              buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
++                      if (rc < len)
++                              buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
++              }
++      } else
++              buf[rc++] = READ_REG_1(sc, HIFN_1_RNG_DATA);
++
++      /* NB: discard first data read */
++      if (sc->sc_rngfirst) {
++              sc->sc_rngfirst = 0;
++              rc = 0;
++      }
++
++      return(rc);
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++static void
++hifn_puc_wait(struct hifn_softc *sc)
++{
++      int i;
++      int reg = HIFN_0_PUCTRL;
++
++      if (sc->sc_flags & HIFN_IS_7956) {
++              reg = HIFN_0_PUCTRL2;
++      }
++
++      for (i = 5000; i > 0; i--) {
++              DELAY(1);
++              if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET))
++                      break;
++      }
++      if (!i)
++              device_printf(sc->sc_dev, "proc unit did not reset(0x%x)\n",
++                              READ_REG_0(sc, HIFN_0_PUCTRL));
++}
++
++/*
++ * Reset the processing unit.
++ */
++static void
++hifn_reset_puc(struct hifn_softc *sc)
++{
++      /* Reset processing unit */
++      int reg = HIFN_0_PUCTRL;
++
++      if (sc->sc_flags & HIFN_IS_7956) {
++              reg = HIFN_0_PUCTRL2;
++      }
++      WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA);
++
++      hifn_puc_wait(sc);
++}
++
++/*
++ * Set the Retry and TRDY registers; note that we set them to
++ * zero because the 7811 locks up when forced to retry (section
++ * 3.6 of "Specification Update SU-0014-04".  Not clear if we
++ * should do this for all Hifn parts, but it doesn't seem to hurt.
++ */
++static void
++hifn_set_retry(struct hifn_softc *sc)
++{
++      DPRINTF("%s()\n", __FUNCTION__);
++      /* NB: RETRY only responds to 8-bit reads/writes */
++      pci_write_config_byte(sc->sc_pcidev, HIFN_RETRY_TIMEOUT, 0);
++      pci_write_config_dword(sc->sc_pcidev, HIFN_TRDY_TIMEOUT, 0);
++}
++
++/*
++ * Resets the board.  Values in the regesters are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++hifn_reset_board(struct hifn_softc *sc, int full)
++{
++      u_int32_t reg;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      /*
++       * Set polling in the DMA configuration register to zero.  0x7 avoids
++       * resetting the board and zeros out the other fields.
++       */
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++      /*
++       * Now that polling has been disabled, we have to wait 1 ms
++       * before resetting the board.
++       */
++      DELAY(1000);
++
++      /* Reset the DMA unit */
++      if (full) {
++              WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
++              DELAY(1000);
++      } else {
++              WRITE_REG_1(sc, HIFN_1_DMA_CNFG,
++                  HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET);
++              hifn_reset_puc(sc);
++      }
++
++      KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!"));
++      bzero(sc->sc_dma, sizeof(*sc->sc_dma));
++
++      /* Bring dma unit out of reset */
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++      hifn_puc_wait(sc);
++      hifn_set_retry(sc);
++
++      if (sc->sc_flags & HIFN_IS_7811) {
++              for (reg = 0; reg < 1000; reg++) {
++                      if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) &
++                          HIFN_MIPSRST_CRAMINIT)
++                              break;
++                      DELAY(1000);
++              }
++              if (reg == 1000)
++                      device_printf(sc->sc_dev, ": cram init timeout\n");
++      } else {
++        /* set up DMA configuration register #2 */
++        /* turn off all PK and BAR0 swaps */
++        WRITE_REG_1(sc, HIFN_1_DMA_CNFG2,
++                    (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)|
++                    (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)|
++                    (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)|
++                    (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT));
++      }
++}
++
++static u_int32_t
++hifn_next_signature(u_int32_t a, u_int cnt)
++{
++      int i;
++      u_int32_t v;
++
++      for (i = 0; i < cnt; i++) {
++
++              /* get the parity */
++              v = a & 0x80080125;
++              v ^= v >> 16;
++              v ^= v >> 8;
++              v ^= v >> 4;
++              v ^= v >> 2;
++              v ^= v >> 1;
++
++              a = (v & 1) ^ (a << 1);
++      }
++
++      return a;
++}
++
++
++/*
++ * Checks to see if crypto is already enabled.  If crypto isn't enable,
++ * "hifn_enable_crypto" is called to enable it.  The check is important,
++ * as enabling crypto twice will lock the board.
++ */
++static int 
++hifn_enable_crypto(struct hifn_softc *sc)
++{
++      u_int32_t dmacfg, ramcfg, encl, addr, i;
++      char offtbl[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                                        0x00, 0x00, 0x00, 0x00 };
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG);
++      dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG);
++
++      /*
++       * The RAM config register's encrypt level bit needs to be set before
++       * every read performed on the encryption level register.
++       */
++      WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
++
++      encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++      /*
++       * Make sure we don't re-unlock.  Two unlocks kills chip until the
++       * next reboot.
++       */
++      if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) {
++#ifdef HIFN_DEBUG
++              if (hifn_debug)
++                      device_printf(sc->sc_dev,
++                          "Strong crypto already enabled!\n");
++#endif
++              goto report;
++      }
++
++      if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) {
++#ifdef HIFN_DEBUG
++              if (hifn_debug)
++                      device_printf(sc->sc_dev,
++                            "Unknown encryption level 0x%x\n", encl);
++#endif
++              return 1;
++      }
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK |
++          HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++      DELAY(1000);
++      addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1);
++      DELAY(1000);
++      WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0);
++      DELAY(1000);
++
++      for (i = 0; i <= 12; i++) {
++              addr = hifn_next_signature(addr, offtbl[i] + 0x101);
++              WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr);
++
++              DELAY(1000);
++      }
++
++      WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
++      encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++#ifdef HIFN_DEBUG
++      if (hifn_debug) {
++              if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2)
++                      device_printf(sc->sc_dev, "Engine is permanently "
++                              "locked until next system reset!\n");
++              else
++                      device_printf(sc->sc_dev, "Engine enabled "
++                              "successfully!\n");
++      }
++#endif
++
++report:
++      WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg);
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg);
++
++      switch (encl) {
++      case HIFN_PUSTAT_ENA_1:
++      case HIFN_PUSTAT_ENA_2:
++              break;
++      case HIFN_PUSTAT_ENA_0:
++      default:
++              device_printf(sc->sc_dev, "disabled\n");
++              break;
++      }
++
++      return 0;
++}
++
++/*
++ * Give initial values to the registers listed in the "Register Space"
++ * section of the HIFN Software Development reference manual.
++ */
++static void 
++hifn_init_pci_registers(struct hifn_softc *sc)
++{
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /* write fixed values needed by the Initialization registers */
++      WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
++      WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
++      WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
++
++      /* write all 4 ring address registers */
++      WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, cmdr[0]));
++      WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, srcr[0]));
++      WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, dstr[0]));
++      WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, resr[0]));
++
++      DELAY(2000);
++
++      /* write status register */
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++          HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
++          HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
++          HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
++          HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
++          HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
++          HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
++          HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
++          HIFN_DMACSR_S_WAIT |
++          HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
++          HIFN_DMACSR_C_WAIT |
++          HIFN_DMACSR_ENGINE |
++          ((sc->sc_flags & HIFN_HAS_PUBLIC) ?
++              HIFN_DMACSR_PUBDONE : 0) |
++          ((sc->sc_flags & HIFN_IS_7811) ?
++              HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0));
++
++      sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0;
++      sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
++          HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
++          HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
++          ((sc->sc_flags & HIFN_IS_7811) ?
++              HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0);
++      sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
++      WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++
++
++      if (sc->sc_flags & HIFN_IS_7956) {
++              u_int32_t pll;
++
++              WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
++                  HIFN_PUCNFG_TCALLPHASES |
++                  HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32);
++
++              /* turn off the clocks and insure bypass is set */
++              pll = READ_REG_1(sc, HIFN_1_PLL);
++              pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL))
++                | HIFN_PLL_BP | HIFN_PLL_MBSET;
++              WRITE_REG_1(sc, HIFN_1_PLL, pll);
++              DELAY(10*1000);         /* 10ms */
++
++              /* change configuration */
++              pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig;
++              WRITE_REG_1(sc, HIFN_1_PLL, pll);
++              DELAY(10*1000);         /* 10ms */
++
++              /* disable bypass */
++              pll &= ~HIFN_PLL_BP;
++              WRITE_REG_1(sc, HIFN_1_PLL, pll);
++              /* enable clocks with new configuration */
++              pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL;
++              WRITE_REG_1(sc, HIFN_1_PLL, pll);
++      } else {
++              WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
++                  HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
++                  HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
++                  (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM));
++      }
++
++      WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
++          ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
++          ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
++}
++
++/*
++ * The maximum number of sessions supported by the card
++ * is dependent on the amount of context ram, which
++ * encryption algorithms are enabled, and how compression
++ * is configured.  This should be configured before this
++ * routine is called.
++ */
++static void
++hifn_sessions(struct hifn_softc *sc)
++{
++      u_int32_t pucnfg;
++      int ctxsize;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG);
++
++      if (pucnfg & HIFN_PUCNFG_COMPSING) {
++              if (pucnfg & HIFN_PUCNFG_ENCCNFG)
++                      ctxsize = 128;
++              else
++                      ctxsize = 512;
++              /*
++               * 7955/7956 has internal context memory of 32K
++               */
++              if (sc->sc_flags & HIFN_IS_7956)
++                      sc->sc_maxses = 32768 / ctxsize;
++              else
++                      sc->sc_maxses = 1 +
++                          ((sc->sc_ramsize - 32768) / ctxsize);
++      } else
++              sc->sc_maxses = sc->sc_ramsize / 16384;
++
++      if (sc->sc_maxses > 2048)
++              sc->sc_maxses = 2048;
++}
++
++/*
++ * Determine ram type (sram or dram).  Board should be just out of a reset
++ * state when this is called.
++ */
++static int
++hifn_ramtype(struct hifn_softc *sc)
++{
++      u_int8_t data[8], dataexpect[8];
++      int i;
++
++      for (i = 0; i < sizeof(data); i++)
++              data[i] = dataexpect[i] = 0x55;
++      if (hifn_writeramaddr(sc, 0, data))
++              return (-1);
++      if (hifn_readramaddr(sc, 0, data))
++              return (-1);
++      if (bcmp(data, dataexpect, sizeof(data)) != 0) {
++              sc->sc_drammodel = 1;
++              return (0);
++      }
++
++      for (i = 0; i < sizeof(data); i++)
++              data[i] = dataexpect[i] = 0xaa;
++      if (hifn_writeramaddr(sc, 0, data))
++              return (-1);
++      if (hifn_readramaddr(sc, 0, data))
++              return (-1);
++      if (bcmp(data, dataexpect, sizeof(data)) != 0) {
++              sc->sc_drammodel = 1;
++              return (0);
++      }
++
++      return (0);
++}
++
++#define       HIFN_SRAM_MAX           (32 << 20)
++#define       HIFN_SRAM_STEP_SIZE     16384
++#define       HIFN_SRAM_GRANULARITY   (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE)
++
++static int
++hifn_sramsize(struct hifn_softc *sc)
++{
++      u_int32_t a;
++      u_int8_t data[8];
++      u_int8_t dataexpect[sizeof(data)];
++      int32_t i;
++
++      for (i = 0; i < sizeof(data); i++)
++              data[i] = dataexpect[i] = i ^ 0x5a;
++
++      for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) {
++              a = i * HIFN_SRAM_STEP_SIZE;
++              bcopy(&i, data, sizeof(i));
++              hifn_writeramaddr(sc, a, data);
++      }
++
++      for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) {
++              a = i * HIFN_SRAM_STEP_SIZE;
++              bcopy(&i, dataexpect, sizeof(i));
++              if (hifn_readramaddr(sc, a, data) < 0)
++                      return (0);
++              if (bcmp(data, dataexpect, sizeof(data)) != 0)
++                      return (0);
++              sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE;
++      }
++
++      return (0);
++}
++
++/*
++ * XXX For dram boards, one should really try all of the
++ * HIFN_PUCNFG_DSZ_*'s.  This just assumes that PUCNFG
++ * is already set up correctly.
++ */
++static int
++hifn_dramsize(struct hifn_softc *sc)
++{
++      u_int32_t cnfg;
++
++      if (sc->sc_flags & HIFN_IS_7956) {
++              /*
++               * 7955/7956 have a fixed internal ram of only 32K.
++               */
++              sc->sc_ramsize = 32768;
++      } else {
++              cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) &
++                  HIFN_PUCNFG_DRAMMASK;
++              sc->sc_ramsize = 1 << ((cnfg >> 13) + 18);
++      }
++      return (0);
++}
++
++static void
++hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (dma->cmdi == HIFN_D_CMD_RSIZE) {
++              dma->cmdi = 0;
++              dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      }
++      *cmdp = dma->cmdi++;
++      dma->cmdk = dma->cmdi;
++
++      if (dma->srci == HIFN_D_SRC_RSIZE) {
++              dma->srci = 0;
++              dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->srcr[HIFN_D_SRC_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      }
++      *srcp = dma->srci++;
++      dma->srck = dma->srci;
++
++      if (dma->dsti == HIFN_D_DST_RSIZE) {
++              dma->dsti = 0;
++              dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->dstr[HIFN_D_DST_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      }
++      *dstp = dma->dsti++;
++      dma->dstk = dma->dsti;
++
++      if (dma->resi == HIFN_D_RES_RSIZE) {
++              dma->resi = 0;
++              dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      }
++      *resp = dma->resi++;
++      dma->resk = dma->resi;
++}
++
++static int
++hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      hifn_base_command_t wc;
++      const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
++      int r, cmdi, resi, srci, dsti;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      wc.masks = htole16(3 << 13);
++      wc.session_num = htole16(addr >> 14);
++      wc.total_source_count = htole16(8);
++      wc.total_dest_count = htole16(addr & 0x3fff);
++
++      hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++          HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
++          HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
++
++      /* build write command */
++      bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
++      *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc;
++      bcopy(data, &dma->test_src, sizeof(dma->test_src));
++
++      dma->srcr[srci].p = htole32(sc->sc_dma_physaddr
++          + offsetof(struct hifn_dma, test_src));
++      dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr
++          + offsetof(struct hifn_dma, test_dst));
++
++      dma->cmdr[cmdi].l = htole32(16 | masks);
++      dma->srcr[srci].l = htole32(8 | masks);
++      dma->dstr[dsti].l = htole32(4 | masks);
++      dma->resr[resi].l = htole32(4 | masks);
++
++      for (r = 10000; r >= 0; r--) {
++              DELAY(10);
++              if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
++                      break;
++      }
++      if (r == 0) {
++              device_printf(sc->sc_dev, "writeramaddr -- "
++                  "result[%d](addr %d) still valid\n", resi, addr);
++              r = -1;
++              return (-1);
++      } else
++              r = 0;
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++          HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
++          HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
++
++      return (r);
++}
++
++static int
++hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      hifn_base_command_t rc;
++      const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
++      int r, cmdi, srci, dsti, resi;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      rc.masks = htole16(2 << 13);
++      rc.session_num = htole16(addr >> 14);
++      rc.total_source_count = htole16(addr & 0x3fff);
++      rc.total_dest_count = htole16(8);
++
++      hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++          HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
++          HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
++
++      bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
++      *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc;
++
++      dma->srcr[srci].p = htole32(sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, test_src));
++      dma->test_src = 0;
++      dma->dstr[dsti].p =  htole32(sc->sc_dma_physaddr +
++          offsetof(struct hifn_dma, test_dst));
++      dma->test_dst = 0;
++      dma->cmdr[cmdi].l = htole32(8 | masks);
++      dma->srcr[srci].l = htole32(8 | masks);
++      dma->dstr[dsti].l = htole32(8 | masks);
++      dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks);
++
++      for (r = 10000; r >= 0; r--) {
++              DELAY(10);
++              if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
++                      break;
++      }
++      if (r == 0) {
++              device_printf(sc->sc_dev, "readramaddr -- "
++                  "result[%d](addr %d) still valid\n", resi, addr);
++              r = -1;
++      } else {
++              r = 0;
++              bcopy(&dma->test_dst, data, sizeof(dma->test_dst));
++      }
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++          HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
++          HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
++
++      return (r);
++}
++
++/*
++ * Initialize the descriptor rings.
++ */
++static void 
++hifn_init_dma(struct hifn_softc *sc)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      hifn_set_retry(sc);
++
++      /* initialize static pointer values */
++      for (i = 0; i < HIFN_D_CMD_RSIZE; i++)
++              dma->cmdr[i].p = htole32(sc->sc_dma_physaddr +
++                  offsetof(struct hifn_dma, command_bufs[i][0]));
++      for (i = 0; i < HIFN_D_RES_RSIZE; i++)
++              dma->resr[i].p = htole32(sc->sc_dma_physaddr +
++                  offsetof(struct hifn_dma, result_bufs[i][0]));
++
++      dma->cmdr[HIFN_D_CMD_RSIZE].p =
++          htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0]));
++      dma->srcr[HIFN_D_SRC_RSIZE].p =
++          htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0]));
++      dma->dstr[HIFN_D_DST_RSIZE].p =
++          htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0]));
++      dma->resr[HIFN_D_RES_RSIZE].p =
++          htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0]));
++
++      dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
++      dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
++      dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
++}
++
++/*
++ * Writes out the raw command buffer space.  Returns the
++ * command buffer size.
++ */
++static u_int
++hifn_write_command(struct hifn_command *cmd, u_int8_t *buf)
++{
++      struct hifn_softc *sc = NULL;
++      u_int8_t *buf_pos;
++      hifn_base_command_t *base_cmd;
++      hifn_mac_command_t *mac_cmd;
++      hifn_crypt_command_t *cry_cmd;
++      int using_mac, using_crypt, len, ivlen;
++      u_int32_t dlen, slen;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      buf_pos = buf;
++      using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC;
++      using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT;
++
++      base_cmd = (hifn_base_command_t *)buf_pos;
++      base_cmd->masks = htole16(cmd->base_masks);
++      slen = cmd->src_mapsize;
++      if (cmd->sloplen)
++              dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t);
++      else
++              dlen = cmd->dst_mapsize;
++      base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO);
++      base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO);
++      dlen >>= 16;
++      slen >>= 16;
++      base_cmd->session_num = htole16(
++          ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
++          ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
++      buf_pos += sizeof(hifn_base_command_t);
++
++      if (using_mac) {
++              mac_cmd = (hifn_mac_command_t *)buf_pos;
++              dlen = cmd->maccrd->crd_len;
++              mac_cmd->source_count = htole16(dlen & 0xffff);
++              dlen >>= 16;
++              mac_cmd->masks = htole16(cmd->mac_masks |
++                  ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M));
++              mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip);
++              mac_cmd->reserved = 0;
++              buf_pos += sizeof(hifn_mac_command_t);
++      }
++
++      if (using_crypt) {
++              cry_cmd = (hifn_crypt_command_t *)buf_pos;
++              dlen = cmd->enccrd->crd_len;
++              cry_cmd->source_count = htole16(dlen & 0xffff);
++              dlen >>= 16;
++              cry_cmd->masks = htole16(cmd->cry_masks |
++                  ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M));
++              cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip);
++              cry_cmd->reserved = 0;
++              buf_pos += sizeof(hifn_crypt_command_t);
++      }
++
++      if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) {
++              bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH);
++              buf_pos += HIFN_MAC_KEY_LENGTH;
++      }
++
++      if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) {
++              switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) {
++              case HIFN_CRYPT_CMD_ALG_3DES:
++                      bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH);
++                      buf_pos += HIFN_3DES_KEY_LENGTH;
++                      break;
++              case HIFN_CRYPT_CMD_ALG_DES:
++                      bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH);
++                      buf_pos += HIFN_DES_KEY_LENGTH;
++                      break;
++              case HIFN_CRYPT_CMD_ALG_RC4:
++                      len = 256;
++                      do {
++                              int clen;
++
++                              clen = MIN(cmd->cklen, len);
++                              bcopy(cmd->ck, buf_pos, clen);
++                              len -= clen;
++                              buf_pos += clen;
++                      } while (len > 0);
++                      bzero(buf_pos, 4);
++                      buf_pos += 4;
++                      break;
++              case HIFN_CRYPT_CMD_ALG_AES:
++                      /*
++                       * AES keys are variable 128, 192 and
++                       * 256 bits (16, 24 and 32 bytes).
++                       */
++                      bcopy(cmd->ck, buf_pos, cmd->cklen);
++                      buf_pos += cmd->cklen;
++                      break;
++              }
++      }
++
++      if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) {
++              switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) {
++              case HIFN_CRYPT_CMD_ALG_AES:
++                      ivlen = HIFN_AES_IV_LENGTH;
++                      break;
++              default:
++                      ivlen = HIFN_IV_LENGTH;
++                      break;
++              }
++              bcopy(cmd->iv, buf_pos, ivlen);
++              buf_pos += ivlen;
++      }
++
++      if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) {
++              bzero(buf_pos, 8);
++              buf_pos += 8;
++      }
++
++      return (buf_pos - buf);
++}
++
++static int
++hifn_dmamap_aligned(struct hifn_operand *op)
++{
++      struct hifn_softc *sc = NULL;
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      for (i = 0; i < op->nsegs; i++) {
++              if (op->segs[i].ds_addr & 3)
++                      return (0);
++              if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3))
++                      return (0);
++      }
++      return (1);
++}
++
++static __inline int
++hifn_dmamap_dstwrap(struct hifn_softc *sc, int idx)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++
++      if (++idx == HIFN_D_DST_RSIZE) {
++              dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP |
++                  HIFN_D_MASKDONEIRQ);
++              HIFN_DSTR_SYNC(sc, idx,
++                  BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++              idx = 0;
++      }
++      return (idx);
++}
++
++static int
++hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      struct hifn_operand *dst = &cmd->dst;
++      u_int32_t p, l;
++      int idx, used = 0, i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      idx = dma->dsti;
++      for (i = 0; i < dst->nsegs - 1; i++) {
++              dma->dstr[idx].p = htole32(dst->segs[i].ds_addr);
++              dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len);
++              wmb();
++              dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++              HIFN_DSTR_SYNC(sc, idx,
++                  BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++              used++;
++
++              idx = hifn_dmamap_dstwrap(sc, idx);
++      }
++
++      if (cmd->sloplen == 0) {
++              p = dst->segs[i].ds_addr;
++              l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
++                  dst->segs[i].ds_len;
++      } else {
++              p = sc->sc_dma_physaddr +
++                  offsetof(struct hifn_dma, slop[cmd->slopidx]);
++              l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
++                  sizeof(u_int32_t);
++
++              if ((dst->segs[i].ds_len - cmd->sloplen) != 0) {
++                      dma->dstr[idx].p = htole32(dst->segs[i].ds_addr);
++                      dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ |
++                          (dst->segs[i].ds_len - cmd->sloplen));
++                      wmb();
++                      dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++                      HIFN_DSTR_SYNC(sc, idx,
++                          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++                      used++;
++
++                      idx = hifn_dmamap_dstwrap(sc, idx);
++              }
++      }
++      dma->dstr[idx].p = htole32(p);
++      dma->dstr[idx].l = htole32(l);
++      wmb();
++      dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++      HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++      used++;
++
++      idx = hifn_dmamap_dstwrap(sc, idx);
++
++      dma->dsti = idx;
++      dma->dstu += used;
++      return (idx);
++}
++
++static __inline int
++hifn_dmamap_srcwrap(struct hifn_softc *sc, int idx)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++
++      if (++idx == HIFN_D_SRC_RSIZE) {
++              dma->srcr[idx].l = htole32(HIFN_D_VALID |
++                  HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
++              HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++              idx = 0;
++      }
++      return (idx);
++}
++
++static int
++hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      struct hifn_operand *src = &cmd->src;
++      int idx, i;
++      u_int32_t last = 0;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      idx = dma->srci;
++      for (i = 0; i < src->nsegs; i++) {
++              if (i == src->nsegs - 1)
++                      last = HIFN_D_LAST;
++
++              dma->srcr[idx].p = htole32(src->segs[i].ds_addr);
++              dma->srcr[idx].l = htole32(src->segs[i].ds_len |
++                  HIFN_D_MASKDONEIRQ | last);
++              wmb();
++              dma->srcr[idx].l |= htole32(HIFN_D_VALID);
++              HIFN_SRCR_SYNC(sc, idx,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++
++              idx = hifn_dmamap_srcwrap(sc, idx);
++      }
++      dma->srci = idx;
++      dma->srcu += src->nsegs;
++      return (idx);
++} 
++
++
++static int 
++hifn_crypto(
++      struct hifn_softc *sc,
++      struct hifn_command *cmd,
++      struct cryptop *crp,
++      int hint)
++{
++      struct  hifn_dma *dma = sc->sc_dma;
++      u_int32_t cmdlen, csr;
++      int cmdi, resi, err = 0;
++      unsigned long l_flags;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /*
++       * need 1 cmd, and 1 res
++       *
++       * NB: check this first since it's easy.
++       */
++      HIFN_LOCK(sc);
++      if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
++          (dma->resu + 1) > HIFN_D_RES_RSIZE) {
++#ifdef HIFN_DEBUG
++              if (hifn_debug) {
++                      device_printf(sc->sc_dev,
++                              "cmd/result exhaustion, cmdu %u resu %u\n",
++                              dma->cmdu, dma->resu);
++              }
++#endif
++              hifnstats.hst_nomem_cr++;
++              sc->sc_needwakeup |= CRYPTO_SYMQ;
++              HIFN_UNLOCK(sc);
++              return (ERESTART);
++      }
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              if (pci_map_skb(sc, &cmd->src, cmd->src_skb)) {
++                      hifnstats.hst_nomem_load++;
++                      err = ENOMEM;
++                      goto err_srcmap1;
++              }
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              if (pci_map_uio(sc, &cmd->src, cmd->src_io)) {
++                      hifnstats.hst_nomem_load++;
++                      err = ENOMEM;
++                      goto err_srcmap1;
++              }
++      } else {
++              if (pci_map_buf(sc, &cmd->src, cmd->src_buf, crp->crp_ilen)) {
++                      hifnstats.hst_nomem_load++;
++                      err = ENOMEM;
++                      goto err_srcmap1;
++              }
++      }
++
++      if (hifn_dmamap_aligned(&cmd->src)) {
++              cmd->sloplen = cmd->src_mapsize & 3;
++              cmd->dst = cmd->src;
++      } else {
++              if (crp->crp_flags & CRYPTO_F_IOV) {
++                      DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                      err = EINVAL;
++                      goto err_srcmap;
++              } else if (crp->crp_flags & CRYPTO_F_SKBUF) {
++#ifdef NOTYET
++                      int totlen, len;
++                      struct mbuf *m, *m0, *mlast;
++
++                      KASSERT(cmd->dst_m == cmd->src_m,
++                              ("hifn_crypto: dst_m initialized improperly"));
++                      hifnstats.hst_unaligned++;
++                      /*
++                       * Source is not aligned on a longword boundary.
++                       * Copy the data to insure alignment.  If we fail
++                       * to allocate mbufs or clusters while doing this
++                       * we return ERESTART so the operation is requeued
++                       * at the crypto later, but only if there are
++                       * ops already posted to the hardware; otherwise we
++                       * have no guarantee that we'll be re-entered.
++                       */
++                      totlen = cmd->src_mapsize;
++                      if (cmd->src_m->m_flags & M_PKTHDR) {
++                              len = MHLEN;
++                              MGETHDR(m0, M_DONTWAIT, MT_DATA);
++                              if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) {
++                                      m_free(m0);
++                                      m0 = NULL;
++                              }
++                      } else {
++                              len = MLEN;
++                              MGET(m0, M_DONTWAIT, MT_DATA);
++                      }
++                      if (m0 == NULL) {
++                              hifnstats.hst_nomem_mbuf++;
++                              err = dma->cmdu ? ERESTART : ENOMEM;
++                              goto err_srcmap;
++                      }
++                      if (totlen >= MINCLSIZE) {
++                              MCLGET(m0, M_DONTWAIT);
++                              if ((m0->m_flags & M_EXT) == 0) {
++                                      hifnstats.hst_nomem_mcl++;
++                                      err = dma->cmdu ? ERESTART : ENOMEM;
++                                      m_freem(m0);
++                                      goto err_srcmap;
++                              }
++                              len = MCLBYTES;
++                      }
++                      totlen -= len;
++                      m0->m_pkthdr.len = m0->m_len = len;
++                      mlast = m0;
++
++                      while (totlen > 0) {
++                              MGET(m, M_DONTWAIT, MT_DATA);
++                              if (m == NULL) {
++                                      hifnstats.hst_nomem_mbuf++;
++                                      err = dma->cmdu ? ERESTART : ENOMEM;
++                                      m_freem(m0);
++                                      goto err_srcmap;
++                              }
++                              len = MLEN;
++                              if (totlen >= MINCLSIZE) {
++                                      MCLGET(m, M_DONTWAIT);
++                                      if ((m->m_flags & M_EXT) == 0) {
++                                              hifnstats.hst_nomem_mcl++;
++                                              err = dma->cmdu ? ERESTART : ENOMEM;
++                                              mlast->m_next = m;
++                                              m_freem(m0);
++                                              goto err_srcmap;
++                                      }
++                                      len = MCLBYTES;
++                              }
++
++                              m->m_len = len;
++                              m0->m_pkthdr.len += len;
++                              totlen -= len;
++
++                              mlast->m_next = m;
++                              mlast = m;
++                      }
++                      cmd->dst_m = m0;
++#else
++                      device_printf(sc->sc_dev,
++                                      "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n",
++                                      __FILE__, __LINE__);
++                      err = EINVAL;
++                      goto err_srcmap;
++#endif
++              } else {
++                      device_printf(sc->sc_dev,
++                                      "%s,%d: unaligned contig buffers not implemented\n",
++                                      __FILE__, __LINE__);
++                      err = EINVAL;
++                      goto err_srcmap;
++              }
++      }
++
++      if (cmd->dst_map == NULL) {
++              if (crp->crp_flags & CRYPTO_F_SKBUF) {
++                      if (pci_map_skb(sc, &cmd->dst, cmd->dst_skb)) {
++                              hifnstats.hst_nomem_map++;
++                              err = ENOMEM;
++                              goto err_dstmap1;
++                      }
++              } else if (crp->crp_flags & CRYPTO_F_IOV) {
++                      if (pci_map_uio(sc, &cmd->dst, cmd->dst_io)) {
++                              hifnstats.hst_nomem_load++;
++                              err = ENOMEM;
++                              goto err_dstmap1;
++                      }
++              } else {
++                      if (pci_map_buf(sc, &cmd->dst, cmd->dst_buf, crp->crp_ilen)) {
++                              hifnstats.hst_nomem_load++;
++                              err = ENOMEM;
++                              goto err_dstmap1;
++                      }
++              }
++      }
++
++#ifdef HIFN_DEBUG
++      if (hifn_debug) {
++              device_printf(sc->sc_dev,
++                  "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n",
++                  READ_REG_1(sc, HIFN_1_DMA_CSR),
++                  READ_REG_1(sc, HIFN_1_DMA_IER),
++                  dma->cmdu, dma->srcu, dma->dstu, dma->resu,
++                  cmd->src_nsegs, cmd->dst_nsegs);
++      }
++#endif
++
++#if 0
++      if (cmd->src_map == cmd->dst_map) {
++              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                  BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
++      } else {
++              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                  BUS_DMASYNC_PREWRITE);
++              bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++                  BUS_DMASYNC_PREREAD);
++      }
++#endif
++
++      /*
++       * need N src, and N dst
++       */
++      if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE ||
++          (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) {
++#ifdef HIFN_DEBUG
++              if (hifn_debug) {
++                      device_printf(sc->sc_dev,
++                              "src/dst exhaustion, srcu %u+%u dstu %u+%u\n",
++                              dma->srcu, cmd->src_nsegs,
++                              dma->dstu, cmd->dst_nsegs);
++              }
++#endif
++              hifnstats.hst_nomem_sd++;
++              err = ERESTART;
++              goto err_dstmap;
++      }
++
++      if (dma->cmdi == HIFN_D_CMD_RSIZE) {
++              dma->cmdi = 0;
++              dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
++                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      }
++      cmdi = dma->cmdi++;
++      cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]);
++      HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE);
++
++      /* .p for command/result already set */
++      dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_LAST |
++          HIFN_D_MASKDONEIRQ);
++      wmb();
++      dma->cmdr[cmdi].l |= htole32(HIFN_D_VALID);
++      HIFN_CMDR_SYNC(sc, cmdi,
++          BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++      dma->cmdu++;
++
++      /*
++       * We don't worry about missing an interrupt (which a "command wait"
++       * interrupt salvages us from), unless there is more than one command
++       * in the queue.
++       */
++      if (dma->cmdu > 1) {
++              sc->sc_dmaier |= HIFN_DMAIER_C_WAIT;
++              WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++      }
++
++      hifnstats.hst_ipackets++;
++      hifnstats.hst_ibytes += cmd->src_mapsize;
++
++      hifn_dmamap_load_src(sc, cmd);
++
++      /*
++       * Unlike other descriptors, we don't mask done interrupt from
++       * result descriptor.
++       */
++#ifdef HIFN_DEBUG
++      if (hifn_debug)
++              device_printf(sc->sc_dev, "load res\n");
++#endif
++      if (dma->resi == HIFN_D_RES_RSIZE) {
++              dma->resi = 0;
++              dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID);
++              HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
++                  BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++      }
++      resi = dma->resi++;
++      KASSERT(dma->hifn_commands[resi] == NULL,
++              ("hifn_crypto: command slot %u busy", resi));
++      dma->hifn_commands[resi] = cmd;
++      HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD);
++      if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) {
++              dma->resr[resi].l = htole32(HIFN_MAX_RESULT |
++                  HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
++              wmb();
++              dma->resr[resi].l |= htole32(HIFN_D_VALID);
++              sc->sc_curbatch++;
++              if (sc->sc_curbatch > hifnstats.hst_maxbatch)
++                      hifnstats.hst_maxbatch = sc->sc_curbatch;
++              hifnstats.hst_totbatch++;
++      } else {
++              dma->resr[resi].l = htole32(HIFN_MAX_RESULT | HIFN_D_LAST);
++              wmb();
++              dma->resr[resi].l |= htole32(HIFN_D_VALID);
++              sc->sc_curbatch = 0;
++      }
++      HIFN_RESR_SYNC(sc, resi,
++          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++      dma->resu++;
++
++      if (cmd->sloplen)
++              cmd->slopidx = resi;
++
++      hifn_dmamap_load_dst(sc, cmd);
++
++      csr = 0;
++      if (sc->sc_c_busy == 0) {
++              csr |= HIFN_DMACSR_C_CTRL_ENA;
++              sc->sc_c_busy = 1;
++      }
++      if (sc->sc_s_busy == 0) {
++              csr |= HIFN_DMACSR_S_CTRL_ENA;
++              sc->sc_s_busy = 1;
++      }
++      if (sc->sc_r_busy == 0) {
++              csr |= HIFN_DMACSR_R_CTRL_ENA;
++              sc->sc_r_busy = 1;
++      }
++      if (sc->sc_d_busy == 0) {
++              csr |= HIFN_DMACSR_D_CTRL_ENA;
++              sc->sc_d_busy = 1;
++      }
++      if (csr)
++              WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr);
++
++#ifdef HIFN_DEBUG
++      if (hifn_debug) {
++              device_printf(sc->sc_dev, "command: stat %8x ier %8x\n",
++                  READ_REG_1(sc, HIFN_1_DMA_CSR),
++                  READ_REG_1(sc, HIFN_1_DMA_IER));
++      }
++#endif
++
++      sc->sc_active = 5;
++      HIFN_UNLOCK(sc);
++      KASSERT(err == 0, ("hifn_crypto: success with error %u", err));
++      return (err);           /* success */
++
++err_dstmap:
++      if (cmd->src_map != cmd->dst_map)
++              pci_unmap_buf(sc, &cmd->dst);
++err_dstmap1:
++err_srcmap:
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              if (cmd->src_skb != cmd->dst_skb)
++#ifdef NOTYET
++                      m_freem(cmd->dst_m);
++#else
++                      device_printf(sc->sc_dev,
++                                      "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++                                      __FILE__, __LINE__);
++#endif
++      }
++      pci_unmap_buf(sc, &cmd->src);
++err_srcmap1:
++      HIFN_UNLOCK(sc);
++      return (err);
++}
++
++static void
++hifn_tick(unsigned long arg)
++{
++      struct hifn_softc *sc;
++      unsigned long l_flags;
++
++      if (arg >= HIFN_MAX_CHIPS)
++              return;
++      sc = hifn_chip_idx[arg];
++      if (!sc)
++              return;
++
++      HIFN_LOCK(sc);
++      if (sc->sc_active == 0) {
++              struct hifn_dma *dma = sc->sc_dma;
++              u_int32_t r = 0;
++
++              if (dma->cmdu == 0 && sc->sc_c_busy) {
++                      sc->sc_c_busy = 0;
++                      r |= HIFN_DMACSR_C_CTRL_DIS;
++              }
++              if (dma->srcu == 0 && sc->sc_s_busy) {
++                      sc->sc_s_busy = 0;
++                      r |= HIFN_DMACSR_S_CTRL_DIS;
++              }
++              if (dma->dstu == 0 && sc->sc_d_busy) {
++                      sc->sc_d_busy = 0;
++                      r |= HIFN_DMACSR_D_CTRL_DIS;
++              }
++              if (dma->resu == 0 && sc->sc_r_busy) {
++                      sc->sc_r_busy = 0;
++                      r |= HIFN_DMACSR_R_CTRL_DIS;
++              }
++              if (r)
++                      WRITE_REG_1(sc, HIFN_1_DMA_CSR, r);
++      } else
++              sc->sc_active--;
++      HIFN_UNLOCK(sc);
++      mod_timer(&sc->sc_tickto, jiffies + HZ);
++}
++
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++hifn_intr(int irq, void *arg)
++#else
++hifn_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++      struct hifn_softc *sc = arg;
++      struct hifn_dma *dma;
++      u_int32_t dmacsr, restart;
++      int i, u;
++      unsigned long l_flags;
++
++      dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR);
++
++      /* Nothing in the DMA unit interrupted */
++      if ((dmacsr & sc->sc_dmaier) == 0)
++              return IRQ_NONE;
++
++      HIFN_LOCK(sc);
++
++      dma = sc->sc_dma;
++
++#ifdef HIFN_DEBUG
++      if (hifn_debug) {
++              device_printf(sc->sc_dev,
++                  "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n",
++                  dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier,
++                  dma->cmdi, dma->srci, dma->dsti, dma->resi,
++                  dma->cmdk, dma->srck, dma->dstk, dma->resk,
++                  dma->cmdu, dma->srcu, dma->dstu, dma->resu);
++      }
++#endif
++
++      WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier);
++
++      if ((sc->sc_flags & HIFN_HAS_PUBLIC) &&
++          (dmacsr & HIFN_DMACSR_PUBDONE))
++              WRITE_REG_1(sc, HIFN_1_PUB_STATUS,
++                  READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
++
++      restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER);
++      if (restart)
++              device_printf(sc->sc_dev, "overrun %x\n", dmacsr);
++
++      if (sc->sc_flags & HIFN_IS_7811) {
++              if (dmacsr & HIFN_DMACSR_ILLR)
++                      device_printf(sc->sc_dev, "illegal read\n");
++              if (dmacsr & HIFN_DMACSR_ILLW)
++                      device_printf(sc->sc_dev, "illegal write\n");
++      }
++
++      restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
++          HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
++      if (restart) {
++              device_printf(sc->sc_dev, "abort, resetting.\n");
++              hifnstats.hst_abort++;
++              hifn_abort(sc);
++              HIFN_UNLOCK(sc);
++              return IRQ_HANDLED;
++      }
++
++      if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) {
++              /*
++               * If no slots to process and we receive a "waiting on
++               * command" interrupt, we disable the "waiting on command"
++               * (by clearing it).
++               */
++              sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
++              WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++      }
++
++      /* clear the rings */
++      i = dma->resk; u = dma->resu;
++      while (u != 0) {
++              HIFN_RESR_SYNC(sc, i,
++                  BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++              if (dma->resr[i].l & htole32(HIFN_D_VALID)) {
++                      HIFN_RESR_SYNC(sc, i,
++                          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++                      break;
++              }
++
++              if (i != HIFN_D_RES_RSIZE) {
++                      struct hifn_command *cmd;
++                      u_int8_t *macbuf = NULL;
++
++                      HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD);
++                      cmd = dma->hifn_commands[i];
++                      KASSERT(cmd != NULL,
++                              ("hifn_intr: null command slot %u", i));
++                      dma->hifn_commands[i] = NULL;
++
++                      if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
++                              macbuf = dma->result_bufs[i];
++                              macbuf += 12;
++                      }
++
++                      hifn_callback(sc, cmd, macbuf);
++                      hifnstats.hst_opackets++;
++                      u--;
++              }
++
++              if (++i == (HIFN_D_RES_RSIZE + 1))
++                      i = 0;
++      }
++      dma->resk = i; dma->resu = u;
++
++      i = dma->srck; u = dma->srcu;
++      while (u != 0) {
++              if (i == HIFN_D_SRC_RSIZE)
++                      i = 0;
++              HIFN_SRCR_SYNC(sc, i,
++                  BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++              if (dma->srcr[i].l & htole32(HIFN_D_VALID)) {
++                      HIFN_SRCR_SYNC(sc, i,
++                          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++                      break;
++              }
++              i++, u--;
++      }
++      dma->srck = i; dma->srcu = u;
++
++      i = dma->cmdk; u = dma->cmdu;
++      while (u != 0) {
++              HIFN_CMDR_SYNC(sc, i,
++                  BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++              if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) {
++                      HIFN_CMDR_SYNC(sc, i,
++                          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++                      break;
++              }
++              if (i != HIFN_D_CMD_RSIZE) {
++                      u--;
++                      HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE);
++              }
++              if (++i == (HIFN_D_CMD_RSIZE + 1))
++                      i = 0;
++      }
++      dma->cmdk = i; dma->cmdu = u;
++
++      HIFN_UNLOCK(sc);
++
++      if (sc->sc_needwakeup) {                /* XXX check high watermark */
++              int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);
++#ifdef HIFN_DEBUG
++              if (hifn_debug)
++                      device_printf(sc->sc_dev,
++                              "wakeup crypto (%x) u %d/%d/%d/%d\n",
++                              sc->sc_needwakeup,
++                              dma->cmdu, dma->srcu, dma->dstu, dma->resu);
++#endif
++              sc->sc_needwakeup &= ~wakeup;
++              crypto_unblock(sc->sc_cid, wakeup);
++      }
++
++      return IRQ_HANDLED;
++}
++
++/*
++ * Allocate a new 'session' and return an encoded session id.  'sidp'
++ * contains our registration id, and should contain an encoded session
++ * id on successful allocation.
++ */
++static int
++hifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++      struct hifn_softc *sc = device_get_softc(dev);
++      struct cryptoini *c;
++      int mac = 0, cry = 0, sesn;
++      struct hifn_session *ses = NULL;
++      unsigned long l_flags;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      KASSERT(sc != NULL, ("hifn_newsession: null softc"));
++      if (sidp == NULL || cri == NULL || sc == NULL) {
++              DPRINTF("%s,%d: %s - EINVAL\n", __FILE__, __LINE__, __FUNCTION__);
++              return (EINVAL);
++      }
++
++      HIFN_LOCK(sc);
++      if (sc->sc_sessions == NULL) {
++              ses = sc->sc_sessions = (struct hifn_session *)kmalloc(sizeof(*ses),
++                              SLAB_ATOMIC);
++              if (ses == NULL) {
++                      HIFN_UNLOCK(sc);
++                      return (ENOMEM);
++              }
++              sesn = 0;
++              sc->sc_nsessions = 1;
++      } else {
++              for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++                      if (!sc->sc_sessions[sesn].hs_used) {
++                              ses = &sc->sc_sessions[sesn];
++                              break;
++                      }
++              }
++
++              if (ses == NULL) {
++                      sesn = sc->sc_nsessions;
++                      ses = (struct hifn_session *)kmalloc((sesn + 1) * sizeof(*ses),
++                                      SLAB_ATOMIC);
++                      if (ses == NULL) {
++                              HIFN_UNLOCK(sc);
++                              return (ENOMEM);
++                      }
++                      bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
++                      bzero(sc->sc_sessions, sesn * sizeof(*ses));
++                      kfree(sc->sc_sessions);
++                      sc->sc_sessions = ses;
++                      ses = &sc->sc_sessions[sesn];
++                      sc->sc_nsessions++;
++              }
++      }
++      HIFN_UNLOCK(sc);
++
++      bzero(ses, sizeof(*ses));
++      ses->hs_used = 1;
++
++      for (c = cri; c != NULL; c = c->cri_next) {
++              switch (c->cri_alg) {
++              case CRYPTO_MD5:
++              case CRYPTO_SHA1:
++              case CRYPTO_MD5_HMAC:
++              case CRYPTO_SHA1_HMAC:
++                      if (mac) {
++                              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                              return (EINVAL);
++                      }
++                      mac = 1;
++                      ses->hs_mlen = c->cri_mlen;
++                      if (ses->hs_mlen == 0) {
++                              switch (c->cri_alg) {
++                              case CRYPTO_MD5:
++                              case CRYPTO_MD5_HMAC:
++                                      ses->hs_mlen = 16;
++                                      break;
++                              case CRYPTO_SHA1:
++                              case CRYPTO_SHA1_HMAC:
++                                      ses->hs_mlen = 20;
++                                      break;
++                              }
++                      }
++                      break;
++              case CRYPTO_DES_CBC:
++              case CRYPTO_3DES_CBC:
++              case CRYPTO_AES_CBC:
++                      /* XXX this may read fewer, does it matter? */
++                      read_random(ses->hs_iv,
++                              c->cri_alg == CRYPTO_AES_CBC ?
++                                      HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++                      /*FALLTHROUGH*/
++              case CRYPTO_ARC4:
++                      if (cry) {
++                              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                              return (EINVAL);
++                      }
++                      cry = 1;
++                      break;
++              default:
++                      DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                      return (EINVAL);
++              }
++      }
++      if (mac == 0 && cry == 0) {
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              return (EINVAL);
++      }
++
++      *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn);
++
++      return (0);
++}
++
++/*
++ * Deallocate a session.
++ * XXX this routine should run a zero'd mac/encrypt key into context ram.
++ * XXX to blow away any keys already stored there.
++ */
++static int
++hifn_freesession(device_t dev, u_int64_t tid)
++{
++      struct hifn_softc *sc = device_get_softc(dev);
++      int session, error;
++      u_int32_t sid = CRYPTO_SESID2LID(tid);
++      unsigned long l_flags;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      KASSERT(sc != NULL, ("hifn_freesession: null softc"));
++      if (sc == NULL) {
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              return (EINVAL);
++      }
++
++      HIFN_LOCK(sc);
++      session = HIFN_SESSION(sid);
++      if (session < sc->sc_nsessions) {
++              bzero(&sc->sc_sessions[session], sizeof(struct hifn_session));
++              error = 0;
++      } else {
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              error = EINVAL;
++      }
++      HIFN_UNLOCK(sc);
++
++      return (error);
++}
++
++static int
++hifn_process(device_t dev, struct cryptop *crp, int hint)
++{
++      struct hifn_softc *sc = device_get_softc(dev);
++      struct hifn_command *cmd = NULL;
++      int session, err, ivlen;
++      struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (crp == NULL || crp->crp_callback == NULL) {
++              hifnstats.hst_invalid++;
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              return (EINVAL);
++      }
++      session = HIFN_SESSION(crp->crp_sid);
++
++      if (sc == NULL || session >= sc->sc_nsessions) {
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              err = EINVAL;
++              goto errout;
++      }
++
++      cmd = kmalloc(sizeof(struct hifn_command), SLAB_ATOMIC);
++      if (cmd == NULL) {
++              hifnstats.hst_nomem++;
++              err = ENOMEM;
++              goto errout;
++      }
++      memset(cmd, 0, sizeof(*cmd));
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              cmd->src_skb = (struct sk_buff *)crp->crp_buf;
++              cmd->dst_skb = (struct sk_buff *)crp->crp_buf;
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              cmd->src_io = (struct uio *)crp->crp_buf;
++              cmd->dst_io = (struct uio *)crp->crp_buf;
++      } else {
++              cmd->src_buf = crp->crp_buf;
++              cmd->dst_buf = crp->crp_buf;
++      }
++
++      crd1 = crp->crp_desc;
++      if (crd1 == NULL) {
++              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++              err = EINVAL;
++              goto errout;
++      }
++      crd2 = crd1->crd_next;
++
++      if (crd2 == NULL) {
++              if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1 ||
++                  crd1->crd_alg == CRYPTO_MD5) {
++                      maccrd = crd1;
++                      enccrd = NULL;
++              } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++                  crd1->crd_alg == CRYPTO_3DES_CBC ||
++                  crd1->crd_alg == CRYPTO_AES_CBC ||
++                  crd1->crd_alg == CRYPTO_ARC4) {
++                      if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0)
++                              cmd->base_masks |= HIFN_BASE_CMD_DECODE;
++                      maccrd = NULL;
++                      enccrd = crd1;
++              } else {
++                      DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                      err = EINVAL;
++                      goto errout;
++              }
++      } else {
++              if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                     crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                     crd1->crd_alg == CRYPTO_MD5 ||
++                     crd1->crd_alg == CRYPTO_SHA1) &&
++                  (crd2->crd_alg == CRYPTO_DES_CBC ||
++                   crd2->crd_alg == CRYPTO_3DES_CBC ||
++                   crd2->crd_alg == CRYPTO_AES_CBC ||
++                   crd2->crd_alg == CRYPTO_ARC4) &&
++                  ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++                      cmd->base_masks = HIFN_BASE_CMD_DECODE;
++                      maccrd = crd1;
++                      enccrd = crd2;
++              } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++                   crd1->crd_alg == CRYPTO_ARC4 ||
++                   crd1->crd_alg == CRYPTO_3DES_CBC ||
++                   crd1->crd_alg == CRYPTO_AES_CBC) &&
++                  (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++                     crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++                     crd2->crd_alg == CRYPTO_MD5 ||
++                     crd2->crd_alg == CRYPTO_SHA1) &&
++                  (crd1->crd_flags & CRD_F_ENCRYPT)) {
++                      enccrd = crd1;
++                      maccrd = crd2;
++              } else {
++                      /*
++                       * We cannot order the 7751 as requested
++                       */
++                      DPRINTF("%s,%d: %s %d,%d,%d - EINVAL\n",__FILE__,__LINE__,__FUNCTION__, crd1->crd_alg, crd2->crd_alg, crd1->crd_flags & CRD_F_ENCRYPT);
++                      err = EINVAL;
++                      goto errout;
++              }
++      }
++
++      if (enccrd) {
++              cmd->enccrd = enccrd;
++              cmd->base_masks |= HIFN_BASE_CMD_CRYPT;
++              switch (enccrd->crd_alg) {
++              case CRYPTO_ARC4:
++                      cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4;
++                      break;
++              case CRYPTO_DES_CBC:
++                      cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES |
++                          HIFN_CRYPT_CMD_MODE_CBC |
++                          HIFN_CRYPT_CMD_NEW_IV;
++                      break;
++              case CRYPTO_3DES_CBC:
++                      cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES |
++                          HIFN_CRYPT_CMD_MODE_CBC |
++                          HIFN_CRYPT_CMD_NEW_IV;
++                      break;
++              case CRYPTO_AES_CBC:
++                      cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES |
++                          HIFN_CRYPT_CMD_MODE_CBC |
++                          HIFN_CRYPT_CMD_NEW_IV;
++                      break;
++              default:
++                      DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                      err = EINVAL;
++                      goto errout;
++              }
++              if (enccrd->crd_alg != CRYPTO_ARC4) {
++                      ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ?
++                              HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++                      if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++                              if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                                      bcopy(enccrd->crd_iv, cmd->iv, ivlen);
++                              else
++                                      bcopy(sc->sc_sessions[session].hs_iv,
++                                          cmd->iv, ivlen);
++
++                              if ((enccrd->crd_flags & CRD_F_IV_PRESENT)
++                                  == 0) {
++                                      crypto_copyback(crp->crp_flags,
++                                          crp->crp_buf, enccrd->crd_inject,
++                                          ivlen, cmd->iv);
++                              }
++                      } else {
++                              if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                                      bcopy(enccrd->crd_iv, cmd->iv, ivlen);
++                              else {
++                                      crypto_copydata(crp->crp_flags,
++                                          crp->crp_buf, enccrd->crd_inject,
++                                          ivlen, cmd->iv);
++                              }
++                      }
++              }
++
++              if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT)
++                      cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
++              cmd->ck = enccrd->crd_key;
++              cmd->cklen = enccrd->crd_klen >> 3;
++              cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
++
++              /* 
++               * Need to specify the size for the AES key in the masks.
++               */
++              if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) ==
++                  HIFN_CRYPT_CMD_ALG_AES) {
++                      switch (cmd->cklen) {
++                      case 16:
++                              cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128;
++                              break;
++                      case 24:
++                              cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192;
++                              break;
++                      case 32:
++                              cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256;
++                              break;
++                      default:
++                              DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++                              err = EINVAL;
++                              goto errout;
++                      }
++              }
++      }
++
++      if (maccrd) {
++              cmd->maccrd = maccrd;
++              cmd->base_masks |= HIFN_BASE_CMD_MAC;
++
++              switch (maccrd->crd_alg) {
++              case CRYPTO_MD5:
++                      cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 |
++                          HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH |
++                          HIFN_MAC_CMD_POS_IPSEC;
++                       break;
++              case CRYPTO_MD5_HMAC:
++                      cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 |
++                          HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
++                          HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
++                      break;
++              case CRYPTO_SHA1:
++                      cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 |
++                          HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH |
++                          HIFN_MAC_CMD_POS_IPSEC;
++                      break;
++              case CRYPTO_SHA1_HMAC:
++                      cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 |
++                          HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
++                          HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
++                      break;
++              }
++
++              if (maccrd->crd_alg == CRYPTO_SHA1_HMAC ||
++                   maccrd->crd_alg == CRYPTO_MD5_HMAC) {
++                      cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY;
++                      bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3);
++                      bzero(cmd->mac + (maccrd->crd_klen >> 3),
++                          HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3));
++              }
++      }
++
++      cmd->crp = crp;
++      cmd->session_num = session;
++      cmd->softc = sc;
++
++      err = hifn_crypto(sc, cmd, crp, hint);
++      if (!err) {
++              return 0;
++      } else if (err == ERESTART) {
++              /*
++               * There weren't enough resources to dispatch the request
++               * to the part.  Notify the caller so they'll requeue this
++               * request and resubmit it again soon.
++               */
++#ifdef HIFN_DEBUG
++              if (hifn_debug)
++                      device_printf(sc->sc_dev, "requeue request\n");
++#endif
++              kfree(cmd);
++              sc->sc_needwakeup |= CRYPTO_SYMQ;
++              return (err);
++      }
++
++errout:
++      if (cmd != NULL)
++              kfree(cmd);
++      if (err == EINVAL)
++              hifnstats.hst_invalid++;
++      else
++              hifnstats.hst_nomem++;
++      crp->crp_etype = err;
++      crypto_done(crp);
++      return (err);
++}
++
++static void
++hifn_abort(struct hifn_softc *sc)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      struct hifn_command *cmd;
++      struct cryptop *crp;
++      int i, u;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      i = dma->resk; u = dma->resu;
++      while (u != 0) {
++              cmd = dma->hifn_commands[i];
++              KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i));
++              dma->hifn_commands[i] = NULL;
++              crp = cmd->crp;
++
++              if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) {
++                      /* Salvage what we can. */
++                      u_int8_t *macbuf;
++
++                      if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
++                              macbuf = dma->result_bufs[i];
++                              macbuf += 12;
++                      } else
++                              macbuf = NULL;
++                      hifnstats.hst_opackets++;
++                      hifn_callback(sc, cmd, macbuf);
++              } else {
++#if 0
++                      if (cmd->src_map == cmd->dst_map) {
++                              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                                  BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
++                      } else {
++                              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                                  BUS_DMASYNC_POSTWRITE);
++                              bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++                                  BUS_DMASYNC_POSTREAD);
++                      }
++#endif
++
++                      if (cmd->src_skb != cmd->dst_skb) {
++#ifdef NOTYET
++                              m_freem(cmd->src_m);
++                              crp->crp_buf = (caddr_t)cmd->dst_m;
++#else
++                              device_printf(sc->sc_dev,
++                                              "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++                                              __FILE__, __LINE__);
++#endif
++                      }
++
++                      /* non-shared buffers cannot be restarted */
++                      if (cmd->src_map != cmd->dst_map) {
++                              /*
++                               * XXX should be EAGAIN, delayed until
++                               * after the reset.
++                               */
++                              crp->crp_etype = ENOMEM;
++                              pci_unmap_buf(sc, &cmd->dst);
++                      } else
++                              crp->crp_etype = ENOMEM;
++
++                      pci_unmap_buf(sc, &cmd->src);
++
++                      kfree(cmd);
++                      if (crp->crp_etype != EAGAIN)
++                              crypto_done(crp);
++              }
++
++              if (++i == HIFN_D_RES_RSIZE)
++                      i = 0;
++              u--;
++      }
++      dma->resk = i; dma->resu = u;
++
++      hifn_reset_board(sc, 1);
++      hifn_init_dma(sc);
++      hifn_init_pci_registers(sc);
++}
++
++static void
++hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf)
++{
++      struct hifn_dma *dma = sc->sc_dma;
++      struct cryptop *crp = cmd->crp;
++      struct cryptodesc *crd;
++      int i, u, ivlen;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++#if 0
++      if (cmd->src_map == cmd->dst_map) {
++              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                  BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
++      } else {
++              bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++                  BUS_DMASYNC_POSTWRITE);
++              bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++                  BUS_DMASYNC_POSTREAD);
++      }
++#endif
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              if (cmd->src_skb != cmd->dst_skb) {
++#ifdef NOTYET
++                      crp->crp_buf = (caddr_t)cmd->dst_m;
++                      totlen = cmd->src_mapsize;
++                      for (m = cmd->dst_m; m != NULL; m = m->m_next) {
++                              if (totlen < m->m_len) {
++                                      m->m_len = totlen;
++                                      totlen = 0;
++                              } else
++                                      totlen -= m->m_len;
++                      }
++                      cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len;
++                      m_freem(cmd->src_m);
++#else
++                      device_printf(sc->sc_dev,
++                                      "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++                                      __FILE__, __LINE__);
++#endif
++              }
++      }
++
++      if (cmd->sloplen != 0) {
++              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                  cmd->src_mapsize - cmd->sloplen, cmd->sloplen,
++                  (caddr_t)&dma->slop[cmd->slopidx]);
++      }
++
++      i = dma->dstk; u = dma->dstu;
++      while (u != 0) {
++              if (i == HIFN_D_DST_RSIZE)
++                      i = 0;
++#if 0
++              bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
++                  BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++#endif
++              if (dma->dstr[i].l & htole32(HIFN_D_VALID)) {
++#if 0
++                      bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
++                          BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++#endif
++                      break;
++              }
++              i++, u--;
++      }
++      dma->dstk = i; dma->dstu = u;
++
++      hifnstats.hst_obytes += cmd->dst_mapsize;
++
++      if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) ==
++          HIFN_BASE_CMD_CRYPT) {
++              for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++                      if (crd->crd_alg != CRYPTO_DES_CBC &&
++                          crd->crd_alg != CRYPTO_3DES_CBC &&
++                          crd->crd_alg != CRYPTO_AES_CBC)
++                              continue;
++                      ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ?
++                              HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++                      crypto_copydata(crp->crp_flags, crp->crp_buf,
++                          crd->crd_skip + crd->crd_len - ivlen, ivlen,
++                          cmd->softc->sc_sessions[cmd->session_num].hs_iv);
++                      break;
++              }
++      }
++
++      if (macbuf != NULL) {
++              for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++                        int len;
++
++                      if (crd->crd_alg != CRYPTO_MD5 &&
++                          crd->crd_alg != CRYPTO_SHA1 &&
++                          crd->crd_alg != CRYPTO_MD5_HMAC &&
++                          crd->crd_alg != CRYPTO_SHA1_HMAC) {
++                              continue;
++                      }
++                      len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen;
++                      crypto_copyback(crp->crp_flags, crp->crp_buf,
++                          crd->crd_inject, len, macbuf);
++                      break;
++              }
++      }
++
++      if (cmd->src_map != cmd->dst_map)
++              pci_unmap_buf(sc, &cmd->dst);
++      pci_unmap_buf(sc, &cmd->src);
++      kfree(cmd);
++      crypto_done(crp);
++}
++
++/*
++ * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0
++ * and Group 1 registers; avoid conditions that could create
++ * burst writes by doing a read in between the writes.
++ *
++ * NB: The read we interpose is always to the same register;
++ *     we do this because reading from an arbitrary (e.g. last)
++ *     register may not always work.
++ */
++static void
++hifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val)
++{
++      if (sc->sc_flags & HIFN_IS_7811) {
++              if (sc->sc_bar0_lastreg == reg - 4)
++                      readl(sc->sc_bar0 + HIFN_0_PUCNFG);
++              sc->sc_bar0_lastreg = reg;
++      }
++      writel(val, sc->sc_bar0 + reg);
++}
++
++static void
++hifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val)
++{
++      if (sc->sc_flags & HIFN_IS_7811) {
++              if (sc->sc_bar1_lastreg == reg - 4)
++                      readl(sc->sc_bar1 + HIFN_1_REVID);
++              sc->sc_bar1_lastreg = reg;
++      }
++      writel(val, sc->sc_bar1 + reg);
++}
++
++
++static struct pci_device_id hifn_pci_tbl[] = {
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      /*
++       * Other vendors share this PCI ID as well, such as
++       * http://www.powercrypt.com, and obviously they also
++       * use the same key.
++       */
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { 0, 0, 0, 0, 0, 0, }
++};
++MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
++
++static struct pci_driver hifn_driver = {
++      .name         = "hifn",
++      .id_table     = hifn_pci_tbl,
++      .probe        = hifn_probe,
++      .remove       = hifn_remove,
++      /* add PM stuff here one day */
++};
++
++static int __init hifn_init (void)
++{
++      struct hifn_softc *sc = NULL;
++      int rc;
++
++      DPRINTF("%s(%p)\n", __FUNCTION__, hifn_init);
++
++      rc = pci_register_driver(&hifn_driver);
++      pci_register_driver_compat(&hifn_driver, rc);
++
++      return rc;
++}
++
++static void __exit hifn_exit (void)
++{
++      pci_unregister_driver(&hifn_driver);
++}
++
++module_init(hifn_init);
++module_exit(hifn_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("OCF driver for hifn PCI crypto devices");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifnHIPP.c   2007-07-25 14:36:45.000000000 +1000
+@@ -0,0 +1,420 @@
++/*-
++ * Driver for Hifn HIPP-I/II chipset
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored by Hifn Inc.
++ *
++ */
++
++/*
++ * Driver for various Hifn encryption processors.
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <linux/uio.h>
++#include <linux/sysfs.h>
++#include <linux/miscdevice.h>
++#include <asm/io.h>
++
++#include <cryptodev.h>
++
++#include "hifnHIPPreg.h"
++#include "hifnHIPPvar.h"
++
++#if 1
++#define       DPRINTF(a...)   if (hipp_debug) { \
++                                                      printk("%s: ", sc ? \
++                                                              device_get_nameunit(sc->sc_dev) : "hifn"); \
++                                                      printk(a); \
++                                              } else
++#else
++#define       DPRINTF(a...)
++#endif
++
++typedef int bus_size_t;
++
++static inline int
++pci_get_revid(struct pci_dev *dev)
++{
++      u8 rid = 0;
++      pci_read_config_byte(dev, PCI_REVISION_ID, &rid);
++      return rid;
++}
++
++#define debug hipp_debug
++int hipp_debug = 0;
++module_param(hipp_debug, int, 0644);
++MODULE_PARM_DESC(hipp_debug, "Enable debug");
++
++int hipp_maxbatch = 1;
++module_param(hipp_maxbatch, int, 0644);
++MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt");
++
++static        int  hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent);
++static        void hipp_remove(struct pci_dev *dev);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hipp_intr(int irq, void *arg);
++#else
++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs);
++#endif
++
++static int hipp_num_chips = 0;
++static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS];
++
++static        int hipp_newsession(device_t, u_int32_t *, struct cryptoini *);
++static        int hipp_freesession(device_t, u_int64_t);
++static        int hipp_process(device_t, struct cryptop *, int);
++
++static device_method_t hipp_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, hipp_newsession),
++      DEVMETHOD(cryptodev_freesession,hipp_freesession),
++      DEVMETHOD(cryptodev_process,    hipp_process),
++};
++
++static __inline u_int32_t
++READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg)
++{
++      u_int32_t v = readl(sc->sc_bar[barno] + reg);
++      //sc->sc_bar0_lastreg = (bus_size_t) -1;
++      return (v);
++}
++static __inline void
++WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val)
++{
++      writel(val, sc->sc_bar[barno] + reg);
++}
++
++#define READ_REG_0(sc, reg)         READ_REG(sc, 0, reg)
++#define WRITE_REG_0(sc, reg, val)   WRITE_REG(sc,0, reg, val)
++#define READ_REG_1(sc, reg)         READ_REG(sc, 1, reg)
++#define WRITE_REG_1(sc, reg, val)   WRITE_REG(sc,1, reg, val)
++
++static int
++hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++      return EINVAL;
++}
++
++static int
++hipp_freesession(device_t dev, u_int64_t tid)
++{
++      return EINVAL;
++}
++
++static int
++hipp_process(device_t dev, struct cryptop *crp, int hint)
++{
++      return EINVAL;
++}
++
++static const char*
++hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen)
++{
++      char *n = NULL;
++
++      switch (pci_get_vendor(sc->sc_pcidev)) {
++      case PCI_VENDOR_HIFN:
++              switch (pci_get_device(sc->sc_pcidev)) {
++              case PCI_PRODUCT_HIFN_7855:     n = "Hifn 7855";
++              case PCI_PRODUCT_HIFN_8155:     n = "Hifn 8155";
++              case PCI_PRODUCT_HIFN_6500:     n = "Hifn 6500";
++              }
++      }
++
++      if(n==NULL) {
++              snprintf(buf, blen, "VID=%02x,PID=%02x",
++                       pci_get_vendor(sc->sc_pcidev),
++                       pci_get_device(sc->sc_pcidev));
++      } else {
++              buf[0]='\0';
++              strncat(buf, n, blen);
++      }
++      return buf;
++}
++
++struct hipp_fs_entry {
++      struct attribute attr;
++      /* other stuff */
++};
++
++
++static ssize_t
++cryptoid_show(struct device *dev,
++            struct device_attribute *attr,
++            char *buf)                                                
++{                                                             
++      struct hipp_softc *sc;                                  
++
++      sc = pci_get_drvdata(to_pci_dev (dev));
++      return sprintf (buf, "%d\n", sc->sc_cid);
++}
++
++struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid);
++
++/*
++ * Attach an interface that successfully probed.
++ */
++static int
++hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++      struct hipp_softc *sc = NULL;
++      int i;
++      //char rbase;
++      //u_int16_t ena;
++      int rev;
++      //int rseg;
++      int rc;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (pci_enable_device(dev) < 0)
++              return(-ENODEV);
++
++      if (pci_set_mwi(dev))
++              return(-ENODEV);
++
++      if (!dev->irq) {
++              printk("hifn: found device with no IRQ assigned. check BIOS settings!");
++              pci_disable_device(dev);
++              return(-ENODEV);
++      }
++
++      sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++      if (!sc)
++              return(-ENOMEM);
++      memset(sc, 0, sizeof(*sc));
++
++      softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods);
++
++      sc->sc_pcidev = dev;
++      sc->sc_irq = -1;
++      sc->sc_cid = -1;
++      sc->sc_num = hipp_num_chips++;
++
++      if (sc->sc_num < HIPP_MAX_CHIPS)
++              hipp_chip_idx[sc->sc_num] = sc;
++
++      pci_set_drvdata(sc->sc_pcidev, sc);
++
++      spin_lock_init(&sc->sc_mtx);
++
++      /*
++       * Setup PCI resources.
++       * The READ_REG_0, WRITE_REG_0, READ_REG_1,
++       * and WRITE_REG_1 macros throughout the driver are used
++       * to permit better debugging.
++       */
++      for(i=0; i<4; i++) {
++              unsigned long mem_start, mem_len;
++              mem_start = pci_resource_start(sc->sc_pcidev, i);
++              mem_len   = pci_resource_len(sc->sc_pcidev, i);
++              sc->sc_barphy[i] = (caddr_t)mem_start;
++              sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len);
++              if (!sc->sc_bar[i]) {
++                      device_printf(sc->sc_dev, "cannot map bar%d register space\n", i);
++                      goto fail;
++              }
++      }
++
++      //hipp_reset_board(sc, 0);
++      pci_set_master(sc->sc_pcidev);
++
++      /*
++       * Arrange the interrupt line.
++       */
++      rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc);
++      if (rc) {
++              device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc);
++              goto fail;
++      }
++      sc->sc_irq = dev->irq;
++
++      rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff;
++
++      {
++              char b[32];
++              device_printf(sc->sc_dev, "%s, rev %u",
++                            hipp_partname(sc, b, sizeof(b)), rev);
++      }
++
++#if 0
++      if (sc->sc_flags & HIFN_IS_7956)
++              printf(", pll=0x%x<%s clk, %ux mult>",
++                      sc->sc_pllconfig,
++                      sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci",
++                      2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11));
++#endif
++      printf("\n");
++
++      sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++      if (sc->sc_cid < 0) {
++              device_printf(sc->sc_dev, "could not get crypto driver id\n");
++              goto fail;
++      }
++
++#if 0 /* cannot work with a non-GPL module */
++      /* make a sysfs entry to let the world know what entry we got */
++      sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr);
++#endif
++
++#if 0
++      init_timer(&sc->sc_tickto);
++      sc->sc_tickto.function = hifn_tick;
++      sc->sc_tickto.data = (unsigned long) sc->sc_num;
++      mod_timer(&sc->sc_tickto, jiffies + HZ);
++#endif
++
++#if 0 /* no code here yet ?? */
++      crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++#endif
++
++      return (0);
++
++fail:
++      if (sc->sc_cid >= 0)
++              crypto_unregister_all(sc->sc_cid);
++      if (sc->sc_irq != -1)
++              free_irq(sc->sc_irq, sc);
++      
++#if 0
++      if (sc->sc_dma) {
++              /* Turn off DMA polling */
++              WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++                          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++              
++              pci_free_consistent(sc->sc_pcidev,
++                                  sizeof(*sc->sc_dma),
++                                  sc->sc_dma, sc->sc_dma_physaddr);
++      }
++#endif
++      kfree(sc);
++      return (-ENXIO);
++}
++
++/*
++ * Detach an interface that successfully probed.
++ */
++static void
++hipp_remove(struct pci_dev *dev)
++{
++      struct hipp_softc *sc = pci_get_drvdata(dev);
++      unsigned long l_flags;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /* disable interrupts */
++      HIPP_LOCK(sc);
++
++#if 0
++      WRITE_REG_1(sc, HIFN_1_DMA_IER, 0);
++      HIFN_UNLOCK(sc);
++
++      /*XXX other resources */
++      del_timer_sync(&sc->sc_tickto);
++
++      /* Turn off DMA polling */
++      WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++          HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++#endif
++
++      crypto_unregister_all(sc->sc_cid);
++
++      free_irq(sc->sc_irq, sc);
++
++#if 0
++      pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma),
++                sc->sc_dma, sc->sc_dma_physaddr);
++#endif
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hipp_intr(int irq, void *arg)
++#else
++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++      struct hipp_softc *sc = arg;
++
++      sc = sc; /* shut up compiler */
++
++      return IRQ_HANDLED;
++}
++
++static struct pci_device_id hipp_pci_tbl[] = {
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++};
++MODULE_DEVICE_TABLE(pci, hipp_pci_tbl);
++
++static struct pci_driver hipp_driver = {
++      .name         = "hipp",
++      .id_table     = hipp_pci_tbl,
++      .probe        = hipp_probe,
++      .remove       = hipp_remove,
++      /* add PM stuff here one day */
++};
++
++static int __init hipp_init (void)
++{
++      struct hipp_softc *sc = NULL;
++      int rc;
++
++      DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init);
++
++      rc = pci_register_driver(&hipp_driver);
++      pci_register_driver_compat(&hipp_driver, rc);
++
++      return rc;
++}
++
++static void __exit hipp_exit (void)
++{
++      pci_unregister_driver(&hipp_driver);
++}
++
++module_init(hipp_init);
++module_exit(hipp_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("Michael Richardson <mcr@xelerance.com>");
++MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifnHIPPreg.h        2007-07-25 10:11:22.000000000 +1000
+@@ -0,0 +1,46 @@
++/*-
++ * Hifn HIPP-I/HIPP-II (7855/8155) driver.
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored by Hifn inc.
++ *
++ */
++
++#ifndef __HIFNHIPP_H__
++#define       __HIFNHIPP_H__
++
++/*
++ * PCI vendor and device identifiers
++ */
++#define       PCI_VENDOR_HIFN         0x13a3          /* Hifn */
++#define       PCI_PRODUCT_HIFN_6500   0x0006          /* 6500 */
++#define       PCI_PRODUCT_HIFN_7855   0x001f          /* 7855 */
++#define       PCI_PRODUCT_HIFN_8155   0x999           /* XXX 8155 */
++
++#define HIPP_1_REVID            0x01 /* BOGUS */
++
++#endif /* __HIPP_H__ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/hifn/hifnHIPPvar.h        2007-07-25 13:47:04.000000000 +1000
+@@ -0,0 +1,93 @@
++/*
++ * Hifn HIPP-I/HIPP-II (7855/8155) driver.
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com> * 
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored by Hifn inc.
++ *
++ */
++
++#ifndef __HIFNHIPPVAR_H__
++#define __HIFNHIPPVAR_H__
++
++#define HIPP_MAX_CHIPS 8
++
++/*
++ * Holds data specific to a single Hifn HIPP-I board.
++ */
++struct hipp_softc {
++      softc_device_decl                sc_dev;
++
++      struct pci_dev          *sc_pcidev;     /* device backpointer */
++      ocf_iomem_t             sc_bar[5];
++      caddr_t                 sc_barphy[5];   /* physical address */
++      int                     sc_num;         /* for multiple devs */
++      spinlock_t              sc_mtx;         /* per-instance lock */
++      int32_t                 sc_cid;
++      int                     sc_irq;
++
++#if 0
++
++      u_int32_t               sc_dmaier;
++      u_int32_t               sc_drammodel;   /* 1=dram, 0=sram */
++      u_int32_t               sc_pllconfig;   /* 7954/7955/7956 PLL config */
++
++      struct hifn_dma         *sc_dma;
++      dma_addr_t              sc_dma_physaddr;/* physical address of sc_dma */
++
++      int                     sc_dmansegs;
++      int                     sc_maxses;
++      int                     sc_nsessions;
++      struct hifn_session     *sc_sessions;
++      int                     sc_ramsize;
++      int                     sc_flags;
++#define       HIFN_HAS_RNG            0x1     /* includes random number generator */
++#define       HIFN_HAS_PUBLIC         0x2     /* includes public key support */
++#define       HIFN_HAS_AES            0x4     /* includes AES support */
++#define       HIFN_IS_7811            0x8     /* Hifn 7811 part */
++#define       HIFN_IS_7956            0x10    /* Hifn 7956/7955 don't have SDRAM */
++
++      struct timer_list       sc_tickto;      /* for managing DMA */
++
++      int                     sc_rngfirst;
++      int                     sc_rnghz;       /* RNG polling frequency */
++
++      int                     sc_c_busy;      /* command ring busy */
++      int                     sc_s_busy;      /* source data ring busy */
++      int                     sc_d_busy;      /* destination data ring busy */
++      int                     sc_r_busy;      /* result ring busy */
++      int                     sc_active;      /* for initial countdown */
++      int                     sc_needwakeup;  /* ops q'd wating on resources */
++      int                     sc_curbatch;    /* # ops submitted w/o int */
++      int                     sc_suspended;
++      struct miscdevice       sc_miscdev;
++#endif
++};
++
++#define       HIPP_LOCK(_sc)          spin_lock_irqsave(&(_sc)->sc_mtx, l_flags)
++#define       HIPP_UNLOCK(_sc)        spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags)
++
++#endif /* __HIFNHIPPVAR_H__ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/md5.c        2005-05-20 10:30:52.000000000 +1000
+@@ -0,0 +1,308 @@
++/*    $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $     */
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the project nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#if 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/crypto/md5.c,v 1.9 2004/01/27 19:49:19 des Exp $");
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++#include <sys/time.h>
++#include <sys/systm.h>
++#include <crypto/md5.h>
++#endif
++
++#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
++
++#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
++#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
++#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
++#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
++
++#define ROUND1(a, b, c, d, k, s, i) { \
++      (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
++      (a) = SHIFT((a), (s)); \
++      (a) = (b) + (a); \
++}
++
++#define ROUND2(a, b, c, d, k, s, i) { \
++      (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
++      (a) = SHIFT((a), (s)); \
++      (a) = (b) + (a); \
++}
++
++#define ROUND3(a, b, c, d, k, s, i) { \
++      (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
++      (a) = SHIFT((a), (s)); \
++      (a) = (b) + (a); \
++}
++
++#define ROUND4(a, b, c, d, k, s, i) { \
++      (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
++      (a) = SHIFT((a), (s)); \
++      (a) = (b) + (a); \
++}
++
++#define Sa     7
++#define Sb    12
++#define Sc    17
++#define Sd    22
++
++#define Se     5
++#define Sf     9
++#define Sg    14
++#define Sh    20
++
++#define Si     4
++#define Sj    11
++#define Sk    16
++#define Sl    23
++
++#define Sm     6
++#define Sn    10
++#define So    15
++#define Sp    21
++
++#define MD5_A0        0x67452301
++#define MD5_B0        0xefcdab89
++#define MD5_C0        0x98badcfe
++#define MD5_D0        0x10325476
++
++/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
++static const u_int32_t T[65] = {
++      0,
++      0xd76aa478,     0xe8c7b756,     0x242070db,     0xc1bdceee,
++      0xf57c0faf,     0x4787c62a,     0xa8304613,     0xfd469501,
++      0x698098d8,     0x8b44f7af,     0xffff5bb1,     0x895cd7be,
++      0x6b901122,     0xfd987193,     0xa679438e,     0x49b40821,
++
++      0xf61e2562,     0xc040b340,     0x265e5a51,     0xe9b6c7aa,
++      0xd62f105d,     0x2441453,      0xd8a1e681,     0xe7d3fbc8,
++      0x21e1cde6,     0xc33707d6,     0xf4d50d87,     0x455a14ed,
++      0xa9e3e905,     0xfcefa3f8,     0x676f02d9,     0x8d2a4c8a,
++
++      0xfffa3942,     0x8771f681,     0x6d9d6122,     0xfde5380c,
++      0xa4beea44,     0x4bdecfa9,     0xf6bb4b60,     0xbebfbc70,
++      0x289b7ec6,     0xeaa127fa,     0xd4ef3085,     0x4881d05,
++      0xd9d4d039,     0xe6db99e5,     0x1fa27cf8,     0xc4ac5665,
++
++      0xf4292244,     0x432aff97,     0xab9423a7,     0xfc93a039,
++      0x655b59c3,     0x8f0ccc92,     0xffeff47d,     0x85845dd1,
++      0x6fa87e4f,     0xfe2ce6e0,     0xa3014314,     0x4e0811a1,
++      0xf7537e82,     0xbd3af235,     0x2ad7d2bb,     0xeb86d391,
++};
++
++static const u_int8_t md5_paddat[MD5_BUFLEN] = {
++      0x80,   0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,
++      0,      0,      0,      0,      0,      0,      0,      0,      
++};
++
++static void md5_calc(u_int8_t *, md5_ctxt *);
++
++void md5_init(ctxt)
++      md5_ctxt *ctxt;
++{
++      ctxt->md5_n = 0;
++      ctxt->md5_i = 0;
++      ctxt->md5_sta = MD5_A0;
++      ctxt->md5_stb = MD5_B0;
++      ctxt->md5_stc = MD5_C0;
++      ctxt->md5_std = MD5_D0;
++      bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf));
++}
++
++void md5_loop(ctxt, input, len)
++      md5_ctxt *ctxt;
++      u_int8_t *input;
++      u_int len; /* number of bytes */
++{
++      u_int gap, i;
++
++      ctxt->md5_n += len * 8; /* byte to bit */
++      gap = MD5_BUFLEN - ctxt->md5_i;
++
++      if (len >= gap) {
++              bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
++                      gap);
++              md5_calc(ctxt->md5_buf, ctxt);
++
++              for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
++                      md5_calc((u_int8_t *)(input + i), ctxt);
++              }
++              
++              ctxt->md5_i = len - i;
++              bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
++      } else {
++              bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
++                      len);
++              ctxt->md5_i += len;
++      }
++}
++
++void md5_pad(ctxt)
++      md5_ctxt *ctxt;
++{
++      u_int gap;
++
++      /* Don't count up padding. Keep md5_n. */       
++      gap = MD5_BUFLEN - ctxt->md5_i;
++      if (gap > 8) {
++              bcopy(md5_paddat,
++                    (void *)(ctxt->md5_buf + ctxt->md5_i),
++                    gap - sizeof(ctxt->md5_n));
++      } else {
++              /* including gap == 8 */
++              bcopy(md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
++                      gap);
++              md5_calc(ctxt->md5_buf, ctxt);
++              bcopy((md5_paddat + gap),
++                    (void *)ctxt->md5_buf,
++                    MD5_BUFLEN - sizeof(ctxt->md5_n));
++      }
++
++      /* 8 byte word */       
++#if BYTE_ORDER == LITTLE_ENDIAN
++      bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++      ctxt->md5_buf[56] = ctxt->md5_n8[7];
++      ctxt->md5_buf[57] = ctxt->md5_n8[6];
++      ctxt->md5_buf[58] = ctxt->md5_n8[5];
++      ctxt->md5_buf[59] = ctxt->md5_n8[4];
++      ctxt->md5_buf[60] = ctxt->md5_n8[3];
++      ctxt->md5_buf[61] = ctxt->md5_n8[2];
++      ctxt->md5_buf[62] = ctxt->md5_n8[1];
++      ctxt->md5_buf[63] = ctxt->md5_n8[0];
++#endif
++
++      md5_calc(ctxt->md5_buf, ctxt);
++}
++
++void md5_result(digest, ctxt)
++      u_int8_t *digest;
++      md5_ctxt *ctxt;
++{
++      /* 4 byte words */
++#if BYTE_ORDER == LITTLE_ENDIAN
++      bcopy(&ctxt->md5_st8[0], digest, 16);
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++      digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
++      digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
++      digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
++      digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
++      digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
++      digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
++      digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
++      digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
++#endif
++}
++
++static void md5_calc(b64, ctxt)
++      u_int8_t *b64;
++      md5_ctxt *ctxt;
++{
++      u_int32_t A = ctxt->md5_sta;
++      u_int32_t B = ctxt->md5_stb;
++      u_int32_t C = ctxt->md5_stc;
++      u_int32_t D = ctxt->md5_std;
++#if BYTE_ORDER == LITTLE_ENDIAN
++      u_int32_t *X = (u_int32_t *)b64;
++#endif        
++#if BYTE_ORDER == BIG_ENDIAN
++      /* 4 byte words */
++      /* what a brute force but fast! */
++      u_int32_t X[16];
++      u_int8_t *y = (u_int8_t *)X;
++      y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
++      y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
++      y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
++      y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
++      y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
++      y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
++      y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
++      y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
++      y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
++      y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
++      y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
++      y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
++      y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
++      y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
++      y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
++      y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
++#endif
++
++      ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
++      ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
++      ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
++      ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
++      ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
++      ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
++      ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
++      ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);
++      
++      ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
++      ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
++      ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
++      ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
++      ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
++      ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
++      ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
++      ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);
++
++      ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
++      ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
++      ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
++      ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
++      ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
++      ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
++      ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
++      ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);
++      
++      ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50); 
++      ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52); 
++      ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54); 
++      ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56); 
++      ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); 
++      ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); 
++      ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); 
++      ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);
++
++      ctxt->md5_sta += A;
++      ctxt->md5_stb += B;
++      ctxt->md5_stc += C;
++      ctxt->md5_std += D;
++}
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/md5.h        2005-05-20 10:30:52.000000000 +1000
+@@ -0,0 +1,76 @@
++/*    $FreeBSD: src/sys/crypto/md5.h,v 1.4 2002/03/20 05:13:50 alfred Exp $   */
++/*    $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $   */
++
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the project nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#ifndef _NETINET6_MD5_H_
++#define _NETINET6_MD5_H_
++
++#define MD5_BUFLEN    64
++
++typedef struct {
++      union {
++              u_int32_t       md5_state32[4];
++              u_int8_t        md5_state8[16];
++      } md5_st;
++
++#define md5_sta               md5_st.md5_state32[0]
++#define md5_stb               md5_st.md5_state32[1]
++#define md5_stc               md5_st.md5_state32[2]
++#define md5_std               md5_st.md5_state32[3]
++#define md5_st8               md5_st.md5_state8
++
++      union {
++              u_int64_t       md5_count64;
++              u_int8_t        md5_count8[8];
++      } md5_count;
++#define md5_n md5_count.md5_count64
++#define md5_n8        md5_count.md5_count8
++
++      u_int   md5_i;
++      u_int8_t        md5_buf[MD5_BUFLEN];
++} md5_ctxt;
++
++extern void md5_init(md5_ctxt *);
++extern void md5_loop(md5_ctxt *, u_int8_t *, u_int);
++extern void md5_pad(md5_ctxt *);
++extern void md5_result(u_int8_t *, md5_ctxt *);
++
++/* compatibility */
++#define MD5_CTX               md5_ctxt
++#define MD5Init(x)    md5_init((x))
++#define MD5Update(x, y, z)    md5_loop((x), (y), (z))
++#define MD5Final(x, y) \
++do {                          \
++      md5_pad((y));           \
++      md5_result((x), (y));   \
++} while (0)
++
++#endif /* ! _NETINET6_MD5_H_*/
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/safe.c       2007-07-27 11:34:59.000000000 +1000
+@@ -0,0 +1,2288 @@
++/*-
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2004-2007 David McCullough
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++__FBSDID("$FreeBSD: src/sys/dev/safe/safe.c,v 1.18 2007/03/21 03:42:50 sam Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++/*
++ * SafeNet SafeXcel-1141 hardware crypto accelerator
++ */
++
++#include <cryptodev.h>
++#include <uio.h>
++#include <safe/safereg.h>
++#include <safe/safevar.h>
++
++#if 1
++#define       DPRINTF(a)      do { \
++                                              if (debug) { \
++                                                      printk("%s: ", sc ? \
++                                                              device_get_nameunit(sc->sc_dev) : "safe"); \
++                                                      printk a; \
++                                              } \
++                                      } while (0)
++#else
++#define       DPRINTF(a)
++#endif
++
++/*
++ * until we find a cleaner way, include the BSD md5/sha1 code
++ * here
++ */
++#define HMAC_HACK 1
++#ifdef HMAC_HACK
++#define LITTLE_ENDIAN 1234
++#define BIG_ENDIAN 4321
++#ifdef __LITTLE_ENDIAN
++#define BYTE_ORDER LITTLE_ENDIAN
++#endif
++#ifdef __BIG_ENDIAN
++#define BYTE_ORDER BIG_ENDIAN
++#endif
++#include <safe/md5.h>
++#include <safe/md5.c>
++#include <safe/sha1.h>
++#include <safe/sha1.c>
++
++u_int8_t hmac_ipad_buffer[64] = {
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
++};
++
++u_int8_t hmac_opad_buffer[64] = {
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C
++};
++#endif /* HMAC_HACK */
++
++/* add proc entry for this */
++struct safe_stats safestats;
++
++#define debug safe_debug
++int safe_debug = 0;
++module_param(safe_debug, int, 0644);
++MODULE_PARM_DESC(safe_debug, "Enable debug");
++
++static        void safe_callback(struct safe_softc *, struct safe_ringentry *);
++static        void safe_feed(struct safe_softc *, struct safe_ringentry *);
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++static        void safe_rng_init(struct safe_softc *);
++int safe_rngbufsize = 8;              /* 32 bytes each read  */
++module_param(safe_rngbufsize, int, 0644);
++MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)");
++int safe_rngmaxalarm = 8;             /* max alarms before reset */
++module_param(safe_rngmaxalarm, int, 0644);
++MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset");
++#endif /* SAFE_NO_RNG */
++
++static void safe_totalreset(struct safe_softc *sc);
++static int safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op);
++static int safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op);
++static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re);
++static int safe_kprocess(device_t dev, struct cryptkop *krp, int hint);
++static int safe_kstart(struct safe_softc *sc);
++static int safe_ksigbits(struct safe_softc *sc, struct crparam *cr);
++static void safe_kfeed(struct safe_softc *sc);
++static void safe_kpoll(unsigned long arg);
++static void safe_kload_reg(struct safe_softc *sc, u_int32_t off,
++                                                              u_int32_t len, struct crparam *n);
++
++static        int safe_newsession(device_t, u_int32_t *, struct cryptoini *);
++static        int safe_freesession(device_t, u_int64_t);
++static        int safe_process(device_t, struct cryptop *, int);
++
++static device_method_t safe_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, safe_newsession),
++      DEVMETHOD(cryptodev_freesession,safe_freesession),
++      DEVMETHOD(cryptodev_process,    safe_process),
++      DEVMETHOD(cryptodev_kprocess,   safe_kprocess),
++};
++
++#define       READ_REG(sc,r)                  readl((sc)->sc_base_addr + (r))
++#define WRITE_REG(sc,r,val)           writel((val), (sc)->sc_base_addr + (r))
++
++#define SAFE_MAX_CHIPS 8
++static struct safe_softc *safe_chip_idx[SAFE_MAX_CHIPS];
++
++/*
++ * split our buffers up into safe DMAable byte fragments to avoid lockup
++ * bug in 1141 HW on rev 1.0.
++ */
++
++static int
++pci_map_linear(
++      struct safe_softc *sc,
++      struct safe_operand *buf,
++      void *addr,
++      int len)
++{
++      dma_addr_t tmp;
++      int chunk, tlen = len;
++
++      tmp = pci_map_single(sc->sc_pcidev, addr, len, PCI_DMA_BIDIRECTIONAL);
++
++      buf->mapsize += len;
++      while (len > 0) {
++              chunk = (len > sc->sc_max_dsize) ? sc->sc_max_dsize : len;
++              buf->segs[buf->nsegs].ds_addr = tmp;
++              buf->segs[buf->nsegs].ds_len  = chunk;
++              buf->segs[buf->nsegs].ds_tlen = tlen;
++              buf->nsegs++;
++              tmp  += chunk;
++              len  -= chunk;
++              tlen = 0;
++      }
++      return 0;
++}
++
++/*
++ * map in a given uio buffer (great on some arches :-)
++ */
++
++static int
++pci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio)
++{
++      struct iovec *iov = uio->uio_iov;
++      int n;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      buf->mapsize = 0;
++      buf->nsegs = 0;
++
++      for (n = 0; n < uio->uio_iovcnt; n++) {
++              pci_map_linear(sc, buf, iov->iov_base, iov->iov_len);
++              iov++;
++      }
++
++      /* identify this buffer by the first segment */
++      buf->map = (void *) buf->segs[0].ds_addr;
++      return(0);
++}
++
++/*
++ * map in a given sk_buff
++ */
++
++static int
++pci_map_skb(struct safe_softc *sc,struct safe_operand *buf,struct sk_buff *skb)
++{
++      int i;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      buf->mapsize = 0;
++      buf->nsegs = 0;
++
++      pci_map_linear(sc, buf, skb->data, skb_headlen(skb));
++
++      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++              pci_map_linear(sc, buf,
++                              page_address(skb_shinfo(skb)->frags[i].page) +
++                                                      skb_shinfo(skb)->frags[i].page_offset,
++                              skb_shinfo(skb)->frags[i].size);
++      }
++
++      /* identify this buffer by the first segment */
++      buf->map = (void *) buf->segs[0].ds_addr;
++      return(0);
++}
++
++
++#if 0 /* not needed at this time */
++static void
++pci_sync_operand(struct safe_softc *sc, struct safe_operand *buf)
++{
++      int i;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++      for (i = 0; i < buf->nsegs; i++)
++              pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr,
++                              buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++}
++#endif
++
++static void
++pci_unmap_operand(struct safe_softc *sc, struct safe_operand *buf)
++{
++      int i;
++      DPRINTF(("%s()\n", __FUNCTION__));
++      for (i = 0; i < buf->nsegs; i++) {
++              if (buf->segs[i].ds_tlen) {
++                      DPRINTF(("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen));
++                      pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr,
++                                      buf->segs[i].ds_tlen, PCI_DMA_BIDIRECTIONAL);
++                      DPRINTF(("%s - unmap %d 0x%x %d done\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen));
++              }
++              buf->segs[i].ds_addr = 0;
++              buf->segs[i].ds_len = 0;
++              buf->segs[i].ds_tlen = 0;
++      }
++      buf->nsegs = 0;
++      buf->mapsize = 0;
++      buf->map = 0;
++}
++
++
++/*
++ * SafeXcel Interrupt routine
++ */
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++safe_intr(int irq, void *arg)
++#else
++safe_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++      struct safe_softc *sc = arg;
++      int stat;
++      unsigned long flags;
++
++      stat = READ_REG(sc, SAFE_HM_STAT);
++
++      DPRINTF(("%s(stat=0x%x)\n", __FUNCTION__, stat));
++
++      if (stat == 0)          /* shared irq, not for us */
++              return IRQ_NONE;
++
++      WRITE_REG(sc, SAFE_HI_CLR, stat);       /* IACK */
++
++      if ((stat & SAFE_INT_PE_DDONE)) {
++              /*
++               * Descriptor(s) done; scan the ring and
++               * process completed operations.
++               */
++              spin_lock_irqsave(&sc->sc_ringmtx, flags);
++              while (sc->sc_back != sc->sc_front) {
++                      struct safe_ringentry *re = sc->sc_back;
++
++#ifdef SAFE_DEBUG
++                      if (debug) {
++                              safe_dump_ringstate(sc, __func__);
++                              safe_dump_request(sc, __func__, re);
++                      }
++#endif
++                      /*
++                       * safe_process marks ring entries that were allocated
++                       * but not used with a csr of zero.  This insures the
++                       * ring front pointer never needs to be set backwards
++                       * in the event that an entry is allocated but not used
++                       * because of a setup error.
++                       */
++                      DPRINTF(("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr));
++                      if (re->re_desc.d_csr != 0) {
++                              if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) {
++                                      DPRINTF(("%s !CSR_IS_DONE\n", __FUNCTION__));
++                                      break;
++                              }
++                              if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) {
++                                      DPRINTF(("%s !LEN_IS_DONE\n", __FUNCTION__));
++                                      break;
++                              }
++                              sc->sc_nqchip--;
++                              safe_callback(sc, re);
++                      }
++                      if (++(sc->sc_back) == sc->sc_ringtop)
++                              sc->sc_back = sc->sc_ring;
++              }
++              spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++      }
++
++      /*
++       * Check to see if we got any DMA Error
++       */
++      if (stat & SAFE_INT_PE_ERROR) {
++              printk("%s: dmaerr dmastat %08x\n", device_get_nameunit(sc->sc_dev),
++                              (int)READ_REG(sc, SAFE_PE_DMASTAT));
++              safestats.st_dmaerr++;
++              safe_totalreset(sc);
++#if 0
++              safe_feed(sc);
++#endif
++      }
++
++      if (sc->sc_needwakeup) {                /* XXX check high watermark */
++              int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);
++              DPRINTF(("%s: wakeup crypto %x\n", __func__,
++                      sc->sc_needwakeup));
++              sc->sc_needwakeup &= ~wakeup;
++              crypto_unblock(sc->sc_cid, wakeup);
++      }
++      
++      return IRQ_HANDLED;
++}
++
++/*
++ * safe_feed() - post a request to chip
++ */
++static void
++safe_feed(struct safe_softc *sc, struct safe_ringentry *re)
++{
++      DPRINTF(("%s()\n", __FUNCTION__));
++#ifdef SAFE_DEBUG
++      if (debug) {
++              safe_dump_ringstate(sc, __func__);
++              safe_dump_request(sc, __func__, re);
++      }
++#endif
++      sc->sc_nqchip++;
++      if (sc->sc_nqchip > safestats.st_maxqchip)
++              safestats.st_maxqchip = sc->sc_nqchip;
++      /* poke h/w to check descriptor ring, any value can be written */
++      WRITE_REG(sc, SAFE_HI_RD_DESCR, 0);
++}
++
++#define       N(a)    (sizeof(a) / sizeof (a[0]))
++static void
++safe_setup_enckey(struct safe_session *ses, caddr_t key)
++{
++      int i;
++
++      bcopy(key, ses->ses_key, ses->ses_klen / 8);
++
++      /* PE is little-endian, insure proper byte order */
++      for (i = 0; i < N(ses->ses_key); i++)
++              ses->ses_key[i] = htole32(ses->ses_key[i]);
++}
++
++static void
++safe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen)
++{
++#ifdef HMAC_HACK
++      MD5_CTX md5ctx;
++      SHA1_CTX sha1ctx;
++      int i;
++
++
++      for (i = 0; i < klen; i++)
++              key[i] ^= HMAC_IPAD_VAL;
++
++      if (algo == CRYPTO_MD5_HMAC) {
++              MD5Init(&md5ctx);
++              MD5Update(&md5ctx, key, klen);
++              MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen);
++              bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8));
++      } else {
++              SHA1Init(&sha1ctx);
++              SHA1Update(&sha1ctx, key, klen);
++              SHA1Update(&sha1ctx, hmac_ipad_buffer,
++                  SHA1_HMAC_BLOCK_LEN - klen);
++              bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32));
++      }
++
++      for (i = 0; i < klen; i++)
++              key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
++
++      if (algo == CRYPTO_MD5_HMAC) {
++              MD5Init(&md5ctx);
++              MD5Update(&md5ctx, key, klen);
++              MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen);
++              bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8));
++      } else {
++              SHA1Init(&sha1ctx);
++              SHA1Update(&sha1ctx, key, klen);
++              SHA1Update(&sha1ctx, hmac_opad_buffer,
++                  SHA1_HMAC_BLOCK_LEN - klen);
++              bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32));
++      }
++
++      for (i = 0; i < klen; i++)
++              key[i] ^= HMAC_OPAD_VAL;
++
++#if 0
++      /*
++       * this code prevents SHA working on a BE host,
++       * so it is obviously wrong.  I think the byte
++       * swap setup we do with the chip fixes this for us
++       */
++
++      /* PE is little-endian, insure proper byte order */
++      for (i = 0; i < N(ses->ses_hminner); i++) {
++              ses->ses_hminner[i] = htole32(ses->ses_hminner[i]);
++              ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]);
++      }
++#endif
++#else /* HMAC_HACK */
++      printk("safe: md5/sha not implemented\n");
++#endif /* HMAC_HACK */
++}
++#undef N
++
++/*
++ * Allocate a new 'session' and return an encoded session id.  'sidp'
++ * contains our registration id, and should contain an encoded session
++ * id on successful allocation.
++ */
++static int
++safe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++      struct safe_softc *sc = device_get_softc(dev);
++      struct cryptoini *c, *encini = NULL, *macini = NULL;
++      struct safe_session *ses = NULL;
++      int sesn;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (sidp == NULL || cri == NULL || sc == NULL)
++              return (EINVAL);
++
++      for (c = cri; c != NULL; c = c->cri_next) {
++              if (c->cri_alg == CRYPTO_MD5_HMAC ||
++                  c->cri_alg == CRYPTO_SHA1_HMAC ||
++                  c->cri_alg == CRYPTO_NULL_HMAC) {
++                      if (macini)
++                              return (EINVAL);
++                      macini = c;
++              } else if (c->cri_alg == CRYPTO_DES_CBC ||
++                  c->cri_alg == CRYPTO_3DES_CBC ||
++                  c->cri_alg == CRYPTO_AES_CBC ||
++                  c->cri_alg == CRYPTO_NULL_CBC) {
++                      if (encini)
++                              return (EINVAL);
++                      encini = c;
++              } else
++                      return (EINVAL);
++      }
++      if (encini == NULL && macini == NULL)
++              return (EINVAL);
++      if (encini) {                   /* validate key length */
++              switch (encini->cri_alg) {
++              case CRYPTO_DES_CBC:
++                      if (encini->cri_klen != 64)
++                              return (EINVAL);
++                      break;
++              case CRYPTO_3DES_CBC:
++                      if (encini->cri_klen != 192)
++                              return (EINVAL);
++                      break;
++              case CRYPTO_AES_CBC:
++                      if (encini->cri_klen != 128 &&
++                          encini->cri_klen != 192 &&
++                          encini->cri_klen != 256)
++                              return (EINVAL);
++                      break;
++              }
++      }
++
++      if (sc->sc_sessions == NULL) {
++              ses = sc->sc_sessions = (struct safe_session *)
++                      kmalloc(sizeof(struct safe_session), SLAB_ATOMIC);
++              if (ses == NULL)
++                      return (ENOMEM);
++              memset(ses, 0, sizeof(struct safe_session));
++              sesn = 0;
++              sc->sc_nsessions = 1;
++      } else {
++              for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++                      if (sc->sc_sessions[sesn].ses_used == 0) {
++                              ses = &sc->sc_sessions[sesn];
++                              break;
++                      }
++              }
++
++              if (ses == NULL) {
++                      sesn = sc->sc_nsessions;
++                      ses = (struct safe_session *)
++                              kmalloc((sesn + 1) * sizeof(struct safe_session), SLAB_ATOMIC);
++                      if (ses == NULL)
++                              return (ENOMEM);
++                      memset(ses, 0, (sesn + 1) * sizeof(struct safe_session));
++                      bcopy(sc->sc_sessions, ses, sesn *
++                          sizeof(struct safe_session));
++                      bzero(sc->sc_sessions, sesn *
++                          sizeof(struct safe_session));
++                      kfree(sc->sc_sessions);
++                      sc->sc_sessions = ses;
++                      ses = &sc->sc_sessions[sesn];
++                      sc->sc_nsessions++;
++              }
++      }
++
++      bzero(ses, sizeof(struct safe_session));
++      ses->ses_used = 1;
++
++      if (encini) {
++              /* get an IV */
++              /* XXX may read fewer than requested */
++              read_random(ses->ses_iv, sizeof(ses->ses_iv));
++
++              ses->ses_klen = encini->cri_klen;
++              if (encini->cri_key != NULL)
++                      safe_setup_enckey(ses, encini->cri_key);
++      }
++
++      if (macini) {
++              ses->ses_mlen = macini->cri_mlen;
++              if (ses->ses_mlen == 0) {
++                      if (macini->cri_alg == CRYPTO_MD5_HMAC)
++                              ses->ses_mlen = MD5_HASH_LEN;
++                      else
++                              ses->ses_mlen = SHA1_HASH_LEN;
++              }
++
++              if (macini->cri_key != NULL) {
++                      safe_setup_mackey(ses, macini->cri_alg, macini->cri_key,
++                          macini->cri_klen / 8);
++              }
++      }
++
++      *sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn);
++      return (0);
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++safe_freesession(device_t dev, u_int64_t tid)
++{
++      struct safe_softc *sc = device_get_softc(dev);
++      int session, ret;
++      u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (sc == NULL)
++              return (EINVAL);
++
++      session = SAFE_SESSION(sid);
++      if (session < sc->sc_nsessions) {
++              bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));
++              ret = 0;
++      } else
++              ret = EINVAL;
++      return (ret);
++}
++
++
++static int
++safe_process(device_t dev, struct cryptop *crp, int hint)
++{
++      struct safe_softc *sc = device_get_softc(dev);
++      int err = 0, i, nicealign, uniform;
++      struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++      int bypass, oplen, ivsize;
++      caddr_t iv;
++      int16_t coffset;
++      struct safe_session *ses;
++      struct safe_ringentry *re;
++      struct safe_sarec *sa;
++      struct safe_pdesc *pd;
++      u_int32_t cmd0, cmd1, staterec;
++      unsigned long flags;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
++              safestats.st_invalid++;
++              return (EINVAL);
++      }
++      if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
++              safestats.st_badsession++;
++              return (EINVAL);
++      }
++
++      spin_lock_irqsave(&sc->sc_ringmtx, flags);
++      if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) {
++              safestats.st_ringfull++;
++              sc->sc_needwakeup |= CRYPTO_SYMQ;
++              spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++              return (ERESTART);
++      }
++      re = sc->sc_front;
++
++      staterec = re->re_sa.sa_staterec;       /* save */
++      /* NB: zero everything but the PE descriptor */
++      bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc));
++      re->re_sa.sa_staterec = staterec;       /* restore */
++
++      re->re_crp = crp;
++      re->re_sesn = SAFE_SESSION(crp->crp_sid);
++
++      re->re_src.nsegs = 0;
++      re->re_dst.nsegs = 0;
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              re->re_src_skb = (struct sk_buff *)crp->crp_buf;
++              re->re_dst_skb = (struct sk_buff *)crp->crp_buf;
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              re->re_src_io = (struct uio *)crp->crp_buf;
++              re->re_dst_io = (struct uio *)crp->crp_buf;
++      } else {
++              safestats.st_badflags++;
++              err = EINVAL;
++              goto errout;    /* XXX we don't handle contiguous blocks! */
++      }
++
++      sa = &re->re_sa;
++      ses = &sc->sc_sessions[re->re_sesn];
++
++      crd1 = crp->crp_desc;
++      if (crd1 == NULL) {
++              safestats.st_nodesc++;
++              err = EINVAL;
++              goto errout;
++      }
++      crd2 = crd1->crd_next;
++
++      cmd0 = SAFE_SA_CMD0_BASIC;              /* basic group operation */
++      cmd1 = 0;
++      if (crd2 == NULL) {
++              if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                  crd1->crd_alg == CRYPTO_NULL_HMAC) {
++                      maccrd = crd1;
++                      enccrd = NULL;
++                      cmd0 |= SAFE_SA_CMD0_OP_HASH;
++              } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++                  crd1->crd_alg == CRYPTO_3DES_CBC ||
++                  crd1->crd_alg == CRYPTO_AES_CBC ||
++                  crd1->crd_alg == CRYPTO_NULL_CBC) {
++                      maccrd = NULL;
++                      enccrd = crd1;
++                      cmd0 |= SAFE_SA_CMD0_OP_CRYPT;
++              } else {
++                      safestats.st_badalg++;
++                      err = EINVAL;
++                      goto errout;
++              }
++      } else {
++              if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                  crd1->crd_alg == CRYPTO_NULL_HMAC) &&
++                  (crd2->crd_alg == CRYPTO_DES_CBC ||
++                      crd2->crd_alg == CRYPTO_3DES_CBC ||
++                      crd2->crd_alg == CRYPTO_AES_CBC ||
++                      crd2->crd_alg == CRYPTO_NULL_CBC) &&
++                  ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++                      maccrd = crd1;
++                      enccrd = crd2;
++              } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++                  crd1->crd_alg == CRYPTO_3DES_CBC ||
++                  crd1->crd_alg == CRYPTO_AES_CBC ||
++                  crd1->crd_alg == CRYPTO_NULL_CBC) &&
++                  (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++                      crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++                      crd2->crd_alg == CRYPTO_NULL_HMAC) &&
++                  (crd1->crd_flags & CRD_F_ENCRYPT)) {
++                      enccrd = crd1;
++                      maccrd = crd2;
++              } else {
++                      safestats.st_badalg++;
++                      err = EINVAL;
++                      goto errout;
++              }
++              cmd0 |= SAFE_SA_CMD0_OP_BOTH;
++      }
++
++      if (enccrd) {
++              if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT)
++                      safe_setup_enckey(ses, enccrd->crd_key);
++
++              if (enccrd->crd_alg == CRYPTO_DES_CBC) {
++                      cmd0 |= SAFE_SA_CMD0_DES;
++                      cmd1 |= SAFE_SA_CMD1_CBC;
++                      ivsize = 2*sizeof(u_int32_t);
++              } else if (enccrd->crd_alg == CRYPTO_3DES_CBC) {
++                      cmd0 |= SAFE_SA_CMD0_3DES;
++                      cmd1 |= SAFE_SA_CMD1_CBC;
++                      ivsize = 2*sizeof(u_int32_t);
++              } else if (enccrd->crd_alg == CRYPTO_AES_CBC) {
++                      cmd0 |= SAFE_SA_CMD0_AES;
++                      cmd1 |= SAFE_SA_CMD1_CBC;
++                      if (ses->ses_klen == 128)
++                           cmd1 |=  SAFE_SA_CMD1_AES128;
++                      else if (ses->ses_klen == 192)
++                           cmd1 |=  SAFE_SA_CMD1_AES192;
++                      else
++                           cmd1 |=  SAFE_SA_CMD1_AES256;
++                      ivsize = 4*sizeof(u_int32_t);
++              } else {
++                      cmd0 |= SAFE_SA_CMD0_CRYPT_NULL;
++                      ivsize = 0;
++              }
++
++              /*
++               * Setup encrypt/decrypt state.  When using basic ops
++               * we can't use an inline IV because hash/crypt offset
++               * must be from the end of the IV to the start of the
++               * crypt data and this leaves out the preceding header
++               * from the hash calculation.  Instead we place the IV
++               * in the state record and set the hash/crypt offset to
++               * copy both the header+IV.
++               */
++              if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++                      cmd0 |= SAFE_SA_CMD0_OUTBOUND;
++
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                              iv = enccrd->crd_iv;
++                      else
++                              iv = (caddr_t) ses->ses_iv;
++                      if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                  enccrd->crd_inject, ivsize, iv);
++                      }
++                      bcopy(iv, re->re_sastate.sa_saved_iv, ivsize);
++                      /* make iv LE */
++                      for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++)
++                              re->re_sastate.sa_saved_iv[i] =
++                                      cpu_to_le32(re->re_sastate.sa_saved_iv[i]);
++                      cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV;
++                      re->re_flags |= SAFE_QFLAGS_COPYOUTIV;
++              } else {
++                      cmd0 |= SAFE_SA_CMD0_INBOUND;
++
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++                              bcopy(enccrd->crd_iv,
++                                      re->re_sastate.sa_saved_iv, ivsize);
++                      } else {
++                              crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                  enccrd->crd_inject, ivsize,
++                                  (caddr_t)re->re_sastate.sa_saved_iv);
++                      }
++                      /* make iv LE */
++                      for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++)
++                              re->re_sastate.sa_saved_iv[i] =
++                                      cpu_to_le32(re->re_sastate.sa_saved_iv[i]);
++                      cmd0 |= SAFE_SA_CMD0_IVLD_STATE;
++              }
++              /*
++               * For basic encryption use the zero pad algorithm.
++               * This pads results to an 8-byte boundary and
++               * suppresses padding verification for inbound (i.e.
++               * decrypt) operations.
++               *
++               * NB: Not sure if the 8-byte pad boundary is a problem.
++               */
++              cmd0 |= SAFE_SA_CMD0_PAD_ZERO;
++
++              /* XXX assert key bufs have the same size */
++              bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key));
++      }
++
++      if (maccrd) {
++              if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++                      safe_setup_mackey(ses, maccrd->crd_alg,
++                          maccrd->crd_key, maccrd->crd_klen / 8);
++              }
++
++              if (maccrd->crd_alg == CRYPTO_MD5_HMAC) {
++                      cmd0 |= SAFE_SA_CMD0_MD5;
++                      cmd1 |= SAFE_SA_CMD1_HMAC;      /* NB: enable HMAC */
++              } else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) {
++                      cmd0 |= SAFE_SA_CMD0_SHA1;
++                      cmd1 |= SAFE_SA_CMD1_HMAC;      /* NB: enable HMAC */
++              } else {
++                      cmd0 |= SAFE_SA_CMD0_HASH_NULL;
++              }
++              /*
++               * Digest data is loaded from the SA and the hash
++               * result is saved to the state block where we
++               * retrieve it for return to the caller.
++               */
++              /* XXX assert digest bufs have the same size */
++              bcopy(ses->ses_hminner, sa->sa_indigest,
++                      sizeof(sa->sa_indigest));
++              bcopy(ses->ses_hmouter, sa->sa_outdigest,
++                      sizeof(sa->sa_outdigest));
++
++              cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH;
++              re->re_flags |= SAFE_QFLAGS_COPYOUTICV;
++      }
++
++      if (enccrd && maccrd) {
++              /*
++               * The offset from hash data to the start of
++               * crypt data is the difference in the skips.
++               */
++              bypass = maccrd->crd_skip;
++              coffset = enccrd->crd_skip - maccrd->crd_skip;
++              if (coffset < 0) {
++                      DPRINTF(("%s: hash does not precede crypt; "
++                              "mac skip %u enc skip %u\n",
++                              __func__, maccrd->crd_skip, enccrd->crd_skip));
++                      safestats.st_skipmismatch++;
++                      err = EINVAL;
++                      goto errout;
++              }
++              oplen = enccrd->crd_skip + enccrd->crd_len;
++              if (maccrd->crd_skip + maccrd->crd_len != oplen) {
++                      DPRINTF(("%s: hash amount %u != crypt amount %u\n",
++                              __func__, maccrd->crd_skip + maccrd->crd_len,
++                              oplen));
++                      safestats.st_lenmismatch++;
++                      err = EINVAL;
++                      goto errout;
++              }
++#ifdef SAFE_DEBUG
++              if (debug) {
++                      printf("mac: skip %d, len %d, inject %d\n",
++                          maccrd->crd_skip, maccrd->crd_len,
++                          maccrd->crd_inject);
++                      printf("enc: skip %d, len %d, inject %d\n",
++                          enccrd->crd_skip, enccrd->crd_len,
++                          enccrd->crd_inject);
++                      printf("bypass %d coffset %d oplen %d\n",
++                              bypass, coffset, oplen);
++              }
++#endif
++              if (coffset & 3) {      /* offset must be 32-bit aligned */
++                      DPRINTF(("%s: coffset %u misaligned\n",
++                              __func__, coffset));
++                      safestats.st_coffmisaligned++;
++                      err = EINVAL;
++                      goto errout;
++              }
++              coffset >>= 2;
++              if (coffset > 255) {    /* offset must be <256 dwords */
++                      DPRINTF(("%s: coffset %u too big\n",
++                              __func__, coffset));
++                      safestats.st_cofftoobig++;
++                      err = EINVAL;
++                      goto errout;
++              }
++              /*
++               * Tell the hardware to copy the header to the output.
++               * The header is defined as the data from the end of
++               * the bypass to the start of data to be encrypted. 
++               * Typically this is the inline IV.  Note that you need
++               * to do this even if src+dst are the same; it appears
++               * that w/o this bit the crypted data is written
++               * immediately after the bypass data.
++               */
++              cmd1 |= SAFE_SA_CMD1_HDRCOPY;
++              /*
++               * Disable IP header mutable bit handling.  This is
++               * needed to get correct HMAC calculations.
++               */
++              cmd1 |= SAFE_SA_CMD1_MUTABLE;
++      } else {
++              if (enccrd) {
++                      bypass = enccrd->crd_skip;
++                      oplen = bypass + enccrd->crd_len;
++              } else {
++                      bypass = maccrd->crd_skip;
++                      oplen = bypass + maccrd->crd_len;
++              }
++              coffset = 0;
++      }
++      /* XXX verify multiple of 4 when using s/g */
++      if (bypass > 96) {              /* bypass offset must be <= 96 bytes */
++              DPRINTF(("%s: bypass %u too big\n", __func__, bypass));
++              safestats.st_bypasstoobig++;
++              err = EINVAL;
++              goto errout;
++      }
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              if (pci_map_skb(sc, &re->re_src, re->re_src_skb)) {
++                      safestats.st_noload++;
++                      err = ENOMEM;
++                      goto errout;
++              }
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              if (pci_map_uio(sc, &re->re_src, re->re_src_io)) {
++                      safestats.st_noload++;
++                      err = ENOMEM;
++                      goto errout;
++              }
++      }
++      nicealign = safe_dmamap_aligned(sc, &re->re_src);
++      uniform = safe_dmamap_uniform(sc, &re->re_src);
++
++      DPRINTF(("src nicealign %u uniform %u nsegs %u\n",
++              nicealign, uniform, re->re_src.nsegs));
++      if (re->re_src.nsegs > 1) {
++              re->re_desc.d_src = sc->sc_spalloc.dma_paddr +
++                      ((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring);
++              for (i = 0; i < re->re_src_nsegs; i++) {
++                      /* NB: no need to check if there's space */
++                      pd = sc->sc_spfree;
++                      if (++(sc->sc_spfree) == sc->sc_springtop)
++                              sc->sc_spfree = sc->sc_spring;
++
++                      KASSERT((pd->pd_flags&3) == 0 ||
++                              (pd->pd_flags&3) == SAFE_PD_DONE,
++                              ("bogus source particle descriptor; flags %x",
++                              pd->pd_flags));
++                      pd->pd_addr = re->re_src_segs[i].ds_addr;
++                      pd->pd_size = re->re_src_segs[i].ds_len;
++                      pd->pd_flags = SAFE_PD_READY;
++              }
++              cmd0 |= SAFE_SA_CMD0_IGATHER;
++      } else {
++              /*
++               * No need for gather, reference the operand directly.
++               */
++              re->re_desc.d_src = re->re_src_segs[0].ds_addr;
++      }
++
++      if (enccrd == NULL && maccrd != NULL) {
++              /*
++               * Hash op; no destination needed.
++               */
++      } else {
++              if (crp->crp_flags & (CRYPTO_F_IOV|CRYPTO_F_SKBUF)) {
++                      if (!nicealign) {
++                              safestats.st_iovmisaligned++;
++                              err = EINVAL;
++                              goto errout;
++                      }
++                      if (uniform != 1) {
++                              device_printf(sc->sc_dev, "!uniform source\n");
++                              if (!uniform) {
++                                      /*
++                                       * There's no way to handle the DMA
++                                       * requirements with this uio.  We
++                                       * could create a separate DMA area for
++                                       * the result and then copy it back,
++                                       * but for now we just bail and return
++                                       * an error.  Note that uio requests
++                                       * > SAFE_MAX_DSIZE are handled because
++                                       * the DMA map and segment list for the
++                                       * destination wil result in a
++                                       * destination particle list that does
++                                       * the necessary scatter DMA.
++                                       */ 
++                                      safestats.st_iovnotuniform++;
++                                      err = EINVAL;
++                                      goto errout;
++                              }
++                      } else
++                              re->re_dst = re->re_src;
++              } else {
++                      safestats.st_badflags++;
++                      err = EINVAL;
++                      goto errout;
++              }
++
++              if (re->re_dst.nsegs > 1) {
++                      re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr +
++                          ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring);
++                      for (i = 0; i < re->re_dst_nsegs; i++) {
++                              pd = sc->sc_dpfree;
++                              KASSERT((pd->pd_flags&3) == 0 ||
++                                      (pd->pd_flags&3) == SAFE_PD_DONE,
++                                      ("bogus dest particle descriptor; flags %x",
++                                              pd->pd_flags));
++                              if (++(sc->sc_dpfree) == sc->sc_dpringtop)
++                                      sc->sc_dpfree = sc->sc_dpring;
++                              pd->pd_addr = re->re_dst_segs[i].ds_addr;
++                              pd->pd_flags = SAFE_PD_READY;
++                      }
++                      cmd0 |= SAFE_SA_CMD0_OSCATTER;
++              } else {
++                      /*
++                       * No need for scatter, reference the operand directly.
++                       */
++                      re->re_desc.d_dst = re->re_dst_segs[0].ds_addr;
++              }
++      }
++
++      /*
++       * All done with setup; fillin the SA command words
++       * and the packet engine descriptor.  The operation
++       * is now ready for submission to the hardware.
++       */
++      sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI;
++      sa->sa_cmd1 = cmd1
++                  | (coffset << SAFE_SA_CMD1_OFFSET_S)
++                  | SAFE_SA_CMD1_SAREV1       /* Rev 1 SA data structure */
++                  | SAFE_SA_CMD1_SRPCI
++                  ;
++      /*
++       * NB: the order of writes is important here.  In case the
++       * chip is scanning the ring because of an outstanding request
++       * it might nab this one too.  In that case we need to make
++       * sure the setup is complete before we write the length
++       * field of the descriptor as it signals the descriptor is
++       * ready for processing.
++       */
++      re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI;
++      if (maccrd)
++              re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL;
++      wmb();
++      re->re_desc.d_len = oplen
++                        | SAFE_PE_LEN_READY
++                        | (bypass << SAFE_PE_LEN_BYPASS_S)
++                        ;
++
++      safestats.st_ipackets++;
++      safestats.st_ibytes += oplen;
++
++      if (++(sc->sc_front) == sc->sc_ringtop)
++              sc->sc_front = sc->sc_ring;
++
++      /* XXX honor batching */
++      safe_feed(sc, re);
++      spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++      return (0);
++
++errout:
++      if (re->re_src.map != re->re_dst.map)
++              pci_unmap_operand(sc, &re->re_dst);
++      if (re->re_src.map)
++              pci_unmap_operand(sc, &re->re_src);
++      spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++      if (err != ERESTART) {
++              crp->crp_etype = err;
++              crypto_done(crp);
++      } else {
++              sc->sc_needwakeup |= CRYPTO_SYMQ;
++      }
++      return (err);
++}
++
++static void
++safe_callback(struct safe_softc *sc, struct safe_ringentry *re)
++{
++      struct cryptop *crp = (struct cryptop *)re->re_crp;
++      struct cryptodesc *crd;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      safestats.st_opackets++;
++      safestats.st_obytes += re->re_dst.mapsize;
++
++      if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) {
++              device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n",
++                      re->re_desc.d_csr,
++                      re->re_sa.sa_cmd0, re->re_sa.sa_cmd1);
++              safestats.st_peoperr++;
++              crp->crp_etype = EIO;           /* something more meaningful? */
++      }
++
++      if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map)
++              pci_unmap_operand(sc, &re->re_dst);
++      pci_unmap_operand(sc, &re->re_src);
++
++      /* 
++       * If result was written to a differet mbuf chain, swap
++       * it in as the return value and reclaim the original.
++       */
++      if ((crp->crp_flags & CRYPTO_F_SKBUF) && re->re_src_skb != re->re_dst_skb) {
++              device_printf(sc->sc_dev, "no CRYPTO_F_SKBUF swapping support\n");
++              /* kfree_skb(skb) */
++              /* crp->crp_buf = (caddr_t)re->re_dst_skb */
++              return;
++      }
++
++      if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) {
++              /* copy out IV for future use */
++              for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++                      int i;
++                      int ivsize;
++
++                      if (crd->crd_alg == CRYPTO_DES_CBC ||
++                          crd->crd_alg == CRYPTO_3DES_CBC) {
++                              ivsize = 2*sizeof(u_int32_t);
++                      } else if (crd->crd_alg == CRYPTO_AES_CBC) {
++                              ivsize = 4*sizeof(u_int32_t);
++                      } else
++                              continue;
++                      crypto_copydata(crp->crp_flags, crp->crp_buf,
++                          crd->crd_skip + crd->crd_len - ivsize, ivsize,
++                          (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv);
++                      for (i = 0;
++                                      i < ivsize/sizeof(sc->sc_sessions[re->re_sesn].ses_iv[0]);
++                                      i++)
++                              sc->sc_sessions[re->re_sesn].ses_iv[i] =
++                                      cpu_to_le32(sc->sc_sessions[re->re_sesn].ses_iv[i]);
++                      break;
++              }
++      }
++
++      if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) {
++              /* copy out ICV result */
++              for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++                      if (!(crd->crd_alg == CRYPTO_MD5_HMAC ||
++                          crd->crd_alg == CRYPTO_SHA1_HMAC ||
++                          crd->crd_alg == CRYPTO_NULL_HMAC))
++                              continue;
++                      if (crd->crd_alg == CRYPTO_SHA1_HMAC) {
++                              /*
++                               * SHA-1 ICV's are byte-swapped; fix 'em up
++                               * before copy them to their destination.
++                               */
++                              re->re_sastate.sa_saved_indigest[0] =
++                                      cpu_to_be32(re->re_sastate.sa_saved_indigest[0]);
++                              re->re_sastate.sa_saved_indigest[1] = 
++                                      cpu_to_be32(re->re_sastate.sa_saved_indigest[1]);
++                              re->re_sastate.sa_saved_indigest[2] =
++                                      cpu_to_be32(re->re_sastate.sa_saved_indigest[2]);
++                      } else {
++                              re->re_sastate.sa_saved_indigest[0] =
++                                      cpu_to_le32(re->re_sastate.sa_saved_indigest[0]);
++                              re->re_sastate.sa_saved_indigest[1] = 
++                                      cpu_to_le32(re->re_sastate.sa_saved_indigest[1]);
++                              re->re_sastate.sa_saved_indigest[2] =
++                                      cpu_to_le32(re->re_sastate.sa_saved_indigest[2]);
++                      }
++                      crypto_copyback(crp->crp_flags, crp->crp_buf,
++                          crd->crd_inject,
++                          sc->sc_sessions[re->re_sesn].ses_mlen,
++                          (caddr_t)re->re_sastate.sa_saved_indigest);
++                      break;
++              }
++      }
++      crypto_done(crp);
++}
++
++
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++#define       SAFE_RNG_MAXWAIT        1000
++
++static void
++safe_rng_init(struct safe_softc *sc)
++{
++      u_int32_t w, v;
++      int i;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      WRITE_REG(sc, SAFE_RNG_CTRL, 0);
++      /* use default value according to the manual */
++      WRITE_REG(sc, SAFE_RNG_CNFG, 0x834);    /* magic from SafeNet */
++      WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++      /*
++       * There is a bug in rev 1.0 of the 1140 that when the RNG
++       * is brought out of reset the ready status flag does not
++       * work until the RNG has finished its internal initialization.
++       *
++       * So in order to determine the device is through its
++       * initialization we must read the data register, using the
++       * status reg in the read in case it is initialized.  Then read
++       * the data register until it changes from the first read.
++       * Once it changes read the data register until it changes
++       * again.  At this time the RNG is considered initialized. 
++       * This could take between 750ms - 1000ms in time.
++       */
++      i = 0;
++      w = READ_REG(sc, SAFE_RNG_OUT);
++      do {
++              v = READ_REG(sc, SAFE_RNG_OUT);
++              if (v != w) {
++                      w = v;
++                      break;
++              }
++              DELAY(10);
++      } while (++i < SAFE_RNG_MAXWAIT);
++
++      /* Wait Until data changes again */
++      i = 0;
++      do {
++              v = READ_REG(sc, SAFE_RNG_OUT);
++              if (v != w)
++                      break;
++              DELAY(10);
++      } while (++i < SAFE_RNG_MAXWAIT);
++}
++
++static __inline void
++safe_rng_disable_short_cycle(struct safe_softc *sc)
++{
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      WRITE_REG(sc, SAFE_RNG_CTRL,
++              READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN);
++}
++
++static __inline void
++safe_rng_enable_short_cycle(struct safe_softc *sc)
++{
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      WRITE_REG(sc, SAFE_RNG_CTRL, 
++              READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN);
++}
++
++static __inline u_int32_t
++safe_rng_read(struct safe_softc *sc)
++{
++      int i;
++
++      i = 0;
++      while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT)
++              ;
++      return READ_REG(sc, SAFE_RNG_OUT);
++}
++
++static int
++safe_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++      struct safe_softc *sc = (struct safe_softc *) arg;
++      int i, rc;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++      
++      safestats.st_rng++;
++      /*
++       * Fetch the next block of data.
++       */
++      if (maxwords > safe_rngbufsize)
++              maxwords = safe_rngbufsize;
++      if (maxwords > SAFE_RNG_MAXBUFSIZ)
++              maxwords = SAFE_RNG_MAXBUFSIZ;
++retry:
++      /* read as much as we can */
++      for (rc = 0; rc < maxwords; rc++) {
++              if (READ_REG(sc, SAFE_RNG_STAT) != 0)
++                      break;
++              buf[rc] = READ_REG(sc, SAFE_RNG_OUT);
++      }
++      if (rc == 0)
++              return 0;
++      /*
++       * Check the comparator alarm count and reset the h/w if
++       * it exceeds our threshold.  This guards against the
++       * hardware oscillators resonating with external signals.
++       */
++      if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) {
++              u_int32_t freq_inc, w;
++
++              DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__,
++                      (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm));
++              safestats.st_rngalarm++;
++              safe_rng_enable_short_cycle(sc);
++              freq_inc = 18;
++              for (i = 0; i < 64; i++) {
++                      w = READ_REG(sc, SAFE_RNG_CNFG);
++                      freq_inc = ((w + freq_inc) & 0x3fL);
++                      w = ((w & ~0x3fL) | freq_inc);
++                      WRITE_REG(sc, SAFE_RNG_CNFG, w);
++
++                      WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++                      (void) safe_rng_read(sc);
++                      DELAY(25);
++
++                      if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) {
++                              safe_rng_disable_short_cycle(sc);
++                              goto retry;
++                      }
++                      freq_inc = 1;
++              }
++              safe_rng_disable_short_cycle(sc);
++      } else
++              WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++      return(rc);
++}
++#endif /* defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) */
++
++
++/*
++ * Resets the board.  Values in the regesters are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++safe_reset_board(struct safe_softc *sc)
++{
++      u_int32_t v;
++      /*
++       * Reset the device.  The manual says no delay
++       * is needed between marking and clearing reset.
++       */
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      v = READ_REG(sc, SAFE_PE_DMACFG) &~
++              (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET |
++               SAFE_PE_DMACFG_SGRESET);
++      WRITE_REG(sc, SAFE_PE_DMACFG, v
++                                  | SAFE_PE_DMACFG_PERESET
++                                  | SAFE_PE_DMACFG_PDRRESET
++                                  | SAFE_PE_DMACFG_SGRESET);
++      WRITE_REG(sc, SAFE_PE_DMACFG, v);
++}
++
++/*
++ * Initialize registers we need to touch only once.
++ */
++static void
++safe_init_board(struct safe_softc *sc)
++{
++      u_int32_t v, dwords;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      v = READ_REG(sc, SAFE_PE_DMACFG);
++      v &=~ (   SAFE_PE_DMACFG_PEMODE
++                      | SAFE_PE_DMACFG_FSENA          /* failsafe enable */
++                      | SAFE_PE_DMACFG_GPRPCI         /* gather ring on PCI */
++                      | SAFE_PE_DMACFG_SPRPCI         /* scatter ring on PCI */
++                      | SAFE_PE_DMACFG_ESDESC         /* endian-swap descriptors */
++                      | SAFE_PE_DMACFG_ESPDESC        /* endian-swap part. desc's */
++                      | SAFE_PE_DMACFG_ESSA           /* endian-swap SA's */
++                      | SAFE_PE_DMACFG_ESPACKET       /* swap the packet data */
++                );
++      v |= SAFE_PE_DMACFG_FSENA               /* failsafe enable */
++        |  SAFE_PE_DMACFG_GPRPCI              /* gather ring on PCI */
++        |  SAFE_PE_DMACFG_SPRPCI              /* scatter ring on PCI */
++        |  SAFE_PE_DMACFG_ESDESC              /* endian-swap descriptors */
++        |  SAFE_PE_DMACFG_ESPDESC             /* endian-swap part. desc's */
++        |  SAFE_PE_DMACFG_ESSA                /* endian-swap SA's */
++#if 0
++        |  SAFE_PE_DMACFG_ESPACKET    /* swap the packet data */
++#endif
++        ;
++      WRITE_REG(sc, SAFE_PE_DMACFG, v);
++
++#ifdef __BIG_ENDIAN
++      /* tell the safenet that we are 4321 and not 1234 */
++      WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b);
++#endif
++
++      if (sc->sc_chiprev == SAFE_REV(1,0)) {
++              /*
++               * Avoid large PCI DMA transfers.  Rev 1.0 has a bug where
++               * "target mode transfers" done while the chip is DMA'ing
++               * >1020 bytes cause the hardware to lockup.  To avoid this
++               * we reduce the max PCI transfer size and use small source
++               * particle descriptors (<= 256 bytes).
++               */
++              WRITE_REG(sc, SAFE_DMA_CFG, 256);
++              device_printf(sc->sc_dev,
++                      "Reduce max DMA size to %u words for rev %u.%u WAR\n",
++                      (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff),
++                      (unsigned) SAFE_REV_MAJ(sc->sc_chiprev),
++                      (unsigned) SAFE_REV_MIN(sc->sc_chiprev));
++              sc->sc_max_dsize = 256;
++      } else {
++              sc->sc_max_dsize = SAFE_MAX_DSIZE;
++      }
++
++      /* NB: operands+results are overlaid */
++      WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr);
++      WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr);
++      /*
++       * Configure ring entry size and number of items in the ring.
++       */
++      KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0,
++              ("PE ring entry not 32-bit aligned!"));
++      dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t);
++      WRITE_REG(sc, SAFE_PE_RINGCFG,
++              (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE);
++      WRITE_REG(sc, SAFE_PE_RINGPOLL, 0);     /* disable polling */
++
++      WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr);
++      WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr);
++      WRITE_REG(sc, SAFE_PE_PARTSIZE,
++              (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART);
++      /*
++       * NB: destination particles are fixed size.  We use
++       *     an mbuf cluster and require all results go to
++       *     clusters or smaller.
++       */
++      WRITE_REG(sc, SAFE_PE_PARTCFG, sc->sc_max_dsize);
++
++      /* it's now safe to enable PE mode, do it */
++      WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE);
++
++      /*
++       * Configure hardware to use level-triggered interrupts and
++       * to interrupt after each descriptor is processed.
++       */
++      WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL);
++      WRITE_REG(sc, SAFE_HI_CLR, 0xffffffff);
++      WRITE_REG(sc, SAFE_HI_DESC_CNT, 1);
++      WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR);
++}
++
++
++/*
++ * Clean up after a chip crash.
++ * It is assumed that the caller in splimp()
++ */
++static void
++safe_cleanchip(struct safe_softc *sc)
++{
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (sc->sc_nqchip != 0) {
++              struct safe_ringentry *re = sc->sc_back;
++
++              while (re != sc->sc_front) {
++                      if (re->re_desc.d_csr != 0)
++                              safe_free_entry(sc, re);
++                      if (++re == sc->sc_ringtop)
++                              re = sc->sc_ring;
++              }
++              sc->sc_back = re;
++              sc->sc_nqchip = 0;
++      }
++}
++
++/*
++ * free a safe_q
++ * It is assumed that the caller is within splimp().
++ */
++static int
++safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re)
++{
++      struct cryptop *crp;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      /*
++       * Free header MCR
++       */
++      if ((re->re_dst_skb != NULL) && (re->re_src_skb != re->re_dst_skb))
++#ifdef NOTYET
++              m_freem(re->re_dst_m);
++#else
++              printk("%s,%d: SKB not supported\n", __FILE__, __LINE__);
++#endif
++
++      crp = (struct cryptop *)re->re_crp;
++      
++      re->re_desc.d_csr = 0;
++      
++      crp->crp_etype = EFAULT;
++      crypto_done(crp);
++      return(0);
++}
++
++/*
++ * Routine to reset the chip and clean up.
++ * It is assumed that the caller is in splimp()
++ */
++static void
++safe_totalreset(struct safe_softc *sc)
++{
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      safe_reset_board(sc);
++      safe_init_board(sc);
++      safe_cleanchip(sc);
++}
++
++/*
++ * Is the operand suitable aligned for direct DMA.  Each
++ * segment must be aligned on a 32-bit boundary and all
++ * but the last segment must be a multiple of 4 bytes.
++ */
++static int
++safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op)
++{
++      int i;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      for (i = 0; i < op->nsegs; i++) {
++              if (op->segs[i].ds_addr & 3)
++                      return (0);
++              if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3))
++                      return (0);
++      }
++      return (1);
++}
++
++/*
++ * Is the operand suitable for direct DMA as the destination
++ * of an operation.  The hardware requires that each ``particle''
++ * but the last in an operation result have the same size.  We
++ * fix that size at SAFE_MAX_DSIZE bytes.  This routine returns
++ * 0 if some segment is not a multiple of of this size, 1 if all
++ * segments are exactly this size, or 2 if segments are at worst
++ * a multple of this size.
++ */
++static int
++safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op)
++{
++      int result = 1;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (op->nsegs > 0) {
++              int i;
++
++              for (i = 0; i < op->nsegs-1; i++) {
++                      if (op->segs[i].ds_len % sc->sc_max_dsize)
++                              return (0);
++                      if (op->segs[i].ds_len != sc->sc_max_dsize)
++                              result = 2;
++              }
++      }
++      return (result);
++}
++
++static int
++safe_kprocess(device_t dev, struct cryptkop *krp, int hint)
++{
++      struct safe_softc *sc = device_get_softc(dev);
++      struct safe_pkq *q;
++      unsigned long flags;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (sc == NULL) {
++              krp->krp_status = EINVAL;
++              goto err;
++      }
++
++      if (krp->krp_op != CRK_MOD_EXP) {
++              krp->krp_status = EOPNOTSUPP;
++              goto err;
++      }
++
++      q = (struct safe_pkq *) kmalloc(sizeof(*q), GFP_KERNEL);
++      if (q == NULL) {
++              krp->krp_status = ENOMEM;
++              goto err;
++      }
++      memset(q, 0, sizeof(*q));
++      q->pkq_krp = krp;
++      INIT_LIST_HEAD(&q->pkq_list);
++
++      spin_lock_irqsave(&sc->sc_pkmtx, flags);
++      list_add_tail(&q->pkq_list, &sc->sc_pkq);
++      safe_kfeed(sc);
++      spin_unlock_irqrestore(&sc->sc_pkmtx, flags);
++      return (0);
++
++err:
++      crypto_kdone(krp);
++      return (0);
++}
++
++#define       SAFE_CRK_PARAM_BASE     0
++#define       SAFE_CRK_PARAM_EXP      1
++#define       SAFE_CRK_PARAM_MOD      2
++
++static int
++safe_kstart(struct safe_softc *sc)
++{
++      struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp;
++      int exp_bits, mod_bits, base_bits;
++      u_int32_t op, a_off, b_off, c_off, d_off;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (krp->krp_iparams < 3 || krp->krp_oparams != 1) {
++              krp->krp_status = EINVAL;
++              return (1);
++      }
++
++      base_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_BASE]);
++      if (base_bits > 2048)
++              goto too_big;
++      if (base_bits <= 0)             /* 5. base not zero */
++              goto too_small;
++
++      exp_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_EXP]);
++      if (exp_bits > 2048)
++              goto too_big;
++      if (exp_bits <= 0)              /* 1. exponent word length > 0 */
++              goto too_small;         /* 4. exponent not zero */
++
++      mod_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_MOD]);
++      if (mod_bits > 2048)
++              goto too_big;
++      if (mod_bits <= 32)             /* 2. modulus word length > 1 */
++              goto too_small;         /* 8. MSW of modulus != zero */
++      if (mod_bits < exp_bits)        /* 3 modulus len >= exponent len */
++              goto too_small;
++      if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0)
++              goto bad_domain;        /* 6. modulus is odd */
++      if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits)
++              goto too_small;         /* make sure result will fit */
++
++      /* 7. modulus > base */
++      if (mod_bits < base_bits)
++              goto too_small;
++      if (mod_bits == base_bits) {
++              u_int8_t *basep, *modp;
++              int i;
++
++              basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p +
++                  ((base_bits + 7) / 8) - 1;
++              modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p +
++                  ((mod_bits + 7) / 8) - 1;
++              
++              for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) {
++                      if (*modp < *basep)
++                              goto too_small;
++                      if (*modp > *basep)
++                              break;
++              }
++      }
++
++      /* And on the 9th step, he rested. */
++
++      WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32);
++      WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32);
++      if (mod_bits > 1024) {
++              op = SAFE_PK_FUNC_EXP4;
++              a_off = 0x000;
++              b_off = 0x100;
++              c_off = 0x200;
++              d_off = 0x300;
++      } else {
++              op = SAFE_PK_FUNC_EXP16;
++              a_off = 0x000;
++              b_off = 0x080;
++              c_off = 0x100;
++              d_off = 0x180;
++      }
++      sc->sc_pk_reslen = b_off - a_off;
++      sc->sc_pk_resoff = d_off;
++
++      /* A is exponent, B is modulus, C is base, D is result */
++      safe_kload_reg(sc, a_off, b_off - a_off,
++          &krp->krp_param[SAFE_CRK_PARAM_EXP]);
++      WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2);
++      safe_kload_reg(sc, b_off, b_off - a_off,
++          &krp->krp_param[SAFE_CRK_PARAM_MOD]);
++      WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2);
++      safe_kload_reg(sc, c_off, b_off - a_off,
++          &krp->krp_param[SAFE_CRK_PARAM_BASE]);
++      WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2);
++      WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2);
++
++      WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN);
++
++      return (0);
++
++too_big:
++      krp->krp_status = E2BIG;
++      return (1);
++too_small:
++      krp->krp_status = ERANGE;
++      return (1);
++bad_domain:
++      krp->krp_status = EDOM;
++      return (1);
++}
++
++static int
++safe_ksigbits(struct safe_softc *sc, struct crparam *cr)
++{
++      u_int plen = (cr->crp_nbits + 7) / 8;
++      int i, sig = plen * 8;
++      u_int8_t c, *p = cr->crp_p;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      for (i = plen - 1; i >= 0; i--) {
++              c = p[i];
++              if (c != 0) {
++                      while ((c & 0x80) == 0) {
++                              sig--;
++                              c <<= 1;
++                      }
++                      break;
++              }
++              sig -= 8;
++      }
++      return (sig);
++}
++
++static void
++safe_kfeed(struct safe_softc *sc)
++{
++      struct safe_pkq *q, *tmp;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (list_empty(&sc->sc_pkq) && sc->sc_pkq_cur == NULL)
++              return;
++      if (sc->sc_pkq_cur != NULL)
++              return;
++      list_for_each_entry_safe(q, tmp, &sc->sc_pkq, pkq_list) {
++              sc->sc_pkq_cur = q;
++              list_del(&q->pkq_list);
++              if (safe_kstart(sc) != 0) {
++                      crypto_kdone(q->pkq_krp);
++                      kfree(q);
++                      sc->sc_pkq_cur = NULL;
++              } else {
++                      /* op started, start polling */
++                      mod_timer(&sc->sc_pkto, jiffies + 1);
++                      break;
++              }
++      }
++}
++
++static void
++safe_kpoll(unsigned long arg)
++{
++      struct safe_softc *sc = NULL;
++      struct safe_pkq *q;
++      struct crparam *res;
++      int i;
++      u_int32_t buf[64];
++      unsigned long flags;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (arg >= SAFE_MAX_CHIPS)
++              return;
++      sc = safe_chip_idx[arg];
++      if (!sc) {
++              DPRINTF(("%s() - bad callback\n", __FUNCTION__));
++              return;
++      }
++
++      spin_lock_irqsave(&sc->sc_pkmtx, flags);
++      if (sc->sc_pkq_cur == NULL)
++              goto out;
++      if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) {
++              /* still running, check back later */
++              mod_timer(&sc->sc_pkto, jiffies + 1);
++              goto out;
++      }
++
++      q = sc->sc_pkq_cur;
++      res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams];
++      bzero(buf, sizeof(buf));
++      bzero(res->crp_p, (res->crp_nbits + 7) / 8);
++      for (i = 0; i < sc->sc_pk_reslen >> 2; i++)
++              buf[i] = le32_to_cpu(READ_REG(sc, SAFE_PK_RAM_START +
++                  sc->sc_pk_resoff + (i << 2)));
++      bcopy(buf, res->crp_p, (res->crp_nbits + 7) / 8);
++      /*
++       * reduce the bits that need copying if possible
++       */
++      res->crp_nbits = min(res->crp_nbits,sc->sc_pk_reslen * 8);
++      res->crp_nbits = safe_ksigbits(sc, res);
++
++      for (i = SAFE_PK_RAM_START; i < SAFE_PK_RAM_END; i += 4)
++              WRITE_REG(sc, i, 0);
++
++      crypto_kdone(q->pkq_krp);
++      kfree(q);
++      sc->sc_pkq_cur = NULL;
++
++      safe_kfeed(sc);
++out:
++      spin_unlock_irqrestore(&sc->sc_pkmtx, flags);
++}
++
++static void
++safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len,
++    struct crparam *n)
++{
++      u_int32_t buf[64], i;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      bzero(buf, sizeof(buf));
++      bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8);
++
++      for (i = 0; i < len >> 2; i++)
++              WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2),
++                  cpu_to_le32(buf[i]));
++}
++
++#ifdef SAFE_DEBUG
++static void
++safe_dump_dmastatus(struct safe_softc *sc, const char *tag)
++{
++      printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n"
++              , tag
++              , READ_REG(sc, SAFE_DMA_ENDIAN)
++              , READ_REG(sc, SAFE_DMA_SRCADDR)
++              , READ_REG(sc, SAFE_DMA_DSTADDR)
++              , READ_REG(sc, SAFE_DMA_STAT)
++      );
++}
++
++static void
++safe_dump_intrstate(struct safe_softc *sc, const char *tag)
++{
++      printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n"
++              , tag
++              , READ_REG(sc, SAFE_HI_CFG)
++              , READ_REG(sc, SAFE_HI_MASK)
++              , READ_REG(sc, SAFE_HI_DESC_CNT)
++              , READ_REG(sc, SAFE_HU_STAT)
++              , READ_REG(sc, SAFE_HM_STAT)
++      );
++}
++
++static void
++safe_dump_ringstate(struct safe_softc *sc, const char *tag)
++{
++      u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT);
++
++      /* NB: assume caller has lock on ring */
++      printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n",
++              tag,
++              estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S),
++              (unsigned long)(sc->sc_back - sc->sc_ring),
++              (unsigned long)(sc->sc_front - sc->sc_ring));
++}
++
++static void
++safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re)
++{
++      int ix, nsegs;
++
++      ix = re - sc->sc_ring;
++      printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n"
++              , tag
++              , re, ix
++              , re->re_desc.d_csr
++              , re->re_desc.d_src
++              , re->re_desc.d_dst
++              , re->re_desc.d_sa
++              , re->re_desc.d_len
++      );
++      if (re->re_src.nsegs > 1) {
++              ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) /
++                      sizeof(struct safe_pdesc);
++              for (nsegs = re->re_src.nsegs; nsegs; nsegs--) {
++                      printf(" spd[%u] %p: %p size %u flags %x"
++                              , ix, &sc->sc_spring[ix]
++                              , (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr
++                              , sc->sc_spring[ix].pd_size
++                              , sc->sc_spring[ix].pd_flags
++                      );
++                      if (sc->sc_spring[ix].pd_size == 0)
++                              printf(" (zero!)");
++                      printf("\n");
++                      if (++ix == SAFE_TOTAL_SPART)
++                              ix = 0;
++              }
++      }
++      if (re->re_dst.nsegs > 1) {
++              ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) /
++                      sizeof(struct safe_pdesc);
++              for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) {
++                      printf(" dpd[%u] %p: %p flags %x\n"
++                              , ix, &sc->sc_dpring[ix]
++                              , (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr
++                              , sc->sc_dpring[ix].pd_flags
++                      );
++                      if (++ix == SAFE_TOTAL_DPART)
++                              ix = 0;
++              }
++      }
++      printf("sa: cmd0 %08x cmd1 %08x staterec %x\n",
++              re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec);
++      printf("sa: key %x %x %x %x %x %x %x %x\n"
++              , re->re_sa.sa_key[0]
++              , re->re_sa.sa_key[1]
++              , re->re_sa.sa_key[2]
++              , re->re_sa.sa_key[3]
++              , re->re_sa.sa_key[4]
++              , re->re_sa.sa_key[5]
++              , re->re_sa.sa_key[6]
++              , re->re_sa.sa_key[7]
++      );
++      printf("sa: indigest %x %x %x %x %x\n"
++              , re->re_sa.sa_indigest[0]
++              , re->re_sa.sa_indigest[1]
++              , re->re_sa.sa_indigest[2]
++              , re->re_sa.sa_indigest[3]
++              , re->re_sa.sa_indigest[4]
++      );
++      printf("sa: outdigest %x %x %x %x %x\n"
++              , re->re_sa.sa_outdigest[0]
++              , re->re_sa.sa_outdigest[1]
++              , re->re_sa.sa_outdigest[2]
++              , re->re_sa.sa_outdigest[3]
++              , re->re_sa.sa_outdigest[4]
++      );
++      printf("sr: iv %x %x %x %x\n"
++              , re->re_sastate.sa_saved_iv[0]
++              , re->re_sastate.sa_saved_iv[1]
++              , re->re_sastate.sa_saved_iv[2]
++              , re->re_sastate.sa_saved_iv[3]
++      );
++      printf("sr: hashbc %u indigest %x %x %x %x %x\n"
++              , re->re_sastate.sa_saved_hashbc
++              , re->re_sastate.sa_saved_indigest[0]
++              , re->re_sastate.sa_saved_indigest[1]
++              , re->re_sastate.sa_saved_indigest[2]
++              , re->re_sastate.sa_saved_indigest[3]
++              , re->re_sastate.sa_saved_indigest[4]
++      );
++}
++
++static void
++safe_dump_ring(struct safe_softc *sc, const char *tag)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&sc->sc_ringmtx, flags);
++      printf("\nSafeNet Ring State:\n");
++      safe_dump_intrstate(sc, tag);
++      safe_dump_dmastatus(sc, tag);
++      safe_dump_ringstate(sc, tag);
++      if (sc->sc_nqchip) {
++              struct safe_ringentry *re = sc->sc_back;
++              do {
++                      safe_dump_request(sc, tag, re);
++                      if (++re == sc->sc_ringtop)
++                              re = sc->sc_ring;
++              } while (re != sc->sc_front);
++      }
++      spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++}
++#endif /* SAFE_DEBUG */
++
++
++static int safe_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++      struct safe_softc *sc = NULL;
++      u32 mem_start, mem_len, cmd;
++      int i, rc, devinfo;
++      dma_addr_t raddr;
++      static int num_chips = 0;
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      if (pci_enable_device(dev) < 0)
++              return(-ENODEV);
++
++      if (!dev->irq) {
++              printk("safe: found device with no IRQ assigned. check BIOS settings!");
++              pci_disable_device(dev);
++              return(-ENODEV);
++      }
++
++      if (pci_set_mwi(dev)) {
++              printk("safe: pci_set_mwi failed!");
++              return(-ENODEV);
++      }
++
++      sc = (struct safe_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++      if (!sc)
++              return(-ENOMEM);
++      memset(sc, 0, sizeof(*sc));
++
++      softc_device_init(sc, "safe", num_chips, safe_methods);
++
++      sc->sc_irq = -1;
++      sc->sc_cid = -1;
++      sc->sc_pcidev = dev;
++      if (num_chips < SAFE_MAX_CHIPS) {
++              safe_chip_idx[device_get_unit(sc->sc_dev)] = sc;
++              num_chips++;
++      }
++
++      INIT_LIST_HEAD(&sc->sc_pkq);
++      spin_lock_init(&sc->sc_pkmtx);
++
++      pci_set_drvdata(sc->sc_pcidev, sc);
++
++      /* we read its hardware registers as memory */
++      mem_start = pci_resource_start(sc->sc_pcidev, 0);
++      mem_len   = pci_resource_len(sc->sc_pcidev, 0);
++
++      sc->sc_base_addr = (ocf_iomem_t) ioremap(mem_start, mem_len);
++      if (!sc->sc_base_addr) {
++              device_printf(sc->sc_dev, "failed to ioremap 0x%x-0x%x\n",
++                              mem_start, mem_start + mem_len - 1);
++              goto out;
++      }
++
++      /* fix up the bus size */
++      if (pci_set_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) {
++              device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n");
++              goto out;
++      }
++      if (pci_set_consistent_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) {
++              device_printf(sc->sc_dev, "No usable consistent DMA configuration, aborting.\n");
++              goto out;
++      }
++
++      pci_set_master(sc->sc_pcidev);
++
++      pci_read_config_dword(sc->sc_pcidev, PCI_COMMAND, &cmd);
++
++      if (!(cmd & PCI_COMMAND_MEMORY)) {
++              device_printf(sc->sc_dev, "failed to enable memory mapping\n");
++              goto out;
++      }
++
++      if (!(cmd & PCI_COMMAND_MASTER)) {
++              device_printf(sc->sc_dev, "failed to enable bus mastering\n");
++              goto out;
++      }
++
++      rc = request_irq(dev->irq, safe_intr, IRQF_SHARED, "safe", sc);
++      if (rc) {
++              device_printf(sc->sc_dev, "failed to hook irq %d\n", sc->sc_irq);
++              goto out;
++      }
++      sc->sc_irq = dev->irq;
++
++      sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) &
++                      (SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN);
++
++      /*
++       * Allocate packet engine descriptors.
++       */
++      sc->sc_ringalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++                      SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++                      &sc->sc_ringalloc.dma_paddr);
++      if (!sc->sc_ringalloc.dma_vaddr) {
++              device_printf(sc->sc_dev, "cannot allocate PE descriptor ring\n");
++              goto out;
++      }
++
++      /*
++       * Hookup the static portion of all our data structures.
++       */
++      sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr;
++      sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE;
++      sc->sc_front = sc->sc_ring;
++      sc->sc_back = sc->sc_ring;
++      raddr = sc->sc_ringalloc.dma_paddr;
++      bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry));
++      for (i = 0; i < SAFE_MAX_NQUEUE; i++) {
++              struct safe_ringentry *re = &sc->sc_ring[i];
++
++              re->re_desc.d_sa = raddr +
++                      offsetof(struct safe_ringentry, re_sa);
++              re->re_sa.sa_staterec = raddr +
++                      offsetof(struct safe_ringentry, re_sastate);
++
++              raddr += sizeof (struct safe_ringentry);
++      }
++      spin_lock_init(&sc->sc_ringmtx);
++
++      /*
++       * Allocate scatter and gather particle descriptors.
++       */
++      sc->sc_spalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++                      SAFE_TOTAL_SPART * sizeof (struct safe_pdesc),
++                      &sc->sc_spalloc.dma_paddr);
++      if (!sc->sc_spalloc.dma_vaddr) {
++              device_printf(sc->sc_dev, "cannot allocate source particle descriptor ring\n");
++              goto out;
++      }
++      sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr;
++      sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART;
++      sc->sc_spfree = sc->sc_spring;
++      bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc));
++
++      sc->sc_dpalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++                      SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++                      &sc->sc_dpalloc.dma_paddr);
++      if (!sc->sc_dpalloc.dma_vaddr) {
++              device_printf(sc->sc_dev, "cannot allocate destination particle descriptor ring\n");
++              goto out;
++      }
++      sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr;
++      sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART;
++      sc->sc_dpfree = sc->sc_dpring;
++      bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc));
++
++      sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE);
++      if (sc->sc_cid < 0) {
++              device_printf(sc->sc_dev, "could not get crypto driver id\n");
++              goto out;
++      }
++
++      printf("%s:", device_get_nameunit(sc->sc_dev));
++
++      devinfo = READ_REG(sc, SAFE_DEVINFO);
++      if (devinfo & SAFE_DEVINFO_RNG) {
++              sc->sc_flags |= SAFE_FLAGS_RNG;
++              printf(" rng");
++      }
++      if (devinfo & SAFE_DEVINFO_PKEY) {
++              printf(" key");
++              sc->sc_flags |= SAFE_FLAGS_KEY;
++              crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0);
++#if 0
++              crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0);
++#endif
++              init_timer(&sc->sc_pkto);
++              sc->sc_pkto.function = safe_kpoll;
++              sc->sc_pkto.data = (unsigned long) device_get_unit(sc->sc_dev);
++      }
++      if (devinfo & SAFE_DEVINFO_DES) {
++              printf(" des/3des");
++              crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++      }
++      if (devinfo & SAFE_DEVINFO_AES) {
++              printf(" aes");
++              crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++      }
++      if (devinfo & SAFE_DEVINFO_MD5) {
++              printf(" md5");
++              crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++      }
++      if (devinfo & SAFE_DEVINFO_SHA1) {
++              printf(" sha1");
++              crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++      }
++      printf(" null");
++      crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0);
++      /* XXX other supported algorithms */
++      printf("\n");
++
++      safe_reset_board(sc);           /* reset h/w */
++      safe_init_board(sc);            /* init h/w */
++
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++      if (sc->sc_flags & SAFE_FLAGS_RNG) {
++              safe_rng_init(sc);
++              crypto_rregister(sc->sc_cid, safe_read_random, sc);
++      }
++#endif /* SAFE_NO_RNG */
++
++      return (0);
++
++out:
++      if (sc->sc_cid >= 0)
++              crypto_unregister_all(sc->sc_cid);
++      if (sc->sc_irq != -1)
++              free_irq(sc->sc_irq, sc);
++      if (sc->sc_ringalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++                              sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr);
++      if (sc->sc_spalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++                              sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr);
++      if (sc->sc_dpalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++                              sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr);
++      kfree(sc);
++      return(-ENODEV);
++}
++
++static void safe_remove(struct pci_dev *dev)
++{
++      struct safe_softc *sc = pci_get_drvdata(dev);
++
++      DPRINTF(("%s()\n", __FUNCTION__));
++
++      /* XXX wait/abort active ops */
++
++      WRITE_REG(sc, SAFE_HI_MASK, 0);         /* disable interrupts */
++
++      del_timer_sync(&sc->sc_pkto);
++
++      crypto_unregister_all(sc->sc_cid);
++
++      safe_cleanchip(sc);
++
++      if (sc->sc_irq != -1)
++              free_irq(sc->sc_irq, sc);
++      if (sc->sc_ringalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++                              sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr);
++      if (sc->sc_spalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++                              sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr);
++      if (sc->sc_dpalloc.dma_vaddr)
++              pci_free_consistent(sc->sc_pcidev,
++                              SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++                              sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr);
++      sc->sc_irq = -1;
++      sc->sc_ringalloc.dma_vaddr = NULL;
++      sc->sc_spalloc.dma_vaddr = NULL;
++      sc->sc_dpalloc.dma_vaddr = NULL;
++}
++
++static struct pci_device_id safe_pci_tbl[] = {
++      { PCI_VENDOR_SAFENET, PCI_PRODUCT_SAFEXCEL,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++      { },
++};
++MODULE_DEVICE_TABLE(pci, safe_pci_tbl);
++
++static struct pci_driver safe_driver = {
++      .name         = "safe",
++      .id_table     = safe_pci_tbl,
++      .probe        = safe_probe,
++      .remove       = safe_remove,
++      /* add PM stuff here one day */
++};
++
++static int __init safe_init (void)
++{
++      struct safe_softc *sc = NULL;
++      int rc;
++
++      DPRINTF(("%s(%p)\n", __FUNCTION__, safe_init));
++
++      rc = pci_register_driver(&safe_driver);
++      pci_register_driver_compat(&safe_driver, rc);
++
++      return rc;
++}
++
++static void __exit safe_exit (void)
++{
++      pci_unregister_driver(&safe_driver);
++}
++
++module_init(safe_init);
++module_exit(safe_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("OCF driver for safenet PCI crypto devices");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/sha1.c       2005-05-20 10:30:53.000000000 +1000
+@@ -0,0 +1,279 @@
++/*    $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $    */
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the project nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/*
++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
++ * based on: http://csrc.nist.gov/fips/fip180-1.txt
++ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
++ */
++
++#if 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/crypto/sha1.c,v 1.9 2003/06/10 21:36:57 obrien Exp $");
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++#include <sys/time.h>
++#include <sys/systm.h>
++
++#include <crypto/sha1.h>
++#endif
++
++/* sanity check */
++#if BYTE_ORDER != BIG_ENDIAN
++# if BYTE_ORDER != LITTLE_ENDIAN
++#  define unsupported 1
++# endif
++#endif
++
++#ifndef unsupported
++
++/* constant table */
++static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
++#define       K(t)    _K[(t) / 20]
++
++#define       F0(b, c, d)     (((b) & (c)) | ((~(b)) & (d)))
++#define       F1(b, c, d)     (((b) ^ (c)) ^ (d))
++#define       F2(b, c, d)     (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
++#define       F3(b, c, d)     (((b) ^ (c)) ^ (d))
++
++#define       S(n, x)         (((x) << (n)) | ((x) >> (32 - n)))
++
++#undef H
++#define       H(n)    (ctxt->h.b32[(n)])
++#define       COUNT   (ctxt->count)
++#define       BCOUNT  (ctxt->c.b64[0] / 8)
++#define       W(n)    (ctxt->m.b32[(n)])
++
++#define       PUTBYTE(x)      { \
++      ctxt->m.b8[(COUNT % 64)] = (x);         \
++      COUNT++;                                \
++      COUNT %= 64;                            \
++      ctxt->c.b64[0] += 8;                    \
++      if (COUNT % 64 == 0)                    \
++              sha1_step(ctxt);                \
++     }
++
++#define       PUTPAD(x)       { \
++      ctxt->m.b8[(COUNT % 64)] = (x);         \
++      COUNT++;                                \
++      COUNT %= 64;                            \
++      if (COUNT % 64 == 0)                    \
++              sha1_step(ctxt);                \
++     }
++
++static void sha1_step(struct sha1_ctxt *);
++
++static void
++sha1_step(ctxt)
++      struct sha1_ctxt *ctxt;
++{
++      u_int32_t       a, b, c, d, e;
++      size_t t, s;
++      u_int32_t       tmp;
++
++#if BYTE_ORDER == LITTLE_ENDIAN
++      struct sha1_ctxt tctxt;
++      bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64);
++      ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
++      ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
++      ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
++      ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
++      ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
++      ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
++      ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
++      ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
++      ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
++      ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
++      ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
++      ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
++      ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
++      ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
++      ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
++      ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
++      ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
++      ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
++      ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
++      ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
++      ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
++      ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
++      ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
++      ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
++      ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
++      ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
++      ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
++      ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
++      ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
++      ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
++      ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
++      ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
++#endif
++
++      a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
++
++      for (t = 0; t < 20; t++) {
++              s = t & 0x0f;
++              if (t >= 16) {
++                      W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++              }
++              tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
++              e = d; d = c; c = S(30, b); b = a; a = tmp;
++      }
++      for (t = 20; t < 40; t++) {
++              s = t & 0x0f;
++              W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++              tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
++              e = d; d = c; c = S(30, b); b = a; a = tmp;
++      }
++      for (t = 40; t < 60; t++) {
++              s = t & 0x0f;
++              W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++              tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
++              e = d; d = c; c = S(30, b); b = a; a = tmp;
++      }
++      for (t = 60; t < 80; t++) {
++              s = t & 0x0f;
++              W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++              tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
++              e = d; d = c; c = S(30, b); b = a; a = tmp;
++      }
++
++      H(0) = H(0) + a;
++      H(1) = H(1) + b;
++      H(2) = H(2) + c;
++      H(3) = H(3) + d;
++      H(4) = H(4) + e;
++
++      bzero(&ctxt->m.b8[0], 64);
++}
++
++/*------------------------------------------------------------*/
++
++void
++sha1_init(ctxt)
++      struct sha1_ctxt *ctxt;
++{
++      bzero(ctxt, sizeof(struct sha1_ctxt));
++      H(0) = 0x67452301;
++      H(1) = 0xefcdab89;
++      H(2) = 0x98badcfe;
++      H(3) = 0x10325476;
++      H(4) = 0xc3d2e1f0;
++}
++
++void
++sha1_pad(ctxt)
++      struct sha1_ctxt *ctxt;
++{
++      size_t padlen;          /*pad length in bytes*/
++      size_t padstart;
++
++      PUTPAD(0x80);
++
++      padstart = COUNT % 64;
++      padlen = 64 - padstart;
++      if (padlen < 8) {
++              bzero(&ctxt->m.b8[padstart], padlen);
++              COUNT += padlen;
++              COUNT %= 64;
++              sha1_step(ctxt);
++              padstart = COUNT % 64;  /* should be 0 */
++              padlen = 64 - padstart; /* should be 64 */
++      }
++      bzero(&ctxt->m.b8[padstart], padlen - 8);
++      COUNT += (padlen - 8);
++      COUNT %= 64;
++#if BYTE_ORDER == BIG_ENDIAN
++      PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
++      PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
++      PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
++      PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
++#else
++      PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
++      PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
++      PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
++      PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
++#endif
++}
++
++void
++sha1_loop(ctxt, input, len)
++      struct sha1_ctxt *ctxt;
++      const u_int8_t *input;
++      size_t len;
++{
++      size_t gaplen;
++      size_t gapstart;
++      size_t off;
++      size_t copysiz;
++
++      off = 0;
++
++      while (off < len) {
++              gapstart = COUNT % 64;
++              gaplen = 64 - gapstart;
++
++              copysiz = (gaplen < len - off) ? gaplen : len - off;
++              bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz);
++              COUNT += copysiz;
++              COUNT %= 64;
++              ctxt->c.b64[0] += copysiz * 8;
++              if (COUNT % 64 == 0)
++                      sha1_step(ctxt);
++              off += copysiz;
++      }
++}
++
++void
++sha1_result(ctxt, digest0)
++      struct sha1_ctxt *ctxt;
++      caddr_t digest0;
++{
++      u_int8_t *digest;
++
++      digest = (u_int8_t *)digest0;
++      sha1_pad(ctxt);
++#if BYTE_ORDER == BIG_ENDIAN
++      bcopy(&ctxt->h.b8[0], digest, 20);
++#else
++      digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
++      digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
++      digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
++      digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
++      digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
++      digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
++      digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
++      digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
++      digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
++      digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
++#endif
++}
++
++#endif /*unsupported*/
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/sha1.h       2005-05-20 10:30:53.000000000 +1000
+@@ -0,0 +1,72 @@
++/*    $FreeBSD: src/sys/crypto/sha1.h,v 1.8 2002/03/20 05:13:50 alfred Exp $  */
++/*    $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $  */
++
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the project nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++/*
++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
++ * based on: http://csrc.nist.gov/fips/fip180-1.txt
++ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
++ */
++
++#ifndef _NETINET6_SHA1_H_
++#define _NETINET6_SHA1_H_
++
++struct sha1_ctxt {
++      union {
++              u_int8_t        b8[20];
++              u_int32_t       b32[5];
++      } h;
++      union {
++              u_int8_t        b8[8];
++              u_int64_t       b64[1];
++      } c;
++      union {
++              u_int8_t        b8[64];
++              u_int32_t       b32[16];
++      } m;
++      u_int8_t        count;
++};
++
++#ifdef __KERNEL__
++extern void sha1_init(struct sha1_ctxt *);
++extern void sha1_pad(struct sha1_ctxt *);
++extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t);
++extern void sha1_result(struct sha1_ctxt *, caddr_t);
++
++/* compatibilty with other SHA1 source codes */
++typedef struct sha1_ctxt SHA1_CTX;
++#define SHA1Init(x)           sha1_init((x))
++#define SHA1Update(x, y, z)   sha1_loop((x), (y), (z))
++#define SHA1Final(x, y)               sha1_result((y), (x))
++#endif /* __KERNEL__ */
++
++#define       SHA1_RESULTLEN  (160/8)
++
++#endif /*_NETINET6_SHA1_H_*/
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/safereg.h    2005-03-16 15:19:57.000000000 +1000
+@@ -0,0 +1,421 @@
++/*-
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * $FreeBSD: src/sys/dev/safe/safereg.h,v 1.1 2003/07/21 21:46:07 sam Exp $
++ */
++#ifndef _SAFE_SAFEREG_H_
++#define       _SAFE_SAFEREG_H_
++
++/*
++ * Register definitions for SafeNet SafeXcel-1141 crypto device.
++ * Definitions from revision 1.3 (Nov 6 2002) of the User's Manual.
++ */
++
++#define BS_BAR                        0x10    /* DMA base address register */
++#define       BS_TRDY_TIMEOUT         0x40    /* TRDY timeout */
++#define       BS_RETRY_TIMEOUT        0x41    /* DMA retry timeout */
++
++#define       PCI_VENDOR_SAFENET      0x16ae          /* SafeNet, Inc. */
++
++/* SafeNet */
++#define       PCI_PRODUCT_SAFEXCEL    0x1141          /* 1141 */
++
++#define       SAFE_PE_CSR             0x0000  /* Packet Enginge Ctrl/Status */
++#define       SAFE_PE_SRC             0x0004  /* Packet Engine Source */
++#define       SAFE_PE_DST             0x0008  /* Packet Engine Destination */
++#define       SAFE_PE_SA              0x000c  /* Packet Engine SA */
++#define       SAFE_PE_LEN             0x0010  /* Packet Engine Length */
++#define       SAFE_PE_DMACFG          0x0040  /* Packet Engine DMA Configuration */
++#define       SAFE_PE_DMASTAT         0x0044  /* Packet Engine DMA Status */
++#define       SAFE_PE_PDRBASE         0x0048  /* Packet Engine Descriptor Ring Base */
++#define       SAFE_PE_RDRBASE         0x004c  /* Packet Engine Result Ring Base */
++#define       SAFE_PE_RINGCFG         0x0050  /* Packet Engine Ring Configuration */
++#define       SAFE_PE_RINGPOLL        0x0054  /* Packet Engine Ring Poll */
++#define       SAFE_PE_IRNGSTAT        0x0058  /* Packet Engine Internal Ring Status */
++#define       SAFE_PE_ERNGSTAT        0x005c  /* Packet Engine External Ring Status */
++#define       SAFE_PE_IOTHRESH        0x0060  /* Packet Engine I/O Threshold */
++#define       SAFE_PE_GRNGBASE        0x0064  /* Packet Engine Gather Ring Base */
++#define       SAFE_PE_SRNGBASE        0x0068  /* Packet Engine Scatter Ring Base */
++#define       SAFE_PE_PARTSIZE        0x006c  /* Packet Engine Particlar Ring Size */
++#define       SAFE_PE_PARTCFG         0x0070  /* Packet Engine Particle Ring Config */
++#define       SAFE_CRYPTO_CTRL        0x0080  /* Crypto Control */
++#define       SAFE_DEVID              0x0084  /* Device ID */
++#define       SAFE_DEVINFO            0x0088  /* Device Info */
++#define       SAFE_HU_STAT            0x00a0  /* Host Unmasked Status */
++#define       SAFE_HM_STAT            0x00a4  /* Host Masked Status (read-only) */
++#define       SAFE_HI_CLR             0x00a4  /* Host Clear Interrupt (write-only) */
++#define       SAFE_HI_MASK            0x00a8  /* Host Mask Control */
++#define       SAFE_HI_CFG             0x00ac  /* Interrupt Configuration */
++#define       SAFE_HI_RD_DESCR        0x00b4  /* Force Descriptor Read */
++#define       SAFE_HI_DESC_CNT        0x00b8  /* Host Descriptor Done Count */
++#define       SAFE_DMA_ENDIAN         0x00c0  /* Master Endian Status */
++#define       SAFE_DMA_SRCADDR        0x00c4  /* DMA Source Address Status */
++#define       SAFE_DMA_DSTADDR        0x00c8  /* DMA Destination Address Status */
++#define       SAFE_DMA_STAT           0x00cc  /* DMA Current Status */
++#define       SAFE_DMA_CFG            0x00d4  /* DMA Configuration/Status */
++#define       SAFE_ENDIAN             0x00e0  /* Endian Configuration */
++#define       SAFE_PK_A_ADDR          0x0800  /* Public Key A Address */
++#define       SAFE_PK_B_ADDR          0x0804  /* Public Key B Address */
++#define       SAFE_PK_C_ADDR          0x0808  /* Public Key C Address */
++#define       SAFE_PK_D_ADDR          0x080c  /* Public Key D Address */
++#define       SAFE_PK_A_LEN           0x0810  /* Public Key A Length */
++#define       SAFE_PK_B_LEN           0x0814  /* Public Key B Length */
++#define       SAFE_PK_SHIFT           0x0818  /* Public Key Shift */
++#define       SAFE_PK_FUNC            0x081c  /* Public Key Function */
++#define SAFE_PK_RAM_START     0x1000  /* Public Key RAM start address */
++#define SAFE_PK_RAM_END               0x1fff  /* Public Key RAM end address */
++
++#define       SAFE_RNG_OUT            0x0100  /* RNG Output */
++#define       SAFE_RNG_STAT           0x0104  /* RNG Status */
++#define       SAFE_RNG_CTRL           0x0108  /* RNG Control */
++#define       SAFE_RNG_A              0x010c  /* RNG A */
++#define       SAFE_RNG_B              0x0110  /* RNG B */
++#define       SAFE_RNG_X_LO           0x0114  /* RNG X [31:0] */
++#define       SAFE_RNG_X_MID          0x0118  /* RNG X [63:32] */
++#define       SAFE_RNG_X_HI           0x011c  /* RNG X [80:64] */
++#define       SAFE_RNG_X_CNTR         0x0120  /* RNG Counter */
++#define       SAFE_RNG_ALM_CNT        0x0124  /* RNG Alarm Count */
++#define       SAFE_RNG_CNFG           0x0128  /* RNG Configuration */
++#define       SAFE_RNG_LFSR1_LO       0x012c  /* RNG LFSR1 [31:0] */
++#define       SAFE_RNG_LFSR1_HI       0x0130  /* RNG LFSR1 [47:32] */
++#define       SAFE_RNG_LFSR2_LO       0x0134  /* RNG LFSR1 [31:0] */
++#define       SAFE_RNG_LFSR2_HI       0x0138  /* RNG LFSR1 [47:32] */
++
++#define       SAFE_PE_CSR_READY       0x00000001      /* ready for processing */
++#define       SAFE_PE_CSR_DONE        0x00000002      /* h/w completed processing */
++#define       SAFE_PE_CSR_LOADSA      0x00000004      /* load SA digests */
++#define       SAFE_PE_CSR_HASHFINAL   0x00000010      /* do hash pad & write result */
++#define       SAFE_PE_CSR_SABUSID     0x000000c0      /* bus id for SA */
++#define       SAFE_PE_CSR_SAPCI       0x00000040      /* PCI bus id for SA */
++#define       SAFE_PE_CSR_NXTHDR      0x0000ff00      /* next hdr value for IPsec */
++#define       SAFE_PE_CSR_FPAD        0x0000ff00      /* fixed pad for basic ops */
++#define       SAFE_PE_CSR_STATUS      0x00ff0000      /* operation result status */
++#define       SAFE_PE_CSR_AUTH_FAIL   0x00010000      /* ICV mismatch (inbound) */
++#define       SAFE_PE_CSR_PAD_FAIL    0x00020000      /* pad verify fail (inbound) */
++#define       SAFE_PE_CSR_SEQ_FAIL    0x00040000      /* sequence number (inbound) */
++#define       SAFE_PE_CSR_XERROR      0x00080000      /* extended error follows */
++#define       SAFE_PE_CSR_XECODE      0x00f00000      /* extended error code */
++#define       SAFE_PE_CSR_XECODE_S    20
++#define       SAFE_PE_CSR_XECODE_BADCMD       0       /* invalid command */
++#define       SAFE_PE_CSR_XECODE_BADALG       1       /* invalid algorithm */
++#define       SAFE_PE_CSR_XECODE_ALGDIS       2       /* algorithm disabled */
++#define       SAFE_PE_CSR_XECODE_ZEROLEN      3       /* zero packet length */
++#define       SAFE_PE_CSR_XECODE_DMAERR       4       /* bus DMA error */
++#define       SAFE_PE_CSR_XECODE_PIPEABORT    5       /* secondary bus DMA error */
++#define       SAFE_PE_CSR_XECODE_BADSPI       6       /* IPsec SPI mismatch */
++#define       SAFE_PE_CSR_XECODE_TIMEOUT      10      /* failsafe timeout */
++#define       SAFE_PE_CSR_PAD         0xff000000      /* ESP padding control/status */
++#define       SAFE_PE_CSR_PAD_MIN     0x00000000      /* minimum IPsec padding */
++#define       SAFE_PE_CSR_PAD_16      0x08000000      /* pad to 16-byte boundary */
++#define       SAFE_PE_CSR_PAD_32      0x10000000      /* pad to 32-byte boundary */
++#define       SAFE_PE_CSR_PAD_64      0x20000000      /* pad to 64-byte boundary */
++#define       SAFE_PE_CSR_PAD_128     0x40000000      /* pad to 128-byte boundary */
++#define       SAFE_PE_CSR_PAD_256     0x80000000      /* pad to 256-byte boundary */
++
++/*
++ * Check the CSR to see if the PE has returned ownership to
++ * the host.  Note that before processing a descriptor this
++ * must be done followed by a check of the SAFE_PE_LEN register
++ * status bits to avoid premature processing of a descriptor
++ * on its way back to the host.
++ */
++#define       SAFE_PE_CSR_IS_DONE(_csr) \
++    (((_csr) & (SAFE_PE_CSR_READY | SAFE_PE_CSR_DONE)) == SAFE_PE_CSR_DONE)
++
++#define       SAFE_PE_LEN_LENGTH      0x000fffff      /* total length (bytes) */
++#define       SAFE_PE_LEN_READY       0x00400000      /* ready for processing */
++#define       SAFE_PE_LEN_DONE        0x00800000      /* h/w completed processing */
++#define       SAFE_PE_LEN_BYPASS      0xff000000      /* bypass offset (bytes) */
++#define       SAFE_PE_LEN_BYPASS_S    24
++
++#define       SAFE_PE_LEN_IS_DONE(_len) \
++    (((_len) & (SAFE_PE_LEN_READY | SAFE_PE_LEN_DONE)) == SAFE_PE_LEN_DONE)
++
++/* NB: these apply to HU_STAT, HM_STAT, HI_CLR, and HI_MASK */
++#define       SAFE_INT_PE_CDONE       0x00000002      /* PE context done */
++#define       SAFE_INT_PE_DDONE       0x00000008      /* PE descriptor done */
++#define       SAFE_INT_PE_ERROR       0x00000010      /* PE error */
++#define       SAFE_INT_PE_ODONE       0x00000020      /* PE operation done */
++
++#define       SAFE_HI_CFG_PULSE       0x00000001      /* use pulse interrupt */
++#define       SAFE_HI_CFG_LEVEL       0x00000000      /* use level interrupt */
++#define       SAFE_HI_CFG_AUTOCLR     0x00000002      /* auto-clear pulse interrupt */
++
++#define       SAFE_ENDIAN_PASS        0x000000e4      /* straight pass-thru */
++#define       SAFE_ENDIAN_SWAB        0x0000001b      /* swap bytes in 32-bit word */
++
++#define       SAFE_PE_DMACFG_PERESET  0x00000001      /* reset packet engine */
++#define       SAFE_PE_DMACFG_PDRRESET 0x00000002      /* reset PDR counters/ptrs */
++#define       SAFE_PE_DMACFG_SGRESET  0x00000004      /* reset scatter/gather cache */
++#define       SAFE_PE_DMACFG_FSENA    0x00000008      /* enable failsafe reset */
++#define       SAFE_PE_DMACFG_PEMODE   0x00000100      /* packet engine mode */
++#define       SAFE_PE_DMACFG_SAPREC   0x00000200      /* SA precedes packet */
++#define       SAFE_PE_DMACFG_PKFOLL   0x00000400      /* packet follows descriptor */
++#define       SAFE_PE_DMACFG_GPRBID   0x00003000      /* gather particle ring busid */
++#define       SAFE_PE_DMACFG_GPRPCI   0x00001000      /* PCI gather particle ring */
++#define       SAFE_PE_DMACFG_SPRBID   0x0000c000      /* scatter part. ring busid */
++#define       SAFE_PE_DMACFG_SPRPCI   0x00004000      /* PCI scatter part. ring */
++#define       SAFE_PE_DMACFG_ESDESC   0x00010000      /* endian swap descriptors */
++#define       SAFE_PE_DMACFG_ESSA     0x00020000      /* endian swap SA data */
++#define       SAFE_PE_DMACFG_ESPACKET 0x00040000      /* endian swap packet data */
++#define       SAFE_PE_DMACFG_ESPDESC  0x00080000      /* endian swap particle desc. */
++#define       SAFE_PE_DMACFG_NOPDRUP  0x00100000      /* supp. PDR ownership update */
++#define       SAFE_PD_EDMACFG_PCIMODE 0x01000000      /* PCI target mode */
++
++#define       SAFE_PE_DMASTAT_PEIDONE 0x00000001      /* PE core input done */
++#define       SAFE_PE_DMASTAT_PEODONE 0x00000002      /* PE core output done */
++#define       SAFE_PE_DMASTAT_ENCDONE 0x00000004      /* encryption done */
++#define       SAFE_PE_DMASTAT_IHDONE  0x00000008      /* inner hash done */
++#define       SAFE_PE_DMASTAT_OHDONE  0x00000010      /* outer hash (HMAC) done */
++#define       SAFE_PE_DMASTAT_PADFLT  0x00000020      /* crypto pad fault */
++#define       SAFE_PE_DMASTAT_ICVFLT  0x00000040      /* ICV fault */
++#define       SAFE_PE_DMASTAT_SPIMIS  0x00000080      /* SPI mismatch */
++#define       SAFE_PE_DMASTAT_CRYPTO  0x00000100      /* crypto engine timeout */
++#define       SAFE_PE_DMASTAT_CQACT   0x00000200      /* command queue active */
++#define       SAFE_PE_DMASTAT_IRACT   0x00000400      /* input request active */
++#define       SAFE_PE_DMASTAT_ORACT   0x00000800      /* output request active */
++#define       SAFE_PE_DMASTAT_PEISIZE 0x003ff000      /* PE input size:32-bit words */
++#define       SAFE_PE_DMASTAT_PEOSIZE 0xffc00000      /* PE out. size:32-bit words */
++
++#define       SAFE_PE_RINGCFG_SIZE    0x000003ff      /* ring size (descriptors) */
++#define       SAFE_PE_RINGCFG_OFFSET  0xffff0000      /* offset btw desc's (dwords) */
++#define       SAFE_PE_RINGCFG_OFFSET_S        16
++
++#define       SAFE_PE_RINGPOLL_POLL   0x00000fff      /* polling frequency/divisor */
++#define       SAFE_PE_RINGPOLL_RETRY  0x03ff0000      /* polling frequency/divisor */
++#define       SAFE_PE_RINGPOLL_CONT   0x80000000      /* continuously poll */
++
++#define       SAFE_PE_IRNGSTAT_CQAVAIL 0x00000001     /* command queue available */
++
++#define       SAFE_PE_ERNGSTAT_NEXT   0x03ff0000      /* index of next packet desc. */
++#define       SAFE_PE_ERNGSTAT_NEXT_S 16
++
++#define       SAFE_PE_IOTHRESH_INPUT  0x000003ff      /* input threshold (dwords) */
++#define       SAFE_PE_IOTHRESH_OUTPUT 0x03ff0000      /* output threshold (dwords) */
++
++#define       SAFE_PE_PARTCFG_SIZE    0x0000ffff      /* scatter particle size */
++#define       SAFE_PE_PARTCFG_GBURST  0x00030000      /* gather particle burst */
++#define       SAFE_PE_PARTCFG_GBURST_2        0x00000000
++#define       SAFE_PE_PARTCFG_GBURST_4        0x00010000
++#define       SAFE_PE_PARTCFG_GBURST_8        0x00020000
++#define       SAFE_PE_PARTCFG_GBURST_16       0x00030000
++#define       SAFE_PE_PARTCFG_SBURST  0x000c0000      /* scatter particle burst */
++#define       SAFE_PE_PARTCFG_SBURST_2        0x00000000
++#define       SAFE_PE_PARTCFG_SBURST_4        0x00040000
++#define       SAFE_PE_PARTCFG_SBURST_8        0x00080000
++#define       SAFE_PE_PARTCFG_SBURST_16       0x000c0000
++
++#define       SAFE_PE_PARTSIZE_SCAT   0xffff0000      /* scatter particle ring size */
++#define       SAFE_PE_PARTSIZE_GATH   0x0000ffff      /* gather particle ring size */
++
++#define       SAFE_CRYPTO_CTRL_3DES   0x00000001      /* enable 3DES support */
++#define       SAFE_CRYPTO_CTRL_PKEY   0x00010000      /* enable public key support */
++#define       SAFE_CRYPTO_CTRL_RNG    0x00020000      /* enable RNG support */
++
++#define       SAFE_DEVINFO_REV_MIN    0x0000000f      /* minor rev for chip */
++#define       SAFE_DEVINFO_REV_MAJ    0x000000f0      /* major rev for chip */
++#define       SAFE_DEVINFO_REV_MAJ_S  4
++#define       SAFE_DEVINFO_DES        0x00000100      /* DES/3DES support present */
++#define       SAFE_DEVINFO_ARC4       0x00000200      /* ARC4 support present */
++#define       SAFE_DEVINFO_AES        0x00000400      /* AES support present */
++#define       SAFE_DEVINFO_MD5        0x00001000      /* MD5 support present */
++#define       SAFE_DEVINFO_SHA1       0x00002000      /* SHA-1 support present */
++#define       SAFE_DEVINFO_RIPEMD     0x00004000      /* RIPEMD support present */
++#define       SAFE_DEVINFO_DEFLATE    0x00010000      /* Deflate support present */
++#define       SAFE_DEVINFO_SARAM      0x00100000      /* on-chip SA RAM present */
++#define       SAFE_DEVINFO_EMIBUS     0x00200000      /* EMI bus present */
++#define       SAFE_DEVINFO_PKEY       0x00400000      /* public key support present */
++#define       SAFE_DEVINFO_RNG        0x00800000      /* RNG present */
++
++#define       SAFE_REV(_maj, _min)    (((_maj) << SAFE_DEVINFO_REV_MAJ_S) | (_min))
++#define       SAFE_REV_MAJ(_chiprev) \
++      (((_chiprev) & SAFE_DEVINFO_REV_MAJ) >> SAFE_DEVINFO_REV_MAJ_S)
++#define       SAFE_REV_MIN(_chiprev)  ((_chiprev) & SAFE_DEVINFO_REV_MIN)
++
++#define       SAFE_PK_FUNC_MULT       0x00000001      /* Multiply function */
++#define       SAFE_PK_FUNC_SQUARE     0x00000004      /* Square function */
++#define       SAFE_PK_FUNC_ADD        0x00000010      /* Add function */
++#define       SAFE_PK_FUNC_SUB        0x00000020      /* Subtract function */
++#define       SAFE_PK_FUNC_LSHIFT     0x00000040      /* Left-shift function */
++#define       SAFE_PK_FUNC_RSHIFT     0x00000080      /* Right-shift function */
++#define       SAFE_PK_FUNC_DIV        0x00000100      /* Divide function */
++#define       SAFE_PK_FUNC_CMP        0x00000400      /* Compare function */
++#define       SAFE_PK_FUNC_COPY       0x00000800      /* Copy function */
++#define       SAFE_PK_FUNC_EXP16      0x00002000      /* Exponentiate (4-bit ACT) */
++#define       SAFE_PK_FUNC_EXP4       0x00004000      /* Exponentiate (2-bit ACT) */
++#define       SAFE_PK_FUNC_RUN        0x00008000      /* start/status */
++
++#define       SAFE_RNG_STAT_BUSY      0x00000001      /* busy, data not valid */
++
++#define       SAFE_RNG_CTRL_PRE_LFSR  0x00000001      /* enable output pre-LFSR */
++#define       SAFE_RNG_CTRL_TST_MODE  0x00000002      /* enable test mode */
++#define       SAFE_RNG_CTRL_TST_RUN   0x00000004      /* start test state machine */
++#define       SAFE_RNG_CTRL_ENA_RING1 0x00000008      /* test entropy oscillator #1 */
++#define       SAFE_RNG_CTRL_ENA_RING2 0x00000010      /* test entropy oscillator #2 */
++#define       SAFE_RNG_CTRL_DIS_ALARM 0x00000020      /* disable RNG alarm reports */
++#define       SAFE_RNG_CTRL_TST_CLOCK 0x00000040      /* enable test clock */
++#define       SAFE_RNG_CTRL_SHORTEN   0x00000080      /* shorten state timers */
++#define       SAFE_RNG_CTRL_TST_ALARM 0x00000100      /* simulate alarm state */
++#define       SAFE_RNG_CTRL_RST_LFSR  0x00000200      /* reset LFSR */
++
++/*
++ * Packet engine descriptor.  Note that d_csr is a copy of the
++ * SAFE_PE_CSR register and all definitions apply, and d_len
++ * is a copy of the SAFE_PE_LEN register and all definitions apply.
++ * d_src and d_len may point directly to contiguous data or to a
++ * list of ``particle descriptors'' when using scatter/gather i/o.
++ */
++struct safe_desc {
++      u_int32_t       d_csr;                  /* per-packet control/status */
++      u_int32_t       d_src;                  /* source address */
++      u_int32_t       d_dst;                  /* destination address */
++      u_int32_t       d_sa;                   /* SA address */
++      u_int32_t       d_len;                  /* length, bypass, status */
++};
++
++/*
++ * Scatter/Gather particle descriptor.
++ *
++ * NB: scatter descriptors do not specify a size; this is fixed
++ *     by the setting of the SAFE_PE_PARTCFG register.
++ */
++struct safe_pdesc {
++      u_int32_t       pd_addr;                /* particle address */
++#ifdef __BIG_ENDIAN
++      u_int16_t       pd_flags;               /* control word */
++      u_int16_t       pd_size;                /* particle size (bytes) */
++#else
++      u_int16_t       pd_flags;               /* control word */
++      u_int16_t       pd_size;                /* particle size (bytes) */
++#endif
++};
++
++#define       SAFE_PD_READY   0x0001                  /* ready for processing */
++#define       SAFE_PD_DONE    0x0002                  /* h/w completed processing */
++
++/*
++ * Security Association (SA) Record (Rev 1).  One of these is
++ * required for each operation processed by the packet engine.
++ */
++struct safe_sarec {
++      u_int32_t       sa_cmd0;
++      u_int32_t       sa_cmd1;
++      u_int32_t       sa_resv0;
++      u_int32_t       sa_resv1;
++      u_int32_t       sa_key[8];              /* DES/3DES/AES key */
++      u_int32_t       sa_indigest[5];         /* inner digest */
++      u_int32_t       sa_outdigest[5];        /* outer digest */
++      u_int32_t       sa_spi;                 /* SPI */
++      u_int32_t       sa_seqnum;              /* sequence number */
++      u_int32_t       sa_seqmask[2];          /* sequence number mask */
++      u_int32_t       sa_resv2;
++      u_int32_t       sa_staterec;            /* address of state record */
++      u_int32_t       sa_resv3[2];
++      u_int32_t       sa_samgmt0;             /* SA management field 0 */
++      u_int32_t       sa_samgmt1;             /* SA management field 0 */
++};
++
++#define       SAFE_SA_CMD0_OP         0x00000007      /* operation code */
++#define       SAFE_SA_CMD0_OP_CRYPT   0x00000000      /* encrypt/decrypt (basic) */
++#define       SAFE_SA_CMD0_OP_BOTH    0x00000001      /* encrypt-hash/hash-decrypto */
++#define       SAFE_SA_CMD0_OP_HASH    0x00000003      /* hash (outbound-only) */
++#define       SAFE_SA_CMD0_OP_ESP     0x00000000      /* ESP in/out (proto) */
++#define       SAFE_SA_CMD0_OP_AH      0x00000001      /* AH in/out (proto) */
++#define       SAFE_SA_CMD0_INBOUND    0x00000008      /* inbound operation */
++#define       SAFE_SA_CMD0_OUTBOUND   0x00000000      /* outbound operation */
++#define       SAFE_SA_CMD0_GROUP      0x00000030      /* operation group */
++#define       SAFE_SA_CMD0_BASIC      0x00000000      /* basic operation */
++#define       SAFE_SA_CMD0_PROTO      0x00000010      /* protocol/packet operation */
++#define       SAFE_SA_CMD0_BUNDLE     0x00000020      /* bundled operation (resvd) */
++#define       SAFE_SA_CMD0_PAD        0x000000c0      /* crypto pad method */
++#define       SAFE_SA_CMD0_PAD_IPSEC  0x00000000      /* IPsec padding */
++#define       SAFE_SA_CMD0_PAD_PKCS7  0x00000040      /* PKCS#7 padding */
++#define       SAFE_SA_CMD0_PAD_CONS   0x00000080      /* constant padding */
++#define       SAFE_SA_CMD0_PAD_ZERO   0x000000c0      /* zero padding */
++#define       SAFE_SA_CMD0_CRYPT_ALG  0x00000f00      /* symmetric crypto algorithm */
++#define       SAFE_SA_CMD0_DES        0x00000000      /* DES crypto algorithm */
++#define       SAFE_SA_CMD0_3DES       0x00000100      /* 3DES crypto algorithm */
++#define       SAFE_SA_CMD0_AES        0x00000300      /* AES crypto algorithm */
++#define       SAFE_SA_CMD0_CRYPT_NULL 0x00000f00      /* null crypto algorithm */
++#define       SAFE_SA_CMD0_HASH_ALG   0x0000f000      /* hash algorithm */
++#define       SAFE_SA_CMD0_MD5        0x00000000      /* MD5 hash algorithm */
++#define       SAFE_SA_CMD0_SHA1       0x00001000      /* SHA-1 hash algorithm */
++#define       SAFE_SA_CMD0_HASH_NULL  0x0000f000      /* null hash algorithm */
++#define       SAFE_SA_CMD0_HDR_PROC   0x00080000      /* header processing */
++#define       SAFE_SA_CMD0_IBUSID     0x00300000      /* input bus id */
++#define       SAFE_SA_CMD0_IPCI       0x00100000      /* PCI input bus id */
++#define       SAFE_SA_CMD0_OBUSID     0x00c00000      /* output bus id */
++#define       SAFE_SA_CMD0_OPCI       0x00400000      /* PCI output bus id */
++#define       SAFE_SA_CMD0_IVLD       0x03000000      /* IV loading */
++#define       SAFE_SA_CMD0_IVLD_NONE  0x00000000      /* IV no load (reuse) */
++#define       SAFE_SA_CMD0_IVLD_IBUF  0x01000000      /* IV load from input buffer */
++#define       SAFE_SA_CMD0_IVLD_STATE 0x02000000      /* IV load from state */
++#define       SAFE_SA_CMD0_HSLD       0x0c000000      /* hash state loading */
++#define       SAFE_SA_CMD0_HSLD_SA    0x00000000      /* hash state load from SA */
++#define       SAFE_SA_CMD0_HSLD_STATE 0x08000000      /* hash state load from state */
++#define       SAFE_SA_CMD0_HSLD_NONE  0x0c000000      /* hash state no load */
++#define       SAFE_SA_CMD0_SAVEIV     0x10000000      /* save IV */
++#define       SAFE_SA_CMD0_SAVEHASH   0x20000000      /* save hash state */
++#define       SAFE_SA_CMD0_IGATHER    0x40000000      /* input gather */
++#define       SAFE_SA_CMD0_OSCATTER   0x80000000      /* output scatter */
++
++#define       SAFE_SA_CMD1_HDRCOPY    0x00000002      /* copy header to output */
++#define       SAFE_SA_CMD1_PAYCOPY    0x00000004      /* copy payload to output */
++#define       SAFE_SA_CMD1_PADCOPY    0x00000008      /* copy pad to output */
++#define       SAFE_SA_CMD1_IPV4       0x00000000      /* IPv4 protocol */
++#define       SAFE_SA_CMD1_IPV6       0x00000010      /* IPv6 protocol */
++#define       SAFE_SA_CMD1_MUTABLE    0x00000020      /* mutable bit processing */
++#define       SAFE_SA_CMD1_SRBUSID    0x000000c0      /* state record bus id */
++#define       SAFE_SA_CMD1_SRPCI      0x00000040      /* state record from PCI */
++#define       SAFE_SA_CMD1_CRMODE     0x00000300      /* crypto mode */
++#define       SAFE_SA_CMD1_ECB        0x00000000      /* ECB crypto mode */
++#define       SAFE_SA_CMD1_CBC        0x00000100      /* CBC crypto mode */
++#define       SAFE_SA_CMD1_OFB        0x00000200      /* OFB crypto mode */
++#define       SAFE_SA_CMD1_CFB        0x00000300      /* CFB crypto mode */
++#define       SAFE_SA_CMD1_CRFEEDBACK 0x00000c00      /* crypto feedback mode */
++#define       SAFE_SA_CMD1_64BIT      0x00000000      /* 64-bit crypto feedback */
++#define       SAFE_SA_CMD1_8BIT       0x00000400      /* 8-bit crypto feedback */
++#define       SAFE_SA_CMD1_1BIT       0x00000800      /* 1-bit crypto feedback */
++#define       SAFE_SA_CMD1_128BIT     0x00000c00      /* 128-bit crypto feedback */
++#define       SAFE_SA_CMD1_OPTIONS    0x00001000      /* HMAC/options mutable bit */
++#define       SAFE_SA_CMD1_HMAC       SAFE_SA_CMD1_OPTIONS
++#define       SAFE_SA_CMD1_SAREV1     0x00008000      /* SA Revision 1 */
++#define       SAFE_SA_CMD1_OFFSET     0x00ff0000      /* hash/crypto offset(dwords) */
++#define       SAFE_SA_CMD1_OFFSET_S   16
++#define       SAFE_SA_CMD1_AESKEYLEN  0x0f000000      /* AES key length */
++#define       SAFE_SA_CMD1_AES128     0x02000000      /* 128-bit AES key */
++#define       SAFE_SA_CMD1_AES192     0x03000000      /* 192-bit AES key */
++#define       SAFE_SA_CMD1_AES256     0x04000000      /* 256-bit AES key */
++
++/* 
++ * Security Associate State Record (Rev 1).
++ */
++struct safe_sastate {
++      u_int32_t       sa_saved_iv[4];         /* saved IV (DES/3DES/AES) */
++      u_int32_t       sa_saved_hashbc;        /* saved hash byte count */
++      u_int32_t       sa_saved_indigest[5];   /* saved inner digest */
++};
++#endif /* _SAFE_SAFEREG_H_ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/safe/safevar.h    2007-07-03 09:46:58.000000000 +1000
+@@ -0,0 +1,230 @@
++/*-
++ * The linux port of this code done by David McCullough
++ * Copyright (C) 2004-2007 David McCullough <david_mccullough@securecomputing.com>
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * $FreeBSD: src/sys/dev/safe/safevar.h,v 1.2 2006/05/17 18:34:26 pjd Exp $
++ */
++#ifndef _SAFE_SAFEVAR_H_
++#define       _SAFE_SAFEVAR_H_
++
++/* Maximum queue length */
++#ifndef SAFE_MAX_NQUEUE
++#define SAFE_MAX_NQUEUE       60
++#endif
++
++#define       SAFE_MAX_PART           64      /* Maximum scatter/gather depth */
++#define       SAFE_DMA_BOUNDARY       0       /* No boundary for source DMA ops */
++#define       SAFE_MAX_DSIZE          2048 /* MCLBYTES Fixed scatter particle size */
++#define       SAFE_MAX_SSIZE          0x0ffff /* Maximum gather particle size */
++#define       SAFE_MAX_DMA            0xfffff /* Maximum PE operand size (20 bits) */
++/* total src+dst particle descriptors */
++#define       SAFE_TOTAL_DPART        (SAFE_MAX_NQUEUE * SAFE_MAX_PART)
++#define       SAFE_TOTAL_SPART        (SAFE_MAX_NQUEUE * SAFE_MAX_PART)
++
++#define       SAFE_RNG_MAXBUFSIZ      128     /* 32-bit words */
++
++#define       SAFE_CARD(sid)          (((sid) & 0xf0000000) >> 28)
++#define       SAFE_SESSION(sid)       ( (sid) & 0x0fffffff)
++#define       SAFE_SID(crd, sesn)     (((crd) << 28) | ((sesn) & 0x0fffffff))
++
++#define SAFE_DEF_RTY          0xff    /* PCI Retry Timeout */
++#define SAFE_DEF_TOUT         0xff    /* PCI TRDY Timeout */
++#define SAFE_DEF_CACHELINE    0x01    /* Cache Line setting */
++
++#ifdef __KERNEL__
++/*
++ * State associated with the allocation of each chunk
++ * of memory setup for DMA.
++ */
++struct safe_dma_alloc {
++      dma_addr_t              dma_paddr;
++      void                    *dma_vaddr;
++};
++
++/*
++ * Cryptographic operand state.  One of these exists for each
++ * source and destination operand passed in from the crypto
++ * subsystem.  When possible source and destination operands
++ * refer to the same memory.  More often they are distinct.
++ * We track the virtual address of each operand as well as
++ * where each is mapped for DMA.
++ */
++struct safe_operand {
++      union {
++              struct sk_buff *skb;
++              struct uio *io;
++      } u;
++      void                    *map;
++      int                             mapsize;        /* total number of bytes in segs */
++      struct {
++              dma_addr_t      ds_addr;
++              int                     ds_len;
++              int                     ds_tlen;
++      } segs[SAFE_MAX_PART];
++      int                             nsegs;
++};
++
++/*
++ * Packet engine ring entry and cryptographic operation state.
++ * The packet engine requires a ring of descriptors that contain
++ * pointers to various cryptographic state.  However the ring
++ * configuration register allows you to specify an arbitrary size
++ * for ring entries.  We use this feature to collect most of the
++ * state for each cryptographic request into one spot.  Other than
++ * ring entries only the ``particle descriptors'' (scatter/gather
++ * lists) and the actual operand data are kept separate.  The
++ * particle descriptors must also be organized in rings.  The
++ * operand data can be located aribtrarily (modulo alignment constraints).
++ *
++ * Note that the descriptor ring is mapped onto the PCI bus so
++ * the hardware can DMA data.  This means the entire ring must be
++ * contiguous.
++ */
++struct safe_ringentry {
++      struct safe_desc        re_desc;        /* command descriptor */
++      struct safe_sarec       re_sa;          /* SA record */
++      struct safe_sastate     re_sastate;     /* SA state record */
++
++      struct cryptop          *re_crp;        /* crypto operation */
++
++      struct safe_operand     re_src;         /* source operand */
++      struct safe_operand     re_dst;         /* destination operand */
++
++      int                     re_sesn;        /* crypto session ID */
++      int                     re_flags;
++#define       SAFE_QFLAGS_COPYOUTIV   0x1             /* copy back on completion */
++#define       SAFE_QFLAGS_COPYOUTICV  0x2             /* copy back on completion */
++};
++
++#define       re_src_skb      re_src.u.skb
++#define       re_src_io       re_src.u.io
++#define       re_src_map      re_src.map
++#define       re_src_nsegs    re_src.nsegs
++#define       re_src_segs     re_src.segs
++#define       re_src_mapsize  re_src.mapsize
++
++#define       re_dst_skb      re_dst.u.skb
++#define       re_dst_io       re_dst.u.io
++#define       re_dst_map      re_dst.map
++#define       re_dst_nsegs    re_dst.nsegs
++#define       re_dst_segs     re_dst.segs
++#define       re_dst_mapsize  re_dst.mapsize
++
++struct rndstate_test;
++
++struct safe_session {
++      u_int32_t       ses_used;
++      u_int32_t       ses_klen;               /* key length in bits */
++      u_int32_t       ses_key[8];             /* DES/3DES/AES key */
++      u_int32_t       ses_mlen;               /* hmac length in bytes */
++      u_int32_t       ses_hminner[5];         /* hmac inner state */
++      u_int32_t       ses_hmouter[5];         /* hmac outer state */
++      u_int32_t       ses_iv[4];              /* DES/3DES/AES iv */
++};
++
++struct safe_pkq {
++      struct list_head        pkq_list;
++      struct cryptkop         *pkq_krp;
++};
++
++struct safe_softc {
++      softc_device_decl       sc_dev;
++      u32                     sc_irq;
++
++      struct pci_dev          *sc_pcidev;
++      ocf_iomem_t             sc_base_addr;
++
++      u_int                   sc_chiprev;     /* major/minor chip revision */
++      int                     sc_flags;       /* device specific flags */
++#define       SAFE_FLAGS_KEY          0x01            /* has key accelerator */
++#define       SAFE_FLAGS_RNG          0x02            /* hardware rng */
++      int                     sc_suspended;
++      int                     sc_needwakeup;  /* notify crypto layer */
++      int32_t                 sc_cid;         /* crypto tag */
++
++      struct safe_dma_alloc   sc_ringalloc;   /* PE ring allocation state */
++      struct safe_ringentry   *sc_ring;       /* PE ring */
++      struct safe_ringentry   *sc_ringtop;    /* PE ring top */
++      struct safe_ringentry   *sc_front;      /* next free entry */
++      struct safe_ringentry   *sc_back;       /* next pending entry */
++      int                     sc_nqchip;      /* # passed to chip */
++      spinlock_t              sc_ringmtx;     /* PE ring lock */
++      struct safe_pdesc       *sc_spring;     /* src particle ring */
++      struct safe_pdesc       *sc_springtop;  /* src particle ring top */
++      struct safe_pdesc       *sc_spfree;     /* next free src particle */
++      struct safe_dma_alloc   sc_spalloc;     /* src particle ring state */
++      struct safe_pdesc       *sc_dpring;     /* dest particle ring */
++      struct safe_pdesc       *sc_dpringtop;  /* dest particle ring top */
++      struct safe_pdesc       *sc_dpfree;     /* next free dest particle */
++      struct safe_dma_alloc   sc_dpalloc;     /* dst particle ring state */
++      int                     sc_nsessions;   /* # of sessions */
++      struct safe_session     *sc_sessions;   /* sessions */
++
++      struct timer_list       sc_pkto;        /* PK polling */
++      spinlock_t              sc_pkmtx;       /* PK lock */
++      struct list_head        sc_pkq;         /* queue of PK requests */
++      struct safe_pkq         *sc_pkq_cur;    /* current processing request */
++      u_int32_t               sc_pk_reslen, sc_pk_resoff;
++
++      int                     sc_max_dsize;   /* maximum safe DMA size */
++};
++#endif /* __KERNEL__ */
++
++struct safe_stats {
++      u_int64_t st_ibytes;
++      u_int64_t st_obytes;
++      u_int32_t st_ipackets;
++      u_int32_t st_opackets;
++      u_int32_t st_invalid;           /* invalid argument */
++      u_int32_t st_badsession;        /* invalid session id */
++      u_int32_t st_badflags;          /* flags indicate !(mbuf | uio) */
++      u_int32_t st_nodesc;            /* op submitted w/o descriptors */
++      u_int32_t st_badalg;            /* unsupported algorithm */
++      u_int32_t st_ringfull;          /* PE descriptor ring full */
++      u_int32_t st_peoperr;           /* PE marked error */
++      u_int32_t st_dmaerr;            /* PE DMA error */
++      u_int32_t st_bypasstoobig;      /* bypass > 96 bytes */
++      u_int32_t st_skipmismatch;      /* enc part begins before auth part */
++      u_int32_t st_lenmismatch;       /* enc length different auth length */
++      u_int32_t st_coffmisaligned;    /* crypto offset not 32-bit aligned */
++      u_int32_t st_cofftoobig;        /* crypto offset > 255 words */
++      u_int32_t st_iovmisaligned;     /* iov op not aligned */
++      u_int32_t st_iovnotuniform;     /* iov op not suitable */
++      u_int32_t st_unaligned;         /* unaligned src caused copy */
++      u_int32_t st_notuniform;        /* non-uniform src caused copy */
++      u_int32_t st_nomap;             /* bus_dmamap_create failed */
++      u_int32_t st_noload;            /* bus_dmamap_load_* failed */
++      u_int32_t st_nombuf;            /* MGET* failed */
++      u_int32_t st_nomcl;             /* MCLGET* failed */
++      u_int32_t st_maxqchip;          /* max mcr1 ops out for processing */
++      u_int32_t st_rng;               /* RNG requests */
++      u_int32_t st_rngalarm;          /* RNG alarm requests */
++      u_int32_t st_noicvcopy;         /* ICV data copies suppressed */
++};
++#endif /* _SAFE_SAFEVAR_H_ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/crypto.c  2008-07-03 10:58:33.000000000 +1000
+@@ -0,0 +1,1741 @@
++/*-
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * Copyright (c) 2002-2006 Sam Leffler.  All rights reserved.
++ *
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $");
++#endif
++
++/*
++ * Cryptographic Subsystem.
++ *
++ * This code is derived from the Openbsd Cryptographic Framework (OCF)
++ * that has the copyright shown below.  Very little of the original
++ * code remains.
++ */
++/*-
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000, 2001 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $");
++ */
++
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <cryptodev.h>
++
++/*
++ * keep track of whether or not we have been initialised, a big
++ * issue if we are linked into the kernel and a driver gets started before
++ * us
++ */
++static int crypto_initted = 0;
++
++/*
++ * Crypto drivers register themselves by allocating a slot in the
++ * crypto_drivers table with crypto_get_driverid() and then registering
++ * each algorithm they support with crypto_register() and crypto_kregister().
++ */
++
++/*
++ * lock on driver table
++ * we track its state as spin_is_locked does not do anything on non-SMP boxes
++ */
++static spinlock_t     crypto_drivers_lock;
++static int                    crypto_drivers_locked;          /* for non-SMP boxes */
++
++#define       CRYPTO_DRIVER_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_drivers_lock, d_flags); \
++                              crypto_drivers_locked = 1; \
++                              dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_DRIVER_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \
++                              crypto_drivers_locked = 0; \
++                              spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \
++                       })
++#define       CRYPTO_DRIVER_ASSERT() \
++                      ({ \
++                              if (!crypto_drivers_locked) { \
++                                      dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \
++                              } \
++                       })
++
++/*
++ * Crypto device/driver capabilities structure.
++ *
++ * Synchronization:
++ * (d) - protected by CRYPTO_DRIVER_LOCK()
++ * (q) - protected by CRYPTO_Q_LOCK()
++ * Not tagged fields are read-only.
++ */
++struct cryptocap {
++      device_t        cc_dev;                 /* (d) device/driver */
++      u_int32_t       cc_sessions;            /* (d) # of sessions */
++      u_int32_t       cc_koperations;         /* (d) # os asym operations */
++      /*
++       * Largest possible operator length (in bits) for each type of
++       * encryption algorithm. XXX not used
++       */
++      u_int16_t       cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1];
++      u_int8_t        cc_alg[CRYPTO_ALGORITHM_MAX + 1];
++      u_int8_t        cc_kalg[CRK_ALGORITHM_MAX + 1];
++
++      int             cc_flags;               /* (d) flags */
++#define CRYPTOCAP_F_CLEANUP   0x80000000      /* needs resource cleanup */
++      int             cc_qblocked;            /* (q) symmetric q blocked */
++      int             cc_kqblocked;           /* (q) asymmetric q blocked */
++};
++static struct cryptocap *crypto_drivers = NULL;
++static int crypto_drivers_num = 0;
++
++/*
++ * There are two queues for crypto requests; one for symmetric (e.g.
++ * cipher) operations and one for asymmetric (e.g. MOD)operations.
++ * A single mutex is used to lock access to both queues.  We could
++ * have one per-queue but having one simplifies handling of block/unblock
++ * operations.
++ */
++static        int crp_sleep = 0;
++static LIST_HEAD(crp_q);              /* request queues */
++static LIST_HEAD(crp_kq);
++
++static spinlock_t crypto_q_lock;
++
++int crypto_all_qblocked = 0;  /* protect with Q_LOCK */
++module_param(crypto_all_qblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked");
++
++int crypto_all_kqblocked = 0; /* protect with Q_LOCK */
++module_param(crypto_all_kqblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked");
++
++#define       CRYPTO_Q_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_q_lock, q_flags); \
++                              dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_Q_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \
++                              spin_unlock_irqrestore(&crypto_q_lock, q_flags); \
++                       })
++
++/*
++ * There are two queues for processing completed crypto requests; one
++ * for the symmetric and one for the asymmetric ops.  We only need one
++ * but have two to avoid type futzing (cryptop vs. cryptkop).  A single
++ * mutex is used to lock access to both queues.  Note that this lock
++ * must be separate from the lock on request queues to insure driver
++ * callbacks don't generate lock order reversals.
++ */
++static LIST_HEAD(crp_ret_q);          /* callback queues */
++static LIST_HEAD(crp_ret_kq);
++
++static spinlock_t crypto_ret_q_lock;
++#define       CRYPTO_RETQ_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \
++                              dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_RETQ_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \
++                              spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \
++                       })
++#define       CRYPTO_RETQ_EMPTY()     (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq))
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *cryptop_zone;
++static kmem_cache_t *cryptodesc_zone;
++#else
++static struct kmem_cache *cryptop_zone;
++static struct kmem_cache *cryptodesc_zone;
++#endif
++
++#define debug crypto_debug
++int crypto_debug = 0;
++module_param(crypto_debug, int, 0644);
++MODULE_PARM_DESC(crypto_debug, "Enable debug");
++EXPORT_SYMBOL(crypto_debug);
++
++/*
++ * Maximum number of outstanding crypto requests before we start
++ * failing requests.  We need this to prevent DOS when too many
++ * requests are arriving for us to keep up.  Otherwise we will
++ * run the system out of memory.  Since crypto is slow,  we are
++ * usually the bottleneck that needs to say, enough is enough.
++ *
++ * We cannot print errors when this condition occurs,  we are already too
++ * slow,  printing anything will just kill us
++ */
++
++static int crypto_q_cnt = 0;
++module_param(crypto_q_cnt, int, 0444);
++MODULE_PARM_DESC(crypto_q_cnt,
++              "Current number of outstanding crypto requests");
++
++static int crypto_q_max = 1000;
++module_param(crypto_q_max, int, 0644);
++MODULE_PARM_DESC(crypto_q_max,
++              "Maximum number of outstanding crypto requests");
++
++#define bootverbose crypto_verbose
++static int crypto_verbose = 0;
++module_param(crypto_verbose, int, 0644);
++MODULE_PARM_DESC(crypto_verbose,
++              "Enable verbose crypto startup");
++
++int   crypto_usercrypto = 1;  /* userland may do crypto reqs */
++module_param(crypto_usercrypto, int, 0644);
++MODULE_PARM_DESC(crypto_usercrypto,
++         "Enable/disable user-mode access to crypto support");
++
++int   crypto_userasymcrypto = 1;      /* userland may do asym crypto reqs */
++module_param(crypto_userasymcrypto, int, 0644);
++MODULE_PARM_DESC(crypto_userasymcrypto,
++         "Enable/disable user-mode access to asymmetric crypto support");
++
++int   crypto_devallowsoft = 0;        /* only use hardware crypto */
++module_param(crypto_devallowsoft, int, 0644);
++MODULE_PARM_DESC(crypto_devallowsoft,
++         "Enable/disable use of software crypto support");
++
++static pid_t  cryptoproc = (pid_t) -1;
++static struct completion cryptoproc_exited;
++static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
++static pid_t  cryptoretproc = (pid_t) -1;
++static struct completion cryptoretproc_exited;
++static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
++
++static        int crypto_proc(void *arg);
++static        int crypto_ret_proc(void *arg);
++static        int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
++static        int crypto_kinvoke(struct cryptkop *krp, int flags);
++static        void crypto_exit(void);
++static  int crypto_init(void);
++
++static        struct cryptostats cryptostats;
++
++static struct cryptocap *
++crypto_checkdriver(u_int32_t hid)
++{
++      if (crypto_drivers == NULL)
++              return NULL;
++      return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
++}
++
++/*
++ * Compare a driver's list of supported algorithms against another
++ * list; return non-zero if all algorithms are supported.
++ */
++static int
++driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri)
++{
++      const struct cryptoini *cr;
++
++      /* See if all the algorithms are supported. */
++      for (cr = cri; cr; cr = cr->cri_next)
++              if (cap->cc_alg[cr->cri_alg] == 0)
++                      return 0;
++      return 1;
++}
++
++/*
++ * Select a driver for a new session that supports the specified
++ * algorithms and, optionally, is constrained according to the flags.
++ * The algorithm we use here is pretty stupid; just use the
++ * first driver that supports all the algorithms we need. If there
++ * are multiple drivers we choose the driver with the fewest active
++ * sessions.  We prefer hardware-backed drivers to software ones.
++ *
++ * XXX We need more smarts here (in real life too, but that's
++ * XXX another story altogether).
++ */
++static struct cryptocap *
++crypto_select_driver(const struct cryptoini *cri, int flags)
++{
++      struct cryptocap *cap, *best;
++      int match, hid;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      /*
++       * Look first for hardware crypto devices if permitted.
++       */
++      if (flags & CRYPTOCAP_F_HARDWARE)
++              match = CRYPTOCAP_F_HARDWARE;
++      else
++              match = CRYPTOCAP_F_SOFTWARE;
++      best = NULL;
++again:
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              cap = &crypto_drivers[hid];
++              /*
++               * If it's not initialized, is in the process of
++               * going away, or is not appropriate (hardware
++               * or software based on match), then skip.
++               */
++              if (cap->cc_dev == NULL ||
++                  (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++                  (cap->cc_flags & match) == 0)
++                      continue;
++
++              /* verify all the algorithms are supported. */
++              if (driver_suitable(cap, cri)) {
++                      if (best == NULL ||
++                          cap->cc_sessions < best->cc_sessions)
++                              best = cap;
++              }
++      }
++      if (best != NULL)
++              return best;
++      if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++              /* sort of an Algol 68-style for loop */
++              match = CRYPTOCAP_F_SOFTWARE;
++              goto again;
++      }
++      return best;
++}
++
++/*
++ * Create a new session.  The crid argument specifies a crypto
++ * driver to use or constraints on a driver to select (hardware
++ * only, software only, either).  Whatever driver is selected
++ * must be capable of the requested crypto algorithms.
++ */
++int
++crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid)
++{
++      struct cryptocap *cap;
++      u_int32_t hid, lid;
++      int err;
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              /*
++               * Use specified driver; verify it is capable.
++               */
++              cap = crypto_checkdriver(crid);
++              if (cap != NULL && !driver_suitable(cap, cri))
++                      cap = NULL;
++      } else {
++              /*
++               * No requested driver; select based on crid flags.
++               */
++              cap = crypto_select_driver(cri, crid);
++              /*
++               * if NULL then can't do everything in one session.
++               * XXX Fix this. We need to inject a "virtual" session
++               * XXX layer right about here.
++               */
++      }
++      if (cap != NULL) {
++              /* Call the driver initialization routine. */
++              hid = cap - crypto_drivers;
++              lid = hid;              /* Pass the driver ID. */
++              cap->cc_sessions++;
++              CRYPTO_DRIVER_UNLOCK();
++              err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri);
++              CRYPTO_DRIVER_LOCK();
++              if (err == 0) {
++                      (*sid) = (cap->cc_flags & 0xff000000)
++                             | (hid & 0x00ffffff);
++                      (*sid) <<= 32;
++                      (*sid) |= (lid & 0xffffffff);
++              } else
++                      cap->cc_sessions--;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++static void
++crypto_remove(struct cryptocap *cap)
++{
++      CRYPTO_DRIVER_ASSERT();
++      if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
++              bzero(cap, sizeof(*cap));
++}
++
++/*
++ * Delete an existing session (or a reserved session on an unregistered
++ * driver).
++ */
++int
++crypto_freesession(u_int64_t sid)
++{
++      struct cryptocap *cap;
++      u_int32_t hid;
++      int err = 0;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      if (crypto_drivers == NULL) {
++              err = EINVAL;
++              goto done;
++      }
++
++      /* Determine two IDs. */
++      hid = CRYPTO_SESID2HID(sid);
++
++      if (hid >= crypto_drivers_num) {
++              dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid);
++              err = ENOENT;
++              goto done;
++      }
++      cap = &crypto_drivers[hid];
++
++      if (cap->cc_dev) {
++              CRYPTO_DRIVER_UNLOCK();
++              /* Call the driver cleanup routine, if available, unlocked. */
++              err = CRYPTODEV_FREESESSION(cap->cc_dev, sid);
++              CRYPTO_DRIVER_LOCK();
++      }
++
++      if (cap->cc_sessions)
++              cap->cc_sessions--;
++
++      if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++              crypto_remove(cap);
++
++done:
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Return an unused driver id.  Used by drivers prior to registering
++ * support for the algorithms they handle.
++ */
++int32_t
++crypto_get_driverid(device_t dev, int flags)
++{
++      struct cryptocap *newdrv;
++      int i;
++      unsigned long d_flags;
++
++      if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              printf("%s: no flags specified when registering driver\n",
++                  device_get_nameunit(dev));
++              return -1;
++      }
++
++      CRYPTO_DRIVER_LOCK();
++
++      for (i = 0; i < crypto_drivers_num; i++) {
++              if (crypto_drivers[i].cc_dev == NULL &&
++                  (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
++                      break;
++              }
++      }
++
++      /* Out of entries, allocate some more. */
++      if (i == crypto_drivers_num) {
++              /* Be careful about wrap-around. */
++              if (2 * crypto_drivers_num <= crypto_drivers_num) {
++                      CRYPTO_DRIVER_UNLOCK();
++                      printk("crypto: driver count wraparound!\n");
++                      return -1;
++              }
++
++              newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),
++                              GFP_KERNEL);
++              if (newdrv == NULL) {
++                      CRYPTO_DRIVER_UNLOCK();
++                      printk("crypto: no space to expand driver table!\n");
++                      return -1;
++              }
++
++              memcpy(newdrv, crypto_drivers,
++                              crypto_drivers_num * sizeof(struct cryptocap));
++              memset(&newdrv[crypto_drivers_num], 0,
++                              crypto_drivers_num * sizeof(struct cryptocap));
++
++              crypto_drivers_num *= 2;
++
++              kfree(crypto_drivers);
++              crypto_drivers = newdrv;
++      }
++
++      /* NB: state is zero'd on free */
++      crypto_drivers[i].cc_sessions = 1;      /* Mark */
++      crypto_drivers[i].cc_dev = dev;
++      crypto_drivers[i].cc_flags = flags;
++      if (bootverbose)
++              printf("crypto: assign %s driver id %u, flags %u\n",
++                  device_get_nameunit(dev), i, flags);
++
++      CRYPTO_DRIVER_UNLOCK();
++
++      return i;
++}
++
++/*
++ * Lookup a driver by name.  We match against the full device
++ * name and unit, and against just the name.  The latter gives
++ * us a simple widlcarding by device name.  On success return the
++ * driver/hardware identifier; otherwise return -1.
++ */
++int
++crypto_find_driver(const char *match)
++{
++      int i, len = strlen(match);
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      for (i = 0; i < crypto_drivers_num; i++) {
++              device_t dev = crypto_drivers[i].cc_dev;
++              if (dev == NULL ||
++                  (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP))
++                      continue;
++              if (strncmp(match, device_get_nameunit(dev), len) == 0 ||
++                  strncmp(match, device_get_name(dev), len) == 0)
++                      break;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++      return i < crypto_drivers_num ? i : -1;
++}
++
++/*
++ * Return the device_t for the specified driver or NULL
++ * if the driver identifier is invalid.
++ */
++device_t
++crypto_find_device_byhid(int hid)
++{
++      struct cryptocap *cap = crypto_checkdriver(hid);
++      return cap != NULL ? cap->cc_dev : NULL;
++}
++
++/*
++ * Return the device/driver capabilities.
++ */
++int
++crypto_getcaps(int hid)
++{
++      struct cryptocap *cap = crypto_checkdriver(hid);
++      return cap != NULL ? cap->cc_flags : 0;
++}
++
++/*
++ * Register support for a key-related algorithm.  This routine
++ * is called once for each algorithm supported a driver.
++ */
++int
++crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL &&
++          (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
++              /*
++               * XXX Do some performance testing to determine placing.
++               * XXX We probably need an auxiliary data structure that
++               * XXX describes relative performances.
++               */
++
++              cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++              if (bootverbose)
++                      printf("crypto: %s registers key alg %u flags %u\n"
++                              , device_get_nameunit(cap->cc_dev)
++                              , kalg
++                              , flags
++                      );
++              err = 0;
++      } else
++              err = EINVAL;
++
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Register support for a non-key-related algorithm.  This routine
++ * is called once for each such algorithm supported by a driver.
++ */
++int
++crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++    u_int32_t flags)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__,
++                      driverid, alg, maxoplen, flags);
++
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      /* NB: algorithms are in the range [1..max] */
++      if (cap != NULL &&
++          (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
++              /*
++               * XXX Do some performance testing to determine placing.
++               * XXX We probably need an auxiliary data structure that
++               * XXX describes relative performances.
++               */
++
++              cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++              cap->cc_max_op_len[alg] = maxoplen;
++              if (bootverbose)
++                      printf("crypto: %s registers alg %u flags %u maxoplen %u\n"
++                              , device_get_nameunit(cap->cc_dev)
++                              , alg
++                              , flags
++                              , maxoplen
++                      );
++              cap->cc_sessions = 0;           /* Unmark */
++              err = 0;
++      } else
++              err = EINVAL;
++
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++static void
++driver_finis(struct cryptocap *cap)
++{
++      u_int32_t ses, kops;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      ses = cap->cc_sessions;
++      kops = cap->cc_koperations;
++      bzero(cap, sizeof(*cap));
++      if (ses != 0 || kops != 0) {
++              /*
++               * If there are pending sessions,
++               * just mark as invalid.
++               */
++              cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
++              cap->cc_sessions = ses;
++              cap->cc_koperations = kops;
++      }
++}
++
++/*
++ * Unregister a crypto driver. If there are pending sessions using it,
++ * leave enough information around so that subsequent calls using those
++ * sessions will correctly detect the driver has been unregistered and
++ * reroute requests.
++ */
++int
++crypto_unregister(u_int32_t driverid, int alg)
++{
++      struct cryptocap *cap;
++      int i, err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL &&
++          (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
++          cap->cc_alg[alg] != 0) {
++              cap->cc_alg[alg] = 0;
++              cap->cc_max_op_len[alg] = 0;
++
++              /* Was this the last algorithm ? */
++              for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
++                      if (cap->cc_alg[i] != 0)
++                              break;
++
++              if (i == CRYPTO_ALGORITHM_MAX + 1)
++                      driver_finis(cap);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Unregister all algorithms associated with a crypto driver.
++ * If there are pending sessions using it, leave enough information
++ * around so that subsequent calls using those sessions will
++ * correctly detect the driver has been unregistered and reroute
++ * requests.
++ */
++int
++crypto_unregister_all(u_int32_t driverid)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL) {
++              driver_finis(cap);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++
++      return err;
++}
++
++/*
++ * Clear blockage on a driver.  The what parameter indicates whether
++ * the driver is now ready for cryptop's and/or cryptokop's.
++ */
++int
++crypto_unblock(u_int32_t driverid, int what)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long q_flags;
++
++      CRYPTO_Q_LOCK();
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL) {
++              if (what & CRYPTO_SYMQ) {
++                      cap->cc_qblocked = 0;
++                      crypto_all_qblocked = 0;
++              }
++              if (what & CRYPTO_ASYMQ) {
++                      cap->cc_kqblocked = 0;
++                      crypto_all_kqblocked = 0;
++              }
++              if (crp_sleep)
++                      wake_up_interruptible(&cryptoproc_wait);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock
++
++      return err;
++}
++
++/*
++ * Add a crypto request to a queue, to be processed by the kernel thread.
++ */
++int
++crypto_dispatch(struct cryptop *crp)
++{
++      struct cryptocap *cap;
++      int result = -1;
++      unsigned long q_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      cryptostats.cs_ops++;
++
++      CRYPTO_Q_LOCK();
++      if (crypto_q_cnt >= crypto_q_max) {
++              CRYPTO_Q_UNLOCK();
++              cryptostats.cs_drops++;
++              return ENOMEM;
++      }
++      crypto_q_cnt++;
++
++      /*
++       * Caller marked the request to be processed immediately; dispatch
++       * it directly to the driver unless the driver is currently blocked.
++       */
++      if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
++              int hid = CRYPTO_SESID2HID(crp->crp_sid);
++              cap = crypto_checkdriver(hid);
++              /* Driver cannot disappear when there is an active session. */
++              KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
++              if (!cap->cc_qblocked) {
++                      crypto_all_qblocked = 0;
++                      crypto_drivers[hid].cc_qblocked = 1;
++                      CRYPTO_Q_UNLOCK();
++                      result = crypto_invoke(cap, crp, 0);
++                      CRYPTO_Q_LOCK();
++                      if (result != ERESTART)
++                              crypto_drivers[hid].cc_qblocked = 0;
++              }
++      }
++      if (result == ERESTART) {
++              /*
++               * The driver ran out of resources, mark the
++               * driver ``blocked'' for cryptop's and put
++               * the request back in the queue.  It would
++               * best to put the request back where we got
++               * it but that's hard so for now we put it
++               * at the front.  This should be ok; putting
++               * it at the end does not work.
++               */
++              list_add(&crp->crp_next, &crp_q);
++              cryptostats.cs_blocks++;
++      } else if (result == -1) {
++              TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
++      }
++      if (crp_sleep)
++              wake_up_interruptible(&cryptoproc_wait);
++      CRYPTO_Q_UNLOCK();
++      return 0;
++}
++
++/*
++ * Add an asymetric crypto request to a queue,
++ * to be processed by the kernel thread.
++ */
++int
++crypto_kdispatch(struct cryptkop *krp)
++{
++      int error;
++      unsigned long q_flags;
++
++      cryptostats.cs_kops++;
++
++      error = crypto_kinvoke(krp, krp->krp_crid);
++      if (error == ERESTART) {
++              CRYPTO_Q_LOCK();
++              TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
++              if (crp_sleep)
++                      wake_up_interruptible(&cryptoproc_wait);
++              CRYPTO_Q_UNLOCK();
++              error = 0;
++      }
++      return error;
++}
++
++/*
++ * Verify a driver is suitable for the specified operation.
++ */
++static __inline int
++kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp)
++{
++      return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0;
++}
++
++/*
++ * Select a driver for an asym operation.  The driver must
++ * support the necessary algorithm.  The caller can constrain
++ * which device is selected with the flags parameter.  The
++ * algorithm we use here is pretty stupid; just use the first
++ * driver that supports the algorithms we need. If there are
++ * multiple suitable drivers we choose the driver with the
++ * fewest active operations.  We prefer hardware-backed
++ * drivers to software ones when either may be used.
++ */
++static struct cryptocap *
++crypto_select_kdriver(const struct cryptkop *krp, int flags)
++{
++      struct cryptocap *cap, *best, *blocked;
++      int match, hid;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      /*
++       * Look first for hardware crypto devices if permitted.
++       */
++      if (flags & CRYPTOCAP_F_HARDWARE)
++              match = CRYPTOCAP_F_HARDWARE;
++      else
++              match = CRYPTOCAP_F_SOFTWARE;
++      best = NULL;
++      blocked = NULL;
++again:
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              cap = &crypto_drivers[hid];
++              /*
++               * If it's not initialized, is in the process of
++               * going away, or is not appropriate (hardware
++               * or software based on match), then skip.
++               */
++              if (cap->cc_dev == NULL ||
++                  (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++                  (cap->cc_flags & match) == 0)
++                      continue;
++
++              /* verify all the algorithms are supported. */
++              if (kdriver_suitable(cap, krp)) {
++                      if (best == NULL ||
++                          cap->cc_koperations < best->cc_koperations)
++                              best = cap;
++              }
++      }
++      if (best != NULL)
++              return best;
++      if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++              /* sort of an Algol 68-style for loop */
++              match = CRYPTOCAP_F_SOFTWARE;
++              goto again;
++      }
++      return best;
++}
++
++/*
++ * Dispatch an assymetric crypto request.
++ */
++static int
++crypto_kinvoke(struct cryptkop *krp, int crid)
++{
++      struct cryptocap *cap = NULL;
++      int error;
++      unsigned long d_flags;
++
++      KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
++      KASSERT(krp->krp_callback != NULL,
++          ("%s: krp->crp_callback == NULL", __func__));
++
++      CRYPTO_DRIVER_LOCK();
++      if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              cap = crypto_checkdriver(crid);
++              if (cap != NULL) {
++                      /*
++                       * Driver present, it must support the necessary
++                       * algorithm and, if s/w drivers are excluded,
++                       * it must be registered as hardware-backed.
++                       */
++                      if (!kdriver_suitable(cap, krp) ||
++                          (!crypto_devallowsoft &&
++                           (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0))
++                              cap = NULL;
++              }
++      } else {
++              /*
++               * No requested driver; select based on crid flags.
++               */
++              if (!crypto_devallowsoft)       /* NB: disallow s/w drivers */
++                      crid &= ~CRYPTOCAP_F_SOFTWARE;
++              cap = crypto_select_kdriver(krp, crid);
++      }
++      if (cap != NULL && !cap->cc_kqblocked) {
++              krp->krp_hid = cap - crypto_drivers;
++              cap->cc_koperations++;
++              CRYPTO_DRIVER_UNLOCK();
++              error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0);
++              CRYPTO_DRIVER_LOCK();
++              if (error == ERESTART) {
++                      cap->cc_koperations--;
++                      CRYPTO_DRIVER_UNLOCK();
++                      return (error);
++              }
++              /* return the actual device used */
++              krp->krp_crid = krp->krp_hid;
++      } else {
++              /*
++               * NB: cap is !NULL if device is blocked; in
++               *     that case return ERESTART so the operation
++               *     is resubmitted if possible.
++               */
++              error = (cap == NULL) ? ENODEV : ERESTART;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++
++      if (error) {
++              krp->krp_status = error;
++              crypto_kdone(krp);
++      }
++      return 0;
++}
++
++
++/*
++ * Dispatch a crypto request to the appropriate crypto devices.
++ */
++static int
++crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
++{
++      KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
++      KASSERT(crp->crp_callback != NULL,
++          ("%s: crp->crp_callback == NULL", __func__));
++      KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
++
++      dprintk("%s()\n", __FUNCTION__);
++
++#ifdef CRYPTO_TIMING
++      if (crypto_timing)
++              crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
++#endif
++      if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
++              struct cryptodesc *crd;
++              u_int64_t nid;
++
++              /*
++               * Driver has unregistered; migrate the session and return
++               * an error to the caller so they'll resubmit the op.
++               *
++               * XXX: What if there are more already queued requests for this
++               *      session?
++               */
++              crypto_freesession(crp->crp_sid);
++
++              for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
++                      crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
++
++              /* XXX propagate flags from initial session? */
++              if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI),
++                  CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0)
++                      crp->crp_sid = nid;
++
++              crp->crp_etype = EAGAIN;
++              crypto_done(crp);
++              return 0;
++      } else {
++              /*
++               * Invoke the driver to process the request.
++               */
++              return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint);
++      }
++}
++
++/*
++ * Release a set of crypto descriptors.
++ */
++void
++crypto_freereq(struct cryptop *crp)
++{
++      struct cryptodesc *crd;
++
++      if (crp == NULL)
++              return;
++
++#ifdef DIAGNOSTIC
++      {
++              struct cryptop *crp2;
++              unsigned long q_flags;
++
++              CRYPTO_Q_LOCK();
++              TAILQ_FOREACH(crp2, &crp_q, crp_next) {
++                      KASSERT(crp2 != crp,
++                          ("Freeing cryptop from the crypto queue (%p).",
++                          crp));
++              }
++              CRYPTO_Q_UNLOCK();
++              CRYPTO_RETQ_LOCK();
++              TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) {
++                      KASSERT(crp2 != crp,
++                          ("Freeing cryptop from the return queue (%p).",
++                          crp));
++              }
++              CRYPTO_RETQ_UNLOCK();
++      }
++#endif
++
++      while ((crd = crp->crp_desc) != NULL) {
++              crp->crp_desc = crd->crd_next;
++              kmem_cache_free(cryptodesc_zone, crd);
++      }
++      kmem_cache_free(cryptop_zone, crp);
++}
++
++/*
++ * Acquire a set of crypto descriptors.
++ */
++struct cryptop *
++crypto_getreq(int num)
++{
++      struct cryptodesc *crd;
++      struct cryptop *crp;
++
++      crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC);
++      if (crp != NULL) {
++              memset(crp, 0, sizeof(*crp));
++              INIT_LIST_HEAD(&crp->crp_next);
++              init_waitqueue_head(&crp->crp_waitq);
++              while (num--) {
++                      crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC);
++                      if (crd == NULL) {
++                              crypto_freereq(crp);
++                              return NULL;
++                      }
++                      memset(crd, 0, sizeof(*crd));
++                      crd->crd_next = crp->crp_desc;
++                      crp->crp_desc = crd;
++              }
++      }
++      return crp;
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_done(struct cryptop *crp)
++{
++      unsigned long q_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if ((crp->crp_flags & CRYPTO_F_DONE) == 0) {
++              crp->crp_flags |= CRYPTO_F_DONE;
++              CRYPTO_Q_LOCK();
++              crypto_q_cnt--;
++              CRYPTO_Q_UNLOCK();
++      } else
++              printk("crypto: crypto_done op already done, flags 0x%x",
++                              crp->crp_flags);
++      if (crp->crp_etype != 0)
++              cryptostats.cs_errs++;
++      /*
++       * CBIMM means unconditionally do the callback immediately;
++       * CBIFSYNC means do the callback immediately only if the
++       * operation was done synchronously.  Both are used to avoid
++       * doing extraneous context switches; the latter is mostly
++       * used with the software crypto driver.
++       */
++      if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
++          ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
++           (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
++              /*
++               * Do the callback directly.  This is ok when the
++               * callback routine does very little (e.g. the
++               * /dev/crypto callback method just does a wakeup).
++               */
++              crp->crp_callback(crp);
++      } else {
++              unsigned long r_flags;
++              /*
++               * Normal case; queue the callback for the thread.
++               */
++              CRYPTO_RETQ_LOCK();
++              if (CRYPTO_RETQ_EMPTY())
++                      wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++              TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
++              CRYPTO_RETQ_UNLOCK();
++      }
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_kdone(struct cryptkop *krp)
++{
++      struct cryptocap *cap;
++      unsigned long d_flags;
++
++      if ((krp->krp_flags & CRYPTO_KF_DONE) != 0)
++              printk("crypto: crypto_kdone op already done, flags 0x%x",
++                              krp->krp_flags);
++      krp->krp_flags |= CRYPTO_KF_DONE;
++      if (krp->krp_status != 0)
++              cryptostats.cs_kerrs++;
++
++      CRYPTO_DRIVER_LOCK();
++      /* XXX: What if driver is loaded in the meantime? */
++      if (krp->krp_hid < crypto_drivers_num) {
++              cap = &crypto_drivers[krp->krp_hid];
++              cap->cc_koperations--;
++              KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
++              if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++                      crypto_remove(cap);
++      }
++      CRYPTO_DRIVER_UNLOCK();
++
++      /*
++       * CBIMM means unconditionally do the callback immediately;
++       * This is used to avoid doing extraneous context switches
++       */
++      if ((krp->krp_flags & CRYPTO_KF_CBIMM)) {
++              /*
++               * Do the callback directly.  This is ok when the
++               * callback routine does very little (e.g. the
++               * /dev/crypto callback method just does a wakeup).
++               */
++              krp->krp_callback(krp);
++      } else {
++              unsigned long r_flags;
++              /*
++               * Normal case; queue the callback for the thread.
++               */
++              CRYPTO_RETQ_LOCK();
++              if (CRYPTO_RETQ_EMPTY())
++                      wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++              TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
++              CRYPTO_RETQ_UNLOCK();
++      }
++}
++
++int
++crypto_getfeat(int *featp)
++{
++      int hid, kalg, feat = 0;
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              const struct cryptocap *cap = &crypto_drivers[hid];
++
++              if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
++                  !crypto_devallowsoft) {
++                      continue;
++              }
++              for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
++                      if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED)
++                              feat |=  1 << kalg;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++      *featp = feat;
++      return (0);
++}
++
++/*
++ * Crypto thread, dispatches crypto requests.
++ */
++static int
++crypto_proc(void *arg)
++{
++      struct cryptop *crp, *submit;
++      struct cryptkop *krp, *krpp;
++      struct cryptocap *cap;
++      u_int32_t hid;
++      int result, hint;
++      unsigned long q_flags;
++
++      ocf_daemonize("crypto");
++
++      CRYPTO_Q_LOCK();
++      for (;;) {
++              /*
++               * we need to make sure we don't get into a busy loop with nothing
++               * to do,  the two crypto_all_*blocked vars help us find out when
++               * we are all full and can do nothing on any driver or Q.  If so we
++               * wait for an unblock.
++               */
++              crypto_all_qblocked  = !list_empty(&crp_q);
++
++              /*
++               * Find the first element in the queue that can be
++               * processed and look-ahead to see if multiple ops
++               * are ready for the same driver.
++               */
++              submit = NULL;
++              hint = 0;
++              list_for_each_entry(crp, &crp_q, crp_next) {
++                      hid = CRYPTO_SESID2HID(crp->crp_sid);
++                      cap = crypto_checkdriver(hid);
++                      /*
++                       * Driver cannot disappear when there is an active
++                       * session.
++                       */
++                      KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++                          __func__, __LINE__));
++                      if (cap == NULL || cap->cc_dev == NULL) {
++                              /* Op needs to be migrated, process it. */
++                              if (submit == NULL)
++                                      submit = crp;
++                              break;
++                      }
++                      if (!cap->cc_qblocked) {
++                              if (submit != NULL) {
++                                      /*
++                                       * We stop on finding another op,
++                                       * regardless whether its for the same
++                                       * driver or not.  We could keep
++                                       * searching the queue but it might be
++                                       * better to just use a per-driver
++                                       * queue instead.
++                                       */
++                                      if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
++                                              hint = CRYPTO_HINT_MORE;
++                                      break;
++                              } else {
++                                      submit = crp;
++                                      if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
++                                              break;
++                                      /* keep scanning for more are q'd */
++                              }
++                      }
++              }
++              if (submit != NULL) {
++                      hid = CRYPTO_SESID2HID(submit->crp_sid);
++                      crypto_all_qblocked = 0;
++                      list_del(&submit->crp_next);
++                      crypto_drivers[hid].cc_qblocked = 1;
++                      cap = crypto_checkdriver(hid);
++                      CRYPTO_Q_UNLOCK();
++                      KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++                          __func__, __LINE__));
++                      result = crypto_invoke(cap, submit, hint);
++                      CRYPTO_Q_LOCK();
++                      if (result == ERESTART) {
++                              /*
++                               * The driver ran out of resources, mark the
++                               * driver ``blocked'' for cryptop's and put
++                               * the request back in the queue.  It would
++                               * best to put the request back where we got
++                               * it but that's hard so for now we put it
++                               * at the front.  This should be ok; putting
++                               * it at the end does not work.
++                               */
++                              /* XXX validate sid again? */
++                              list_add(&submit->crp_next, &crp_q);
++                              cryptostats.cs_blocks++;
++                      } else
++                              crypto_drivers[hid].cc_qblocked=0;
++              }
++
++              crypto_all_kqblocked = !list_empty(&crp_kq);
++
++              /* As above, but for key ops */
++              krp = NULL;
++              list_for_each_entry(krpp, &crp_kq, krp_next) {
++                      cap = crypto_checkdriver(krpp->krp_hid);
++                      if (cap == NULL || cap->cc_dev == NULL) {
++                              /*
++                               * Operation needs to be migrated, invalidate
++                               * the assigned device so it will reselect a
++                               * new one below.  Propagate the original
++                               * crid selection flags if supplied.
++                               */
++                              krp->krp_hid = krp->krp_crid &
++                                  (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE);
++                              if (krp->krp_hid == 0)
++                                      krp->krp_hid =
++                                  CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE;
++                              break;
++                      }
++                      if (!cap->cc_kqblocked) {
++                              krp = krpp;
++                              break;
++                      }
++              }
++              if (krp != NULL) {
++                      crypto_all_kqblocked = 0;
++                      list_del(&krp->krp_next);
++                      crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
++                      CRYPTO_Q_UNLOCK();
++                      result = crypto_kinvoke(krp, krp->krp_hid);
++                      CRYPTO_Q_LOCK();
++                      if (result == ERESTART) {
++                              /*
++                               * The driver ran out of resources, mark the
++                               * driver ``blocked'' for cryptkop's and put
++                               * the request back in the queue.  It would
++                               * best to put the request back where we got
++                               * it but that's hard so for now we put it
++                               * at the front.  This should be ok; putting
++                               * it at the end does not work.
++                               */
++                              /* XXX validate sid again? */
++                              list_add(&krp->krp_next, &crp_kq);
++                              cryptostats.cs_kblocks++;
++                      } else
++                              crypto_drivers[krp->krp_hid].cc_kqblocked = 0;
++              }
++
++              if (submit == NULL && krp == NULL) {
++                      /*
++                       * Nothing more to be processed.  Sleep until we're
++                       * woken because there are more ops to process.
++                       * This happens either by submission or by a driver
++                       * becoming unblocked and notifying us through
++                       * crypto_unblock.  Note that when we wakeup we
++                       * start processing each queue again from the
++                       * front. It's not clear that it's important to
++                       * preserve this ordering since ops may finish
++                       * out of order if dispatched to different devices
++                       * and some become blocked while others do not.
++                       */
++                      dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n",
++                                      __FUNCTION__,
++                                      list_empty(&crp_q), crypto_all_qblocked,
++                                      list_empty(&crp_kq), crypto_all_kqblocked);
++                      CRYPTO_Q_UNLOCK();
++                      crp_sleep = 1;
++                      wait_event_interruptible(cryptoproc_wait,
++                                      !(list_empty(&crp_q) || crypto_all_qblocked) ||
++                                      !(list_empty(&crp_kq) || crypto_all_kqblocked) ||
++                                      cryptoproc == (pid_t) -1);
++                      crp_sleep = 0;
++                      if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_lock_irq(&current->sigmask_lock);
++#endif
++                              flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_unlock_irq(&current->sigmask_lock);
++#endif
++                      }
++                      CRYPTO_Q_LOCK();
++                      dprintk("%s - awake\n", __FUNCTION__);
++                      if (cryptoproc == (pid_t) -1)
++                              break;
++                      cryptostats.cs_intrs++;
++              }
++      }
++      CRYPTO_Q_UNLOCK();
++      complete_and_exit(&cryptoproc_exited, 0);
++}
++
++/*
++ * Crypto returns thread, does callbacks for processed crypto requests.
++ * Callbacks are done here, rather than in the crypto drivers, because
++ * callbacks typically are expensive and would slow interrupt handling.
++ */
++static int
++crypto_ret_proc(void *arg)
++{
++      struct cryptop *crpt;
++      struct cryptkop *krpt;
++      unsigned long  r_flags;
++
++      ocf_daemonize("crypto_ret");
++
++      CRYPTO_RETQ_LOCK();
++      for (;;) {
++              /* Harvest return q's for completed ops */
++              crpt = NULL;
++              if (!list_empty(&crp_ret_q))
++                      crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next);
++              if (crpt != NULL)
++                      list_del(&crpt->crp_next);
++
++              krpt = NULL;
++              if (!list_empty(&crp_ret_kq))
++                      krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next);
++              if (krpt != NULL)
++                      list_del(&krpt->krp_next);
++
++              if (crpt != NULL || krpt != NULL) {
++                      CRYPTO_RETQ_UNLOCK();
++                      /*
++                       * Run callbacks unlocked.
++                       */
++                      if (crpt != NULL)
++                              crpt->crp_callback(crpt);
++                      if (krpt != NULL)
++                              krpt->krp_callback(krpt);
++                      CRYPTO_RETQ_LOCK();
++              } else {
++                      /*
++                       * Nothing more to be processed.  Sleep until we're
++                       * woken because there are more returns to process.
++                       */
++                      dprintk("%s - sleeping\n", __FUNCTION__);
++                      CRYPTO_RETQ_UNLOCK();
++                      wait_event_interruptible(cryptoretproc_wait,
++                                      cryptoretproc == (pid_t) -1 ||
++                                      !list_empty(&crp_ret_q) ||
++                                      !list_empty(&crp_ret_kq));
++                      if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_lock_irq(&current->sigmask_lock);
++#endif
++                              flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_unlock_irq(&current->sigmask_lock);
++#endif
++                      }
++                      CRYPTO_RETQ_LOCK();
++                      dprintk("%s - awake\n", __FUNCTION__);
++                      if (cryptoretproc == (pid_t) -1) {
++                              dprintk("%s - EXITING!\n", __FUNCTION__);
++                              break;
++                      }
++                      cryptostats.cs_rets++;
++              }
++      }
++      CRYPTO_RETQ_UNLOCK();
++      complete_and_exit(&cryptoretproc_exited, 0);
++}
++
++
++#if 0 /* should put this into /proc or something */
++static void
++db_show_drivers(void)
++{
++      int hid;
++
++      db_printf("%12s %4s %4s %8s %2s %2s\n"
++              , "Device"
++              , "Ses"
++              , "Kops"
++              , "Flags"
++              , "QB"
++              , "KB"
++      );
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              const struct cryptocap *cap = &crypto_drivers[hid];
++              if (cap->cc_dev == NULL)
++                      continue;
++              db_printf("%-12s %4u %4u %08x %2u %2u\n"
++                  , device_get_nameunit(cap->cc_dev)
++                  , cap->cc_sessions
++                  , cap->cc_koperations
++                  , cap->cc_flags
++                  , cap->cc_qblocked
++                  , cap->cc_kqblocked
++              );
++      }
++}
++
++DB_SHOW_COMMAND(crypto, db_show_crypto)
++{
++      struct cryptop *crp;
++
++      db_show_drivers();
++      db_printf("\n");
++
++      db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n",
++          "HID", "Caps", "Ilen", "Olen", "Etype", "Flags",
++          "Desc", "Callback");
++      TAILQ_FOREACH(crp, &crp_q, crp_next) {
++              db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n"
++                  , (int) CRYPTO_SESID2HID(crp->crp_sid)
++                  , (int) CRYPTO_SESID2CAPS(crp->crp_sid)
++                  , crp->crp_ilen, crp->crp_olen
++                  , crp->crp_etype
++                  , crp->crp_flags
++                  , crp->crp_desc
++                  , crp->crp_callback
++              );
++      }
++      if (!TAILQ_EMPTY(&crp_ret_q)) {
++              db_printf("\n%4s %4s %4s %8s\n",
++                  "HID", "Etype", "Flags", "Callback");
++              TAILQ_FOREACH(crp, &crp_ret_q, crp_next) {
++                      db_printf("%4u %4u %04x %8p\n"
++                          , (int) CRYPTO_SESID2HID(crp->crp_sid)
++                          , crp->crp_etype
++                          , crp->crp_flags
++                          , crp->crp_callback
++                      );
++              }
++      }
++}
++
++DB_SHOW_COMMAND(kcrypto, db_show_kcrypto)
++{
++      struct cryptkop *krp;
++
++      db_show_drivers();
++      db_printf("\n");
++
++      db_printf("%4s %5s %4s %4s %8s %4s %8s\n",
++          "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback");
++      TAILQ_FOREACH(krp, &crp_kq, krp_next) {
++              db_printf("%4u %5u %4u %4u %08x %4u %8p\n"
++                  , krp->krp_op
++                  , krp->krp_status
++                  , krp->krp_iparams, krp->krp_oparams
++                  , krp->krp_crid, krp->krp_hid
++                  , krp->krp_callback
++              );
++      }
++      if (!TAILQ_EMPTY(&crp_ret_q)) {
++              db_printf("%4s %5s %8s %4s %8s\n",
++                  "Op", "Status", "CRID", "HID", "Callback");
++              TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) {
++                      db_printf("%4u %5u %08x %4u %8p\n"
++                          , krp->krp_op
++                          , krp->krp_status
++                          , krp->krp_crid, krp->krp_hid
++                          , krp->krp_callback
++                      );
++              }
++      }
++}
++#endif
++
++
++static int
++crypto_init(void)
++{
++      int error;
++
++      dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init);
++
++      if (crypto_initted)
++              return 0;
++      crypto_initted = 1;
++
++      spin_lock_init(&crypto_drivers_lock);
++      spin_lock_init(&crypto_q_lock);
++      spin_lock_init(&crypto_ret_q_lock);
++
++      cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop),
++                                     0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++                                     , NULL
++#endif
++                                      );
++
++      cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc),
++                                     0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++                                     , NULL
++#endif
++                                      );
++
++      if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
++              printk("crypto: crypto_init cannot setup crypto zones\n");
++              error = ENOMEM;
++              goto bad;
++      }
++
++      crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
++      crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap),
++                      GFP_KERNEL);
++      if (crypto_drivers == NULL) {
++              printk("crypto: crypto_init cannot setup crypto drivers\n");
++              error = ENOMEM;
++              goto bad;
++      }
++
++      memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap));
++
++      init_completion(&cryptoproc_exited);
++      init_completion(&cryptoretproc_exited);
++
++      cryptoproc = 0; /* to avoid race condition where proc runs first */
++      cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES);
++      if (cryptoproc < 0) {
++              error = cryptoproc;
++              printk("crypto: crypto_init cannot start crypto thread; error %d",
++                      error);
++              goto bad;
++      }
++
++      cryptoretproc = 0; /* to avoid race condition where proc runs first */
++      cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES);
++      if (cryptoretproc < 0) {
++              error = cryptoretproc;
++              printk("crypto: crypto_init cannot start cryptoret thread; error %d",
++                              error);
++              goto bad;
++      }
++
++      return 0;
++bad:
++      crypto_exit();
++      return error;
++}
++
++
++static void
++crypto_exit(void)
++{
++      pid_t p;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      /*
++       * Terminate any crypto threads.
++       */
++
++      CRYPTO_DRIVER_LOCK();
++      p = cryptoproc;
++      cryptoproc = (pid_t) -1;
++      kill_proc(p, SIGTERM, 1);
++      wake_up_interruptible(&cryptoproc_wait);
++      CRYPTO_DRIVER_UNLOCK();
++
++      wait_for_completion(&cryptoproc_exited);
++
++      CRYPTO_DRIVER_LOCK();
++      p = cryptoretproc;
++      cryptoretproc = (pid_t) -1;
++      kill_proc(p, SIGTERM, 1);
++      wake_up_interruptible(&cryptoretproc_wait);
++      CRYPTO_DRIVER_UNLOCK();
++
++      wait_for_completion(&cryptoretproc_exited);
++
++      /* XXX flush queues??? */
++
++      /* 
++       * Reclaim dynamically allocated resources.
++       */
++      if (crypto_drivers != NULL)
++              kfree(crypto_drivers);
++
++      if (cryptodesc_zone != NULL)
++              kmem_cache_destroy(cryptodesc_zone);
++      if (cryptop_zone != NULL)
++              kmem_cache_destroy(cryptop_zone);
++}
++
++
++EXPORT_SYMBOL(crypto_newsession);
++EXPORT_SYMBOL(crypto_freesession);
++EXPORT_SYMBOL(crypto_get_driverid);
++EXPORT_SYMBOL(crypto_kregister);
++EXPORT_SYMBOL(crypto_register);
++EXPORT_SYMBOL(crypto_unregister);
++EXPORT_SYMBOL(crypto_unregister_all);
++EXPORT_SYMBOL(crypto_unblock);
++EXPORT_SYMBOL(crypto_dispatch);
++EXPORT_SYMBOL(crypto_kdispatch);
++EXPORT_SYMBOL(crypto_freereq);
++EXPORT_SYMBOL(crypto_getreq);
++EXPORT_SYMBOL(crypto_done);
++EXPORT_SYMBOL(crypto_kdone);
++EXPORT_SYMBOL(crypto_getfeat);
++EXPORT_SYMBOL(crypto_userasymcrypto);
++EXPORT_SYMBOL(crypto_getcaps);
++EXPORT_SYMBOL(crypto_find_driver);
++EXPORT_SYMBOL(crypto_find_device_byhid);
++
++module_init(crypto_init);
++module_exit(crypto_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/criov.c   2007-07-18 13:01:47.000000000 +1000
+@@ -0,0 +1,215 @@
++/*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $       */
++
++/*
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 1999 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/uio.h>
++#include <linux/skbuff.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <asm/io.h>
++
++#include <uio.h>
++#include <cryptodev.h>
++
++/*
++ * This macro is only for avoiding code duplication, as we need to skip
++ * given number of bytes in the same way in three functions below.
++ */
++#define       CUIO_SKIP()     do {                                            \
++      KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));           \
++      KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));           \
++      while (off > 0) {                                               \
++              KASSERT(iol >= 0, ("%s: empty in skip", __func__));     \
++              if (off < iov->iov_len)                                 \
++                      break;                                          \
++              off -= iov->iov_len;                                    \
++              iol--;                                                  \
++              iov++;                                                  \
++      }                                                               \
++} while (0)
++
++void
++cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++      unsigned count;
++
++      CUIO_SKIP();
++      while (len > 0) {
++              KASSERT(iol >= 0, ("%s: empty", __func__));
++              count = min((int)(iov->iov_len - off), len);
++              memcpy(cp, ((caddr_t)iov->iov_base) + off, count);
++              len -= count;
++              cp += count;
++              off = 0;
++              iol--;
++              iov++;
++      }
++}
++
++void
++cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++      unsigned count;
++
++      CUIO_SKIP();
++      while (len > 0) {
++              KASSERT(iol >= 0, ("%s: empty", __func__));
++              count = min((int)(iov->iov_len - off), len);
++              memcpy(((caddr_t)iov->iov_base) + off, cp, count);
++              len -= count;
++              cp += count;
++              off = 0;
++              iol--;
++              iov++;
++      }
++}
++
++/*
++ * Return a pointer to iov/offset of location in iovec list.
++ */
++struct iovec *
++cuio_getptr(struct uio *uio, int loc, int *off)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++
++      while (loc >= 0) {
++              /* Normal end of search */
++              if (loc < iov->iov_len) {
++                      *off = loc;
++                      return (iov);
++              }
++
++              loc -= iov->iov_len;
++              if (iol == 0) {
++                      if (loc == 0) {
++                              /* Point at the end of valid data */
++                              *off = iov->iov_len;
++                              return (iov);
++                      } else
++                              return (NULL);
++              } else {
++                      iov++, iol--;
++              }
++      }
++
++      return (NULL);
++}
++
++EXPORT_SYMBOL(cuio_copyback);
++EXPORT_SYMBOL(cuio_copydata);
++EXPORT_SYMBOL(cuio_getptr);
++
++
++static void
++skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len)
++{
++      int i;
++      if (offset < skb_headlen(skb)) {
++              memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len));
++              len -= skb_headlen(skb);
++              cp += skb_headlen(skb);
++      }
++      offset -= skb_headlen(skb);
++      for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) {
++              if (offset < skb_shinfo(skb)->frags[i].size) {
++                      memcpy(page_address(skb_shinfo(skb)->frags[i].page) +
++                                      skb_shinfo(skb)->frags[i].page_offset,
++                                      cp, min_t(int, skb_shinfo(skb)->frags[i].size, len));
++                      len -= skb_shinfo(skb)->frags[i].size;
++                      cp += skb_shinfo(skb)->frags[i].size;
++              }
++              offset -= skb_shinfo(skb)->frags[i].size;
++      }
++}
++
++void
++crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
++{
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              skb_copy_bits_back((struct sk_buff *)buf, off, in, size);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              cuio_copyback((struct uio *)buf, off, size, in);
++      else
++              bcopy(in, buf + off, size);
++}
++
++void
++crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
++{
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              skb_copy_bits((struct sk_buff *)buf, off, out, size);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              cuio_copydata((struct uio *)buf, off, size, out);
++      else
++              bcopy(buf + off, out, size);
++}
++
++int
++crypto_apply(int flags, caddr_t buf, int off, int len,
++    int (*f)(void *, void *, u_int), void *arg)
++{
++#if 0
++      int error;
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              error = XXXXXX((struct mbuf *)buf, off, len, f, arg);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              error = cuio_apply((struct uio *)buf, off, len, f, arg);
++      else
++              error = (*f)(arg, buf + off, len);
++      return (error);
++#else
++      KASSERT(0, ("crypto_apply not implemented!\n"));
++#endif
++      return 0;
++}
++
++EXPORT_SYMBOL(crypto_copyback);
++EXPORT_SYMBOL(crypto_copydata);
++EXPORT_SYMBOL(crypto_apply);
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/uio.h     2007-07-03 09:52:33.000000000 +1000
+@@ -0,0 +1,54 @@
++#ifndef _OCF_UIO_H_
++#define _OCF_UIO_H_
++
++#include <linux/uio.h>
++
++/*
++ * The linux uio.h doesn't have all we need.  To be fully api compatible
++ * with the BSD cryptodev,  we need to keep this around.  Perhaps this can
++ * be moved back into the linux/uio.h
++ *
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++struct uio {
++      struct  iovec *uio_iov;
++      int             uio_iovcnt;
++      off_t   uio_offset;
++      int             uio_resid;
++#if 0
++      enum    uio_seg uio_segflg;
++      enum    uio_rw uio_rw;
++      struct  thread *uio_td;
++#endif
++};
++
++#endif
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/talitos/talitos.c 2008-04-01 15:48:31.000000000 +1000
+@@ -0,0 +1,1359 @@
++/*
++ * crypto/ocf/talitos/talitos.c
++ *
++ * An OCF-Linux module that uses Freescale's SEC to do the crypto.
++ * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * This code written by Kim A. B. Phillips <kim.phillips@freescale.com>
++ * some code copied from files with the following:
++ * Copyright (C) 2004-2007 David McCullough <david_mccullough@securecomputing.com
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * ---------------------------------------------------------------------------
++ *
++ * NOTES:
++ *
++ * The Freescale SEC (also known as 'talitos') resides on the
++ * internal bus, and runs asynchronous to the processor core.  It has
++ * a wide gamut of cryptographic acceleration features, including single-
++ * pass IPsec (also known as algorithm chaining).  To properly utilize 
++ * all of the SEC's performance enhancing features, further reworking 
++ * of higher level code (framework, applications) will be necessary.
++ *
++ * The following table shows which SEC version is present in which devices:
++ * 
++ * Devices       SEC version
++ *
++ * 8272, 8248    SEC 1.0
++ * 885, 875      SEC 1.2
++ * 8555E, 8541E  SEC 2.0
++ * 8349E         SEC 2.01
++ * 8548E         SEC 2.1
++ *
++ * The following table shows the features offered by each SEC version:
++ *
++ *                           Max.   chan-
++ * version  Bus I/F       Clock  nels  DEU AESU AFEU MDEU PKEU RNG KEU
++ *
++ * SEC 1.0  internal 64b  100MHz   4     1    1    1    1    1   1   0
++ * SEC 1.2  internal 32b   66MHz   1     1    1    0    1    0   0   0
++ * SEC 2.0  internal 64b  166MHz   4     1    1    1    1    1   1   0
++ * SEC 2.01 internal 64b  166MHz   4     1    1    1    1    1   1   0
++ * SEC 2.1  internal 64b  333MHz   4     1    1    1    1    1   1   1
++ *
++ * Each execution unit in the SEC has two modes of execution; channel and
++ * slave/debug.  This driver employs the channel infrastructure in the
++ * device for convenience.  Only the RNG is directly accessed due to the
++ * convenience of its random fifo pool.  The relationship between the
++ * channels and execution units is depicted in the following diagram:
++ *
++ *    -------   ------------
++ * ---| ch0 |---|          |
++ *    -------   |          |
++ *              |          |------+-------+-------+-------+------------
++ *    -------   |          |      |       |       |       |           |
++ * ---| ch1 |---|          |      |       |       |       |           |
++ *    -------   |          |   ------  ------  ------  ------      ------
++ *              |controller|   |DEU |  |AESU|  |MDEU|  |PKEU| ...  |RNG |
++ *    -------   |          |   ------  ------  ------  ------      ------
++ * ---| ch2 |---|          |      |       |       |       |           |
++ *    -------   |          |      |       |       |       |           |
++ *              |          |------+-------+-------+-------+------------
++ *    -------   |          |
++ * ---| ch3 |---|          |
++ *    -------   ------------
++ *
++ * Channel ch0 may drive an aes operation to the aes unit (AESU),
++ * and, at the same time, ch1 may drive a message digest operation
++ * to the mdeu. Each channel has an input descriptor FIFO, and the 
++ * FIFO can contain, e.g. on the 8541E, up to 24 entries, before a
++ * a buffer overrun error is triggered. The controller is responsible
++ * for fetching the data from descriptor pointers, and passing the 
++ * data to the appropriate EUs. The controller also writes the 
++ * cryptographic operation's result to memory. The SEC notifies 
++ * completion by triggering an interrupt and/or setting the 1st byte 
++ * of the hdr field to 0xff.
++ *
++ * TODO:
++ * o support more algorithms
++ * o support more versions of the SEC
++ * o add support for linux 2.4
++ * o scatter-gather (sg) support
++ * o add support for public key ops (PKEU)
++ * o add statistics
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/skbuff.h>
++#include <asm/scatterlist.h>
++#include <linux/dma-mapping.h>  /* dma_map_single() */
++#include <linux/moduleparam.h>
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
++#include <linux/platform_device.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++#include <linux/of_platform.h>
++#endif
++
++#include <cryptodev.h>
++#include <uio.h>
++
++#define DRV_NAME "talitos" 
++
++#include "talitos_dev.h"
++#include "talitos_soft.h"
++
++#define read_random(p,l) get_random_bytes(p,l)
++
++const char talitos_driver_name[] = "Talitos OCF";
++const char talitos_driver_version[] = "0.2";
++
++static int talitos_newsession(device_t dev, u_int32_t *sidp,
++                                                              struct cryptoini *cri);
++static int talitos_freesession(device_t dev, u_int64_t tid);
++static int talitos_process(device_t dev, struct cryptop *crp, int hint);
++static void dump_talitos_status(struct talitos_softc *sc);
++static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td, 
++                                                              int chsel);
++static void talitos_doneprocessing(struct talitos_softc *sc);
++static void talitos_init_device(struct talitos_softc *sc);
++static void talitos_reset_device_master(struct talitos_softc *sc);
++static void talitos_reset_device(struct talitos_softc *sc);
++static void talitos_errorprocessing(struct talitos_softc *sc);
++#ifdef CONFIG_PPC_MERGE
++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match);
++static int talitos_remove(struct of_device *ofdev);
++#else
++static int talitos_probe(struct platform_device *pdev);
++static int talitos_remove(struct platform_device *pdev);
++#endif
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords);
++static void talitos_rng_init(struct talitos_softc *sc);
++#endif
++
++static device_method_t talitos_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, talitos_newsession),
++      DEVMETHOD(cryptodev_freesession,talitos_freesession),
++      DEVMETHOD(cryptodev_process,    talitos_process),
++};
++
++#define debug talitos_debug
++int talitos_debug = 0;
++module_param(talitos_debug, int, 0644);
++MODULE_PARM_DESC(talitos_debug, "Enable debug");
++
++static inline void talitos_write(volatile unsigned *addr, u32 val)
++{
++        out_be32(addr, val);
++}
++
++static inline u32 talitos_read(volatile unsigned *addr)
++{
++        u32 val;
++        val = in_be32(addr);
++        return val;
++}
++
++static void dump_talitos_status(struct talitos_softc *sc)
++{
++      unsigned int v, v_hi, i, *ptr;
++      v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
++      v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI);
++      printk(KERN_INFO "%s: MCR          0x%08x_%08x\n",
++                      device_get_nameunit(sc->sc_cdev), v, v_hi);
++      v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
++      v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
++      printk(KERN_INFO "%s: IMR          0x%08x_%08x\n",
++                      device_get_nameunit(sc->sc_cdev), v, v_hi);
++      v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
++      v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
++      printk(KERN_INFO "%s: ISR          0x%08x_%08x\n",
++                      device_get_nameunit(sc->sc_cdev), v, v_hi);
++      for (i = 0; i < sc->sc_num_channels; i++) { 
++              v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + 
++                      TALITOS_CH_CDPR);
++              v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + 
++                      TALITOS_CH_CDPR_HI);
++              printk(KERN_INFO "%s: CDPR     ch%d 0x%08x_%08x\n", 
++                              device_get_nameunit(sc->sc_cdev), i, v, v_hi);
++      }
++      for (i = 0; i < sc->sc_num_channels; i++) { 
++              v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + 
++                      TALITOS_CH_CCPSR);
++              v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + 
++                      TALITOS_CH_CCPSR_HI);
++              printk(KERN_INFO "%s: CCPSR    ch%d 0x%08x_%08x\n", 
++                              device_get_nameunit(sc->sc_cdev), i, v, v_hi);
++      }
++      ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF;
++      for (i = 0; i < 16; i++) { 
++              v = talitos_read(ptr++); v_hi = talitos_read(ptr++);
++              printk(KERN_INFO "%s: DESCBUF  ch0 0x%08x_%08x (tdp%02d)\n", 
++                              device_get_nameunit(sc->sc_cdev), v, v_hi, i);
++      }
++      return;
++}
++
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++/* 
++ * pull random numbers off the RNG FIFO, not exceeding amount available
++ */
++static int
++talitos_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++      struct talitos_softc *sc = (struct talitos_softc *) arg;
++      int rc;
++      u_int32_t v;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /* check for things like FIFO underflow */
++      v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
++      if (unlikely(v)) {
++              printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
++                              device_get_nameunit(sc->sc_cdev), v);
++              return 0;
++      }
++      /*
++       * OFL is number of available 64-bit words, 
++       * shift and convert to a 32-bit word count
++       */
++      v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI);
++      v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1);
++      if (maxwords > v)
++              maxwords = v;
++      for (rc = 0; rc < maxwords; rc++) {
++              buf[rc] = talitos_read(sc->sc_base_addr + 
++                      TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
++      }
++      if (maxwords & 1) {
++              /* 
++               * RNG will complain with an AE in the RNGISR
++               * if we don't complete the pairs of 32-bit reads
++               * to its 64-bit register based FIFO
++               */
++              v = talitos_read(sc->sc_base_addr + 
++                      TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
++      }
++
++      return rc;
++}
++
++static void
++talitos_rng_init(struct talitos_softc *sc)
++{
++      u_int32_t v;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      /* reset RNG EU */
++      v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI);
++      v |= TALITOS_RNGRCR_HI_SR;
++      talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v);
++      while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI) 
++              & TALITOS_RNGSR_HI_RD) == 0)
++                      cpu_relax();
++      /*
++       * we tell the RNG to start filling the RNG FIFO
++       * by writing the RNGDSR 
++       */
++      v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI);
++      talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v);
++      /*
++       * 64 bits of data will be pushed onto the FIFO every 
++       * 256 SEC cycles until the FIFO is full.  The RNG then 
++       * attempts to keep the FIFO full.
++       */
++      v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
++      if (v) {
++              printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
++                      device_get_nameunit(sc->sc_cdev), v);
++              return;
++      }
++      /*
++       * n.b. we need to add a FIPS test here - if the RNG is going 
++       * to fail, it's going to fail at reset time
++       */
++      return;
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++/*
++ * Generate a new software session.
++ */
++static int
++talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++      struct cryptoini *c, *encini = NULL, *macini = NULL;
++      struct talitos_softc *sc = device_get_softc(dev);
++      struct talitos_session *ses = NULL;
++      int sesn;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      if (sidp == NULL || cri == NULL || sc == NULL) {
++              DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++      for (c = cri; c != NULL; c = c->cri_next) {
++              if (c->cri_alg == CRYPTO_MD5 ||
++                  c->cri_alg == CRYPTO_MD5_HMAC ||
++                  c->cri_alg == CRYPTO_SHA1 ||
++                  c->cri_alg == CRYPTO_SHA1_HMAC ||
++                  c->cri_alg == CRYPTO_NULL_HMAC) {
++                      if (macini)
++                              return EINVAL;
++                      macini = c;
++              } else if (c->cri_alg == CRYPTO_DES_CBC ||
++                  c->cri_alg == CRYPTO_3DES_CBC ||
++                  c->cri_alg == CRYPTO_AES_CBC ||
++                  c->cri_alg == CRYPTO_NULL_CBC) {
++                      if (encini)
++                              return EINVAL;
++                      encini = c;
++              } else {
++                      DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg);
++                      return EINVAL;
++              }
++      }
++      if (encini == NULL && macini == NULL)
++              return EINVAL;
++      if (encini) {   
++              /* validate key length */
++              switch (encini->cri_alg) {
++              case CRYPTO_DES_CBC:
++                      if (encini->cri_klen != 64)
++                              return EINVAL;
++                      break;
++              case CRYPTO_3DES_CBC:
++                      if (encini->cri_klen != 192) {
++                              return EINVAL;
++                      }
++                      break;
++              case CRYPTO_AES_CBC:
++                      if (encini->cri_klen != 128 &&
++                          encini->cri_klen != 192 &&
++                          encini->cri_klen != 256)
++                              return EINVAL;
++                      break;
++              default:
++                      DPRINTF("UNKNOWN encini->cri_alg %d\n", 
++                              encini->cri_alg);
++                      return EINVAL;
++              }
++      }
++
++      if (sc->sc_sessions == NULL) {
++              ses = sc->sc_sessions = (struct talitos_session *)
++                      kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC);
++              if (ses == NULL)
++                      return ENOMEM;
++              memset(ses, 0, sizeof(struct talitos_session));
++              sesn = 0;
++              sc->sc_nsessions = 1;
++      } else {
++              for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++                      if (sc->sc_sessions[sesn].ses_used == 0) {
++                              ses = &sc->sc_sessions[sesn];
++                              break;
++                      }
++              }
++
++              if (ses == NULL) {
++                      /* allocating session */
++                      sesn = sc->sc_nsessions;
++                      ses = (struct talitos_session *) kmalloc(
++                              (sesn + 1) * sizeof(struct talitos_session), 
++                              SLAB_ATOMIC);
++                      if (ses == NULL)
++                              return ENOMEM;
++                      memset(ses, 0,
++                              (sesn + 1) * sizeof(struct talitos_session));
++                      memcpy(ses, sc->sc_sessions, 
++                              sesn * sizeof(struct talitos_session));
++                      memset(sc->sc_sessions, 0,
++                              sesn * sizeof(struct talitos_session));
++                      kfree(sc->sc_sessions);
++                      sc->sc_sessions = ses;
++                      ses = &sc->sc_sessions[sesn];
++                      sc->sc_nsessions++;
++              }
++      }
++
++      ses->ses_used = 1;
++
++      if (encini) {
++              /* get an IV */
++              /* XXX may read fewer than requested */
++              read_random(ses->ses_iv, sizeof(ses->ses_iv));
++
++              ses->ses_klen = (encini->cri_klen + 7) / 8;
++              memcpy(ses->ses_key, encini->cri_key, ses->ses_klen);
++              if (macini) {
++                      /* doing hash on top of cipher */
++                      ses->ses_hmac_len = (macini->cri_klen + 7) / 8;
++                      memcpy(ses->ses_hmac, macini->cri_key,
++                              ses->ses_hmac_len);
++              }
++      } else if (macini) {
++              /* doing hash */
++              ses->ses_klen = (macini->cri_klen + 7) / 8;
++              memcpy(ses->ses_key, macini->cri_key, ses->ses_klen);
++      }
++
++      /* back compat way of determining MSC result len */
++      if (macini) {
++              ses->ses_mlen = macini->cri_mlen;
++              if (ses->ses_mlen == 0) {
++                      if (macini->cri_alg == CRYPTO_MD5_HMAC)
++                              ses->ses_mlen = MD5_HASH_LEN;
++                      else
++                              ses->ses_mlen = SHA1_HASH_LEN;
++              }
++      }
++
++      /* really should make up a template td here, 
++       * and only fill things like i/o and direction in process() */
++
++      /* assign session ID */
++      *sidp = TALITOS_SID(sc->sc_num, sesn);
++      return 0;
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++talitos_freesession(device_t dev, u_int64_t tid)
++{
++      struct talitos_softc *sc = device_get_softc(dev);
++      int session, ret;
++      u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++      if (sc == NULL)
++              return EINVAL;
++      session = TALITOS_SESSION(sid);
++      if (session < sc->sc_nsessions) {
++              memset(&sc->sc_sessions[session], 0,
++                      sizeof(sc->sc_sessions[session]));
++              ret = 0;
++      } else
++              ret = EINVAL;
++      return ret;
++}
++
++/*
++ * launch device processing - it will come back with done notification 
++ * in the form of an interrupt and/or HDR_DONE_BITS in header 
++ */
++static int 
++talitos_submit(
++      struct talitos_softc *sc,
++      struct talitos_desc *td,
++      int chsel)
++{
++      u_int32_t v;
++
++      v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE);
++      talitos_write(sc->sc_base_addr + 
++              chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0);
++      talitos_write(sc->sc_base_addr + 
++              chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v);
++      return 0;
++}
++
++static int
++talitos_process(device_t dev, struct cryptop *crp, int hint)
++{
++      int i, err = 0, ivsize;
++      struct talitos_softc *sc = device_get_softc(dev);
++      struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++      caddr_t iv;
++      struct talitos_session *ses;
++      struct talitos_desc *td;
++      unsigned long flags;
++      /* descriptor mappings */
++      int hmac_key, hmac_data, cipher_iv, cipher_key, 
++              in_fifo, out_fifo, cipher_iv_out;
++      static int chsel = -1;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
++              return EINVAL;
++      }
++      crp->crp_etype = 0;
++      if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
++              return EINVAL;
++      }
++
++      ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)];
++
++        /* enter the channel scheduler */ 
++      spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++      /* reuse channel that already had/has requests for the required EU */
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg)
++                      break;
++      }
++      if (i == sc->sc_num_channels) {
++              /*
++               * haven't seen this algo the last sc_num_channels or more
++               * use round robin in this case
++               * nb: sc->sc_num_channels must be power of 2 
++               */
++              chsel = (chsel + 1) & (sc->sc_num_channels - 1);
++      } else {
++              /*
++               * matches channel with same target execution unit; 
++               * use same channel in this case
++               */
++              chsel = i;
++      }
++      sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg;
++
++        /* release the channel scheduler lock */ 
++      spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++      /* acquire the selected channel fifo lock */
++      spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags);
++
++      /* find and reserve next available descriptor-cryptop pair */
++      for (i = 0; i < sc->sc_chfifo_len; i++) {
++              if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) {
++                      /* 
++                       * ensure correct descriptor formation by
++                       * avoiding inadvertently setting "optional" entries
++                       * e.g. not using "optional" dptr2 for MD/HMAC descs
++                       */
++                      memset(&sc->sc_chnfifo[chsel][i].cf_desc,
++                              0, sizeof(*td));
++                      /* reserve it with done notification request bit */
++                      sc->sc_chnfifo[chsel][i].cf_desc.hdr |= 
++                              TALITOS_DONE_NOTIFY;
++                      break;
++              }
++      }
++      spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags);
++
++      if (i == sc->sc_chfifo_len) {
++              /* fifo full */
++              err = ERESTART;
++              goto errout;
++      }
++      
++      td = &sc->sc_chnfifo[chsel][i].cf_desc;
++      sc->sc_chnfifo[chsel][i].cf_crp = crp;
++
++      crd1 = crp->crp_desc;
++      if (crd1 == NULL) {
++              err = EINVAL;
++              goto errout;
++      }
++      crd2 = crd1->crd_next;
++      /* prevent compiler warning */
++      hmac_key = 0;
++      hmac_data = 0;
++      if (crd2 == NULL) {
++              td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU;
++              /* assign descriptor dword ptr mappings for this desc. type */
++              cipher_iv = 1;
++              cipher_key = 2;
++              in_fifo = 3;
++              cipher_iv_out = 5;
++              if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                  crd1->crd_alg == CRYPTO_SHA1 ||
++                  crd1->crd_alg == CRYPTO_MD5) {
++                      out_fifo = 5;
++                      maccrd = crd1;
++                      enccrd = NULL;
++              } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++                  crd1->crd_alg == CRYPTO_3DES_CBC ||
++                  crd1->crd_alg == CRYPTO_AES_CBC ||
++                  crd1->crd_alg == CRYPTO_ARC4) {
++                      out_fifo = 4;
++                      maccrd = NULL;
++                      enccrd = crd1;
++              } else {
++                      DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg);
++                      err = EINVAL;
++                      goto errout;
++              }
++      } else {
++              if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) {
++                      td->hdr |= TD_TYPE_IPSEC_ESP;
++              } else {
++                      DPRINTF("unimplemented: multiple descriptor ipsec\n");
++                      err = EINVAL;
++                      goto errout;
++              }
++              /* assign descriptor dword ptr mappings for this desc. type */
++              hmac_key = 0;
++              hmac_data = 1;
++              cipher_iv = 2;
++              cipher_key = 3;
++              in_fifo = 4;
++              out_fifo = 5;
++              cipher_iv_out = 6;
++              if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++                     crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++                     crd1->crd_alg == CRYPTO_MD5 ||
++                     crd1->crd_alg == CRYPTO_SHA1) &&
++                  (crd2->crd_alg == CRYPTO_DES_CBC ||
++                   crd2->crd_alg == CRYPTO_3DES_CBC ||
++                   crd2->crd_alg == CRYPTO_AES_CBC ||
++                   crd2->crd_alg == CRYPTO_ARC4) &&
++                  ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++                      maccrd = crd1;
++                      enccrd = crd2;
++              } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++                   crd1->crd_alg == CRYPTO_ARC4 ||
++                   crd1->crd_alg == CRYPTO_3DES_CBC ||
++                   crd1->crd_alg == CRYPTO_AES_CBC) &&
++                  (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++                     crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++                     crd2->crd_alg == CRYPTO_MD5 ||
++                     crd2->crd_alg == CRYPTO_SHA1) &&
++                  (crd1->crd_flags & CRD_F_ENCRYPT)) {
++                      enccrd = crd1;
++                      maccrd = crd2;
++              } else {
++                      /* We cannot order the SEC as requested */
++                      printk("%s: cannot do the order\n",
++                                      device_get_nameunit(sc->sc_cdev));
++                      err = EINVAL;
++                      goto errout;
++              }
++      }
++      /* assign in_fifo and out_fifo based on input/output struct type */
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              /* using SKB buffers */
++              struct sk_buff *skb = (struct sk_buff *)crp->crp_buf;
++              if (skb_shinfo(skb)->nr_frags) {
++                      printk("%s: skb frags unimplemented\n",
++                                      device_get_nameunit(sc->sc_cdev));
++                      err = EINVAL;
++                      goto errout;
++              }
++              td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data, 
++                      skb->len, DMA_TO_DEVICE);
++              td->ptr[in_fifo].len = skb->len;
++              td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data, 
++                      skb->len, DMA_TO_DEVICE);
++              td->ptr[out_fifo].len = skb->len;
++              td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data,
++                      skb->len, DMA_TO_DEVICE);
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              /* using IOV buffers */
++              struct uio *uiop = (struct uio *)crp->crp_buf;
++              if (uiop->uio_iovcnt > 1) {
++                      printk("%s: iov frags unimplemented\n",
++                                      device_get_nameunit(sc->sc_cdev));
++                      err = EINVAL;
++                      goto errout;
++              }
++              td->ptr[in_fifo].ptr = dma_map_single(NULL,
++                      uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE);
++              td->ptr[in_fifo].len = crp->crp_ilen;
++              /* crp_olen is never set; always use crp_ilen */
++              td->ptr[out_fifo].ptr = dma_map_single(NULL,
++                      uiop->uio_iov->iov_base,
++                      crp->crp_ilen, DMA_TO_DEVICE);
++              td->ptr[out_fifo].len = crp->crp_ilen;
++      } else {
++              /* using contig buffers */
++              td->ptr[in_fifo].ptr = dma_map_single(NULL,
++                      crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
++              td->ptr[in_fifo].len = crp->crp_ilen;
++              td->ptr[out_fifo].ptr = dma_map_single(NULL,
++                      crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
++              td->ptr[out_fifo].len = crp->crp_ilen;
++      }
++      if (enccrd) {
++              switch (enccrd->crd_alg) {
++              case CRYPTO_3DES_CBC:
++                      td->hdr |= TALITOS_MODE0_DEU_3DES;
++                      /* FALLTHROUGH */
++              case CRYPTO_DES_CBC:
++                      td->hdr |= TALITOS_SEL0_DEU
++                              |  TALITOS_MODE0_DEU_CBC;
++                      if (enccrd->crd_flags & CRD_F_ENCRYPT)
++                              td->hdr |= TALITOS_MODE0_DEU_ENC;
++                      ivsize = 2*sizeof(u_int32_t);
++                      DPRINTF("%cDES ses %d ch %d len %d\n",
++                              (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1',
++                              (u32)TALITOS_SESSION(crp->crp_sid),
++                              chsel, td->ptr[in_fifo].len);
++                      break;
++              case CRYPTO_AES_CBC:
++                      td->hdr |= TALITOS_SEL0_AESU
++                              |  TALITOS_MODE0_AESU_CBC;
++                      if (enccrd->crd_flags & CRD_F_ENCRYPT)
++                              td->hdr |= TALITOS_MODE0_AESU_ENC;
++                      ivsize = 4*sizeof(u_int32_t);
++                      DPRINTF("AES  ses %d ch %d len %d\n",
++                              (u32)TALITOS_SESSION(crp->crp_sid),
++                              chsel, td->ptr[in_fifo].len);
++                      break;
++              default:
++                      printk("%s: unimplemented enccrd->crd_alg %d\n",
++                                      device_get_nameunit(sc->sc_cdev), enccrd->crd_alg);
++                      err = EINVAL;
++                      goto errout;
++              }
++              /*
++               * Setup encrypt/decrypt state.  When using basic ops
++               * we can't use an inline IV because hash/crypt offset
++               * must be from the end of the IV to the start of the
++               * crypt data and this leaves out the preceding header
++               * from the hash calculation.  Instead we place the IV
++               * in the state record and set the hash/crypt offset to
++               * copy both the header+IV.
++               */
++              if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++                      td->hdr |= TALITOS_DIR_OUTBOUND; 
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                              iv = enccrd->crd_iv;
++                      else
++                              iv = (caddr_t) ses->ses_iv;
++                      if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                  enccrd->crd_inject, ivsize, iv);
++                      }
++              } else {
++                      td->hdr |= TALITOS_DIR_INBOUND; 
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++                              iv = enccrd->crd_iv;
++                              bcopy(enccrd->crd_iv, iv, ivsize);
++                      } else {
++                              iv = (caddr_t) ses->ses_iv;
++                              crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                  enccrd->crd_inject, ivsize, iv);
++                      }
++              }
++              td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize, 
++                      DMA_TO_DEVICE);
++              td->ptr[cipher_iv].len = ivsize;
++              /*
++               * we don't need the cipher iv out length/pointer
++               * field to do ESP IPsec. Therefore we set the len field as 0,
++               * which tells the SEC not to do anything with this len/ptr
++               * field. Previously, when length/pointer as pointing to iv,
++               * it gave us corruption of packets.
++               */
++              td->ptr[cipher_iv_out].len = 0;
++      }
++      if (enccrd && maccrd) {
++              /* this is ipsec only for now */
++              td->hdr |= TALITOS_SEL1_MDEU
++                      |  TALITOS_MODE1_MDEU_INIT
++                      |  TALITOS_MODE1_MDEU_PAD;
++              switch (maccrd->crd_alg) {
++                      case    CRYPTO_MD5:     
++                              td->hdr |= TALITOS_MODE1_MDEU_MD5;
++                              break;
++                      case    CRYPTO_MD5_HMAC:        
++                              td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC;
++                              break;
++                      case    CRYPTO_SHA1:    
++                              td->hdr |= TALITOS_MODE1_MDEU_SHA1;
++                              break;
++                      case    CRYPTO_SHA1_HMAC:       
++                              td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC;
++                              break;
++                      default:
++                              /* We cannot order the SEC as requested */
++                              printk("%s: cannot do the order\n",
++                                              device_get_nameunit(sc->sc_cdev));
++                              err = EINVAL;
++                              goto errout;
++              }
++              if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
++                 (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
++                      /*
++                       * The offset from hash data to the start of
++                       * crypt data is the difference in the skips.
++                       */
++                      /* ipsec only for now */
++                      td->ptr[hmac_key].ptr = dma_map_single(NULL, 
++                              ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE);
++                      td->ptr[hmac_key].len = ses->ses_hmac_len;
++                      td->ptr[in_fifo].ptr  += enccrd->crd_skip;
++                      td->ptr[in_fifo].len  =  enccrd->crd_len;
++                      td->ptr[out_fifo].ptr += enccrd->crd_skip;
++                      td->ptr[out_fifo].len =  enccrd->crd_len;
++                      /* bytes of HMAC to postpend to ciphertext */
++                      td->ptr[out_fifo].extent =  ses->ses_mlen;
++                      td->ptr[hmac_data].ptr += maccrd->crd_skip; 
++                      td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip;
++              }
++              if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++                      printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n",
++                                      device_get_nameunit(sc->sc_cdev));
++              }
++      }
++      if (!enccrd && maccrd) {
++              /* single MD5 or SHA */
++              td->hdr |= TALITOS_SEL0_MDEU
++                              |  TALITOS_MODE0_MDEU_INIT
++                              |  TALITOS_MODE0_MDEU_PAD;
++              switch (maccrd->crd_alg) {
++                      case    CRYPTO_MD5:     
++                              td->hdr |= TALITOS_MODE0_MDEU_MD5;
++                              DPRINTF("MD5  ses %d ch %d len %d\n",
++                                      (u32)TALITOS_SESSION(crp->crp_sid), 
++                                      chsel, td->ptr[in_fifo].len);
++                              break;
++                      case    CRYPTO_MD5_HMAC:        
++                              td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC;
++                              break;
++                      case    CRYPTO_SHA1:    
++                              td->hdr |= TALITOS_MODE0_MDEU_SHA1;
++                              DPRINTF("SHA1 ses %d ch %d len %d\n",
++                                      (u32)TALITOS_SESSION(crp->crp_sid), 
++                                      chsel, td->ptr[in_fifo].len);
++                              break;
++                      case    CRYPTO_SHA1_HMAC:       
++                              td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC;
++                              break;
++                      default:
++                              /* We cannot order the SEC as requested */
++                              DPRINTF("cannot do the order\n");
++                              err = EINVAL;
++                              goto errout;
++              }
++
++              if (crp->crp_flags & CRYPTO_F_IOV)
++                      td->ptr[out_fifo].ptr += maccrd->crd_inject;
++
++              if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
++                 (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
++                      td->ptr[hmac_key].ptr = dma_map_single(NULL, 
++                              ses->ses_hmac, ses->ses_hmac_len, 
++                              DMA_TO_DEVICE);
++                      td->ptr[hmac_key].len = ses->ses_hmac_len;
++              }
++      } 
++      else {
++              /* using process key (session data has duplicate) */
++              td->ptr[cipher_key].ptr = dma_map_single(NULL, 
++                      enccrd->crd_key, (enccrd->crd_klen + 7) / 8, 
++                      DMA_TO_DEVICE);
++              td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8;
++      }
++      /* descriptor complete - GO! */
++      return talitos_submit(sc, td, chsel);
++
++errout:
++      if (err != ERESTART) {
++              crp->crp_etype = err;
++              crypto_done(crp);
++      }
++      return err;
++}
++
++/* go through all channels descriptors, notifying OCF what has 
++ * _and_hasn't_ successfully completed and reset the device 
++ * (otherwise it's up to decoding desc hdrs!)
++ */
++static void talitos_errorprocessing(struct talitos_softc *sc)
++{
++      unsigned long flags;
++      int i, j;
++
++      /* disable further scheduling until under control */
++      spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++      if (debug) dump_talitos_status(sc);
++      /* go through descriptors, try and salvage those successfully done, 
++       * and EIO those that weren't
++       */
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
++              for (j = 0; j < sc->sc_chfifo_len; j++) {
++                      if (sc->sc_chnfifo[i][j].cf_desc.hdr) {
++                              if ((sc->sc_chnfifo[i][j].cf_desc.hdr 
++                                      & TALITOS_HDR_DONE_BITS) 
++                                      != TALITOS_HDR_DONE_BITS) {
++                                      /* this one didn't finish */
++                                      /* signify in crp->etype */
++                                      sc->sc_chnfifo[i][j].cf_crp->crp_etype 
++                                              = EIO;
++                              }
++                      } else
++                              continue; /* free entry */
++                      /* either way, notify ocf */
++                      crypto_done(sc->sc_chnfifo[i][j].cf_crp);
++                      /* and tag it available again
++                       *
++                       * memset to ensure correct descriptor formation by
++                       * avoiding inadvertently setting "optional" entries
++                       * e.g. not using "optional" dptr2 MD/HMAC processing
++                       */
++                      memset(&sc->sc_chnfifo[i][j].cf_desc,
++                              0, sizeof(struct talitos_desc));
++              }
++              spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
++      }
++      /* reset and initialize the SEC h/w device */
++      talitos_reset_device(sc);
++      talitos_init_device(sc);
++#ifdef CONFIG_OCF_RANDOMHARVEST
++      if (sc->sc_exec_units & TALITOS_HAS_EU_RNG)
++              talitos_rng_init(sc);
++#endif
++
++      /* Okay. Stand by. */
++      spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++      return;
++}
++
++/* go through all channels descriptors, notifying OCF what's been done */
++static void talitos_doneprocessing(struct talitos_softc *sc)
++{
++      unsigned long flags;
++      int i, j;
++
++      /* go through descriptors looking for done bits */
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
++              for (j = 0; j < sc->sc_chfifo_len; j++) {
++                      /* descriptor has done bits set? */
++                      if ((sc->sc_chnfifo[i][j].cf_desc.hdr 
++                              & TALITOS_HDR_DONE_BITS) 
++                              == TALITOS_HDR_DONE_BITS) {
++                              /* notify ocf */
++                              crypto_done(sc->sc_chnfifo[i][j].cf_crp);
++                              /* and tag it available again
++                               *
++                               * memset to ensure correct descriptor formation by
++                               * avoiding inadvertently setting "optional" entries
++                               * e.g. not using "optional" dptr2 MD/HMAC processing
++                               */
++                              memset(&sc->sc_chnfifo[i][j].cf_desc,
++                                      0, sizeof(struct talitos_desc));
++                      }
++              }
++              spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
++      }
++      return;
++}
++
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++talitos_intr(int irq, void *arg)
++#else
++talitos_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++      struct talitos_softc *sc = arg;
++      u_int32_t v, v_hi;
++      
++      /* ack */
++      v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
++      v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
++      talitos_write(sc->sc_base_addr + TALITOS_ICR, v);
++      talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi);
++
++      if (unlikely(v & TALITOS_ISR_ERROR)) {
++              /* Okay, Houston, we've had a problem here. */
++              printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n",
++                              device_get_nameunit(sc->sc_cdev), v, v_hi);
++              talitos_errorprocessing(sc);
++      } else
++      if (likely(v & TALITOS_ISR_DONE)) {
++              talitos_doneprocessing(sc);
++      }
++      return IRQ_HANDLED;
++}
++
++/*
++ * Initialize registers we need to touch only once.
++ */
++static void
++talitos_init_device(struct talitos_softc *sc)
++{
++      u_int32_t v;
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /* init all channels */
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              v = talitos_read(sc->sc_base_addr + 
++                      i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI);
++              v |= TALITOS_CH_CCCR_HI_CDWE
++                |  TALITOS_CH_CCCR_HI_CDIE;  /* invoke interrupt if done */
++              talitos_write(sc->sc_base_addr + 
++                      i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v);
++      }
++      /* enable all interrupts */
++      v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
++      v |= TALITOS_IMR_ALL;
++      talitos_write(sc->sc_base_addr + TALITOS_IMR, v);
++      v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
++      v |= TALITOS_IMR_HI_ERRONLY;
++      talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v);
++      return;
++}
++
++/*
++ * set the master reset bit on the device.
++ */
++static void
++talitos_reset_device_master(struct talitos_softc *sc)
++{
++      u_int32_t v;
++
++      /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */
++      v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
++      talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR);
++
++      while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR)
++              cpu_relax();
++
++      return;
++}
++
++/*
++ * Resets the device.  Values in the registers are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++talitos_reset_device(struct talitos_softc *sc)
++{
++      u_int32_t v;
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      /*
++       * Master reset
++       * errata documentation: warning: certain SEC interrupts 
++       * are not fully cleared by writing the MCR:SWR bit, 
++       * set bit twice to completely reset 
++       */
++      talitos_reset_device_master(sc);        /* once */
++      talitos_reset_device_master(sc);        /* and once again */
++      
++      /* reset all channels */
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++                      TALITOS_CH_CCCR);
++              talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++                      TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET);
++      }
++}
++
++/* Set up the crypto device structure, private data,
++ * and anything else we need before we start */
++#ifdef CONFIG_PPC_MERGE
++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match)
++#else
++static int talitos_probe(struct platform_device *pdev)
++#endif
++{
++      struct talitos_softc *sc = NULL;
++      struct resource *r;
++#ifdef CONFIG_PPC_MERGE
++      struct device *device = &ofdev->dev;
++      struct device_node *np = ofdev->node;
++      const unsigned int *prop;
++      int err;
++      struct resource res;
++#endif
++      static int num_chips = 0;
++      int rc;
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++      if (!sc)
++              return -ENOMEM;
++      memset(sc, 0, sizeof(*sc));
++
++      softc_device_init(sc, DRV_NAME, num_chips, talitos_methods);
++
++      sc->sc_irq = -1;
++      sc->sc_cid = -1;
++#ifndef CONFIG_PPC_MERGE
++      sc->sc_dev = pdev;
++#endif
++      sc->sc_num = num_chips++;
++
++#ifdef CONFIG_PPC_MERGE
++      dev_set_drvdata(device, sc);
++#else
++      platform_set_drvdata(sc->sc_dev, sc);
++#endif
++
++      /* get the irq line */
++#ifdef CONFIG_PPC_MERGE
++      err = of_address_to_resource(np, 0, &res);
++      if (err)
++              return -EINVAL;
++      r = &res;
++
++      sc->sc_irq = irq_of_parse_and_map(np, 0);
++#else
++      /* get a pointer to the register memory */
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      sc->sc_irq = platform_get_irq(pdev, 0);
++#endif
++      rc = request_irq(sc->sc_irq, talitos_intr, 0,
++                      device_get_nameunit(sc->sc_cdev), sc);
++      if (rc) {
++              printk(KERN_ERR "%s: failed to hook irq %d\n", 
++                              device_get_nameunit(sc->sc_cdev), sc->sc_irq);
++              sc->sc_irq = -1;
++              goto out;
++      }
++
++      sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start));
++      if (!sc->sc_base_addr) {
++              printk(KERN_ERR "%s: failed to ioremap\n",
++                              device_get_nameunit(sc->sc_cdev));
++              goto out;
++      }
++
++      /* figure out our SEC's properties and capabilities */
++      sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32
++               | talitos_read(sc->sc_base_addr + TALITOS_ID_HI);
++      DPRINTF("sec id 0x%llx\n", sc->sc_chiprev);
++
++#ifdef CONFIG_PPC_MERGE
++      /* get SEC properties from device tree, defaulting to SEC 2.0 */
++
++      prop = of_get_property(np, "num-channels", NULL);
++      sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0;
++
++      prop = of_get_property(np, "channel-fifo-len", NULL);
++      sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0;
++
++      prop = of_get_property(np, "exec-units-mask", NULL);
++      sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0;
++
++      prop = of_get_property(np, "descriptor-types-mask", NULL);
++      sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0;
++#else
++      /* bulk should go away with openfirmware flat device tree support */
++      if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) {
++              sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0;
++              sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0;
++              sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0;
++              sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0;
++      } else {
++              printk(KERN_ERR "%s: failed to id device\n",
++                              device_get_nameunit(sc->sc_cdev));
++              goto out;
++      }
++#endif
++
++      /* + 1 is for the meta-channel lock used by the channel scheduler */
++      sc->sc_chnfifolock = (spinlock_t *) kmalloc(
++              (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL);
++      if (!sc->sc_chnfifolock)
++              goto out;
++      for (i = 0; i < sc->sc_num_channels + 1; i++) {
++              spin_lock_init(&sc->sc_chnfifolock[i]);
++      }
++
++      sc->sc_chnlastalg = (int *) kmalloc(
++              sc->sc_num_channels * sizeof(int), GFP_KERNEL);
++      if (!sc->sc_chnlastalg)
++              goto out;
++      memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int));
++
++      sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc(
++              sc->sc_num_channels * sizeof(struct desc_cryptop_pair *), 
++              GFP_KERNEL);
++      if (!sc->sc_chnfifo)
++              goto out;
++      for (i = 0; i < sc->sc_num_channels; i++) {
++              sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc(
++                      sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair), 
++                      GFP_KERNEL);
++              if (!sc->sc_chnfifo[i])
++                      goto out;
++              memset(sc->sc_chnfifo[i], 0, 
++                      sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair));
++      }
++
++      /* reset and initialize the SEC h/w device */
++      talitos_reset_device(sc);
++      talitos_init_device(sc);
++
++      sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++      if (sc->sc_cid < 0) {
++              printk(KERN_ERR "%s: could not get crypto driver id\n",
++                              device_get_nameunit(sc->sc_cdev));
++              goto out;
++      }
++
++      /* register algorithms with the framework */
++      printk("%s:", device_get_nameunit(sc->sc_cdev));
++
++      if (sc->sc_exec_units & TALITOS_HAS_EU_RNG)  {
++              printk(" rng");
++#ifdef CONFIG_OCF_RANDOMHARVEST
++              talitos_rng_init(sc);
++              crypto_rregister(sc->sc_cid, talitos_read_random, sc);
++#endif
++      }
++      if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) {
++              printk(" des/3des");
++              crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++              crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++      }
++      if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) {
++              printk(" aes");
++              crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++      }
++      if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) {
++              printk(" md5");
++              crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++              /* HMAC support only with IPsec for now */
++              crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++              printk(" sha1");
++              crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++              /* HMAC support only with IPsec for now */
++              crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++      }
++      printk("\n");
++      return 0;
++
++out:
++#ifndef CONFIG_PPC_MERGE
++      talitos_remove(pdev);
++#endif
++      return -ENOMEM;
++}
++
++#ifdef CONFIG_PPC_MERGE
++static int talitos_remove(struct of_device *ofdev)
++#else
++static int talitos_remove(struct platform_device *pdev)
++#endif
++{
++#ifdef CONFIG_PPC_MERGE
++      struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev);
++#else
++      struct talitos_softc *sc = platform_get_drvdata(pdev);
++#endif
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      if (sc->sc_cid >= 0)
++              crypto_unregister_all(sc->sc_cid);
++      if (sc->sc_chnfifo) {
++              for (i = 0; i < sc->sc_num_channels; i++)
++                      if (sc->sc_chnfifo[i])
++                              kfree(sc->sc_chnfifo[i]);
++              kfree(sc->sc_chnfifo);
++      }
++      if (sc->sc_chnlastalg)
++              kfree(sc->sc_chnlastalg);
++      if (sc->sc_chnfifolock)
++              kfree(sc->sc_chnfifolock);
++      if (sc->sc_irq != -1)
++              free_irq(sc->sc_irq, sc);
++      if (sc->sc_base_addr)
++              iounmap((void *) sc->sc_base_addr);
++      kfree(sc);
++      return 0;
++}
++
++#ifdef CONFIG_PPC_MERGE
++static struct of_device_id talitos_match[] = {
++      {
++              .type = "crypto",
++              .compatible = "talitos",
++      },
++      {},
++};
++
++MODULE_DEVICE_TABLE(of, talitos_match);
++
++static struct of_platform_driver talitos_driver = {
++      .name           = DRV_NAME,
++      .match_table    = talitos_match,
++      .probe          = talitos_probe,
++      .remove         = talitos_remove,
++};
++
++static int __init talitos_init(void)
++{
++      return of_register_platform_driver(&talitos_driver);
++}
++
++static void __exit talitos_exit(void)
++{
++      of_unregister_platform_driver(&talitos_driver);
++}
++#else
++/* Structure for a platform device driver */
++static struct platform_driver talitos_driver = {
++      .probe = talitos_probe,
++      .remove = talitos_remove,
++      .driver = {
++              .name = "fsl-sec2",
++      }
++};
++
++static int __init talitos_init(void)
++{
++      return platform_driver_register(&talitos_driver);
++}
++
++static void __exit talitos_exit(void)
++{
++      platform_driver_unregister(&talitos_driver);
++}
++#endif
++
++module_init(talitos_init);
++module_exit(talitos_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("kim.phillips@freescale.com");
++MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/talitos/talitos_soft.h    2007-07-20 11:47:16.000000000 +1000
+@@ -0,0 +1,77 @@
++/*
++ * Freescale SEC data structures for integration with ocf-linux
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * paired descriptor and associated crypto operation
++ */
++struct desc_cryptop_pair {
++      struct talitos_desc     cf_desc;        /* descriptor ptr */
++      struct cryptop          *cf_crp;        /* cryptop ptr */
++};
++
++/*
++ * Holds data specific to a single talitos device.
++ */
++struct talitos_softc {
++      softc_device_decl       sc_cdev;
++      struct platform_device  *sc_dev;        /* device backpointer */
++      ocf_iomem_t             sc_base_addr;
++      int                     sc_irq;
++      int                     sc_num;         /* if we have multiple chips */
++      int32_t                 sc_cid;         /* crypto tag */
++      u64                     sc_chiprev;     /* major/minor chip revision */
++      int                     sc_nsessions;
++      struct talitos_session  *sc_sessions;
++      int                     sc_num_channels;/* number of crypto channels */
++      int                     sc_chfifo_len;  /* channel fetch fifo len */
++      int                     sc_exec_units;  /* execution units mask */
++      int                     sc_desc_types;  /* descriptor types mask */
++      /*
++       * mutual exclusion for intra-channel resources, e.g. fetch fifos
++       * the last entry is a meta-channel lock used by the channel scheduler
++       */
++      spinlock_t              *sc_chnfifolock;
++      /* sc_chnlastalgo contains last algorithm for that channel */
++      int                     *sc_chnlastalg;
++      /* sc_chnfifo holds pending descriptor--crypto operation pairs */
++      struct desc_cryptop_pair        **sc_chnfifo;
++};
++
++struct talitos_session {
++      u_int32_t       ses_used;
++      u_int32_t       ses_klen;               /* key length in bits */
++      u_int32_t       ses_key[8];             /* DES/3DES/AES key */
++      u_int32_t       ses_hmac[5];            /* hmac inner state */
++      u_int32_t       ses_hmac_len;           /* hmac length */
++      u_int32_t       ses_iv[4];              /* DES/3DES/AES iv */
++      u_int32_t       ses_mlen;               /* desired hash result len (12=ipsec or 16) */
++};
++
++#define       TALITOS_SESSION(sid)    ((sid) & 0x0fffffff)
++#define       TALITOS_SID(crd, sesn)  (((crd) << 28) | ((sesn) & 0x0fffffff))
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/talitos/talitos_dev.h     2007-11-23 07:31:44.000000000 +1000
+@@ -0,0 +1,277 @@
++/*
++ * Freescale SEC (talitos) device dependent data structures
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ */
++
++/* device ID register values */
++#define TALITOS_ID_SEC_2_0    0x40
++#define TALITOS_ID_SEC_2_1    0x40 /* cross ref with IP block revision reg */
++
++/*
++ * following num_channels, channel-fifo-depth, exec-unit-mask, and 
++ * descriptor-types-mask are for forward-compatibility with openfirmware
++ * flat device trees
++ */
++
++/*
++ *  num_channels : the number of channels available in each SEC version.
++ */
++
++/* n.b. this driver requires these values be a power of 2 */
++#define TALITOS_NCHANNELS_SEC_1_0     4
++#define TALITOS_NCHANNELS_SEC_1_2     1
++#define TALITOS_NCHANNELS_SEC_2_0     4
++#define TALITOS_NCHANNELS_SEC_2_01    4
++#define TALITOS_NCHANNELS_SEC_2_1     4
++#define TALITOS_NCHANNELS_SEC_2_4     4
++
++/*
++ *  channel-fifo-depth : The number of descriptor
++ *  pointers a channel fetch fifo can hold.
++ */
++#define TALITOS_CHFIFOLEN_SEC_1_0     1
++#define TALITOS_CHFIFOLEN_SEC_1_2     1
++#define TALITOS_CHFIFOLEN_SEC_2_0     24
++#define TALITOS_CHFIFOLEN_SEC_2_01    24
++#define TALITOS_CHFIFOLEN_SEC_2_1     24
++#define TALITOS_CHFIFOLEN_SEC_2_4     24
++
++/* 
++ *  exec-unit-mask : The bitmask representing what Execution Units (EUs)
++ *  are available. EU information should be encoded following the SEC's 
++ *  EU_SEL0 bitfield documentation, i.e. as follows:
++ * 
++ *    bit 31 = set if SEC permits no-EU selection (should be always set)
++ *    bit 30 = set if SEC has the ARC4 EU (AFEU)
++ *    bit 29 = set if SEC has the des/3des EU (DEU)
++ *    bit 28 = set if SEC has the message digest EU (MDEU)
++ *    bit 27 = set if SEC has the random number generator EU (RNG)
++ *    bit 26 = set if SEC has the public key EU (PKEU)
++ *    bit 25 = set if SEC has the aes EU (AESU)
++ *    bit 24 = set if SEC has the Kasumi EU (KEU)
++ * 
++ */
++#define TALITOS_HAS_EU_NONE           (1<<0)
++#define TALITOS_HAS_EU_AFEU           (1<<1)
++#define TALITOS_HAS_EU_DEU            (1<<2)
++#define TALITOS_HAS_EU_MDEU           (1<<3)
++#define TALITOS_HAS_EU_RNG            (1<<4)
++#define TALITOS_HAS_EU_PKEU           (1<<5)
++#define TALITOS_HAS_EU_AESU           (1<<6)
++#define TALITOS_HAS_EU_KEU            (1<<7)
++
++/* the corresponding masks for each SEC version */
++#define TALITOS_HAS_EUS_SEC_1_0               0x7f
++#define TALITOS_HAS_EUS_SEC_1_2               0x4d
++#define TALITOS_HAS_EUS_SEC_2_0               0x7f
++#define TALITOS_HAS_EUS_SEC_2_01      0x7f
++#define TALITOS_HAS_EUS_SEC_2_1               0xff
++#define TALITOS_HAS_EUS_SEC_2_4               0x7f
++
++/*
++ *  descriptor-types-mask : The bitmask representing what descriptors
++ *  are available. Descriptor type information should be encoded 
++ *  following the SEC's Descriptor Header Dword DESC_TYPE field 
++ *  documentation, i.e. as follows:
++ *
++ *    bit 0  = set if SEC supports the aesu_ctr_nonsnoop desc. type
++ *    bit 1  = set if SEC supports the ipsec_esp descriptor type
++ *    bit 2  = set if SEC supports the common_nonsnoop desc. type
++ *    bit 3  = set if SEC supports the 802.11i AES ccmp desc. type
++ *    bit 4  = set if SEC supports the hmac_snoop_no_afeu desc. type
++ *    bit 5  = set if SEC supports the srtp descriptor type
++ *    bit 6  = set if SEC supports the non_hmac_snoop_no_afeu desc.type
++ *    bit 7  = set if SEC supports the pkeu_assemble descriptor type
++ *    bit 8  = set if SEC supports the aesu_key_expand_output desc.type
++ *    bit 9  = set if SEC supports the pkeu_ptmul descriptor type
++ *    bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
++ *    bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
++ *
++ *  ..and so on and so forth.
++ */
++#define TALITOS_HAS_DT_AESU_CTR_NONSNOOP      (1<<0)
++#define TALITOS_HAS_DT_IPSEC_ESP              (1<<1)
++#define TALITOS_HAS_DT_COMMON_NONSNOOP                (1<<2)
++
++/* the corresponding masks for each SEC version */
++#define TALITOS_HAS_DESCTYPES_SEC_2_0 0x01010ebf
++#define TALITOS_HAS_DESCTYPES_SEC_2_1 0x012b0ebf
++
++/* 
++ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register
++ */
++
++/* global register offset addresses */
++#define TALITOS_ID            0x1020
++#define TALITOS_ID_HI         0x1024
++#define TALITOS_MCR           0x1030          /* master control register */
++#define TALITOS_MCR_HI                0x1038          /* master control register */
++#define TALITOS_MCR_SWR               0x1
++#define TALITOS_IMR           0x1008          /* interrupt mask register */
++#define TALITOS_IMR_ALL               0x00010fff      /* enable all interrupts mask */
++#define TALITOS_IMR_ERRONLY   0x00010aaa      /* enable error interrupts */
++#define TALITOS_IMR_HI                0x100C          /* interrupt mask register */
++#define TALITOS_IMR_HI_ALL    0x00323333      /* enable all interrupts mask */
++#define TALITOS_IMR_HI_ERRONLY        0x00222222      /* enable error interrupts */
++#define TALITOS_ISR           0x1010          /* interrupt status register */
++#define TALITOS_ISR_ERROR     0x00010faa      /* errors mask */
++#define TALITOS_ISR_DONE      0x00000055      /* channel(s) done mask */
++#define TALITOS_ISR_HI                0x1014          /* interrupt status register */
++#define TALITOS_ICR           0x1018          /* interrupt clear register */
++#define TALITOS_ICR_HI                0x101C          /* interrupt clear register */
++
++/* channel register address stride */
++#define TALITOS_CH_OFFSET     0x100
++
++/* channel register offset addresses and bits */
++#define TALITOS_CH_CCCR               0x1108  /* Crypto-Channel Config Register */
++#define TALITOS_CH_CCCR_RESET 0x1     /* Channel Reset bit */
++#define TALITOS_CH_CCCR_HI    0x110c  /* Crypto-Channel Config Register */
++#define TALITOS_CH_CCCR_HI_CDWE       0x10    /* Channel done writeback enable bit */
++#define TALITOS_CH_CCCR_HI_NT 0x4     /* Notification type bit */
++#define TALITOS_CH_CCCR_HI_CDIE       0x2     /* Channel Done Interrupt Enable bit */
++#define TALITOS_CH_CCPSR      0x1110  /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_CCPSR_HI   0x1114  /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_FF         0x1148  /* Fetch FIFO */
++#define TALITOS_CH_FF_HI      0x114c  /* Fetch FIFO's FETCH_ADRS */
++#define TALITOS_CH_CDPR               0x1140  /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_CDPR_HI    0x1144  /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_DESCBUF    0x1180  /* (thru 11bf) Crypto-Channel 
++                                       * Descriptor Buffer (debug) */
++
++/* execution unit register offset addresses and bits */
++#define TALITOS_DEUSR         0x2028  /* DEU status register */
++#define TALITOS_DEUSR_HI      0x202c  /* DEU status register */
++#define TALITOS_DEUISR                0x2030  /* DEU interrupt status register */
++#define TALITOS_DEUISR_HI     0x2034  /* DEU interrupt status register */
++#define TALITOS_DEUICR                0x2038  /* DEU interrupt control register */
++#define TALITOS_DEUICR_HI     0x203c  /* DEU interrupt control register */
++#define TALITOS_AESUISR               0x4030  /* AESU interrupt status register */
++#define TALITOS_AESUISR_HI    0x4034  /* AESU interrupt status register */
++#define TALITOS_AESUICR               0x4038  /* AESU interrupt control register */
++#define TALITOS_AESUICR_HI    0x403c  /* AESU interrupt control register */
++#define TALITOS_MDEUISR               0x6030  /* MDEU interrupt status register */
++#define TALITOS_MDEUISR_HI    0x6034  /* MDEU interrupt status register */
++#define TALITOS_RNGSR         0xa028  /* RNG status register */
++#define TALITOS_RNGSR_HI      0xa02c  /* RNG status register */
++#define TALITOS_RNGSR_HI_RD   0x1     /* RNG Reset done */
++#define TALITOS_RNGSR_HI_OFL  0xff0000/* number of dwords in RNG output FIFO*/
++#define TALITOS_RNGDSR                0xa010  /* RNG data size register */
++#define TALITOS_RNGDSR_HI     0xa014  /* RNG data size register */
++#define TALITOS_RNG_FIFO      0xa800  /* RNG FIFO - pool of random numbers */
++#define TALITOS_RNGISR                0xa030  /* RNG Interrupt status register */
++#define TALITOS_RNGISR_HI     0xa034  /* RNG Interrupt status register */
++#define TALITOS_RNGRCR                0xa018  /* RNG Reset control register */
++#define TALITOS_RNGRCR_HI     0xa01c  /* RNG Reset control register */
++#define TALITOS_RNGRCR_HI_SR  0x1     /* RNG RNGRCR:Software Reset */
++
++/* descriptor pointer entry */
++struct talitos_desc_ptr {
++      u16     len;            /* length */
++      u8      extent;         /* jump (to s/g link table) and extent */
++      u8      res;            /* reserved */
++      u32     ptr;            /* pointer */
++};
++
++/* descriptor */
++struct talitos_desc {
++      u32     hdr;                            /* header */
++      u32     res;                            /* reserved */
++      struct talitos_desc_ptr         ptr[7]; /* ptr/len pair array */
++};
++
++/* talitos descriptor header (hdr) bits */
++
++/* primary execution unit select */
++#define       TALITOS_SEL0_AFEU       0x10000000
++#define       TALITOS_SEL0_DEU        0x20000000
++#define       TALITOS_SEL0_MDEU       0x30000000
++#define       TALITOS_SEL0_RNG        0x40000000
++#define       TALITOS_SEL0_PKEU       0x50000000
++#define       TALITOS_SEL0_AESU       0x60000000
++
++/* primary execution unit mode (MODE0) and derivatives */
++#define       TALITOS_MODE0_AESU_CBC          0x00200000
++#define       TALITOS_MODE0_AESU_ENC          0x00100000
++#define       TALITOS_MODE0_DEU_CBC           0x00400000
++#define       TALITOS_MODE0_DEU_3DES          0x00200000
++#define       TALITOS_MODE0_DEU_ENC           0x00100000
++#define       TALITOS_MODE0_MDEU_INIT         0x01000000      /* init starting regs */
++#define       TALITOS_MODE0_MDEU_HMAC         0x00800000
++#define       TALITOS_MODE0_MDEU_PAD          0x00400000      /* PD */
++#define       TALITOS_MODE0_MDEU_MD5          0x00200000
++#define       TALITOS_MODE0_MDEU_SHA256       0x00100000
++#define       TALITOS_MODE0_MDEU_SHA1         0x00000000      /* SHA-160 */
++#define       TALITOS_MODE0_MDEU_MD5_HMAC     \
++              (TALITOS_MODE0_MDEU_MD5 | TALITOS_MODE0_MDEU_HMAC)
++#define       TALITOS_MODE0_MDEU_SHA256_HMAC  \
++              (TALITOS_MODE0_MDEU_SHA256 | TALITOS_MODE0_MDEU_HMAC)
++#define       TALITOS_MODE0_MDEU_SHA1_HMAC    \
++              (TALITOS_MODE0_MDEU_SHA1 | TALITOS_MODE0_MDEU_HMAC)
++
++/* secondary execution unit select (SEL1) */
++/* it's MDEU or nothing */
++#define       TALITOS_SEL1_MDEU       0x00030000
++
++/* secondary execution unit mode (MODE1) and derivatives */
++#define       TALITOS_MODE1_MDEU_INIT         0x00001000      /* init starting regs */
++#define       TALITOS_MODE1_MDEU_HMAC         0x00000800
++#define       TALITOS_MODE1_MDEU_PAD          0x00000400      /* PD */
++#define       TALITOS_MODE1_MDEU_MD5          0x00000200
++#define       TALITOS_MODE1_MDEU_SHA256       0x00000100
++#define       TALITOS_MODE1_MDEU_SHA1         0x00000000      /* SHA-160 */
++#define       TALITOS_MODE1_MDEU_MD5_HMAC     \
++      (TALITOS_MODE1_MDEU_MD5 | TALITOS_MODE1_MDEU_HMAC)
++#define       TALITOS_MODE1_MDEU_SHA256_HMAC  \
++      (TALITOS_MODE1_MDEU_SHA256 | TALITOS_MODE1_MDEU_HMAC)
++#define       TALITOS_MODE1_MDEU_SHA1_HMAC    \
++      (TALITOS_MODE1_MDEU_SHA1 | TALITOS_MODE1_MDEU_HMAC)
++
++/* direction of overall data flow (DIR) */
++#define       TALITOS_DIR_OUTBOUND    0x00000000
++#define       TALITOS_DIR_INBOUND     0x00000002
++
++/* done notification (DN) */
++#define       TALITOS_DONE_NOTIFY     0x00000001
++
++/* descriptor types */
++/* odd numbers here are valid on SEC2 and greater only (e.g. ipsec_esp) */
++#define TD_TYPE_AESU_CTR_NONSNOOP     (0 << 3)
++#define TD_TYPE_IPSEC_ESP             (1 << 3)
++#define TD_TYPE_COMMON_NONSNOOP_NO_AFEU       (2 << 3)
++#define TD_TYPE_HMAC_SNOOP_NO_AFEU    (4 << 3)
++
++#define TALITOS_HDR_DONE_BITS 0xff000000
++
++#define       DPRINTF(a...)   do { \
++                                              if (debug) { \
++                                                      printk("%s: ", sc ? \
++                                                              device_get_nameunit(sc->sc_cdev) : "talitos"); \
++                                                      printk(a); \
++                                              } \
++                                      } while (0)
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/random.c  2007-12-04 13:56:03.000000000 +1000
+@@ -0,0 +1,317 @@
++/*
++ * A system independant way of adding entropy to the kernels pool
++ * this way the drivers can focus on the real work and we can take
++ * care of pushing it to the appropriate place in the kernel.
++ *
++ * This should be fast and callable from timers/interrupts
++ *
++ * Written by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <linux/unistd.h>
++#include <linux/poll.h>
++#include <linux/random.h>
++#include <cryptodev.h>
++
++#ifdef CONFIG_OCF_FIPS
++#include "rndtest.h"
++#endif
++
++#ifndef HAS_RANDOM_INPUT_WAIT
++#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches"
++#endif
++
++/*
++ * a hack to access the debug levels from the crypto driver
++ */
++extern int crypto_debug;
++#define debug crypto_debug
++
++/*
++ * a list of all registered random providers
++ */
++static LIST_HEAD(random_ops);
++static int started = 0;
++static int initted = 0;
++
++struct random_op {
++      struct list_head random_list;
++      u_int32_t driverid;
++      int (*read_random)(void *arg, u_int32_t *buf, int len);
++      void *arg;
++};
++
++static int random_proc(void *arg);
++
++static pid_t          randomproc = (pid_t) -1;
++static spinlock_t     random_lock;
++
++/*
++ * just init the spin locks
++ */
++static int
++crypto_random_init(void)
++{
++      spin_lock_init(&random_lock);
++      initted = 1;
++      return(0);
++}
++
++/*
++ * Add the given random reader to our list (if not present)
++ * and start the thread (if not already started)
++ *
++ * we have to assume that driver id is ok for now
++ */
++int
++crypto_rregister(
++      u_int32_t driverid,
++      int (*read_random)(void *arg, u_int32_t *buf, int len),
++      void *arg)
++{
++      unsigned long flags;
++      int ret = 0;
++      struct random_op        *rops, *tmp;
++
++      dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__,
++                      __FUNCTION__, driverid, read_random, arg);
++
++      if (!initted)
++              crypto_random_init();
++
++#if 0
++      struct cryptocap        *cap;
++
++      cap = crypto_checkdriver(driverid);
++      if (!cap)
++              return EINVAL;
++#endif
++
++      list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++              if (rops->driverid == driverid && rops->read_random == read_random)
++                      return EEXIST;
++      }
++
++      rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL);
++      if (!rops)
++              return ENOMEM;
++
++      rops->driverid    = driverid;
++      rops->read_random = read_random;
++      rops->arg = arg;
++
++      spin_lock_irqsave(&random_lock, flags);
++      list_add_tail(&rops->random_list, &random_ops);
++      if (!started) {
++              randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES);
++              if (randomproc < 0) {
++                      ret = randomproc;
++                      printk("crypto: crypto_rregister cannot start random thread; "
++                                      "error %d", ret);
++              } else
++                      started = 1;
++      }
++      spin_unlock_irqrestore(&random_lock, flags);
++
++      return ret;
++}
++EXPORT_SYMBOL(crypto_rregister);
++
++int
++crypto_runregister_all(u_int32_t driverid)
++{
++      struct random_op *rops, *tmp;
++      unsigned long flags;
++
++      dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid);
++
++      list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++              if (rops->driverid == driverid) {
++                      list_del(&rops->random_list);
++                      kfree(rops);
++              }
++      }
++
++      spin_lock_irqsave(&random_lock, flags);
++      if (list_empty(&random_ops) && started)
++              kill_proc(randomproc, SIGKILL, 1);
++      spin_unlock_irqrestore(&random_lock, flags);
++      return(0);
++}
++EXPORT_SYMBOL(crypto_runregister_all);
++
++/*
++ * while we can add entropy to random.c continue to read random data from
++ * the drivers and push it to random.
++ */
++static int
++random_proc(void *arg)
++{
++      int n;
++      int wantcnt;
++      int bufcnt = 0;
++      int retval = 0;
++      int *buf = NULL;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++      daemonize();
++      spin_lock_irq(&current->sigmask_lock);
++      sigemptyset(&current->blocked);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++      sprintf(current->comm, "ocf-random");
++#else
++      daemonize("ocf-random");
++      allow_signal(SIGKILL);
++#endif
++
++      (void) get_fs();
++      set_fs(get_ds());
++
++#ifdef CONFIG_OCF_FIPS
++#define NUM_INT (RNDTEST_NBYTES/sizeof(int))
++#else
++#define NUM_INT 32
++#endif
++
++      /*
++       * some devices can transferr their RNG data direct into memory,
++       * so make sure it is device friendly
++       */
++      buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA);
++      if (NULL == buf) {
++              printk("crypto: RNG could not allocate memory\n");
++              retval = -ENOMEM;
++              goto bad_alloc;
++      }
++
++      wantcnt = NUM_INT;   /* start by adding some entropy */
++
++      /*
++       * its possible due to errors or driver removal that we no longer
++       * have anything to do,  if so exit or we will consume all the CPU
++       * doing nothing
++       */
++      while (!list_empty(&random_ops)) {
++              struct random_op        *rops, *tmp;
++
++#ifdef CONFIG_OCF_FIPS
++              if (wantcnt)
++                      wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */
++#endif
++
++              /* see if we can get enough entropy to make the world
++               * a better place.
++               */
++              while (bufcnt < wantcnt && bufcnt < NUM_INT) {
++                      list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++
++                              n = (*rops->read_random)(rops->arg, &buf[bufcnt],
++                                                       NUM_INT - bufcnt);
++
++                              /* on failure remove the random number generator */
++                              if (n == -1) {
++                                      list_del(&rops->random_list);
++                                      printk("crypto: RNG (driverid=0x%x) failed, disabling\n",
++                                                      rops->driverid);
++                                      kfree(rops);
++                              } else if (n > 0)
++                                      bufcnt += n;
++                      }
++                      /* give up CPU for a bit, just in case as this is a loop */
++                      schedule();
++              }
++
++
++#ifdef CONFIG_OCF_FIPS
++              if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) {
++                      dprintk("crypto: buffer had fips errors, discarding\n");
++                      bufcnt = 0;
++              }
++#endif
++
++              /*
++               * if we have a certified buffer,  we can send some data
++               * to /dev/random and move along
++               */
++              if (bufcnt > 0) {
++                      /* add what we have */
++                      random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8);
++                      bufcnt = 0;
++              }
++
++              /* give up CPU for a bit so we don't hog while filling */
++              schedule();
++
++              /* wait for needing more */
++              wantcnt = random_input_wait();
++
++              if (wantcnt <= 0)
++                      wantcnt = 0; /* try to get some info again */
++              else
++                      /* round up to one word or we can loop forever */
++                      wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8);
++              if (wantcnt > NUM_INT) {
++                      wantcnt = NUM_INT;
++              }
++
++              if (signal_pending(current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                      spin_lock_irq(&current->sigmask_lock);
++#endif
++                      flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                      spin_unlock_irq(&current->sigmask_lock);
++#endif
++              }
++      }
++      
++      kfree(buf);
++
++bad_alloc:
++      spin_lock_irq(&random_lock);
++      randomproc = (pid_t) -1;
++      started = 0;
++      spin_unlock_irq(&random_lock);
++
++      return retval;
++}
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ocf-bench.c       2007-07-23 22:26:12.000000000 +1000
+@@ -0,0 +1,436 @@
++/*
++ * A loadable module that benchmarks the OCF crypto speed from kernel space.
++ *
++ * Copyright (C) 2004-2007 David McCullough <david_mccullough@securecomputing.com>
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <linux/interrupt.h>
++#include <cryptodev.h>
++
++#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK
++#define BENCH_IXP_ACCESS_LIB 1
++#endif
++#ifdef BENCH_IXP_ACCESS_LIB
++#include <IxTypes.h>
++#include <IxOsBuffMgt.h>
++#include <IxNpeDl.h>
++#include <IxCryptoAcc.h>
++#include <IxQMgr.h>
++#include <IxOsServices.h>
++#include <IxOsCacheMMU.h>
++#endif
++
++/*
++ * support for access lib version 1.4
++ */
++#ifndef IX_MBUF_PRIV
++#define IX_MBUF_PRIV(x) ((x)->priv)
++#endif
++
++/*
++ * the number of simultaneously active requests
++ */
++static int request_q_len = 20;
++module_param(request_q_len, int, 0);
++MODULE_PARM_DESC(request_q_len, "Number of outstanding requests");
++/*
++ * how many requests we want to have processed
++ */
++static int request_num = 1024;
++module_param(request_num, int, 0);
++MODULE_PARM_DESC(request_num, "run for at least this many requests");
++/*
++ * the size of each request
++ */
++static int request_size = 1500;
++module_param(request_size, int, 0);
++MODULE_PARM_DESC(request_size, "size of each request");
++
++/*
++ * a structure for each request
++ */
++typedef struct  {
++      struct work_struct work;
++#ifdef BENCH_IXP_ACCESS_LIB
++      IX_MBUF mbuf;
++#endif
++      unsigned char *buffer;
++} request_t;
++
++static request_t *requests;
++
++static int outstanding;
++static int total;
++
++/*************************************************************************/
++/*
++ * OCF benchmark routines
++ */
++
++static uint64_t ocf_cryptoid;
++static int ocf_init(void);
++static int ocf_cb(struct cryptop *crp);
++static void ocf_request(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ocf_request_wq(struct work_struct *work);
++#endif
++
++static int
++ocf_init(void)
++{
++      int error;
++      struct cryptoini crie, cria;
++      struct cryptodesc crda, crde;
++
++      memset(&crie, 0, sizeof(crie));
++      memset(&cria, 0, sizeof(cria));
++      memset(&crde, 0, sizeof(crde));
++      memset(&crda, 0, sizeof(crda));
++
++      cria.cri_alg  = CRYPTO_SHA1_HMAC;
++      cria.cri_klen = 20 * 8;
++      cria.cri_key  = "0123456789abcdefghij";
++
++      crie.cri_alg  = CRYPTO_3DES_CBC;
++      crie.cri_klen = 24 * 8;
++      crie.cri_key  = "0123456789abcdefghijklmn";
++
++      crie.cri_next = &cria;
++
++      error = crypto_newsession(&ocf_cryptoid, &crie, 0);
++      if (error) {
++              printk("crypto_newsession failed %d\n", error);
++              return -1;
++      }
++      return 0;
++}
++
++static int
++ocf_cb(struct cryptop *crp)
++{
++      request_t *r = (request_t *) crp->crp_opaque;
++
++      if (crp->crp_etype)
++              printk("Error in OCF processing: %d\n", crp->crp_etype);
++      total++;
++      crypto_freereq(crp);
++      crp = NULL;
++
++      if (total > request_num) {
++              outstanding--;
++              return 0;
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&r->work, ocf_request_wq);
++#else
++      INIT_WORK(&r->work, ocf_request, r);
++#endif
++      schedule_work(&r->work);
++      return 0;
++}
++
++
++static void
++ocf_request(void *arg)
++{
++      request_t *r = arg;
++      struct cryptop *crp = crypto_getreq(2);
++      struct cryptodesc *crde, *crda;
++
++      if (!crp) {
++              outstanding--;
++              return;
++      }
++
++      crde = crp->crp_desc;
++      crda = crde->crd_next;
++
++      crda->crd_skip = 0;
++      crda->crd_flags = 0;
++      crda->crd_len = request_size;
++      crda->crd_inject = request_size;
++      crda->crd_alg = CRYPTO_SHA1_HMAC;
++      crda->crd_key = "0123456789abcdefghij";
++      crda->crd_klen = 20 * 8;
++
++      crde->crd_skip = 0;
++      crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT;
++      crde->crd_len = request_size;
++      crde->crd_inject = request_size;
++      crde->crd_alg = CRYPTO_3DES_CBC;
++      crde->crd_key = "0123456789abcdefghijklmn";
++      crde->crd_klen = 24 * 8;
++
++      crp->crp_ilen = request_size + 64;
++      crp->crp_flags = CRYPTO_F_CBIMM;
++      crp->crp_buf = (caddr_t) r->buffer;
++      crp->crp_callback = ocf_cb;
++      crp->crp_sid = ocf_cryptoid;
++      crp->crp_opaque = (caddr_t) r;
++      crypto_dispatch(crp);
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ocf_request_wq(struct work_struct *work)
++{
++      request_t *r = container_of(work, request_t, work);
++      ocf_request(r);
++}
++#endif
++
++/*************************************************************************/
++#ifdef BENCH_IXP_ACCESS_LIB
++/*************************************************************************/
++/*
++ * CryptoAcc benchmark routines
++ */
++
++static IxCryptoAccCtx ixp_ctx;
++static UINT32 ixp_ctx_id;
++static IX_MBUF ixp_pri;
++static IX_MBUF ixp_sec;
++static int ixp_registered = 0;
++
++static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp,
++                                      IxCryptoAccStatus status);
++static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp,
++                                      IxCryptoAccStatus status);
++static void ixp_request(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ixp_request_wq(struct work_struct *work);
++#endif
++
++static int
++ixp_init(void)
++{
++      IxCryptoAccStatus status;
++
++      ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES;
++      ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++      ixp_ctx.cipherCtx.cipherKeyLen = 24;
++      ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++      ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64;
++      memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24);
++
++      ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1;
++      ixp_ctx.authCtx.authDigestLen = 12;
++      ixp_ctx.authCtx.aadLen = 0;
++      ixp_ctx.authCtx.authKeyLen = 20;
++      memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20);
++
++      ixp_ctx.useDifferentSrcAndDestMbufs = 0;
++      ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ;
++
++      IX_MBUF_MLEN(&ixp_pri)  = IX_MBUF_PKT_LEN(&ixp_pri) = 128;
++      IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++      IX_MBUF_MLEN(&ixp_sec)  = IX_MBUF_PKT_LEN(&ixp_sec) = 128;
++      IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++
++      status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec,
++                      ixp_register_cb, ixp_perform_cb, &ixp_ctx_id);
++
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) {
++              while (!ixp_registered)
++                      schedule();
++              return ixp_registered < 0 ? -1 : 0;
++      }
++
++      printk("ixp: ixCryptoAccCtxRegister failed %d\n", status);
++      return -1;
++}
++
++static void
++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status)
++{
++      if (bufp) {
++              IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0;
++              kfree(IX_MBUF_MDATA(bufp));
++              IX_MBUF_MDATA(bufp) = NULL;
++      }
++
++      if (IX_CRYPTO_ACC_STATUS_WAIT == status)
++              return;
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++              ixp_registered = 1;
++      else
++              ixp_registered = -1;
++}
++
++static void
++ixp_perform_cb(
++      UINT32 ctx_id,
++      IX_MBUF *sbufp,
++      IX_MBUF *dbufp,
++      IxCryptoAccStatus status)
++{
++      request_t *r = NULL;
++
++      total++;
++      if (total > request_num) {
++              outstanding--;
++              return;
++      }
++
++      if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) {
++              printk("crappo %p %p\n", sbufp, r);
++              outstanding--;
++              return;
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&r->work, ixp_request_wq);
++#else
++      INIT_WORK(&r->work, ixp_request, r);
++#endif
++      schedule_work(&r->work);
++}
++
++static void
++ixp_request(void *arg)
++{
++      request_t *r = arg;
++      IxCryptoAccStatus status;
++
++      memset(&r->mbuf, 0, sizeof(r->mbuf));
++      IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64;
++      IX_MBUF_MDATA(&r->mbuf) = r->buffer;
++      IX_MBUF_PRIV(&r->mbuf) = r;
++      status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL,
++                      0, request_size, 0, request_size, request_size, r->buffer);
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) {
++              printk("status1 = %d\n", status);
++              outstanding--;
++              return;
++      }
++      return;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_request_wq(struct work_struct *work)
++{
++      request_t *r = container_of(work, request_t, work);
++      ixp_request(r);
++}
++#endif
++
++/*************************************************************************/
++#endif /* BENCH_IXP_ACCESS_LIB */
++/*************************************************************************/
++
++int
++ocfbench_init(void)
++{
++      int i, jstart, jstop;
++
++      printk("Crypto Speed tests\n");
++
++      requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL);
++      if (!requests) {
++              printk("malloc failed\n");
++              return -EINVAL;
++      }
++
++      for (i = 0; i < request_q_len; i++) {
++              /* +64 for return data */
++              requests[i].buffer = kmalloc(request_size + 128, GFP_DMA);
++              if (!requests[i].buffer) {
++                      printk("malloc failed\n");
++                      return -EINVAL;
++              }
++              memset(requests[i].buffer, '0' + i, request_size + 128);
++      }
++
++      /*
++       * OCF benchmark
++       */
++      printk("OCF: testing ...\n");
++      ocf_init();
++      total = outstanding = 0;
++      jstart = jiffies;
++      for (i = 0; i < request_q_len; i++) {
++              outstanding++;
++              ocf_request(&requests[i]);
++      }
++      while (outstanding > 0)
++              schedule();
++      jstop = jiffies;
++
++      printk("OCF: %d requests of %d bytes in %d jiffies\n", total, request_size,
++                      jstop - jstart);
++
++#ifdef BENCH_IXP_ACCESS_LIB
++      /*
++       * IXP benchmark
++       */
++      printk("IXP: testing ...\n");
++      ixp_init();
++      total = outstanding = 0;
++      jstart = jiffies;
++      for (i = 0; i < request_q_len; i++) {
++              outstanding++;
++              ixp_request(&requests[i]);
++      }
++      while (outstanding > 0)
++              schedule();
++      jstop = jiffies;
++
++      printk("IXP: %d requests of %d bytes in %d jiffies\n", total, request_size,
++                      jstop - jstart);
++#endif /* BENCH_IXP_ACCESS_LIB */
++
++      for (i = 0; i < request_q_len; i++)
++              kfree(requests[i].buffer);
++      kfree(requests);
++      return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */
++}
++
++static void __exit ocfbench_exit(void)
++{
++}
++
++module_init(ocfbench_init);
++module_exit(ocfbench_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ixp4xx/ixp4xx.c   2008-07-03 10:28:05.000000000 +1000
+@@ -0,0 +1,1328 @@
++/*
++ * An OCF module that uses Intels IXP CryptACC API to do the crypto.
++ * This driver requires the IXP400 Access Library that is available
++ * from Intel in order to operate (or compile).
++ *
++ * Written by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++#include <asm/scatterlist.h>
++
++#include <IxTypes.h>
++#include <IxOsBuffMgt.h>
++#include <IxNpeDl.h>
++#include <IxCryptoAcc.h>
++#include <IxQMgr.h>
++#include <IxOsServices.h>
++#include <IxOsCacheMMU.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++#ifndef IX_MBUF_PRIV
++#define IX_MBUF_PRIV(x) ((x)->priv)
++#endif
++
++struct ixp_data;
++
++struct ixp_q {
++      struct list_head         ixp_q_list;
++      struct ixp_data         *ixp_q_data;
++      struct cryptop          *ixp_q_crp;
++      struct cryptodesc       *ixp_q_ccrd;
++      struct cryptodesc       *ixp_q_acrd;
++      IX_MBUF                          ixp_q_mbuf;
++      UINT8                           *ixp_hash_dest; /* Location for hash in client buffer */
++      UINT8                           *ixp_hash_src; /* Location of hash in internal buffer */
++      unsigned char            ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH];
++      unsigned char           *ixp_q_iv;
++};
++
++struct ixp_data {
++      int                                      ixp_registered;        /* is the context registered */
++      int                                      ixp_crd_flags;         /* detect direction changes */
++
++      int                                      ixp_cipher_alg;
++      int                                      ixp_auth_alg;
++
++      UINT32                           ixp_ctx_id;
++      UINT32                           ixp_hash_key_id;       /* used when hashing */
++      IxCryptoAccCtx           ixp_ctx;
++      IX_MBUF                          ixp_pri_mbuf;
++      IX_MBUF                          ixp_sec_mbuf;
++
++      struct work_struct   ixp_pending_work;
++      struct work_struct   ixp_registration_work;
++      struct list_head         ixp_q;                         /* unprocessed requests */
++};
++
++#ifdef __ixp46X
++
++#define       MAX_IOP_SIZE    64      /* words */
++#define       MAX_OOP_SIZE    128
++
++#define       MAX_PARAMS              3
++
++struct ixp_pkq {
++      struct list_head                         pkq_list;
++      struct cryptkop                         *pkq_krp;
++
++      IxCryptoAccPkeEauInOperands      pkq_op;
++      IxCryptoAccPkeEauOpResult        pkq_result;
++
++      UINT32                                           pkq_ibuf0[MAX_IOP_SIZE];
++      UINT32                                           pkq_ibuf1[MAX_IOP_SIZE];
++      UINT32                                           pkq_ibuf2[MAX_IOP_SIZE];
++      UINT32                                           pkq_obuf[MAX_OOP_SIZE];
++};
++
++static LIST_HEAD(ixp_pkq); /* current PK wait list */
++static struct ixp_pkq *ixp_pk_cur;
++static spinlock_t ixp_pkq_lock;
++
++#endif /* __ixp46X */
++
++static int ixp_blocked = 0;
++
++static int32_t                         ixp_id = -1;
++static struct ixp_data **ixp_sessions = NULL;
++static u_int32_t               ixp_sesnum = 0;
++
++static int ixp_process(device_t, struct cryptop *, int);
++static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int ixp_freesession(device_t, u_int64_t);
++#ifdef __ixp46X
++static int ixp_kprocess(device_t, struct cryptkop *krp, int hint);
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *qcache;
++#else
++static struct kmem_cache *qcache;
++#endif
++
++#define debug ixp_debug
++static int ixp_debug = 0;
++module_param(ixp_debug, int, 0644);
++MODULE_PARM_DESC(ixp_debug, "Enable debug");
++
++static int ixp_init_crypto = 1;
++module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */
++MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)");
++
++static void ixp_process_pending(void *arg);
++static void ixp_registration(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ixp_process_pending_wq(struct work_struct *work);
++static void ixp_registration_wq(struct work_struct *work);
++#endif
++
++/*
++ * dummy device structure
++ */
++
++static struct {
++      softc_device_decl       sc_dev;
++} ixpdev;
++
++static device_method_t ixp_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, ixp_newsession),
++      DEVMETHOD(cryptodev_freesession,ixp_freesession),
++      DEVMETHOD(cryptodev_process,    ixp_process),
++#ifdef __ixp46X
++      DEVMETHOD(cryptodev_kprocess,   ixp_kprocess),
++#endif
++};
++
++/*
++ * Generate a new software session.
++ */
++static int
++ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++      struct ixp_data *ixp;
++      u_int32_t i;
++#define AUTH_LEN(cri, def) \
++      (cri->cri_mlen ? cri->cri_mlen : (def))
++
++      dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg);
++      if (sid == NULL || cri == NULL) {
++              dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      if (ixp_sessions) {
++              for (i = 1; i < ixp_sesnum; i++)
++                      if (ixp_sessions[i] == NULL)
++                              break;
++      } else
++              i = 1;          /* NB: to silence compiler warning */
++
++      if (ixp_sessions == NULL || i == ixp_sesnum) {
++              struct ixp_data **ixpd;
++
++              if (ixp_sessions == NULL) {
++                      i = 1; /* We leave ixp_sessions[0] empty */
++                      ixp_sesnum = CRYPTO_SW_SESSIONS;
++              } else
++                      ixp_sesnum *= 2;
++
++              ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC);
++              if (ixpd == NULL) {
++                      /* Reset session number */
++                      if (ixp_sesnum == CRYPTO_SW_SESSIONS)
++                              ixp_sesnum = 0;
++                      else
++                              ixp_sesnum /= 2;
++                      dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                      return ENOBUFS;
++              }
++              memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *));
++
++              /* Copy existing sessions */
++              if (ixp_sessions) {
++                      memcpy(ixpd, ixp_sessions,
++                          (ixp_sesnum / 2) * sizeof(struct ixp_data *));
++                      kfree(ixp_sessions);
++              }
++
++              ixp_sessions = ixpd;
++      }
++
++      ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data),
++                      SLAB_ATOMIC);
++      if (ixp_sessions[i] == NULL) {
++              ixp_freesession(NULL, i);
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return ENOBUFS;
++      }
++
++      *sid = i;
++
++      ixp = ixp_sessions[i];
++      memset(ixp, 0, sizeof(*ixp));
++
++      ixp->ixp_cipher_alg = -1;
++      ixp->ixp_auth_alg = -1;
++      ixp->ixp_ctx_id = -1;
++      INIT_LIST_HEAD(&ixp->ixp_q);
++
++      ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0;
++
++      while (cri) {
++              switch (cri->cri_alg) {
++              case CRYPTO_DES_CBC:
++                      ixp->ixp_cipher_alg = cri->cri_alg;
++                      ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES;
++                      ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++                      ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++                      ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++                      ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen =
++                                              IX_CRYPTO_ACC_DES_IV_64;
++                      memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++                                      cri->cri_key, (cri->cri_klen + 7) / 8);
++                      break;
++
++              case CRYPTO_3DES_CBC:
++                      ixp->ixp_cipher_alg = cri->cri_alg;
++                      ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES;
++                      ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++                      ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++                      ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++                      ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen =
++                                              IX_CRYPTO_ACC_DES_IV_64;
++                      memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++                                      cri->cri_key, (cri->cri_klen + 7) / 8);
++                      break;
++
++              case CRYPTO_RIJNDAEL128_CBC:
++                      ixp->ixp_cipher_alg = cri->cri_alg;
++                      ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES;
++                      ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++                      ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++                      ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16;
++                      ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16;
++                      memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++                                      cri->cri_key, (cri->cri_klen + 7) / 8);
++                      break;
++
++              case CRYPTO_MD5:
++              case CRYPTO_MD5_HMAC:
++                      ixp->ixp_auth_alg = cri->cri_alg;
++                      ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5;
++                      ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN);
++                      ixp->ixp_ctx.authCtx.aadLen = 0;
++                      /* Only MD5_HMAC needs a key */
++                      if (cri->cri_alg == CRYPTO_MD5_HMAC) {
++                              ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8;
++                              if (ixp->ixp_ctx.authCtx.authKeyLen >
++                                              sizeof(ixp->ixp_ctx.authCtx.key.authKey)) {
++                                      printk(
++                                              "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n",
++                                                      cri->cri_klen);
++                                      ixp_freesession(NULL, i);
++                                      return EINVAL;
++                              }
++                              memcpy(ixp->ixp_ctx.authCtx.key.authKey,
++                                              cri->cri_key, (cri->cri_klen + 7) / 8);
++                      }
++                      break;
++
++              case CRYPTO_SHA1:
++              case CRYPTO_SHA1_HMAC:
++                      ixp->ixp_auth_alg = cri->cri_alg;
++                      ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1;
++                      ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN);
++                      ixp->ixp_ctx.authCtx.aadLen = 0;
++                      /* Only SHA1_HMAC needs a key */
++                      if (cri->cri_alg == CRYPTO_SHA1_HMAC) {
++                              ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8;
++                              if (ixp->ixp_ctx.authCtx.authKeyLen >
++                                              sizeof(ixp->ixp_ctx.authCtx.key.authKey)) {
++                                      printk(
++                                              "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n",
++                                                      cri->cri_klen);
++                                      ixp_freesession(NULL, i);
++                                      return EINVAL;
++                              }
++                              memcpy(ixp->ixp_ctx.authCtx.key.authKey,
++                                              cri->cri_key, (cri->cri_klen + 7) / 8);
++                      }
++                      break;
++
++              default:
++                      printk("ixp: unknown algo 0x%x\n", cri->cri_alg);
++                      ixp_freesession(NULL, i);
++                      return EINVAL;
++              }
++              cri = cri->cri_next;
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq);
++      INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq);
++#else
++      INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp);
++      INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp);
++#endif
++
++      return 0;
++}
++
++
++/*
++ * Free a session.
++ */
++static int
++ixp_freesession(device_t dev, u_int64_t tid)
++{
++      u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid > ixp_sesnum || ixp_sessions == NULL ||
++                      ixp_sessions[sid] == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      /* Silently accept and return */
++      if (sid == 0)
++              return 0;
++
++      if (ixp_sessions[sid]) {
++              if (ixp_sessions[sid]->ixp_ctx_id != -1) {
++                      ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id);
++                      ixp_sessions[sid]->ixp_ctx_id = -1;
++              }
++
++              flush_scheduled_work();
++
++              kfree(ixp_sessions[sid]);
++      }
++      ixp_sessions[sid] = NULL;
++      if (ixp_blocked) {
++              ixp_blocked = 0;
++              crypto_unblock(ixp_id, CRYPTO_SYMQ);
++      }
++      return 0;
++}
++
++
++/*
++ * callback for when hash processing is complete
++ */
++
++static void
++ixp_hash_perform_cb(
++      UINT32 hash_key_id,
++      IX_MBUF *bufp,
++      IxCryptoAccStatus status)
++{
++      struct ixp_q *q;
++
++      dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status);
++
++      if (bufp == NULL) {
++              printk("ixp: NULL buf in %s\n", __FUNCTION__);
++              return;
++      }
++
++      q = IX_MBUF_PRIV(bufp);
++      if (q == NULL) {
++              printk("ixp: NULL priv in %s\n", __FUNCTION__);
++              return;
++      }
++
++      if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) {
++              /* On success, need to copy hash back into original client buffer */
++              memcpy(q->ixp_hash_dest, q->ixp_hash_src,
++                              (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ?
++                                      SHA1_HASH_LEN : MD5_HASH_LEN);
++      }
++      else {
++              printk("ixp: hash perform failed status=%d\n", status);
++              q->ixp_q_crp->crp_etype = EINVAL;
++      }
++
++      /* Free internal buffer used for hashing */
++      kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf));
++
++      crypto_done(q->ixp_q_crp);
++      kmem_cache_free(qcache, q);
++}
++
++/*
++ * setup a request and perform it
++ */
++static void
++ixp_q_process(struct ixp_q *q)
++{
++      IxCryptoAccStatus status;
++      struct ixp_data *ixp = q->ixp_q_data;
++      int auth_off = 0;
++      int auth_len = 0;
++      int crypt_off = 0;
++      int crypt_len = 0;
++      int icv_off = 0;
++      char *crypt_func;
++
++      dprintk("%s(%p)\n", __FUNCTION__, q);
++
++      if (q->ixp_q_ccrd) {
++              if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++                      q->ixp_q_iv = q->ixp_q_ccrd->crd_iv;
++              } else {
++                      q->ixp_q_iv = q->ixp_q_iv_data;
++                      crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf,
++                                      q->ixp_q_ccrd->crd_inject,
++                                      ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen,
++                                      (caddr_t) q->ixp_q_iv);
++              }
++
++              if (q->ixp_q_acrd) {
++                      auth_off = q->ixp_q_acrd->crd_skip;
++                      auth_len = q->ixp_q_acrd->crd_len;
++                      icv_off  = q->ixp_q_acrd->crd_inject;
++              }
++
++              crypt_off = q->ixp_q_ccrd->crd_skip;
++              crypt_len = q->ixp_q_ccrd->crd_len;
++      } else { /* if (q->ixp_q_acrd) */
++              auth_off = q->ixp_q_acrd->crd_skip;
++              auth_len = q->ixp_q_acrd->crd_len;
++              icv_off  = q->ixp_q_acrd->crd_inject;
++      }
++
++      if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) {
++              struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf;
++              if (skb_shinfo(skb)->nr_frags) {
++                      /*
++                       * DAVIDM fix this limitation one day by using
++                       * a buffer pool and chaining,  it is not currently
++                       * needed for current user/kernel space acceleration
++                       */
++                      printk("ixp: Cannot handle fragmented skb's yet !\n");
++                      q->ixp_q_crp->crp_etype = ENOENT;
++                      goto done;
++              }
++              IX_MBUF_MLEN(&q->ixp_q_mbuf) =
++                              IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) =  skb->len;
++              IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data;
++      } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) {
++              struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf;
++              if (uiop->uio_iovcnt != 1) {
++                      /*
++                       * DAVIDM fix this limitation one day by using
++                       * a buffer pool and chaining,  it is not currently
++                       * needed for current user/kernel space acceleration
++                       */
++                      printk("ixp: Cannot handle more than 1 iovec yet !\n");
++                      q->ixp_q_crp->crp_etype = ENOENT;
++                      goto done;
++              }
++              IX_MBUF_MLEN(&q->ixp_q_mbuf) =
++                              IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len;
++              IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base;
++      } else /* contig buffer */ {
++              IX_MBUF_MLEN(&q->ixp_q_mbuf)  =
++                              IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen;
++              IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf;
++      }
++
++      IX_MBUF_PRIV(&q->ixp_q_mbuf) = q;
++
++      if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) {
++              /*
++               * For SHA1 and MD5 hash, need to create an internal buffer that is big
++               * enough to hold the original data + the appropriate padding for the
++               * hash algorithm.
++               */
++              UINT8 *tbuf = NULL;
++
++              IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) =
++                      ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8;
++              tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC);
++              
++              if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) {
++                      printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n",
++                                      IX_MBUF_MLEN(&q->ixp_q_mbuf));
++                      q->ixp_q_crp->crp_etype = ENOMEM;
++                      goto done;
++              }
++              memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len);
++
++              /* Set location in client buffer to copy hash into */
++              q->ixp_hash_dest =
++                      &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len];
++
++              IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf;
++
++              /* Set location in internal buffer for where hash starts */
++              q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len];
++
++              crypt_func = "ixCryptoAccHashPerform";
++              status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo,
++                              &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len,
++                              &ixp->ixp_hash_key_id);
++      }
++      else {
++              crypt_func = "ixCryptoAccAuthCryptPerform";
++              status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf,
++                      NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off,
++                      q->ixp_q_iv);
++      }
++
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++              return;
++
++      if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) {
++              q->ixp_q_crp->crp_etype = ENOMEM;
++              goto done;
++      }
++
++      printk("ixp: %s failed %u\n", crypt_func, status);
++      q->ixp_q_crp->crp_etype = EINVAL;
++
++done:
++      crypto_done(q->ixp_q_crp);
++      kmem_cache_free(qcache, q);
++}
++
++
++/*
++ * because we cannot process the Q from the Register callback
++ * we do it here on a task Q.
++ */
++
++static void
++ixp_process_pending(void *arg)
++{
++      struct ixp_data *ixp = arg;
++      struct ixp_q *q = NULL;
++
++      dprintk("%s(%p)\n", __FUNCTION__, arg);
++
++      if (!ixp)
++              return;
++
++      while (!list_empty(&ixp->ixp_q)) {
++              q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++              list_del(&q->ixp_q_list);
++              ixp_q_process(q);
++      }
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_process_pending_wq(struct work_struct *work)
++{
++      struct ixp_data *ixp = container_of(work, struct ixp_data,
++                                                              ixp_pending_work);
++      ixp_process_pending(ixp);
++}
++#endif
++
++/*
++ * callback for when context registration is complete
++ */
++
++static void
++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status)
++{
++      int i;
++      struct ixp_data *ixp;
++      struct ixp_q *q;
++
++      dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status);
++
++      /*
++       * free any buffer passed in to this routine
++       */
++      if (bufp) {
++              IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0;
++              kfree(IX_MBUF_MDATA(bufp));
++              IX_MBUF_MDATA(bufp) = NULL;
++      }
++
++      for (i = 0; i < ixp_sesnum; i++) {
++              ixp = ixp_sessions[i];
++              if (ixp && ixp->ixp_ctx_id == ctx_id)
++                      break;
++      }
++      if (i >= ixp_sesnum) {
++              printk("ixp: invalid context id %d\n", ctx_id);
++              return;
++      }
++
++      if (IX_CRYPTO_ACC_STATUS_WAIT == status) {
++              /* this is normal to free the first of two buffers */
++              dprintk("ixp: register not finished yet.\n");
++              return;
++      }
++
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) {
++              printk("ixp: register failed 0x%x\n", status);
++              while (!list_empty(&ixp->ixp_q)) {
++                      q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++                      list_del(&q->ixp_q_list);
++                      q->ixp_q_crp->crp_etype = EINVAL;
++                      crypto_done(q->ixp_q_crp);
++                      kmem_cache_free(qcache, q);
++              }
++              return;
++      }
++
++      /*
++       * we are now registered,  we cannot start processing the Q here
++       * or we get strange errors with AES (DES/3DES seem to be ok).
++       */
++      ixp->ixp_registered = 1;
++      schedule_work(&ixp->ixp_pending_work);
++}
++
++
++/*
++ * callback for when data processing is complete
++ */
++
++static void
++ixp_perform_cb(
++      UINT32 ctx_id,
++      IX_MBUF *sbufp,
++      IX_MBUF *dbufp,
++      IxCryptoAccStatus status)
++{
++      struct ixp_q *q;
++
++      dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp,
++                      dbufp, status);
++
++      if (sbufp == NULL) {
++              printk("ixp: NULL sbuf in ixp_perform_cb\n");
++              return;
++      }
++
++      q = IX_MBUF_PRIV(sbufp);
++      if (q == NULL) {
++              printk("ixp: NULL priv in ixp_perform_cb\n");
++              return;
++      }
++
++      if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++              printk("ixp: perform failed status=%d\n", status);
++              q->ixp_q_crp->crp_etype = EINVAL;
++      }
++
++      crypto_done(q->ixp_q_crp);
++      kmem_cache_free(qcache, q);
++}
++
++
++/*
++ * registration is not callable at IRQ time,  so we defer
++ * to a task queue,  this routines completes the registration for us
++ * when the task queue runs
++ *
++ * Unfortunately this means we cannot tell OCF that the driver is blocked,
++ * we do that on the next request.
++ */
++
++static void
++ixp_registration(void *arg)
++{
++      struct ixp_data *ixp = arg;
++      struct ixp_q *q = NULL;
++      IX_MBUF *pri = NULL, *sec = NULL;
++      int status = IX_CRYPTO_ACC_STATUS_SUCCESS;
++
++      if (!ixp) {
++              printk("ixp: ixp_registration with no arg\n");
++              return;
++      }
++
++      if (ixp->ixp_ctx_id != -1) {
++              ixCryptoAccCtxUnregister(ixp->ixp_ctx_id);
++              ixp->ixp_ctx_id = -1;
++      }
++
++      if (list_empty(&ixp->ixp_q)) {
++              printk("ixp: ixp_registration with no Q\n");
++              return;
++      }
++
++      /*
++       * setup the primary and secondary buffers
++       */
++      q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++      if (q->ixp_q_acrd) {
++              pri = &ixp->ixp_pri_mbuf;
++              sec = &ixp->ixp_sec_mbuf;
++              IX_MBUF_MLEN(pri)  = IX_MBUF_PKT_LEN(pri) = 128;
++              IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++              IX_MBUF_MLEN(sec)  = IX_MBUF_PKT_LEN(sec) = 128;
++              IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++      }
++
++      /* Only need to register if a crypt op or HMAC op */
++      if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 ||
++                              ixp->ixp_auth_alg == CRYPTO_MD5)) {
++              status = ixCryptoAccCtxRegister(
++                                      &ixp->ixp_ctx,
++                                      pri, sec,
++                                      ixp_register_cb,
++                                      ixp_perform_cb,
++                                      &ixp->ixp_ctx_id);
++      }
++      else {
++              /* Otherwise we start processing pending q */
++              schedule_work(&ixp->ixp_pending_work);
++      }
++
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++              return;
++
++      if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) {
++              printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n");
++              ixp_blocked = 1;
++              /* perhaps we should return EGAIN on queued ops ? */
++              return;
++      }
++
++      printk("ixp: ixCryptoAccCtxRegister failed %d\n", status);
++      ixp->ixp_ctx_id = -1;
++
++      /*
++       * everything waiting is toasted
++       */
++      while (!list_empty(&ixp->ixp_q)) {
++              q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++              list_del(&q->ixp_q_list);
++              q->ixp_q_crp->crp_etype = ENOENT;
++              crypto_done(q->ixp_q_crp);
++              kmem_cache_free(qcache, q);
++      }
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_registration_wq(struct work_struct *work)
++{
++      struct ixp_data *ixp = container_of(work, struct ixp_data,
++                                                              ixp_registration_work);
++      ixp_registration(ixp);
++}
++#endif
++
++/*
++ * Process a request.
++ */
++static int
++ixp_process(device_t dev, struct cryptop *crp, int hint)
++{
++      struct ixp_data *ixp;
++      unsigned int lid;
++      struct ixp_q *q = NULL;
++      int status;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      /* Sanity check */
++      if (crp == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      crp->crp_etype = 0;
++
++      if (ixp_blocked)
++              return ERESTART;
++
++      if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              crp->crp_etype = EINVAL;
++              goto done;
++      }
++
++      /*
++       * find the session we are using
++       */
++
++      lid = crp->crp_sid & 0xffffffff;
++      if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL ||
++                      ixp_sessions[lid] == NULL) {
++              crp->crp_etype = ENOENT;
++              dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++              goto done;
++      }
++      ixp = ixp_sessions[lid];
++
++      /*
++       * setup a new request ready for queuing
++       */
++      q = kmem_cache_alloc(qcache, SLAB_ATOMIC);
++      if (q == NULL) {
++              dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__);
++              crp->crp_etype = ENOMEM;
++              goto done;
++      }
++      /*
++       * save some cycles by only zeroing the important bits
++       */
++      memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf));
++      q->ixp_q_ccrd = NULL;
++      q->ixp_q_acrd = NULL;
++      q->ixp_q_crp = crp;
++      q->ixp_q_data = ixp;
++
++      /*
++       * point the cipher and auth descriptors appropriately
++       * check that we have something to do
++       */
++      if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg)
++              q->ixp_q_ccrd = crp->crp_desc;
++      else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg)
++              q->ixp_q_acrd = crp->crp_desc;
++      else {
++              crp->crp_etype = ENOENT;
++              dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__);
++              goto done;
++      }
++      if (crp->crp_desc->crd_next) {
++              if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg)
++                      q->ixp_q_ccrd = crp->crp_desc->crd_next;
++              else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg)
++                      q->ixp_q_acrd = crp->crp_desc->crd_next;
++              else {
++                      crp->crp_etype = ENOENT;
++                      dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__);
++                      goto done;
++              }
++      }
++
++      /*
++       * If there is a direction change for this context then we mark it as
++       * unregistered and re-register is for the new direction.  This is not
++       * a very expensive operation and currently only tends to happen when
++       * user-space application are doing benchmarks
++       *
++       * DM - we should be checking for pending requests before unregistering.
++       */
++      if (q->ixp_q_ccrd && ixp->ixp_registered &&
++                      ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) {
++              dprintk("%s - detected direction change on session\n", __FUNCTION__);
++              ixp->ixp_registered = 0;
++      }
++
++      /*
++       * if we are registered,  call straight into the perform code
++       */
++      if (ixp->ixp_registered) {
++              ixp_q_process(q);
++              return 0;
++      }
++
++      /*
++       * the only part of the context not set in newsession is the direction
++       * dependent parts
++       */
++      if (q->ixp_q_ccrd) {
++              ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT);
++              if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) {
++                      ixp->ixp_ctx.operation = q->ixp_q_acrd ?
++                                      IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT;
++              } else {
++                      ixp->ixp_ctx.operation = q->ixp_q_acrd ?
++                                      IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT;
++              }
++      } else {
++              /* q->ixp_q_acrd must be set if we are here */
++              ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC;
++      }
++
++      status = list_empty(&ixp->ixp_q);
++      list_add_tail(&q->ixp_q_list, &ixp->ixp_q);
++      if (status)
++              schedule_work(&ixp->ixp_registration_work);
++      return 0;
++
++done:
++      if (q)
++              kmem_cache_free(qcache, q);
++      crypto_done(crp);
++      return 0;
++}
++
++
++#ifdef __ixp46X
++/*
++ * key processing support for the ixp465
++ */
++
++
++/*
++ * copy a BN (LE) into a buffer (BE) an fill out the op appropriately
++ * assume zeroed and only copy bits that are significant
++ */
++
++static int
++ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf)
++{
++      unsigned char *src = (unsigned char *) p->crp_p;
++      unsigned char *dst;
++      int len, bits = p->crp_nbits;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) {
++              dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__,
++                              bits, MAX_IOP_SIZE * sizeof(UINT32) * 8);
++              return -1;
++      }
++
++      len = (bits + 31) / 32; /* the number UINT32's needed */
++
++      dst = (unsigned char *) &buf[len];
++      dst--;
++
++      while (bits > 0) {
++              *dst-- = *src++;
++              bits -= 8;
++      }
++
++#if 0 /* no need to zero remaining bits as it is done during request alloc */
++      while (dst > (unsigned char *) buf)
++              *dst-- = '\0';
++#endif
++
++      op->pData = buf;
++      op->dataLen = len;
++      return 0;
++}
++
++/*
++ * copy out the result,  be as forgiving as we can about small output buffers
++ */
++
++static int
++ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf)
++{
++      unsigned char *dst = (unsigned char *) p->crp_p;
++      unsigned char *src = (unsigned char *) buf;
++      int len, z, bits = p->crp_nbits;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      len = op->dataLen * sizeof(UINT32);
++
++      /* skip leading zeroes to be small buffer friendly */
++      z = 0;
++      while (z < len && src[z] == '\0')
++              z++;
++
++      src += len;
++      src--;
++      len -= z;
++
++      while (len > 0 && bits > 0) {
++              *dst++ = *src--;
++              len--;
++              bits -= 8;
++      }
++
++      while (bits > 0) {
++              *dst++ = '\0';
++              bits -= 8;
++      }
++
++      if (len > 0) {
++              dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n",
++                              __FUNCTION__, len, z, p->crp_nbits / 8);
++              return -1;
++      }
++
++      return 0;
++}
++
++
++/*
++ * the parameter offsets for exp_mod
++ */
++
++#define IXP_PARAM_BASE 0
++#define IXP_PARAM_EXP  1
++#define IXP_PARAM_MOD  2
++#define IXP_PARAM_RES  3
++
++/*
++ * key processing complete callback,  is also used to start processing
++ * by passing a NULL for pResult
++ */
++
++static void
++ixp_kperform_cb(
++      IxCryptoAccPkeEauOperation operation,
++      IxCryptoAccPkeEauOpResult *pResult,
++      BOOL carryOrBorrow,
++      IxCryptoAccStatus status)
++{
++      struct ixp_pkq *q, *tmp;
++      unsigned long flags;
++
++      dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult,
++                      carryOrBorrow, status);
++
++      /* handle a completed request */
++      if (pResult) {
++              if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) {
++                      q = ixp_pk_cur;
++                      if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++                              dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status);
++                              q->pkq_krp->krp_status = ERANGE; /* could do better */
++                      } else {
++                              /* copy out the result */
++                              if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES],
++                                              &q->pkq_result, q->pkq_obuf))
++                                      q->pkq_krp->krp_status = ERANGE;
++                      }
++                      crypto_kdone(q->pkq_krp);
++                      kfree(q);
++                      ixp_pk_cur = NULL;
++              } else
++                      printk("%s - callback with invalid result pointer\n", __FUNCTION__);
++      }
++
++      spin_lock_irqsave(&ixp_pkq_lock, flags);
++      if (ixp_pk_cur || list_empty(&ixp_pkq)) {
++              spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++              return;
++      }
++
++      list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) {
++
++              list_del(&q->pkq_list);
++              ixp_pk_cur = q;
++
++              spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++
++              status = ixCryptoAccPkeEauPerform(
++                              IX_CRYPTO_ACC_OP_EAU_MOD_EXP,
++                              &q->pkq_op,
++                              ixp_kperform_cb,
++                              &q->pkq_result);
++      
++              if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) {
++                      dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__);
++                      return; /* callback will return here for callback */
++              } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) {
++                      printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__);
++              } else {
++                      printk("%s() - ixCryptoAccPkeEauPerform failed %d\n",
++                                      __FUNCTION__, status);
++              }
++              q->pkq_krp->krp_status = ERANGE; /* could do better */
++              crypto_kdone(q->pkq_krp);
++              kfree(q);
++              spin_lock_irqsave(&ixp_pkq_lock, flags);
++      }
++      spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++}
++
++
++static int
++ixp_kprocess(device_t dev, struct cryptkop *krp, int hint)
++{
++      struct ixp_pkq *q;
++      int rc = 0;
++      unsigned long flags;
++
++      dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__,
++                      krp->krp_param[IXP_PARAM_BASE].crp_nbits,
++                      krp->krp_param[IXP_PARAM_EXP].crp_nbits,
++                      krp->krp_param[IXP_PARAM_MOD].crp_nbits,
++                      krp->krp_param[IXP_PARAM_RES].crp_nbits);
++
++
++      if (krp->krp_op != CRK_MOD_EXP) {
++              krp->krp_status = EOPNOTSUPP;
++              goto err;
++      }
++
++      q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL);
++      if (q == NULL) {
++              krp->krp_status = ENOMEM;
++              goto err;
++      }
++
++      /*
++       * The PKE engine does not appear to zero the output buffer
++       * appropriately, so we need to do it all here.
++       */
++      memset(q, 0, sizeof(*q));
++
++      q->pkq_krp = krp;
++      INIT_LIST_HEAD(&q->pkq_list);
++
++      if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M,
++                      q->pkq_ibuf0))
++              rc = 1;
++      if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP],
++                              &q->pkq_op.modExpOpr.e, q->pkq_ibuf1))
++              rc = 2;
++      if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD],
++                              &q->pkq_op.modExpOpr.N, q->pkq_ibuf2))
++              rc = 3;
++
++      if (rc) {
++              kfree(q);
++              krp->krp_status = ERANGE;
++              goto err;
++      }
++
++      q->pkq_result.pData           = q->pkq_obuf;
++      q->pkq_result.dataLen         =
++                      (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32;
++
++      spin_lock_irqsave(&ixp_pkq_lock, flags);
++      list_add_tail(&q->pkq_list, &ixp_pkq);
++      spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++
++      if (!ixp_pk_cur)
++              ixp_kperform_cb(0, NULL, 0, 0);
++      return (0);
++
++err:
++      crypto_kdone(krp);
++      return (0);
++}
++
++
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++/*
++ * We run the random number generator output through SHA so that it
++ * is FIPS compliant.
++ */
++
++static volatile int sha_done = 0;
++static unsigned char sha_digest[20];
++
++static void
++ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status)
++{
++      dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status);
++      if (sha_digest != digest)
++              printk("digest error\n");
++      if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++              sha_done = 1;
++      else
++              sha_done = -status;
++}
++
++static int
++ixp_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++      IxCryptoAccStatus status;
++      int i, n, rc;
++
++      dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords);
++      memset(buf, 0, maxwords * sizeof(*buf));
++      status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf);
++      if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++              dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n",
++                              __FUNCTION__, status);
++              return 0;
++      }
++
++      /*
++       * run the random data through SHA to make it look more random
++       */
++
++      n = sizeof(sha_digest); /* process digest bytes at a time */
++
++      rc = 0;
++      for (i = 0; i < maxwords; i += n / sizeof(*buf)) {
++              if ((maxwords - i) * sizeof(*buf) < n)
++                      n = (maxwords - i) * sizeof(*buf);
++              sha_done = 0;
++              status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1,
++                              (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest);
++              if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++                      dprintk("ixCryptoAccPkeHashPerform failed %d\n", status);
++                      return -EIO;
++              }
++              while (!sha_done)
++                      schedule();
++              if (sha_done < 0) {
++                      dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done);
++                      return 0;
++              }
++              memcpy(&buf[i], sha_digest, n);
++              rc += n / sizeof(*buf);;
++      }
++
++      return rc;
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++#endif /* __ixp46X */
++
++
++
++/*
++ * our driver startup and shutdown routines
++ */
++
++static int
++ixp_init(void)
++{
++      dprintk("%s(%p)\n", __FUNCTION__, ixp_init);
++
++      if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS)
++              printk("ixCryptoAccInit failed, assuming already initialised!\n");
++
++      qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0,
++                              SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++                              , NULL
++#endif
++                                );
++      if (!qcache) {
++              printk("failed to create Qcache\n");
++              return -ENOENT;
++      }
++
++      memset(&ixpdev, 0, sizeof(ixpdev));
++      softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods);
++
++      ixp_id = crypto_get_driverid(softc_get_device(&ixpdev),
++                              CRYPTOCAP_F_HARDWARE);
++      if (ixp_id < 0)
++              panic("IXP/OCF crypto device cannot initialize!");
++
++#define       REGISTER(alg) \
++      crypto_register(ixp_id,alg,0,0)
++
++      REGISTER(CRYPTO_DES_CBC);
++      REGISTER(CRYPTO_3DES_CBC);
++      REGISTER(CRYPTO_RIJNDAEL128_CBC);
++#ifdef CONFIG_OCF_IXP4XX_SHA1_MD5
++      REGISTER(CRYPTO_MD5);
++      REGISTER(CRYPTO_SHA1);
++#endif
++      REGISTER(CRYPTO_MD5_HMAC);
++      REGISTER(CRYPTO_SHA1_HMAC);
++#undef REGISTER
++
++#ifdef __ixp46X
++      spin_lock_init(&ixp_pkq_lock);
++      /*
++       * we do not enable the go fast options here as they can potentially
++       * allow timing based attacks
++       *
++       * http://www.openssl.org/news/secadv_20030219.txt
++       */
++      ixCryptoAccPkeEauExpConfig(0, 0);
++      crypto_kregister(ixp_id, CRK_MOD_EXP, 0);
++#ifdef CONFIG_OCF_RANDOMHARVEST
++      crypto_rregister(ixp_id, ixp_read_random, NULL);
++#endif
++#endif
++
++      return 0;
++}
++
++static void
++ixp_exit(void)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      crypto_unregister_all(ixp_id);
++      ixp_id = -1;
++      kmem_cache_destroy(qcache);
++      qcache = NULL;
++}
++
++module_init(ixp_init);
++module_exit(ixp_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <dmccullough@cyberguard.com>");
++MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/cryptodev.c       2007-12-14 12:35:04.000000000 +1000
+@@ -0,0 +1,1048 @@
++/*    $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $  */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/types.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/mount.h>
++#include <linux/miscdevice.h>
++#include <linux/version.h>
++#include <asm/uaccess.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++extern asmlinkage long sys_dup(unsigned int fildes);
++
++#define debug cryptodev_debug
++int cryptodev_debug = 0;
++module_param(cryptodev_debug, int, 0644);
++MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug");
++
++struct csession_info {
++      u_int16_t       blocksize;
++      u_int16_t       minkey, maxkey;
++
++      u_int16_t       keysize;
++      /* u_int16_t    hashsize;  */
++      u_int16_t       authsize;
++      /* u_int16_t    ctxsize; */
++};
++
++struct csession {
++      struct list_head        list;
++      u_int64_t       sid;
++      u_int32_t       ses;
++
++      wait_queue_head_t waitq;
++
++      u_int32_t       cipher;
++
++      u_int32_t       mac;
++
++      caddr_t         key;
++      int             keylen;
++      u_char          tmp_iv[EALG_MAX_BLOCK_LEN];
++
++      caddr_t         mackey;
++      int             mackeylen;
++
++      struct csession_info info;
++
++      struct iovec    iovec;
++      struct uio      uio;
++      int             error;
++};
++
++struct fcrypt {
++      struct list_head        csessions;
++      int             sesn;
++};
++
++static struct csession *csefind(struct fcrypt *, u_int);
++static int csedelete(struct fcrypt *, struct csession *);
++static struct csession *cseadd(struct fcrypt *, struct csession *);
++static struct csession *csecreate(struct fcrypt *, u_int64_t,
++              struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);
++static int csefree(struct csession *);
++
++static        int cryptodev_op(struct csession *, struct crypt_op *);
++static        int cryptodev_key(struct crypt_kop *);
++static        int cryptodev_find(struct crypt_find_op *);
++
++static int cryptodev_cb(void *);
++static int cryptodev_open(struct inode *inode, struct file *filp);
++
++/*
++ * Check a crypto identifier to see if it requested
++ * a valid crid and it's capabilities match.
++ */
++static int
++checkcrid(int crid)
++{
++      int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++      int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++      int caps = 0;
++      
++      /* if the user hasn't selected a driver, then just call newsession */
++      if (hid == 0 && typ != 0)
++              return 0;
++
++      caps = crypto_getcaps(hid);
++
++      /* didn't find anything with capabilities */
++      if (caps == 0) {
++              dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ);
++              return EINVAL;
++      }
++      
++      /* the user didn't specify SW or HW, so the driver is ok */
++      if (typ == 0)
++              return 0;
++
++      /* if the type specified didn't match */
++      if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) {
++              dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__,
++                              hid, typ, caps);
++              return EINVAL;
++      }
++
++      return 0;
++}
++
++static int
++cryptodev_op(struct csession *cse, struct crypt_op *cop)
++{
++      struct cryptop *crp = NULL;
++      struct cryptodesc *crde = NULL, *crda = NULL;
++      int error = 0;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (cop->len > CRYPTO_MAX_DATA_LEN) {
++              dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN);
++              return (E2BIG);
++      }
++
++      if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) {
++              dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize,
++                              cop->len);
++              return (EINVAL);
++      }
++
++      cse->uio.uio_iov = &cse->iovec;
++      cse->uio.uio_iovcnt = 1;
++      cse->uio.uio_offset = 0;
++#if 0
++      cse->uio.uio_resid = cop->len;
++      cse->uio.uio_segflg = UIO_SYSSPACE;
++      cse->uio.uio_rw = UIO_WRITE;
++      cse->uio.uio_td = td;
++#endif
++      cse->uio.uio_iov[0].iov_len = cop->len;
++      if (cse->info.authsize)
++              cse->uio.uio_iov[0].iov_len += cse->info.authsize;
++      cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
++                      GFP_KERNEL);
++
++      if (cse->uio.uio_iov[0].iov_base == NULL) {
++              dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__,
++                              cse->uio.uio_iov[0].iov_len);
++              return (ENOMEM);
++      }
++
++      crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0));
++      if (crp == NULL) {
++              dprintk("%s: ENOMEM\n", __FUNCTION__);
++              error = ENOMEM;
++              goto bail;
++      }
++
++      if (cse->info.authsize) {
++              crda = crp->crp_desc;
++              if (cse->info.blocksize)
++                      crde = crda->crd_next;
++      } else {
++              if (cse->info.blocksize)
++                      crde = crp->crp_desc;
++              else {
++                      dprintk("%s: bad request\n", __FUNCTION__);
++                      error = EINVAL;
++                      goto bail;
++              }
++      }
++
++      if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src,
++                                      cop->len))) {
++              dprintk("%s: bad copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (crda) {
++              crda->crd_skip = 0;
++              crda->crd_len = cop->len;
++              crda->crd_inject = cop->len;
++
++              crda->crd_alg = cse->mac;
++              crda->crd_key = cse->mackey;
++              crda->crd_klen = cse->mackeylen * 8;
++      }
++
++      if (crde) {
++              if (cop->op == COP_ENCRYPT)
++                      crde->crd_flags |= CRD_F_ENCRYPT;
++              else
++                      crde->crd_flags &= ~CRD_F_ENCRYPT;
++              crde->crd_len = cop->len;
++              crde->crd_inject = 0;
++
++              crde->crd_alg = cse->cipher;
++              crde->crd_key = cse->key;
++              crde->crd_klen = cse->keylen * 8;
++      }
++
++      crp->crp_ilen = cse->uio.uio_iov[0].iov_len;
++      crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
++                     | (cop->flags & COP_F_BATCH);
++      crp->crp_buf = (caddr_t)&cse->uio;
++      crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
++      crp->crp_sid = cse->sid;
++      crp->crp_opaque = (void *)cse;
++
++      if (cop->iv) {
++              if (crde == NULL) {
++                      error = EINVAL;
++                      dprintk("%s no crde\n", __FUNCTION__);
++                      goto bail;
++              }
++              if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++                      error = EINVAL;
++                      dprintk("%s arc4 with IV\n", __FUNCTION__);
++                      goto bail;
++              }
++              if ((error = copy_from_user(cse->tmp_iv, cop->iv,
++                                              cse->info.blocksize))) {
++                      dprintk("%s bad iv copy\n", __FUNCTION__);
++                      goto bail;
++              }
++              memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize);
++              crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
++              crde->crd_skip = 0;
++      } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++              crde->crd_skip = 0;
++      } else if (crde) {
++              crde->crd_flags |= CRD_F_IV_PRESENT;
++              crde->crd_skip = cse->info.blocksize;
++              crde->crd_len -= cse->info.blocksize;
++      }
++
++      if (cop->mac && crda == NULL) {
++              error = EINVAL;
++              dprintk("%s no crda\n", __FUNCTION__);
++              goto bail;
++      }
++
++      /*
++       * Let the dispatch run unlocked, then, interlock against the
++       * callback before checking if the operation completed and going
++       * to sleep.  This insures drivers don't inherit our lock which
++       * results in a lock order reversal between crypto_dispatch forced
++       * entry and the crypto_done callback into us.
++       */
++      error = crypto_dispatch(crp);
++      if (error == 0) {
++              dprintk("%s about to WAIT\n", __FUNCTION__);
++              /*
++               * we really need to wait for driver to complete to maintain
++               * state,  luckily interrupts will be remembered
++               */
++              do {
++                      error = wait_event_interruptible(crp->crp_waitq,
++                                      ((crp->crp_flags & CRYPTO_F_DONE) != 0));
++                      /*
++                       * we can't break out of this loop or we will leave behind
++                       * a huge mess,  however,  staying here means if your driver
++                       * is broken user applications can hang and not be killed.
++                       * The solution,  fix your driver :-)
++                       */
++                      if (error) {
++                              schedule();
++                              error = 0;
++                      }
++              } while ((crp->crp_flags & CRYPTO_F_DONE) == 0);
++              dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++      }
++
++      if (crp->crp_etype != 0) {
++              error = crp->crp_etype;
++              dprintk("%s error in crp processing\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cse->error) {
++              error = cse->error;
++              dprintk("%s error in cse processing\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cop->dst && (error = copy_to_user(cop->dst,
++                                      cse->uio.uio_iov[0].iov_base, cop->len))) {
++              dprintk("%s bad dst copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cop->mac &&
++                      (error=copy_to_user(cop->mac,
++                              (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
++                              cse->info.authsize))) {
++              dprintk("%s bad mac copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++bail:
++      if (crp)
++              crypto_freereq(crp);
++      if (cse->uio.uio_iov[0].iov_base)
++              kfree(cse->uio.uio_iov[0].iov_base);
++
++      return (error);
++}
++
++static int
++cryptodev_cb(void *op)
++{
++      struct cryptop *crp = (struct cryptop *) op;
++      struct csession *cse = (struct csession *)crp->crp_opaque;
++      int error;
++
++      dprintk("%s()\n", __FUNCTION__);
++      error = crp->crp_etype;
++      if (error == EAGAIN) {
++              crp->crp_flags &= ~CRYPTO_F_DONE;
++#ifdef NOTYET
++              /*
++               * DAVIDM I am fairly sure that we should turn this into a batch
++               * request to stop bad karma/lockup, revisit
++               */
++              crp->crp_flags |= CRYPTO_F_BATCH;
++#endif
++              return crypto_dispatch(crp);
++      }
++      if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
++              cse->error = error;
++              wake_up_interruptible(&crp->crp_waitq);
++      }
++      return (0);
++}
++
++static int
++cryptodevkey_cb(void *op)
++{
++      struct cryptkop *krp = (struct cryptkop *) op;
++      dprintk("%s()\n", __FUNCTION__);
++      wake_up_interruptible(&krp->krp_waitq);
++      return (0);
++}
++
++static int
++cryptodev_key(struct crypt_kop *kop)
++{
++      struct cryptkop *krp = NULL;
++      int error = EINVAL;
++      int in, out, size, i;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
++              dprintk("%s params too big\n", __FUNCTION__);
++              return (EFBIG);
++      }
++
++      in = kop->crk_iparams;
++      out = kop->crk_oparams;
++      switch (kop->crk_op) {
++      case CRK_MOD_EXP:
++              if (in == 3 && out == 1)
++                      break;
++              return (EINVAL);
++      case CRK_MOD_EXP_CRT:
++              if (in == 6 && out == 1)
++                      break;
++              return (EINVAL);
++      case CRK_DSA_SIGN:
++              if (in == 5 && out == 2)
++                      break;
++              return (EINVAL);
++      case CRK_DSA_VERIFY:
++              if (in == 7 && out == 0)
++                      break;
++              return (EINVAL);
++      case CRK_DH_COMPUTE_KEY:
++              if (in == 3 && out == 1)
++                      break;
++              return (EINVAL);
++      default:
++              return (EINVAL);
++      }
++
++      krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL);
++      if (!krp)
++              return (ENOMEM);
++      bzero(krp, sizeof *krp);
++      krp->krp_op = kop->crk_op;
++      krp->krp_status = kop->crk_status;
++      krp->krp_iparams = kop->crk_iparams;
++      krp->krp_oparams = kop->crk_oparams;
++      krp->krp_crid = kop->crk_crid;
++      krp->krp_status = 0;
++      krp->krp_flags = CRYPTO_KF_CBIMM;
++      krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
++      init_waitqueue_head(&krp->krp_waitq);
++
++      for (i = 0; i < CRK_MAXPARAM; i++)
++              krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
++      for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
++              size = (krp->krp_param[i].crp_nbits + 7) / 8;
++              if (size == 0)
++                      continue;
++              krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL);
++              if (i >= krp->krp_iparams)
++                      continue;
++              error = copy_from_user(krp->krp_param[i].crp_p,
++                              kop->crk_param[i].crp_p, size);
++              if (error)
++                      goto fail;
++      }
++
++      error = crypto_kdispatch(krp);
++      if (error)
++              goto fail;
++
++      do {
++              error = wait_event_interruptible(krp->krp_waitq,
++                              ((krp->krp_flags & CRYPTO_KF_DONE) != 0));
++              /*
++               * we can't break out of this loop or we will leave behind
++               * a huge mess,  however,  staying here means if your driver
++               * is broken user applications can hang and not be killed.
++               * The solution,  fix your driver :-)
++               */
++              if (error) {
++                      schedule();
++                      error = 0;
++              }
++      } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0);
++
++      dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++      
++      kop->crk_crid = krp->krp_crid;          /* device that did the work */
++      if (krp->krp_status != 0) {
++              error = krp->krp_status;
++              goto fail;
++      }
++
++      for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
++              size = (krp->krp_param[i].crp_nbits + 7) / 8;
++              if (size == 0)
++                      continue;
++              error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p,
++                              size);
++              if (error)
++                      goto fail;
++      }
++
++fail:
++      if (krp) {
++              kop->crk_status = krp->krp_status;
++              for (i = 0; i < CRK_MAXPARAM; i++) {
++                      if (krp->krp_param[i].crp_p)
++                              kfree(krp->krp_param[i].crp_p);
++              }
++              kfree(krp);
++      }
++      return (error);
++}
++
++static int
++cryptodev_find(struct crypt_find_op *find)
++{
++      device_t dev;
++
++      if (find->crid != -1) {
++              dev = crypto_find_device_byhid(find->crid);
++              if (dev == NULL)
++                      return (ENOENT);
++              strlcpy(find->name, device_get_nameunit(dev),
++                  sizeof(find->name));
++      } else {
++              find->crid = crypto_find_driver(find->name);
++              if (find->crid == -1)
++                      return (ENOENT);
++      }
++      return (0);
++}
++
++static struct csession *
++csefind(struct fcrypt *fcr, u_int ses)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      list_for_each_entry(cse, &fcr->csessions, list)
++              if (cse->ses == ses)
++                      return (cse);
++      return (NULL);
++}
++
++static int
++csedelete(struct fcrypt *fcr, struct csession *cse_del)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      list_for_each_entry(cse, &fcr->csessions, list) {
++              if (cse == cse_del) {
++                      list_del(&cse->list);
++                      return (1);
++              }
++      }
++      return (0);
++}
++      
++static struct csession *
++cseadd(struct fcrypt *fcr, struct csession *cse)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      list_add_tail(&cse->list, &fcr->csessions);
++      cse->ses = fcr->sesn++;
++      return (cse);
++}
++
++static struct csession *
++csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie,
++      struct cryptoini *cria, struct csession_info *info)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL);
++      if (cse == NULL)
++              return NULL;
++      memset(cse, 0, sizeof(struct csession));
++
++      INIT_LIST_HEAD(&cse->list);
++      init_waitqueue_head(&cse->waitq);
++
++      cse->key = crie->cri_key;
++      cse->keylen = crie->cri_klen/8;
++      cse->mackey = cria->cri_key;
++      cse->mackeylen = cria->cri_klen/8;
++      cse->sid = sid;
++      cse->cipher = crie->cri_alg;
++      cse->mac = cria->cri_alg;
++      cse->info = *info;
++      cseadd(fcr, cse);
++      return (cse);
++}
++
++static int
++csefree(struct csession *cse)
++{
++      int error;
++
++      dprintk("%s()\n", __FUNCTION__);
++      error = crypto_freesession(cse->sid);
++      if (cse->key)
++              kfree(cse->key);
++      if (cse->mackey)
++              kfree(cse->mackey);
++      kfree(cse);
++      return(error);
++}
++
++static int
++cryptodev_ioctl(
++      struct inode *inode,
++      struct file *filp,
++      unsigned int cmd,
++      unsigned long arg)
++{
++      struct cryptoini cria, crie;
++      struct fcrypt *fcr = filp->private_data;
++      struct csession *cse;
++      struct csession_info info;
++      struct session2_op sop;
++      struct crypt_op cop;
++      struct crypt_kop kop;
++      struct crypt_find_op fop;
++      u_int64_t sid;
++      u_int32_t ses;
++      int feat, fd, error = 0, crid;
++      mm_segment_t fs;
++
++      dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg);
++
++      switch (cmd) {
++
++      case CRIOGET: {
++              dprintk("%s(CRIOGET)\n", __FUNCTION__);
++              fs = get_fs();
++              set_fs(get_ds());
++              for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
++                      if (files_fdtable(current->files)->fd[fd] == filp)
++                              break;
++              fd = sys_dup(fd);
++              set_fs(fs);
++              put_user(fd, (int *) arg);
++              return IS_ERR_VALUE(fd) ? fd : 0;
++              }
++
++#define       CIOCGSESSSTR    (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2")
++      case CIOCGSESSION:
++      case CIOCGSESSION2:
++              dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR);
++              memset(&crie, 0, sizeof(crie));
++              memset(&cria, 0, sizeof(cria));
++              memset(&info, 0, sizeof(info));
++              memset(&sop, 0, sizeof(sop));
++
++              if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ?
++                                      sizeof(struct session_op) : sizeof(sop))) {
++                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EFAULT;
++                      goto bail;
++              }
++
++              switch (sop.cipher) {
++              case 0:
++                      dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR);
++                      break;
++              case CRYPTO_NULL_CBC:
++                      info.blocksize = NULL_BLOCK_LEN;
++                      info.minkey = NULL_MIN_KEY_LEN;
++                      info.maxkey = NULL_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_DES_CBC:
++                      info.blocksize = DES_BLOCK_LEN;
++                      info.minkey = DES_MIN_KEY_LEN;
++                      info.maxkey = DES_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_3DES_CBC:
++                      info.blocksize = DES3_BLOCK_LEN;
++                      info.minkey = DES3_MIN_KEY_LEN;
++                      info.maxkey = DES3_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_BLF_CBC:
++                      info.blocksize = BLOWFISH_BLOCK_LEN;
++                      info.minkey = BLOWFISH_MIN_KEY_LEN;
++                      info.maxkey = BLOWFISH_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_CAST_CBC:
++                      info.blocksize = CAST128_BLOCK_LEN;
++                      info.minkey = CAST128_MIN_KEY_LEN;
++                      info.maxkey = CAST128_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_SKIPJACK_CBC:
++                      info.blocksize = SKIPJACK_BLOCK_LEN;
++                      info.minkey = SKIPJACK_MIN_KEY_LEN;
++                      info.maxkey = SKIPJACK_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_AES_CBC:
++                      info.blocksize = AES_BLOCK_LEN;
++                      info.minkey = AES_MIN_KEY_LEN;
++                      info.maxkey = AES_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_ARC4:
++                      info.blocksize = ARC4_BLOCK_LEN;
++                      info.minkey = ARC4_MIN_KEY_LEN;
++                      info.maxkey = ARC4_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_CAMELLIA_CBC:
++                      info.blocksize = CAMELLIA_BLOCK_LEN;
++                      info.minkey = CAMELLIA_MIN_KEY_LEN;
++                      info.maxkey = CAMELLIA_MAX_KEY_LEN;
++                      break;
++              default:
++                      dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EINVAL;
++                      goto bail;
++              }
++
++              switch (sop.mac) {
++              case 0:
++                      dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR);
++                      break;
++              case CRYPTO_NULL_HMAC:
++                      info.authsize = NULL_HASH_LEN;
++                      break;
++              case CRYPTO_MD5:
++                      info.authsize = MD5_HASH_LEN;
++                      break;
++              case CRYPTO_SHA1:
++                      info.authsize = SHA1_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_256:
++                      info.authsize = SHA2_256_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_384:
++                      info.authsize = SHA2_384_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_512:
++                      info.authsize = SHA2_512_HASH_LEN;
++                      break;
++              case CRYPTO_RIPEMD160:
++                      info.authsize = RIPEMD160_HASH_LEN;
++                      break;
++              case CRYPTO_MD5_HMAC:
++                      info.authsize = MD5_HASH_LEN;
++                      break;
++              case CRYPTO_SHA1_HMAC:
++                      info.authsize = SHA1_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_256_HMAC:
++                      info.authsize = SHA2_256_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_384_HMAC:
++                      info.authsize = SHA2_384_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_512_HMAC:
++                      info.authsize = SHA2_512_HASH_LEN;
++                      break;
++              case CRYPTO_RIPEMD160_HMAC:
++                      info.authsize = RIPEMD160_HASH_LEN;
++                      break;
++              default:
++                      dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EINVAL;
++                      goto bail;
++              }
++
++              if (info.blocksize) {
++                      crie.cri_alg = sop.cipher;
++                      crie.cri_klen = sop.keylen * 8;
++                      if ((info.maxkey && sop.keylen > info.maxkey) ||
++                                      sop.keylen < info.minkey) {
++                              dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR);
++                              error = EINVAL;
++                              goto bail;
++                      }
++
++                      crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL);
++                      if (copy_from_user(crie.cri_key, sop.key,
++                                                      crie.cri_klen/8)) {
++                              dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                              error = EFAULT;
++                              goto bail;
++                      }
++                      if (info.authsize)
++                              crie.cri_next = &cria;
++              }
++
++              if (info.authsize) {
++                      cria.cri_alg = sop.mac;
++                      cria.cri_klen = sop.mackeylen * 8;
++                      if ((info.maxkey && sop.mackeylen > info.maxkey) ||
++                                      sop.keylen < info.minkey) {
++                              dprintk("%s(%s) - mackeylen %d\n", __FUNCTION__, CIOCGSESSSTR,
++                                              sop.mackeylen);
++                              error = EINVAL;
++                              goto bail;
++                      }
++
++                      if (cria.cri_klen) {
++                              cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL);
++                              if (copy_from_user(cria.cri_key, sop.mackey,
++                                                              cria.cri_klen / 8)) {
++                                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                                      error = EFAULT;
++                                      goto bail;
++                              }
++                      }
++              }
++
++              /* NB: CIOGSESSION2 has the crid */
++              if (cmd == CIOCGSESSION2) {
++                      crid = sop.crid;
++                      error = checkcrid(crid);
++                      if (error) {
++                              dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__,
++                                              CIOCGSESSSTR, error);
++                              goto bail;
++                      }
++              } else {
++                      /* allow either HW or SW to be used */
++                      crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++              }
++              error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid);
++              if (error) {
++                      dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error);
++                      goto bail;
++              }
++
++              cse = csecreate(fcr, sid, &crie, &cria, &info);
++              if (cse == NULL) {
++                      crypto_freesession(sid);
++                      error = EINVAL;
++                      dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR);
++                      goto bail;
++              }
++              sop.ses = cse->ses;
++
++              if (cmd == CIOCGSESSION2) {
++                      /* return hardware/driver id */
++                      sop.crid = CRYPTO_SESID2HID(cse->sid);
++              }
++
++              if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ?
++                                      sizeof(struct session_op) : sizeof(sop))) {
++                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EFAULT;
++              }
++bail:
++              if (error) {
++                      dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error);
++                      if (crie.cri_key)
++                              kfree(crie.cri_key);
++                      if (cria.cri_key)
++                              kfree(cria.cri_key);
++              }
++              break;
++      case CIOCFSESSION:
++              dprintk("%s(CIOCFSESSION)\n", __FUNCTION__);
++              get_user(ses, (uint32_t*)arg);
++              cse = csefind(fcr, ses);
++              if (cse == NULL) {
++                      error = EINVAL;
++                      dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error);
++                      break;
++              }
++              csedelete(fcr, cse);
++              error = csefree(cse);
++              break;
++      case CIOCCRYPT:
++              dprintk("%s(CIOCCRYPT)\n", __FUNCTION__);
++              if(copy_from_user(&cop, (void*)arg, sizeof(cop))) {
++                      dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              cse = csefind(fcr, cop.ses);
++              if (cse == NULL) {
++                      error = EINVAL;
++                      dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error);
++                      break;
++              }
++              error = cryptodev_op(cse, &cop);
++              if(copy_to_user((void*)arg, &cop, sizeof(cop))) {
++                      dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      case CIOCKEY:
++      case CIOCKEY2:
++              dprintk("%s(CIOCKEY)\n", __FUNCTION__);
++              if (!crypto_userasymcrypto)
++                      return (EPERM);         /* XXX compat? */
++              if(copy_from_user(&kop, (void*)arg, sizeof(kop))) {
++                      dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              if (cmd == CIOCKEY) {
++                      /* NB: crypto core enforces s/w driver use */
++                      kop.crk_crid =
++                          CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++              }
++              error = cryptodev_key(&kop);
++              if(copy_to_user((void*)arg, &kop, sizeof(kop))) {
++                      dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      case CIOCASYMFEAT:
++              dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__);
++              if (!crypto_userasymcrypto) {
++                      /*
++                       * NB: if user asym crypto operations are
++                       * not permitted return "no algorithms"
++                       * so well-behaved applications will just
++                       * fallback to doing them in software.
++                       */
++                      feat = 0;
++              } else
++                      error = crypto_getfeat(&feat);
++              if (!error) {
++                error = copy_to_user((void*)arg, &feat, sizeof(feat));
++              }
++              break;
++      case CIOCFINDDEV:
++              if (copy_from_user(&fop, (void*)arg, sizeof(fop))) {
++                      dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              error = cryptodev_find(&fop);
++              if (copy_to_user((void*)arg, &fop, sizeof(fop))) {
++                      dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      default:
++              dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd);
++              error = EINVAL;
++              break;
++      }
++      return(-error);
++}
++
++#ifdef HAVE_UNLOCKED_IOCTL
++static long
++cryptodev_unlocked_ioctl(
++      struct file *filp,
++      unsigned int cmd,
++      unsigned long arg)
++{
++      return cryptodev_ioctl(NULL, filp, cmd, arg);
++}
++#endif
++
++static int
++cryptodev_open(struct inode *inode, struct file *filp)
++{
++      struct fcrypt *fcr;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (filp->private_data) {
++              printk("cryptodev: Private data already exists !\n");
++              return(0);
++      }
++
++      fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
++      if (!fcr) {
++              dprintk("%s() - malloc failed\n", __FUNCTION__);
++              return(-ENOMEM);
++      }
++      memset(fcr, 0, sizeof(*fcr));
++
++      INIT_LIST_HEAD(&fcr->csessions);
++      filp->private_data = fcr;
++      return(0);
++}
++
++static int
++cryptodev_release(struct inode *inode, struct file *filp)
++{
++      struct fcrypt *fcr = filp->private_data;
++      struct csession *cse, *tmp;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (!filp) {
++              printk("cryptodev: No private data on release\n");
++              return(0);
++      }
++
++      list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) {
++              list_del(&cse->list);
++              (void)csefree(cse);
++      }
++      filp->private_data = NULL;
++      kfree(fcr);
++      return(0);
++}
++
++static struct file_operations cryptodev_fops = {
++      .owner = THIS_MODULE,
++      .open = cryptodev_open,
++      .release = cryptodev_release,
++      .ioctl = cryptodev_ioctl,
++#ifdef HAVE_UNLOCKED_IOCTL
++      .unlocked_ioctl = cryptodev_unlocked_ioctl,
++#endif
++};
++
++static struct miscdevice cryptodev = {
++      .minor = CRYPTODEV_MINOR,
++      .name = "crypto",
++      .fops = &cryptodev_fops,
++};
++
++static int __init
++cryptodev_init(void)
++{
++      int rc;
++
++      dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init);
++      rc = misc_register(&cryptodev);
++      if (rc) {
++              printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n");
++              return(rc);
++      }
++
++      return(0);
++}
++
++static void __exit
++cryptodev_exit(void)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      misc_deregister(&cryptodev);
++}
++
++module_init(cryptodev_init);
++module_exit(cryptodev_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("Cryptodev (user interface to OCF)");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/cryptodev.h       2007-09-26 22:15:05.000000000 +1000
+@@ -0,0 +1,478 @@
++/*    $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $   */
++/*    $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $     */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef _CRYPTO_CRYPTO_H_
++#define _CRYPTO_CRYPTO_H_
++
++/* Some initial values */
++#define CRYPTO_DRIVERS_INITIAL        4
++#define CRYPTO_SW_SESSIONS    32
++
++/* Hash values */
++#define NULL_HASH_LEN         0
++#define MD5_HASH_LEN          16
++#define SHA1_HASH_LEN         20
++#define RIPEMD160_HASH_LEN    20
++#define SHA2_256_HASH_LEN     32
++#define SHA2_384_HASH_LEN     48
++#define SHA2_512_HASH_LEN     64
++#define MD5_KPDK_HASH_LEN     16
++#define SHA1_KPDK_HASH_LEN    20
++/* Maximum hash algorithm result length */
++#define HASH_MAX_LEN          SHA2_512_HASH_LEN /* Keep this updated */
++
++/* HMAC values */
++#define NULL_HMAC_BLOCK_LEN                   1
++#define MD5_HMAC_BLOCK_LEN                    64
++#define SHA1_HMAC_BLOCK_LEN                   64
++#define RIPEMD160_HMAC_BLOCK_LEN      64
++#define SHA2_256_HMAC_BLOCK_LEN               64
++#define SHA2_384_HMAC_BLOCK_LEN               128
++#define SHA2_512_HMAC_BLOCK_LEN               128
++/* Maximum HMAC block length */
++#define HMAC_MAX_BLOCK_LEN            SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
++#define HMAC_IPAD_VAL                 0x36
++#define HMAC_OPAD_VAL                 0x5C
++
++/* Encryption algorithm block sizes */
++#define NULL_BLOCK_LEN                        1
++#define DES_BLOCK_LEN                 8
++#define DES3_BLOCK_LEN                        8
++#define BLOWFISH_BLOCK_LEN            8
++#define SKIPJACK_BLOCK_LEN            8
++#define CAST128_BLOCK_LEN             8
++#define RIJNDAEL128_BLOCK_LEN 16
++#define AES_BLOCK_LEN                 RIJNDAEL128_BLOCK_LEN
++#define CAMELLIA_BLOCK_LEN            16
++#define ARC4_BLOCK_LEN                        1
++#define EALG_MAX_BLOCK_LEN            AES_BLOCK_LEN /* Keep this updated */
++
++/* Encryption algorithm min and max key sizes */
++#define NULL_MIN_KEY_LEN              0
++#define NULL_MAX_KEY_LEN              0
++#define DES_MIN_KEY_LEN                       8
++#define DES_MAX_KEY_LEN                       8
++#define DES3_MIN_KEY_LEN              24
++#define DES3_MAX_KEY_LEN              24
++#define BLOWFISH_MIN_KEY_LEN  4
++#define BLOWFISH_MAX_KEY_LEN  56
++#define SKIPJACK_MIN_KEY_LEN  10
++#define SKIPJACK_MAX_KEY_LEN  10
++#define CAST128_MIN_KEY_LEN           5
++#define CAST128_MAX_KEY_LEN           16
++#define RIJNDAEL128_MIN_KEY_LEN       16
++#define RIJNDAEL128_MAX_KEY_LEN       32
++#define AES_MIN_KEY_LEN                       RIJNDAEL128_MIN_KEY_LEN
++#define AES_MAX_KEY_LEN                       RIJNDAEL128_MAX_KEY_LEN
++#define CAMELLIA_MIN_KEY_LEN  16
++#define CAMELLIA_MAX_KEY_LEN  32
++#define ARC4_MIN_KEY_LEN              1
++#define ARC4_MAX_KEY_LEN              256
++
++/* Max size of data that can be processed */
++#define CRYPTO_MAX_DATA_LEN           64*1024 - 1
++
++#define CRYPTO_ALGORITHM_MIN  1
++#define CRYPTO_DES_CBC                        1
++#define CRYPTO_3DES_CBC                       2
++#define CRYPTO_BLF_CBC                        3
++#define CRYPTO_CAST_CBC                       4
++#define CRYPTO_SKIPJACK_CBC           5
++#define CRYPTO_MD5_HMAC                       6
++#define CRYPTO_SHA1_HMAC              7
++#define CRYPTO_RIPEMD160_HMAC 8
++#define CRYPTO_MD5_KPDK                       9
++#define CRYPTO_SHA1_KPDK              10
++#define CRYPTO_RIJNDAEL128_CBC        11 /* 128 bit blocksize */
++#define CRYPTO_AES_CBC                        11 /* 128 bit blocksize -- the same as above */
++#define CRYPTO_ARC4                           12
++#define CRYPTO_MD5                            13
++#define CRYPTO_SHA1                           14
++#define CRYPTO_NULL_HMAC              15
++#define CRYPTO_NULL_CBC                       16
++#define CRYPTO_DEFLATE_COMP           17 /* Deflate compression algorithm */
++#define CRYPTO_SHA2_256_HMAC  18
++#define CRYPTO_SHA2_384_HMAC  19
++#define CRYPTO_SHA2_512_HMAC  20
++#define CRYPTO_CAMELLIA_CBC           21
++#define CRYPTO_SHA2_256                       22
++#define CRYPTO_SHA2_384                       23
++#define CRYPTO_SHA2_512                       24
++#define CRYPTO_RIPEMD160              25
++#define CRYPTO_ALGORITHM_MAX  25 /* Keep updated - see below */
++
++/* Algorithm flags */
++#define CRYPTO_ALG_FLAG_SUPPORTED     0x01 /* Algorithm is supported */
++#define CRYPTO_ALG_FLAG_RNG_ENABLE    0x02 /* Has HW RNG for DH/DSA */
++#define CRYPTO_ALG_FLAG_DSA_SHA               0x04 /* Can do SHA on msg */
++
++/*
++ * Crypto driver/device flags.  They can set in the crid
++ * parameter when creating a session or submitting a key
++ * op to affect the device/driver assigned.  If neither
++ * of these are specified then the crid is assumed to hold
++ * the driver id of an existing (and suitable) device that
++ * must be used to satisfy the request.
++ */
++#define CRYPTO_FLAG_HARDWARE  0x01000000      /* hardware accelerated */
++#define CRYPTO_FLAG_SOFTWARE  0x02000000      /* software implementation */
++
++/* NB: deprecated */
++struct session_op {
++      u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
++      u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
++
++      u_int32_t       keylen;         /* cipher key */
++      caddr_t         key;
++      int             mackeylen;      /* mac key */
++      caddr_t         mackey;
++
++      u_int32_t       ses;            /* returns: session # */ 
++};
++
++struct session2_op {
++      u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
++      u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
++
++      u_int32_t       keylen;         /* cipher key */
++      caddr_t         key;
++      int             mackeylen;      /* mac key */
++      caddr_t         mackey;
++
++      u_int32_t       ses;            /* returns: session # */ 
++      int             crid;           /* driver id + flags (rw) */
++      int             pad[4];         /* for future expansion */
++};
++
++struct crypt_op {
++      u_int32_t       ses;
++      u_int16_t       op;             /* i.e. COP_ENCRYPT */
++#define COP_NONE      0
++#define COP_ENCRYPT   1
++#define COP_DECRYPT   2
++      u_int16_t       flags;
++#define       COP_F_BATCH     0x0008          /* Batch op if possible */
++      u_int           len;
++      caddr_t         src, dst;       /* become iov[] inside kernel */
++      caddr_t         mac;            /* must be big enough for chosen MAC */
++      caddr_t         iv;
++};
++
++/*
++ * Parameters for looking up a crypto driver/device by
++ * device name or by id.  The latter are returned for
++ * created sessions (crid) and completed key operations.
++ */
++struct crypt_find_op {
++      int             crid;           /* driver id + flags */
++      char            name[32];       /* device/driver name */
++};
++
++/* bignum parameter, in packed bytes, ... */
++struct crparam {
++      caddr_t         crp_p;
++      u_int           crp_nbits;
++};
++
++#define CRK_MAXPARAM  8
++
++struct crypt_kop {
++      u_int           crk_op;         /* ie. CRK_MOD_EXP or other */
++      u_int           crk_status;     /* return status */
++      u_short         crk_iparams;    /* # of input parameters */
++      u_short         crk_oparams;    /* # of output parameters */
++      u_int           crk_crid;       /* NB: only used by CIOCKEY2 (rw) */
++      struct crparam  crk_param[CRK_MAXPARAM];
++};
++#define CRK_ALGORITM_MIN      0
++#define CRK_MOD_EXP           0
++#define CRK_MOD_EXP_CRT               1
++#define CRK_DSA_SIGN          2
++#define CRK_DSA_VERIFY                3
++#define CRK_DH_COMPUTE_KEY    4
++#define CRK_ALGORITHM_MAX     4 /* Keep updated - see below */
++
++#define CRF_MOD_EXP           (1 << CRK_MOD_EXP)
++#define CRF_MOD_EXP_CRT               (1 << CRK_MOD_EXP_CRT)
++#define CRF_DSA_SIGN          (1 << CRK_DSA_SIGN)
++#define CRF_DSA_VERIFY                (1 << CRK_DSA_VERIFY)
++#define CRF_DH_COMPUTE_KEY    (1 << CRK_DH_COMPUTE_KEY)
++
++/*
++ * done against open of /dev/crypto, to get a cloned descriptor.
++ * Please use F_SETFD against the cloned descriptor.
++ */
++#define CRIOGET               _IOWR('c', 100, u_int32_t)
++#define CRIOASYMFEAT  CIOCASYMFEAT
++#define CRIOFINDDEV   CIOCFINDDEV
++
++/* the following are done against the cloned descriptor */
++#define CIOCGSESSION  _IOWR('c', 101, struct session_op)
++#define CIOCFSESSION  _IOW('c', 102, u_int32_t)
++#define CIOCCRYPT     _IOWR('c', 103, struct crypt_op)
++#define CIOCKEY               _IOWR('c', 104, struct crypt_kop)
++#define CIOCASYMFEAT  _IOR('c', 105, u_int32_t)
++#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op)
++#define CIOCKEY2      _IOWR('c', 107, struct crypt_kop)
++#define CIOCFINDDEV   _IOWR('c', 108, struct crypt_find_op)
++
++struct cryptotstat {
++      struct timespec acc;            /* total accumulated time */
++      struct timespec min;            /* min time */
++      struct timespec max;            /* max time */
++      u_int32_t       count;          /* number of observations */
++};
++
++struct cryptostats {
++      u_int32_t       cs_ops;         /* symmetric crypto ops submitted */
++      u_int32_t       cs_errs;        /* symmetric crypto ops that failed */
++      u_int32_t       cs_kops;        /* asymetric/key ops submitted */
++      u_int32_t       cs_kerrs;       /* asymetric/key ops that failed */
++      u_int32_t       cs_intrs;       /* crypto swi thread activations */
++      u_int32_t       cs_rets;        /* crypto return thread activations */
++      u_int32_t       cs_blocks;      /* symmetric op driver block */
++      u_int32_t       cs_kblocks;     /* symmetric op driver block */
++      /*
++       * When CRYPTO_TIMING is defined at compile time and the
++       * sysctl debug.crypto is set to 1, the crypto system will
++       * accumulate statistics about how long it takes to process
++       * crypto requests at various points during processing.
++       */
++      struct cryptotstat cs_invoke;   /* crypto_dipsatch -> crypto_invoke */
++      struct cryptotstat cs_done;     /* crypto_invoke -> crypto_done */
++      struct cryptotstat cs_cb;       /* crypto_done -> callback */
++      struct cryptotstat cs_finis;    /* callback -> callback return */
++
++      u_int32_t       cs_drops;               /* crypto ops dropped due to congestion */
++};
++
++#ifdef __KERNEL__
++
++/* Standard initialization structure beginning */
++struct cryptoini {
++      int             cri_alg;        /* Algorithm to use */
++      int             cri_klen;       /* Key length, in bits */
++      int             cri_mlen;       /* Number of bytes we want from the
++                                         entire hash. 0 means all. */
++      caddr_t         cri_key;        /* key to use */
++      u_int8_t        cri_iv[EALG_MAX_BLOCK_LEN];     /* IV to use */
++      struct cryptoini *cri_next;
++};
++
++/* Describe boundaries of a single crypto operation */
++struct cryptodesc {
++      int             crd_skip;       /* How many bytes to ignore from start */
++      int             crd_len;        /* How many bytes to process */
++      int             crd_inject;     /* Where to inject results, if applicable */
++      int             crd_flags;
++
++#define CRD_F_ENCRYPT         0x01    /* Set when doing encryption */
++#define CRD_F_IV_PRESENT      0x02    /* When encrypting, IV is already in
++                                         place, so don't copy. */
++#define CRD_F_IV_EXPLICIT     0x04    /* IV explicitly provided */
++#define CRD_F_DSA_SHA_NEEDED  0x08    /* Compute SHA-1 of buffer for DSA */
++#define CRD_F_KEY_EXPLICIT    0x10    /* Key explicitly provided */
++#define CRD_F_COMP            0x0f    /* Set when doing compression */
++
++      struct cryptoini        CRD_INI; /* Initialization/context data */
++#define crd_iv                CRD_INI.cri_iv
++#define crd_key               CRD_INI.cri_key
++#define crd_alg               CRD_INI.cri_alg
++#define crd_klen      CRD_INI.cri_klen
++
++      struct cryptodesc *crd_next;
++};
++
++/* Structure describing complete operation */
++struct cryptop {
++      struct list_head crp_next;
++      wait_queue_head_t crp_waitq;
++
++      u_int64_t       crp_sid;        /* Session ID */
++      int             crp_ilen;       /* Input data total length */
++      int             crp_olen;       /* Result total length */
++
++      int             crp_etype;      /*
++                                       * Error type (zero means no error).
++                                       * All error codes except EAGAIN
++                                       * indicate possible data corruption (as in,
++                                       * the data have been touched). On all
++                                       * errors, the crp_sid may have changed
++                                       * (reset to a new one), so the caller
++                                       * should always check and use the new
++                                       * value on future requests.
++                                       */
++      int             crp_flags;
++
++#define CRYPTO_F_SKBUF                0x0001  /* Input/output are skbuf chains */
++#define CRYPTO_F_IOV          0x0002  /* Input/output are uio */
++#define CRYPTO_F_REL          0x0004  /* Must return data in same place */
++#define CRYPTO_F_BATCH                0x0008  /* Batch op if possible */
++#define CRYPTO_F_CBIMM                0x0010  /* Do callback immediately */
++#define CRYPTO_F_DONE         0x0020  /* Operation completed */
++#define CRYPTO_F_CBIFSYNC     0x0040  /* Do CBIMM if op is synchronous */
++
++      caddr_t         crp_buf;        /* Data to be processed */
++      caddr_t         crp_opaque;     /* Opaque pointer, passed along */
++      struct cryptodesc *crp_desc;    /* Linked list of processing descriptors */
++
++      int (*crp_callback)(struct cryptop *); /* Callback function */
++};
++
++#define CRYPTO_BUF_CONTIG     0x0
++#define CRYPTO_BUF_IOV                0x1
++#define CRYPTO_BUF_SKBUF              0x2
++
++#define CRYPTO_OP_DECRYPT     0x0
++#define CRYPTO_OP_ENCRYPT     0x1
++
++/*
++ * Hints passed to process methods.
++ */
++#define CRYPTO_HINT_MORE      0x1     /* more ops coming shortly */
++
++struct cryptkop {
++      struct list_head krp_next;
++      wait_queue_head_t krp_waitq;
++
++      int             krp_flags;
++#define CRYPTO_KF_DONE                0x0001  /* Operation completed */
++#define CRYPTO_KF_CBIMM               0x0002  /* Do callback immediately */
++
++      u_int           krp_op;         /* ie. CRK_MOD_EXP or other */
++      u_int           krp_status;     /* return status */
++      u_short         krp_iparams;    /* # of input parameters */
++      u_short         krp_oparams;    /* # of output parameters */
++      u_int           krp_crid;       /* desired device, etc. */
++      u_int32_t       krp_hid;
++      struct crparam  krp_param[CRK_MAXPARAM];        /* kvm */
++      int             (*krp_callback)(struct cryptkop *);
++};
++
++#include <ocf-compat.h>
++
++/*
++ * Session ids are 64 bits.  The lower 32 bits contain a "local id" which
++ * is a driver-private session identifier.  The upper 32 bits contain a
++ * "hardware id" used by the core crypto code to identify the driver and
++ * a copy of the driver's capabilities that can be used by client code to
++ * optimize operation.
++ */
++#define CRYPTO_SESID2HID(_sid)        (((_sid) >> 32) & 0x00ffffff)
++#define CRYPTO_SESID2CAPS(_sid)       (((_sid) >> 32) & 0xff000000)
++#define CRYPTO_SESID2LID(_sid)        (((u_int32_t) (_sid)) & 0xffffffff)
++
++extern        int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
++extern        int crypto_freesession(u_int64_t sid);
++#define CRYPTOCAP_F_HARDWARE  CRYPTO_FLAG_HARDWARE
++#define CRYPTOCAP_F_SOFTWARE  CRYPTO_FLAG_SOFTWARE
++#define CRYPTOCAP_F_SYNC      0x04000000      /* operates synchronously */
++extern        int32_t crypto_get_driverid(device_t dev, int flags);
++extern        int crypto_find_driver(const char *);
++extern        device_t crypto_find_device_byhid(int hid);
++extern        int crypto_getcaps(int hid);
++extern        int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++          u_int32_t flags);
++extern        int crypto_kregister(u_int32_t, int, u_int32_t);
++extern        int crypto_unregister(u_int32_t driverid, int alg);
++extern        int crypto_unregister_all(u_int32_t driverid);
++extern        int crypto_dispatch(struct cryptop *crp);
++extern        int crypto_kdispatch(struct cryptkop *);
++#define CRYPTO_SYMQ   0x1
++#define CRYPTO_ASYMQ  0x2
++extern        int crypto_unblock(u_int32_t, int);
++extern        void crypto_done(struct cryptop *crp);
++extern        void crypto_kdone(struct cryptkop *);
++extern        int crypto_getfeat(int *);
++
++extern        void crypto_freereq(struct cryptop *crp);
++extern        struct cryptop *crypto_getreq(int num);
++
++extern  int crypto_usercrypto;      /* userland may do crypto requests */
++extern  int crypto_userasymcrypto;  /* userland may do asym crypto reqs */
++extern  int crypto_devallowsoft;    /* only use hardware crypto */
++
++/*
++ * random number support,  crypto_unregister_all will unregister
++ */
++extern int crypto_rregister(u_int32_t driverid,
++              int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
++extern int crypto_runregister_all(u_int32_t driverid);
++
++/*
++ * Crypto-related utility routines used mainly by drivers.
++ *
++ * XXX these don't really belong here; but for now they're
++ *     kept apart from the rest of the system.
++ */
++struct uio;
++extern        void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
++extern        void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
++extern        struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
++
++extern        void crypto_copyback(int flags, caddr_t buf, int off, int size,
++          caddr_t in);
++extern        void crypto_copydata(int flags, caddr_t buf, int off, int size,
++          caddr_t out);
++extern        int crypto_apply(int flags, caddr_t buf, int off, int len,
++          int (*f)(void *, void *, u_int), void *arg);
++
++#endif /* __KERNEL__ */
++#endif /* _CRYPTO_CRYPTO_H_ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ocfnull/ocfnull.c 2007-07-13 16:02:05.000000000 +1000
+@@ -0,0 +1,203 @@
++/*
++ * An OCF module for determining the cost of crypto versus the cost of
++ * IPSec processing outside of OCF.  This modules gives us the effect of
++ * zero cost encryption,  of course you will need to run it at both ends
++ * since it does no crypto at all.
++ *
++ * Written by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough 
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++static int32_t                         null_id = -1;
++static u_int32_t               null_sesnum = 0;
++
++static int null_process(device_t, struct cryptop *, int);
++static int null_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int null_freesession(device_t, u_int64_t);
++
++#define debug ocfnull_debug
++int ocfnull_debug = 0;
++module_param(ocfnull_debug, int, 0644);
++MODULE_PARM_DESC(ocfnull_debug, "Enable debug");
++
++/*
++ * dummy device structure
++ */
++
++static struct {
++      softc_device_decl       sc_dev;
++} nulldev;
++
++static device_method_t null_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, null_newsession),
++      DEVMETHOD(cryptodev_freesession,null_freesession),
++      DEVMETHOD(cryptodev_process,    null_process),
++};
++
++/*
++ * Generate a new software session.
++ */
++static int
++null_newsession(device_t arg, u_int32_t *sid, struct cryptoini *cri)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid == NULL || cri == NULL) {
++              dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      if (null_sesnum == 0)
++              null_sesnum++;
++      *sid = null_sesnum++;
++      return 0;
++}
++
++
++/*
++ * Free a session.
++ */
++static int
++null_freesession(device_t arg, u_int64_t tid)
++{
++      u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid > null_sesnum) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      /* Silently accept and return */
++      if (sid == 0)
++              return 0;
++      return 0;
++}
++
++
++/*
++ * Process a request.
++ */
++static int
++null_process(device_t arg, struct cryptop *crp, int hint)
++{
++      unsigned int lid;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      /* Sanity check */
++      if (crp == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      crp->crp_etype = 0;
++
++      if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              crp->crp_etype = EINVAL;
++              goto done;
++      }
++
++      /*
++       * find the session we are using
++       */
++
++      lid = crp->crp_sid & 0xffffffff;
++      if (lid >= null_sesnum || lid == 0) {
++              crp->crp_etype = ENOENT;
++              dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++              goto done;
++      }
++
++done:
++      crypto_done(crp);
++      return 0;
++}
++
++
++/*
++ * our driver startup and shutdown routines
++ */
++
++static int
++null_init(void)
++{
++      dprintk("%s(%p)\n", __FUNCTION__, null_init);
++
++      memset(&nulldev, 0, sizeof(nulldev));
++      softc_device_init(&nulldev, "ocfnull", 0, null_methods);
++
++      null_id = crypto_get_driverid(softc_get_device(&nulldev),
++                              CRYPTOCAP_F_HARDWARE);
++      if (null_id < 0)
++              panic("ocfnull: crypto device cannot initialize!");
++
++#define       REGISTER(alg) \
++      crypto_register(null_id,alg,0,0)
++      REGISTER(CRYPTO_DES_CBC);
++      REGISTER(CRYPTO_3DES_CBC);
++      REGISTER(CRYPTO_RIJNDAEL128_CBC);
++      REGISTER(CRYPTO_MD5);
++      REGISTER(CRYPTO_SHA1);
++      REGISTER(CRYPTO_MD5_HMAC);
++      REGISTER(CRYPTO_SHA1_HMAC);
++#undef REGISTER
++
++      return 0;
++}
++
++static void
++null_exit(void)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      crypto_unregister_all(null_id);
++      null_id = -1;
++}
++
++module_init(null_init);
++module_exit(null_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("ocfnull - claims a lot but does nothing");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/cryptosoft.c      2008-02-14 14:59:01.000000000 +1000
+@@ -0,0 +1,898 @@
++/*
++ * An OCF module that uses the linux kernel cryptoapi, based on the
++ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * but is mostly unrecognisable,
++ *
++ * Written by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2004-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <asm/scatterlist.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++struct {
++      softc_device_decl       sc_dev;
++} swcr_softc;
++
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++/* Software session entry */
++
++#define SW_TYPE_CIPHER                0
++#define SW_TYPE_HMAC          1
++#define SW_TYPE_AUTH2         2
++#define SW_TYPE_HASH          3
++#define SW_TYPE_COMP          4
++#define SW_TYPE_BLKCIPHER     5
++
++struct swcr_data {
++      int                                     sw_type;
++      int                                     sw_alg;
++      struct crypto_tfm       *sw_tfm;
++      union {
++              struct {
++                      char *sw_key;
++                      int  sw_klen;
++                      int  sw_mlen;
++              } hmac;
++              void *sw_comp_buf;
++      } u;
++      struct swcr_data        *sw_next;
++};
++
++#ifndef CRYPTO_TFM_MODE_CBC
++/*
++ * As of linux-2.6.21 this is no longer defined, and presumably no longer
++ * needed to be passed into the crypto core code.
++ */
++#define       CRYPTO_TFM_MODE_CBC     0
++#define       CRYPTO_TFM_MODE_ECB     0
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++      /*
++       * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
++       * API into old API.
++       */
++
++      /* Symmetric/Block Cipher */
++      struct blkcipher_desc
++      {
++              struct crypto_tfm *tfm;
++              void *info;
++      };
++      #define ecb(X)                                                          #X
++      #define cbc(X)                                                          #X
++      #define crypto_has_blkcipher(X, Y, Z)           crypto_alg_available(X, 0)
++      #define crypto_blkcipher_cast(X)                        X
++      #define crypto_blkcipher_tfm(X)                         X
++      #define crypto_alloc_blkcipher(X, Y, Z)         crypto_alloc_tfm(X, mode)
++      #define crypto_blkcipher_ivsize(X)                      crypto_tfm_alg_ivsize(X)
++      #define crypto_blkcipher_blocksize(X)           crypto_tfm_alg_blocksize(X)
++      #define crypto_blkcipher_setkey(X, Y, Z)        crypto_cipher_setkey(X, Y, Z)
++      #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++      #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++
++      /* Hash/HMAC/Digest */
++      struct hash_desc
++      {
++              struct crypto_tfm *tfm;
++      };
++      #define hmac(X)                                                 #X
++      #define crypto_has_hash(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_hash_cast(X)                             X
++      #define crypto_hash_tfm(X)                              X
++      #define crypto_alloc_hash(X, Y, Z)              crypto_alloc_tfm(X, mode)
++      #define crypto_hash_digestsize(X)               crypto_tfm_alg_digestsize(X)
++      #define crypto_hash_digest(W, X, Y, Z)  \
++                              crypto_digest_digest((W)->tfm, X, sg_num, Z)
++
++      /* Asymmetric Cipher */
++      #define crypto_has_cipher(X, Y, Z)              crypto_alg_available(X, 0)
++
++      /* Compression */
++      #define crypto_has_comp(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_comp_tfm(X)                              X
++      #define crypto_comp_cast(X)                             X
++      #define crypto_alloc_comp(X, Y, Z)              crypto_alloc_tfm(X, mode)
++#else
++      #define ecb(X)  "ecb(" #X ")"
++      #define cbc(X)  "cbc(" #X ")"
++      #define hmac(X) "hmac(" #X ")"
++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++struct crypto_details
++{
++      char *alg_name;
++      int mode;
++      int sw_type;
++};
++
++/*
++ * This needs to be kept updated with CRYPTO_xxx list (cryptodev.h).
++ * If the Algorithm is not supported, then insert a {NULL, 0, 0} entry.
++ *
++ * IMPORTANT: The index to the array IS CRYPTO_xxx.
++ */
++static struct crypto_details crypto_details[CRYPTO_ALGORITHM_MAX + 1] = {
++      { NULL,              0,                   0 },
++      /* CRYPTO_xxx index starts at 1 */
++      { cbc(des),          CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { cbc(des3_ede),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { cbc(blowfish),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { cbc(cast5),        CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { cbc(skipjack),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { hmac(md5),         0,                   SW_TYPE_HMAC },
++      { hmac(sha1),        0,                   SW_TYPE_HMAC },
++      { hmac(ripemd160),   0,                   SW_TYPE_HMAC },
++      { "md5-kpdk??",      0,                   SW_TYPE_HASH },
++      { "sha1-kpdk??",     0,                   SW_TYPE_HASH },
++      { cbc(aes),          CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { ecb(arc4),         CRYPTO_TFM_MODE_ECB, SW_TYPE_BLKCIPHER },
++      { "md5",             0,                   SW_TYPE_HASH },
++      { "sha1",            0,                   SW_TYPE_HASH },
++      { hmac(digest_null), 0,                   SW_TYPE_HMAC },
++      { cbc(cipher_null),  CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { "deflate",         0,                   SW_TYPE_COMP },
++      { hmac(sha256),      0,                   SW_TYPE_HMAC },
++      { hmac(sha384),      0,                   SW_TYPE_HMAC },
++      { hmac(sha512),      0,                   SW_TYPE_HMAC },
++      { cbc(camellia),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
++      { "sha256",          0,                   SW_TYPE_HASH },
++      { "sha384",          0,                   SW_TYPE_HASH },
++      { "sha512",          0,                   SW_TYPE_HASH },
++      { "ripemd160",       0,                   SW_TYPE_HASH },
++};
++
++int32_t swcr_id = -1;
++module_param(swcr_id, int, 0444);
++MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
++
++int swcr_fail_if_compression_grows = 1;
++module_param(swcr_fail_if_compression_grows, int, 0644);
++MODULE_PARM_DESC(swcr_fail_if_compression_grows,
++                "Treat compression that results in more data as a failure");
++
++static struct swcr_data **swcr_sessions = NULL;
++static u_int32_t swcr_sesnum = 0;
++
++static        int swcr_process(device_t, struct cryptop *, int);
++static        int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
++static        int swcr_freesession(device_t, u_int64_t);
++
++static device_method_t swcr_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, swcr_newsession),
++      DEVMETHOD(cryptodev_freesession,swcr_freesession),
++      DEVMETHOD(cryptodev_process,    swcr_process),
++};
++
++#define debug swcr_debug
++int swcr_debug = 0;
++module_param(swcr_debug, int, 0644);
++MODULE_PARM_DESC(swcr_debug, "Enable debug");
++
++/*
++ * Generate a new software session.
++ */
++static int
++swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++      struct swcr_data **swd;
++      u_int32_t i;
++      int error;
++      char *algo;
++      int mode, sw_type;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid == NULL || cri == NULL) {
++              dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      if (swcr_sessions) {
++              for (i = 1; i < swcr_sesnum; i++)
++                      if (swcr_sessions[i] == NULL)
++                              break;
++      } else
++              i = 1;          /* NB: to silence compiler warning */
++
++      if (swcr_sessions == NULL || i == swcr_sesnum) {
++              if (swcr_sessions == NULL) {
++                      i = 1; /* We leave swcr_sessions[0] empty */
++                      swcr_sesnum = CRYPTO_SW_SESSIONS;
++              } else
++                      swcr_sesnum *= 2;
++
++              swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
++              if (swd == NULL) {
++                      /* Reset session number */
++                      if (swcr_sesnum == CRYPTO_SW_SESSIONS)
++                              swcr_sesnum = 0;
++                      else
++                              swcr_sesnum /= 2;
++                      dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                      return ENOBUFS;
++              }
++              memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
++
++              /* Copy existing sessions */
++              if (swcr_sessions) {
++                      memcpy(swd, swcr_sessions,
++                          (swcr_sesnum / 2) * sizeof(struct swcr_data *));
++                      kfree(swcr_sessions);
++              }
++
++              swcr_sessions = swd;
++      }
++
++      swd = &swcr_sessions[i];
++      *sid = i;
++
++      while (cri) {
++              *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
++                              SLAB_ATOMIC);
++              if (*swd == NULL) {
++                      swcr_freesession(NULL, i);
++                      dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                      return ENOBUFS;
++              }
++              memset(*swd, 0, sizeof(struct swcr_data));
++
++              if (cri->cri_alg > CRYPTO_ALGORITHM_MAX) {
++                      printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              algo = crypto_details[cri->cri_alg].alg_name;
++              if (!algo || !*algo) {
++                      printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              mode = crypto_details[cri->cri_alg].mode;
++              sw_type = crypto_details[cri->cri_alg].sw_type;
++
++              /* Algorithm specific configuration */
++              switch (cri->cri_alg) {
++              case CRYPTO_NULL_CBC:
++                      cri->cri_klen = 0; /* make it work with crypto API */
++                      break;
++              default:
++                      break;
++              }
++
++              if (sw_type == SW_TYPE_BLKCIPHER) {
++                      dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__,
++                                      algo, mode);
++
++                      (*swd)->sw_tfm = crypto_blkcipher_tfm(
++                                                              crypto_alloc_blkcipher(algo, 0,
++                                                                      CRYPTO_ALG_ASYNC));
++                      if (!(*swd)->sw_tfm) {
++                              dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n",
++                                              algo,mode);
++                              swcr_freesession(NULL, i);
++                              return EINVAL;
++                      }
++
++                      if (debug) {
++                              dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
++                                              __FUNCTION__,cri->cri_klen,(cri->cri_klen + 7)/8);
++                              for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
++                              {
++                                      dprintk("%s0x%x", (i % 8) ? " " : "\n    ",cri->cri_key[i]);
++                              }
++                              dprintk("\n");
++                      }
++                      error = crypto_blkcipher_setkey(
++                                              crypto_blkcipher_cast((*swd)->sw_tfm), cri->cri_key,
++                                                      (cri->cri_klen + 7) / 8);
++                      if (error) {
++                              printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
++                                              (*swd)->sw_tfm->crt_flags);
++                              swcr_freesession(NULL, i);
++                              return error;
++                      }
++              } else if (sw_type == SW_TYPE_HMAC || sw_type == SW_TYPE_HASH) {
++                      dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__,
++                                      algo, mode);
++
++                      (*swd)->sw_tfm = crypto_hash_tfm(
++                                                              crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
++
++                      if (!(*swd)->sw_tfm) {
++                              dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
++                                              algo, mode);
++                              swcr_freesession(NULL, i);
++                              return EINVAL;
++                      }
++
++                      (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
++                      (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
++                              SLAB_ATOMIC);
++                      if ((*swd)->u.hmac.sw_key == NULL) {
++                              swcr_freesession(NULL, i);
++                              dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                              return ENOBUFS;
++                      }
++                      memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
++                      if (cri->cri_mlen) {
++                              (*swd)->u.hmac.sw_mlen = cri->cri_mlen;
++                      } else {
++                              (*swd)->u.hmac.sw_mlen =
++                                              crypto_hash_digestsize(
++                                                              crypto_hash_cast((*swd)->sw_tfm));
++                      }
++              } else if (sw_type == SW_TYPE_COMP) {
++                      (*swd)->sw_tfm = crypto_comp_tfm(
++                                      crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
++                      if (!(*swd)->sw_tfm) {
++                              dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
++                                              algo, mode);
++                              swcr_freesession(NULL, i);
++                              return EINVAL;
++                      }
++                      (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
++                      if ((*swd)->u.sw_comp_buf == NULL) {
++                              swcr_freesession(NULL, i);
++                              dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                              return ENOBUFS;
++                      }
++              } else {
++                      printk("cryptosoft: Unhandled sw_type %d\n", sw_type);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              (*swd)->sw_alg = cri->cri_alg;
++              (*swd)->sw_type = sw_type;
++
++              cri = cri->cri_next;
++              swd = &((*swd)->sw_next);
++      }
++      return 0;
++}
++
++/*
++ * Free a session.
++ */
++static int
++swcr_freesession(device_t dev, u_int64_t tid)
++{
++      struct swcr_data *swd;
++      u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid > swcr_sesnum || swcr_sessions == NULL ||
++                      swcr_sessions[sid] == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return(EINVAL);
++      }
++
++      /* Silently accept and return */
++      if (sid == 0)
++              return(0);
++
++      while ((swd = swcr_sessions[sid]) != NULL) {
++              swcr_sessions[sid] = swd->sw_next;
++              if (swd->sw_tfm)
++                      crypto_free_tfm(swd->sw_tfm);
++              if (swd->sw_type == SW_TYPE_COMP) {
++                      if (swd->u.sw_comp_buf)
++                              kfree(swd->u.sw_comp_buf);
++              } else {
++                      if (swd->u.hmac.sw_key)
++                              kfree(swd->u.hmac.sw_key);
++              }
++              kfree(swd);
++      }
++      return 0;
++}
++
++/*
++ * Process a software request.
++ */
++static int
++swcr_process(device_t dev, struct cryptop *crp, int hint)
++{
++      struct cryptodesc *crd;
++      struct swcr_data *sw;
++      u_int32_t lid;
++#define SCATTERLIST_MAX 16
++      struct scatterlist sg[SCATTERLIST_MAX];
++      int sg_num, sg_len, skip;
++      struct sk_buff *skb = NULL;
++      struct uio *uiop = NULL;
++
++      dprintk("%s()\n", __FUNCTION__);
++      /* Sanity check */
++      if (crp == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      crp->crp_etype = 0;
++
++      if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              crp->crp_etype = EINVAL;
++              goto done;
++      }
++
++      lid = crp->crp_sid & 0xffffffff;
++      if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||
++                      swcr_sessions[lid] == NULL) {
++              crp->crp_etype = ENOENT;
++              dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++              goto done;
++      }
++
++      /*
++       * do some error checking outside of the loop for SKB and IOV processing
++       * this leaves us with valid skb or uiop pointers for later
++       */
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              skb = (struct sk_buff *) crp->crp_buf;
++              if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
++                      printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
++                                      skb_shinfo(skb)->nr_frags);
++                      goto done;
++              }
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              uiop = (struct uio *) crp->crp_buf;
++              if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
++                      printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
++                                      uiop->uio_iovcnt);
++                      goto done;
++              }
++      }
++
++      /* Go through crypto descriptors, processing as we go */
++      for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++              /*
++               * Find the crypto context.
++               *
++               * XXX Note that the logic here prevents us from having
++               * XXX the same algorithm multiple times in a session
++               * XXX (or rather, we can but it won't give us the right
++               * XXX results). To do that, we'd need some way of differentiating
++               * XXX between the various instances of an algorithm (so we can
++               * XXX locate the correct crypto context).
++               */
++              for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg;
++                              sw = sw->sw_next)
++                      ;
++
++              /* No such context ? */
++              if (sw == NULL) {
++                      crp->crp_etype = EINVAL;
++                      dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++                      goto done;
++              }
++
++              skip = crd->crd_skip;
++
++              /*
++               * setup the SG list skip from the start of the buffer
++               */
++              memset(sg, 0, sizeof(sg));
++              if (crp->crp_flags & CRYPTO_F_SKBUF) {
++                      int i, len;
++
++                      sg_num = 0;
++                      sg_len = 0;
++
++                      if (skip < skb_headlen(skb)) {
++                              len = skb_headlen(skb) - skip;
++                              if (len + sg_len > crd->crd_len)
++                                      len = crd->crd_len - sg_len;
++                              sg_set_page(&sg[sg_num],
++                                      virt_to_page(skb->data + skip), len,
++                                      offset_in_page(skb->data + skip));
++                              sg_len += len;
++                              sg_num++;
++                              skip = 0;
++                      } else
++                              skip -= skb_headlen(skb);
++
++                      for (i = 0; sg_len < crd->crd_len &&
++                                              i < skb_shinfo(skb)->nr_frags &&
++                                              sg_num < SCATTERLIST_MAX; i++) {
++                              if (skip < skb_shinfo(skb)->frags[i].size) {
++                                      len = skb_shinfo(skb)->frags[i].size - skip;
++                                      if (len + sg_len > crd->crd_len)
++                                              len = crd->crd_len - sg_len;
++                                      sg_set_page(&sg[sg_num],
++                                              skb_shinfo(skb)->frags[i].page,
++                                              len,
++                                              skb_shinfo(skb)->frags[i].page_offset + skip);
++                                      sg_len += len;
++                                      sg_num++;
++                                      skip = 0;
++                              } else
++                                      skip -= skb_shinfo(skb)->frags[i].size;
++                      }
++              } else if (crp->crp_flags & CRYPTO_F_IOV) {
++                      int len;
++
++                      sg_len = 0;
++                      for (sg_num = 0; sg_len <= crd->crd_len &&
++                                      sg_num < uiop->uio_iovcnt &&
++                                      sg_num < SCATTERLIST_MAX; sg_num++) {
++                              if (skip <= uiop->uio_iov[sg_num].iov_len) {
++                                      len = uiop->uio_iov[sg_num].iov_len - skip;
++                                      if (len + sg_len > crd->crd_len)
++                                              len = crd->crd_len - sg_len;
++                                      sg_set_page(&sg[sg_num],
++                                              virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
++                                              len,
++                                              offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
++                                      sg_len += len;
++                                      skip = 0;
++                              } else 
++                                      skip -= uiop->uio_iov[sg_num].iov_len;
++                      }
++              } else {
++                      sg_len = (crp->crp_ilen - skip);
++                      if (sg_len > crd->crd_len)
++                              sg_len = crd->crd_len;
++                      sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip),
++                              sg_len, offset_in_page(crp->crp_buf + skip));
++                      sg_num = 1;
++              }
++
++
++              switch (sw->sw_type) {
++              case SW_TYPE_BLKCIPHER: {
++                      unsigned char iv[EALG_MAX_BLOCK_LEN];
++                      unsigned char *ivp = iv;
++                      int ivsize = 
++                              crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
++                      struct blkcipher_desc desc;
++
++                      if (sg_len < crypto_blkcipher_blocksize(
++                                      crypto_blkcipher_cast(sw->sw_tfm))) {
++                              crp->crp_etype = EINVAL;
++                              dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
++                                              sg_len, crypto_blkcipher_blocksize(
++                                                      crypto_blkcipher_cast(sw->sw_tfm)));
++                              goto done;
++                      }
++
++                      if (ivsize > sizeof(iv)) {
++                              crp->crp_etype = EINVAL;
++                              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++                              goto done;
++                      }
++
++                      if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
++                              int i, error;
++
++                              if (debug) {
++                                      dprintk("%s key:", __FUNCTION__);
++                                      for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++                                              dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
++                                                              crd->crd_key[i]);
++                                      dprintk("\n");
++                              }
++                              error = crypto_blkcipher_setkey(
++                                                      crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
++                                                      (crd->crd_klen + 7) / 8);
++                              if (error) {
++                                      dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
++                                                      error, sw->sw_tfm->crt_flags);
++                                      crp->crp_etype = -error;
++                              }
++                      }
++
++                      memset(&desc, 0, sizeof(desc));
++                      desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
++
++                      if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++                              if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++                                      ivp = crd->crd_iv;
++                              } else {
++                                      get_random_bytes(ivp, ivsize);
++                              }
++                              /*
++                               * do we have to copy the IV back to the buffer ?
++                               */
++                              if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++                                      crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                                      crd->crd_inject, ivsize, (caddr_t)ivp);
++                              }
++                              desc.info = ivp;
++                              crypto_blkcipher_encrypt_iv(&desc, sg, sg, sg_len);
++
++                      } else { /*decrypt */
++
++                              if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++                                      ivp = crd->crd_iv;
++                              } else {
++                                      crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                                      crd->crd_inject, ivsize, (caddr_t)ivp);
++                              }
++                              desc.info = ivp;
++                              crypto_blkcipher_decrypt_iv(&desc, sg, sg, sg_len);
++                      }
++                      } break;
++              case SW_TYPE_HMAC:
++              case SW_TYPE_HASH:
++                      {
++                      char result[HASH_MAX_LEN];
++                      struct hash_desc desc;
++
++                      /* check we have room for the result */
++                      if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
++                              dprintk(
++                      "cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d digestsize=%d\n",
++                                              crp->crp_ilen, crd->crd_skip + sg_len, crd->crd_inject,
++                                              sw->u.hmac.sw_mlen);
++                              crp->crp_etype = EINVAL;
++                              goto done;
++                      }
++
++                      memset(&desc, 0, sizeof(desc));
++                      desc.tfm = crypto_hash_cast(sw->sw_tfm);
++
++                      memset(result, 0, sizeof(result));
++
++                      if (sw->sw_type == SW_TYPE_HMAC) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++                              crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
++                                              sg, sg_num, result);
++#else
++                              crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
++                                              sw->u.hmac.sw_klen);
++                              crypto_hash_digest(&desc, sg, sg_len, result);
++#endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++                              
++                      } else { /* SW_TYPE_HASH */
++                              crypto_hash_digest(&desc, sg, sg_len, result);
++                      }
++
++                      crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                      crd->crd_inject, sw->u.hmac.sw_mlen, result);
++                      }
++                      break;
++
++              case SW_TYPE_COMP: {
++                      void *ibuf = NULL;
++                      void *obuf = sw->u.sw_comp_buf;
++                      int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
++                      int ret = 0;
++
++                      /*
++                       * we need to use an additional copy if there is more than one
++                       * input chunk since the kernel comp routines do not handle
++                       * SG yet.  Otherwise we just use the input buffer as is.
++                       * Rather than allocate another buffer we just split the tmp
++                       * buffer we already have.
++                       * Perhaps we should just use zlib directly ?
++                       */
++                      if (sg_num > 1) {
++                              int blk;
++
++                              ibuf = obuf;
++                              for (blk = 0; blk < sg_num; blk++) {
++                                      memcpy(obuf, sg_virt(&sg[blk]),
++                                                      sg[blk].length);
++                                      obuf += sg[blk].length;
++                              }
++                              olen -= sg_len;
++                      } else
++                              ibuf = sg_virt(&sg[0]);
++
++                      if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
++                              ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
++                                              ibuf, ilen, obuf, &olen);
++                              if (!ret && olen > crd->crd_len) {
++                                      dprintk("cryptosoft: ERANGE compress %d into %d\n",
++                                                      crd->crd_len, olen);
++                                      if (swcr_fail_if_compression_grows)
++                                              ret = ERANGE;
++                              }
++                      } else { /* decompress */
++                              ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
++                                              ibuf, ilen, obuf, &olen);
++                              if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
++                                      dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
++                                                      "space for %d,at offset %d\n",
++                                                      crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
++                                      ret = ETOOSMALL;
++                              }
++                      }
++                      if (ret)
++                              dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret);
++
++                      /*
++                       * on success copy result back,
++                       * linux crpyto API returns -errno,  we need to fix that
++                       */
++                      crp->crp_etype = ret < 0 ? -ret : ret;
++                      if (ret == 0) {
++                              /* copy back the result and return it's size */
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                              crd->crd_inject, olen, obuf);
++                              crp->crp_olen = olen;
++                      }
++
++
++                      } break;
++
++              default:
++                      /* Unknown/unsupported algorithm */
++                      dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++                      crp->crp_etype = EINVAL;
++                      goto done;
++              }
++      }
++
++done:
++      crypto_done(crp);
++      return 0;
++}
++
++static int
++cryptosoft_init(void)
++{
++      int i, sw_type, mode;
++      char *algo;
++
++      dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);
++
++      softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods);
++
++      swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc),
++                      CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
++      if (swcr_id < 0) {
++              printk("Software crypto device cannot initialize!");
++              return -ENODEV;
++      }
++
++#define       REGISTER(alg) \
++              crypto_register(swcr_id, alg, 0,0);
++
++      for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; ++i)
++      {
++              
++              algo = crypto_details[i].alg_name;
++              if (!algo || !*algo)
++              {
++                      dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i);
++                      continue;
++              }
++
++              mode = crypto_details[i].mode;
++              sw_type = crypto_details[i].sw_type;
++
++              switch (sw_type)
++              {
++                      case SW_TYPE_CIPHER:
++                              if (crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC))
++                              {
++                                      REGISTER(i);
++                              }
++                              else
++                              {
++                                      dprintk("%s:CIPHER algorithm %d:'%s' not supported\n",
++                                                              __FUNCTION__, i, algo);
++                              }
++                              break;
++                      case SW_TYPE_HMAC:
++                              if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
++                              {
++                                      REGISTER(i);
++                              }
++                              else
++                              {
++                                      dprintk("%s:HMAC algorithm %d:'%s' not supported\n",
++                                                              __FUNCTION__, i, algo);
++                              }
++                              break;
++                      case SW_TYPE_HASH:
++                              if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
++                              {
++                                      REGISTER(i);
++                              }
++                              else
++                              {
++                                      dprintk("%s:HASH algorithm %d:'%s' not supported\n",
++                                                              __FUNCTION__, i, algo);
++                              }
++                              break;
++                      case SW_TYPE_COMP:
++                              if (crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC))
++                              {
++                                      REGISTER(i);
++                              }
++                              else
++                              {
++                                      dprintk("%s:COMP algorithm %d:'%s' not supported\n",
++                                                              __FUNCTION__, i, algo);
++                              }
++                              break;
++                      case SW_TYPE_BLKCIPHER:
++                              if (crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC))
++                              {
++                                      REGISTER(i);
++                              }
++                              else
++                              {
++                                      dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n",
++                                                              __FUNCTION__, i, algo);
++                              }
++                              break;
++                      default:
++                              dprintk(
++                              "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
++                                      __FUNCTION__, sw_type, i, algo);
++                              break;
++              }
++      }
++
++      return(0);
++}
++
++static void
++cryptosoft_exit(void)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      crypto_unregister_all(swcr_id);
++      swcr_id = -1;
++}
++
++module_init(cryptosoft_init);
++module_exit(cryptosoft_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/rndtest.c 2007-07-20 13:22:03.000000000 +1000
+@@ -0,0 +1,300 @@
++/*    $OpenBSD$       */
++
++/*
++ * OCF/Linux port done by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2006-2007 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by Jason L. Wright
++ * 4. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/wait.h>
++#include <linux/time.h>
++#include <linux/version.h>
++#include <linux/unistd.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/time.h>
++#include <cryptodev.h>
++#include "rndtest.h"
++
++static struct rndtest_stats rndstats;
++
++static        void rndtest_test(struct rndtest_state *);
++
++/* The tests themselves */
++static        int rndtest_monobit(struct rndtest_state *);
++static        int rndtest_runs(struct rndtest_state *);
++static        int rndtest_longruns(struct rndtest_state *);
++static        int rndtest_chi_4(struct rndtest_state *);
++
++static        int rndtest_runs_check(struct rndtest_state *, int, int *);
++static        void rndtest_runs_record(struct rndtest_state *, int, int *);
++
++static const struct rndtest_testfunc {
++      int (*test)(struct rndtest_state *);
++} rndtest_funcs[] = {
++      { rndtest_monobit },
++      { rndtest_runs },
++      { rndtest_chi_4 },
++      { rndtest_longruns },
++};
++
++#define       RNDTEST_NTESTS  (sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0]))
++
++static void
++rndtest_test(struct rndtest_state *rsp)
++{
++      int i, rv = 0;
++
++      rndstats.rst_tests++;
++      for (i = 0; i < RNDTEST_NTESTS; i++)
++              rv |= (*rndtest_funcs[i].test)(rsp);
++      rsp->rs_discard = (rv != 0);
++}
++
++
++extern int crypto_debug;
++#define rndtest_verbose 2
++#define rndtest_report(rsp, failure, fmt, a...) \
++      { if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; }
++
++#define       RNDTEST_MONOBIT_MINONES 9725
++#define       RNDTEST_MONOBIT_MAXONES 10275
++
++static int
++rndtest_monobit(struct rndtest_state *rsp)
++{
++      int i, ones = 0, j;
++      u_int8_t r;
++
++      for (i = 0; i < RNDTEST_NBYTES; i++) {
++              r = rsp->rs_buf[i];
++              for (j = 0; j < 8; j++, r <<= 1)
++                      if (r & 0x80)
++                              ones++;
++      }
++      if (ones > RNDTEST_MONOBIT_MINONES &&
++          ones < RNDTEST_MONOBIT_MAXONES) {
++              if (rndtest_verbose > 1)
++                      rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)",
++                          RNDTEST_MONOBIT_MINONES, ones,
++                          RNDTEST_MONOBIT_MAXONES);
++              return (0);
++      } else {
++              if (rndtest_verbose)
++                      rndtest_report(rsp, 1,
++                          "monobit failed (%d ones)", ones);
++              rndstats.rst_monobit++;
++              return (-1);
++      }
++}
++
++#define       RNDTEST_RUNS_NINTERVAL  6
++
++static const struct rndtest_runs_tabs {
++      u_int16_t min, max;
++} rndtest_runs_tab[] = {
++      { 2343, 2657 },
++      { 1135, 1365 },
++      { 542, 708 },
++      { 251, 373 },
++      { 111, 201 },
++      { 111, 201 },
++};
++
++static int
++rndtest_runs(struct rndtest_state *rsp)
++{
++      int i, j, ones, zeros, rv = 0;
++      int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL];
++      u_int8_t c;
++
++      bzero(onei, sizeof(onei));
++      bzero(zeroi, sizeof(zeroi));
++      ones = zeros = 0;
++      for (i = 0; i < RNDTEST_NBYTES; i++) {
++              c = rsp->rs_buf[i];
++              for (j = 0; j < 8; j++, c <<= 1) {
++                      if (c & 0x80) {
++                              ones++;
++                              rndtest_runs_record(rsp, zeros, zeroi);
++                              zeros = 0;
++                      } else {
++                              zeros++;
++                              rndtest_runs_record(rsp, ones, onei);
++                              ones = 0;
++                      }
++              }
++      }
++      rndtest_runs_record(rsp, ones, onei);
++      rndtest_runs_record(rsp, zeros, zeroi);
++
++      rv |= rndtest_runs_check(rsp, 0, zeroi);
++      rv |= rndtest_runs_check(rsp, 1, onei);
++
++      if (rv)
++              rndstats.rst_runs++;
++
++      return (rv);
++}
++
++static void
++rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv)
++{
++      if (len == 0)
++              return;
++      if (len > RNDTEST_RUNS_NINTERVAL)
++              len = RNDTEST_RUNS_NINTERVAL;
++      len -= 1;
++      intrv[len]++;
++}
++
++static int
++rndtest_runs_check(struct rndtest_state *rsp, int val, int *src)
++{
++      int i, rv = 0;
++
++      for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) {
++              if (src[i] < rndtest_runs_tab[i].min ||
++                  src[i] > rndtest_runs_tab[i].max) {
++                      rndtest_report(rsp, 1,
++                          "%s interval %d failed (%d, %d-%d)",
++                          val ? "ones" : "zeros",
++                          i + 1, src[i], rndtest_runs_tab[i].min,
++                          rndtest_runs_tab[i].max);
++                      rv = -1;
++              } else {
++                      rndtest_report(rsp, 0,
++                          "runs pass %s interval %d (%d < %d < %d)",
++                          val ? "ones" : "zeros",
++                          i + 1, rndtest_runs_tab[i].min, src[i],
++                          rndtest_runs_tab[i].max);
++              }
++      }
++      return (rv);
++}
++
++static int
++rndtest_longruns(struct rndtest_state *rsp)
++{
++      int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0;
++      u_int8_t c;
++
++      for (i = 0; i < RNDTEST_NBYTES; i++) {
++              c = rsp->rs_buf[i];
++              for (j = 0; j < 8; j++, c <<= 1) {
++                      if (c & 0x80) {
++                              zeros = 0;
++                              ones++;
++                              if (ones > maxones)
++                                      maxones = ones;
++                      } else {
++                              ones = 0;
++                              zeros++;
++                              if (zeros > maxzeros)
++                                      maxzeros = zeros;
++                      }
++              }
++      }
++
++      if (maxones < 26 && maxzeros < 26) {
++              rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)",
++                      maxones, maxzeros);
++              return (0);
++      } else {
++              rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)",
++                      maxones, maxzeros);
++              rndstats.rst_longruns++;
++              return (-1);
++      }
++}
++
++/*
++ * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2,
++ * but it is really the chi^2 test over 4 bits (the poker test as described
++ * by Knuth vol 2 is something different, and I take him as authoritative
++ * on nomenclature over NIST).
++ */
++#define       RNDTEST_CHI4_K  16
++#define       RNDTEST_CHI4_K_MASK     (RNDTEST_CHI4_K - 1)
++
++/*
++ * The unnormalized values are used so that we don't have to worry about
++ * fractional precision.  The "real" value is found by:
++ *    (V - 1562500) * (16 / 5000) = Vn   (where V is the unnormalized value)
++ */
++#define       RNDTEST_CHI4_VMIN       1563181         /* 2.1792 */
++#define       RNDTEST_CHI4_VMAX       1576929         /* 46.1728 */
++
++static int
++rndtest_chi_4(struct rndtest_state *rsp)
++{
++      unsigned int freq[RNDTEST_CHI4_K], i, sum;
++
++      for (i = 0; i < RNDTEST_CHI4_K; i++)
++              freq[i] = 0;
++
++      /* Get number of occurances of each 4 bit pattern */
++      for (i = 0; i < RNDTEST_NBYTES; i++) {
++              freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++;
++              freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++;
++      }
++
++      for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++)
++              sum += freq[i] * freq[i];
++
++      if (sum >= 1563181 && sum <= 1576929) {
++              rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum);
++              return (0);
++      } else {
++              rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum);
++              rndstats.rst_chi++;
++              return (-1);
++      }
++}
++
++int
++rndtest_buf(unsigned char *buf)
++{
++      struct rndtest_state rsp;
++
++      memset(&rsp, 0, sizeof(rsp));
++      rsp.rs_buf = buf;
++      rndtest_test(&rsp);
++      return(rsp.rs_discard);
++}
++
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/rndtest.h 2005-05-20 10:28:26.000000000 +1000
+@@ -0,0 +1,54 @@
++/*    $FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $     */
++/*    $OpenBSD$       */
++
++/*
++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by Jason L. Wright
++ * 4. The name of the author may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/* Some of the tests depend on these values */
++#define       RNDTEST_NBYTES  2500
++#define       RNDTEST_NBITS   (8 * RNDTEST_NBYTES)
++
++struct rndtest_state {
++      int             rs_discard;     /* discard/accept random data */
++      u_int8_t        *rs_buf;
++};
++
++struct rndtest_stats {
++      u_int32_t       rst_discard;    /* number of bytes discarded */
++      u_int32_t       rst_tests;      /* number of test runs */
++      u_int32_t       rst_monobit;    /* monobit test failures */
++      u_int32_t       rst_runs;       /* 0/1 runs failures */
++      u_int32_t       rst_longruns;   /* longruns failures */
++      u_int32_t       rst_chi;        /* chi^2 failures */
++};
++
++extern int rndtest_buf(unsigned char *buf);
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/ocf-compat.h      2008-04-27 09:30:47.000000000 +1000
+@@ -0,0 +1,268 @@
++#ifndef _BSD_COMPAT_H_
++#define _BSD_COMPAT_H_ 1
++/****************************************************************************/
++/*
++ * Provide compat routines for older linux kernels and BSD kernels
++ *
++ * Written by David McCullough <david_mccullough@securecomputing.com>
++ * Copyright (C) 2007 David McCullough <david_mccullough@securecomputing.com>
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this file
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++/****************************************************************************/
++#ifdef __KERNEL__
++/*
++ * fake some BSD driver interface stuff specifically for OCF use
++ */
++
++typedef struct ocf_device *device_t;
++
++typedef struct {
++      int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri);
++      int (*cryptodev_freesession)(device_t dev, u_int64_t tid);
++      int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint);
++      int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint);
++} device_method_t;
++#define DEVMETHOD(id, func)   id: func
++
++struct ocf_device {
++      char name[32];          /* the driver name */
++      char nameunit[32];      /* the driver name + HW instance */
++      int  unit;
++      device_method_t methods;
++      void *softc;
++};
++
++#define CRYPTODEV_NEWSESSION(dev, sid, cri) \
++      ((*(dev)->methods.cryptodev_newsession)(dev,sid,cri))
++#define CRYPTODEV_FREESESSION(dev, sid) \
++      ((*(dev)->methods.cryptodev_freesession)(dev, sid))
++#define CRYPTODEV_PROCESS(dev, crp, hint) \
++      ((*(dev)->methods.cryptodev_process)(dev, crp, hint))
++#define CRYPTODEV_KPROCESS(dev, krp, hint) \
++      ((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint))
++
++#define device_get_name(dev)  ((dev)->name)
++#define device_get_nameunit(dev)      ((dev)->nameunit)
++#define device_get_unit(dev)  ((dev)->unit)
++#define device_get_softc(dev) ((dev)->softc)
++
++#define       softc_device_decl \
++              struct ocf_device _device; \
++              device_t
++
++#define       softc_device_init(_sc, _name, _unit, _methods) \
++      if (1) {\
++      strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \
++      snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \
++      (_sc)->_device.unit = _unit; \
++      (_sc)->_device.methods = _methods; \
++      (_sc)->_device.softc = (void *) _sc; \
++      *(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \
++      } else
++
++#define       softc_get_device(_sc)   (&(_sc)->_device)
++
++/*
++ * iomem support for 2.4 and 2.6 kernels
++ */
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define ocf_iomem_t   unsigned long
++
++/*
++ * implement simple workqueue like support for older kernels
++ */
++
++#include <linux/tqueue.h>
++
++#define work_struct tq_struct
++
++#define INIT_WORK(wp, fp, ap) \
++      do { \
++              (wp)->sync = 0; \
++              (wp)->routine = (fp); \
++              (wp)->data = (ap); \
++      } while (0)
++
++#define schedule_work(wp) \
++      do { \
++              queue_task((wp), &tq_immediate); \
++              mark_bh(IMMEDIATE_BH); \
++      } while (0)
++
++#define flush_scheduled_work()        run_task_queue(&tq_immediate)
++
++#else
++#define ocf_iomem_t   void __iomem *
++
++#include <linux/workqueue.h>
++
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
++#define files_fdtable(files)  (files)
++#endif
++
++#ifdef MODULE_PARM
++#undef module_param   /* just in case */
++#define       module_param(a,b,c)             MODULE_PARM(a,"i")
++#endif
++
++#define bzero(s,l)            memset(s,0,l)
++#define bcopy(s,d,l)  memcpy(d,s,l)
++#define bcmp(x, y, l) memcmp(x,y,l)
++
++#define MIN(x,y)      ((x) < (y) ? (x) : (y))
++
++#define device_printf(dev, a...) ({ \
++                              printk("%s: ", device_get_nameunit(dev)); printk(a); \
++                      })
++
++#undef printf
++#define printf(fmt...)        printk(fmt)
++
++#define KASSERT(c,p)  if (!(c)) { printk p ; } else
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define ocf_daemonize(str) \
++      daemonize(); \
++      spin_lock_irq(&current->sigmask_lock); \
++      sigemptyset(&current->blocked); \
++      recalc_sigpending(current); \
++      spin_unlock_irq(&current->sigmask_lock); \
++      sprintf(current->comm, str);
++#else
++#define ocf_daemonize(str) daemonize(str);
++#endif
++
++#define       TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q))
++#define       TAILQ_EMPTY(q)  list_empty(q)
++#define       TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m)
++
++#define read_random(p,l) get_random_bytes(p,l)
++
++#define DELAY(x)      ((x) > 2000 ? mdelay((x)/1000) : udelay(x))
++#define strtoul simple_strtoul
++
++#define pci_get_vendor(dev)   ((dev)->vendor)
++#define pci_get_device(dev)   ((dev)->device)
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define pci_set_consistent_dma_mask(dev, mask) (0)
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++#define pci_dma_sync_single_for_cpu pci_dma_sync_single
++#endif
++
++#ifndef DMA_32BIT_MASK
++#define DMA_32BIT_MASK  0x00000000ffffffffULL
++#endif
++
++#define htole32(x)    cpu_to_le32(x)
++#define htobe32(x)    cpu_to_be32(x)
++#define htole16(x)    cpu_to_le16(x)
++#define htobe16(x)    cpu_to_be16(x)
++
++/* older kernels don't have these */
++
++#ifndef IRQ_NONE
++#define IRQ_NONE
++#define IRQ_HANDLED
++#define irqreturn_t void
++#endif
++#ifndef IRQF_SHARED
++#define IRQF_SHARED   SA_SHIRQ
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++# define strlcpy(dest,src,len) \
++              ({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; })
++#endif
++
++#ifndef MAX_ERRNO
++#define MAX_ERRNO     4095
++#endif
++#ifndef IS_ERR_VALUE
++#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
++#endif
++
++/*
++ * common debug for all
++ */
++#if 1
++#define dprintk(a...) do { if (debug) printk(a); } while(0)
++#else
++#define dprintk(a...)
++#endif
++
++#ifndef SLAB_ATOMIC
++/* Changed in 2.6.20, must use GFP_ATOMIC now */
++#define       SLAB_ATOMIC     GFP_ATOMIC
++#endif
++
++/*
++ * need some additional support for older kernels */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2)
++#define pci_register_driver_compat(driver, rc) \
++      do { \
++              if ((rc) > 0) { \
++                      (rc) = 0; \
++              } else if (rc == 0) { \
++                      (rc) = -ENODEV; \
++              } else { \
++                      pci_unregister_driver(driver); \
++              } \
++      } while (0)
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0)
++#else
++#define pci_register_driver_compat(driver,rc)
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++
++#include <asm/scatterlist.h>
++
++static inline void sg_set_page(struct scatterlist *sg,  struct page *page,
++                             unsigned int len, unsigned int offset)
++{
++      sg->page = page;
++      sg->offset = offset;
++      sg->length = len;
++}
++
++static inline void *sg_virt(struct scatterlist *sg)
++{
++      return page_address(sg->page) + sg->offset;
++}
++
++#endif
++
++#endif /* __KERNEL__ */
++
++/****************************************************************************/
++#endif /* _BSD_COMPAT_H_ */
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/pasemi/pasemi.c   2007-12-12 11:36:18.000000000 +1000
+@@ -0,0 +1,1009 @@
++/*
++ * Copyright (C) 2007 PA Semi, Inc
++ *
++ * Driver for the PA Semi PWRficient DMA Crypto Engine
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/timer.h>
++#include <linux/random.h>
++#include <linux/skbuff.h>
++#include <asm/scatterlist.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <cryptodev.h>
++#include <uio.h>
++#include "pasemi_fnu.h"
++
++#define DRV_NAME "pasemi"
++
++#define TIMER_INTERVAL 1000
++
++static void __devexit pasemi_dma_remove(struct pci_dev *pdev);
++static struct pasdma_status volatile * dma_status;
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Enable debug");
++
++static void pasemi_desc_start(struct pasemi_desc *desc, u64 hdr)
++{
++      desc->postop = 0;
++      desc->quad[0] = hdr;
++      desc->quad_cnt = 1;
++      desc->size = 1;
++}
++
++static void pasemi_desc_build(struct pasemi_desc *desc, u64 val)
++{
++      desc->quad[desc->quad_cnt++] = val;
++      desc->size = (desc->quad_cnt + 1) / 2;
++}
++
++static void pasemi_desc_hdr(struct pasemi_desc *desc, u64 hdr)
++{
++      desc->quad[0] |= hdr;
++}
++
++static int pasemi_desc_size(struct pasemi_desc *desc)
++{
++      return desc->size;
++}
++
++static void pasemi_ring_add_desc(
++                               struct pasemi_fnu_txring *ring,
++                               struct pasemi_desc *desc,
++                               struct cryptop *crp) {
++      int i;
++      int ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1));
++
++      TX_DESC_INFO(ring, ring->next_to_fill).desc_size = desc->size;
++      TX_DESC_INFO(ring, ring->next_to_fill).desc_postop = desc->postop;
++      TX_DESC_INFO(ring, ring->next_to_fill).cf_crp = crp;
++
++      for (i = 0; i < desc->quad_cnt; i += 2) {
++              ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1));
++              ring->desc[ring_index] = desc->quad[i];
++              ring->desc[ring_index + 1] = desc->quad[i + 1];
++              ring->next_to_fill++;
++      }
++
++      if (desc->quad_cnt & 1)
++              ring->desc[ring_index + 1] = 0;
++}
++
++static void pasemi_ring_incr(struct pasemi_softc *sc, int chan_index, int incr)
++{
++      out_le32(sc->dma_regs + PAS_DMA_TXCHAN_INCR(sc->base_chan + chan_index),
++               incr);
++}
++
++/*
++ * Generate a new software session.
++ */
++static int
++pasemi_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++      struct cryptoini *c, *encini = NULL, *macini = NULL;
++      struct pasemi_softc *sc = device_get_softc(dev);
++      struct pasemi_session *ses = NULL, **sespp;
++      int sesn, blksz = 0;
++      u64 ccmd = 0;
++      unsigned long flags;
++      struct pasemi_desc init_desc;
++      struct pasemi_fnu_txring *txring;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++      if (sidp == NULL || cri == NULL || sc == NULL) {
++              DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return -EINVAL;
++      }
++      for (c = cri; c != NULL; c = c->cri_next) {
++              if (ALG_IS_SIG(c->cri_alg)) {
++                      if (macini)
++                              return -EINVAL;
++                      macini = c;
++              } else if (ALG_IS_CIPHER(c->cri_alg)) {
++                      if (encini)
++                              return -EINVAL;
++                      encini = c;
++              } else {
++                      DPRINTF("UNKNOWN c->cri_alg %d\n", c->cri_alg);
++                      return -EINVAL;
++              }
++      }
++      if (encini == NULL && macini == NULL)
++              return -EINVAL;
++      if (encini) {
++              /* validate key length */
++              switch (encini->cri_alg) {
++              case CRYPTO_DES_CBC:
++                      if (encini->cri_klen != 64)
++                              return -EINVAL;
++                      ccmd = DMA_CALGO_DES;
++                      break;
++              case CRYPTO_3DES_CBC:
++                      if (encini->cri_klen != 192)
++                              return -EINVAL;
++                      ccmd = DMA_CALGO_3DES;
++                      break;
++              case CRYPTO_AES_CBC:
++                      if (encini->cri_klen != 128 &&
++                          encini->cri_klen != 192 &&
++                          encini->cri_klen != 256)
++                              return -EINVAL;
++                      ccmd = DMA_CALGO_AES;
++                      break;
++              case CRYPTO_ARC4:
++                      if (encini->cri_klen != 128)
++                              return -EINVAL;
++                      ccmd = DMA_CALGO_ARC;
++                      break;
++              default:
++                      DPRINTF("UNKNOWN encini->cri_alg %d\n",
++                              encini->cri_alg);
++                      return -EINVAL;
++              }
++      }
++
++      if (macini) {
++              switch (macini->cri_alg) {
++              case CRYPTO_MD5:
++              case CRYPTO_MD5_HMAC:
++                      blksz = 16;
++                      break;
++              case CRYPTO_SHA1:
++              case CRYPTO_SHA1_HMAC:
++                      blksz = 20;
++                      break;
++              default:
++                      DPRINTF("UNKNOWN macini->cri_alg %d\n",
++                              macini->cri_alg);
++                      return -EINVAL;
++              }
++              if (((macini->cri_klen + 7) / 8) > blksz) {
++                      DPRINTF("key length %d bigger than blksize %d not supported\n",
++                              ((macini->cri_klen + 7) / 8), blksz);
++                      return -EINVAL;
++              }
++      }
++
++      for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++              if (sc->sc_sessions[sesn] == NULL) {
++                      sc->sc_sessions[sesn] = (struct pasemi_session *)
++                              kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC);
++                      ses = sc->sc_sessions[sesn];
++                      break;
++              } else if (sc->sc_sessions[sesn]->used == 0) {
++                      ses = sc->sc_sessions[sesn];
++                      break;
++              }
++      }
++
++      if (ses == NULL) {
++              sespp = (struct pasemi_session **)
++                      kzalloc(sc->sc_nsessions * 2 *
++                              sizeof(struct pasemi_session *), GFP_ATOMIC);
++              if (sespp == NULL)
++                      return -ENOMEM;
++              memcpy(sespp, sc->sc_sessions,
++                     sc->sc_nsessions * sizeof(struct pasemi_session *));
++              kfree(sc->sc_sessions);
++              sc->sc_sessions = sespp;
++              sesn = sc->sc_nsessions;
++              ses = sc->sc_sessions[sesn] = (struct pasemi_session *)
++                      kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC);
++              if (ses == NULL)
++                      return -ENOMEM;
++              sc->sc_nsessions *= 2;
++      }
++
++      ses->used = 1;
++
++      ses->dma_addr = pci_map_single(sc->dma_pdev, (void *) ses->civ,
++                                     sizeof(struct pasemi_session), DMA_TO_DEVICE);
++
++      /* enter the channel scheduler */
++      spin_lock_irqsave(&sc->sc_chnlock, flags);
++
++      /* ARC4 has to be processed by the even channel */
++      if (encini && (encini->cri_alg == CRYPTO_ARC4))
++              ses->chan = sc->sc_lastchn & ~1;
++      else
++              ses->chan = sc->sc_lastchn;
++      sc->sc_lastchn = (sc->sc_lastchn + 1) % sc->sc_num_channels;
++
++      spin_unlock_irqrestore(&sc->sc_chnlock, flags);
++
++      txring = &sc->tx[ses->chan];
++
++      if (encini) {
++              ses->ccmd = ccmd;
++
++              /* get an IV */
++              /* XXX may read fewer than requested */
++              get_random_bytes(ses->civ, sizeof(ses->civ));
++
++              ses->keysz = (encini->cri_klen - 63) / 64;
++              memcpy(ses->key, encini->cri_key, (ses->keysz + 1) * 8);
++
++              pasemi_desc_start(&init_desc,
++                                XCT_CTRL_HDR(ses->chan, (encini && macini) ? 0x68 : 0x40, DMA_FN_CIV0));
++              pasemi_desc_build(&init_desc,
++                                XCT_FUN_SRC_PTR((encini && macini) ? 0x68 : 0x40, ses->dma_addr));
++      }
++      if (macini) {
++              if (macini->cri_alg == CRYPTO_MD5_HMAC ||
++                  macini->cri_alg == CRYPTO_SHA1_HMAC)
++                      memcpy(ses->hkey, macini->cri_key, blksz);
++              else {
++                      /* Load initialization constants(RFC 1321, 3174) */
++                      ses->hiv[0] = 0x67452301efcdab89ULL;
++                      ses->hiv[1] = 0x98badcfe10325476ULL;
++                      ses->hiv[2] = 0xc3d2e1f000000000ULL;
++              }
++              ses->hseq = 0ULL;
++      }
++
++      spin_lock_irqsave(&txring->fill_lock, flags);
++
++      if (((txring->next_to_fill + pasemi_desc_size(&init_desc)) -
++           txring->next_to_clean) > TX_RING_SIZE) {
++              spin_unlock_irqrestore(&txring->fill_lock, flags);
++              return ERESTART;
++      }
++
++      if (encini) {
++              pasemi_ring_add_desc(txring, &init_desc, NULL);
++              pasemi_ring_incr(sc, ses->chan,
++                               pasemi_desc_size(&init_desc));
++      }
++
++      txring->sesn = sesn;
++      spin_unlock_irqrestore(&txring->fill_lock, flags);
++
++      *sidp = PASEMI_SID(sesn);
++      return 0;
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++pasemi_freesession(device_t dev, u_int64_t tid)
++{
++      struct pasemi_softc *sc = device_get_softc(dev);
++      int session;
++      u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (sc == NULL)
++              return -EINVAL;
++      session = PASEMI_SESSION(sid);
++      if (session >= sc->sc_nsessions || !sc->sc_sessions[session])
++              return -EINVAL;
++
++      pci_unmap_single(sc->dma_pdev,
++                       sc->sc_sessions[session]->dma_addr,
++                       sizeof(struct pasemi_session), DMA_TO_DEVICE);
++      memset(sc->sc_sessions[session], 0,
++             sizeof(struct pasemi_session));
++
++      return 0;
++}
++
++static int
++pasemi_process(device_t dev, struct cryptop *crp, int hint)
++{
++
++      int err = 0, ivsize, srclen = 0, reinit = 0, reinit_size = 0, chsel;
++      struct pasemi_softc *sc = device_get_softc(dev);
++      struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++      caddr_t ivp;
++      struct pasemi_desc init_desc, work_desc;
++      struct pasemi_session *ses;
++      struct sk_buff *skb;
++      struct uio *uiop;
++      unsigned long flags;
++      struct pasemi_fnu_txring *txring;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (crp == NULL || crp->crp_callback == NULL || sc == NULL)
++              return -EINVAL;
++
++      crp->crp_etype = 0;
++      if (PASEMI_SESSION(crp->crp_sid) >= sc->sc_nsessions)
++              return -EINVAL;
++
++      ses = sc->sc_sessions[PASEMI_SESSION(crp->crp_sid)];
++
++      crd1 = crp->crp_desc;
++      if (crd1 == NULL) {
++              err = -EINVAL;
++              goto errout;
++      }
++      crd2 = crd1->crd_next;
++
++      if (ALG_IS_SIG(crd1->crd_alg)) {
++              maccrd = crd1;
++              if (crd2 == NULL)
++                      enccrd = NULL;
++              else if (ALG_IS_CIPHER(crd2->crd_alg) &&
++                       (crd2->crd_flags & CRD_F_ENCRYPT) == 0)
++                      enccrd = crd2;
++              else
++                      goto erralg;
++      } else if (ALG_IS_CIPHER(crd1->crd_alg)) {
++              enccrd = crd1;
++              if (crd2 == NULL)
++                      maccrd = NULL;
++              else if (ALG_IS_SIG(crd2->crd_alg) &&
++                       (crd1->crd_flags & CRD_F_ENCRYPT))
++                      maccrd = crd2;
++              else
++                      goto erralg;
++      } else
++              goto erralg;
++
++      chsel = ses->chan;
++
++      txring = &sc->tx[chsel];
++
++      if (enccrd && !maccrd) {
++              if (enccrd->crd_alg == CRYPTO_ARC4)
++                      reinit = 1;
++              reinit_size = 0x40;
++              srclen = crp->crp_ilen;
++
++              pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I
++                                | XCT_FUN_FUN(chsel));
++              if (enccrd->crd_flags & CRD_F_ENCRYPT)
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_ENC);
++              else
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_DEC);
++      } else if (enccrd && maccrd) {
++              if (enccrd->crd_alg == CRYPTO_ARC4)
++                      reinit = 1;
++              reinit_size = 0x68;
++
++              if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++                      /* Encrypt -> Authenticate */
++                      pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_ENC_SIG
++                                        | XCT_FUN_A | XCT_FUN_FUN(chsel));
++                      srclen = maccrd->crd_skip + maccrd->crd_len;
++              } else {
++                      /* Authenticate -> Decrypt */
++                      pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG_DEC
++                                        | XCT_FUN_24BRES | XCT_FUN_FUN(chsel));
++                      pasemi_desc_build(&work_desc, 0);
++                      pasemi_desc_build(&work_desc, 0);
++                      pasemi_desc_build(&work_desc, 0);
++                      work_desc.postop = PASEMI_CHECK_SIG;
++                      srclen = crp->crp_ilen;
++              }
++
++              pasemi_desc_hdr(&work_desc, XCT_FUN_SHL(maccrd->crd_skip / 4));
++              pasemi_desc_hdr(&work_desc, XCT_FUN_CHL(enccrd->crd_skip - maccrd->crd_skip));
++      } else if (!enccrd && maccrd) {
++              srclen = maccrd->crd_len;
++
++              pasemi_desc_start(&init_desc,
++                                XCT_CTRL_HDR(chsel, 0x58, DMA_FN_HKEY0));
++              pasemi_desc_build(&init_desc,
++                                XCT_FUN_SRC_PTR(0x58, ((struct pasemi_session *)ses->dma_addr)->hkey));
++
++              pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG
++                                | XCT_FUN_A | XCT_FUN_FUN(chsel));
++      }
++
++      if (enccrd) {
++              switch (enccrd->crd_alg) {
++              case CRYPTO_3DES_CBC:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_3DES |
++                                      XCT_FUN_BCM_CBC);
++                      ivsize = sizeof(u64);
++                      break;
++              case CRYPTO_DES_CBC:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_DES |
++                                      XCT_FUN_BCM_CBC);
++                      ivsize = sizeof(u64);
++                      break;
++              case CRYPTO_AES_CBC:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_AES |
++                                      XCT_FUN_BCM_CBC);
++                      ivsize = 2 * sizeof(u64);
++                      break;
++              case CRYPTO_ARC4:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_ARC);
++                      ivsize = 0;
++                      break;
++              default:
++                      printk(DRV_NAME ": unimplemented enccrd->crd_alg %d\n",
++                             enccrd->crd_alg);
++                      err = -EINVAL;
++                      goto errout;
++              }
++
++              ivp = (ivsize == sizeof(u64)) ? (caddr_t) &ses->civ[1] : (caddr_t) &ses->civ[0];
++              if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                              memcpy(ivp, enccrd->crd_iv, ivsize);
++                      /* If IV is not present in the buffer already, it has to be copied there */
++                      if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                              enccrd->crd_inject, ivsize, ivp);
++              } else {
++                      if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++                              /* IV is provided expicitly in descriptor */
++                              memcpy(ivp, enccrd->crd_iv, ivsize);
++                      else
++                              /* IV is provided in the packet */
++                              crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                              enccrd->crd_inject, ivsize,
++                                              ivp);
++              }
++      }
++
++      if (maccrd) {
++              switch (maccrd->crd_alg) {
++              case CRYPTO_MD5:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_MD5 |
++                                      XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++                      break;
++              case CRYPTO_SHA1:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_SHA1 |
++                                      XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++                      break;
++              case CRYPTO_MD5_HMAC:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_MD5 |
++                                      XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++                      break;
++              case CRYPTO_SHA1_HMAC:
++                      pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_SHA1 |
++                                      XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++                      break;
++              default:
++                      printk(DRV_NAME ": unimplemented maccrd->crd_alg %d\n",
++                             maccrd->crd_alg);
++                      err = -EINVAL;
++                      goto errout;
++              }
++      }
++
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              /* using SKB buffers */
++              skb = (struct sk_buff *)crp->crp_buf;
++              if (skb_shinfo(skb)->nr_frags) {
++                      printk(DRV_NAME ": skb frags unimplemented\n");
++                      err = -EINVAL;
++                      goto errout;
++              }
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_DST_PTR(skb->len, pci_map_single(
++                                              sc->dma_pdev, skb->data,
++                                              skb->len, DMA_TO_DEVICE)));
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_SRC_PTR(
++                              srclen, pci_map_single(
++                                      sc->dma_pdev, skb->data,
++                                      srclen, DMA_TO_DEVICE)));
++              pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              /* using IOV buffers */
++              uiop = (struct uio *)crp->crp_buf;
++              if (uiop->uio_iovcnt > 1) {
++                      printk(DRV_NAME ": iov frags unimplemented\n");
++                      err = -EINVAL;
++                      goto errout;
++              }
++
++              /* crp_olen is never set; always use crp_ilen */
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single(
++                                              sc->dma_pdev,
++                                              uiop->uio_iov->iov_base,
++                                              crp->crp_ilen, DMA_TO_DEVICE)));
++              pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_SRC_PTR(srclen, pci_map_single(
++                                              sc->dma_pdev,
++                                              uiop->uio_iov->iov_base,
++                                              srclen, DMA_TO_DEVICE)));
++      } else {
++              /* using contig buffers */
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single(
++                                              sc->dma_pdev,
++                                              crp->crp_buf,
++                                              crp->crp_ilen, DMA_TO_DEVICE)));
++              pasemi_desc_build(
++                      &work_desc,
++                      XCT_FUN_SRC_PTR(srclen, pci_map_single(
++                                              sc->dma_pdev,
++                                              crp->crp_buf, srclen,
++                                              DMA_TO_DEVICE)));
++              pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++      }
++
++      spin_lock_irqsave(&txring->fill_lock, flags);
++
++      if (txring->sesn != PASEMI_SESSION(crp->crp_sid)) {
++              txring->sesn = PASEMI_SESSION(crp->crp_sid);
++              reinit = 1;
++      }
++
++      if (enccrd) {
++              pasemi_desc_start(&init_desc,
++                                XCT_CTRL_HDR(chsel, reinit ? reinit_size : 0x10, DMA_FN_CIV0));
++              pasemi_desc_build(&init_desc,
++                                XCT_FUN_SRC_PTR(reinit ? reinit_size : 0x10, ses->dma_addr));
++      }
++
++      if (((txring->next_to_fill + pasemi_desc_size(&init_desc) +
++            pasemi_desc_size(&work_desc)) -
++           txring->next_to_clean) > TX_RING_SIZE) {
++              spin_unlock_irqrestore(&txring->fill_lock, flags);
++              err = ERESTART;
++              goto errout;
++      }
++
++      pasemi_ring_add_desc(txring, &init_desc, NULL);
++      pasemi_ring_add_desc(txring, &work_desc, crp);
++
++      pasemi_ring_incr(sc, chsel,
++                       pasemi_desc_size(&init_desc) +
++                       pasemi_desc_size(&work_desc));
++
++      spin_unlock_irqrestore(&txring->fill_lock, flags);
++
++      mod_timer(&txring->crypto_timer, jiffies + TIMER_INTERVAL);
++
++      return 0;
++
++erralg:
++      printk(DRV_NAME ": unsupported algorithm or algorithm order alg1 %d alg2 %d\n",
++             crd1->crd_alg, crd2->crd_alg);
++      err = -EINVAL;
++
++errout:
++      if (err != ERESTART) {
++              crp->crp_etype = err;
++              crypto_done(crp);
++      }
++      return err;
++}
++
++static int pasemi_clean_tx(struct pasemi_softc *sc, int chan)
++{
++      int i, j, ring_idx;
++      struct pasemi_fnu_txring *ring = &sc->tx[chan];
++      u16 delta_cnt;
++      int flags, loops = 10;
++      int desc_size;
++      struct cryptop *crp;
++
++      spin_lock_irqsave(&ring->clean_lock, flags);
++
++      while ((delta_cnt = (dma_status->tx_sta[sc->base_chan + chan]
++                           & PAS_STATUS_PCNT_M) - ring->total_pktcnt)
++             && loops--) {
++
++              for (i = 0; i < delta_cnt; i++) {
++                      desc_size = TX_DESC_INFO(ring, ring->next_to_clean).desc_size;
++                      crp = TX_DESC_INFO(ring, ring->next_to_clean).cf_crp;
++                      if (crp) {
++                              ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1));
++                              if (TX_DESC_INFO(ring, ring->next_to_clean).desc_postop & PASEMI_CHECK_SIG) {
++                                      /* Need to make sure signature matched,
++                                       * if not - return error */
++                                      if (!(ring->desc[ring_idx + 1] & (1ULL << 63)))
++                                              crp->crp_etype = -EINVAL;
++                              }
++                              crypto_done(TX_DESC_INFO(ring,
++                                                       ring->next_to_clean).cf_crp);
++                              TX_DESC_INFO(ring, ring->next_to_clean).cf_crp = NULL;
++                              pci_unmap_single(
++                                      sc->dma_pdev,
++                                      XCT_PTR_ADDR_LEN(ring->desc[ring_idx + 1]),
++                                      PCI_DMA_TODEVICE);
++
++                              ring->desc[ring_idx] = ring->desc[ring_idx + 1] = 0;
++
++                              ring->next_to_clean++;
++                              for (j = 1; j < desc_size; j++) {
++                                      ring_idx = 2 *
++                                              (ring->next_to_clean &
++                                               (TX_RING_SIZE-1));
++                                      pci_unmap_single(
++                                              sc->dma_pdev,
++                                              XCT_PTR_ADDR_LEN(ring->desc[ring_idx]),
++                                              PCI_DMA_TODEVICE);
++                                      if (ring->desc[ring_idx + 1])
++                                              pci_unmap_single(
++                                                      sc->dma_pdev,
++                                                      XCT_PTR_ADDR_LEN(
++                                                              ring->desc[
++                                                                      ring_idx + 1]),
++                                                      PCI_DMA_TODEVICE);
++                                      ring->desc[ring_idx] =
++                                              ring->desc[ring_idx + 1] = 0;
++                                      ring->next_to_clean++;
++                              }
++                      } else {
++                              for (j = 0; j < desc_size; j++) {
++                                      ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1));
++                                      ring->desc[ring_idx] =
++                                              ring->desc[ring_idx + 1] = 0;
++                                      ring->next_to_clean++;
++                              }
++                      }
++              }
++
++              ring->total_pktcnt += delta_cnt;
++      }
++      spin_unlock_irqrestore(&ring->clean_lock, flags);
++
++      return 0;
++}
++
++static void sweepup_tx(struct pasemi_softc *sc)
++{
++      int i;
++
++      for (i = 0; i < sc->sc_num_channels; i++)
++              pasemi_clean_tx(sc, i);
++}
++
++static irqreturn_t pasemi_intr(int irq, void *arg, struct pt_regs *regs)
++{
++      struct pasemi_softc *sc = arg;
++      unsigned int reg;
++      int chan = irq - sc->base_irq;
++      int chan_index = sc->base_chan + chan;
++      u64 stat = dma_status->tx_sta[chan_index];
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (!(stat & PAS_STATUS_CAUSE_M))
++              return IRQ_NONE;
++
++      pasemi_clean_tx(sc, chan);
++
++      stat = dma_status->tx_sta[chan_index];
++
++      reg = PAS_IOB_DMA_TXCH_RESET_PINTC |
++              PAS_IOB_DMA_TXCH_RESET_PCNT(sc->tx[chan].total_pktcnt);
++
++      if (stat & PAS_STATUS_SOFT)
++              reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
++
++      out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), reg);
++
++
++      return IRQ_HANDLED;
++}
++
++static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan)
++{
++      u32 val;
++      int chan_index = chan + sc->base_chan;
++      int ret;
++      struct pasemi_fnu_txring *ring;
++
++      ring = &sc->tx[chan];
++
++      spin_lock_init(&ring->fill_lock);
++      spin_lock_init(&ring->clean_lock);
++
++      ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) *
++                                TX_RING_SIZE, GFP_KERNEL);
++      if (!ring->desc_info)
++              return -ENOMEM;
++
++      /* Allocate descriptors */
++      ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev,
++                                      TX_RING_SIZE *
++                                      2 * sizeof(u64),
++                                      &ring->dma, GFP_KERNEL);
++      if (!ring->desc)
++              return -ENOMEM;
++
++      memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64));
++
++      out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30);
++
++      ring->total_pktcnt = 0;
++
++      out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index),
++               PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
++
++      val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
++      val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
++
++      out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val);
++
++      out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index),
++               PAS_DMA_TXCHAN_CFG_TY_FUNC |
++               PAS_DMA_TXCHAN_CFG_TATTR(chan) |
++               PAS_DMA_TXCHAN_CFG_WT(2));
++
++      /* enable tx channel */
++      out_le32(sc->dma_regs +
++               PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++               PAS_DMA_TXCHAN_TCMDSTA_EN);
++
++      out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index),
++               PAS_IOB_DMA_TXCH_CFG_CNTTH(1000));
++
++      ring->next_to_fill = 0;
++      ring->next_to_clean = 0;
++
++      snprintf(ring->irq_name, sizeof(ring->irq_name),
++               "%s%d", "crypto", chan);
++
++      ring->irq = irq_create_mapping(NULL, sc->base_irq + chan);
++      ret = request_irq(ring->irq, (irq_handler_t)
++                        pasemi_intr, IRQF_DISABLED, ring->irq_name, sc);
++      if (ret) {
++              printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n",
++                     ring->irq, ret);
++              ring->irq = -1;
++              return ret;
++      }
++
++      setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc);
++
++      return 0;
++}
++
++static device_method_t pasemi_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession,         pasemi_newsession),
++      DEVMETHOD(cryptodev_freesession,        pasemi_freesession),
++      DEVMETHOD(cryptodev_process,            pasemi_process),
++};
++
++/* Set up the crypto device structure, private data,
++ * and anything else we need before we start */
++
++static int __devinit
++pasemi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++      struct pasemi_softc *sc;
++      int ret, i;
++
++      DPRINTF(KERN_ERR "%s()\n", __FUNCTION__);
++
++      sc = kzalloc(sizeof(*sc), GFP_KERNEL);
++      if (!sc)
++              return -ENOMEM;
++
++      softc_device_init(sc, DRV_NAME, 1, pasemi_methods);
++
++      pci_set_drvdata(pdev, sc);
++
++      spin_lock_init(&sc->sc_chnlock);
++
++      sc->sc_sessions = (struct pasemi_session **)
++              kzalloc(PASEMI_INITIAL_SESSIONS *
++                      sizeof(struct pasemi_session *), GFP_ATOMIC);
++      if (sc->sc_sessions == NULL) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      sc->sc_nsessions = PASEMI_INITIAL_SESSIONS;
++      sc->sc_lastchn = 0;
++      sc->base_irq = pdev->irq + 6;
++      sc->base_chan = 6;
++      sc->sc_cid = -1;
++      sc->dma_pdev = pdev;
++
++      sc->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
++      if (!sc->iob_pdev) {
++              dev_err(&pdev->dev, "Can't find I/O Bridge\n");
++              ret = -ENODEV;
++              goto out;
++      }
++
++      /* This is hardcoded and ugly, but we have some firmware versions
++       * who don't provide the register space in the device tree. Luckily
++       * they are at well-known locations so we can just do the math here.
++       */
++      sc->dma_regs =
++              ioremap(0xe0000000 + (sc->dma_pdev->devfn << 12), 0x2000);
++      sc->iob_regs =
++              ioremap(0xe0000000 + (sc->iob_pdev->devfn << 12), 0x2000);
++      if (!sc->dma_regs || !sc->iob_regs) {
++              dev_err(&pdev->dev, "Can't map registers\n");
++              ret = -ENODEV;
++              goto out;
++      }
++
++      dma_status = __ioremap(0xfd800000, 0x1000, 0);
++      if (!dma_status) {
++              ret = -ENODEV;
++              dev_err(&pdev->dev, "Can't map dmastatus space\n");
++              goto out;
++      }
++
++      sc->tx = (struct pasemi_fnu_txring *)
++              kzalloc(sizeof(struct pasemi_fnu_txring)
++                      * 8, GFP_KERNEL);
++      if (!sc->tx) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      /* Initialize the h/w */
++      out_le32(sc->dma_regs + PAS_DMA_COM_CFG,
++               (in_le32(sc->dma_regs + PAS_DMA_COM_CFG) |
++                PAS_DMA_COM_CFG_FWF));
++      out_le32(sc->dma_regs + PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
++
++      for (i = 0; i < PASEMI_FNU_CHANNELS; i++) {
++              sc->sc_num_channels++;
++              ret = pasemi_dma_setup_tx_resources(sc, i);
++              if (ret)
++                      goto out;
++      }
++
++      sc->sc_cid = crypto_get_driverid(softc_get_device(sc),
++                                       CRYPTOCAP_F_HARDWARE);
++      if (sc->sc_cid < 0) {
++              printk(KERN_ERR DRV_NAME ": could not get crypto driver id\n");
++              ret = -ENXIO;
++              goto out;
++      }
++
++      /* register algorithms with the framework */
++      printk(DRV_NAME ":");
++
++      crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++      crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++
++      return 0;
++
++out:
++      pasemi_dma_remove(pdev);
++      return ret;
++}
++
++#define MAX_RETRIES 5000
++
++static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan)
++{
++      struct pasemi_fnu_txring *ring = &sc->tx[chan];
++      int chan_index = chan + sc->base_chan;
++      int retries;
++      u32 stat;
++
++      /* Stop the channel */
++      out_le32(sc->dma_regs +
++               PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++               PAS_DMA_TXCHAN_TCMDSTA_ST);
++
++      for (retries = 0; retries < MAX_RETRIES; retries++) {
++              stat = in_le32(sc->dma_regs +
++                             PAS_DMA_TXCHAN_TCMDSTA(chan_index));
++              if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
++                      break;
++              cond_resched();
++      }
++
++      if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
++              dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n",
++                      chan_index);
++
++      /* Disable the channel */
++      out_le32(sc->dma_regs +
++               PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++               0);
++
++      if (ring->desc_info)
++              kfree((void *) ring->desc_info);
++      if (ring->desc)
++              dma_free_coherent(&sc->dma_pdev->dev,
++                                TX_RING_SIZE *
++                                2 * sizeof(u64),
++                                (void *) ring->desc, ring->dma);
++      if (ring->irq != -1)
++              free_irq(ring->irq, sc);
++
++      del_timer(&ring->crypto_timer);
++}
++
++static void __devexit pasemi_dma_remove(struct pci_dev *pdev)
++{
++      struct pasemi_softc *sc = pci_get_drvdata(pdev);
++      int i;
++
++      DPRINTF("%s()\n", __FUNCTION__);
++
++      if (sc->sc_cid >= 0) {
++              crypto_unregister_all(sc->sc_cid);
++      }
++
++      if (sc->tx) {
++              for (i = 0; i < sc->sc_num_channels; i++)
++                      pasemi_free_tx_resources(sc, i);
++
++              kfree(sc->tx);
++      }
++      if (sc->sc_sessions) {
++              for (i = 0; i < sc->sc_nsessions; i++)
++                      kfree(sc->sc_sessions[i]);
++              kfree(sc->sc_sessions);
++      }
++      if (sc->iob_pdev)
++              pci_dev_put(sc->iob_pdev);
++      if (sc->dma_regs)
++              iounmap(sc->dma_regs);
++      if (sc->iob_regs)
++              iounmap(sc->iob_regs);
++      kfree(sc);
++}
++
++static struct pci_device_id pasemi_dma_pci_tbl[] = {
++      { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa007) },
++};
++
++MODULE_DEVICE_TABLE(pci, pasemi_dma_pci_tbl);
++
++static struct pci_driver pasemi_dma_driver = {
++      .name           = "pasemi_dma",
++      .id_table       = pasemi_dma_pci_tbl,
++      .probe          = pasemi_dma_probe,
++      .remove         = __devexit_p(pasemi_dma_remove),
++};
++
++static void __exit pasemi_dma_cleanup_module(void)
++{
++      pci_unregister_driver(&pasemi_dma_driver);
++      __iounmap(dma_status);
++      dma_status = NULL;
++}
++
++int pasemi_dma_init_module(void)
++{
++      return pci_register_driver(&pasemi_dma_driver);
++}
++
++module_init(pasemi_dma_init_module);
++module_exit(pasemi_dma_cleanup_module);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Egor Martovetsky egor@pasemi.com");
++MODULE_DESCRIPTION("OCF driver for PA Semi PWRficient DMA Crypto Engine");
+--- /dev/null  2007-07-04 13:54:27.000000000 +1000
++++ linux/crypto/ocf/pasemi/pasemi_fnu.h       2007-12-12 11:36:18.000000000 +1000
+@@ -0,0 +1,410 @@
++/*
++ * Copyright (C) 2007 PA Semi, Inc
++ *
++ * Driver for the PA Semi PWRficient DMA Crypto Engine, soft state and
++ * hardware register layouts.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ */
++
++#ifndef PASEMI_FNU_H
++#define PASEMI_FNU_H
++
++#include <linux/spinlock.h>
++
++#define       PASEMI_SESSION(sid)     ((sid) & 0xffffffff)
++#define       PASEMI_SID(sesn)        ((sesn) & 0xffffffff)
++#define       DPRINTF(a...)   if (debug) { printk(DRV_NAME ": " a); }
++
++/* Must be a power of two */
++#define RX_RING_SIZE 512
++#define TX_RING_SIZE 512
++#define TX_DESC(ring, num)    ((ring)->desc[2 * (num & (TX_RING_SIZE-1))])
++#define TX_DESC_INFO(ring, num)       ((ring)->desc_info[(num) & (TX_RING_SIZE-1)])
++#define MAX_DESC_SIZE 8
++#define PASEMI_INITIAL_SESSIONS 10
++#define PASEMI_FNU_CHANNELS 8
++
++/* DMA descriptor */
++struct pasemi_desc {
++      u64 quad[2*MAX_DESC_SIZE];
++      int quad_cnt;
++      int size;
++      int postop;
++};
++
++/*
++ * Holds per descriptor data
++ */
++struct pasemi_desc_info {
++      int                     desc_size;
++      int                     desc_postop;
++#define PASEMI_CHECK_SIG 0x1
++
++      struct cryptop          *cf_crp;
++};
++
++/*
++ * Holds per channel data
++ */
++struct pasemi_fnu_txring {
++      volatile u64            *desc;
++      volatile struct
++      pasemi_desc_info        *desc_info;
++      dma_addr_t              dma;
++      struct timer_list       crypto_timer;
++      spinlock_t              fill_lock;
++      spinlock_t              clean_lock;
++      unsigned int            next_to_fill;
++      unsigned int            next_to_clean;
++      u16                     total_pktcnt;
++      int                     irq;
++      int                     sesn;
++      char                    irq_name[10];
++};
++
++/*
++ * Holds data specific to a single pasemi device.
++ */
++struct pasemi_softc {
++      softc_device_decl       sc_cdev;
++      struct pci_dev          *dma_pdev;      /* device backpointer */
++      struct pci_dev          *iob_pdev;      /* device backpointer */
++      void __iomem            *dma_regs;
++      void __iomem            *iob_regs;
++      int                     base_irq;
++      int                     base_chan;
++      int32_t                 sc_cid;         /* crypto tag */
++      int                     sc_nsessions;
++      struct pasemi_session   **sc_sessions;
++      int                     sc_num_channels;/* number of crypto channels */
++
++      /* pointer to the array of txring datastructures, one txring per channel */
++      struct pasemi_fnu_txring *tx;
++
++      /*
++       * mutual exclusion for the channel scheduler
++       */
++      spinlock_t              sc_chnlock;
++      /* last channel used, for now use round-robin to allocate channels */
++      int                     sc_lastchn;
++};
++
++struct pasemi_session {
++      u64 civ[2];
++      u64 keysz;
++      u64 key[4];
++      u64 ccmd;
++      u64 hkey[4];
++      u64 hseq;
++      u64 giv[2];
++      u64 hiv[4];
++
++      int used;
++      dma_addr_t      dma_addr;
++      int chan;
++};
++
++/* status register layout in IOB region, at 0xfd800000 */
++struct pasdma_status {
++      u64 rx_sta[64];
++      u64 tx_sta[20];
++};
++
++#define ALG_IS_CIPHER(alg) ((alg == CRYPTO_DES_CBC)           || \
++                              (alg == CRYPTO_3DES_CBC)        || \
++                              (alg == CRYPTO_AES_CBC)         || \
++                              (alg == CRYPTO_ARC4)            || \
++                              (alg == CRYPTO_NULL_CBC))
++
++#define ALG_IS_SIG(alg) ((alg == CRYPTO_MD5)                  || \
++                              (alg == CRYPTO_MD5_HMAC)        || \
++                              (alg == CRYPTO_SHA1)            || \
++                              (alg == CRYPTO_SHA1_HMAC)       || \
++                              (alg == CRYPTO_NULL_HMAC))
++
++enum {
++      PAS_DMA_COM_TXCMD = 0x100,      /* Transmit Command Register  */
++      PAS_DMA_COM_TXSTA = 0x104,      /* Transmit Status Register   */
++      PAS_DMA_COM_RXCMD = 0x108,      /* Receive Command Register   */
++      PAS_DMA_COM_RXSTA = 0x10c,      /* Receive Status Register    */
++      PAS_DMA_COM_CFG   = 0x114,      /* DMA Configuration Register */
++};
++
++/* All these registers live in the PCI configuration space for the DMA PCI
++ * device. Use the normal PCI config access functions for them.
++ */
++
++#define PAS_DMA_COM_CFG_FWF   0x18000000
++
++#define PAS_DMA_COM_TXCMD_EN  0x00000001 /* enable */
++#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */
++#define PAS_DMA_COM_RXCMD_EN  0x00000001 /* enable */
++#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */
++
++#define _PAS_DMA_TXCHAN_STRIDE        0x20    /* Size per channel             */
++#define _PAS_DMA_TXCHAN_TCMDSTA       0x300   /* Command / Status             */
++#define _PAS_DMA_TXCHAN_CFG   0x304   /* Configuration                */
++#define _PAS_DMA_TXCHAN_DSCRBU        0x308   /* Descriptor BU Allocation     */
++#define _PAS_DMA_TXCHAN_INCR  0x310   /* Descriptor increment         */
++#define _PAS_DMA_TXCHAN_CNT   0x314   /* Descriptor count/offset      */
++#define _PAS_DMA_TXCHAN_BASEL 0x318   /* Descriptor ring base (low)   */
++#define _PAS_DMA_TXCHAN_BASEU 0x31c   /*                      (high)  */
++#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define    PAS_DMA_TXCHAN_TCMDSTA_EN  0x00000001      /* Enabled */
++#define    PAS_DMA_TXCHAN_TCMDSTA_ST  0x00000002      /* Stop interface */
++#define    PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000      /* Active */
++#define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define    PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002      /* Type = interface */
++#define    PAS_DMA_TXCHAN_CFG_TY_IFACE        0x00000000      /* Type = interface */
++#define    PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
++#define    PAS_DMA_TXCHAN_CFG_TATTR_S 2
++#define    PAS_DMA_TXCHAN_CFG_TATTR(x)        (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
++                                       PAS_DMA_TXCHAN_CFG_TATTR_M)
++#define    PAS_DMA_TXCHAN_CFG_WT_M    0x000001c0
++#define    PAS_DMA_TXCHAN_CFG_WT_S    6
++#define    PAS_DMA_TXCHAN_CFG_WT(x)   (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
++                                       PAS_DMA_TXCHAN_CFG_WT_M)
++#define    PAS_DMA_TXCHAN_CFG_LPSQ_FAST       0x00000400
++#define    PAS_DMA_TXCHAN_CFG_LPDQ_FAST       0x00000800
++#define    PAS_DMA_TXCHAN_CFG_CF      0x00001000      /* Clean first line */
++#define    PAS_DMA_TXCHAN_CFG_CL      0x00002000      /* Clean last line */
++#define    PAS_DMA_TXCHAN_CFG_UP      0x00004000      /* update tx descr when sent */
++#define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define    PAS_DMA_TXCHAN_BASEL_BRBL_M        0xffffffc0
++#define    PAS_DMA_TXCHAN_BASEL_BRBL_S        0
++#define    PAS_DMA_TXCHAN_BASEL_BRBL(x)       (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
++                                       PAS_DMA_TXCHAN_BASEL_BRBL_M)
++#define PAS_DMA_TXCHAN_BASEU(c)   (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define    PAS_DMA_TXCHAN_BASEU_BRBH_M        0x00000fff
++#define    PAS_DMA_TXCHAN_BASEU_BRBH_S        0
++#define    PAS_DMA_TXCHAN_BASEU_BRBH(x)       (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
++                                       PAS_DMA_TXCHAN_BASEU_BRBH_M)
++/* # of cache lines worth of buffer ring */
++#define    PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000
++#define    PAS_DMA_TXCHAN_BASEU_SIZ_S 16              /* 0 = 16K */
++#define    PAS_DMA_TXCHAN_BASEU_SIZ(x)        (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
++                                       PAS_DMA_TXCHAN_BASEU_SIZ_M)
++
++#define    PAS_STATUS_PCNT_M          0x000000000000ffffull
++#define    PAS_STATUS_PCNT_S          0
++#define    PAS_STATUS_DCNT_M          0x00000000ffff0000ull
++#define    PAS_STATUS_DCNT_S          16
++#define    PAS_STATUS_BPCNT_M         0x0000ffff00000000ull
++#define    PAS_STATUS_BPCNT_S         32
++#define    PAS_STATUS_CAUSE_M         0xf000000000000000ull
++#define    PAS_STATUS_TIMER           0x1000000000000000ull
++#define    PAS_STATUS_ERROR           0x2000000000000000ull
++#define    PAS_STATUS_SOFT            0x4000000000000000ull
++#define    PAS_STATUS_INT             0x8000000000000000ull
++
++#define PAS_IOB_DMA_RXCH_CFG(i)               (0x1100 + (i)*4)
++#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M               0x00000fff
++#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S               0
++#define    PAS_IOB_DMA_RXCH_CFG_CNTTH(x)      (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
++                                               PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
++#define PAS_IOB_DMA_TXCH_CFG(i)               (0x1200 + (i)*4)
++#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_M               0x00000fff
++#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_S               0
++#define    PAS_IOB_DMA_TXCH_CFG_CNTTH(x)      (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
++                                               PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
++#define PAS_IOB_DMA_RXCH_STAT(i)      (0x1300 + (i)*4)
++#define    PAS_IOB_DMA_RXCH_STAT_INTGEN       0x00001000
++#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_M     0x00000fff
++#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_S     0
++#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL(x)    (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
++                                               PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
++#define PAS_IOB_DMA_TXCH_STAT(i)      (0x1400 + (i)*4)
++#define    PAS_IOB_DMA_TXCH_STAT_INTGEN       0x00001000
++#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_M     0x00000fff
++#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_S     0
++#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL(x)    (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
++                                               PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
++#define PAS_IOB_DMA_RXCH_RESET(i)     (0x1500 + (i)*4)
++#define    PAS_IOB_DMA_RXCH_RESET_PCNT_M      0xffff0000
++#define    PAS_IOB_DMA_RXCH_RESET_PCNT_S      16
++#define    PAS_IOB_DMA_RXCH_RESET_PCNT(x)     (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
++                                               PAS_IOB_DMA_RXCH_RESET_PCNT_M)
++#define    PAS_IOB_DMA_RXCH_RESET_PCNTRST     0x00000020
++#define    PAS_IOB_DMA_RXCH_RESET_DCNTRST     0x00000010
++#define    PAS_IOB_DMA_RXCH_RESET_TINTC               0x00000008
++#define    PAS_IOB_DMA_RXCH_RESET_DINTC               0x00000004
++#define    PAS_IOB_DMA_RXCH_RESET_SINTC               0x00000002
++#define    PAS_IOB_DMA_RXCH_RESET_PINTC               0x00000001
++#define PAS_IOB_DMA_TXCH_RESET(i)     (0x1600 + (i)*4)
++#define    PAS_IOB_DMA_TXCH_RESET_PCNT_M      0xffff0000
++#define    PAS_IOB_DMA_TXCH_RESET_PCNT_S      16
++#define    PAS_IOB_DMA_TXCH_RESET_PCNT(x)     (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
++                                               PAS_IOB_DMA_TXCH_RESET_PCNT_M)
++#define    PAS_IOB_DMA_TXCH_RESET_PCNTRST     0x00000020
++#define    PAS_IOB_DMA_TXCH_RESET_DCNTRST     0x00000010
++#define    PAS_IOB_DMA_TXCH_RESET_TINTC               0x00000008
++#define    PAS_IOB_DMA_TXCH_RESET_DINTC               0x00000004
++#define    PAS_IOB_DMA_TXCH_RESET_SINTC               0x00000002
++#define    PAS_IOB_DMA_TXCH_RESET_PINTC               0x00000001
++
++#define PAS_IOB_DMA_COM_TIMEOUTCFG            0x1700
++#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M  0x00ffffff
++#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S  0
++#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
++                                               PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
++
++/* Transmit descriptor fields */
++#define       XCT_MACTX_T             0x8000000000000000ull
++#define       XCT_MACTX_ST            0x4000000000000000ull
++#define XCT_MACTX_NORES               0x0000000000000000ull
++#define XCT_MACTX_8BRES               0x1000000000000000ull
++#define XCT_MACTX_24BRES      0x2000000000000000ull
++#define XCT_MACTX_40BRES      0x3000000000000000ull
++#define XCT_MACTX_I           0x0800000000000000ull
++#define XCT_MACTX_O           0x0400000000000000ull
++#define XCT_MACTX_E           0x0200000000000000ull
++#define XCT_MACTX_VLAN_M      0x0180000000000000ull
++#define XCT_MACTX_VLAN_NOP    0x0000000000000000ull
++#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull
++#define XCT_MACTX_VLAN_INSERT   0x0100000000000000ull
++#define XCT_MACTX_VLAN_REPLACE  0x0180000000000000ull
++#define XCT_MACTX_CRC_M               0x0060000000000000ull
++#define XCT_MACTX_CRC_NOP     0x0000000000000000ull
++#define XCT_MACTX_CRC_INSERT  0x0020000000000000ull
++#define XCT_MACTX_CRC_PAD     0x0040000000000000ull
++#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull
++#define XCT_MACTX_SS          0x0010000000000000ull
++#define XCT_MACTX_LLEN_M      0x00007fff00000000ull
++#define XCT_MACTX_LLEN_S      32ull
++#define XCT_MACTX_LLEN(x)     ((((long)(x)) << XCT_MACTX_LLEN_S) & \
++                               XCT_MACTX_LLEN_M)
++#define XCT_MACTX_IPH_M               0x00000000f8000000ull
++#define XCT_MACTX_IPH_S               27ull
++#define XCT_MACTX_IPH(x)      ((((long)(x)) << XCT_MACTX_IPH_S) & \
++                               XCT_MACTX_IPH_M)
++#define XCT_MACTX_IPO_M               0x0000000007c00000ull
++#define XCT_MACTX_IPO_S               22ull
++#define XCT_MACTX_IPO(x)      ((((long)(x)) << XCT_MACTX_IPO_S) & \
++                               XCT_MACTX_IPO_M)
++#define XCT_MACTX_CSUM_M      0x0000000000000060ull
++#define XCT_MACTX_CSUM_NOP    0x0000000000000000ull
++#define XCT_MACTX_CSUM_TCP    0x0000000000000040ull
++#define XCT_MACTX_CSUM_UDP    0x0000000000000060ull
++#define XCT_MACTX_V6          0x0000000000000010ull
++#define XCT_MACTX_C           0x0000000000000004ull
++#define XCT_MACTX_AL2         0x0000000000000002ull
++
++#define XCT_PTR_T             0x8000000000000000ull
++#define XCT_PTR_LEN_M         0x7ffff00000000000ull
++#define XCT_PTR_LEN_S         44
++#define XCT_PTR_LEN(x)                ((((long)(x)) << XCT_PTR_LEN_S) & \
++                               XCT_PTR_LEN_M)
++#define XCT_PTR_ADDR_M                0x00000fffffffffffull
++#define XCT_PTR_ADDR_S                0
++#define XCT_PTR_ADDR(x)               ((((long)(x)) << XCT_PTR_ADDR_S) & \
++                               XCT_PTR_ADDR_M)
++
++/* Function descriptor fields */
++#define       XCT_FUN_T               0x8000000000000000ull
++#define       XCT_FUN_ST              0x4000000000000000ull
++#define XCT_FUN_NORES         0x0000000000000000ull
++#define XCT_FUN_8BRES         0x1000000000000000ull
++#define XCT_FUN_24BRES                0x2000000000000000ull
++#define XCT_FUN_40BRES                0x3000000000000000ull
++#define XCT_FUN_I             0x0800000000000000ull
++#define XCT_FUN_O             0x0400000000000000ull
++#define XCT_FUN_E             0x0200000000000000ull
++#define XCT_FUN_FUN_S         54
++#define XCT_FUN_FUN_M         0x01c0000000000000ull
++#define XCT_FUN_FUN(num)      ((((long)(num)) << XCT_FUN_FUN_S) & \
++                              XCT_FUN_FUN_M)
++#define XCT_FUN_CRM_NOP               0x0000000000000000ull
++#define XCT_FUN_CRM_SIG               0x0008000000000000ull
++#define XCT_FUN_CRM_ENC               0x0010000000000000ull
++#define XCT_FUN_CRM_DEC               0x0018000000000000ull
++#define XCT_FUN_CRM_SIG_ENC   0x0020000000000000ull
++#define XCT_FUN_CRM_ENC_SIG   0x0028000000000000ull
++#define XCT_FUN_CRM_SIG_DEC   0x0030000000000000ull
++#define XCT_FUN_CRM_DEC_SIG   0x0038000000000000ull
++#define XCT_FUN_LLEN_M                0x0007ffff00000000ull
++#define XCT_FUN_LLEN_S                32ULL
++#define XCT_FUN_LLEN(x)               ((((long)(x)) << XCT_FUN_LLEN_S) & \
++                               XCT_FUN_LLEN_M)
++#define XCT_FUN_SHL_M         0x00000000f8000000ull
++#define XCT_FUN_SHL_S         27ull
++#define XCT_FUN_SHL(x)                ((((long)(x)) << XCT_FUN_SHL_S) & \
++                               XCT_FUN_SHL_M)
++#define XCT_FUN_CHL_M         0x0000000007c00000ull
++#define XCT_FUN_CHL_S         22ull
++#define XCT_FUN_CHL(x)                ((((long)(x)) << XCT_FUN_CHL_S) & \
++                               XCT_FUN_CHL_M)
++#define XCT_FUN_HSZ_M         0x00000000003c0000ull
++#define XCT_FUN_HSZ_S         18ull
++#define XCT_FUN_HSZ(x)                ((((long)(x)) << XCT_FUN_HSZ_S) & \
++                               XCT_FUN_HSZ_M)
++#define XCT_FUN_ALG_DES               0x0000000000000000ull
++#define XCT_FUN_ALG_3DES      0x0000000000008000ull
++#define XCT_FUN_ALG_AES               0x0000000000010000ull
++#define XCT_FUN_ALG_ARC               0x0000000000018000ull
++#define XCT_FUN_ALG_KASUMI    0x0000000000020000ull
++#define XCT_FUN_BCM_ECB               0x0000000000000000ull
++#define XCT_FUN_BCM_CBC               0x0000000000001000ull
++#define XCT_FUN_BCM_CFB               0x0000000000002000ull
++#define XCT_FUN_BCM_OFB               0x0000000000003000ull
++#define XCT_FUN_BCM_CNT               0x0000000000003800ull
++#define XCT_FUN_BCM_KAS_F8    0x0000000000002800ull
++#define XCT_FUN_BCM_KAS_F9    0x0000000000001800ull
++#define XCT_FUN_BCP_NO_PAD    0x0000000000000000ull
++#define XCT_FUN_BCP_ZRO               0x0000000000000200ull
++#define XCT_FUN_BCP_PL                0x0000000000000400ull
++#define XCT_FUN_BCP_INCR      0x0000000000000600ull
++#define XCT_FUN_SIG_MD5               (0ull << 4)
++#define XCT_FUN_SIG_SHA1      (2ull << 4)
++#define XCT_FUN_SIG_HMAC_MD5  (8ull << 4)
++#define XCT_FUN_SIG_HMAC_SHA1 (10ull << 4)
++#define XCT_FUN_A             0x0000000000000008ull
++#define XCT_FUN_C             0x0000000000000004ull
++#define XCT_FUN_AL2           0x0000000000000002ull
++#define XCT_FUN_SE            0x0000000000000001ull
++
++#define XCT_FUN_SRC_PTR(len, addr)    (XCT_PTR_LEN(len) | XCT_PTR_ADDR(addr))
++#define XCT_FUN_DST_PTR(len, addr)    (XCT_FUN_SRC_PTR(len, addr) | \
++                                      0x8000000000000000ull)
++
++#define XCT_CTRL_HDR_FUN_NUM_M                0x01c0000000000000ull
++#define XCT_CTRL_HDR_FUN_NUM_S                54
++#define XCT_CTRL_HDR_LEN_M            0x0007ffff00000000ull
++#define XCT_CTRL_HDR_LEN_S            32
++#define XCT_CTRL_HDR_REG_M            0x00000000000000ffull
++#define XCT_CTRL_HDR_REG_S            0
++
++#define XCT_CTRL_HDR(funcN,len,reg)   (0x9400000000000000ull | \
++                      ((((long)(funcN)) << XCT_CTRL_HDR_FUN_NUM_S) \
++                      & XCT_CTRL_HDR_FUN_NUM_M) | \
++                      ((((long)(len)) << \
++                      XCT_CTRL_HDR_LEN_S) & XCT_CTRL_HDR_LEN_M) | \
++                      ((((long)(reg)) << \
++                      XCT_CTRL_HDR_REG_S) & XCT_CTRL_HDR_REG_M))
++
++/* Function config command options */
++#define       DMA_CALGO_DES                   0x00
++#define       DMA_CALGO_3DES                  0x01
++#define       DMA_CALGO_AES                   0x02
++#define       DMA_CALGO_ARC                   0x03
++
++#define DMA_FN_CIV0                   0x02
++#define DMA_FN_CIV1                   0x03
++#define DMA_FN_HKEY0                  0x0a
++
++#define XCT_PTR_ADDR_LEN(ptr)         ((ptr) & XCT_PTR_ADDR_M), \
++                      (((ptr) & XCT_PTR_LEN_M) >> XCT_PTR_LEN_S)
++
++#endif /* PASEMI_FNU_H */
diff --git a/target/linux/generic-2.6/patches-2.6.25/951-ocf-scatterlist-inc.patch b/target/linux/generic-2.6/patches-2.6.25/951-ocf-scatterlist-inc.patch
new file mode 100644 (file)
index 0000000..6148490
--- /dev/null
@@ -0,0 +1,11 @@
+diff -Nru linux-2.6.25.10-old/crypto/ocf/cryptosoft.c linux-2.6.25.10/crypto/ocf/cryptosoft.c
+--- linux-2.6.25.10-old/crypto/ocf/cryptosoft.c        2008-07-08 23:38:58.114980680 +0200
++++ linux-2.6.25.10/crypto/ocf/cryptosoft.c    2008-07-08 23:31:15.866980267 +0200
+@@ -48,6 +48,7 @@
+ #include <linux/skbuff.h>
+ #include <linux/random.h>
+ #include <asm/scatterlist.h>
++#include <linux/scatterlist.h>
+ #include <cryptodev.h>
+ #include <uio.h>
This page took 0.425404 seconds and 4 git commands to generate.