1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Deimos - cryptographic acceleration based upon Broadcom 582x.
31 */
32
33#include <sys/types.h>
34#include <sys/ddi.h>
35#include <sys/sunddi.h>
36#include <sys/kstat.h>
37#include <sys/crypto/dca.h>
38
39/*
40 * Kernel statistics.
41 */
42static int dca_ksupdate(kstat_t *, int);
43
44/*
45 * Initialize Kstats.
46 */
47void
48dca_ksinit(dca_t *dca)
49{
50	char	buf[64];
51	int	instance;
52
53	if (ddi_getprop(DDI_DEV_T_ANY, dca->dca_dip,
54	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "nostats", 0) != 0) {
55		/*
56		 * sysadmin has explicity disabled stats to prevent
57		 * covert channel.
58		 */
59		return;
60	}
61
62	instance = ddi_get_instance(dca->dca_dip);
63
64	/*
65	 * Interrupt kstats.
66	 */
67	(void) sprintf(buf, "%sc%d", DRIVER, instance);
68	if ((dca->dca_intrstats = kstat_create(DRIVER, instance, buf,
69	    "controller", KSTAT_TYPE_INTR, 1, 0)) == NULL) {
70		dca_error(dca, "unable to create interrupt kstat");
71	} else {
72		kstat_install(dca->dca_intrstats);
73	}
74
75	/*
76	 * Named kstats.
77	 */
78	if ((dca->dca_ksp = kstat_create(DRIVER, instance, NULL, "misc",
79	    KSTAT_TYPE_NAMED, sizeof (dca_stat_t) / sizeof (kstat_named_t),
80	    KSTAT_FLAG_WRITABLE)) == NULL) {
81		dca_error(dca, "unable to create kstats");
82	} else {
83		dca_stat_t *dkp = (dca_stat_t *)dca->dca_ksp->ks_data;
84		kstat_named_init(&dkp->ds_status, "status", KSTAT_DATA_CHAR);
85		kstat_named_init(&dkp->ds_mcr[0].ds_submit, "mcr1submit",
86		    KSTAT_DATA_ULONGLONG);
87		kstat_named_init(&dkp->ds_mcr[0].ds_flowctl, "mcr1flowctl",
88		    KSTAT_DATA_ULONGLONG);
89		kstat_named_init(&dkp->ds_mcr[0].ds_lowater, "mcr1lowater",
90		    KSTAT_DATA_ULONGLONG);
91		kstat_named_init(&dkp->ds_mcr[0].ds_hiwater, "mcr1hiwater",
92		    KSTAT_DATA_ULONGLONG);
93		kstat_named_init(&dkp->ds_mcr[0].ds_maxreqs, "mcr1maxreqs",
94		    KSTAT_DATA_ULONGLONG);
95		kstat_named_init(&dkp->ds_mcr[1].ds_submit, "mcr2submit",
96		    KSTAT_DATA_ULONGLONG);
97		kstat_named_init(&dkp->ds_mcr[1].ds_flowctl, "mcr2flowctl",
98		    KSTAT_DATA_ULONGLONG);
99		kstat_named_init(&dkp->ds_mcr[1].ds_lowater, "mcr2lowater",
100		    KSTAT_DATA_ULONGLONG);
101		kstat_named_init(&dkp->ds_mcr[1].ds_hiwater, "mcr2hiwater",
102		    KSTAT_DATA_ULONGLONG);
103		kstat_named_init(&dkp->ds_mcr[1].ds_maxreqs, "mcr2maxreqs",
104		    KSTAT_DATA_ULONGLONG);
105#ifdef	DS_RC4JOBS
106		/* rc4 */
107		kstat_named_init(&dkp->ds_algs[DS_RC4JOBS], "rc4jobs",
108		    KSTAT_DATA_ULONGLONG);
109#endif
110#ifdef	DS_RC4BYTES
111		kstat_named_init(&dkp->ds_algs[DS_RC4BYTES], "rc4bytes",
112		    KSTAT_DATA_ULONGLONG);
113#endif
114		/* 3des */
115		kstat_named_init(&dkp->ds_algs[DS_3DESJOBS], "3desjobs",
116		    KSTAT_DATA_ULONGLONG);
117		kstat_named_init(&dkp->ds_algs[DS_3DESBYTES], "3desbytes",
118		    KSTAT_DATA_ULONGLONG);
119		/* rsa */
120		kstat_named_init(&dkp->ds_algs[DS_RSAPUBLIC], "rsapublic",
121		    KSTAT_DATA_ULONGLONG);
122		kstat_named_init(&dkp->ds_algs[DS_RSAPRIVATE], "rsaprivate",
123		    KSTAT_DATA_ULONGLONG);
124		/* dsa */
125		kstat_named_init(&dkp->ds_algs[DS_DSASIGN], "dsasign",
126		    KSTAT_DATA_ULONGLONG);
127		kstat_named_init(&dkp->ds_algs[DS_DSAVERIFY], "dsaverify",
128		    KSTAT_DATA_ULONGLONG);
129#ifdef	DS_DHPUBLIC
130		/* diffie-hellman */
131		kstat_named_init(&dkp->ds_algs[DS_DHPUBLIC], "dhpublic",
132		    KSTAT_DATA_ULONGLONG);
133#endif
134#ifdef	DS_DHSECRET
135		kstat_named_init(&dkp->ds_algs[DS_DHSECRET], "dhsecret",
136		    KSTAT_DATA_ULONGLONG);
137#endif
138		/* random number jobs */
139		kstat_named_init(&dkp->ds_algs[DS_RNGJOBS], "rngjobs",
140		    KSTAT_DATA_ULONGLONG);
141		kstat_named_init(&dkp->ds_algs[DS_RNGBYTES], "rngbytes",
142		    KSTAT_DATA_ULONGLONG);
143		kstat_named_init(&dkp->ds_algs[DS_RNGSHA1JOBS], "rngsha1jobs",
144		    KSTAT_DATA_ULONGLONG);
145		kstat_named_init(&dkp->ds_algs[DS_RNGSHA1BYTES],
146		    "rngsha1bytes", KSTAT_DATA_ULONGLONG);
147		dca->dca_ksp->ks_update = dca_ksupdate;
148		dca->dca_ksp->ks_private = dca;
149		kstat_install(dca->dca_ksp);
150	}
151}
152
153/*
154 * Update Kstats.
155 */
156int
157dca_ksupdate(kstat_t *ksp, int rw)
158{
159	dca_t		*dca;
160	dca_stat_t	*dkp;
161	int		i;
162
163	dca = (dca_t *)ksp->ks_private;
164	dkp = (dca_stat_t *)ksp->ks_data;
165
166	if (rw == KSTAT_WRITE) {
167		for (i = 0; i < DS_MAX; i++) {
168			dca->dca_stats[i] = dkp->ds_algs[i].value.ull;
169		}
170		for (i = MCR1; i <= MCR2; i++) {
171			WORKLIST(dca, i)->dwl_submit =
172			    dkp->ds_mcr[i - 1].ds_submit.value.ull;
173			WORKLIST(dca, i)->dwl_flowctl =
174			    dkp->ds_mcr[i - 1].ds_flowctl.value.ull;
175			/* hiwater, lowater, and maxreqs are read only */
176		}
177	} else {
178		/* handy status value */
179		if (dca->dca_flags & DCA_FAILED) {
180			/* device has failed */
181			(void) strcpy(dkp->ds_status.value.c, "fail");
182		} else if ((WORKLIST(dca, MCR1)->dwl_drain) ||
183		    (WORKLIST(dca, MCR2)->dwl_drain)) {
184			/* device is draining for DR */
185			(void) strcpy(dkp->ds_status.value.c, "drain");
186		} else {
187			/* everything looks good */
188			(void) strcpy(dkp->ds_status.value.c, "online");
189		}
190
191		for (i = 0; i < DS_MAX; i++) {
192			dkp->ds_algs[i].value.ull = dca->dca_stats[i];
193		}
194		for (i = MCR1; i <= MCR2; i++) {
195			dkp->ds_mcr[i - 1].ds_submit.value.ull =
196			    WORKLIST(dca, i)->dwl_submit;
197			dkp->ds_mcr[i - 1].ds_flowctl.value.ull =
198			    WORKLIST(dca, i)->dwl_flowctl;
199			dkp->ds_mcr[i - 1].ds_lowater.value.ull =
200			    WORKLIST(dca, i)->dwl_lowater;
201			dkp->ds_mcr[i - 1].ds_hiwater.value.ull =
202			    WORKLIST(dca, i)->dwl_hiwater;
203			dkp->ds_mcr[i - 1].ds_maxreqs.value.ull =
204			    WORKLIST(dca, i)->dwl_reqspermcr;
205		}
206	}
207	return (0);
208}
209