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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include <sys/time.h>
28 #include <sys/errno.h>
29 #include <sys/kmem.h>
30 #include <sys/stat.h>
31 #include <sys/cmn_err.h>
32
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/devops.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/callb.h>
39 #include <sys/disp.h>
40 #include <sys/strlog.h>
41 #include <sys/file.h>
42
43 #include <sys/uadmin.h>
44 #include <sys/machsystm.h>
45 #include <sys/hypervisor_api.h>
46 #include <sys/hsvc.h>
47 #include <sys/glvc.h>
48
49 /*
50 * Global Variables - can be patched from Solaris
51 * ==============================================
52 */
53
54 /* bit defination in virtual device register */
55 #define GLVC_REG_RECV 0x0001
56 #define GLVC_REG_RECV_ENA 0x0002
57 #define GLVC_REG_SEND 0x0004
58 #define GLVC_REG_SEND_ENA 0x0008
59 #define GLVC_REG_ERR 0x8000
60
61 /*
62 * For interrupt mode
63 */
64 #define GLVC_MODE_NONE 0
65 #define GLVC_POLLING_MODE 1
66 #define GLVC_INTR_MODE 2
67
68 /*
69 * For open
70 */
71 #define GLVC_NO_OPEN 0
72 #define GLVC_OPEN 1
73 #define GLVC_EXCL_OPEN 2
74
75 /*
76 * For timeout polling, in microsecond.
77 */
78 #define GLVC_TIMEOUT_POLL 5000000 /* Timeout in intr mode */
79 #define GLVC_POLLMODE_POLL 500000 /* Interval in polling mode */
80
81 /*
82 * For debug printing
83 */
84 #define _PRINTF printf
85 #define DPRINTF(args) if (glvc_debug) _PRINTF args;
86
87 /*
88 * Driver entry points
89 */
90 static int glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
91 static int glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
92 static int glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
93 static int glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
94 static int glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
95 cred_t *cred_p, int *rval_p);
96 static int glvc_read(dev_t dev, struct uio *uiop, cred_t *credp);
97 static int glvc_write(dev_t dev, struct uio *uiop, cred_t *credp);
98
99 static struct cb_ops glvc_cb_ops = {
100 glvc_open, /* open */
101 glvc_close, /* close */
102 nodev, /* strategy() */
103 nodev, /* print() */
104 nodev, /* dump() */
105 glvc_read, /* read() */
106 glvc_write, /* write() */
107 glvc_ioctl, /* ioctl() */
108 nodev, /* devmap() */
109 nodev, /* mmap() */
110 ddi_segmap, /* segmap() */
111 nochpoll, /* poll() */
112 ddi_prop_op, /* prop_op() */
113 NULL, /* cb_str */
114 D_NEW | D_MP /* cb_flag */
115 };
116
117
118 static struct dev_ops glvc_ops = {
119 DEVO_REV,
120 0, /* ref count */
121 ddi_getinfo_1to1, /* getinfo() */
122 nulldev, /* identify() */
123 nulldev, /* probe() */
124 glvc_attach, /* attach() */
125 glvc_detach, /* detach */
126 nodev, /* reset */
127 &glvc_cb_ops, /* pointer to cb_ops structure */
128 (struct bus_ops *)NULL,
129 nulldev, /* power() */
130 ddi_quiesce_not_needed, /* quiesce */
131 };
132
133 /*
134 * Loadable module support.
135 */
136 extern struct mod_ops mod_driverops;
137
138 static struct modldrv modldrv = {
139 &mod_driverops, /* Type of module. This is a driver */
140 "Sun4v virtual channel driver", /* Name of the module */
141 &glvc_ops /* pointer to the dev_ops structure */
142 };
143
144 static struct modlinkage modlinkage = {
145 MODREV_1,
146 &modldrv,
147 NULL
148 };
149
150 typedef struct glvc_soft_state {
151 dev_info_t *dip; /* dev info of myself */
152 uint64_t s_id; /* service id for this node */
153 uint64_t mtu; /* max transmit unit size */
154 uint64_t flag; /* flag register */
155 kmutex_t open_mutex; /* protect open_state flag */
156 uint8_t open_state; /* no-open, open or open exclusively */
157 kmutex_t recv_mutex;
158 kmutex_t send_complete_mutex;
159 uint8_t send_complete_flag; /* 1 = send completed */
160 uint8_t intr_mode; /* 1 = polling mode, 2 = interrupt mode */
161 clock_t polling_interval;
162 ddi_softintr_t poll_mode_softint_id;
163 kcondvar_t recv_cv;
164 kcondvar_t send_complete_cv;
165 kmutex_t statusreg_mutex; /* Protects status register */
166 char *mb_recv_buf;
167 char *mb_send_buf;
168 uint64_t mb_recv_buf_pa;
169 uint64_t mb_send_buf_pa;
170 } glvc_soft_state_t;
171
172 /*
173 * Hypervisor VSC api versioning information for glvc driver.
174 */
175 static uint64_t glvc_vsc_min_ver; /* Negotiated VSC API minor version */
176 static uint_t glvc_vsc_users = 0; /* VSC API users */
177 static kmutex_t glvc_vsc_users_mutex; /* Mutex to protect user count */
178
179 static hsvc_info_t glvc_hsvc = {
180 HSVC_REV_1, NULL, HSVC_GROUP_VSC, GLVC_VSC_MAJOR_VER,
181 GLVC_VSC_MINOR_VER, "glvc"
182 };
183
184 /*
185 * Module Variables
186 * ================
187 */
188
189 /*
190 * functions local to this driver.
191 */
192 static int glvc_add_intr_handlers(dev_info_t *dip);
193 static int glvc_remove_intr_handlers(dev_info_t *dip);
194 static uint_t glvc_intr(caddr_t arg);
195 static int glvc_peek(glvc_soft_state_t *softsp,
196 glvc_xport_msg_peek_t *msg_peek);
197 static uint_t glvc_soft_intr(caddr_t arg);
198 static int glvc_emap_h2s(uint64_t hv_errcode);
199 static int glvc_ioctl_opt_op(glvc_soft_state_t *softsp,
200 intptr_t arg, int mode);
201
202 /*
203 * Driver globals
204 */
205 static void *glvc_ssp; /* pointer to driver soft state */
206
207 static uint_t glvc_debug = 0;
208
209 int
_init(void)210 _init(void)
211 {
212 int error = 0;
213
214 if ((error = ddi_soft_state_init(&glvc_ssp,
215 sizeof (glvc_soft_state_t), 1)) != 0)
216 return (error);
217
218 /*
219 * Initialize the mutex for global data structure
220 */
221 mutex_init(&glvc_vsc_users_mutex, NULL, MUTEX_DRIVER, NULL);
222
223 error = mod_install(&modlinkage);
224
225 return (error);
226 }
227
228
229 int
_info(struct modinfo * modinfop)230 _info(struct modinfo *modinfop)
231 {
232 return (mod_info(&modlinkage, modinfop));
233 }
234
235
236 int
_fini(void)237 _fini(void)
238 {
239 int error = 0;
240
241 error = mod_remove(&modlinkage);
242 if (error)
243 return (error);
244
245 mutex_destroy(&glvc_vsc_users_mutex);
246
247 ddi_soft_state_fini(&glvc_ssp);
248 return (0);
249 }
250
251
252 static int
glvc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)253 glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
254 {
255 int instance;
256 int err;
257 glvc_soft_state_t *softsp;
258
259 switch (cmd) {
260 case DDI_ATTACH:
261 instance = ddi_get_instance(dip);
262
263 /*
264 * Negotiate the API version for VSC hypervisor services.
265 */
266 mutex_enter(&glvc_vsc_users_mutex);
267 if (glvc_vsc_users == 0 &&
268 (err = hsvc_register(&glvc_hsvc, &glvc_vsc_min_ver))
269 != 0) {
270 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor "
271 "services group: 0x%lx major: 0x%lx minor: 0x%lx "
272 "errno: %d\n", glvc_hsvc.hsvc_modname,
273 glvc_hsvc.hsvc_group, glvc_hsvc.hsvc_major,
274 glvc_hsvc.hsvc_minor, err);
275
276 mutex_exit(&glvc_vsc_users_mutex);
277 return (DDI_FAILURE);
278 } else {
279 glvc_vsc_users++;
280 mutex_exit(&glvc_vsc_users_mutex);
281 }
282
283 DPRINTF(("Glvc instance %d negotiated VSC API version, "
284 " major 0x%lx minor 0x%lx\n",
285 instance, glvc_hsvc.hsvc_major, glvc_vsc_min_ver));
286
287 if (ddi_soft_state_zalloc(glvc_ssp, instance)
288 != DDI_SUCCESS) {
289 mutex_enter(&glvc_vsc_users_mutex);
290 if (--glvc_vsc_users == 0)
291 (void) hsvc_unregister(&glvc_hsvc);
292 mutex_exit(&glvc_vsc_users_mutex);
293 return (DDI_FAILURE);
294 }
295
296 softsp = ddi_get_soft_state(glvc_ssp, instance);
297
298 /* Set the dip in the soft state */
299 softsp->dip = dip;
300
301 softsp->open_state = GLVC_NO_OPEN;
302 softsp->send_complete_flag = 1;
303
304 glvc_debug = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
305 softsp->dip, DDI_PROP_DONTPASS, "glvc_debug", glvc_debug);
306
307 if ((softsp->s_id = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
308 softsp->dip, DDI_PROP_DONTPASS, "channel#", -1))
309 == -1) {
310 cmn_err(CE_WARN, "Failed to get channel#");
311 goto bad;
312 }
313
314 if ((softsp->mtu = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
315 softsp->dip, DDI_PROP_DONTPASS, "mtu", -1))
316 <= 0) {
317 cmn_err(CE_WARN, "Failed to get mtu");
318 goto bad;
319 }
320
321 softsp->mb_recv_buf =
322 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
323 if (softsp->mb_recv_buf == NULL) {
324 cmn_err(CE_WARN, "Failed to alloc mem for recv buf");
325 goto bad;
326 }
327 softsp->mb_recv_buf_pa =
328 va_to_pa((caddr_t)softsp->mb_recv_buf);
329
330 softsp->mb_send_buf =
331 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
332 if (softsp->mb_send_buf == NULL) {
333 kmem_free(softsp->mb_recv_buf, softsp->mtu);
334 cmn_err(CE_WARN, "Failed to alloc mem for send buf");
335 goto bad;
336 }
337 softsp->mb_send_buf_pa =
338 va_to_pa((caddr_t)softsp->mb_send_buf);
339
340 err = ddi_create_minor_node(dip, "glvc", S_IFCHR,
341 instance, DDI_PSEUDO, 0);
342 if (err != DDI_SUCCESS) {
343 kmem_free(softsp->mb_recv_buf, softsp->mtu);
344 kmem_free(softsp->mb_send_buf, softsp->mtu);
345 cmn_err(CE_WARN, "Failed to create minor node");
346 goto bad;
347 }
348
349 mutex_init(&(softsp->open_mutex), NULL, MUTEX_DRIVER, NULL);
350 mutex_init(&(softsp->recv_mutex), NULL, MUTEX_DRIVER, NULL);
351 mutex_init(&(softsp->send_complete_mutex), NULL,
352 MUTEX_DRIVER, NULL);
353 mutex_init(&(softsp->statusreg_mutex), NULL,
354 MUTEX_DRIVER, NULL);
355 cv_init(&(softsp->recv_cv), NULL, CV_DRIVER, NULL);
356 cv_init(&(softsp->send_complete_cv), NULL, CV_DRIVER, NULL);
357
358 /*
359 * Add the handlers which watch for unsolicited messages
360 * and post event to Sysevent Framework.
361 */
362 err = glvc_add_intr_handlers(dip);
363 if (err != DDI_SUCCESS) {
364 cmn_err(CE_WARN, "Failed to add intr handler");
365 kmem_free(softsp->mb_recv_buf, softsp->mtu);
366 kmem_free(softsp->mb_send_buf, softsp->mtu);
367 ddi_remove_minor_node(dip, NULL);
368 goto bad1;
369 }
370
371 /*
372 * Trigger soft interrupt to start polling device if
373 * we are in the polling mode
374 */
375 if (softsp->intr_mode == GLVC_POLLING_MODE)
376 ddi_trigger_softintr(softsp->poll_mode_softint_id);
377
378 ddi_report_dev(dip);
379
380 DPRINTF(("glvc instance %d, s_id %lu,"
381 "mtu %lu attached\n", instance, softsp->s_id,
382 softsp->mtu));
383
384 return (DDI_SUCCESS);
385 case DDI_RESUME:
386 return (DDI_SUCCESS);
387 default:
388 return (DDI_FAILURE);
389 }
390
391 bad1:
392 cv_destroy(&(softsp->send_complete_cv));
393 cv_destroy(&(softsp->recv_cv));
394 mutex_destroy(&(softsp->open_mutex));
395 mutex_destroy(&(softsp->send_complete_mutex));
396 mutex_destroy(&(softsp->recv_mutex));
397 mutex_destroy(&(softsp->statusreg_mutex));
398
399 bad:
400 mutex_enter(&glvc_vsc_users_mutex);
401 if (--glvc_vsc_users == 0)
402 (void) hsvc_unregister(&glvc_hsvc);
403 mutex_exit(&glvc_vsc_users_mutex);
404 cmn_err(CE_WARN, "glvc: attach failed for instance %d\n", instance);
405 ddi_soft_state_free(glvc_ssp, instance);
406 return (DDI_FAILURE);
407 }
408
409
410 static int
glvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)411 glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
412 {
413 int instance;
414 int err;
415 glvc_soft_state_t *softsp;
416
417
418 switch (cmd) {
419 case DDI_DETACH:
420 instance = ddi_get_instance(dip);
421
422 softsp = ddi_get_soft_state(glvc_ssp, instance);
423
424 cv_destroy(&(softsp->send_complete_cv));
425 cv_destroy(&(softsp->recv_cv));
426 mutex_destroy(&(softsp->open_mutex));
427 mutex_destroy(&(softsp->statusreg_mutex));
428 mutex_destroy(&(softsp->send_complete_mutex));
429 mutex_destroy(&(softsp->recv_mutex));
430
431 kmem_free(softsp->mb_recv_buf, softsp->mtu);
432 kmem_free(softsp->mb_send_buf, softsp->mtu);
433
434 err = glvc_remove_intr_handlers(dip);
435
436 if (err != DDI_SUCCESS) {
437 cmn_err(CE_WARN, "Failed to remove event handlers");
438 return (DDI_FAILURE);
439 }
440
441 ddi_remove_minor_node(dip, NULL);
442
443 ddi_soft_state_free(glvc_ssp, instance);
444
445 mutex_enter(&glvc_vsc_users_mutex);
446 if (--glvc_vsc_users == 0)
447 (void) hsvc_unregister(&glvc_hsvc);
448 mutex_exit(&glvc_vsc_users_mutex);
449
450 return (DDI_SUCCESS);
451 case DDI_SUSPEND:
452 return (DDI_SUCCESS);
453 default:
454 return (DDI_FAILURE);
455 }
456 }
457
458 static int
glvc_add_intr_handlers(dev_info_t * dip)459 glvc_add_intr_handlers(dev_info_t *dip)
460 {
461 int instance;
462 glvc_soft_state_t *softsp;
463 int err = DDI_FAILURE;
464 uint64_t polling_interval;
465
466 instance = ddi_get_instance(dip);
467 softsp = ddi_get_soft_state(glvc_ssp, instance);
468
469 if ((uint64_t)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
470 DDI_PROP_DONTPASS, "flags", -1) != -1) {
471 err = ddi_add_intr(dip, 0, NULL, NULL, glvc_intr,
472 (caddr_t)softsp);
473 if (err != DDI_SUCCESS)
474 cmn_err(CE_NOTE, "glvc, instance %d"
475 " ddi_add_intr() failed, using"
476 " polling mode", instance);
477 }
478
479 if (err == DDI_SUCCESS) {
480 softsp->intr_mode = GLVC_INTR_MODE;
481 polling_interval = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
482 softsp->dip, DDI_PROP_DONTPASS, "intrmode_poll",
483 GLVC_TIMEOUT_POLL);
484 DPRINTF(("glvc instance %d polling_interval = %lu\n",
485 instance, polling_interval));
486 softsp->polling_interval = drv_usectohz(polling_interval);
487 } else {
488 DPRINTF(("glvc, instance %d intr support not found, "
489 "err = %d , use polling mode", instance, err));
490 softsp->intr_mode = GLVC_POLLING_MODE;
491 polling_interval =
492 (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
493 softsp->dip, DDI_PROP_DONTPASS, "pollmode_poll",
494 GLVC_POLLMODE_POLL);
495 DPRINTF(("glvc instance %d polling_interval = %lu\n",
496 instance, polling_interval));
497 softsp->polling_interval =
498 drv_usectohz(polling_interval);
499 }
500
501 /* Now enable interrupt bits in the status register */
502 if (softsp->intr_mode == GLVC_INTR_MODE) {
503 err = hv_service_setstatus(softsp->s_id,
504 GLVC_REG_RECV_ENA|GLVC_REG_SEND_ENA);
505 if (err != H_EOK) {
506 cmn_err(CE_NOTE, "glvc instance %d"
507 " cannot enable receive interrupt\n",
508 instance);
509 return (DDI_FAILURE);
510 }
511 }
512
513
514 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
515 &softsp->poll_mode_softint_id, NULL, NULL,
516 glvc_soft_intr, (caddr_t)softsp);
517
518 return (err);
519 }
520
521 static int
glvc_remove_intr_handlers(dev_info_t * dip)522 glvc_remove_intr_handlers(dev_info_t *dip)
523 {
524 int instance;
525 glvc_soft_state_t *softsp;
526
527 instance = ddi_get_instance(dip);
528 softsp = ddi_get_soft_state(glvc_ssp, instance);
529
530 if (softsp->intr_mode == GLVC_INTR_MODE)
531 ddi_remove_intr(dip, 0, NULL);
532
533 ddi_remove_softintr(softsp->poll_mode_softint_id);
534
535 softsp->intr_mode = GLVC_MODE_NONE;
536 softsp->polling_interval = 0;
537
538 return (DDI_SUCCESS);
539 }
540
541 static uint_t
glvc_soft_intr(caddr_t arg)542 glvc_soft_intr(caddr_t arg)
543 {
544 /*
545 * Call the interrupt handle routine to check the register
546 * status.
547 */
548 (uint_t)glvc_intr(arg);
549
550 return (DDI_INTR_CLAIMED);
551 }
552
553 /*ARGSUSED*/
554 static int
glvc_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)555 glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
556 {
557 int error = 0;
558 int instance;
559 glvc_soft_state_t *softsp;
560
561 instance = getminor(*dev_p);
562
563 softsp = ddi_get_soft_state(glvc_ssp, instance);
564
565 mutex_enter(&softsp->open_mutex);
566
567 switch (softsp->open_state) {
568 case GLVC_NO_OPEN:
569 if (flag & FEXCL)
570 softsp->open_state = GLVC_EXCL_OPEN;
571 else
572 softsp->open_state = GLVC_OPEN;
573 break;
574
575 case GLVC_OPEN:
576 if (flag & FEXCL)
577 error = EBUSY;
578 break;
579
580 case GLVC_EXCL_OPEN:
581 error = EBUSY;
582 break;
583
584 default:
585 /* Should not happen */
586 cmn_err(CE_WARN, "glvc_open: bad open state %d.",
587 softsp->open_state);
588 error = ENXIO;
589 break;
590 }
591
592 mutex_exit(&softsp->open_mutex);
593
594 return (error);
595 }
596
597 /*ARGSUSED*/
598 static int
glvc_close(dev_t dev,int flag,int otyp,cred_t * cred_p)599 glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
600 {
601 glvc_soft_state_t *softsp;
602 int instance;
603 int error = 0;
604
605 instance = getminor(dev);
606
607 softsp = ddi_get_soft_state(glvc_ssp, instance);
608
609 mutex_enter(&softsp->open_mutex);
610 if (softsp->open_state == GLVC_NO_OPEN) {
611 cmn_err(CE_WARN,
612 "glvc_close: device already closed");
613 error = ENXIO;
614 } else {
615 softsp->open_state = GLVC_NO_OPEN;
616 }
617 mutex_exit(&softsp->open_mutex);
618
619 return (error);
620 }
621
622 /*ARGSUSED*/
623 static int
glvc_read(dev_t dev,struct uio * uiop,cred_t * credp)624 glvc_read(dev_t dev, struct uio *uiop, cred_t *credp)
625 {
626 glvc_soft_state_t *softsp;
627 int instance;
628 int rv, error = DDI_SUCCESS;
629 uint64_t hverr, recv_count = 0;
630 uint64_t status_reg;
631
632 instance = getminor(dev);
633
634 softsp = ddi_get_soft_state(glvc_ssp, instance);
635
636 mutex_enter(&softsp->recv_mutex);
637
638 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
639 DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx",
640 hverr, status_reg));
641
642
643 /*
644 * If no data available, we wait till we get some.
645 * Notice we still holding the recv_mutex lock at this
646 * point.
647 */
648 while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) !=
649 GLVC_REG_RECV) {
650 rv = cv_reltimedwait_sig(&softsp->recv_cv,
651 &softsp->recv_mutex, softsp->polling_interval,
652 TR_CLOCK_TICK);
653 if (rv == 0) {
654 /*
655 * We got interrupted.
656 */
657 mutex_exit(&softsp->recv_mutex);
658 return (EINTR);
659 }
660 if (rv == -1) {
661 /*
662 * Timeout wait, trigger a soft intr in case
663 * we miss an interrupt or in polling mode.
664 */
665 ddi_trigger_softintr(softsp->poll_mode_softint_id);
666 }
667 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
668 DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx",
669 hverr, status_reg));
670 }
671
672 /* Read data into kernel buffer */
673 hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa,
674 softsp->mtu, &recv_count);
675
676 DPRINTF(("Instance %d glvc_read returns error = %ld, recv_count = %lu",
677 instance, hverr, recv_count));
678
679 if (hverr == H_EOK) {
680 if (uiop->uio_resid < recv_count) {
681 DPRINTF(("Instance %d, glvc_read user buffer "
682 "size(%lu) smaller than number of bytes "
683 "received(%lu).", instance, uiop->uio_resid,
684 recv_count));
685 mutex_exit(&softsp->recv_mutex);
686 return (EINVAL);
687 }
688 /* move data from kernel to user space */
689 error = uiomove(softsp->mb_recv_buf, recv_count,
690 UIO_READ, uiop);
691 } else {
692 error = glvc_emap_h2s(hverr);
693 }
694
695 /* Clear the RECV data interrupt bit on device register */
696 if (hv_service_clrstatus(softsp->s_id, GLVC_REG_RECV) != H_EOK) {
697 cmn_err(CE_WARN, "glvc_read clear status reg failed");
698 }
699
700 /* Set RECV interrupt enable bit so we can receive interrupt */
701 if (softsp->intr_mode == GLVC_INTR_MODE)
702 if (hv_service_setstatus(softsp->s_id, GLVC_REG_RECV_ENA)
703 != H_EOK) {
704 cmn_err(CE_WARN, "glvc_read set status reg failed");
705 }
706
707 mutex_exit(&softsp->recv_mutex);
708
709 return (error);
710 }
711
712 /*ARGSUSED*/
713 static int
glvc_write(dev_t dev,struct uio * uiop,cred_t * credp)714 glvc_write(dev_t dev, struct uio *uiop, cred_t *credp)
715 {
716 glvc_soft_state_t *softsp;
717 int instance;
718 int rv, error = DDI_SUCCESS;
719 uint64_t hverr, send_count = 0;
720
721 instance = getminor(dev);
722
723 softsp = ddi_get_soft_state(glvc_ssp, instance);
724
725 if (uiop->uio_resid > softsp->mtu)
726 return (EINVAL);
727
728 send_count = uiop->uio_resid;
729 DPRINTF(("instance %d glvc_write: request to send %lu bytes",
730 instance, send_count));
731
732 mutex_enter(&softsp->send_complete_mutex);
733 while (softsp->send_complete_flag == 0) {
734 rv = cv_reltimedwait_sig(&softsp->send_complete_cv,
735 &softsp->send_complete_mutex, softsp->polling_interval,
736 TR_CLOCK_TICK);
737 if (rv == 0) {
738 /*
739 * We got interrupted.
740 */
741 mutex_exit(&softsp->send_complete_mutex);
742 return (EINTR);
743 }
744 if (rv == -1) {
745 /*
746 * Timeout wait, trigger a soft intr in case
747 * we miss an interrupt or in polling mode.
748 */
749 ddi_trigger_softintr(softsp->poll_mode_softint_id);
750 }
751 }
752
753 /* move data from to user to kernel space */
754 error = uiomove(softsp->mb_send_buf, send_count,
755 UIO_WRITE, uiop);
756
757 if (error == 0) {
758 hverr = hv_service_send(softsp->s_id,
759 softsp->mb_send_buf_pa, send_count, &send_count);
760 error = glvc_emap_h2s(hverr);
761 }
762
763 DPRINTF(("instance %d glvc_write write check error = %d,"
764 " send_count = %lu", instance, error, send_count));
765
766 softsp->send_complete_flag = 0;
767
768 mutex_exit(&softsp->send_complete_mutex);
769
770 return (error);
771 }
772
773 /*
774 * Interrupt handler
775 */
776 static uint_t
glvc_intr(caddr_t arg)777 glvc_intr(caddr_t arg)
778 {
779 glvc_soft_state_t *softsp = (glvc_soft_state_t *)arg;
780 uint64_t status_reg;
781 int error = DDI_INTR_UNCLAIMED;
782 uint64_t hverr = H_EOK;
783 uint64_t clr_bits = 0;
784
785 mutex_enter(&softsp->recv_mutex);
786 mutex_enter(&softsp->send_complete_mutex);
787 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
788 DPRINTF(("glvc_intr: err = %ld, getstatus = 0x%lx",
789 hverr, status_reg));
790
791 /*
792 * Clear SEND_COMPLETE bit and disable RECV interrupt
793 */
794 if (status_reg & GLVC_REG_SEND)
795 clr_bits |= GLVC_REG_SEND;
796 if ((softsp->intr_mode == GLVC_INTR_MODE) &&
797 (status_reg & GLVC_REG_RECV))
798 clr_bits |= GLVC_REG_RECV_ENA;
799
800 if ((hverr = hv_service_clrstatus(softsp->s_id, clr_bits))
801 != H_EOK) {
802 cmn_err(CE_WARN, "glvc_intr clear status reg failed"
803 "error = %ld", hverr);
804 mutex_exit(&softsp->send_complete_mutex);
805 mutex_exit(&softsp->recv_mutex);
806 return (DDI_INTR_UNCLAIMED);
807 }
808
809 if (status_reg & GLVC_REG_RECV) {
810 cv_broadcast(&softsp->recv_cv);
811 error = DDI_INTR_CLAIMED;
812 }
813
814 if (status_reg & GLVC_REG_SEND) {
815 softsp->send_complete_flag = 1;
816 cv_broadcast(&softsp->send_complete_cv);
817 error = DDI_INTR_CLAIMED;
818 }
819
820 mutex_exit(&softsp->send_complete_mutex);
821 mutex_exit(&softsp->recv_mutex);
822
823 return (error);
824 }
825
826 /*
827 * Peek to see if there is data received. If no data available,
828 * we sleep wait. If there is data, read from hypervisor and copy
829 * to ioctl buffer. We don't clear the receive data interrupt bit.
830 */
831 static int
glvc_peek(glvc_soft_state_t * softsp,glvc_xport_msg_peek_t * msg_peek)832 glvc_peek(glvc_soft_state_t *softsp, glvc_xport_msg_peek_t *msg_peek)
833 {
834 int rv, error = 0;
835 uint64_t hverr = H_EOK;
836 uint64_t recv_count = 0;
837 uint64_t status_reg;
838
839 mutex_enter(&softsp->recv_mutex);
840
841 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
842 DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx",
843 hverr, status_reg));
844
845 /*
846 * If no data available, we wait till we get some.
847 * Notice we still holding the recv_mutex lock at
848 * this point.
849 */
850 while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) !=
851 GLVC_REG_RECV) {
852 rv = cv_reltimedwait_sig(&softsp->recv_cv,
853 &softsp->recv_mutex, softsp->polling_interval,
854 TR_CLOCK_TICK);
855 if (rv == 0) {
856 /*
857 * We got interrupted.
858 */
859 mutex_exit(&softsp->recv_mutex);
860 return (EINTR);
861 }
862 if (rv == -1) {
863 /*
864 * Timeout wait, trigger a soft intr in case
865 * we miss an interrupt or in polling mode.
866 */
867 ddi_trigger_softintr(softsp->poll_mode_softint_id);
868 }
869 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
870 DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx",
871 hverr, status_reg));
872 }
873
874 /* Read data into kernel buffer */
875 hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa,
876 softsp->mtu, &recv_count);
877 DPRINTF(("glvc_peek recv data, error = %ld, recv_count = %lu",
878 hverr, recv_count));
879
880 if (hverr == H_EOK && recv_count > 0) {
881 (void *) memcpy(msg_peek->buf,
882 softsp->mb_recv_buf, recv_count);
883 msg_peek->buflen = recv_count;
884 } else {
885 error = glvc_emap_h2s(hverr);
886 }
887
888 mutex_exit(&softsp->recv_mutex);
889
890 return (error);
891 }
892
893 static int
glvc_ioctl_opt_op(glvc_soft_state_t * softsp,intptr_t arg,int mode)894 glvc_ioctl_opt_op(glvc_soft_state_t *softsp, intptr_t arg, int mode)
895 {
896 glvc_xport_opt_op_t glvc_xport_cmd;
897 uint64_t status_reg;
898 int retval = 0;
899 uint64_t hverr;
900
901 if (ddi_copyin((caddr_t)arg, (caddr_t)&glvc_xport_cmd,
902 sizeof (glvc_xport_opt_op_t), mode) != 0) {
903 return (EFAULT);
904 }
905
906 switch (glvc_xport_cmd.opt_sel) {
907 case GLVC_XPORT_OPT_MTU_SZ:
908 if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) {
909 glvc_xport_cmd.opt_val = softsp->mtu;
910 retval = ddi_copyout((caddr_t)&glvc_xport_cmd,
911 (caddr_t)arg, sizeof (glvc_xport_opt_op_t),
912 mode);
913 } else
914 retval = ENOTSUP;
915
916 break;
917
918 case GLVC_XPORT_OPT_REG_STATUS:
919 if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) {
920 mutex_enter(&softsp->statusreg_mutex);
921 hverr = hv_service_getstatus(softsp->s_id, &status_reg);
922 mutex_exit(&softsp->statusreg_mutex);
923 if (hverr == H_EOK) {
924 glvc_xport_cmd.opt_val = (uint32_t)status_reg;
925 retval = ddi_copyout((caddr_t)&glvc_xport_cmd,
926 (caddr_t)arg, sizeof (glvc_xport_opt_op_t),
927 mode);
928 } else {
929 retval = EIO;
930 }
931 } else {
932 retval = ENOTSUP;
933 }
934
935 break;
936
937 default:
938 retval = ENOTSUP;
939 break;
940 }
941
942 return (retval);
943 }
944
945
946 /*ARGSUSED*/
947 static int
glvc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)948 glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
949 int *rval_p)
950 {
951 glvc_soft_state_t *softsp;
952 int instance = getminor(dev);
953 glvc_xport_msg_peek_t glvc_peek_msg, msg_peek_cmd;
954 glvc_xport_msg_peek32_t msg_peek_cmd32;
955
956 int retval = 0;
957
958 softsp = ddi_get_soft_state(glvc_ssp, instance);
959
960 switch (cmd) {
961 case GLVC_XPORT_IOCTL_OPT_OP:
962 retval = glvc_ioctl_opt_op(softsp, arg, mode);
963 break;
964
965 case GLVC_XPORT_IOCTL_DATA_PEEK:
966 glvc_peek_msg.buf =
967 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
968 if (glvc_peek_msg.buf == NULL)
969 return (EBUSY);
970 retval = glvc_peek(softsp, &glvc_peek_msg);
971 if (retval == 0) {
972 switch (ddi_model_convert_from(mode)) {
973 case DDI_MODEL_ILP32:
974 if (ddi_copyin((caddr_t)arg,
975 (caddr_t)&msg_peek_cmd32,
976 sizeof (glvc_xport_msg_peek32_t),
977 mode) == -1) {
978 retval = EFAULT;
979 break;
980 }
981
982 if (msg_peek_cmd32.buflen32 == 0) {
983 retval = EINVAL;
984 break;
985 }
986
987 if (msg_peek_cmd32.buflen32 >
988 glvc_peek_msg.buflen)
989 msg_peek_cmd32.buflen32 =
990 glvc_peek_msg.buflen;
991
992 if (ddi_copyout((caddr_t)glvc_peek_msg.buf,
993 (caddr_t)(uintptr_t)msg_peek_cmd32.buf32,
994 msg_peek_cmd32.buflen32, mode) == -1) {
995 retval = EFAULT;
996 break;
997 }
998
999 if (ddi_copyout((caddr_t)&msg_peek_cmd32,
1000 (caddr_t)arg,
1001 sizeof (glvc_xport_msg_peek32_t), mode)
1002 == -1)
1003 retval = EFAULT;
1004 break;
1005
1006 case DDI_MODEL_NONE:
1007 if (ddi_copyin((caddr_t)arg,
1008 (caddr_t)&msg_peek_cmd,
1009 sizeof (glvc_xport_msg_peek_t), mode) == -1)
1010 retval = EFAULT;
1011
1012 if (msg_peek_cmd.buflen == 0) {
1013 retval = EINVAL;
1014 break;
1015 }
1016
1017 if (msg_peek_cmd.buflen > glvc_peek_msg.buflen)
1018 msg_peek_cmd.buflen =
1019 glvc_peek_msg.buflen;
1020
1021 if (ddi_copyout((caddr_t)glvc_peek_msg.buf,
1022 (caddr_t)msg_peek_cmd.buf,
1023 msg_peek_cmd.buflen, mode) == -1) {
1024 retval = EFAULT;
1025 break;
1026 }
1027
1028 if (ddi_copyout((caddr_t)&msg_peek_cmd,
1029 (caddr_t)arg,
1030 sizeof (glvc_xport_msg_peek_t), mode) == -1)
1031 retval = EFAULT;
1032 break;
1033
1034 default:
1035 retval = EFAULT;
1036 break;
1037 }
1038 }
1039 kmem_free(glvc_peek_msg.buf, softsp->mtu);
1040 break;
1041
1042 default:
1043 retval = ENOTSUP;
1044 break;
1045 }
1046 return (retval);
1047 }
1048
1049 /*
1050 * Map hypervisor error code to solaris. Only
1051 * H_EOK, H_EINVA, H_EWOULDBLOCK and H_EIO are meaningful
1052 * to this device. All other error codes are mapped to EIO.
1053 */
1054 static int
glvc_emap_h2s(uint64_t hv_errcode)1055 glvc_emap_h2s(uint64_t hv_errcode)
1056 {
1057 int s_errcode;
1058
1059 switch (hv_errcode) {
1060 case H_EOK:
1061 s_errcode = 0;
1062 break;
1063
1064 case H_EINVAL:
1065 s_errcode = EINVAL;
1066 break;
1067
1068 case H_EWOULDBLOCK:
1069 s_errcode = EWOULDBLOCK;
1070 break;
1071
1072 case H_EIO:
1073 s_errcode = EIO;
1074 break;
1075
1076 default:
1077 /* should not happen */
1078 DPRINTF(("Unexpected device error code %ld received, "
1079 "mapped to EIO", hv_errcode));
1080 s_errcode = EIO;
1081 break;
1082 }
1083
1084 return (s_errcode);
1085 }
1086