safe.c revision 227309
1193323Sed/*-
2193323Sed * Copyright (c) 2003 Sam Leffler, Errno Consulting
3193323Sed * Copyright (c) 2003 Global Technology Associates, Inc.
4193323Sed * All rights reserved.
5193323Sed *
6193323Sed * Redistribution and use in source and binary forms, with or without
7193323Sed * modification, are permitted provided that the following conditions
8193323Sed * are met:
9193323Sed * 1. Redistributions of source code must retain the above copyright
10193323Sed *    notice, this list of conditions and the following disclaimer.
11193323Sed * 2. Redistributions in binary form must reproduce the above copyright
12193323Sed *    notice, this list of conditions and the following disclaimer in the
13193323Sed *    documentation and/or other materials provided with the distribution.
14193323Sed *
15193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25193323Sed * SUCH DAMAGE.
26207618Srdivacky */
27193323Sed
28198892Srdivacky#include <sys/cdefs.h>
29193323Sed__FBSDID("$FreeBSD: head/sys/dev/safe/safe.c 227309 2011-11-07 15:43:11Z ed $");
30198892Srdivacky
31224145Sdim/*
32218893Sdim * SafeNet SafeXcel-1141 hardware crypto accelerator
33193323Sed */
34193323Sed#include "opt_safe.h"
35193323Sed
36198090Srdivacky#include <sys/param.h>
37193323Sed#include <sys/systm.h>
38207618Srdivacky#include <sys/proc.h>
39193323Sed#include <sys/errno.h>
40226633Sdim#include <sys/malloc.h>
41193323Sed#include <sys/kernel.h>
42198090Srdivacky#include <sys/mbuf.h>
43193323Sed#include <sys/module.h>
44193323Sed#include <sys/lock.h>
45226633Sdim#include <sys/mutex.h>
46226633Sdim#include <sys/sysctl.h>
47226633Sdim#include <sys/endian.h>
48234353Sdim
49226633Sdim#include <vm/vm.h>
50218893Sdim#include <vm/pmap.h>
51218893Sdim
52218893Sdim#include <machine/bus.h>
53218893Sdim#include <machine/resource.h>
54218893Sdim#include <sys/bus.h>
55218893Sdim#include <sys/rman.h>
56218893Sdim
57218893Sdim#include <crypto/sha1.h>
58207618Srdivacky#include <opencrypto/cryptodev.h>
59207618Srdivacky#include <opencrypto/cryptosoft.h>
60193323Sed#include <sys/md5.h>
61193323Sed#include <sys/random.h>
62198892Srdivacky#include <sys/kobj.h>
63193323Sed
64193323Sed#include "cryptodev_if.h"
65218893Sdim
66198090Srdivacky#include <dev/pci/pcivar.h>
67207618Srdivacky#include <dev/pci/pcireg.h>
68218893Sdim
69218893Sdim#ifdef SAFE_RNDTEST
70234353Sdim#include <dev/rndtest/rndtest.h>
71193323Sed#endif
72193323Sed#include <dev/safe/safereg.h>
73198090Srdivacky#include <dev/safe/safevar.h>
74207618Srdivacky
75193323Sed#ifndef bswap32
76193323Sed#define	bswap32	NTOHL
77193323Sed#endif
78193323Sed
79210299Sed/*
80193323Sed * Prototypes and count for the pci_device structure
81193323Sed */
82193323Sedstatic	int safe_probe(device_t);
83234353Sdimstatic	int safe_attach(device_t);
84234353Sdimstatic	int safe_detach(device_t);
85207618Srdivackystatic	int safe_suspend(device_t);
86234353Sdimstatic	int safe_resume(device_t);
87234353Sdimstatic	int safe_shutdown(device_t);
88234353Sdim
89234353Sdimstatic	int safe_newsession(device_t, u_int32_t *, struct cryptoini *);
90234353Sdimstatic	int safe_freesession(device_t, u_int64_t);
91218893Sdimstatic	int safe_process(device_t, struct cryptop *, int);
92218893Sdim
93218893Sdimstatic device_method_t safe_methods[] = {
94218893Sdim	/* Device interface */
95218893Sdim	DEVMETHOD(device_probe,		safe_probe),
96218893Sdim	DEVMETHOD(device_attach,	safe_attach),
97218893Sdim	DEVMETHOD(device_detach,	safe_detach),
98218893Sdim	DEVMETHOD(device_suspend,	safe_suspend),
99218893Sdim	DEVMETHOD(device_resume,	safe_resume),
100218893Sdim	DEVMETHOD(device_shutdown,	safe_shutdown),
101218893Sdim
102212904Sdim	/* bus interface */
103198892Srdivacky	DEVMETHOD(bus_print_child,	bus_generic_print_child),
104207618Srdivacky	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
105226633Sdim
106226633Sdim	/* crypto device methods */
107226633Sdim	DEVMETHOD(cryptodev_newsession,	safe_newsession),
108226633Sdim	DEVMETHOD(cryptodev_freesession,safe_freesession),
109226633Sdim	DEVMETHOD(cryptodev_process,	safe_process),
110226633Sdim
111226633Sdim	{ 0, 0 }
112226633Sdim};
113226633Sdimstatic driver_t safe_driver = {
114226633Sdim	"safe",
115226633Sdim	safe_methods,
116193323Sed	sizeof (struct safe_softc)
117193323Sed};
118207618Srdivackystatic devclass_t safe_devclass;
119218893Sdim
120218893SdimDRIVER_MODULE(safe, pci, safe_driver, safe_devclass, 0, 0);
121218893SdimMODULE_DEPEND(safe, crypto, 1, 1, 1);
122193323Sed#ifdef SAFE_RNDTEST
123207618SrdivackyMODULE_DEPEND(safe, rndtest, 1, 1, 1);
124218893Sdim#endif
125218893Sdim
126218893Sdimstatic	void safe_intr(void *);
127207618Srdivackystatic	void safe_callback(struct safe_softc *, struct safe_ringentry *);
128193323Sedstatic	void safe_feed(struct safe_softc *, struct safe_ringentry *);
129193323Sedstatic	void safe_mcopy(struct mbuf *, struct mbuf *, u_int);
130193323Sed#ifndef SAFE_NO_RNG
131193323Sedstatic	void safe_rng_init(struct safe_softc *);
132193323Sedstatic	void safe_rng(void *);
133198090Srdivacky#endif /* SAFE_NO_RNG */
134193323Sedstatic	int safe_dma_malloc(struct safe_softc *, bus_size_t,
135193323Sed	        struct safe_dma_alloc *, int);
136193323Sed#define	safe_dma_sync(_dma, _flags) \
137193323Sed	bus_dmamap_sync((_dma)->dma_tag, (_dma)->dma_map, (_flags))
138193323Sedstatic	void safe_dma_free(struct safe_softc *, struct safe_dma_alloc *);
139193323Sedstatic	int safe_dmamap_aligned(const struct safe_operand *);
140218893Sdimstatic	int safe_dmamap_uniform(const struct safe_operand *);
141218893Sdim
142218893Sdimstatic	void safe_reset_board(struct safe_softc *);
143218893Sdimstatic	void safe_init_board(struct safe_softc *);
144218893Sdimstatic	void safe_init_pciregs(device_t dev);
145218893Sdimstatic	void safe_cleanchip(struct safe_softc *);
146218893Sdimstatic	void safe_totalreset(struct safe_softc *);
147193323Sed
148193323Sedstatic	int safe_free_entry(struct safe_softc *, struct safe_ringentry *);
149193323Sed
150193323Sedstatic SYSCTL_NODE(_hw, OID_AUTO, safe, CTLFLAG_RD, 0,
151207618Srdivacky    "SafeNet driver parameters");
152207618Srdivacky
153207618Srdivacky#ifdef SAFE_DEBUG
154207618Srdivackystatic	void safe_dump_dmastatus(struct safe_softc *, const char *);
155207618Srdivackystatic	void safe_dump_ringstate(struct safe_softc *, const char *);
156207618Srdivackystatic	void safe_dump_intrstate(struct safe_softc *, const char *);
157207618Srdivackystatic	void safe_dump_request(struct safe_softc *, const char *,
158207618Srdivacky		struct safe_ringentry *);
159207618Srdivacky
160207618Srdivackystatic	struct safe_softc *safec;		/* for use by hw.safe.dump */
161207618Srdivacky
162207618Srdivackystatic	int safe_debug = 0;
163207618SrdivackySYSCTL_INT(_hw_safe, OID_AUTO, debug, CTLFLAG_RW, &safe_debug,
164207618Srdivacky	    0, "control debugging msgs");
165207618Srdivacky#define	DPRINTF(_x)	if (safe_debug) printf _x
166207618Srdivacky#else
167207618Srdivacky#define	DPRINTF(_x)
168207618Srdivacky#endif
169207618Srdivacky
170207618Srdivacky#define	READ_REG(sc,r) \
171234353Sdim	bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (r))
172234353Sdim
173234353Sdim#define WRITE_REG(sc,reg,val) \
174207618Srdivacky	bus_space_write_4((sc)->sc_st, (sc)->sc_sh, reg, val)
175207618Srdivacky
176207618Srdivackystruct safe_stats safestats;
177207618SrdivackySYSCTL_STRUCT(_hw_safe, OID_AUTO, stats, CTLFLAG_RD, &safestats,
178207618Srdivacky	    safe_stats, "driver statistics");
179207618Srdivacky#ifndef SAFE_NO_RNG
180207618Srdivackystatic	int safe_rnginterval = 1;		/* poll once a second */
181207618SrdivackySYSCTL_INT(_hw_safe, OID_AUTO, rnginterval, CTLFLAG_RW, &safe_rnginterval,
182210299Sed	    0, "RNG polling interval (secs)");
183210299Sedstatic	int safe_rngbufsize = 16;		/* 64 bytes each poll  */
184207618SrdivackySYSCTL_INT(_hw_safe, OID_AUTO, rngbufsize, CTLFLAG_RW, &safe_rngbufsize,
185207618Srdivacky	    0, "RNG polling buffer size (32-bit words)");
186193323Sedstatic	int safe_rngmaxalarm = 8;		/* max alarms before reset */
187193323SedSYSCTL_INT(_hw_safe, OID_AUTO, rngmaxalarm, CTLFLAG_RW, &safe_rngmaxalarm,
188193323Sed	    0, "RNG max alarms before reset");
189193323Sed#endif /* SAFE_NO_RNG */
190234353Sdim
191193323Sedstatic int
192193323Sedsafe_probe(device_t dev)
193234353Sdim{
194234353Sdim	if (pci_get_vendor(dev) == PCI_VENDOR_SAFENET &&
195234353Sdim	    pci_get_device(dev) == PCI_PRODUCT_SAFEXCEL)
196221345Sdim		return (BUS_PROBE_DEFAULT);
197218893Sdim	return (ENXIO);
198218893Sdim}
199218893Sdim
200218893Sdimstatic const char*
201218893Sdimsafe_partname(struct safe_softc *sc)
202218893Sdim{
203218893Sdim	/* XXX sprintf numbers when not decoded */
204218893Sdim	switch (pci_get_vendor(sc->sc_dev)) {
205218893Sdim	case PCI_VENDOR_SAFENET:
206218893Sdim		switch (pci_get_device(sc->sc_dev)) {
207218893Sdim		case PCI_PRODUCT_SAFEXCEL: return "SafeNet SafeXcel-1141";
208234353Sdim		}
209218893Sdim		return "SafeNet unknown-part";
210218893Sdim	}
211218893Sdim	return "Unknown-vendor unknown-part";
212218893Sdim}
213218893Sdim
214218893Sdim#ifndef SAFE_NO_RNG
215193323Sedstatic void
216193323Seddefault_harvest(struct rndtest_state *rsp, void *buf, u_int count)
217193323Sed{
218193323Sed	random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE);
219226633Sdim}
220226633Sdim#endif /* SAFE_NO_RNG */
221226633Sdim
222226633Sdimstatic int
223234353Sdimsafe_attach(device_t dev)
224234353Sdim{
225234353Sdim	struct safe_softc *sc = device_get_softc(dev);
226234353Sdim	u_int32_t raddr;
227234353Sdim	u_int32_t cmd, i, devinfo;
228234353Sdim	int rid;
229234353Sdim
230234353Sdim	bzero(sc, sizeof (*sc));
231234353Sdim	sc->sc_dev = dev;
232234353Sdim
233234353Sdim	/* XXX handle power management */
234234353Sdim
235234353Sdim	cmd = pci_read_config(dev, PCIR_COMMAND, 4);
236234353Sdim	cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN;
237234353Sdim	pci_write_config(dev, PCIR_COMMAND, cmd, 4);
238234353Sdim	cmd = pci_read_config(dev, PCIR_COMMAND, 4);
239193323Sed
240234353Sdim	if (!(cmd & PCIM_CMD_MEMEN)) {
241234353Sdim		device_printf(dev, "failed to enable memory mapping\n");
242193323Sed		goto bad;
243226633Sdim	}
244226633Sdim
245226633Sdim	if (!(cmd & PCIM_CMD_BUSMASTEREN)) {
246226633Sdim		device_printf(dev, "failed to enable bus mastering\n");
247226633Sdim		goto bad;
248226633Sdim	}
249226633Sdim
250218893Sdim	/*
251218893Sdim	 * Setup memory-mapping of PCI registers.
252218893Sdim	 */
253218893Sdim	rid = BS_BAR;
254199989Srdivacky	sc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
255218893Sdim					   RF_ACTIVE);
256218893Sdim	if (sc->sc_sr == NULL) {
257218893Sdim		device_printf(dev, "cannot map register space\n");
258218893Sdim		goto bad;
259198892Srdivacky	}
260198892Srdivacky	sc->sc_st = rman_get_bustag(sc->sc_sr);
261198892Srdivacky	sc->sc_sh = rman_get_bushandle(sc->sc_sr);
262198892Srdivacky
263198892Srdivacky	/*
264198892Srdivacky	 * Arrange interrupt line.
265199481Srdivacky	 */
266199481Srdivacky	rid = 0;
267199481Srdivacky	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
268199481Srdivacky					    RF_SHAREABLE|RF_ACTIVE);
269199481Srdivacky	if (sc->sc_irq == NULL) {
270198953Srdivacky		device_printf(dev, "could not map interrupt\n");
271198953Srdivacky		goto bad1;
272198953Srdivacky	}
273198953Srdivacky	/*
274198953Srdivacky	 * NB: Network code assumes we are blocked with splimp()
275198953Srdivacky	 *     so make sure the IRQ is mapped appropriately.
276198953Srdivacky	 */
277226633Sdim	if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
278226633Sdim			   NULL, safe_intr, sc, &sc->sc_ih)) {
279226633Sdim		device_printf(dev, "could not establish interrupt\n");
280226633Sdim		goto bad2;
281193323Sed	}
282193323Sed
283218893Sdim	sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE);
284218893Sdim	if (sc->sc_cid < 0) {
285198892Srdivacky		device_printf(dev, "could not get crypto driver id\n");
286198892Srdivacky		goto bad3;
287198892Srdivacky	}
288198892Srdivacky
289198892Srdivacky	sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) &
290210299Sed		(SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN);
291210299Sed
292210299Sed	/*
293210299Sed	 * Setup DMA descriptor area.
294193323Sed	 */
295193323Sed	if (bus_dma_tag_create(NULL,			/* parent */
296193323Sed			       1,			/* alignment */
297193323Sed			       SAFE_DMA_BOUNDARY,	/* boundary */
298234353Sdim			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
299218893Sdim			       BUS_SPACE_MAXADDR,	/* highaddr */
300218893Sdim			       NULL, NULL,		/* filter, filterarg */
301218893Sdim			       SAFE_MAX_DMA,		/* maxsize */
302218893Sdim			       SAFE_MAX_PART,		/* nsegments */
303218893Sdim			       SAFE_MAX_SSIZE,		/* maxsegsize */
304218893Sdim			       BUS_DMA_ALLOCNOW,	/* flags */
305218893Sdim			       NULL, NULL,		/* locking */
306193323Sed			       &sc->sc_srcdmat)) {
307210299Sed		device_printf(dev, "cannot allocate DMA tag\n");
308210299Sed		goto bad4;
309210299Sed	}
310210299Sed	if (bus_dma_tag_create(NULL,			/* parent */
311210299Sed			       1,			/* alignment */
312210299Sed			       SAFE_MAX_DSIZE,		/* boundary */
313210299Sed			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
314193323Sed			       BUS_SPACE_MAXADDR,	/* highaddr */
315210299Sed			       NULL, NULL,		/* filter, filterarg */
316193323Sed			       SAFE_MAX_DMA,		/* maxsize */
317210299Sed			       SAFE_MAX_PART,		/* nsegments */
318193323Sed			       SAFE_MAX_DSIZE,		/* maxsegsize */
319193323Sed			       BUS_DMA_ALLOCNOW,	/* flags */
320193323Sed			       NULL, NULL,		/* locking */
321193323Sed			       &sc->sc_dstdmat)) {
322210299Sed		device_printf(dev, "cannot allocate DMA tag\n");
323193323Sed		goto bad4;
324193323Sed	}
325218893Sdim
326198090Srdivacky	/*
327207618Srdivacky	 * Allocate packet engine descriptors.
328218893Sdim	 */
329218893Sdim	if (safe_dma_malloc(sc,
330193323Sed	    SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
331234353Sdim	    &sc->sc_ringalloc, 0)) {
332234353Sdim		device_printf(dev, "cannot allocate PE descriptor ring\n");
333234353Sdim		bus_dma_tag_destroy(sc->sc_srcdmat);
334234353Sdim		goto bad4;
335234353Sdim	}
336234353Sdim	/*
337234353Sdim	 * Hookup the static portion of all our data structures.
338234353Sdim	 */
339218893Sdim	sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr;
340218893Sdim	sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE;
341218893Sdim	sc->sc_front = sc->sc_ring;
342218893Sdim	sc->sc_back = sc->sc_ring;
343218893Sdim	raddr = sc->sc_ringalloc.dma_paddr;
344218893Sdim	bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry));
345218893Sdim	for (i = 0; i < SAFE_MAX_NQUEUE; i++) {
346218893Sdim		struct safe_ringentry *re = &sc->sc_ring[i];
347221345Sdim
348218893Sdim		re->re_desc.d_sa = raddr +
349218893Sdim			offsetof(struct safe_ringentry, re_sa);
350193323Sed		re->re_sa.sa_staterec = raddr +
351207618Srdivacky			offsetof(struct safe_ringentry, re_sastate);
352207618Srdivacky
353207618Srdivacky		raddr += sizeof (struct safe_ringentry);
354193323Sed	}
355210299Sed	mtx_init(&sc->sc_ringmtx, device_get_nameunit(dev),
356210299Sed		"packet engine ring", MTX_DEF);
357210299Sed
358210299Sed	/*
359234353Sdim	 * Allocate scatter and gather particle descriptors.
360193323Sed	 */
361207618Srdivacky	if (safe_dma_malloc(sc, SAFE_TOTAL_SPART * sizeof (struct safe_pdesc),
362207618Srdivacky	    &sc->sc_spalloc, 0)) {
363210299Sed		device_printf(dev, "cannot allocate source particle "
364210299Sed			"descriptor ring\n");
365193323Sed		mtx_destroy(&sc->sc_ringmtx);
366210299Sed		safe_dma_free(sc, &sc->sc_ringalloc);
367193323Sed		bus_dma_tag_destroy(sc->sc_srcdmat);
368234353Sdim		goto bad4;
369234353Sdim	}
370207618Srdivacky	sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr;
371207618Srdivacky	sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART;
372207618Srdivacky	sc->sc_spfree = sc->sc_spring;
373207618Srdivacky	bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc));
374207618Srdivacky
375207618Srdivacky	if (safe_dma_malloc(sc, SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
376210299Sed	    &sc->sc_dpalloc, 0)) {
377234353Sdim		device_printf(dev, "cannot allocate destination particle "
378207618Srdivacky			"descriptor ring\n");
379207618Srdivacky		mtx_destroy(&sc->sc_ringmtx);
380193323Sed		safe_dma_free(sc, &sc->sc_spalloc);
381193323Sed		safe_dma_free(sc, &sc->sc_ringalloc);
382193323Sed		bus_dma_tag_destroy(sc->sc_dstdmat);
383193323Sed		goto bad4;
384193323Sed	}
385207618Srdivacky	sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr;
386207618Srdivacky	sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART;
387207618Srdivacky	sc->sc_dpfree = sc->sc_dpring;
388207618Srdivacky	bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc));
389207618Srdivacky
390207618Srdivacky	device_printf(sc->sc_dev, "%s", safe_partname(sc));
391207618Srdivacky
392207618Srdivacky	devinfo = READ_REG(sc, SAFE_DEVINFO);
393207618Srdivacky	if (devinfo & SAFE_DEVINFO_RNG) {
394207618Srdivacky		sc->sc_flags |= SAFE_FLAGS_RNG;
395207618Srdivacky		printf(" rng");
396207618Srdivacky	}
397207618Srdivacky	if (devinfo & SAFE_DEVINFO_PKEY) {
398207618Srdivacky#if 0
399207618Srdivacky		printf(" key");
400207618Srdivacky		sc->sc_flags |= SAFE_FLAGS_KEY;
401207618Srdivacky		crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0);
402207618Srdivacky		crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0);
403207618Srdivacky#endif
404234353Sdim	}
405234353Sdim	if (devinfo & SAFE_DEVINFO_DES) {
406207618Srdivacky		printf(" des/3des");
407207618Srdivacky		crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
408207618Srdivacky		crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
409207618Srdivacky	}
410207618Srdivacky	if (devinfo & SAFE_DEVINFO_AES) {
411207618Srdivacky		printf(" aes");
412207618Srdivacky		crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
413207618Srdivacky	}
414207618Srdivacky	if (devinfo & SAFE_DEVINFO_MD5) {
415207618Srdivacky		printf(" md5");
416207618Srdivacky		crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
417207618Srdivacky	}
418207618Srdivacky	if (devinfo & SAFE_DEVINFO_SHA1) {
419207618Srdivacky		printf(" sha1");
420207618Srdivacky		crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
421207618Srdivacky	}
422207618Srdivacky	printf(" null");
423207618Srdivacky	crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0);
424234353Sdim	crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0);
425234353Sdim	/* XXX other supported algorithms */
426234353Sdim	printf("\n");
427234353Sdim
428234353Sdim	safe_reset_board(sc);		/* reset h/w */
429234353Sdim	safe_init_pciregs(dev);		/* init pci settings */
430234353Sdim	safe_init_board(sc);		/* init h/w */
431207618Srdivacky
432207618Srdivacky#ifndef SAFE_NO_RNG
433207618Srdivacky	if (sc->sc_flags & SAFE_FLAGS_RNG) {
434207618Srdivacky#ifdef SAFE_RNDTEST
435207618Srdivacky		sc->sc_rndtest = rndtest_attach(dev);
436207618Srdivacky		if (sc->sc_rndtest)
437207618Srdivacky			sc->sc_harvest = rndtest_harvest;
438207618Srdivacky		else
439207618Srdivacky			sc->sc_harvest = default_harvest;
440234353Sdim#else
441207618Srdivacky		sc->sc_harvest = default_harvest;
442207618Srdivacky#endif
443207618Srdivacky		safe_rng_init(sc);
444207618Srdivacky
445207618Srdivacky		callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
446207618Srdivacky		callout_reset(&sc->sc_rngto, hz*safe_rnginterval, safe_rng, sc);
447207618Srdivacky	}
448239462Sdim#endif /* SAFE_NO_RNG */
449239462Sdim#ifdef SAFE_DEBUG
450207618Srdivacky	safec = sc;			/* for use by hw.safe.dump */
451207618Srdivacky#endif
452207618Srdivacky	return (0);
453207618Srdivackybad4:
454207618Srdivacky	crypto_unregister_all(sc->sc_cid);
455207618Srdivackybad3:
456207618Srdivacky	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
457207618Srdivackybad2:
458207618Srdivacky	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
459207618Srdivackybad1:
460207618Srdivacky	bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_sr);
461207618Srdivackybad:
462207618Srdivacky	return (ENXIO);
463207618Srdivacky}
464207618Srdivacky
465207618Srdivacky/*
466234353Sdim * Detach a device that successfully probed.
467234353Sdim */
468239462Sdimstatic int
469234353Sdimsafe_detach(device_t dev)
470234353Sdim{
471234353Sdim	struct safe_softc *sc = device_get_softc(dev);
472234353Sdim
473234353Sdim	/* XXX wait/abort active ops */
474207618Srdivacky
475234353Sdim	WRITE_REG(sc, SAFE_HI_MASK, 0);		/* disable interrupts */
476234353Sdim
477207618Srdivacky	callout_stop(&sc->sc_rngto);
478207618Srdivacky
479207618Srdivacky	crypto_unregister_all(sc->sc_cid);
480207618Srdivacky
481207618Srdivacky#ifdef SAFE_RNDTEST
482207618Srdivacky	if (sc->sc_rndtest)
483207618Srdivacky		rndtest_detach(sc->sc_rndtest);
484207618Srdivacky#endif
485207618Srdivacky
486207618Srdivacky	safe_cleanchip(sc);
487207618Srdivacky	safe_dma_free(sc, &sc->sc_dpalloc);
488207618Srdivacky	safe_dma_free(sc, &sc->sc_spalloc);
489207618Srdivacky	mtx_destroy(&sc->sc_ringmtx);
490207618Srdivacky	safe_dma_free(sc, &sc->sc_ringalloc);
491207618Srdivacky
492234353Sdim	bus_generic_detach(dev);
493234353Sdim	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
494234353Sdim	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
495234353Sdim
496207618Srdivacky	bus_dma_tag_destroy(sc->sc_srcdmat);
497234353Sdim	bus_dma_tag_destroy(sc->sc_dstdmat);
498234353Sdim	bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_sr);
499207618Srdivacky
500207618Srdivacky	return (0);
501207618Srdivacky}
502207618Srdivacky
503207618Srdivacky/*
504207618Srdivacky * Stop all chip i/o so that the kernel's probe routines don't
505207618Srdivacky * get confused by errant DMAs when rebooting.
506207618Srdivacky */
507207618Srdivackystatic int
508226633Sdimsafe_shutdown(device_t dev)
509226633Sdim{
510226633Sdim#ifdef notyet
511226633Sdim	safe_stop(device_get_softc(dev));
512226633Sdim#endif
513226633Sdim	return (0);
514207618Srdivacky}
515207618Srdivacky
516207618Srdivacky/*
517207618Srdivacky * Device suspend routine.
518207618Srdivacky */
519207618Srdivackystatic int
520239462Sdimsafe_suspend(device_t dev)
521239462Sdim{
522207618Srdivacky	struct safe_softc *sc = device_get_softc(dev);
523207618Srdivacky
524226633Sdim#ifdef notyet
525207618Srdivacky	/* XXX stop the device and save PCI settings */
526207618Srdivacky#endif
527207618Srdivacky	sc->sc_suspended = 1;
528234353Sdim
529207618Srdivacky	return (0);
530207618Srdivacky}
531207618Srdivacky
532234353Sdimstatic int
533234353Sdimsafe_resume(device_t dev)
534234353Sdim{
535234353Sdim	struct safe_softc *sc = device_get_softc(dev);
536234353Sdim
537234353Sdim#ifdef notyet
538234353Sdim	/* XXX retore PCI settings and start the device */
539234353Sdim#endif
540234353Sdim	sc->sc_suspended = 0;
541234353Sdim	return (0);
542234353Sdim}
543239462Sdim
544239462Sdim/*
545234353Sdim * SafeXcel Interrupt routine
546234353Sdim */
547234353Sdimstatic void
548207618Srdivackysafe_intr(void *arg)
549207618Srdivacky{
550207618Srdivacky	struct safe_softc *sc = arg;
551207618Srdivacky	volatile u_int32_t stat;
552207618Srdivacky
553234353Sdim	stat = READ_REG(sc, SAFE_HM_STAT);
554234353Sdim	if (stat == 0)			/* shared irq, not for us */
555234353Sdim		return;
556207618Srdivacky
557207618Srdivacky	WRITE_REG(sc, SAFE_HI_CLR, stat);	/* IACK */
558207618Srdivacky
559207618Srdivacky	if ((stat & SAFE_INT_PE_DDONE)) {
560207618Srdivacky		/*
561234353Sdim		 * Descriptor(s) done; scan the ring and
562234353Sdim		 * process completed operations.
563207618Srdivacky		 */
564207618Srdivacky		mtx_lock(&sc->sc_ringmtx);
565207618Srdivacky		while (sc->sc_back != sc->sc_front) {
566207618Srdivacky			struct safe_ringentry *re = sc->sc_back;
567207618Srdivacky#ifdef SAFE_DEBUG
568207618Srdivacky			if (safe_debug) {
569234353Sdim				safe_dump_ringstate(sc, __func__);
570234353Sdim				safe_dump_request(sc, __func__, re);
571234353Sdim			}
572207618Srdivacky#endif
573207618Srdivacky			/*
574207618Srdivacky			 * safe_process marks ring entries that were allocated
575207618Srdivacky			 * but not used with a csr of zero.  This insures the
576207618Srdivacky			 * ring front pointer never needs to be set backwards
577207618Srdivacky			 * in the event that an entry is allocated but not used
578207618Srdivacky			 * because of a setup error.
579207618Srdivacky			 */
580207618Srdivacky			if (re->re_desc.d_csr != 0) {
581207618Srdivacky				if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr))
582207618Srdivacky					break;
583207618Srdivacky				if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len))
584207618Srdivacky					break;
585207618Srdivacky				sc->sc_nqchip--;
586207618Srdivacky				safe_callback(sc, re);
587207618Srdivacky			}
588207618Srdivacky			if (++(sc->sc_back) == sc->sc_ringtop)
589207618Srdivacky				sc->sc_back = sc->sc_ring;
590207618Srdivacky		}
591207618Srdivacky		mtx_unlock(&sc->sc_ringmtx);
592207618Srdivacky	}
593207618Srdivacky
594207618Srdivacky	/*
595207618Srdivacky	 * Check to see if we got any DMA Error
596207618Srdivacky	 */
597207618Srdivacky	if (stat & SAFE_INT_PE_ERROR) {
598207618Srdivacky		DPRINTF(("dmaerr dmastat %08x\n",
599207618Srdivacky			READ_REG(sc, SAFE_PE_DMASTAT)));
600207618Srdivacky		safestats.st_dmaerr++;
601207618Srdivacky		safe_totalreset(sc);
602207618Srdivacky#if 0
603207618Srdivacky		safe_feed(sc);
604207618Srdivacky#endif
605207618Srdivacky	}
606207618Srdivacky
607207618Srdivacky	if (sc->sc_needwakeup) {		/* XXX check high watermark */
608207618Srdivacky		int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);
609210299Sed		DPRINTF(("%s: wakeup crypto %x\n", __func__,
610210299Sed			sc->sc_needwakeup));
611207618Srdivacky		sc->sc_needwakeup &= ~wakeup;
612207618Srdivacky		crypto_unblock(sc->sc_cid, wakeup);
613234353Sdim	}
614234353Sdim}
615207618Srdivacky
616207618Srdivacky/*
617207618Srdivacky * safe_feed() - post a request to chip
618210299Sed */
619207618Srdivackystatic void
620234353Sdimsafe_feed(struct safe_softc *sc, struct safe_ringentry *re)
621207618Srdivacky{
622207618Srdivacky	bus_dmamap_sync(sc->sc_srcdmat, re->re_src_map, BUS_DMASYNC_PREWRITE);
623207618Srdivacky	if (re->re_dst_map != NULL)
624207618Srdivacky		bus_dmamap_sync(sc->sc_dstdmat, re->re_dst_map,
625207618Srdivacky			BUS_DMASYNC_PREREAD);
626207618Srdivacky	/* XXX have no smaller granularity */
627207618Srdivacky	safe_dma_sync(&sc->sc_ringalloc,
628207618Srdivacky		BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
629226633Sdim	safe_dma_sync(&sc->sc_spalloc, BUS_DMASYNC_PREWRITE);
630226633Sdim	safe_dma_sync(&sc->sc_dpalloc, BUS_DMASYNC_PREWRITE);
631226633Sdim
632226633Sdim#ifdef SAFE_DEBUG
633226633Sdim	if (safe_debug) {
634234353Sdim		safe_dump_ringstate(sc, __func__);
635226633Sdim		safe_dump_request(sc, __func__, re);
636226633Sdim	}
637226633Sdim#endif
638226633Sdim	sc->sc_nqchip++;
639226633Sdim	if (sc->sc_nqchip > safestats.st_maxqchip)
640226633Sdim		safestats.st_maxqchip = sc->sc_nqchip;
641226633Sdim	/* poke h/w to check descriptor ring, any value can be written */
642226633Sdim	WRITE_REG(sc, SAFE_HI_RD_DESCR, 0);
643226633Sdim}
644226633Sdim
645226633Sdim#define	N(a)	(sizeof(a) / sizeof (a[0]))
646226633Sdimstatic void
647226633Sdimsafe_setup_enckey(struct safe_session *ses, caddr_t key)
648226633Sdim{
649226633Sdim	int i;
650234353Sdim
651234353Sdim	bcopy(key, ses->ses_key, ses->ses_klen / 8);
652193323Sed
653234353Sdim	/* PE is little-endian, insure proper byte order */
654234353Sdim	for (i = 0; i < N(ses->ses_key); i++)
655234353Sdim		ses->ses_key[i] = htole32(ses->ses_key[i]);
656226633Sdim}
657234353Sdim
658234353Sdimstatic void
659234353Sdimsafe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen)
660234353Sdim{
661193323Sed	MD5_CTX md5ctx;
662234353Sdim	SHA1_CTX sha1ctx;
663234353Sdim	int i;
664234353Sdim
665234353Sdim
666234353Sdim	for (i = 0; i < klen; i++)
667234353Sdim		key[i] ^= HMAC_IPAD_VAL;
668234353Sdim
669218893Sdim	if (algo == CRYPTO_MD5_HMAC) {
670218893Sdim		MD5Init(&md5ctx);
671234353Sdim		MD5Update(&md5ctx, key, klen);
672234353Sdim		MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen);
673234353Sdim		bcopy(md5ctx.state, ses->ses_hminner, sizeof(md5ctx.state));
674234353Sdim	} else {
675234353Sdim		SHA1Init(&sha1ctx);
676234353Sdim		SHA1Update(&sha1ctx, key, klen);
677234353Sdim		SHA1Update(&sha1ctx, hmac_ipad_buffer,
678234353Sdim		    SHA1_HMAC_BLOCK_LEN - klen);
679234353Sdim		bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32));
680234353Sdim	}
681234353Sdim
682234353Sdim	for (i = 0; i < klen; i++)
683234353Sdim		key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
684234353Sdim
685234353Sdim	if (algo == CRYPTO_MD5_HMAC) {
686234353Sdim		MD5Init(&md5ctx);
687234353Sdim		MD5Update(&md5ctx, key, klen);
688234353Sdim		MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen);
689234353Sdim		bcopy(md5ctx.state, ses->ses_hmouter, sizeof(md5ctx.state));
690234353Sdim	} else {
691234353Sdim		SHA1Init(&sha1ctx);
692234353Sdim		SHA1Update(&sha1ctx, key, klen);
693234353Sdim		SHA1Update(&sha1ctx, hmac_opad_buffer,
694234353Sdim		    SHA1_HMAC_BLOCK_LEN - klen);
695234353Sdim		bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32));
696234353Sdim	}
697234353Sdim
698234353Sdim	for (i = 0; i < klen; i++)
699234353Sdim		key[i] ^= HMAC_OPAD_VAL;
700234353Sdim
701234353Sdim	/* PE is little-endian, insure proper byte order */
702234353Sdim	for (i = 0; i < N(ses->ses_hminner); i++) {
703234353Sdim		ses->ses_hminner[i] = htole32(ses->ses_hminner[i]);
704234353Sdim		ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]);
705234353Sdim	}
706234353Sdim}
707234353Sdim#undef N
708234353Sdim
709234353Sdim/*
710234353Sdim * Allocate a new 'session' and return an encoded session id.  'sidp'
711234353Sdim * contains our registration id, and should contain an encoded session
712234353Sdim * id on successful allocation.
713234353Sdim */
714234353Sdimstatic int
715234353Sdimsafe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
716234353Sdim{
717234353Sdim	struct safe_softc *sc = device_get_softc(dev);
718234353Sdim	struct cryptoini *c, *encini = NULL, *macini = NULL;
719234353Sdim	struct safe_session *ses = NULL;
720234353Sdim	int sesn;
721234353Sdim
722234353Sdim	if (sidp == NULL || cri == NULL || sc == NULL)
723234353Sdim		return (EINVAL);
724234353Sdim
725234353Sdim	for (c = cri; c != NULL; c = c->cri_next) {
726234353Sdim		if (c->cri_alg == CRYPTO_MD5_HMAC ||
727234353Sdim		    c->cri_alg == CRYPTO_SHA1_HMAC ||
728234353Sdim		    c->cri_alg == CRYPTO_NULL_HMAC) {
729234353Sdim			if (macini)
730234353Sdim				return (EINVAL);
731234353Sdim			macini = c;
732234353Sdim		} else if (c->cri_alg == CRYPTO_DES_CBC ||
733234353Sdim		    c->cri_alg == CRYPTO_3DES_CBC ||
734234353Sdim		    c->cri_alg == CRYPTO_AES_CBC ||
735234353Sdim		    c->cri_alg == CRYPTO_NULL_CBC) {
736234353Sdim			if (encini)
737234353Sdim				return (EINVAL);
738234353Sdim			encini = c;
739218893Sdim		} else
740218893Sdim			return (EINVAL);
741218893Sdim	}
742218893Sdim	if (encini == NULL && macini == NULL)
743218893Sdim		return (EINVAL);
744218893Sdim	if (encini) {			/* validate key length */
745234353Sdim		switch (encini->cri_alg) {
746234353Sdim		case CRYPTO_DES_CBC:
747234353Sdim			if (encini->cri_klen != 64)
748234353Sdim				return (EINVAL);
749218893Sdim			break;
750234353Sdim		case CRYPTO_3DES_CBC:
751234353Sdim			if (encini->cri_klen != 192)
752234353Sdim				return (EINVAL);
753193323Sed			break;
754234353Sdim		case CRYPTO_AES_CBC:
755234353Sdim			if (encini->cri_klen != 128 &&
756234353Sdim			    encini->cri_klen != 192 &&
757234353Sdim			    encini->cri_klen != 256)
758234353Sdim				return (EINVAL);
759234353Sdim			break;
760234353Sdim		}
761234353Sdim	}
762234353Sdim
763234353Sdim	if (sc->sc_sessions == NULL) {
764234353Sdim		ses = sc->sc_sessions = (struct safe_session *)malloc(
765234353Sdim		    sizeof(struct safe_session), M_DEVBUF, M_NOWAIT);
766234353Sdim		if (ses == NULL)
767234353Sdim			return (ENOMEM);
768234353Sdim		sesn = 0;
769212904Sdim		sc->sc_nsessions = 1;
770193323Sed	} else {
771193323Sed		for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
772218893Sdim			if (sc->sc_sessions[sesn].ses_used == 0) {
773218893Sdim				ses = &sc->sc_sessions[sesn];
774218893Sdim				break;
775218893Sdim			}
776226633Sdim		}
777226633Sdim
778226633Sdim		if (ses == NULL) {
779226633Sdim			sesn = sc->sc_nsessions;
780226633Sdim			ses = (struct safe_session *)malloc((sesn + 1) *
781226633Sdim			    sizeof(struct safe_session), M_DEVBUF, M_NOWAIT);
782226633Sdim			if (ses == NULL)
783226633Sdim				return (ENOMEM);
784234353Sdim			bcopy(sc->sc_sessions, ses, sesn *
785226633Sdim			    sizeof(struct safe_session));
786226633Sdim			bzero(sc->sc_sessions, sesn *
787226633Sdim			    sizeof(struct safe_session));
788226633Sdim			free(sc->sc_sessions, M_DEVBUF);
789226633Sdim			sc->sc_sessions = ses;
790226633Sdim			ses = &sc->sc_sessions[sesn];
791226633Sdim			sc->sc_nsessions++;
792234353Sdim		}
793218893Sdim	}
794218893Sdim
795218893Sdim	bzero(ses, sizeof(struct safe_session));
796218893Sdim	ses->ses_used = 1;
797218893Sdim
798218893Sdim	if (encini) {
799218893Sdim		/* get an IV */
800218893Sdim		/* XXX may read fewer than requested */
801218893Sdim		read_random(ses->ses_iv, sizeof(ses->ses_iv));
802218893Sdim
803218893Sdim		ses->ses_klen = encini->cri_klen;
804218893Sdim		if (encini->cri_key != NULL)
805218893Sdim			safe_setup_enckey(ses, encini->cri_key);
806218893Sdim	}
807218893Sdim
808218893Sdim	if (macini) {
809218893Sdim		ses->ses_mlen = macini->cri_mlen;
810218893Sdim		if (ses->ses_mlen == 0) {
811218893Sdim			if (macini->cri_alg == CRYPTO_MD5_HMAC)
812218893Sdim				ses->ses_mlen = MD5_HASH_LEN;
813218893Sdim			else
814218893Sdim				ses->ses_mlen = SHA1_HASH_LEN;
815218893Sdim		}
816218893Sdim
817218893Sdim		if (macini->cri_key != NULL) {
818218893Sdim			safe_setup_mackey(ses, macini->cri_alg, macini->cri_key,
819218893Sdim			    macini->cri_klen / 8);
820218893Sdim		}
821218893Sdim	}
822226633Sdim
823226633Sdim	*sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn);
824218893Sdim	return (0);
825226633Sdim}
826218893Sdim
827218893Sdim/*
828218893Sdim * Deallocate a session.
829218893Sdim */
830226633Sdimstatic int
831218893Sdimsafe_freesession(device_t dev, u_int64_t tid)
832226633Sdim{
833218893Sdim	struct safe_softc *sc = device_get_softc(dev);
834218893Sdim	int session, ret;
835218893Sdim	u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
836218893Sdim
837218893Sdim	if (sc == NULL)
838218893Sdim		return (EINVAL);
839218893Sdim
840218893Sdim	session = SAFE_SESSION(sid);
841218893Sdim	if (session < sc->sc_nsessions) {
842218893Sdim		bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));
843218893Sdim		ret = 0;
844218893Sdim	} else
845218893Sdim		ret = EINVAL;
846218893Sdim	return (ret);
847218893Sdim}
848218893Sdim
849218893Sdimstatic void
850218893Sdimsafe_op_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error)
851218893Sdim{
852218893Sdim	struct safe_operand *op = arg;
853218893Sdim
854218893Sdim	DPRINTF(("%s: mapsize %u nsegs %d error %d\n", __func__,
855218893Sdim		(u_int) mapsize, nsegs, error));
856218893Sdim	if (error != 0)
857226633Sdim		return;
858226633Sdim	op->mapsize = mapsize;
859218893Sdim	op->nsegs = nsegs;
860218893Sdim	bcopy(seg, op->segs, nsegs * sizeof (seg[0]));
861218893Sdim}
862218893Sdim
863218893Sdimstatic int
864218893Sdimsafe_process(device_t dev, struct cryptop *crp, int hint)
865218893Sdim{
866226633Sdim	struct safe_softc *sc = device_get_softc(dev);
867218893Sdim	int err = 0, i, nicealign, uniform;
868218893Sdim	struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
869226633Sdim	int bypass, oplen, ivsize;
870226633Sdim	caddr_t iv;
871218893Sdim	int16_t coffset;
872226633Sdim	struct safe_session *ses;
873218893Sdim	struct safe_ringentry *re;
874218893Sdim	struct safe_sarec *sa;
875218893Sdim	struct safe_pdesc *pd;
876234353Sdim	u_int32_t cmd0, cmd1, staterec;
877234353Sdim
878234353Sdim	if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
879234353Sdim		safestats.st_invalid++;
880234353Sdim		return (EINVAL);
881234353Sdim	}
882234353Sdim	if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
883234353Sdim		safestats.st_badsession++;
884234353Sdim		return (EINVAL);
885234353Sdim	}
886234353Sdim
887234353Sdim	mtx_lock(&sc->sc_ringmtx);
888234353Sdim	if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) {
889234353Sdim		safestats.st_ringfull++;
890234353Sdim		sc->sc_needwakeup |= CRYPTO_SYMQ;
891207618Srdivacky		mtx_unlock(&sc->sc_ringmtx);
892207618Srdivacky		return (ERESTART);
893207618Srdivacky	}
894207618Srdivacky	re = sc->sc_front;
895210299Sed
896210299Sed	staterec = re->re_sa.sa_staterec;	/* save */
897210299Sed	/* NB: zero everything but the PE descriptor */
898207618Srdivacky	bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc));
899226633Sdim	re->re_sa.sa_staterec = staterec;	/* restore */
900226633Sdim
901226633Sdim	re->re_crp = crp;
902234353Sdim	re->re_sesn = SAFE_SESSION(crp->crp_sid);
903234353Sdim
904234353Sdim	if (crp->crp_flags & CRYPTO_F_IMBUF) {
905226633Sdim		re->re_src_m = (struct mbuf *)crp->crp_buf;
906234353Sdim		re->re_dst_m = (struct mbuf *)crp->crp_buf;
907234353Sdim	} else if (crp->crp_flags & CRYPTO_F_IOV) {
908226633Sdim		re->re_src_io = (struct uio *)crp->crp_buf;
909226633Sdim		re->re_dst_io = (struct uio *)crp->crp_buf;
910207618Srdivacky	} else {
911207618Srdivacky		safestats.st_badflags++;
912193323Sed		err = EINVAL;
913207618Srdivacky		goto errout;	/* XXX we don't handle contiguous blocks! */
914207618Srdivacky	}
915207618Srdivacky
916207618Srdivacky	sa = &re->re_sa;
917234353Sdim	ses = &sc->sc_sessions[re->re_sesn];
918207618Srdivacky
919207618Srdivacky	crd1 = crp->crp_desc;
920207618Srdivacky	if (crd1 == NULL) {
921207618Srdivacky		safestats.st_nodesc++;
922193323Sed		err = EINVAL;
923193323Sed		goto errout;
924193323Sed	}
925193323Sed	crd2 = crd1->crd_next;
926193323Sed
927193323Sed	cmd0 = SAFE_SA_CMD0_BASIC;		/* basic group operation */
928193323Sed	cmd1 = 0;
929193323Sed	if (crd2 == NULL) {
930193323Sed		if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
931193323Sed		    crd1->crd_alg == CRYPTO_SHA1_HMAC ||
932193323Sed		    crd1->crd_alg == CRYPTO_NULL_HMAC) {
933198090Srdivacky			maccrd = crd1;
934198090Srdivacky			enccrd = NULL;
935198090Srdivacky			cmd0 |= SAFE_SA_CMD0_OP_HASH;
936198090Srdivacky		} else if (crd1->crd_alg == CRYPTO_DES_CBC ||
937198090Srdivacky		    crd1->crd_alg == CRYPTO_3DES_CBC ||
938234353Sdim		    crd1->crd_alg == CRYPTO_AES_CBC ||
939198090Srdivacky		    crd1->crd_alg == CRYPTO_NULL_CBC) {
940198090Srdivacky			maccrd = NULL;
941198090Srdivacky			enccrd = crd1;
942198090Srdivacky			cmd0 |= SAFE_SA_CMD0_OP_CRYPT;
943198090Srdivacky		} else {
944198090Srdivacky			safestats.st_badalg++;
945204642Srdivacky			err = EINVAL;
946204642Srdivacky			goto errout;
947204642Srdivacky		}
948204642Srdivacky	} else {
949198090Srdivacky		if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
950198090Srdivacky		    crd1->crd_alg == CRYPTO_SHA1_HMAC ||
951193323Sed		    crd1->crd_alg == CRYPTO_NULL_HMAC) &&
952193323Sed		    (crd2->crd_alg == CRYPTO_DES_CBC ||
953193323Sed			crd2->crd_alg == CRYPTO_3DES_CBC ||
954193323Sed		        crd2->crd_alg == CRYPTO_AES_CBC ||
955218893Sdim		        crd2->crd_alg == CRYPTO_NULL_CBC) &&
956193323Sed		    ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
957193323Sed			maccrd = crd1;
958193323Sed			enccrd = crd2;
959193323Sed		} else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
960218893Sdim		    crd1->crd_alg == CRYPTO_3DES_CBC ||
961193323Sed		    crd1->crd_alg == CRYPTO_AES_CBC ||
962193323Sed		    crd1->crd_alg == CRYPTO_NULL_CBC) &&
963193323Sed		    (crd2->crd_alg == CRYPTO_MD5_HMAC ||
964193323Sed			crd2->crd_alg == CRYPTO_SHA1_HMAC ||
965193323Sed			crd2->crd_alg == CRYPTO_NULL_HMAC) &&
966193323Sed		    (crd1->crd_flags & CRD_F_ENCRYPT)) {
967193323Sed			enccrd = crd1;
968193323Sed			maccrd = crd2;
969234353Sdim		} else {
970234353Sdim			safestats.st_badalg++;
971234353Sdim			err = EINVAL;
972234353Sdim			goto errout;
973234353Sdim		}
974234353Sdim		cmd0 |= SAFE_SA_CMD0_OP_BOTH;
975234353Sdim	}
976234353Sdim
977234353Sdim	if (enccrd) {
978234353Sdim		if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT)
979234353Sdim			safe_setup_enckey(ses, enccrd->crd_key);
980234353Sdim
981234353Sdim		if (enccrd->crd_alg == CRYPTO_DES_CBC) {
982234353Sdim			cmd0 |= SAFE_SA_CMD0_DES;
983234353Sdim			cmd1 |= SAFE_SA_CMD1_CBC;
984234353Sdim			ivsize = 2*sizeof(u_int32_t);
985234353Sdim		} else if (enccrd->crd_alg == CRYPTO_3DES_CBC) {
986234353Sdim			cmd0 |= SAFE_SA_CMD0_3DES;
987234353Sdim			cmd1 |= SAFE_SA_CMD1_CBC;
988234353Sdim			ivsize = 2*sizeof(u_int32_t);
989234353Sdim		} else if (enccrd->crd_alg == CRYPTO_AES_CBC) {
990234353Sdim			cmd0 |= SAFE_SA_CMD0_AES;
991234353Sdim			cmd1 |= SAFE_SA_CMD1_CBC;
992234353Sdim			if (ses->ses_klen == 128)
993234353Sdim			     cmd1 |=  SAFE_SA_CMD1_AES128;
994234353Sdim			else if (ses->ses_klen == 192)
995234353Sdim			     cmd1 |=  SAFE_SA_CMD1_AES192;
996234353Sdim			else
997234353Sdim			     cmd1 |=  SAFE_SA_CMD1_AES256;
998234353Sdim			ivsize = 4*sizeof(u_int32_t);
999234353Sdim		} else {
1000234353Sdim			cmd0 |= SAFE_SA_CMD0_CRYPT_NULL;
1001221345Sdim			ivsize = 0;
1002234353Sdim		}
1003193323Sed
1004193323Sed		/*
1005193323Sed		 * Setup encrypt/decrypt state.  When using basic ops
1006218893Sdim		 * we can't use an inline IV because hash/crypt offset
1007218893Sdim		 * must be from the end of the IV to the start of the
1008218893Sdim		 * crypt data and this leaves out the preceding header
1009218893Sdim		 * from the hash calculation.  Instead we place the IV
1010218893Sdim		 * in the state record and set the hash/crypt offset to
1011218893Sdim		 * copy both the header+IV.
1012218893Sdim		 */
1013218893Sdim		if (enccrd->crd_flags & CRD_F_ENCRYPT) {
1014218893Sdim			cmd0 |= SAFE_SA_CMD0_OUTBOUND;
1015218893Sdim
1016218893Sdim			if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
1017218893Sdim				iv = enccrd->crd_iv;
1018218893Sdim			else
1019218893Sdim				iv = (caddr_t) ses->ses_iv;
1020218893Sdim			if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
1021218893Sdim				crypto_copyback(crp->crp_flags, crp->crp_buf,
1022218893Sdim				    enccrd->crd_inject, ivsize, iv);
1023218893Sdim			}
1024218893Sdim			bcopy(iv, re->re_sastate.sa_saved_iv, ivsize);
1025218893Sdim			cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV;
1026218893Sdim			re->re_flags |= SAFE_QFLAGS_COPYOUTIV;
1027218893Sdim		} else {
1028218893Sdim			cmd0 |= SAFE_SA_CMD0_INBOUND;
1029218893Sdim
1030218893Sdim			if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
1031218893Sdim				bcopy(enccrd->crd_iv,
1032218893Sdim					re->re_sastate.sa_saved_iv, ivsize);
1033218893Sdim			} else {
1034218893Sdim				crypto_copydata(crp->crp_flags, crp->crp_buf,
1035199989Srdivacky				    enccrd->crd_inject, ivsize,
1036218893Sdim				    (caddr_t)re->re_sastate.sa_saved_iv);
1037218893Sdim			}
1038199989Srdivacky			cmd0 |= SAFE_SA_CMD0_IVLD_STATE;
1039199989Srdivacky		}
1040218893Sdim		/*
1041218893Sdim		 * For basic encryption use the zero pad algorithm.
1042218893Sdim		 * This pads results to an 8-byte boundary and
1043234353Sdim		 * suppresses padding verification for inbound (i.e.
1044218893Sdim		 * decrypt) operations.
1045218893Sdim		 *
1046218893Sdim		 * NB: Not sure if the 8-byte pad boundary is a problem.
1047218893Sdim		 */
1048218893Sdim		cmd0 |= SAFE_SA_CMD0_PAD_ZERO;
1049218893Sdim
1050218893Sdim		/* XXX assert key bufs have the same size */
1051218893Sdim		bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key));
1052218893Sdim	}
1053218893Sdim
1054218893Sdim	if (maccrd) {
1055218893Sdim		if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
1056218893Sdim			safe_setup_mackey(ses, maccrd->crd_alg,
1057218893Sdim			    maccrd->crd_key, maccrd->crd_klen / 8);
1058218893Sdim		}
1059218893Sdim
1060218893Sdim		if (maccrd->crd_alg == CRYPTO_MD5_HMAC) {
1061218893Sdim			cmd0 |= SAFE_SA_CMD0_MD5;
1062218893Sdim			cmd1 |= SAFE_SA_CMD1_HMAC;	/* NB: enable HMAC */
1063218893Sdim		} else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) {
1064218893Sdim			cmd0 |= SAFE_SA_CMD0_SHA1;
1065218893Sdim			cmd1 |= SAFE_SA_CMD1_HMAC;	/* NB: enable HMAC */
1066218893Sdim		} else {
1067218893Sdim			cmd0 |= SAFE_SA_CMD0_HASH_NULL;
1068218893Sdim		}
1069218893Sdim		/*
1070234353Sdim		 * Digest data is loaded from the SA and the hash
1071234353Sdim		 * result is saved to the state block where we
1072218893Sdim		 * retrieve it for return to the caller.
1073218893Sdim		 */
1074234353Sdim		/* XXX assert digest bufs have the same size */
1075218893Sdim		bcopy(ses->ses_hminner, sa->sa_indigest,
1076218893Sdim			sizeof(sa->sa_indigest));
1077218893Sdim		bcopy(ses->ses_hmouter, sa->sa_outdigest,
1078234353Sdim			sizeof(sa->sa_outdigest));
1079234353Sdim
1080234353Sdim		cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH;
1081234353Sdim		re->re_flags |= SAFE_QFLAGS_COPYOUTICV;
1082234353Sdim	}
1083234353Sdim
1084234353Sdim	if (enccrd && maccrd) {
1085234353Sdim		/*
1086218893Sdim		 * The offset from hash data to the start of
1087218893Sdim		 * crypt data is the difference in the skips.
1088234353Sdim		 */
1089218893Sdim		bypass = maccrd->crd_skip;
1090218893Sdim		coffset = enccrd->crd_skip - maccrd->crd_skip;
1091218893Sdim		if (coffset < 0) {
1092218893Sdim			DPRINTF(("%s: hash does not precede crypt; "
1093218893Sdim				"mac skip %u enc skip %u\n",
1094218893Sdim				__func__, maccrd->crd_skip, enccrd->crd_skip));
1095218893Sdim			safestats.st_skipmismatch++;
1096218893Sdim			err = EINVAL;
1097218893Sdim			goto errout;
1098218893Sdim		}
1099218893Sdim		oplen = enccrd->crd_skip + enccrd->crd_len;
1100218893Sdim		if (maccrd->crd_skip + maccrd->crd_len != oplen) {
1101218893Sdim			DPRINTF(("%s: hash amount %u != crypt amount %u\n",
1102218893Sdim				__func__, maccrd->crd_skip + maccrd->crd_len,
1103218893Sdim				oplen));
1104218893Sdim			safestats.st_lenmismatch++;
1105218893Sdim			err = EINVAL;
1106218893Sdim			goto errout;
1107218893Sdim		}
1108218893Sdim#ifdef SAFE_DEBUG
1109218893Sdim		if (safe_debug) {
1110218893Sdim			printf("mac: skip %d, len %d, inject %d\n",
1111218893Sdim			    maccrd->crd_skip, maccrd->crd_len,
1112218893Sdim			    maccrd->crd_inject);
1113218893Sdim			printf("enc: skip %d, len %d, inject %d\n",
1114226633Sdim			    enccrd->crd_skip, enccrd->crd_len,
1115226633Sdim			    enccrd->crd_inject);
1116218893Sdim			printf("bypass %d coffset %d oplen %d\n",
1117218893Sdim				bypass, coffset, oplen);
1118218893Sdim		}
1119218893Sdim#endif
1120218893Sdim		if (coffset & 3) {	/* offset must be 32-bit aligned */
1121218893Sdim			DPRINTF(("%s: coffset %u misaligned\n",
1122218893Sdim				__func__, coffset));
1123218893Sdim			safestats.st_coffmisaligned++;
1124218893Sdim			err = EINVAL;
1125218893Sdim			goto errout;
1126218893Sdim		}
1127218893Sdim		coffset >>= 2;
1128218893Sdim		if (coffset > 255) {	/* offset must be <256 dwords */
1129218893Sdim			DPRINTF(("%s: coffset %u too big\n",
1130218893Sdim				__func__, coffset));
1131218893Sdim			safestats.st_cofftoobig++;
1132218893Sdim			err = EINVAL;
1133218893Sdim			goto errout;
1134218893Sdim		}
1135218893Sdim		/*
1136218893Sdim		 * Tell the hardware to copy the header to the output.
1137218893Sdim		 * The header is defined as the data from the end of
1138218893Sdim		 * the bypass to the start of data to be encrypted.
1139218893Sdim		 * Typically this is the inline IV.  Note that you need
1140218893Sdim		 * to do this even if src+dst are the same; it appears
1141218893Sdim		 * that w/o this bit the crypted data is written
1142193323Sed		 * immediately after the bypass data.
1143193323Sed		 */
1144193323Sed		cmd1 |= SAFE_SA_CMD1_HDRCOPY;
1145218893Sdim		/*
1146218893Sdim		 * Disable IP header mutable bit handling.  This is
1147218893Sdim		 * needed to get correct HMAC calculations.
1148234353Sdim		 */
1149234353Sdim		cmd1 |= SAFE_SA_CMD1_MUTABLE;
1150234353Sdim	} else {
1151234353Sdim		if (enccrd) {
1152234353Sdim			bypass = enccrd->crd_skip;
1153234353Sdim			oplen = bypass + enccrd->crd_len;
1154234353Sdim		} else {
1155234353Sdim			bypass = maccrd->crd_skip;
1156234353Sdim			oplen = bypass + maccrd->crd_len;
1157234353Sdim		}
1158234353Sdim		coffset = 0;
1159226633Sdim	}
1160234353Sdim	/* XXX verify multiple of 4 when using s/g */
1161234353Sdim	if (bypass > 96) {		/* bypass offset must be <= 96 bytes */
1162218893Sdim		DPRINTF(("%s: bypass %u too big\n", __func__, bypass));
1163234353Sdim		safestats.st_bypasstoobig++;
1164234353Sdim		err = EINVAL;
1165234353Sdim		goto errout;
1166234353Sdim	}
1167234353Sdim
1168234353Sdim	if (bus_dmamap_create(sc->sc_srcdmat, BUS_DMA_NOWAIT, &re->re_src_map)) {
1169234353Sdim		safestats.st_nomap++;
1170234353Sdim		err = ENOMEM;
1171234353Sdim		goto errout;
1172234353Sdim	}
1173234353Sdim	if (crp->crp_flags & CRYPTO_F_IMBUF) {
1174234353Sdim		if (bus_dmamap_load_mbuf(sc->sc_srcdmat, re->re_src_map,
1175234353Sdim		    re->re_src_m, safe_op_cb,
1176234353Sdim		    &re->re_src, BUS_DMA_NOWAIT) != 0) {
1177234353Sdim			bus_dmamap_destroy(sc->sc_srcdmat, re->re_src_map);
1178234353Sdim			re->re_src_map = NULL;
1179234353Sdim			safestats.st_noload++;
1180234353Sdim			err = ENOMEM;
1181234353Sdim			goto errout;
1182234353Sdim		}
1183234353Sdim	} else if (crp->crp_flags & CRYPTO_F_IOV) {
1184234353Sdim		if (bus_dmamap_load_uio(sc->sc_srcdmat, re->re_src_map,
1185234353Sdim		    re->re_src_io, safe_op_cb,
1186234353Sdim		    &re->re_src, BUS_DMA_NOWAIT) != 0) {
1187234353Sdim			bus_dmamap_destroy(sc->sc_srcdmat, re->re_src_map);
1188234353Sdim			re->re_src_map = NULL;
1189234353Sdim			safestats.st_noload++;
1190234353Sdim			err = ENOMEM;
1191234353Sdim			goto errout;
1192234353Sdim		}
1193234353Sdim	}
1194234353Sdim	nicealign = safe_dmamap_aligned(&re->re_src);
1195234353Sdim	uniform = safe_dmamap_uniform(&re->re_src);
1196234353Sdim
1197234353Sdim	DPRINTF(("src nicealign %u uniform %u nsegs %u\n",
1198218893Sdim		nicealign, uniform, re->re_src.nsegs));
1199234353Sdim	if (re->re_src.nsegs > 1) {
1200234353Sdim		re->re_desc.d_src = sc->sc_spalloc.dma_paddr +
1201234353Sdim			((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring);
1202234353Sdim		for (i = 0; i < re->re_src_nsegs; i++) {
1203234353Sdim			/* NB: no need to check if there's space */
1204234353Sdim			pd = sc->sc_spfree;
1205218893Sdim			if (++(sc->sc_spfree) == sc->sc_springtop)
1206234353Sdim				sc->sc_spfree = sc->sc_spring;
1207218893Sdim
1208234353Sdim			KASSERT((pd->pd_flags&3) == 0 ||
1209234353Sdim				(pd->pd_flags&3) == SAFE_PD_DONE,
1210234353Sdim				("bogus source particle descriptor; flags %x",
1211234353Sdim				pd->pd_flags));
1212234353Sdim			pd->pd_addr = re->re_src_segs[i].ds_addr;
1213234353Sdim			pd->pd_size = re->re_src_segs[i].ds_len;
1214234353Sdim			pd->pd_flags = SAFE_PD_READY;
1215218893Sdim		}
1216234353Sdim		cmd0 |= SAFE_SA_CMD0_IGATHER;
1217234353Sdim	} else {
1218234353Sdim		/*
1219234353Sdim		 * No need for gather, reference the operand directly.
1220234353Sdim		 */
1221226633Sdim		re->re_desc.d_src = re->re_src_segs[0].ds_addr;
1222234353Sdim	}
1223234353Sdim
1224234353Sdim	if (enccrd == NULL && maccrd != NULL) {
1225234353Sdim		/*
1226234353Sdim		 * Hash op; no destination needed.
1227234353Sdim		 */
1228234353Sdim	} else {
1229199989Srdivacky		if (crp->crp_flags & CRYPTO_F_IOV) {
1230193323Sed			if (!nicealign) {
1231234353Sdim				safestats.st_iovmisaligned++;
1232234353Sdim				err = EINVAL;
1233234353Sdim				goto errout;
1234234353Sdim			}
1235234353Sdim			if (uniform != 1) {
1236234353Sdim				/*
1237193323Sed				 * Source is not suitable for direct use as
1238193323Sed				 * the destination.  Create a new scatter/gather
1239193323Sed				 * list based on the destination requirements
1240193323Sed				 * and check if that's ok.
1241193323Sed				 */
1242198892Srdivacky				if (bus_dmamap_create(sc->sc_dstdmat,
1243218893Sdim				    BUS_DMA_NOWAIT, &re->re_dst_map)) {
1244234353Sdim					safestats.st_nomap++;
1245218893Sdim					err = ENOMEM;
1246218893Sdim					goto errout;
1247198892Srdivacky				}
1248198892Srdivacky				if (bus_dmamap_load_uio(sc->sc_dstdmat,
1249198892Srdivacky				    re->re_dst_map, re->re_dst_io,
1250218893Sdim				    safe_op_cb, &re->re_dst,
1251199989Srdivacky				    BUS_DMA_NOWAIT) != 0) {
1252199989Srdivacky					bus_dmamap_destroy(sc->sc_dstdmat,
1253198892Srdivacky						re->re_dst_map);
1254198892Srdivacky					re->re_dst_map = NULL;
1255198892Srdivacky					safestats.st_noload++;
1256198892Srdivacky					err = ENOMEM;
1257198892Srdivacky					goto errout;
1258198892Srdivacky				}
1259198892Srdivacky				uniform = safe_dmamap_uniform(&re->re_dst);
1260198892Srdivacky				if (!uniform) {
1261224145Sdim					/*
1262224145Sdim					 * There's no way to handle the DMA
1263239462Sdim					 * requirements with this uio.  We
1264239462Sdim					 * could create a separate DMA area for
1265198892Srdivacky					 * the result and then copy it back,
1266218893Sdim					 * but for now we just bail and return
1267199989Srdivacky					 * an error.  Note that uio requests
1268198892Srdivacky					 * > SAFE_MAX_DSIZE are handled because
1269198892Srdivacky					 * the DMA map and segment list for the
1270198892Srdivacky					 * destination wil result in a
1271198892Srdivacky					 * destination particle list that does
1272198892Srdivacky					 * the necessary scatter DMA.
1273198892Srdivacky					 */
1274198892Srdivacky					safestats.st_iovnotuniform++;
1275198892Srdivacky					err = EINVAL;
1276198892Srdivacky					goto errout;
1277198892Srdivacky				}
1278198892Srdivacky			} else
1279198892Srdivacky				re->re_dst = re->re_src;
1280234353Sdim		} else if (crp->crp_flags & CRYPTO_F_IMBUF) {
1281234353Sdim			if (nicealign && uniform == 1) {
1282234353Sdim				/*
1283198892Srdivacky				 * Source layout is suitable for direct
1284198892Srdivacky				 * sharing of the DMA map and segment list.
1285198892Srdivacky				 */
1286198892Srdivacky				re->re_dst = re->re_src;
1287198892Srdivacky			} else if (nicealign && uniform == 2) {
1288198892Srdivacky				/*
1289198892Srdivacky				 * The source is properly aligned but requires a
1290218893Sdim				 * different particle list to handle DMA of the
1291218893Sdim				 * result.  Create a new map and do the load to
1292218893Sdim				 * create the segment list.  The particle
1293218893Sdim				 * descriptor setup code below will handle the
1294198892Srdivacky				 * rest.
1295198892Srdivacky				 */
1296198892Srdivacky				if (bus_dmamap_create(sc->sc_dstdmat,
1297198892Srdivacky				    BUS_DMA_NOWAIT, &re->re_dst_map)) {
1298198892Srdivacky					safestats.st_nomap++;
1299198892Srdivacky					err = ENOMEM;
1300198892Srdivacky					goto errout;
1301198892Srdivacky				}
1302218893Sdim				if (bus_dmamap_load_mbuf(sc->sc_dstdmat,
1303218893Sdim				    re->re_dst_map, re->re_dst_m,
1304218893Sdim				    safe_op_cb, &re->re_dst,
1305218893Sdim				    BUS_DMA_NOWAIT) != 0) {
1306218893Sdim					bus_dmamap_destroy(sc->sc_dstdmat,
1307218893Sdim						re->re_dst_map);
1308218893Sdim					re->re_dst_map = NULL;
1309218893Sdim					safestats.st_noload++;
1310218893Sdim					err = ENOMEM;
1311198892Srdivacky					goto errout;
1312198892Srdivacky				}
1313198892Srdivacky			} else {		/* !(aligned and/or uniform) */
1314198892Srdivacky				int totlen, len;
1315199481Srdivacky				struct mbuf *m, *top, **mp;
1316199481Srdivacky
1317199481Srdivacky				/*
1318198953Srdivacky				 * DMA constraints require that we allocate a
1319198953Srdivacky				 * new mbuf chain for the destination.  We
1320218893Sdim				 * allocate an entire new set of mbufs of
1321198953Srdivacky				 * optimal/required size and then tell the
1322198953Srdivacky				 * hardware to copy any bits that are not
1323198953Srdivacky				 * created as a byproduct of the operation.
1324198953Srdivacky				 */
1325198953Srdivacky				if (!nicealign)
1326198953Srdivacky					safestats.st_unaligned++;
1327198953Srdivacky				if (!uniform)
1328210299Sed					safestats.st_notuniform++;
1329210299Sed				totlen = re->re_src_mapsize;
1330210299Sed				if (re->re_src_m->m_flags & M_PKTHDR) {
1331199481Srdivacky					len = MHLEN;
1332199481Srdivacky					MGETHDR(m, M_DONTWAIT, MT_DATA);
1333199481Srdivacky					if (m && !m_dup_pkthdr(m, re->re_src_m,
1334202375Srdivacky					    M_DONTWAIT)) {
1335204642Srdivacky						m_free(m);
1336204642Srdivacky						m = NULL;
1337204642Srdivacky					}
1338234353Sdim				} else {
1339199481Srdivacky					len = MLEN;
1340199481Srdivacky					MGET(m, M_DONTWAIT, MT_DATA);
1341204642Srdivacky				}
1342204642Srdivacky				if (m == NULL) {
1343204642Srdivacky					safestats.st_nombuf++;
1344204642Srdivacky					err = sc->sc_nqchip ? ERESTART : ENOMEM;
1345204642Srdivacky					goto errout;
1346204642Srdivacky				}
1347204642Srdivacky				if (totlen >= MINCLSIZE) {
1348204642Srdivacky					MCLGET(m, M_DONTWAIT);
1349234353Sdim					if ((m->m_flags & M_EXT) == 0) {
1350234353Sdim						m_free(m);
1351234353Sdim						safestats.st_nomcl++;
1352234353Sdim						err = sc->sc_nqchip ?
1353234353Sdim							ERESTART : ENOMEM;
1354234353Sdim						goto errout;
1355234353Sdim					}
1356234353Sdim					len = MCLBYTES;
1357234353Sdim				}
1358234353Sdim				m->m_len = len;
1359234353Sdim				top = NULL;
1360234353Sdim				mp = &top;
1361234353Sdim
1362234353Sdim				while (totlen > 0) {
1363234353Sdim					if (top) {
1364234353Sdim						MGET(m, M_DONTWAIT, MT_DATA);
1365208599Srdivacky						if (m == NULL) {
1366198953Srdivacky							m_freem(top);
1367234353Sdim							safestats.st_nombuf++;
1368234353Sdim							err = sc->sc_nqchip ?
1369234353Sdim							    ERESTART : ENOMEM;
1370234353Sdim							goto errout;
1371234353Sdim						}
1372234353Sdim						len = MLEN;
1373234353Sdim					}
1374234353Sdim					if (top && totlen >= MINCLSIZE) {
1375234353Sdim						MCLGET(m, M_DONTWAIT);
1376199481Srdivacky						if ((m->m_flags & M_EXT) == 0) {
1377199481Srdivacky							*mp = m;
1378199481Srdivacky							m_freem(top);
1379198953Srdivacky							safestats.st_nomcl++;
1380198953Srdivacky							err = sc->sc_nqchip ?
1381198953Srdivacky							    ERESTART : ENOMEM;
1382198953Srdivacky							goto errout;
1383226633Sdim						}
1384226633Sdim						len = MCLBYTES;
1385226633Sdim					}
1386226633Sdim					m->m_len = len = min(totlen, len);
1387226633Sdim					totlen -= len;
1388226633Sdim					*mp = m;
1389226633Sdim					mp = &m->m_next;
1390226633Sdim				}
1391226633Sdim				re->re_dst_m = top;
1392226633Sdim				if (bus_dmamap_create(sc->sc_dstdmat,
1393226633Sdim				    BUS_DMA_NOWAIT, &re->re_dst_map) != 0) {
1394226633Sdim					safestats.st_nomap++;
1395226633Sdim					err = ENOMEM;
1396226633Sdim					goto errout;
1397193323Sed				}
1398193323Sed				if (bus_dmamap_load_mbuf(sc->sc_dstdmat,
1399193323Sed				    re->re_dst_map, re->re_dst_m,
1400218893Sdim				    safe_op_cb, &re->re_dst,
1401198892Srdivacky				    BUS_DMA_NOWAIT) != 0) {
1402198892Srdivacky					bus_dmamap_destroy(sc->sc_dstdmat,
1403198892Srdivacky					re->re_dst_map);
1404198892Srdivacky					re->re_dst_map = NULL;
1405218893Sdim					safestats.st_noload++;
1406198892Srdivacky					err = ENOMEM;
1407193323Sed					goto errout;
1408193323Sed				}
1409193323Sed				if (re->re_src.mapsize > oplen) {
1410193323Sed					/*
1411202375Srdivacky					 * There's data following what the
1412210299Sed					 * hardware will copy for us.  If this
1413202375Srdivacky					 * isn't just the ICV (that's going to
1414210299Sed					 * be written on completion), copy it
1415198892Srdivacky					 * to the new mbufs
1416202375Srdivacky					 */
1417199989Srdivacky					if (!(maccrd &&
1418202375Srdivacky					    (re->re_src.mapsize-oplen) == 12 &&
1419193323Sed					    maccrd->crd_inject == oplen))
1420193323Sed						safe_mcopy(re->re_src_m,
1421198892Srdivacky							   re->re_dst_m,
1422198892Srdivacky							   oplen);
1423210299Sed					else
1424210299Sed						safestats.st_noicvcopy++;
1425210299Sed				}
1426210299Sed			}
1427198892Srdivacky		} else {
1428193323Sed			safestats.st_badflags++;
1429198892Srdivacky			err = EINVAL;
1430198892Srdivacky			goto errout;
1431198892Srdivacky		}
1432198953Srdivacky
1433198953Srdivacky		if (re->re_dst.nsegs > 1) {
1434210299Sed			re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr +
1435198892Srdivacky			    ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring);
1436218893Sdim			for (i = 0; i < re->re_dst_nsegs; i++) {
1437218893Sdim				pd = sc->sc_dpfree;
1438218893Sdim				KASSERT((pd->pd_flags&3) == 0 ||
1439208599Srdivacky					(pd->pd_flags&3) == SAFE_PD_DONE,
1440208599Srdivacky					("bogus dest particle descriptor; flags %x",
1441208599Srdivacky						pd->pd_flags));
1442208599Srdivacky				if (++(sc->sc_dpfree) == sc->sc_dpringtop)
1443208599Srdivacky					sc->sc_dpfree = sc->sc_dpring;
1444208599Srdivacky				pd->pd_addr = re->re_dst_segs[i].ds_addr;
1445218893Sdim				pd->pd_flags = SAFE_PD_READY;
1446208599Srdivacky			}
1447208599Srdivacky			cmd0 |= SAFE_SA_CMD0_OSCATTER;
1448193323Sed		} else {
1449193323Sed			/*
1450198892Srdivacky			 * No need for scatter, reference the operand directly.
1451193323Sed			 */
1452193323Sed			re->re_desc.d_dst = re->re_dst_segs[0].ds_addr;
1453198892Srdivacky		}
1454198892Srdivacky	}
1455193323Sed
1456193323Sed	/*
1457193323Sed	 * All done with setup; fillin the SA command words
1458193323Sed	 * and the packet engine descriptor.  The operation
1459193323Sed	 * is now ready for submission to the hardware.
1460218893Sdim	 */
1461218893Sdim	sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI;
1462193323Sed	sa->sa_cmd1 = cmd1
1463210299Sed		    | (coffset << SAFE_SA_CMD1_OFFSET_S)
1464210299Sed		    | SAFE_SA_CMD1_SAREV1	/* Rev 1 SA data structure */
1465210299Sed		    | SAFE_SA_CMD1_SRPCI
1466210299Sed		    ;
1467210299Sed	/*
1468210299Sed	 * NB: the order of writes is important here.  In case the
1469210299Sed	 * chip is scanning the ring because of an outstanding request
1470210299Sed	 * it might nab this one too.  In that case we need to make
1471210299Sed	 * sure the setup is complete before we write the length
1472210299Sed	 * field of the descriptor as it signals the descriptor is
1473210299Sed	 * ready for processing.
1474210299Sed	 */
1475210299Sed	re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI;
1476210299Sed	if (maccrd)
1477210299Sed		re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL;
1478210299Sed	re->re_desc.d_len = oplen
1479210299Sed			  | SAFE_PE_LEN_READY
1480210299Sed			  | (bypass << SAFE_PE_LEN_BYPASS_S)
1481210299Sed			  ;
1482210299Sed
1483210299Sed	safestats.st_ipackets++;
1484210299Sed	safestats.st_ibytes += oplen;
1485210299Sed
1486210299Sed	if (++(sc->sc_front) == sc->sc_ringtop)
1487210299Sed		sc->sc_front = sc->sc_ring;
1488210299Sed
1489210299Sed	/* XXX honor batching */
1490	safe_feed(sc, re);
1491	mtx_unlock(&sc->sc_ringmtx);
1492	return (0);
1493
1494errout:
1495	if ((re->re_dst_m != NULL) && (re->re_src_m != re->re_dst_m))
1496		m_freem(re->re_dst_m);
1497
1498	if (re->re_dst_map != NULL && re->re_dst_map != re->re_src_map) {
1499		bus_dmamap_unload(sc->sc_dstdmat, re->re_dst_map);
1500		bus_dmamap_destroy(sc->sc_dstdmat, re->re_dst_map);
1501	}
1502	if (re->re_src_map != NULL) {
1503		bus_dmamap_unload(sc->sc_srcdmat, re->re_src_map);
1504		bus_dmamap_destroy(sc->sc_srcdmat, re->re_src_map);
1505	}
1506	mtx_unlock(&sc->sc_ringmtx);
1507	if (err != ERESTART) {
1508		crp->crp_etype = err;
1509		crypto_done(crp);
1510	} else {
1511		sc->sc_needwakeup |= CRYPTO_SYMQ;
1512	}
1513	return (err);
1514}
1515
1516static void
1517safe_callback(struct safe_softc *sc, struct safe_ringentry *re)
1518{
1519	struct cryptop *crp = (struct cryptop *)re->re_crp;
1520	struct cryptodesc *crd;
1521
1522	safestats.st_opackets++;
1523	safestats.st_obytes += re->re_dst.mapsize;
1524
1525	safe_dma_sync(&sc->sc_ringalloc,
1526		BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1527	if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) {
1528		device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n",
1529			re->re_desc.d_csr,
1530			re->re_sa.sa_cmd0, re->re_sa.sa_cmd1);
1531		safestats.st_peoperr++;
1532		crp->crp_etype = EIO;		/* something more meaningful? */
1533	}
1534	if (re->re_dst_map != NULL && re->re_dst_map != re->re_src_map) {
1535		bus_dmamap_sync(sc->sc_dstdmat, re->re_dst_map,
1536		    BUS_DMASYNC_POSTREAD);
1537		bus_dmamap_unload(sc->sc_dstdmat, re->re_dst_map);
1538		bus_dmamap_destroy(sc->sc_dstdmat, re->re_dst_map);
1539	}
1540	bus_dmamap_sync(sc->sc_srcdmat, re->re_src_map, BUS_DMASYNC_POSTWRITE);
1541	bus_dmamap_unload(sc->sc_srcdmat, re->re_src_map);
1542	bus_dmamap_destroy(sc->sc_srcdmat, re->re_src_map);
1543
1544	/*
1545	 * If result was written to a differet mbuf chain, swap
1546	 * it in as the return value and reclaim the original.
1547	 */
1548	if ((crp->crp_flags & CRYPTO_F_IMBUF) && re->re_src_m != re->re_dst_m) {
1549		m_freem(re->re_src_m);
1550		crp->crp_buf = (caddr_t)re->re_dst_m;
1551	}
1552
1553	if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) {
1554		/* copy out IV for future use */
1555		for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
1556			int ivsize;
1557
1558			if (crd->crd_alg == CRYPTO_DES_CBC ||
1559			    crd->crd_alg == CRYPTO_3DES_CBC) {
1560				ivsize = 2*sizeof(u_int32_t);
1561			} else if (crd->crd_alg == CRYPTO_AES_CBC) {
1562				ivsize = 4*sizeof(u_int32_t);
1563			} else
1564				continue;
1565			crypto_copydata(crp->crp_flags, crp->crp_buf,
1566			    crd->crd_skip + crd->crd_len - ivsize, ivsize,
1567			    (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv);
1568			break;
1569		}
1570	}
1571
1572	if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) {
1573		/* copy out ICV result */
1574		for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
1575			if (!(crd->crd_alg == CRYPTO_MD5_HMAC ||
1576			    crd->crd_alg == CRYPTO_SHA1_HMAC ||
1577			    crd->crd_alg == CRYPTO_NULL_HMAC))
1578				continue;
1579			if (crd->crd_alg == CRYPTO_SHA1_HMAC) {
1580				/*
1581				 * SHA-1 ICV's are byte-swapped; fix 'em up
1582				 * before copy them to their destination.
1583				 */
1584				re->re_sastate.sa_saved_indigest[0] =
1585				    bswap32(re->re_sastate.sa_saved_indigest[0]);
1586				re->re_sastate.sa_saved_indigest[1] =
1587				    bswap32(re->re_sastate.sa_saved_indigest[1]);
1588				re->re_sastate.sa_saved_indigest[2] =
1589				    bswap32(re->re_sastate.sa_saved_indigest[2]);
1590			}
1591			crypto_copyback(crp->crp_flags, crp->crp_buf,
1592			    crd->crd_inject,
1593			    sc->sc_sessions[re->re_sesn].ses_mlen,
1594			    (caddr_t)re->re_sastate.sa_saved_indigest);
1595			break;
1596		}
1597	}
1598	crypto_done(crp);
1599}
1600
1601/*
1602 * Copy all data past offset from srcm to dstm.
1603 */
1604static void
1605safe_mcopy(struct mbuf *srcm, struct mbuf *dstm, u_int offset)
1606{
1607	u_int j, dlen, slen;
1608	caddr_t dptr, sptr;
1609
1610	/*
1611	 * Advance src and dst to offset.
1612	 */
1613	j = offset;
1614	while (j >= 0) {
1615		if (srcm->m_len > j)
1616			break;
1617		j -= srcm->m_len;
1618		srcm = srcm->m_next;
1619		if (srcm == NULL)
1620			return;
1621	}
1622	sptr = mtod(srcm, caddr_t) + j;
1623	slen = srcm->m_len - j;
1624
1625	j = offset;
1626	while (j >= 0) {
1627		if (dstm->m_len > j)
1628			break;
1629		j -= dstm->m_len;
1630		dstm = dstm->m_next;
1631		if (dstm == NULL)
1632			return;
1633	}
1634	dptr = mtod(dstm, caddr_t) + j;
1635	dlen = dstm->m_len - j;
1636
1637	/*
1638	 * Copy everything that remains.
1639	 */
1640	for (;;) {
1641		j = min(slen, dlen);
1642		bcopy(sptr, dptr, j);
1643		if (slen == j) {
1644			srcm = srcm->m_next;
1645			if (srcm == NULL)
1646				return;
1647			sptr = srcm->m_data;
1648			slen = srcm->m_len;
1649		} else
1650			sptr += j, slen -= j;
1651		if (dlen == j) {
1652			dstm = dstm->m_next;
1653			if (dstm == NULL)
1654				return;
1655			dptr = dstm->m_data;
1656			dlen = dstm->m_len;
1657		} else
1658			dptr += j, dlen -= j;
1659	}
1660}
1661
1662#ifndef SAFE_NO_RNG
1663#define	SAFE_RNG_MAXWAIT	1000
1664
1665static void
1666safe_rng_init(struct safe_softc *sc)
1667{
1668	u_int32_t w, v;
1669	int i;
1670
1671	WRITE_REG(sc, SAFE_RNG_CTRL, 0);
1672	/* use default value according to the manual */
1673	WRITE_REG(sc, SAFE_RNG_CNFG, 0x834);	/* magic from SafeNet */
1674	WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
1675
1676	/*
1677	 * There is a bug in rev 1.0 of the 1140 that when the RNG
1678	 * is brought out of reset the ready status flag does not
1679	 * work until the RNG has finished its internal initialization.
1680	 *
1681	 * So in order to determine the device is through its
1682	 * initialization we must read the data register, using the
1683	 * status reg in the read in case it is initialized.  Then read
1684	 * the data register until it changes from the first read.
1685	 * Once it changes read the data register until it changes
1686	 * again.  At this time the RNG is considered initialized.
1687	 * This could take between 750ms - 1000ms in time.
1688	 */
1689	i = 0;
1690	w = READ_REG(sc, SAFE_RNG_OUT);
1691	do {
1692		v = READ_REG(sc, SAFE_RNG_OUT);
1693		if (v != w) {
1694			w = v;
1695			break;
1696		}
1697		DELAY(10);
1698	} while (++i < SAFE_RNG_MAXWAIT);
1699
1700	/* Wait Until data changes again */
1701	i = 0;
1702	do {
1703		v = READ_REG(sc, SAFE_RNG_OUT);
1704		if (v != w)
1705			break;
1706		DELAY(10);
1707	} while (++i < SAFE_RNG_MAXWAIT);
1708}
1709
1710static __inline void
1711safe_rng_disable_short_cycle(struct safe_softc *sc)
1712{
1713	WRITE_REG(sc, SAFE_RNG_CTRL,
1714		READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN);
1715}
1716
1717static __inline void
1718safe_rng_enable_short_cycle(struct safe_softc *sc)
1719{
1720	WRITE_REG(sc, SAFE_RNG_CTRL,
1721		READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN);
1722}
1723
1724static __inline u_int32_t
1725safe_rng_read(struct safe_softc *sc)
1726{
1727	int i;
1728
1729	i = 0;
1730	while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT)
1731		;
1732	return READ_REG(sc, SAFE_RNG_OUT);
1733}
1734
1735static void
1736safe_rng(void *arg)
1737{
1738	struct safe_softc *sc = arg;
1739	u_int32_t buf[SAFE_RNG_MAXBUFSIZ];	/* NB: maybe move to softc */
1740	u_int maxwords;
1741	int i;
1742
1743	safestats.st_rng++;
1744	/*
1745	 * Fetch the next block of data.
1746	 */
1747	maxwords = safe_rngbufsize;
1748	if (maxwords > SAFE_RNG_MAXBUFSIZ)
1749		maxwords = SAFE_RNG_MAXBUFSIZ;
1750retry:
1751	for (i = 0; i < maxwords; i++)
1752		buf[i] = safe_rng_read(sc);
1753	/*
1754	 * Check the comparator alarm count and reset the h/w if
1755	 * it exceeds our threshold.  This guards against the
1756	 * hardware oscillators resonating with external signals.
1757	 */
1758	if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) {
1759		u_int32_t freq_inc, w;
1760
1761		DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__,
1762			READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm));
1763		safestats.st_rngalarm++;
1764		safe_rng_enable_short_cycle(sc);
1765		freq_inc = 18;
1766		for (i = 0; i < 64; i++) {
1767			w = READ_REG(sc, SAFE_RNG_CNFG);
1768			freq_inc = ((w + freq_inc) & 0x3fL);
1769			w = ((w & ~0x3fL) | freq_inc);
1770			WRITE_REG(sc, SAFE_RNG_CNFG, w);
1771
1772			WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
1773
1774			(void) safe_rng_read(sc);
1775			DELAY(25);
1776
1777			if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) {
1778				safe_rng_disable_short_cycle(sc);
1779				goto retry;
1780			}
1781			freq_inc = 1;
1782		}
1783		safe_rng_disable_short_cycle(sc);
1784	} else
1785		WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
1786
1787	(*sc->sc_harvest)(sc->sc_rndtest, buf, maxwords*sizeof (u_int32_t));
1788	callout_reset(&sc->sc_rngto,
1789		hz * (safe_rnginterval ? safe_rnginterval : 1), safe_rng, sc);
1790}
1791#endif /* SAFE_NO_RNG */
1792
1793static void
1794safe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1795{
1796	bus_addr_t *paddr = (bus_addr_t*) arg;
1797	*paddr = segs->ds_addr;
1798}
1799
1800static int
1801safe_dma_malloc(
1802	struct safe_softc *sc,
1803	bus_size_t size,
1804	struct safe_dma_alloc *dma,
1805	int mapflags
1806)
1807{
1808	int r;
1809
1810	r = bus_dma_tag_create(NULL,			/* parent */
1811			       sizeof(u_int32_t), 0,	/* alignment, bounds */
1812			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1813			       BUS_SPACE_MAXADDR,	/* highaddr */
1814			       NULL, NULL,		/* filter, filterarg */
1815			       size,			/* maxsize */
1816			       1,			/* nsegments */
1817			       size,			/* maxsegsize */
1818			       BUS_DMA_ALLOCNOW,	/* flags */
1819			       NULL, NULL,		/* locking */
1820			       &dma->dma_tag);
1821	if (r != 0) {
1822		device_printf(sc->sc_dev, "safe_dma_malloc: "
1823			"bus_dma_tag_create failed; error %u\n", r);
1824		goto fail_0;
1825	}
1826
1827	r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map);
1828	if (r != 0) {
1829		device_printf(sc->sc_dev, "safe_dma_malloc: "
1830			"bus_dmamap_create failed; error %u\n", r);
1831		goto fail_1;
1832	}
1833
1834	r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr,
1835			     BUS_DMA_NOWAIT, &dma->dma_map);
1836	if (r != 0) {
1837		device_printf(sc->sc_dev, "safe_dma_malloc: "
1838			"bus_dmammem_alloc failed; size %zu, error %u\n",
1839			size, r);
1840		goto fail_2;
1841	}
1842
1843	r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
1844		            size,
1845			    safe_dmamap_cb,
1846			    &dma->dma_paddr,
1847			    mapflags | BUS_DMA_NOWAIT);
1848	if (r != 0) {
1849		device_printf(sc->sc_dev, "safe_dma_malloc: "
1850			"bus_dmamap_load failed; error %u\n", r);
1851		goto fail_3;
1852	}
1853
1854	dma->dma_size = size;
1855	return (0);
1856
1857fail_3:
1858	bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1859fail_2:
1860	bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1861fail_1:
1862	bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
1863	bus_dma_tag_destroy(dma->dma_tag);
1864fail_0:
1865	dma->dma_map = NULL;
1866	dma->dma_tag = NULL;
1867	return (r);
1868}
1869
1870static void
1871safe_dma_free(struct safe_softc *sc, struct safe_dma_alloc *dma)
1872{
1873	bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1874	bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1875	bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
1876	bus_dma_tag_destroy(dma->dma_tag);
1877}
1878
1879/*
1880 * Resets the board.  Values in the regesters are left as is
1881 * from the reset (i.e. initial values are assigned elsewhere).
1882 */
1883static void
1884safe_reset_board(struct safe_softc *sc)
1885{
1886	u_int32_t v;
1887	/*
1888	 * Reset the device.  The manual says no delay
1889	 * is needed between marking and clearing reset.
1890	 */
1891	v = READ_REG(sc, SAFE_PE_DMACFG) &~
1892		(SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET |
1893		 SAFE_PE_DMACFG_SGRESET);
1894	WRITE_REG(sc, SAFE_PE_DMACFG, v
1895				    | SAFE_PE_DMACFG_PERESET
1896				    | SAFE_PE_DMACFG_PDRRESET
1897				    | SAFE_PE_DMACFG_SGRESET);
1898	WRITE_REG(sc, SAFE_PE_DMACFG, v);
1899}
1900
1901/*
1902 * Initialize registers we need to touch only once.
1903 */
1904static void
1905safe_init_board(struct safe_softc *sc)
1906{
1907	u_int32_t v, dwords;
1908
1909	v = READ_REG(sc, SAFE_PE_DMACFG);
1910	v &=~ SAFE_PE_DMACFG_PEMODE;
1911	v |= SAFE_PE_DMACFG_FSENA		/* failsafe enable */
1912	  |  SAFE_PE_DMACFG_GPRPCI		/* gather ring on PCI */
1913	  |  SAFE_PE_DMACFG_SPRPCI		/* scatter ring on PCI */
1914	  |  SAFE_PE_DMACFG_ESDESC		/* endian-swap descriptors */
1915	  |  SAFE_PE_DMACFG_ESSA		/* endian-swap SA's */
1916	  |  SAFE_PE_DMACFG_ESPDESC		/* endian-swap part. desc's */
1917	  ;
1918	WRITE_REG(sc, SAFE_PE_DMACFG, v);
1919#if 0
1920	/* XXX select byte swap based on host byte order */
1921	WRITE_REG(sc, SAFE_ENDIAN, 0x1b);
1922#endif
1923	if (sc->sc_chiprev == SAFE_REV(1,0)) {
1924		/*
1925		 * Avoid large PCI DMA transfers.  Rev 1.0 has a bug where
1926		 * "target mode transfers" done while the chip is DMA'ing
1927		 * >1020 bytes cause the hardware to lockup.  To avoid this
1928		 * we reduce the max PCI transfer size and use small source
1929		 * particle descriptors (<= 256 bytes).
1930		 */
1931		WRITE_REG(sc, SAFE_DMA_CFG, 256);
1932		device_printf(sc->sc_dev,
1933			"Reduce max DMA size to %u words for rev %u.%u WAR\n",
1934			(READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff,
1935			SAFE_REV_MAJ(sc->sc_chiprev),
1936			SAFE_REV_MIN(sc->sc_chiprev));
1937	}
1938
1939	/* NB: operands+results are overlaid */
1940	WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr);
1941	WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr);
1942	/*
1943	 * Configure ring entry size and number of items in the ring.
1944	 */
1945	KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0,
1946		("PE ring entry not 32-bit aligned!"));
1947	dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t);
1948	WRITE_REG(sc, SAFE_PE_RINGCFG,
1949		(dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE);
1950	WRITE_REG(sc, SAFE_PE_RINGPOLL, 0);	/* disable polling */
1951
1952	WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr);
1953	WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr);
1954	WRITE_REG(sc, SAFE_PE_PARTSIZE,
1955		(SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART);
1956	/*
1957	 * NB: destination particles are fixed size.  We use
1958	 *     an mbuf cluster and require all results go to
1959	 *     clusters or smaller.
1960	 */
1961	WRITE_REG(sc, SAFE_PE_PARTCFG, SAFE_MAX_DSIZE);
1962
1963	/* it's now safe to enable PE mode, do it */
1964	WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE);
1965
1966	/*
1967	 * Configure hardware to use level-triggered interrupts and
1968	 * to interrupt after each descriptor is processed.
1969	 */
1970	WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL);
1971	WRITE_REG(sc, SAFE_HI_DESC_CNT, 1);
1972	WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR);
1973}
1974
1975/*
1976 * Init PCI registers
1977 */
1978static void
1979safe_init_pciregs(device_t dev)
1980{
1981}
1982
1983/*
1984 * Clean up after a chip crash.
1985 * It is assumed that the caller in splimp()
1986 */
1987static void
1988safe_cleanchip(struct safe_softc *sc)
1989{
1990
1991	if (sc->sc_nqchip != 0) {
1992		struct safe_ringentry *re = sc->sc_back;
1993
1994		while (re != sc->sc_front) {
1995			if (re->re_desc.d_csr != 0)
1996				safe_free_entry(sc, re);
1997			if (++re == sc->sc_ringtop)
1998				re = sc->sc_ring;
1999		}
2000		sc->sc_back = re;
2001		sc->sc_nqchip = 0;
2002	}
2003}
2004
2005/*
2006 * free a safe_q
2007 * It is assumed that the caller is within splimp().
2008 */
2009static int
2010safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re)
2011{
2012	struct cryptop *crp;
2013
2014	/*
2015	 * Free header MCR
2016	 */
2017	if ((re->re_dst_m != NULL) && (re->re_src_m != re->re_dst_m))
2018		m_freem(re->re_dst_m);
2019
2020	crp = (struct cryptop *)re->re_crp;
2021
2022	re->re_desc.d_csr = 0;
2023
2024	crp->crp_etype = EFAULT;
2025	crypto_done(crp);
2026	return(0);
2027}
2028
2029/*
2030 * Routine to reset the chip and clean up.
2031 * It is assumed that the caller is in splimp()
2032 */
2033static void
2034safe_totalreset(struct safe_softc *sc)
2035{
2036	safe_reset_board(sc);
2037	safe_init_board(sc);
2038	safe_cleanchip(sc);
2039}
2040
2041/*
2042 * Is the operand suitable aligned for direct DMA.  Each
2043 * segment must be aligned on a 32-bit boundary and all
2044 * but the last segment must be a multiple of 4 bytes.
2045 */
2046static int
2047safe_dmamap_aligned(const struct safe_operand *op)
2048{
2049	int i;
2050
2051	for (i = 0; i < op->nsegs; i++) {
2052		if (op->segs[i].ds_addr & 3)
2053			return (0);
2054		if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3))
2055			return (0);
2056	}
2057	return (1);
2058}
2059
2060/*
2061 * Is the operand suitable for direct DMA as the destination
2062 * of an operation.  The hardware requires that each ``particle''
2063 * but the last in an operation result have the same size.  We
2064 * fix that size at SAFE_MAX_DSIZE bytes.  This routine returns
2065 * 0 if some segment is not a multiple of of this size, 1 if all
2066 * segments are exactly this size, or 2 if segments are at worst
2067 * a multple of this size.
2068 */
2069static int
2070safe_dmamap_uniform(const struct safe_operand *op)
2071{
2072	int result = 1;
2073
2074	if (op->nsegs > 0) {
2075		int i;
2076
2077		for (i = 0; i < op->nsegs-1; i++) {
2078			if (op->segs[i].ds_len % SAFE_MAX_DSIZE)
2079				return (0);
2080			if (op->segs[i].ds_len != SAFE_MAX_DSIZE)
2081				result = 2;
2082		}
2083	}
2084	return (result);
2085}
2086
2087#ifdef SAFE_DEBUG
2088static void
2089safe_dump_dmastatus(struct safe_softc *sc, const char *tag)
2090{
2091	printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n"
2092		, tag
2093		, READ_REG(sc, SAFE_DMA_ENDIAN)
2094		, READ_REG(sc, SAFE_DMA_SRCADDR)
2095		, READ_REG(sc, SAFE_DMA_DSTADDR)
2096		, READ_REG(sc, SAFE_DMA_STAT)
2097	);
2098}
2099
2100static void
2101safe_dump_intrstate(struct safe_softc *sc, const char *tag)
2102{
2103	printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n"
2104		, tag
2105		, READ_REG(sc, SAFE_HI_CFG)
2106		, READ_REG(sc, SAFE_HI_MASK)
2107		, READ_REG(sc, SAFE_HI_DESC_CNT)
2108		, READ_REG(sc, SAFE_HU_STAT)
2109		, READ_REG(sc, SAFE_HM_STAT)
2110	);
2111}
2112
2113static void
2114safe_dump_ringstate(struct safe_softc *sc, const char *tag)
2115{
2116	u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT);
2117
2118	/* NB: assume caller has lock on ring */
2119	printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n",
2120		tag,
2121		estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S),
2122		(unsigned long)(sc->sc_back - sc->sc_ring),
2123		(unsigned long)(sc->sc_front - sc->sc_ring));
2124}
2125
2126static void
2127safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re)
2128{
2129	int ix, nsegs;
2130
2131	ix = re - sc->sc_ring;
2132	printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n"
2133		, tag
2134		, re, ix
2135		, re->re_desc.d_csr
2136		, re->re_desc.d_src
2137		, re->re_desc.d_dst
2138		, re->re_desc.d_sa
2139		, re->re_desc.d_len
2140	);
2141	if (re->re_src.nsegs > 1) {
2142		ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) /
2143			sizeof(struct safe_pdesc);
2144		for (nsegs = re->re_src.nsegs; nsegs; nsegs--) {
2145			printf(" spd[%u] %p: %p size %u flags %x"
2146				, ix, &sc->sc_spring[ix]
2147				, (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr
2148				, sc->sc_spring[ix].pd_size
2149				, sc->sc_spring[ix].pd_flags
2150			);
2151			if (sc->sc_spring[ix].pd_size == 0)
2152				printf(" (zero!)");
2153			printf("\n");
2154			if (++ix == SAFE_TOTAL_SPART)
2155				ix = 0;
2156		}
2157	}
2158	if (re->re_dst.nsegs > 1) {
2159		ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) /
2160			sizeof(struct safe_pdesc);
2161		for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) {
2162			printf(" dpd[%u] %p: %p flags %x\n"
2163				, ix, &sc->sc_dpring[ix]
2164				, (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr
2165				, sc->sc_dpring[ix].pd_flags
2166			);
2167			if (++ix == SAFE_TOTAL_DPART)
2168				ix = 0;
2169		}
2170	}
2171	printf("sa: cmd0 %08x cmd1 %08x staterec %x\n",
2172		re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec);
2173	printf("sa: key %x %x %x %x %x %x %x %x\n"
2174		, re->re_sa.sa_key[0]
2175		, re->re_sa.sa_key[1]
2176		, re->re_sa.sa_key[2]
2177		, re->re_sa.sa_key[3]
2178		, re->re_sa.sa_key[4]
2179		, re->re_sa.sa_key[5]
2180		, re->re_sa.sa_key[6]
2181		, re->re_sa.sa_key[7]
2182	);
2183	printf("sa: indigest %x %x %x %x %x\n"
2184		, re->re_sa.sa_indigest[0]
2185		, re->re_sa.sa_indigest[1]
2186		, re->re_sa.sa_indigest[2]
2187		, re->re_sa.sa_indigest[3]
2188		, re->re_sa.sa_indigest[4]
2189	);
2190	printf("sa: outdigest %x %x %x %x %x\n"
2191		, re->re_sa.sa_outdigest[0]
2192		, re->re_sa.sa_outdigest[1]
2193		, re->re_sa.sa_outdigest[2]
2194		, re->re_sa.sa_outdigest[3]
2195		, re->re_sa.sa_outdigest[4]
2196	);
2197	printf("sr: iv %x %x %x %x\n"
2198		, re->re_sastate.sa_saved_iv[0]
2199		, re->re_sastate.sa_saved_iv[1]
2200		, re->re_sastate.sa_saved_iv[2]
2201		, re->re_sastate.sa_saved_iv[3]
2202	);
2203	printf("sr: hashbc %u indigest %x %x %x %x %x\n"
2204		, re->re_sastate.sa_saved_hashbc
2205		, re->re_sastate.sa_saved_indigest[0]
2206		, re->re_sastate.sa_saved_indigest[1]
2207		, re->re_sastate.sa_saved_indigest[2]
2208		, re->re_sastate.sa_saved_indigest[3]
2209		, re->re_sastate.sa_saved_indigest[4]
2210	);
2211}
2212
2213static void
2214safe_dump_ring(struct safe_softc *sc, const char *tag)
2215{
2216	mtx_lock(&sc->sc_ringmtx);
2217	printf("\nSafeNet Ring State:\n");
2218	safe_dump_intrstate(sc, tag);
2219	safe_dump_dmastatus(sc, tag);
2220	safe_dump_ringstate(sc, tag);
2221	if (sc->sc_nqchip) {
2222		struct safe_ringentry *re = sc->sc_back;
2223		do {
2224			safe_dump_request(sc, tag, re);
2225			if (++re == sc->sc_ringtop)
2226				re = sc->sc_ring;
2227		} while (re != sc->sc_front);
2228	}
2229	mtx_unlock(&sc->sc_ringmtx);
2230}
2231
2232static int
2233sysctl_hw_safe_dump(SYSCTL_HANDLER_ARGS)
2234{
2235	char dmode[64];
2236	int error;
2237
2238	strncpy(dmode, "", sizeof(dmode) - 1);
2239	dmode[sizeof(dmode) - 1] = '\0';
2240	error = sysctl_handle_string(oidp, &dmode[0], sizeof(dmode), req);
2241
2242	if (error == 0 && req->newptr != NULL) {
2243		struct safe_softc *sc = safec;
2244
2245		if (!sc)
2246			return EINVAL;
2247		if (strncmp(dmode, "dma", 3) == 0)
2248			safe_dump_dmastatus(sc, "safe0");
2249		else if (strncmp(dmode, "int", 3) == 0)
2250			safe_dump_intrstate(sc, "safe0");
2251		else if (strncmp(dmode, "ring", 4) == 0)
2252			safe_dump_ring(sc, "safe0");
2253		else
2254			return EINVAL;
2255	}
2256	return error;
2257}
2258SYSCTL_PROC(_hw_safe, OID_AUTO, dump, CTLTYPE_STRING | CTLFLAG_RW,
2259	0, 0, sysctl_hw_safe_dump, "A", "Dump driver state");
2260#endif /* SAFE_DEBUG */
2261