NetBSD/sys/dev/pci/hifn7751.c
sommerfeld 851de295eb Change pci_intr_map to get interrupt source information from a "struct
pci_attach_args *" instead of from four separate parameters which in
all cases were extracted from the same "struct pci_attach_args".

This both simplifies the driver api, and allows for alternate PCI
interrupt mapping schemes, such as one using the tables described in
the Intel Multiprocessor Spec which describe interrupt wirings for
devices behind pci-pci bridges based on the device's location rather
the bridge's location.

Tested on alpha and i386; welcome to 1.5Q
2000-12-28 22:59:06 +00:00

1464 lines
37 KiB
C

/* $NetBSD: hifn7751.c,v 1.2 2000/12/28 22:59:12 sommerfeld Exp $ */
/* $OpenBSD: hifn7751.c,v 1.47 2000/10/11 13:15:41 itojun Exp $ */
/*
* Invertex AEON / Hi/fn 7751 driver
* Copyright (c) 1999 Invertex Inc. All rights reserved.
* Copyright (c) 1999 Theo de Raadt
* Copyright (c) 2000 Network Security Technologies, Inc.
* http://www.netsec.net
*
* 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.
*/
/*
* Driver for the Hi/Fn 7751 encryption processor.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#ifdef __OpenBSD__
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
#else
#include <uvm/uvm.h>
#include <uvm/uvm_extern.h>
#include <uvm/uvm_pmap.h>
#endif
#include <machine/pmap.h>
#include <sys/device.h>
#ifdef __OpenBSD__
#include <crypto/crypto.h>
#include <dev/rndvar.h>
#endif
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/hifn7751var.h>
#include <dev/pci/hifn7751reg.h>
#undef HIFN_DEBUG
/*
* Prototypes and count for the pci_device structure
*/
#ifdef __OpenBSD__
int hifn_probe __P((struct device *, void *, void *));
#else
int hifn_probe __P((struct device *, struct cfdata *, void *));
#endif
void hifn_attach __P((struct device *, struct device *, void *));
struct cfattach hifn_ca = {
sizeof(struct hifn_softc), hifn_probe, hifn_attach,
};
#ifdef __OpenBSD__
struct cfdriver hifn_cd = {
0, "hifn", DV_DULL
};
#endif
void hifn_reset_board __P((struct hifn_softc *));
int hifn_enable_crypto __P((struct hifn_softc *, pcireg_t));
void hifn_init_dma __P((struct hifn_softc *));
void hifn_init_pci_registers __P((struct hifn_softc *));
int hifn_sramsize __P((struct hifn_softc *));
int hifn_dramsize __P((struct hifn_softc *));
void hifn_ramtype __P((struct hifn_softc *));
void hifn_sessions __P((struct hifn_softc *));
int hifn_intr __P((void *));
u_int hifn_write_command __P((struct hifn_command *, u_int8_t *));
u_int32_t hifn_next_signature __P((u_int32_t a, u_int cnt));
#ifdef __OpenBSD__
int hifn_newsession __P((u_int32_t *, struct cryptoini *));
int hifn_freesession __P((u_int64_t));
int hifn_process __P((struct cryptop *));
void hifn_callback __P((struct hifn_softc *, struct hifn_command *, u_int8_t *));
#endif
int hifn_crypto __P((struct hifn_softc *, hifn_command_t *));
int hifn_readramaddr __P((struct hifn_softc *, int, u_int8_t *, int));
int hifn_writeramaddr __P((struct hifn_softc *, int, u_int8_t *, int));
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;
} hifnstats;
int
hifn_probe(parent, match, aux)
struct device *parent;
#ifdef __OpenBSD__
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INVERTEX &&
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INVERTEX_AEON)
return (1);
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_7751)
return (1);
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NETSEC &&
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NETSEC_7751)
return (1);
return (0);
}
void
hifn_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct hifn_softc *sc = (struct hifn_softc *)self;
struct pci_attach_args *pa = aux;
pci_chipset_tag_t pc = pa->pa_pc;
pci_intr_handle_t ih;
const char *intrstr = NULL;
char rbase;
bus_size_t iosize0, iosize1;
u_int32_t cmd;
u_int16_t ena;
bus_dma_segment_t seg;
bus_dmamap_t dmamap;
int rseg;
caddr_t kva;
cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
cmd |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, cmd);
cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
if (!(cmd & PCI_COMMAND_MEM_ENABLE)) {
printf(": failed to enable memory mapping\n");
return;
}
if (pci_mapreg_map(pa, HIFN_BAR0, PCI_MAPREG_TYPE_MEM, 0,
&sc->sc_st0, &sc->sc_sh0, NULL, &iosize0)) {
printf(": can't find mem space %d\n", 0);
return;
}
if (pci_mapreg_map(pa, HIFN_BAR1, PCI_MAPREG_TYPE_MEM, 0,
&sc->sc_st1, &sc->sc_sh1, NULL, &iosize1)) {
printf(": can't find mem space %d\n", 1);
goto fail_io0;
}
sc->sc_dmat = pa->pa_dmat;
if (bus_dmamem_alloc(sc->sc_dmat, sizeof(*sc->sc_dma), PAGE_SIZE, 0,
&seg, 1, &rseg, BUS_DMA_NOWAIT)) {
printf(": can't alloc dma buffer\n");
goto fail_io1;
}
if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, sizeof(*sc->sc_dma), &kva,
BUS_DMA_NOWAIT)) {
printf(": can't map dma buffers (%lu bytes)\n",
(u_long)sizeof(*sc->sc_dma));
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
goto fail_io1;
}
if (bus_dmamap_create(sc->sc_dmat, sizeof(*sc->sc_dma), 1,
sizeof(*sc->sc_dma), 0, BUS_DMA_NOWAIT, &dmamap)) {
printf(": can't create dma map\n");
bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(*sc->sc_dma));
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
goto fail_io1;
}
if (bus_dmamap_load(sc->sc_dmat, dmamap, kva, sizeof(*sc->sc_dma),
NULL, BUS_DMA_NOWAIT)) {
printf(": can't load dma map\n");
bus_dmamap_destroy(sc->sc_dmat, dmamap);
bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(*sc->sc_dma));
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
goto fail_io1;
}
sc->sc_dma = (struct hifn_dma *)kva;
bzero(sc->sc_dma, sizeof(*sc->sc_dma));
hifn_reset_board(sc);
if (hifn_enable_crypto(sc, pa->pa_id) != 0) {
printf("%s: crypto enabling failed\n", sc->sc_dv.dv_xname);
goto fail_mem;
}
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
hifn_ramtype(sc);
if (sc->sc_drammodel == 0)
hifn_sramsize(sc);
else
hifn_dramsize(sc);
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NETSEC &&
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NETSEC_7751 &&
PCI_REVISION(pa->pa_class) == 0x61)
sc->sc_ramsize >>= 1;
/*
* Reinitialize again, since the DRAM/SRAM detection shifted our ring
* pointers and may have changed the value we send to the RAM Config
* Register.
*/
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
if (pci_intr_map(pa, &ih)) {
printf(": couldn't map interrupt\n");
goto fail_mem;
}
intrstr = pci_intr_string(pc, ih);
#ifdef __OpenBSD__
sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, hifn_intr, sc,
self->dv_xname);
#else
sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, hifn_intr, sc);
#endif
if (sc->sc_ih == NULL) {
printf(": couldn't establish interrupt\n");
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
goto fail_mem;
}
hifn_sessions(sc);
rseg = sc->sc_ramsize / 1024;
rbase = 'K';
if (sc->sc_ramsize >= (1024 * 1024)) {
rbase = 'M';
rseg /= 1024;
}
printf(", %d%cB %cram, %s\n", rseg, rbase,
sc->sc_drammodel ? 'd' : 's', intrstr);
#ifdef __OpenBSD__
sc->sc_cid = crypto_get_driverid();
if (sc->sc_cid < 0)
goto fail_intr;
#endif
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;
#ifdef __OpenBSD__
switch (ena) {
case HIFN_PUSTAT_ENA_2:
crypto_register(sc->sc_cid, CRYPTO_3DES_CBC,
hifn_newsession, hifn_freesession, hifn_process);
/*FALLTHROUGH*/
case HIFN_PUSTAT_ENA_1:
crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC96,
hifn_newsession, hifn_freesession, hifn_process);
crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC96,
NULL, NULL, NULL);
crypto_register(sc->sc_cid, CRYPTO_DES_CBC,
NULL, NULL, NULL);
}
#endif
return;
#ifdef __OpenBSD__
fail_intr:
#endif
pci_intr_disestablish(pc, sc->sc_ih);
fail_mem:
bus_dmamap_unload(sc->sc_dmat, dmamap);
bus_dmamap_destroy(sc->sc_dmat, dmamap);
bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(*sc->sc_dma));
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
fail_io1:
bus_space_unmap(sc->sc_st1, sc->sc_sh1, iosize1);
fail_io0:
bus_space_unmap(sc->sc_st0, sc->sc_sh0, iosize0);
}
/*
* Resets the board. Values in the regesters are left as is
* from the reset (i.e. initial values are assigned elsewhere).
*/
void
hifn_reset_board(sc)
struct hifn_softc *sc;
{
/*
* 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 board. We do this by writing zeros to the DMA reset
* field, the BRD reset field, and the manditory 1 at position 2.
* Every other field is set to zero.
*/
WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
/*
* Wait another millisecond for the board to reset.
*/
DELAY(1000);
/*
* Turn off the reset! (No joke.)
*/
WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
}
u_int32_t
hifn_next_signature(a, cnt)
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;
}
struct pci2id {
u_short pci_vendor;
u_short pci_prod;
char card_id[13];
} pci2id[] = {
{
PCI_VENDOR_NETSEC,
PCI_PRODUCT_NETSEC_7751,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 }
}, {
PCI_VENDOR_INVERTEX,
PCI_PRODUCT_INVERTEX_AEON,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 }
}, {
/*
* 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,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 }
},
};
/*
* 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.
*/
int
hifn_enable_crypto(sc, pciid)
struct hifn_softc *sc;
pcireg_t pciid;
{
u_int32_t dmacfg, ramcfg, encl, addr, i;
char *offtbl = NULL;
for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) {
if (pci2id[i].pci_vendor == PCI_VENDOR(pciid) &&
pci2id[i].pci_prod == PCI_PRODUCT(pciid)) {
offtbl = pci2id[i].card_id;
break;
}
}
if (offtbl == NULL) {
#ifdef HIFN_DEBUG
printf("%s: Unknown card!\n", sc->sc_dv.dv_xname);
#endif
return (1);
}
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
printf("%s: Strong Crypto already enabled!\n",
sc->sc_dv.dv_xname);
#endif
WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg);
WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg);
return 0; /* success */
}
if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) {
#ifdef HIFN_DEBUG
printf("%s: Unknown encryption level\n", sc->sc_dv.dv_xname);
#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 (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2)
printf("Encryption engine is permanently locked until next system reset.");
else
printf("Encryption engine enabled successfully!");
#endif
WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg);
WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg);
switch (encl) {
case HIFN_PUSTAT_ENA_0:
printf(": no encr/auth");
break;
case HIFN_PUSTAT_ENA_1:
printf(": DES enabled");
break;
case HIFN_PUSTAT_ENA_2:
printf(": fully enabled");
break;
default:
printf(": disabled");
break;
}
return 0;
}
/*
* Give initial values to the registers listed in the "Register Space"
* section of the HIFN Software Development reference manual.
*/
void
hifn_init_pci_registers(sc)
struct hifn_softc *sc;
{
/* 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, vtophys((vaddr_t)sc->sc_dma->cmdr));
WRITE_REG_1(sc, HIFN_1_DMA_SRAR, vtophys((vaddr_t)sc->sc_dma->srcr));
WRITE_REG_1(sc, HIFN_1_DMA_DRAR, vtophys((vaddr_t)sc->sc_dma->dstr));
WRITE_REG_1(sc, HIFN_1_DMA_RRAR, vtophys((vaddr_t)sc->sc_dma->resr));
/* write status register */
WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA |
HIFN_DMACSR_R_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
HIFN_DMACSR_C_CTRL_ENA);
WRITE_REG_1(sc, HIFN_1_DMA_IER, HIFN_DMAIER_R_DONE);
#if 0
#if BYTE_ORDER == BIG_ENDIAN
(0x1 << 7) |
#endif
#endif
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.
*/
void
hifn_sessions(sc)
struct hifn_softc *sc;
{
u_int32_t pucnfg;
int ctxsize;
pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG);
if (pucnfg & HIFN_PUCNFG_COMPSING) {
if (pucnfg & HIFN_PUCNFG_ENCCNFG)
ctxsize = 128;
else
ctxsize = 512;
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;
}
void
hifn_ramtype(sc)
struct hifn_softc *sc;
{
u_int8_t data[8], dataexpect[8];
int i;
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
for (i = 0; i < sizeof(data); i++)
data[i] = dataexpect[i] = 0x55;
if (hifn_writeramaddr(sc, 0, data, 0) < 0)
return;
if (hifn_readramaddr(sc, 0, data, 1) < 0)
return;
if (bcmp(data, dataexpect, sizeof(data)) != 0) {
sc->sc_drammodel = 1;
return;
}
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
for (i = 0; i < sizeof(data); i++)
data[i] = dataexpect[i] = 0xaa;
if (hifn_writeramaddr(sc, 0, data, 0) < 0)
return;
if (hifn_readramaddr(sc, 0, data, 1) < 0)
return;
if (bcmp(data, dataexpect, sizeof(data)) != 0)
sc->sc_drammodel = 1;
}
/*
* For sram boards, just write/read memory until it fails, also check for
* banking.
*/
int
hifn_sramsize(sc)
struct hifn_softc *sc;
{
u_int32_t a = 0, end;
u_int8_t data[8], dataexpect[8];
for (a = 0; a < sizeof(data); a++)
data[a] = dataexpect[a] = 0x5a;
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
end = 1 << 20; /* 1MB */
for (a = 0; a < end; a += 16384) {
if (hifn_writeramaddr(sc, a, data, 0) < 0)
return (0);
if (hifn_readramaddr(sc, a, data, 1) < 0)
return (0);
if (bcmp(data, dataexpect, sizeof(data)) != 0)
return (0);
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
sc->sc_ramsize = a + 16384;
}
for (a = 0; a < sizeof(data); a++)
data[a] = dataexpect[a] = 0xa5;
if (hifn_writeramaddr(sc, 0, data, 0) < 0)
return (0);
end = sc->sc_ramsize;
for (a = 0; a < end; a += 16384) {
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
if (hifn_readramaddr(sc, a, data, 0) < 0)
return (0);
if (a != 0 && bcmp(data, dataexpect, sizeof(data)) == 0)
return (0);
sc->sc_ramsize = a + 16384;
}
hifn_reset_board(sc);
hifn_init_dma(sc);
hifn_init_pci_registers(sc);
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.
*/
int
hifn_dramsize(sc)
struct hifn_softc *sc;
{
u_int32_t cnfg;
cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) &
HIFN_PUCNFG_DRAMMASK;
sc->sc_ramsize = 1 << ((cnfg >> 13) + 18);
return (0);
}
int
hifn_writeramaddr(sc, addr, data, slot)
struct hifn_softc *sc;
int addr, slot;
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;
u_int64_t src, dst;
wc.masks = 3 << 13;
wc.session_num = addr >> 14;
wc.total_source_count = 8;
wc.total_dest_count = addr & 0x3fff;;
/* build write command */
*(hifn_base_command_t *) sc->sc_dma->command_bufs[slot] = wc;
bcopy(data, &src, sizeof(src));
dma->srcr[slot].p = vtophys((vaddr_t)&src);
dma->dstr[slot].p = vtophys((vaddr_t)&dst);
dma->cmdr[slot].l = 16 | masks;
dma->srcr[slot].l = 8 | masks;
dma->dstr[slot].l = 8 | masks;
dma->resr[slot].l = HIFN_MAX_RESULT | masks;
DELAY(1000); /* let write command execute */
if (dma->resr[slot].l & HIFN_D_VALID) {
printf("%s: SRAM/DRAM detection error -- "
"result[%d] valid still set\n", sc->sc_dv.dv_xname, slot);
return (-1);
}
return (0);
}
int
hifn_readramaddr(sc, addr, data, slot)
struct hifn_softc *sc;
int addr, slot;
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;
u_int64_t src, dst;
rc.masks = 2 << 13;
rc.session_num = addr >> 14;
rc.total_source_count = addr & 0x3fff;
rc.total_dest_count = 8;
*(hifn_base_command_t *) sc->sc_dma->command_bufs[slot] = rc;
dma->srcr[slot].p = vtophys((vaddr_t)&src);
dma->dstr[slot].p = vtophys((vaddr_t)&dst);
dma->cmdr[slot].l = 16 | masks;
dma->srcr[slot].l = 8 | masks;
dma->dstr[slot].l = 8 | masks;
dma->resr[slot].l = HIFN_MAX_RESULT | masks;
DELAY(1000); /* let read command execute */
if (dma->resr[slot].l & HIFN_D_VALID) {
printf("%s: SRAM/DRAM detection error -- "
"result[%d] valid still set\n", sc->sc_dv.dv_xname, slot);
return (-1);
}
bcopy(&dst, data, sizeof(dst));
return (0);
}
/*
* Initialize the descriptor rings.
*/
void
hifn_init_dma(sc)
struct hifn_softc *sc;
{
struct hifn_dma *dma = sc->sc_dma;
int i;
/* initialize static pointer values */
for (i = 0; i < HIFN_D_CMD_RSIZE; i++)
dma->cmdr[i].p = vtophys((vaddr_t)dma->command_bufs[i]);
for (i = 0; i < HIFN_D_RES_RSIZE; i++)
dma->resr[i].p = vtophys((vaddr_t)dma->result_bufs[i]);
dma->cmdr[HIFN_D_CMD_RSIZE].p = vtophys((vaddr_t)dma->cmdr);
dma->srcr[HIFN_D_SRC_RSIZE].p = vtophys((vaddr_t)dma->srcr);
dma->dstr[HIFN_D_DST_RSIZE].p = vtophys((vaddr_t)dma->dstr);
dma->resr[HIFN_D_RES_RSIZE].p = vtophys((vaddr_t)dma->resr);
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.
*/
u_int
hifn_write_command(cmd, buf)
struct hifn_command *cmd;
u_int8_t *buf;
{
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;
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 = cmd->base_masks;
base_cmd->total_source_count = cmd->src_l;
base_cmd->total_dest_count = cmd->dst_l;
base_cmd->session_num = cmd->session_num;
buf_pos += sizeof(hifn_base_command_t);
if (using_mac) {
mac_cmd = (hifn_mac_command_t *)buf_pos;
mac_cmd->masks = cmd->mac_masks;
mac_cmd->header_skip = cmd->mac_header_skip;
mac_cmd->source_count = cmd->mac_process_len;
buf_pos += sizeof(hifn_mac_command_t);
}
if (using_crypt) {
cry_cmd = (hifn_crypt_command_t *)buf_pos;
cry_cmd->masks = cmd->cry_masks;
cry_cmd->header_skip = cmd->crypt_header_skip;
cry_cmd->source_count = cmd->crypt_process_len;
buf_pos += sizeof(hifn_crypt_command_t);
}
if (using_mac && mac_cmd->masks & HIFN_MAC_CMD_NEW_KEY) {
bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH);
buf_pos += HIFN_MAC_KEY_LENGTH;
}
if (using_crypt && cry_cmd->masks & HIFN_CRYPT_CMD_NEW_KEY) {
len = (cry_cmd->masks & HIFN_CRYPT_CMD_ALG_3DES) ?
HIFN_3DES_KEY_LENGTH : HIFN_DES_KEY_LENGTH;
bcopy(cmd->ck, buf_pos, len);
buf_pos += len;
}
if (using_crypt && cry_cmd->masks & HIFN_CRYPT_CMD_NEW_IV) {
bcopy(cmd->iv, buf_pos, HIFN_IV_LENGTH);
buf_pos += HIFN_IV_LENGTH;
}
if ((base_cmd->masks & (HIFN_BASE_CMD_MAC | HIFN_BASE_CMD_CRYPT)) == 0) {
bzero(buf_pos, 8);
buf_pos += 8;
}
return (buf_pos - buf);
}
int
hifn_crypto(sc, cmd)
struct hifn_softc *sc;
struct hifn_command *cmd;
{
#ifndef __OpenBSD__
return -1;
#else
u_int32_t cmdlen;
struct hifn_dma *dma = sc->sc_dma;
int cmdi, srci, dsti, resi, nicealign = 0;
int s, i;
if (cmd->src_npa == 0 && cmd->src_m)
cmd->src_l = mbuf2pages(cmd->src_m, &cmd->src_npa,
cmd->src_packp, cmd->src_packl, MAX_SCATTER, &nicealign);
if (cmd->src_l == 0)
return (-1);
if (nicealign == 0) {
int totlen, len;
struct mbuf *m, *top, **mp;
totlen = cmd->dst_l = cmd->src_l;
if (cmd->src_m->m_flags & M_PKTHDR) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
M_COPY_PKTHDR(m, cmd->src_m);
len = MHLEN;
} else {
MGET(m, M_DONTWAIT, MT_DATA);
len = MLEN;
}
if (m == NULL)
return (-1);
if (totlen >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
len = MCLBYTES;
}
m->m_len = len;
top = NULL;
mp = &top;
while (totlen > 0) {
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
m_freem(top);
return (-1);
}
len = MLEN;
}
if (top && totlen >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
len = MCLBYTES;
}
m->m_len = len;
totlen -= len;
*mp = m;
mp = &m->m_next;
}
cmd->dst_m = top;
}
else
cmd->dst_m = cmd->src_m;
cmd->dst_l = mbuf2pages(cmd->dst_m, &cmd->dst_npa,
cmd->dst_packp, cmd->dst_packl, MAX_SCATTER, NULL);
if (cmd->dst_l == 0)
return (-1);
#ifdef HIFN_DEBUG
printf("%s: Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n",
sc->sc_dv.dv_xname,
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_npa,
cmd->dst_npa);
#endif
s = splnet();
/*
* need 1 cmd, and 1 res
* need N src, and N dst
*/
if (dma->cmdu+1 > HIFN_D_CMD_RSIZE ||
dma->srcu+cmd->src_npa > HIFN_D_SRC_RSIZE ||
dma->dstu+cmd->dst_npa > HIFN_D_DST_RSIZE ||
dma->resu+1 > HIFN_D_RES_RSIZE) {
splx(s);
return (HIFN_CRYPTO_RINGS_FULL);
}
if (dma->cmdi == HIFN_D_CMD_RSIZE) {
dma->cmdi = 0;
dma->cmdr[HIFN_D_CMD_RSIZE].l = HIFN_D_VALID | HIFN_D_LAST |
HIFN_D_MASKDONEIRQ | HIFN_D_JUMP;
}
cmdi = dma->cmdi++;
if (dma->resi == HIFN_D_RES_RSIZE) {
dma->resi = 0;
dma->resr[HIFN_D_RES_RSIZE].l = HIFN_D_VALID | HIFN_D_LAST |
HIFN_D_MASKDONEIRQ | HIFN_D_JUMP;
}
resi = dma->resi++;
cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]);
#ifdef HIFN_DEBUG
printf("write_command %d (nice %d)\n", cmdlen, nicealign);
#endif
/* .p for command/result already set */
dma->cmdr[cmdi].l = cmdlen | HIFN_D_VALID | HIFN_D_LAST |
HIFN_D_MASKDONEIRQ;
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)
WRITE_REG_1(sc, HIFN_1_DMA_IER,
HIFN_DMAIER_C_WAIT | HIFN_DMAIER_R_DONE);
hifnstats.hst_ipackets++;
for (i = 0; i < cmd->src_npa; i++) {
int last = 0;
if (i == cmd->src_npa-1)
last = HIFN_D_LAST;
if (dma->srci == HIFN_D_SRC_RSIZE) {
srci = 0, dma->srci = 1;
dma->srcr[HIFN_D_SRC_RSIZE].l = HIFN_D_VALID |
HIFN_D_MASKDONEIRQ | HIFN_D_JUMP | HIFN_D_LAST;
} else
srci = dma->srci++;
dma->srcr[srci].p = cmd->src_packp[i];
dma->srcr[srci].l = cmd->src_packl[i] | HIFN_D_VALID |
HIFN_D_MASKDONEIRQ | last;
hifnstats.hst_ibytes += cmd->src_packl[i];
}
dma->srcu += cmd->src_npa;
for (i = 0; i < cmd->dst_npa; i++) {
int last = 0;
if (i == cmd->dst_npa-1)
last = HIFN_D_LAST;
if (dma->dsti == HIFN_D_DST_RSIZE) {
dsti = 0, dma->dsti = 1;
dma->dstr[HIFN_D_DST_RSIZE].l = HIFN_D_VALID |
HIFN_D_MASKDONEIRQ | HIFN_D_JUMP | HIFN_D_LAST;
} else
dsti = dma->dsti++;
dma->dstr[dsti].p = cmd->dst_packp[i];
dma->dstr[dsti].l = cmd->dst_packl[i] | HIFN_D_VALID |
HIFN_D_MASKDONEIRQ | last;
}
dma->dstu += cmd->dst_npa;
/*
* Unlike other descriptors, we don't mask done interrupt from
* result descriptor.
*/
#ifdef HIFN_DEBUG
printf("load res\n");
#endif
dma->hifn_commands[resi] = cmd;
dma->resr[resi].l = HIFN_MAX_RESULT | HIFN_D_VALID | HIFN_D_LAST;
dma->resu++;
#ifdef HIFN_DEBUG
printf("%s: command: stat %8x ier %8x\n",
sc->sc_dv.dv_xname,
READ_REG_1(sc, HIFN_1_DMA_CSR), READ_REG_1(sc, HIFN_1_DMA_IER));
#endif
splx(s);
return 0; /* success */
#endif
}
int
hifn_intr(arg)
void *arg;
{
struct hifn_softc *sc = arg;
struct hifn_dma *dma = sc->sc_dma;
u_int32_t dmacsr;
int i, u;
dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR);
#ifdef HIFN_DEBUG
printf("%s: irq: stat %08x ien %08x u %d/%d/%d/%d\n",
sc->sc_dv.dv_xname,
dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER),
dma->cmdu, dma->srcu, dma->dstu, dma->resu);
#endif
if ((dmacsr & (HIFN_DMACSR_R_DONE | HIFN_DMACSR_C_WAIT)) == 0)
return (0);
if (dma->resu > HIFN_D_RES_RSIZE)
printf("%s: Internal Error -- ring overflow\n",
sc->sc_dv.dv_xname);
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).
*/
WRITE_REG_1(sc, HIFN_1_DMA_IER, HIFN_DMAIER_R_DONE);
}
while (dma->resu > 0) {
struct hifn_command *cmd;
u_int8_t *macbuf = NULL;
cmd = dma->hifn_commands[dma->resk];
/* if still valid, stop processing */
if (dma->resr[dma->resk].l & HIFN_D_VALID)
break;
if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
macbuf = dma->result_bufs[dma->resk];
macbuf += 12;
}
#ifdef __OpenBSD__
hifn_callback(sc, cmd, macbuf);
#endif
if (++dma->resk == HIFN_D_RES_RSIZE)
dma->resk = 0;
dma->resu--;
hifnstats.hst_opackets++;
}
/* clear the rings */
i = dma->srck; u = dma->srcu;
while (u != 0 && (dma->srcr[i].l & HIFN_D_VALID) == 0) {
if (++i == HIFN_D_SRC_RSIZE)
i = 0;
u--;
}
dma->srck = i; dma->srcu = u;
i = dma->cmdk; u = dma->cmdu;
while (u != 0 && (dma->cmdr[i].l & HIFN_D_VALID) == 0) {
if (++i == HIFN_D_CMD_RSIZE)
i = 0;
u--;
}
dma->cmdk = i; dma->cmdu = u;
/*
* Clear "result done" and "command wait" flags in status register.
* If we still have slots to process and we received a "command wait"
* interrupt, this will interupt us again.
*/
WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_R_DONE|HIFN_DMACSR_C_WAIT);
return (1);
}
#ifdef __OpenBSD__
/*
* 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.
*/
int
hifn_newsession(sidp, cri)
u_int32_t *sidp;
struct cryptoini *cri;
{
struct cryptoini *c;
struct hifn_softc *sc = NULL;
int i, mac = 0, cry = 0;
if (sidp == NULL || cri == NULL)
return (EINVAL);
for (i = 0; i < hifn_cd.cd_ndevs; i++) {
sc = hifn_cd.cd_devs[i];
if (sc == NULL)
break;
if (sc->sc_cid == (*sidp))
break;
}
if (sc == NULL)
return (EINVAL);
for (i = 0; i < sc->sc_maxses; i++)
if (sc->sc_sessions[i].hs_flags == 0)
break;
if (i == sc->sc_maxses)
return (ENOMEM);
for (c = cri; c != NULL; c = c->cri_next) {
if (c->cri_alg == CRYPTO_MD5_HMAC96 ||
c->cri_alg == CRYPTO_SHA1_HMAC96) {
if (mac)
return (EINVAL);
mac = 1;
} else if (c->cri_alg == CRYPTO_DES_CBC ||
c->cri_alg == CRYPTO_3DES_CBC) {
if (cry)
return (EINVAL);
cry = 1;
}
else
return (EINVAL);
}
if (mac == 0 && cry == 0)
return (EINVAL);
*sidp = HIFN_SID(sc->sc_dv.dv_unit, i);
sc->sc_sessions[i].hs_flags = 1;
get_random_bytes(sc->sc_sessions[i].hs_iv, HIFN_IV_LENGTH);
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.
*/
int
hifn_freesession(tid)
u_int64_t tid;
{
struct hifn_softc *sc;
int card, session;
u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
card = HIFN_CARD(sid);
if (card >= hifn_cd.cd_ndevs || hifn_cd.cd_devs[card] == NULL)
return (EINVAL);
sc = hifn_cd.cd_devs[card];
session = HIFN_SESSION(sid);
if (session >= sc->sc_maxses)
return (EINVAL);
bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));
return (0);
}
int
hifn_process(crp)
struct cryptop *crp;
{
struct hifn_command *cmd = NULL;
int card, session, err;
struct hifn_softc *sc;
struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
if (crp == NULL || crp->crp_callback == NULL) {
hifnstats.hst_invalid++;
return (EINVAL);
}
card = HIFN_CARD(crp->crp_sid);
if (card >= hifn_cd.cd_ndevs || hifn_cd.cd_devs[card] == NULL) {
err = EINVAL;
goto errout;
}
sc = hifn_cd.cd_devs[card];
session = HIFN_SESSION(crp->crp_sid);
if (session >= sc->sc_maxses) {
err = EINVAL;
goto errout;
}
cmd = (struct hifn_command *)malloc(sizeof(struct hifn_command),
M_DEVBUF, M_NOWAIT);
if (cmd == NULL) {
err = ENOMEM;
goto errout;
}
bzero(cmd, sizeof(struct hifn_command));
if (crp->crp_flags & CRYPTO_F_IMBUF) {
cmd->src_m = (struct mbuf *)crp->crp_buf;
cmd->dst_m = (struct mbuf *)crp->crp_buf;
} else {
err = EINVAL;
goto errout; /* XXX only handle mbufs right now */
}
crd1 = crp->crp_desc;
if (crd1 == NULL) {
err = EINVAL;
goto errout;
}
crd2 = crd1->crd_next;
if (crd2 == NULL) {
if (crd1->crd_alg == CRYPTO_MD5_HMAC96 ||
crd1->crd_alg == CRYPTO_SHA1_HMAC96) {
maccrd = crd1;
enccrd = NULL;
} else if (crd1->crd_alg == CRYPTO_DES_CBC ||
crd1->crd_alg == CRYPTO_3DES_CBC) {
if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0)
cmd->base_masks |= HIFN_BASE_CMD_DECODE;
maccrd = NULL;
enccrd = crd1;
} else {
err = EINVAL;
goto errout;
}
} else {
if ((crd1->crd_alg == CRYPTO_MD5_HMAC96 ||
crd1->crd_alg == CRYPTO_SHA1_HMAC96) &&
(crd2->crd_alg == CRYPTO_DES_CBC ||
crd2->crd_alg == CRYPTO_3DES_CBC) &&
((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_3DES_CBC) &&
(crd2->crd_alg == CRYPTO_MD5_HMAC96 ||
crd2->crd_alg == CRYPTO_SHA1_HMAC96) &&
(crd1->crd_flags & CRD_F_ENCRYPT)) {
enccrd = crd1;
maccrd = crd2;
} else {
/*
* We cannot order the 7751 as requested
*/
err = EINVAL;
goto errout;
}
}
if (enccrd) {
cmd->base_masks |= HIFN_BASE_CMD_CRYPT;
cmd->cry_masks |= HIFN_CRYPT_CMD_MODE_CBC |
HIFN_CRYPT_CMD_NEW_IV;
if (enccrd->crd_flags & CRD_F_ENCRYPT) {
if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
bcopy(enccrd->crd_iv, cmd->iv, HIFN_IV_LENGTH);
else
bcopy(sc->sc_sessions[session].hs_iv,
cmd->iv, HIFN_IV_LENGTH);
if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
m_copyback(cmd->src_m, enccrd->crd_inject,
HIFN_IV_LENGTH, cmd->iv);
} else {
if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
bcopy(enccrd->crd_iv, cmd->iv, HIFN_IV_LENGTH);
else
m_copydata(cmd->src_m, enccrd->crd_inject,
HIFN_IV_LENGTH, cmd->iv);
}
if (enccrd->crd_alg == CRYPTO_DES_CBC)
cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES;
else
cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES;
cmd->crypt_header_skip = enccrd->crd_skip;
cmd->crypt_process_len = enccrd->crd_len;
cmd->ck = enccrd->crd_key;
if (sc->sc_sessions[session].hs_flags == 1)
cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
}
if (maccrd) {
cmd->base_masks |= HIFN_BASE_CMD_MAC;
cmd->mac_masks |= HIFN_MAC_CMD_RESULT |
HIFN_MAC_CMD_MODE_HMAC | HIFN_MAC_CMD_RESULT |
HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
if (maccrd->crd_alg == CRYPTO_MD5_HMAC96)
cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5;
else
cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1;
if (sc->sc_sessions[session].hs_flags == 1) {
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->mac_header_skip = maccrd->crd_skip;
cmd->mac_process_len = maccrd->crd_len;
}
if (sc->sc_sessions[session].hs_flags == 1)
sc->sc_sessions[session].hs_flags = 2;
cmd->private_data = (u_long)crp;
cmd->session_num = session;
cmd->softc = sc;
if (hifn_crypto(sc, cmd) == 0)
return (0);
err = ENOMEM;
errout:
if (cmd != NULL)
free(cmd, M_DEVBUF);
if (err == EINVAL)
hifnstats.hst_invalid++;
else
hifnstats.hst_nomem++;
crp->crp_etype = err;
crp->crp_callback(crp);
return (0);
}
void
hifn_callback(sc, cmd, macbuf)
struct hifn_softc *sc;
struct hifn_command *cmd;
u_int8_t *macbuf;
{
struct hifn_dma *dma = sc->sc_dma;
struct cryptop *crp = (struct cryptop *)cmd->private_data;
struct cryptodesc *crd;
struct mbuf *m;
int totlen;
if ((crp->crp_flags & CRYPTO_F_IMBUF) && (cmd->src_m != cmd->dst_m)) {
m_freem(cmd->src_m);
crp->crp_buf = (caddr_t)cmd->dst_m;
}
if ((m = cmd->dst_m) != NULL) {
totlen = cmd->src_l;
hifnstats.hst_obytes += totlen;
while (m) {
if (totlen < m->m_len) {
m->m_len = totlen;
totlen = 0;
} else
totlen -= m->m_len;
m = m->m_next;
if (++dma->dstk == HIFN_D_DST_RSIZE)
dma->dstk = 0;
dma->dstu--;
}
} else {
hifnstats.hst_obytes += dma->dstr[dma->dstk].l & HIFN_D_LENGTH;
if (++dma->dstk == HIFN_D_DST_RSIZE)
dma->dstk = 0;
dma->dstu--;
}
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)
continue;
m_copydata((struct mbuf *)crp->crp_buf,
crd->crd_skip + crd->crd_len - HIFN_IV_LENGTH,
HIFN_IV_LENGTH,
cmd->softc->sc_sessions[cmd->session_num].hs_iv);
break;
}
}
if (macbuf != NULL) {
for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
if (crd->crd_alg != CRYPTO_MD5_HMAC96 &&
crd->crd_alg != CRYPTO_SHA1_HMAC96)
continue;
m_copyback((struct mbuf *)crp->crp_buf,
crd->crd_inject, 12, macbuf);
break;
}
}
free(cmd, M_DEVBUF);
crypto_done(crp);
}
#endif