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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/systm.h>
32 #include <sys/kstat.h>
33 #include <sys/crypto/common.h>
34 #include <sys/crypto/spi.h>
35 #include <sys/n2rng.h>
36
37 /*
38 * Kernel statistics.
39 */
40 static int n2rng_ksupdate(kstat_t *, int);
41
42 /*
43 * Initialize Kstats.
44 */
45 void
n2rng_ksinit(n2rng_t * n2rng)46 n2rng_ksinit(n2rng_t *n2rng)
47 {
48 int instance;
49 int i;
50 int j;
51 char buf[64];
52
53 if (ddi_getprop(DDI_DEV_T_ANY, n2rng->n_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(n2rng->n_dip);
63
64 /*
65 * Named kstats.
66 */
67 n2rng->n_ksp = kstat_create(DRIVER, instance, NULL, "misc",
68 KSTAT_TYPE_NAMED,
69 sizeof (n2rng_stat_t) / sizeof (kstat_named_t),
70 KSTAT_FLAG_WRITABLE);
71 if (n2rng->n_ksp == NULL) {
72 n2rng_error(n2rng, "unable to create kstats");
73 } else {
74 n2rng_stat_t *dkp = (n2rng_stat_t *)n2rng->n_ksp->ks_data;
75
76 kstat_named_init(&dkp->ns_status, "status", KSTAT_DATA_CHAR);
77
78 kstat_named_init(&dkp->ns_algs[DS_RNGJOBS], "rngjobs",
79 KSTAT_DATA_ULONGLONG);
80 kstat_named_init(&dkp->ns_algs[DS_RNGBYTES], "rngbytes",
81 KSTAT_DATA_ULONGLONG);
82
83 if (n2rng_iscontrol(n2rng)) {
84
85 for (i = 0; i < n2rng->n_ctl_data->n_num_rngs; i++) {
86 (void) sprintf(buf, "rng%d-state", i);
87 kstat_named_init(&dkp->ns_rngstate[i],
88 buf, KSTAT_DATA_CHAR);
89 for (j = 0; j < N2RNG_NOSC; j++) {
90 (void) sprintf(buf,
91 "rng%d-cell%d-bias", i, j);
92 kstat_named_init
93 (&dkp->ns_rngbias[i][j],
94 buf, KSTAT_DATA_ULONGLONG);
95 (void) sprintf(buf,
96 "rng%d-cell%d-entropy", i, j);
97 kstat_named_init
98 (&dkp->ns_rngentropy[i][j],
99 buf, KSTAT_DATA_ULONGLONG);
100 }
101 }
102 }
103 n2rng->n_ksp->ks_update = n2rng_ksupdate;
104 n2rng->n_ksp->ks_private = n2rng;
105
106 kstat_install(n2rng->n_ksp);
107 }
108 }
109
110 /*
111 * Deinitialize Kstats.
112 */
113 void
n2rng_ksdeinit(n2rng_t * n2rng)114 n2rng_ksdeinit(n2rng_t *n2rng)
115 {
116
117 if (n2rng->n_ksp != NULL) {
118 kstat_delete(n2rng->n_ksp);
119 n2rng->n_ksp = NULL;
120 }
121 }
122
123 /*
124 * Update Kstats.
125 */
126 int
n2rng_ksupdate(kstat_t * ksp,int rw)127 n2rng_ksupdate(kstat_t *ksp, int rw)
128 {
129 n2rng_t *n2rng;
130 n2rng_stat_t *dkp;
131 int i;
132 int j;
133
134 n2rng = (n2rng_t *)ksp->ks_private;
135 dkp = (n2rng_stat_t *)ksp->ks_data;
136
137 if (rw == KSTAT_WRITE) {
138 for (i = 0; i < DS_MAX; i++) {
139 n2rng->n_stats[i] = dkp->ns_algs[i].value.ull;
140 }
141 } else {
142 /* handy status value */
143 if (n2rng_isfailed(n2rng)) {
144 /* device has failed */
145 (void) strcpy(dkp->ns_status.value.c, "failed");
146 } else if (!n2rng_isconfigured(n2rng)) {
147 /* device is not configured */
148 (void) strcpy(dkp->ns_status.value.c, "offline");
149 } else {
150 /* everything looks good */
151 (void) strcpy(dkp->ns_status.value.c, "online");
152 }
153
154 for (i = 0; i < DS_MAX; i++) {
155 dkp->ns_algs[i].value.ull = n2rng->n_stats[i];
156 }
157
158 if (n2rng_iscontrol(n2rng)) {
159 rng_entry_t *rng;
160
161 for (i = 0; i < n2rng->n_ctl_data->n_num_rngs; i++) {
162
163 rng = &n2rng->n_ctl_data->n_rngs[i];
164
165 switch (rng->n_rng_state) {
166 case CTL_STATE_ERROR:
167 (void) strcpy(
168 dkp->ns_rngstate[i].value.c,
169 "error");
170 break;
171 case CTL_STATE_HEALTHCHECK:
172 (void) strcpy(
173 dkp->ns_rngstate[i].value.c,
174 "healthcheck");
175 break;
176 case CTL_STATE_CONFIGURED:
177 (void) strcpy(
178 dkp->ns_rngstate[i].value.c,
179 "online");
180 break;
181 case CTL_STATE_UNCONFIGURED:
182 (void) strcpy(
183 dkp->ns_rngstate[i].value.c,
184 "offline");
185 break;
186 default:
187 (void) strcpy(
188 dkp->ns_rngstate[i].value.c,
189 "unknown");
190 break;
191 }
192 for (j = 0; j < N2RNG_NOSC; j++) {
193 dkp->ns_rngbias[i][j].value.ull =
194 rng->n_bias_info[j].bias;
195 dkp->ns_rngentropy[i][j].value.ull =
196 rng->n_bias_info[j].entropy;
197 }
198 }
199 }
200 }
201
202 return (0);
203 }
204