1*b91bbe38SToomas Soome /*
2*b91bbe38SToomas Soome * This file and its contents are supplied under the terms of the
3*b91bbe38SToomas Soome * Common Development and Distribution License ("CDDL"), version 1.0.
4*b91bbe38SToomas Soome * You may only use this file in accordance with the terms of version
5*b91bbe38SToomas Soome * 1.0 of the CDDL.
6*b91bbe38SToomas Soome *
7*b91bbe38SToomas Soome * A full copy of the text of the CDDL should have accompanied this
8*b91bbe38SToomas Soome * source. A copy of the CDDL is also available via the Internet at
9*b91bbe38SToomas Soome * http://www.illumos.org/license/CDDL.
10*b91bbe38SToomas Soome */
11*b91bbe38SToomas Soome
12*b91bbe38SToomas Soome /*
13*b91bbe38SToomas Soome * Copyright 2023 Toomas Soome <tsoome@me.com>
14*b91bbe38SToomas Soome */
15*b91bbe38SToomas Soome
16*b91bbe38SToomas Soome /*
17*b91bbe38SToomas Soome * Virtio random data device.
18*b91bbe38SToomas Soome */
19*b91bbe38SToomas Soome
20*b91bbe38SToomas Soome #include <sys/types.h>
21*b91bbe38SToomas Soome #include <sys/modctl.h>
22*b91bbe38SToomas Soome #include <sys/conf.h>
23*b91bbe38SToomas Soome #include <sys/sunddi.h>
24*b91bbe38SToomas Soome #include <sys/sysmacros.h>
25*b91bbe38SToomas Soome #include <sys/crypto/spi.h>
26*b91bbe38SToomas Soome #include <sys/time.h>
27*b91bbe38SToomas Soome #include <virtio.h>
28*b91bbe38SToomas Soome
29*b91bbe38SToomas Soome #define VIORAND_FEATURES 0
30*b91bbe38SToomas Soome #define VIORAND_RQ 0
31*b91bbe38SToomas Soome
32*b91bbe38SToomas Soome typedef struct viorand_state viorand_state_t;
33*b91bbe38SToomas Soome
34*b91bbe38SToomas Soome typedef struct viorand_rdbuf {
35*b91bbe38SToomas Soome viorand_state_t *rb_viornd;
36*b91bbe38SToomas Soome virtio_dma_t *rb_dma;
37*b91bbe38SToomas Soome virtio_chain_t *rb_chain;
38*b91bbe38SToomas Soome size_t rb_recv_len;
39*b91bbe38SToomas Soome uchar_t *rb_req_buf;
40*b91bbe38SToomas Soome size_t rb_req_len;
41*b91bbe38SToomas Soome crypto_req_handle_t rb_req_handle;
42*b91bbe38SToomas Soome list_node_t rb_link;
43*b91bbe38SToomas Soome } viorand_rdbuf_t;
44*b91bbe38SToomas Soome
45*b91bbe38SToomas Soome struct viorand_state {
46*b91bbe38SToomas Soome dev_info_t *vio_dip;
47*b91bbe38SToomas Soome kmutex_t vio_mutex;
48*b91bbe38SToomas Soome kcondvar_t vio_cv;
49*b91bbe38SToomas Soome crypto_kcf_provider_handle_t vio_handle;
50*b91bbe38SToomas Soome taskq_t *vio_taskq;
51*b91bbe38SToomas Soome virtio_t *vio_virtio;
52*b91bbe38SToomas Soome virtio_queue_t *vio_rq;
53*b91bbe38SToomas Soome uint64_t vio_features;
54*b91bbe38SToomas Soome
55*b91bbe38SToomas Soome uint_t vio_rdbufs_capacity;
56*b91bbe38SToomas Soome uint_t vio_rdbufs_alloc;
57*b91bbe38SToomas Soome list_t vio_rdbufs_free; /* Free list */
58*b91bbe38SToomas Soome viorand_rdbuf_t *vio_rdbuf_mem;
59*b91bbe38SToomas Soome };
60*b91bbe38SToomas Soome
61*b91bbe38SToomas Soome static const ddi_dma_attr_t viorand_dma_attr = {
62*b91bbe38SToomas Soome .dma_attr_version = DMA_ATTR_V0,
63*b91bbe38SToomas Soome .dma_attr_addr_lo = 0x0000000000000000,
64*b91bbe38SToomas Soome .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFF,
65*b91bbe38SToomas Soome .dma_attr_count_max = 0x00000000FFFFFFFF,
66*b91bbe38SToomas Soome .dma_attr_align = 1,
67*b91bbe38SToomas Soome .dma_attr_burstsizes = 1,
68*b91bbe38SToomas Soome .dma_attr_minxfer = 1,
69*b91bbe38SToomas Soome .dma_attr_maxxfer = 0x00000000FFFFFFFF,
70*b91bbe38SToomas Soome .dma_attr_seg = 0x00000000FFFFFFFF,
71*b91bbe38SToomas Soome .dma_attr_sgllen = 64,
72*b91bbe38SToomas Soome .dma_attr_granular = 1,
73*b91bbe38SToomas Soome .dma_attr_flags = 0
74*b91bbe38SToomas Soome };
75*b91bbe38SToomas Soome
76*b91bbe38SToomas Soome /* If set, we do not allow to detach ourselves. */
77*b91bbe38SToomas Soome boolean_t virtio_registered = B_TRUE;
78*b91bbe38SToomas Soome static void *viorand_statep;
79*b91bbe38SToomas Soome
80*b91bbe38SToomas Soome static int viorand_attach(dev_info_t *, ddi_attach_cmd_t);
81*b91bbe38SToomas Soome static int viorand_detach(dev_info_t *, ddi_detach_cmd_t);
82*b91bbe38SToomas Soome static int viorand_quiesce(dev_info_t *);
83*b91bbe38SToomas Soome
84*b91bbe38SToomas Soome static void viorand_provider_status(crypto_provider_handle_t, uint_t *);
85*b91bbe38SToomas Soome static int viorand_generate_random(crypto_provider_handle_t,
86*b91bbe38SToomas Soome crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t);
87*b91bbe38SToomas Soome
88*b91bbe38SToomas Soome static uint_t viorand_interrupt(caddr_t, caddr_t);
89*b91bbe38SToomas Soome
90*b91bbe38SToomas Soome /*
91*b91bbe38SToomas Soome * Module linkage information for the kernel.
92*b91bbe38SToomas Soome */
93*b91bbe38SToomas Soome
94*b91bbe38SToomas Soome static struct dev_ops devops = {
95*b91bbe38SToomas Soome .devo_rev = DEVO_REV,
96*b91bbe38SToomas Soome .devo_refcnt = 0,
97*b91bbe38SToomas Soome .devo_getinfo = ddi_no_info,
98*b91bbe38SToomas Soome .devo_identify = nulldev,
99*b91bbe38SToomas Soome .devo_probe = nulldev,
100*b91bbe38SToomas Soome .devo_attach = viorand_attach,
101*b91bbe38SToomas Soome .devo_detach = viorand_detach,
102*b91bbe38SToomas Soome .devo_reset = nodev,
103*b91bbe38SToomas Soome .devo_cb_ops = NULL,
104*b91bbe38SToomas Soome .devo_bus_ops = NULL,
105*b91bbe38SToomas Soome .devo_power = NULL,
106*b91bbe38SToomas Soome .devo_quiesce = viorand_quiesce
107*b91bbe38SToomas Soome };
108*b91bbe38SToomas Soome
109*b91bbe38SToomas Soome static struct modldrv modldrv = {
110*b91bbe38SToomas Soome .drv_modops = &mod_driverops,
111*b91bbe38SToomas Soome .drv_linkinfo = "VirtIO Random Number Driver",
112*b91bbe38SToomas Soome .drv_dev_ops = &devops
113*b91bbe38SToomas Soome };
114*b91bbe38SToomas Soome
115*b91bbe38SToomas Soome static struct modlcrypto modlcrypto = {
116*b91bbe38SToomas Soome .crypto_modops = &mod_cryptoops,
117*b91bbe38SToomas Soome .crypto_linkinfo = "VirtIO Random Number Provider"
118*b91bbe38SToomas Soome };
119*b91bbe38SToomas Soome
120*b91bbe38SToomas Soome static struct modlinkage modlinkage = {
121*b91bbe38SToomas Soome .ml_rev = MODREV_1,
122*b91bbe38SToomas Soome .ml_linkage = { &modldrv, &modlcrypto, NULL }
123*b91bbe38SToomas Soome };
124*b91bbe38SToomas Soome
125*b91bbe38SToomas Soome /*
126*b91bbe38SToomas Soome * CSPI information (entry points, provider info, etc.)
127*b91bbe38SToomas Soome */
128*b91bbe38SToomas Soome static void viorand_provider_status(crypto_provider_handle_t, uint_t *);
129*b91bbe38SToomas Soome
130*b91bbe38SToomas Soome static crypto_control_ops_t viorand_control_ops = {
131*b91bbe38SToomas Soome .provider_status = viorand_provider_status
132*b91bbe38SToomas Soome };
133*b91bbe38SToomas Soome
134*b91bbe38SToomas Soome static int viorand_generate_random(crypto_provider_handle_t,
135*b91bbe38SToomas Soome crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t);
136*b91bbe38SToomas Soome
137*b91bbe38SToomas Soome static crypto_random_number_ops_t viorand_random_number_ops = {
138*b91bbe38SToomas Soome .generate_random = viorand_generate_random
139*b91bbe38SToomas Soome };
140*b91bbe38SToomas Soome
141*b91bbe38SToomas Soome static crypto_ops_t viorand_crypto_ops = {
142*b91bbe38SToomas Soome .co_control_ops = &viorand_control_ops,
143*b91bbe38SToomas Soome .co_random_ops = &viorand_random_number_ops
144*b91bbe38SToomas Soome };
145*b91bbe38SToomas Soome
146*b91bbe38SToomas Soome static crypto_provider_info_t viorand_prov_info = {
147*b91bbe38SToomas Soome .pi_interface_version = CRYPTO_SPI_VERSION_1,
148*b91bbe38SToomas Soome .pi_provider_description = "VirtIO Random Number Provider",
149*b91bbe38SToomas Soome .pi_provider_type = CRYPTO_HW_PROVIDER,
150*b91bbe38SToomas Soome .pi_ops_vector = &viorand_crypto_ops,
151*b91bbe38SToomas Soome };
152*b91bbe38SToomas Soome
153*b91bbe38SToomas Soome /*
154*b91bbe38SToomas Soome * DDI entry points.
155*b91bbe38SToomas Soome */
156*b91bbe38SToomas Soome int
_init(void)157*b91bbe38SToomas Soome _init(void)
158*b91bbe38SToomas Soome {
159*b91bbe38SToomas Soome int error;
160*b91bbe38SToomas Soome
161*b91bbe38SToomas Soome error = ddi_soft_state_init(&viorand_statep,
162*b91bbe38SToomas Soome sizeof (viorand_state_t), 0);
163*b91bbe38SToomas Soome if (error != 0)
164*b91bbe38SToomas Soome return (error);
165*b91bbe38SToomas Soome
166*b91bbe38SToomas Soome return (mod_install(&modlinkage));
167*b91bbe38SToomas Soome }
168*b91bbe38SToomas Soome
169*b91bbe38SToomas Soome int
_fini(void)170*b91bbe38SToomas Soome _fini(void)
171*b91bbe38SToomas Soome {
172*b91bbe38SToomas Soome int error;
173*b91bbe38SToomas Soome
174*b91bbe38SToomas Soome error = mod_remove(&modlinkage);
175*b91bbe38SToomas Soome if (error == 0)
176*b91bbe38SToomas Soome ddi_soft_state_fini(&viorand_statep);
177*b91bbe38SToomas Soome
178*b91bbe38SToomas Soome return (error);
179*b91bbe38SToomas Soome }
180*b91bbe38SToomas Soome
181*b91bbe38SToomas Soome int
_info(struct modinfo * modinfop)182*b91bbe38SToomas Soome _info(struct modinfo *modinfop)
183*b91bbe38SToomas Soome {
184*b91bbe38SToomas Soome return (mod_info(&modlinkage, modinfop));
185*b91bbe38SToomas Soome }
186*b91bbe38SToomas Soome
187*b91bbe38SToomas Soome /*
188*b91bbe38SToomas Soome * return buffer from free list.
189*b91bbe38SToomas Soome */
190*b91bbe38SToomas Soome static viorand_rdbuf_t *
viorand_rbuf_alloc(viorand_state_t * state)191*b91bbe38SToomas Soome viorand_rbuf_alloc(viorand_state_t *state)
192*b91bbe38SToomas Soome {
193*b91bbe38SToomas Soome viorand_rdbuf_t *rb;
194*b91bbe38SToomas Soome
195*b91bbe38SToomas Soome VERIFY(MUTEX_HELD(&state->vio_mutex));
196*b91bbe38SToomas Soome
197*b91bbe38SToomas Soome while ((rb = list_remove_head(&state->vio_rdbufs_free)) == NULL)
198*b91bbe38SToomas Soome cv_wait(&state->vio_cv, &state->vio_mutex);
199*b91bbe38SToomas Soome
200*b91bbe38SToomas Soome state->vio_rdbufs_alloc++;
201*b91bbe38SToomas Soome return (rb);
202*b91bbe38SToomas Soome }
203*b91bbe38SToomas Soome
204*b91bbe38SToomas Soome /*
205*b91bbe38SToomas Soome * return buffer to free list
206*b91bbe38SToomas Soome */
207*b91bbe38SToomas Soome static void
viorand_rbuf_free(viorand_state_t * state,viorand_rdbuf_t * rb)208*b91bbe38SToomas Soome viorand_rbuf_free(viorand_state_t *state, viorand_rdbuf_t *rb)
209*b91bbe38SToomas Soome {
210*b91bbe38SToomas Soome VERIFY(MUTEX_HELD(&state->vio_mutex));
211*b91bbe38SToomas Soome VERIFY3U(state->vio_rdbufs_alloc, >, 0);
212*b91bbe38SToomas Soome
213*b91bbe38SToomas Soome state->vio_rdbufs_alloc--;
214*b91bbe38SToomas Soome virtio_chain_clear(rb->rb_chain);
215*b91bbe38SToomas Soome if (rb->rb_dma != NULL) {
216*b91bbe38SToomas Soome virtio_dma_free(rb->rb_dma);
217*b91bbe38SToomas Soome rb->rb_dma = NULL;
218*b91bbe38SToomas Soome }
219*b91bbe38SToomas Soome list_insert_head(&state->vio_rdbufs_free, rb);
220*b91bbe38SToomas Soome }
221*b91bbe38SToomas Soome
222*b91bbe38SToomas Soome /*
223*b91bbe38SToomas Soome * Free all allocated buffers. This is called to clean everything up,
224*b91bbe38SToomas Soome * so we do not want to leave anything around.
225*b91bbe38SToomas Soome */
226*b91bbe38SToomas Soome static void
viorand_free_bufs(viorand_state_t * state)227*b91bbe38SToomas Soome viorand_free_bufs(viorand_state_t *state)
228*b91bbe38SToomas Soome {
229*b91bbe38SToomas Soome VERIFY(MUTEX_HELD(&state->vio_mutex));
230*b91bbe38SToomas Soome
231*b91bbe38SToomas Soome for (uint_t i = 0; i < state->vio_rdbufs_capacity; i++) {
232*b91bbe38SToomas Soome viorand_rdbuf_t *rb = &state->vio_rdbuf_mem[i];
233*b91bbe38SToomas Soome
234*b91bbe38SToomas Soome if (rb->rb_dma != NULL) {
235*b91bbe38SToomas Soome virtio_dma_free(rb->rb_dma);
236*b91bbe38SToomas Soome rb->rb_dma = NULL;
237*b91bbe38SToomas Soome }
238*b91bbe38SToomas Soome
239*b91bbe38SToomas Soome if (rb->rb_chain != NULL) {
240*b91bbe38SToomas Soome virtio_chain_free(rb->rb_chain);
241*b91bbe38SToomas Soome rb->rb_chain = NULL;
242*b91bbe38SToomas Soome }
243*b91bbe38SToomas Soome }
244*b91bbe38SToomas Soome
245*b91bbe38SToomas Soome if (state->vio_rdbuf_mem != NULL) {
246*b91bbe38SToomas Soome kmem_free(state->vio_rdbuf_mem,
247*b91bbe38SToomas Soome sizeof (viorand_rdbuf_t) * state->vio_rdbufs_capacity);
248*b91bbe38SToomas Soome state->vio_rdbuf_mem = NULL;
249*b91bbe38SToomas Soome state->vio_rdbufs_capacity = 0;
250*b91bbe38SToomas Soome state->vio_rdbufs_alloc = 0;
251*b91bbe38SToomas Soome }
252*b91bbe38SToomas Soome }
253*b91bbe38SToomas Soome
254*b91bbe38SToomas Soome static int
viorand_alloc_bufs(viorand_state_t * state)255*b91bbe38SToomas Soome viorand_alloc_bufs(viorand_state_t *state)
256*b91bbe38SToomas Soome {
257*b91bbe38SToomas Soome VERIFY(MUTEX_HELD(&state->vio_mutex));
258*b91bbe38SToomas Soome
259*b91bbe38SToomas Soome state->vio_rdbufs_capacity = virtio_queue_size(state->vio_rq);
260*b91bbe38SToomas Soome state->vio_rdbuf_mem = kmem_zalloc(sizeof (viorand_rdbuf_t) *
261*b91bbe38SToomas Soome state->vio_rdbufs_capacity, KM_SLEEP);
262*b91bbe38SToomas Soome list_create(&state->vio_rdbufs_free, sizeof (viorand_rdbuf_t),
263*b91bbe38SToomas Soome offsetof(viorand_rdbuf_t, rb_link));
264*b91bbe38SToomas Soome
265*b91bbe38SToomas Soome /* Put everything in free list. */
266*b91bbe38SToomas Soome for (uint_t i = 0; i < state->vio_rdbufs_capacity; i++)
267*b91bbe38SToomas Soome list_insert_tail(&state->vio_rdbufs_free,
268*b91bbe38SToomas Soome &state->vio_rdbuf_mem[i]);
269*b91bbe38SToomas Soome
270*b91bbe38SToomas Soome for (viorand_rdbuf_t *rb = list_head(&state->vio_rdbufs_free);
271*b91bbe38SToomas Soome rb != NULL; rb = list_next(&state->vio_rdbufs_free, rb)) {
272*b91bbe38SToomas Soome rb->rb_viornd = state;
273*b91bbe38SToomas Soome rb->rb_chain = virtio_chain_alloc(state->vio_rq, KM_SLEEP);
274*b91bbe38SToomas Soome if (rb->rb_chain == NULL)
275*b91bbe38SToomas Soome goto fail;
276*b91bbe38SToomas Soome
277*b91bbe38SToomas Soome virtio_chain_data_set(rb->rb_chain, rb);
278*b91bbe38SToomas Soome }
279*b91bbe38SToomas Soome return (0);
280*b91bbe38SToomas Soome
281*b91bbe38SToomas Soome fail:
282*b91bbe38SToomas Soome viorand_free_bufs(state);
283*b91bbe38SToomas Soome return (ENOMEM);
284*b91bbe38SToomas Soome }
285*b91bbe38SToomas Soome
286*b91bbe38SToomas Soome static int
viorand_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)287*b91bbe38SToomas Soome viorand_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
288*b91bbe38SToomas Soome {
289*b91bbe38SToomas Soome int instance = ddi_get_instance(dip);
290*b91bbe38SToomas Soome int rv = 0;
291*b91bbe38SToomas Soome viorand_state_t *state;
292*b91bbe38SToomas Soome virtio_t *vio;
293*b91bbe38SToomas Soome
294*b91bbe38SToomas Soome switch (cmd) {
295*b91bbe38SToomas Soome case DDI_ATTACH:
296*b91bbe38SToomas Soome break;
297*b91bbe38SToomas Soome
298*b91bbe38SToomas Soome case DDI_RESUME:
299*b91bbe38SToomas Soome default:
300*b91bbe38SToomas Soome return (DDI_FAILURE);
301*b91bbe38SToomas Soome }
302*b91bbe38SToomas Soome
303*b91bbe38SToomas Soome if (ddi_soft_state_zalloc(viorand_statep, instance) != DDI_SUCCESS)
304*b91bbe38SToomas Soome return (DDI_FAILURE);
305*b91bbe38SToomas Soome
306*b91bbe38SToomas Soome vio = virtio_init(dip, VIORAND_FEATURES, B_TRUE);
307*b91bbe38SToomas Soome if (vio == NULL) {
308*b91bbe38SToomas Soome ddi_soft_state_free(viorand_statep, instance);
309*b91bbe38SToomas Soome return (DDI_FAILURE);
310*b91bbe38SToomas Soome }
311*b91bbe38SToomas Soome
312*b91bbe38SToomas Soome state = ddi_get_soft_state(viorand_statep, instance);
313*b91bbe38SToomas Soome state->vio_dip = dip;
314*b91bbe38SToomas Soome state->vio_virtio = vio;
315*b91bbe38SToomas Soome state->vio_rq = virtio_queue_alloc(vio, VIORAND_RQ, "requestq",
316*b91bbe38SToomas Soome viorand_interrupt, state, B_FALSE, 1);
317*b91bbe38SToomas Soome if (state->vio_rq == NULL) {
318*b91bbe38SToomas Soome virtio_fini(state->vio_virtio, B_TRUE);
319*b91bbe38SToomas Soome ddi_soft_state_free(viorand_statep, instance);
320*b91bbe38SToomas Soome return (DDI_FAILURE);
321*b91bbe38SToomas Soome }
322*b91bbe38SToomas Soome
323*b91bbe38SToomas Soome if (virtio_init_complete(state->vio_virtio, VIRTIO_ANY_INTR_TYPE) !=
324*b91bbe38SToomas Soome DDI_SUCCESS) {
325*b91bbe38SToomas Soome virtio_fini(state->vio_virtio, B_TRUE);
326*b91bbe38SToomas Soome ddi_soft_state_free(viorand_statep, instance);
327*b91bbe38SToomas Soome return (DDI_FAILURE);
328*b91bbe38SToomas Soome }
329*b91bbe38SToomas Soome
330*b91bbe38SToomas Soome cv_init(&state->vio_cv, NULL, CV_DRIVER, NULL);
331*b91bbe38SToomas Soome mutex_init(&state->vio_mutex, NULL, MUTEX_DRIVER, virtio_intr_pri(vio));
332*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
333*b91bbe38SToomas Soome
334*b91bbe38SToomas Soome if (viorand_alloc_bufs(state) != 0) {
335*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
336*b91bbe38SToomas Soome dev_err(dip, CE_WARN, "failed to allocate memory");
337*b91bbe38SToomas Soome goto fail;
338*b91bbe38SToomas Soome }
339*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
340*b91bbe38SToomas Soome
341*b91bbe38SToomas Soome viorand_prov_info.pi_provider_dev.pd_hw = dip;
342*b91bbe38SToomas Soome viorand_prov_info.pi_provider_handle = state;
343*b91bbe38SToomas Soome
344*b91bbe38SToomas Soome if (virtio_interrupts_enable(state->vio_virtio) != DDI_SUCCESS)
345*b91bbe38SToomas Soome goto fail;
346*b91bbe38SToomas Soome
347*b91bbe38SToomas Soome rv = crypto_register_provider(&viorand_prov_info, &state->vio_handle);
348*b91bbe38SToomas Soome if (rv == CRYPTO_SUCCESS) {
349*b91bbe38SToomas Soome return (DDI_SUCCESS);
350*b91bbe38SToomas Soome }
351*b91bbe38SToomas Soome
352*b91bbe38SToomas Soome fail:
353*b91bbe38SToomas Soome virtio_interrupts_disable(state->vio_virtio);
354*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
355*b91bbe38SToomas Soome viorand_free_bufs(state);
356*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
357*b91bbe38SToomas Soome cv_destroy(&state->vio_cv);
358*b91bbe38SToomas Soome mutex_destroy(&state->vio_mutex);
359*b91bbe38SToomas Soome virtio_fini(state->vio_virtio, B_TRUE);
360*b91bbe38SToomas Soome ddi_soft_state_free(viorand_statep, instance);
361*b91bbe38SToomas Soome return (DDI_FAILURE);
362*b91bbe38SToomas Soome }
363*b91bbe38SToomas Soome
364*b91bbe38SToomas Soome static int
viorand_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)365*b91bbe38SToomas Soome viorand_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
366*b91bbe38SToomas Soome {
367*b91bbe38SToomas Soome int instance = ddi_get_instance(dip);
368*b91bbe38SToomas Soome viorand_state_t *state = ddi_get_soft_state(viorand_statep, instance);
369*b91bbe38SToomas Soome
370*b91bbe38SToomas Soome switch (cmd) {
371*b91bbe38SToomas Soome case DDI_DETACH:
372*b91bbe38SToomas Soome if (!virtio_registered)
373*b91bbe38SToomas Soome break;
374*b91bbe38SToomas Soome
375*b91bbe38SToomas Soome /* FALLTHROUGH */
376*b91bbe38SToomas Soome case DDI_SUSPEND:
377*b91bbe38SToomas Soome default:
378*b91bbe38SToomas Soome return (DDI_FAILURE);
379*b91bbe38SToomas Soome }
380*b91bbe38SToomas Soome
381*b91bbe38SToomas Soome if (crypto_unregister_provider(state->vio_handle) != CRYPTO_SUCCESS)
382*b91bbe38SToomas Soome return (DDI_FAILURE);
383*b91bbe38SToomas Soome
384*b91bbe38SToomas Soome virtio_interrupts_disable(state->vio_virtio);
385*b91bbe38SToomas Soome virtio_shutdown(state->vio_virtio);
386*b91bbe38SToomas Soome
387*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
388*b91bbe38SToomas Soome for (;;) {
389*b91bbe38SToomas Soome virtio_chain_t *vic;
390*b91bbe38SToomas Soome
391*b91bbe38SToomas Soome vic = virtio_queue_evacuate(state->vio_rq);
392*b91bbe38SToomas Soome if (vic == NULL)
393*b91bbe38SToomas Soome break;
394*b91bbe38SToomas Soome
395*b91bbe38SToomas Soome viorand_rbuf_free(state, virtio_chain_data(vic));
396*b91bbe38SToomas Soome }
397*b91bbe38SToomas Soome
398*b91bbe38SToomas Soome viorand_free_bufs(state);
399*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
400*b91bbe38SToomas Soome cv_destroy(&state->vio_cv);
401*b91bbe38SToomas Soome mutex_destroy(&state->vio_mutex);
402*b91bbe38SToomas Soome (void) virtio_fini(state->vio_virtio, B_FALSE);
403*b91bbe38SToomas Soome ddi_soft_state_free(viorand_statep, instance);
404*b91bbe38SToomas Soome return (DDI_SUCCESS);
405*b91bbe38SToomas Soome }
406*b91bbe38SToomas Soome
407*b91bbe38SToomas Soome static int
viorand_quiesce(dev_info_t * dip)408*b91bbe38SToomas Soome viorand_quiesce(dev_info_t *dip)
409*b91bbe38SToomas Soome {
410*b91bbe38SToomas Soome int instance = ddi_get_instance(dip);
411*b91bbe38SToomas Soome viorand_state_t *state = ddi_get_soft_state(viorand_statep, instance);
412*b91bbe38SToomas Soome
413*b91bbe38SToomas Soome if (state == NULL)
414*b91bbe38SToomas Soome return (DDI_FAILURE);
415*b91bbe38SToomas Soome
416*b91bbe38SToomas Soome return (virtio_quiesce(state->vio_virtio));
417*b91bbe38SToomas Soome }
418*b91bbe38SToomas Soome
419*b91bbe38SToomas Soome /*
420*b91bbe38SToomas Soome * Control entry points.
421*b91bbe38SToomas Soome */
422*b91bbe38SToomas Soome static void
viorand_provider_status(crypto_provider_handle_t provider __unused,uint_t * status)423*b91bbe38SToomas Soome viorand_provider_status(crypto_provider_handle_t provider __unused,
424*b91bbe38SToomas Soome uint_t *status)
425*b91bbe38SToomas Soome {
426*b91bbe38SToomas Soome *status = CRYPTO_PROVIDER_READY;
427*b91bbe38SToomas Soome }
428*b91bbe38SToomas Soome
429*b91bbe38SToomas Soome static boolean_t
viorand_submit_request(viorand_rdbuf_t * rb)430*b91bbe38SToomas Soome viorand_submit_request(viorand_rdbuf_t *rb)
431*b91bbe38SToomas Soome {
432*b91bbe38SToomas Soome if (virtio_chain_append(rb->rb_chain,
433*b91bbe38SToomas Soome virtio_dma_cookie_pa(rb->rb_dma, 0),
434*b91bbe38SToomas Soome rb->rb_req_len,
435*b91bbe38SToomas Soome VIRTIO_DIR_DEVICE_WRITES) != DDI_SUCCESS) {
436*b91bbe38SToomas Soome return (B_FALSE);
437*b91bbe38SToomas Soome }
438*b91bbe38SToomas Soome
439*b91bbe38SToomas Soome virtio_dma_sync(rb->rb_dma, DDI_DMA_SYNC_FORDEV);
440*b91bbe38SToomas Soome virtio_chain_submit(rb->rb_chain, B_TRUE);
441*b91bbe38SToomas Soome return (B_TRUE);
442*b91bbe38SToomas Soome }
443*b91bbe38SToomas Soome
444*b91bbe38SToomas Soome /* We got portion of data, process it */
445*b91bbe38SToomas Soome static void
viorand_process_data(viorand_rdbuf_t * rb)446*b91bbe38SToomas Soome viorand_process_data(viorand_rdbuf_t *rb)
447*b91bbe38SToomas Soome {
448*b91bbe38SToomas Soome size_t len;
449*b91bbe38SToomas Soome int error = CRYPTO_SUCCESS;
450*b91bbe38SToomas Soome
451*b91bbe38SToomas Soome len = MIN(rb->rb_req_len, rb->rb_recv_len);
452*b91bbe38SToomas Soome bcopy(virtio_dma_va(rb->rb_dma, 0), rb->rb_req_buf, len);
453*b91bbe38SToomas Soome bzero(virtio_dma_va(rb->rb_dma, 0), len);
454*b91bbe38SToomas Soome if (len < rb->rb_req_len) {
455*b91bbe38SToomas Soome rb->rb_req_len -= len;
456*b91bbe38SToomas Soome rb->rb_req_buf += len;
457*b91bbe38SToomas Soome /* Try to get reminder */
458*b91bbe38SToomas Soome if (viorand_submit_request(rb))
459*b91bbe38SToomas Soome return;
460*b91bbe38SToomas Soome
461*b91bbe38SToomas Soome /* Release our buffer and return error */
462*b91bbe38SToomas Soome viorand_rbuf_free(rb->rb_viornd, rb);
463*b91bbe38SToomas Soome error = CRYPTO_HOST_MEMORY;
464*b91bbe38SToomas Soome } else {
465*b91bbe38SToomas Soome /* Got all the data, free our buffer */
466*b91bbe38SToomas Soome viorand_rbuf_free(rb->rb_viornd, rb);
467*b91bbe38SToomas Soome }
468*b91bbe38SToomas Soome crypto_op_notification(rb->rb_req_handle, error);
469*b91bbe38SToomas Soome }
470*b91bbe38SToomas Soome
471*b91bbe38SToomas Soome static uint_t
viorand_interrupt(caddr_t a,caddr_t b __unused)472*b91bbe38SToomas Soome viorand_interrupt(caddr_t a, caddr_t b __unused)
473*b91bbe38SToomas Soome {
474*b91bbe38SToomas Soome viorand_state_t *state = (viorand_state_t *)a;
475*b91bbe38SToomas Soome virtio_chain_t *vic;
476*b91bbe38SToomas Soome boolean_t notify = B_FALSE;
477*b91bbe38SToomas Soome
478*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
479*b91bbe38SToomas Soome while ((vic = virtio_queue_poll(state->vio_rq)) != NULL) {
480*b91bbe38SToomas Soome /* Actual received len and our read buffer */
481*b91bbe38SToomas Soome size_t len = virtio_chain_received_length(vic);
482*b91bbe38SToomas Soome viorand_rdbuf_t *rb = virtio_chain_data(vic);
483*b91bbe38SToomas Soome
484*b91bbe38SToomas Soome virtio_dma_sync(rb->rb_dma, DDI_DMA_SYNC_FORCPU);
485*b91bbe38SToomas Soome rb->rb_recv_len = len;
486*b91bbe38SToomas Soome viorand_process_data(rb);
487*b91bbe38SToomas Soome notify = B_TRUE;
488*b91bbe38SToomas Soome }
489*b91bbe38SToomas Soome if (notify)
490*b91bbe38SToomas Soome cv_broadcast(&state->vio_cv);
491*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
492*b91bbe38SToomas Soome if (notify)
493*b91bbe38SToomas Soome return (DDI_INTR_CLAIMED);
494*b91bbe38SToomas Soome return (DDI_INTR_UNCLAIMED);
495*b91bbe38SToomas Soome }
496*b91bbe38SToomas Soome
497*b91bbe38SToomas Soome /*
498*b91bbe38SToomas Soome * Random number entry point.
499*b91bbe38SToomas Soome */
500*b91bbe38SToomas Soome static int
viorand_generate_random(crypto_provider_handle_t provider,crypto_session_id_t sid __unused,uchar_t * buf,size_t len,crypto_req_handle_t req)501*b91bbe38SToomas Soome viorand_generate_random(crypto_provider_handle_t provider,
502*b91bbe38SToomas Soome crypto_session_id_t sid __unused, uchar_t *buf, size_t len,
503*b91bbe38SToomas Soome crypto_req_handle_t req)
504*b91bbe38SToomas Soome {
505*b91bbe38SToomas Soome viorand_state_t *state = provider;
506*b91bbe38SToomas Soome viorand_rdbuf_t *rb;
507*b91bbe38SToomas Soome
508*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
509*b91bbe38SToomas Soome rb = viorand_rbuf_alloc(state);
510*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
511*b91bbe38SToomas Soome
512*b91bbe38SToomas Soome rb->rb_req_buf = buf;
513*b91bbe38SToomas Soome rb->rb_req_len = len;
514*b91bbe38SToomas Soome rb->rb_req_handle = req;
515*b91bbe38SToomas Soome
516*b91bbe38SToomas Soome rb->rb_dma = virtio_dma_alloc(state->vio_virtio, len,
517*b91bbe38SToomas Soome &viorand_dma_attr, DDI_DMA_READ | DDI_DMA_STREAMING, KM_SLEEP);
518*b91bbe38SToomas Soome if (rb->rb_dma == NULL) {
519*b91bbe38SToomas Soome goto error;
520*b91bbe38SToomas Soome }
521*b91bbe38SToomas Soome
522*b91bbe38SToomas Soome if (viorand_submit_request(rb))
523*b91bbe38SToomas Soome return (CRYPTO_QUEUED);
524*b91bbe38SToomas Soome
525*b91bbe38SToomas Soome error:
526*b91bbe38SToomas Soome mutex_enter(&state->vio_mutex);
527*b91bbe38SToomas Soome viorand_rbuf_free(state, rb);
528*b91bbe38SToomas Soome mutex_exit(&state->vio_mutex);
529*b91bbe38SToomas Soome return (CRYPTO_HOST_MEMORY);
530*b91bbe38SToomas Soome }
531