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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * LDOMs Domain Services Device Driver
30 #include <sys/types.h>
32 #include <sys/errno.h>
37 #include <sys/ksynch.h>
38 #include <sys/modctl.h>
40 #include <sys/devops.h>
41 #include <sys/debug.h>
42 #include <sys/cmn_err.h>
44 #include <sys/sunddi.h>
45 #include <sys/taskq.h>
48 #include <sys/mach_descrip.h>
49 #include <sys/mdesc.h>
53 #include <sys/ds_impl.h>
55 #include <sys/bitmap.h>
56 #include <sys/sysevent.h>
58 static dev_info_t
*vlds_devi
;
61 typedef struct vlds_state
{
67 static void *vlds_statep
;
69 typedef struct vlds_recv_hdr
{
70 struct vlds_recv_hdr
*next
; /* next in recv list */
71 void *data
; /* the data itself */
72 size_t datasz
; /* size of the data */
75 typedef struct vlds_svc_info
{
76 int state
; /* driver svc info state VLDS_RECV* */
77 vlds_recv_hdr_t
*recv_headp
; /* ptr to head of recv queue */
78 vlds_recv_hdr_t
*recv_tailp
; /* ptr to tail of recv queue */
79 size_t recv_size
; /* no. of bytes in recv queue */
80 uint_t recv_cnt
; /* no of messages in recv queue */
81 kmutex_t recv_lock
; /* lock for recv queue */
82 kcondvar_t recv_cv
; /* condition variable for recv queue */
83 int recv_nreaders
; /* no of currently waiting readers */
86 #define VLDS_RECV_OK 1
87 #define VLDS_RECV_UNREG_PENDING 2
88 #define VLDS_RECV_OVERFLOW 3
90 static int vlds_ports_inited
= 0;
92 static uint_t
vlds_flags_to_svc(uint64_t flags
);
95 #define VLDS_NAME "vlds"
96 static int vlds_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
);
97 static int vlds_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
);
98 static int vlds_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
100 static int vlds_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
,
102 static int vlds_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
103 static int vlds_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
105 /* mdeg register functions */
106 static void vlds_mdeg_init(void);
107 static int vlds_mdeg_cb(void *cb_argp
, mdeg_result_t
*resp
);
108 static int vlds_mdeg_register(void);
109 static int vlds_mdeg_unregister(void);
110 static int vlds_add_mdeg_port(md_t
*mdp
, mde_cookie_t node
);
112 /* driver utilities */
113 static void vlds_user_reg_cb(ds_cb_arg_t arg
, ds_ver_t
*ver
, ds_svc_hdl_t hdl
);
114 static void vlds_user_unreg_cb(ds_cb_arg_t arg
);
115 static void vlds_user_data_cb(ds_cb_arg_t arg
, void *buf
, size_t buflen
);
116 static void vlds_recvq_init(vlds_svc_info_t
*dpsp
);
117 static void vlds_recvq_destroy(vlds_svc_info_t
*dpsp
);
118 static int vlds_recvq_get_data(vlds_svc_info_t
*dpsp
, void *buf
, size_t buflen
,
119 size_t *msglenp
, int mode
);
120 static void vlds_recvq_drain(vlds_svc_info_t
*dpsp
);
121 static int vlds_recvq_put_data(vlds_svc_info_t
*dpsp
, void *buf
, size_t buflen
);
122 static int vlds_recv_msg(ds_svc_hdl_t hdl
, void *buf
, size_t buflen
,
123 size_t *msglenp
, int mode
);
126 * DS driver Ops Vector
128 static struct cb_ops vlds_cb_ops
= {
129 vlds_open
, /* cb_open */
130 vlds_close
, /* cb_close */
131 nodev
, /* cb_strategy */
132 nodev
, /* cb_print */
135 nodev
, /* cb_write */
136 vlds_ioctl
, /* cb_ioctl */
137 nodev
, /* cb_devmap */
139 nodev
, /* cb_segmap */
140 nochpoll
, /* cb_chpoll */
141 ddi_prop_op
, /* cb_prop_op */
143 D_MP
| D_64BIT
, /* cb_flag */
145 nodev
, /* cb_aread */
146 nodev
/* cb_awrite */
149 static struct dev_ops vlds_dev_ops
= {
150 DEVO_REV
, /* devo_rev */
152 vlds_getinfo
, /* devo_getinfo */
153 nulldev
, /* devo_identify */
154 nulldev
, /* devo_probe */
155 vlds_attach
, /* devo_attach */
156 vlds_detach
, /* devo_detach */
157 nodev
, /* devo_reset */
158 &vlds_cb_ops
, /* devo_cb_ops */
159 NULL
, /* devo_bus_ops */
160 nulldev
/* devo_power */
163 static struct modldrv modldrv
= {
165 "Domain Services Driver 1.0",
169 static struct modlinkage modlinkage
= {
176 * Callback ops for user-land services.
178 static ds_clnt_ops_t ds_user_ops
= {
179 vlds_user_reg_cb
, /* register */
180 vlds_user_unreg_cb
, /* unregister */
181 vlds_user_data_cb
, /* data */
182 NULL
/* ds_ucap_init will fill in */
185 static size_t vlds_recvq_maxsize
= DS_STREAM_MTU
* 8;
186 static uint_t vlds_recvq_maxmsg
= 16;
188 #define VLDS_MINOR_MAX SHRT_MAX
190 /* Definitions for binding handle array */
191 static ulong_t vlds_bitmap_initial
= 1; /* index 0 indicates error */
192 static ulong_t
*vlds_minor_bitmap
= &vlds_bitmap_initial
;
193 static size_t vlds_minor_bits
= BT_NBIPUL
;
194 static kmutex_t vlds_minor_mutex
;
197 * Following vlds_minor_* routines map a binding handle to a minor number.
198 * Has to be called w/ locks held.
201 vlds_minor_alloc(void)
203 ulong_t
*bhst
= vlds_minor_bitmap
;
205 /* Increase bitmap by one BT_NBIPUL */
206 if (vlds_minor_bits
+ BT_NBIPUL
> VLDS_MINOR_MAX
) {
209 vlds_minor_bitmap
= kmem_zalloc(
210 BT_SIZEOFMAP(vlds_minor_bits
+ BT_NBIPUL
), KM_SLEEP
);
211 bcopy(bhst
, vlds_minor_bitmap
, BT_SIZEOFMAP(vlds_minor_bits
));
212 if (bhst
!= &vlds_bitmap_initial
)
213 kmem_free(bhst
, BT_SIZEOFMAP(vlds_minor_bits
));
214 vlds_minor_bits
+= BT_NBIPUL
;
216 return (vlds_minor_bitmap
);
220 vlds_minor_free(ulong_t
*bitmap
)
222 if (bitmap
!= &vlds_bitmap_initial
)
223 kmem_free(bitmap
, BT_SIZEOFMAP(vlds_minor_bits
));
232 /* Search for an available index */
233 mutex_enter(&vlds_minor_mutex
);
234 if ((idx
= bt_availbit(vlds_minor_bitmap
,
235 vlds_minor_bits
)) == -1) {
236 /* All busy - allocate additional binding handle bitmap space */
237 if ((bhst
= vlds_minor_alloc()) == NULL
) {
238 /* Reached our maximum of id's == SHRT_MAX */
239 mutex_exit(&vlds_minor_mutex
);
242 vlds_minor_bitmap
= bhst
;
244 idx
= bt_availbit(vlds_minor_bitmap
, vlds_minor_bits
);
246 BT_SET(vlds_minor_bitmap
, idx
);
247 mutex_exit(&vlds_minor_mutex
);
252 vlds_minor_rele(index_t idx
)
254 mutex_enter(&vlds_minor_mutex
);
255 ASSERT(BT_TEST(vlds_minor_bitmap
, idx
) == 1);
256 BT_CLEAR(vlds_minor_bitmap
, idx
);
257 mutex_exit(&vlds_minor_mutex
);
261 vlds_minor_init(void)
263 mutex_init(&vlds_minor_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
271 if ((s
= ddi_soft_state_init(&vlds_statep
, sizeof (vlds_state_t
), 0))
275 if ((s
= mod_install(&modlinkage
)) != 0) {
276 ddi_soft_state_fini(&vlds_statep
);
290 if ((s
= mod_remove(&modlinkage
)) != 0)
293 ddi_soft_state_fini(&vlds_statep
);
299 _info(struct modinfo
*modinfop
)
301 return (mod_info(&modlinkage
, modinfop
));
308 vlds_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **resultp
)
311 case DDI_INFO_DEVT2DEVINFO
:
312 *resultp
= vlds_devi
;
313 return (DDI_SUCCESS
);
314 case DDI_INFO_DEVT2INSTANCE
:
316 return (DDI_SUCCESS
);
318 return (DDI_FAILURE
);
323 vlds_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
325 if (cmd
!= DDI_ATTACH
) {
326 return (DDI_FAILURE
);
329 if (ddi_create_minor_node(devi
, VLDS_NAME
, S_IFCHR
,
330 0, DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
331 ddi_remove_minor_node(devi
, NULL
);
332 return (DDI_FAILURE
);
338 (void) vlds_mdeg_register();
340 return (DDI_SUCCESS
);
346 vlds_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
348 if (cmd
!= DDI_DETACH
) {
349 return (DDI_FAILURE
);
352 vlds_minor_free(vlds_minor_bitmap
);
353 ddi_remove_minor_node(devi
, NULL
);
354 (void) vlds_mdeg_unregister();
355 return (DDI_SUCCESS
);
361 vlds_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
)
365 if (otyp
!= OTYP_CHR
)
368 if (getminor(*devp
) != 0)
371 minor
= vlds_minor_get();
373 /* All minors are busy */
376 if (ddi_soft_state_zalloc(vlds_statep
, minor
) != DDI_SUCCESS
) {
377 vlds_minor_rele(minor
);
381 *devp
= makedevice(getmajor(*devp
), minor
);
389 vlds_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
391 int minor
= (int)getminor(dev
);
394 DS_DBG_VLDS(CE_NOTE
, "vlds_close");
397 * Unregister all handles associated with this process.
401 if (otyp
!= OTYP_CHR
)
404 sp
= ddi_get_soft_state(vlds_statep
, minor
);
410 (void) sysevent_evc_unbind(sp
->evchan
);
414 ddi_soft_state_free(vlds_statep
, minor
);
415 vlds_minor_rele(minor
);
421 vlds_init_sysevent(vlds_state_t
*sp
, uint32_t flags
)
423 char evchan_name
[MAX_CHNAME_LEN
];
426 if (flags
& DSSF_ANYCB_VALID
) {
428 DS_DBG_VLDS(CE_NOTE
, "%s: sysevent already bound",
432 (void) sprintf(evchan_name
, VLDS_SYSEV_CHAN_FMT
, ddi_get_pid());
433 if ((rv
= sysevent_evc_bind(evchan_name
, &sp
->evchan
,
434 EVCH_CREAT
|EVCH_HOLD_PEND
)) != 0) {
435 cmn_err(CE_WARN
, "%s: can't bind to '%s' (%d)",
436 __func__
, evchan_name
, rv
);
440 DS_DBG_VLDS(CE_NOTE
, "%s: sysevent bind to '%s' successful",
441 __func__
, evchan_name
);
446 #define ARGTOPTR(x) ((void *)((uintptr_t)(x)))
447 #define ARGTOUINT(x) ((uint_t)(x))
448 #define ARGTOINT(x) ((int)(x))
451 vlds_get_string(vlds_string_t
*strp
, char **rstrp
, int mode
)
454 uint_t len
= strp
->vlds_strlen
;
461 if (len
> MAXNAMELEN
) {
462 DS_DBG_VLDS(CE_NOTE
, "%s: invalid string length: %d", __func__
,
466 str
= DS_MALLOC(len
);
467 if (ddi_copyin(ARGTOPTR(strp
->vlds_strp
), str
, len
, mode
) != 0) {
468 DS_DBG_VLDS(CE_NOTE
, "%s: ddi copyin failed (%p)", __func__
,
469 ARGTOPTR(strp
->vlds_strp
));
473 slen
= strlen(str
) + 1;
475 DS_DBG_VLDS(CE_NOTE
, "%s: invalid string len: %d != len: %d",
476 __func__
, slen
, len
);
485 vlds_put_string(char *str
, vlds_string_t
*strp
, int mode
)
494 len
= strlen(str
) + 1;
497 * If string is longer than user buffer, return a
498 * truncated, null-terminated string.
500 if (len
> strp
->vlds_strlen
) {
501 len
= strp
->vlds_strlen
;
503 tstr
= DS_MALLOC(len
);
504 (void) memcpy(tstr
, str
, len
- 1);
505 tstr
[len
- 1] = '\0';
509 rv
= ddi_copyout(str
, ARGTOPTR(strp
->vlds_strp
), len
, mode
);
514 DS_DBG_VLDS(CE_NOTE
, "%s: copyout (%p) failed", __func__
,
515 ARGTOPTR(strp
->vlds_strp
));
522 vlds_get_ucap(vlds_cap_t
*capp
, ds_capability_t
*ucap
, int mode
)
532 if (ddi_copyin(capp
, &vlds_cap
, sizeof (vlds_cap
), mode
) != 0) {
533 DS_DBG_VLDS(CE_NOTE
, "%s: cap copyin failed (%p)", __func__
,
538 nver
= ARGTOUINT(vlds_cap
.vlds_nver
);
540 if (nver
> VLDS_MAX_VERS
) {
541 DS_DBG_VLDS(CE_NOTE
, "%s: vlds_nver (%d) invalid", __func__
,
546 if ((rv
= vlds_get_string(&vlds_cap
.vlds_service
, &servp
, mode
)) != 0) {
547 DS_DBG_VLDS(CE_NOTE
, "%s: vlds_get_string vlds_service failed "
548 "(%d)", __func__
, rv
);
550 } else if (servp
== NULL
) {
551 DS_DBG_VLDS(CE_NOTE
, "%s: vlds_get_string vlds_service is NULL",
556 n
= nver
* sizeof (vlds_ver_t
);
559 if (ddi_copyin(ARGTOPTR(vlds_cap
.vlds_versp
), dsvp
, n
, mode
) != 0) {
560 DS_DBG_VLDS(CE_NOTE
, "%s: copyin of vers (%p, %d) failed",
561 __func__
, ARGTOPTR(vlds_cap
.vlds_versp
), n
);
562 DS_FREE(servp
, strlen(servp
) + 1);
567 ucap
->svc_id
= servp
;
568 ucap
->vers
= DS_MALLOC(nver
* sizeof (ds_ver_t
));
569 for (i
= 0; i
< nver
; i
++) {
570 ucap
->vers
[i
].major
= dsvp
[i
].vlds_major
;
571 ucap
->vers
[i
].minor
= dsvp
[i
].vlds_minor
;
579 vlds_free_ucap(ds_capability_t
*ucap
)
581 kmem_free(ucap
->svc_id
, strlen(ucap
->svc_id
) + 1);
582 kmem_free(ucap
->vers
, ucap
->nvers
* sizeof (ds_ver_t
));
587 vlds_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
592 ds_domain_hdl_t dhdl
;
595 int minor
= (int)getminor(dev
);
597 if ((sp
= ddi_get_soft_state(vlds_statep
, minor
)) == NULL
)
604 vlds_svc_reg_arg_t vlds_arg
;
605 ds_capability_t ucap
;
609 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
611 DS_DBG_VLDS(CE_NOTE
, "%s: SVC REG arg copyin failed",
616 if ((rv
= vlds_get_ucap(ARGTOPTR(vlds_arg
.vlds_capp
), &ucap
,
618 DS_DBG_VLDS(CE_NOTE
, "%s: SVC REG get_ucap failed (%d)",
623 flags
= vlds_flags_to_svc(vlds_arg
.vlds_reg_flags
);
624 if ((rv
= vlds_init_sysevent(sp
, flags
)) != 0) {
625 vlds_free_ucap(&ucap
);
629 rv
= ds_ucap_init(&ucap
, &ds_user_ops
,
630 vlds_flags_to_svc(vlds_arg
.vlds_reg_flags
) | DSSF_ISUSER
,
633 vlds_free_ucap(&ucap
);
636 DS_DBG_VLDS(CE_NOTE
, "%s: SVC REG ds_ucap_init failed "
637 "(%d)", __func__
, rv
);
642 if (ddi_copyout(&hdl_arg
, ARGTOPTR(vlds_arg
.vlds_hdlp
),
643 sizeof (hdl_arg
), mode
) != 0) {
644 DS_DBG_VLDS(CE_NOTE
, "%s: SVC REG copyout failed",
648 DS_DBG_VLDS(CE_NOTE
, "%s: SVC REG succeeded: hdl: %lx",
655 vlds_unreg_hdl_arg_t vlds_arg
;
657 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
659 DS_DBG_VLDS(CE_NOTE
, "%s: UNREG_HDL arg copyin failed",
664 hdl
= vlds_arg
.vlds_hdl
;
666 if ((rv
= ds_is_my_hdl(hdl
, minor
)) != 0) {
667 DS_DBG_VLDS(CE_NOTE
, "%s: UNREG_HDL ds_is_my_hdl "
668 " hdl: %lx inst: %d failed (%d)", __func__
,
673 if ((rv
= ds_unreg_hdl(hdl
)) != 0) {
674 DS_DBG_VLDS(CE_NOTE
, "%s: UNREG_HDL ds_cap_unreg "
675 " hdl: %lx failed (%d)", __func__
, hdl
, rv
);
678 DS_DBG_VLDS(CE_NOTE
, "%s: UNREG_HDL hdl: %lx succeeded",
683 case VLDS_HDL_LOOKUP
:
685 vlds_hdl_lookup_arg_t vlds_arg
;
687 uint_t is_client
, maxhdls
, nhdls
;
690 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
692 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP arg copyin failed",
697 is_client
= ARGTOUINT(vlds_arg
.vlds_isclient
);
698 maxhdls
= ARGTOUINT(vlds_arg
.vlds_maxhdls
);
700 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP invalid maxhdls "
701 "%d", __func__
, maxhdls
);
705 if ((rv
= vlds_get_string(&vlds_arg
.vlds_service
, &servicep
,
707 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP vlds_get_string "
708 "(service) failed (%d)", __func__
, rv
);
710 } else if (servicep
== NULL
) {
711 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP vlds_get_string "
712 " service is NULL", __func__
);
716 if (ARGTOPTR(vlds_arg
.vlds_hdlsp
) == 0) {
719 hdlsp
= DS_MALLOC(maxhdls
* sizeof (*hdlsp
));
722 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP (%s, %d) entered",
723 __func__
, servicep
, is_client
);
724 rv
= ds_hdl_lookup(servicep
, is_client
, hdlsp
, maxhdls
, &nhdls
);
726 DS_FREE(servicep
, strlen(servicep
) + 1);
729 DS_FREE(hdlsp
, maxhdls
* sizeof (*hdlsp
));
731 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP failed: (%d)",
736 if (hdlsp
!= NULL
&& nhdls
> 0 &&
737 ddi_copyout(hdlsp
, ARGTOPTR(vlds_arg
.vlds_hdlsp
),
738 nhdls
* sizeof (ds_svc_hdl_t
), mode
) != 0) {
740 DS_FREE(hdlsp
, maxhdls
* sizeof (*hdlsp
));
742 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP copyout of hdls "
743 " failed", __func__
);
747 DS_FREE(hdlsp
, maxhdls
* sizeof (*hdlsp
));
751 if (ddi_copyout(&nhdls_arg
, ARGTOPTR(vlds_arg
.vlds_nhdlsp
),
752 sizeof (nhdls_arg
), mode
) != 0) {
753 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP copyout of nhdls "
754 " failed", __func__
);
757 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_LOOKUP succeeded: nhdls: %d",
762 case VLDS_DMN_LOOKUP
:
764 vlds_dmn_lookup_arg_t vlds_arg
;
767 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
769 DS_DBG_VLDS(CE_NOTE
, "%s: DMN_LOOKUP arg copyin failed",
774 hdl
= vlds_arg
.vlds_hdl
;
776 if ((rv
= ds_domain_lookup(hdl
, &dhdl
)) != 0) {
777 DS_DBG_VLDS(CE_NOTE
, "%s: DMN_LOOKUP lookup hdl: 0x%lx "
778 "failed (%d)", __func__
, hdl
, rv
);
784 if (ddi_copyout(&dhdl_arg
, ARGTOPTR(vlds_arg
.vlds_dhdlp
),
785 sizeof (dhdl_arg
), mode
) != 0) {
786 DS_DBG_VLDS(CE_NOTE
, "%s: DMN_LOOKUP copyout "
787 "failed (%d)", __func__
, rv
);
791 DS_DBG_VLDS(CE_NOTE
, "%s: DMN_LOOKUP hdl: 0x%lx, dhdl: 0x%lx "
792 "succeeded", __func__
, hdl
, dhdl
);
798 vlds_send_msg_arg_t vlds_arg
;
802 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
804 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG arg copyin failed",
809 hdl
= vlds_arg
.vlds_hdl
;
810 if ((rv
= ds_is_my_hdl(hdl
, minor
)) != 0) {
811 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG ds_is_my_hdl "
812 " hdl: %lx inst: %d failed (%d)", __func__
,
817 buflen
= ARGTOUINT(vlds_arg
.vlds_buflen
);
818 bufp
= DS_MALLOC(buflen
);
819 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG (hdl: %lx, bufp: %p, "
820 "buflen: %ld", __func__
, hdl
, ARGTOPTR(vlds_arg
.vlds_bufp
),
823 if (ddi_copyin(ARGTOPTR(vlds_arg
.vlds_bufp
), bufp
, buflen
,
825 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG buf (%p, %ld) "
826 "copyin failed", __func__
,
827 ARGTOPTR(vlds_arg
.vlds_bufp
), buflen
);
828 DS_FREE(bufp
, buflen
);
832 if ((rv
= ds_cap_send(hdl
, bufp
, buflen
)) != 0) {
833 DS_FREE(bufp
, buflen
);
834 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG ds_cap_send failed "
835 "(%d)", __func__
, rv
);
838 DS_DBG_VLDS(CE_NOTE
, "%s: SEND_MSG hdl: %lx, bufp: %p, "
839 "buflen: %ld succeeded", __func__
, hdl
, (void *)bufp
,
841 DS_DUMP_MSG(DS_DBG_FLAG_VLDS
, bufp
, buflen
);
842 DS_FREE(bufp
, buflen
);
848 vlds_recv_msg_arg_t vlds_arg
;
849 size_t buflen
, msglen
;
852 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
854 DS_DBG_VLDS(CE_NOTE
, "%s: RECV_MSG arg copyin failed",
859 hdl
= vlds_arg
.vlds_hdl
;
860 if ((rv
= ds_is_my_hdl(hdl
, minor
)) != 0) {
861 DS_DBG_VLDS(CE_NOTE
, "%s: RECV_MSG ds_is_my_hdl "
862 " hdl: %lx inst: %d failed (%d)", __func__
,
867 buflen
= ARGTOUINT(vlds_arg
.vlds_buflen
);
869 if ((rv
= vlds_recv_msg(hdl
, ARGTOPTR(vlds_arg
.vlds_bufp
),
870 buflen
, &msglen
, mode
)) != 0 && rv
!= EFBIG
) {
871 DS_DBG_VLDS(CE_NOTE
, "%s: RECV_MSG vlds_recv_msg "
872 " failed (%d)", __func__
, rv
);
877 if (ddi_copyout(&msglen_arg
, ARGTOPTR(vlds_arg
.vlds_msglenp
),
878 sizeof (msglen_arg
), mode
) != 0) {
879 DS_DBG_VLDS(CE_NOTE
, "%s: RECV_MSG copyout of msglen "
888 DS_DBG_VLDS(CE_NOTE
, "%s: RECV_MSG hdl: %lx, "
889 "msglen: %ld succeeded", __func__
, hdl
, buflen
);
893 case VLDS_HDL_ISREADY
:
895 vlds_hdl_isready_arg_t vlds_arg
;
897 uint64_t is_ready_arg
;
900 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
902 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_ISREADY arg copyin "
907 hdl
= vlds_arg
.vlds_hdl
;
908 if ((rv
= ds_hdl_isready(hdl
, &is_ready
)) != 0) {
909 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_ISREADY ds_hdl_isready "
910 "error (%d)", __func__
, rv
);
914 is_ready_arg
= is_ready
;
915 if (ddi_copyout(&is_ready_arg
, ARGTOPTR(vlds_arg
.vlds_isreadyp
),
916 sizeof (is_ready_arg
), mode
) != 0) {
917 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_ISREADY copyout of "
918 "vlds_isready failed", __func__
);
921 DS_DBG_VLDS(CE_NOTE
, "%s: HDL_ISREADY succeeded hdl: %lx, "
922 "is_ready: %d", __func__
, hdl
, is_ready
);
926 case VLDS_DOM_NAM2HDL
:
928 vlds_dom_nam2hdl_arg_t vlds_arg
;
931 ds_domain_hdl_t dhdl
;
933 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
935 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL arg copyin "
940 if ((rv
= vlds_get_string(&vlds_arg
.vlds_domain_name
,
941 &domain_name
, mode
)) != 0) {
942 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL vlds_get_string "
943 "domain_name failed (%d)", __func__
, rv
);
945 } else if (servicep
== NULL
) {
946 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL vlds_get_string "
947 " domain_name is NULL", __func__
);
951 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL (%s) entered", __func__
,
954 if ((rv
= ds_dom_name_to_hdl(domain_name
, &dhdl
)) != 0) {
955 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL name: '%s' "
956 "failed: (%d)", __func__
, domain_name
, rv
);
957 DS_FREE(domain_name
, strlen(domain_name
) + 1);
962 if (ddi_copyout(&dhdl_arg
, ARGTOPTR(vlds_arg
.vlds_dhdlp
),
963 sizeof (dhdl_arg
), mode
) != 0) {
964 DS_FREE(domain_name
, strlen(domain_name
) + 1);
965 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL copyout of dhdl "
966 " failed", __func__
);
970 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_NAM2HDL succeeded: name: '%s', "
971 "dhdl: 0x%lx", __func__
, domain_name
, dhdl
);
972 DS_FREE(domain_name
, strlen(domain_name
) + 1);
976 case VLDS_DOM_HDL2NAM
:
978 vlds_dom_hdl2nam_arg_t vlds_arg
;
979 ds_domain_hdl_t dhdl
;
982 if (ddi_copyin((void *)arg
, &vlds_arg
, sizeof (vlds_arg
),
984 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_HDL2NAM arg copyin "
989 dhdl
= vlds_arg
.vlds_dhdl
;
990 if ((rv
= ds_dom_hdl_to_name(dhdl
, &domain_name
)) != 0) {
991 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_HDL2NAM lookup dhdl: %lx "
992 "failed (%d)", __func__
, dhdl
, rv
);
996 if ((rv
= vlds_put_string(domain_name
,
997 &vlds_arg
.vlds_domain_name
, mode
)) != 0) {
998 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_HDL2NAM vlds_put_string "
999 "'%s' failed (%d)", __func__
, domain_name
, rv
);
1003 DS_DBG_VLDS(CE_NOTE
, "%s: DOM_HDL2NAM dhdl: 0x%lx name: '%s'",
1004 __func__
, dhdl
, domain_name
);
1015 vlds_flags_to_svc(uint64_t flags
)
1019 if (flags
& VLDS_REG_CLIENT
)
1020 sflags
|= DSSF_ISCLIENT
;
1021 if (flags
& VLDS_REGCB_VALID
)
1022 sflags
|= DSSF_REGCB_VALID
;
1023 if (flags
& VLDS_UNREGCB_VALID
)
1024 sflags
|= DSSF_UNREGCB_VALID
;
1025 if (flags
& VLDS_DATACB_VALID
)
1026 sflags
|= DSSF_DATACB_VALID
;
1031 * MD registration code.
1032 * Placed in vlds rather than ds module due to cirular dependency of
1033 * platsvc module which contains the mdeg code.
1035 mdeg_handle_t vlds_mdeg_hdl
;
1038 * Look for "virtual-device-service" node among the
1039 * "virtual-device" nodes.
1041 static mdeg_prop_spec_t vlds_prop_template
[] = {
1042 { MDET_PROP_STR
, "name", VLDS_MD_VIRT_ROOT_NAME
},
1043 { MDET_LIST_END
, NULL
, NULL
}
1046 static mdeg_node_spec_t vlds_node_template
=
1047 { VLDS_MD_VIRT_DEV_NAME
, vlds_prop_template
};
1050 * Matching criteria passed to the MDEG to register interest
1051 * in changes to domain services port nodes identified by their
1054 static md_prop_match_t vlds_port_prop_match
[] = {
1055 { MDET_PROP_VAL
, "id" },
1056 { MDET_LIST_END
, NULL
}
1059 static mdeg_node_match_t vlds_port_match
= { VLDS_MD_VIRT_PORT_NAME
,
1060 vlds_port_prop_match
};
1064 vlds_mdeg_cb(void *cb_argp
, mdeg_result_t
*resp
)
1066 _NOTE(ARGUNUSED(cb_argp
))
1074 DS_DBG_VLDS(CE_NOTE
, "vlds_mdeg_cb: no result returned");
1075 return (MDEG_FAILURE
);
1078 DS_DBG_VLDS(CE_NOTE
, "%s: added=%d, removed=%d, matched=%d", __func__
,
1079 resp
->added
.nelem
, resp
->removed
.nelem
, resp
->match_prev
.nelem
);
1081 /* process added ports */
1082 for (idx
= 0; idx
< resp
->added
.nelem
; idx
++) {
1083 mdp
= resp
->added
.mdp
;
1084 node
= resp
->added
.mdep
[idx
];
1086 DS_DBG_VLDS(CE_NOTE
, "%s: processing added node 0x%lx",
1089 /* attempt to add a port */
1090 if ((rv
= vlds_add_mdeg_port(mdp
, node
)) != MDEG_SUCCESS
) {
1091 if (vlds_ports_inited
) {
1092 cmn_err(CE_NOTE
, "%s: unable to add port, "
1093 "err = %d", __func__
, rv
);
1098 /* process removed ports */
1099 for (idx
= 0; idx
< resp
->removed
.nelem
; idx
++) {
1100 mdp
= resp
->removed
.mdp
;
1101 node
= resp
->removed
.mdep
[idx
];
1103 DS_DBG_VLDS(CE_NOTE
, "%s: processing removed node 0x%lx",
1106 /* read in the port's id property */
1107 if (md_get_prop_val(mdp
, node
, "id", &portno
)) {
1108 cmn_err(CE_NOTE
, "%s: node 0x%lx of removed list "
1109 "has no 'id' property", __func__
, node
);
1113 /* attempt to remove a port */
1114 if ((rv
= ds_remove_port(portno
, 0)) != 0) {
1115 cmn_err(CE_NOTE
, "%s: unable to remove port %lu, "
1116 " err %d", __func__
, portno
, rv
);
1120 vlds_ports_inited
= 1;
1122 return (MDEG_SUCCESS
);
1125 /* register callback to mdeg */
1127 vlds_mdeg_register(void)
1131 DS_DBG_VLDS(CE_NOTE
, "vlds_mdeg_register: entered");
1133 /* perform the registration */
1134 rv
= mdeg_register(&vlds_node_template
, &vlds_port_match
, vlds_mdeg_cb
,
1135 NULL
, &vlds_mdeg_hdl
);
1137 if (rv
!= MDEG_SUCCESS
) {
1138 cmn_err(CE_NOTE
, "vlds_mdeg_register: mdeg_register "
1139 "failed, err = %d", rv
);
1140 return (DDI_FAILURE
);
1143 return (DDI_SUCCESS
);
1146 /* unregister callback from mdeg */
1148 vlds_mdeg_unregister(void)
1150 DS_DBG_VLDS(CE_NOTE
, "vlds_mdeg_unregister: hdl=0x%lx", vlds_mdeg_hdl
);
1152 return (mdeg_unregister(vlds_mdeg_hdl
));
1156 vlds_get_port_channel(md_t
*mdp
, mde_cookie_t node
, uint64_t *ldc_id
)
1158 int num_nodes
, nchan
;
1160 mde_cookie_t
*listp
;
1163 * Find the channel-endpoint node(s) (which should be under this
1164 * port node) which contain the channel id(s).
1166 if ((num_nodes
= md_node_count(mdp
)) <= 0) {
1167 cmn_err(CE_NOTE
, "%s: invalid number of channel-endpoint nodes "
1168 "found (%d)", __func__
, num_nodes
);
1172 /* allocate space for node list */
1173 listsz
= num_nodes
* sizeof (mde_cookie_t
);
1174 listp
= kmem_alloc(listsz
, KM_SLEEP
);
1176 nchan
= md_scan_dag(mdp
, node
, md_find_name(mdp
, "channel-endpoint"),
1177 md_find_name(mdp
, "fwd"), listp
);
1180 cmn_err(CE_NOTE
, "%s: no channel-endpoint nodes found",
1182 kmem_free(listp
, listsz
);
1186 DS_DBG_VLDS(CE_NOTE
, "%s: %d channel-endpoint nodes found", __func__
,
1189 /* use property from first node found */
1190 if (md_get_prop_val(mdp
, listp
[0], "id", ldc_id
)) {
1191 cmn_err(CE_NOTE
, "%s: channel-endpoint has no 'id' property",
1193 kmem_free(listp
, listsz
);
1197 kmem_free(listp
, listsz
);
1202 /* add a DS services port */
1204 vlds_add_mdeg_port(md_t
*mdp
, mde_cookie_t node
)
1212 /* read in the port's id property */
1213 if (md_get_prop_val(mdp
, node
, "id", &portno
)) {
1214 cmn_err(CE_NOTE
, "%s: node 0x%lx of added list has no "
1215 "'id' property", __func__
, node
);
1216 return (MDEG_FAILURE
);
1219 if (portno
>= DS_MAX_PORTS
) {
1220 cmn_err(CE_NOTE
, "%s: found port number (%lu) "
1221 "larger than maximum supported number of ports", __func__
,
1223 return (MDEG_FAILURE
);
1226 /* get all channels for this device (currently only one) */
1227 if (vlds_get_port_channel(mdp
, node
, &ldc_id
) == -1) {
1228 return (MDEG_FAILURE
);
1231 if (md_get_prop_val(mdp
, node
, VLDS_MD_REM_DOMAIN_HDL
, &dhdl
) != 0) {
1232 cmn_err(CE_NOTE
, "!ds%lx: %s no %s property", portno
, __func__
,
1233 VLDS_MD_REM_DOMAIN_HDL
);
1234 dhdl
= DS_DHDL_INVALID
;
1237 if (md_get_prop_str(mdp
, node
, VLDS_MD_REM_DOMAIN_NAME
, &dom_name
)
1239 cmn_err(CE_NOTE
, "!ds%lx: %s no %s property", portno
, __func__
,
1240 VLDS_MD_REM_DOMAIN_NAME
);
1244 rv
= ds_add_port(portno
, ldc_id
, dhdl
, dom_name
, vlds_ports_inited
);
1247 if (vlds_ports_inited
) {
1248 DS_DBG_VLDS(CE_NOTE
, "ds%lx: %s LDC chan: %lx "
1249 "failed err = %d", portno
, __func__
, ldc_id
, rv
);
1251 return (MDEG_FAILURE
);
1254 DS_DBG_VLDS(CE_NOTE
, "ds%lx: %s LDC chan: %lx inited", portno
,
1257 return (MDEG_SUCCESS
);
1261 vlds_mdeg_init(void)
1266 mde_cookie_t rootnode
;
1267 mde_cookie_t vldsnode
;
1268 mde_cookie_t
*vlds_nodes
= NULL
;
1271 ds_domain_hdl_t dhdl
;
1275 if ((mdp
= md_get_handle()) == NULL
) {
1276 cmn_err(CE_NOTE
, "Unable to initialize machine description");
1280 num_nodes
= md_node_count(mdp
);
1281 ASSERT(num_nodes
> 0);
1283 listsz
= num_nodes
* sizeof (mde_cookie_t
);
1285 /* allocate temporary storage for MD scans */
1286 vlds_nodes
= kmem_zalloc(listsz
, KM_SLEEP
);
1288 rootnode
= md_root_node(mdp
);
1289 ASSERT(rootnode
!= MDE_INVAL_ELEM_COOKIE
);
1292 * Search for Virtual Domain Service node.
1294 nvlds
= md_scan_dag(mdp
, rootnode
, md_find_name(mdp
,
1295 VLDS_MD_VIRT_DEV_NAME
), md_find_name(mdp
, "fwd"), vlds_nodes
);
1298 DS_DBG_MD(CE_NOTE
, "No '%s' nodes in MD",
1299 VLDS_MD_VIRT_DEV_NAME
);
1303 for (i
= 0; i
< nvlds
; i
++) {
1304 if (md_get_prop_str(mdp
, vlds_nodes
[i
], "name", &svc_name
)) {
1305 DS_DBG_MD(CE_NOTE
, "%s: missing 'name' property for"
1306 " IO node %d\n", __func__
, i
);
1310 if (strcmp(svc_name
, VLDS_MD_VIRT_ROOT_NAME
) == 0) {
1311 vldsnode
= vlds_nodes
[i
];
1317 DS_DBG_MD(CE_NOTE
, "No '%s' node in MD",
1318 VLDS_MD_VIRT_ROOT_NAME
);
1322 if (md_get_prop_val(mdp
, vldsnode
, VLDS_MD_DOMAIN_HDL
, &dhdl
) != 0) {
1323 DS_DBG_MD(CE_NOTE
, "No '%s' property for '%s' node in MD",
1324 VLDS_MD_DOMAIN_HDL
, VLDS_MD_VIRT_ROOT_NAME
);
1325 dhdl
= DS_DHDL_INVALID
;
1327 if (md_get_prop_str(mdp
, vldsnode
, VLDS_MD_DOMAIN_NAME
, &dom_name
)
1329 DS_DBG_MD(CE_NOTE
, "No '%s' property for '%s' node in MD",
1330 VLDS_MD_DOMAIN_NAME
, VLDS_MD_VIRT_ROOT_NAME
);
1333 DS_DBG_MD(CE_NOTE
, "My Domain Hdl: 0x%lx, Name: '%s'", dhdl
,
1334 dom_name
== NULL
? "NULL" : dom_name
);
1335 ds_set_my_dom_hdl_name(dhdl
, dom_name
);
1338 DS_FREE(vlds_nodes
, listsz
);
1340 (void) md_fini_handle(mdp
);
1344 vlds_user_reg_cb(ds_cb_arg_t arg
, ds_ver_t
*ver
, ds_svc_hdl_t hdl
)
1346 nvlist_t
*nvl
= NULL
;
1347 ds_domain_hdl_t dhdl
;
1352 vlds_svc_info_t
*dpsp
;
1354 ds_cbarg_get_flags(arg
, &flags
);
1355 ASSERT((flags
& DSSF_ISUSER
) != 0);
1357 if ((flags
& DSSF_DATACB_VALID
) == 0) {
1359 * must allocate and init the svc read queue.
1361 DS_DBG_VLDS(CE_NOTE
, "%s: hdl: 0x%lx initing recvq", __func__
,
1363 dpsp
= DS_MALLOC(sizeof (vlds_svc_info_t
));
1364 vlds_recvq_init(dpsp
);
1365 ds_cbarg_set_drv_per_svc_ptr(arg
, dpsp
);
1368 if ((flags
& DSSF_REGCB_VALID
) != 0) {
1369 ds_cbarg_get_drv_info(arg
, &minor
);
1370 sp
= ddi_get_soft_state(vlds_statep
, minor
);
1372 ASSERT(sp
->evchan
!= NULL
);
1373 ds_cbarg_get_domain(arg
, &dhdl
);
1374 ds_cbarg_get_service_id(arg
, &servicep
);
1375 DS_DBG_VLDS(CE_NOTE
, "%s: regcb: hdl: 0x%lx, ver%d.%d, "
1376 " dhdl: 0x%lx", __func__
, hdl
, ver
->major
,
1378 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
) ||
1379 nvlist_add_uint64(nvl
, VLDS_HDL
, hdl
) ||
1380 nvlist_add_uint16(nvl
, VLDS_VER_MAJOR
, ver
->major
) ||
1381 nvlist_add_uint16(nvl
, VLDS_VER_MINOR
, ver
->minor
) ||
1382 nvlist_add_uint64(nvl
, VLDS_DOMAIN_HDL
, dhdl
) ||
1383 nvlist_add_string(nvl
, VLDS_SERVICE_ID
, servicep
) ||
1384 nvlist_add_boolean_value(nvl
, VLDS_ISCLIENT
,
1385 (flags
& DSSF_ISCLIENT
) != 0) ||
1386 sysevent_evc_publish(sp
->evchan
, EC_VLDS
,
1387 ESC_VLDS_REGISTER
, "sun.com", "kernel", nvl
, EVCH_SLEEP
)) {
1388 cmn_err(CE_WARN
, "Failed to send REG Callback");
1390 DS_DBG_VLDS(CE_NOTE
, "%s: sysevent_evc_publish "
1391 "succeeded", __func__
);
1398 vlds_user_unreg_cb(ds_cb_arg_t arg
)
1400 nvlist_t
*nvl
= NULL
;
1407 ds_cbarg_get_flags(arg
, &flags
);
1408 ASSERT((flags
& DSSF_ISUSER
) != 0);
1410 if ((flags
& DSSF_DATACB_VALID
) == 0) {
1411 ds_cbarg_get_drv_per_svc_ptr(arg
, &dpsp
);
1413 DS_DBG_VLDS(CE_NOTE
, "%s: unregcb draining recvq",
1415 vlds_recvq_drain(dpsp
);
1416 vlds_recvq_destroy(dpsp
);
1417 ds_cbarg_set_drv_per_svc_ptr(arg
, NULL
);
1421 if ((flags
& DSSF_UNREGCB_VALID
) != 0) {
1422 ds_cbarg_get_hdl(arg
, &hdl
);
1423 DS_DBG_VLDS(CE_NOTE
, "%s: unregcb hdl: 0x%lx", __func__
,
1425 ds_cbarg_get_drv_info(arg
, &minor
);
1426 sp
= ddi_get_soft_state(vlds_statep
, minor
);
1428 ASSERT(sp
->evchan
!= NULL
);
1429 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
) ||
1430 nvlist_add_uint64(nvl
, VLDS_HDL
, hdl
) ||
1431 sysevent_evc_publish(sp
->evchan
, EC_VLDS
,
1432 ESC_VLDS_UNREGISTER
, "sun.com", "kernel", nvl
,
1434 cmn_err(CE_WARN
, "Failed to send UNREG Callback");
1441 vlds_user_data_cb(ds_cb_arg_t arg
, void *buf
, size_t buflen
)
1443 nvlist_t
*nvl
= NULL
;
1450 ds_cbarg_get_flags(arg
, &flags
);
1451 ASSERT((flags
& DSSF_ISUSER
) != 0);
1453 if ((flags
& DSSF_DATACB_VALID
) == 0) {
1454 ds_cbarg_get_drv_per_svc_ptr(arg
, &dpsp
);
1455 ASSERT(dpsp
!= NULL
);
1456 DS_DBG_VLDS(CE_NOTE
, "%s: datacb: to recvq: buflen: %ld",
1458 (void) vlds_recvq_put_data(dpsp
, buf
, buflen
);
1460 ds_cbarg_get_hdl(arg
, &hdl
);
1461 DS_DBG_VLDS(CE_NOTE
, "%s: datacb: usercb: hdl: 0x%lx, "
1462 " buflen: %ld", __func__
, hdl
, buflen
);
1463 ds_cbarg_get_drv_info(arg
, &minor
);
1464 sp
= ddi_get_soft_state(vlds_statep
, minor
);
1466 ASSERT(sp
->evchan
!= NULL
);
1467 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
) ||
1468 nvlist_add_uint64(nvl
, VLDS_HDL
, hdl
) ||
1469 nvlist_add_byte_array(nvl
, VLDS_DATA
, buf
, buflen
) ||
1470 sysevent_evc_publish(sp
->evchan
, EC_VLDS
,
1471 ESC_VLDS_DATA
, "sun.com", "kernel", nvl
, EVCH_SLEEP
)) {
1472 cmn_err(CE_WARN
, "Failed to send DATA Callback");
1479 * Initialize receive queue if request is from user land but
1480 * data callback is null (implying user will be using ds_recv_msg).
1483 vlds_recvq_init(vlds_svc_info_t
*dpsp
)
1485 dpsp
->state
= VLDS_RECV_OK
;
1486 mutex_init(&dpsp
->recv_lock
, NULL
, MUTEX_DRIVER
, NULL
);
1487 cv_init(&dpsp
->recv_cv
, NULL
, CV_DRIVER
, NULL
);
1488 dpsp
->recv_headp
= NULL
;
1489 dpsp
->recv_tailp
= NULL
;
1490 dpsp
->recv_size
= 0;
1495 vlds_recvq_destroy(vlds_svc_info_t
*dpsp
)
1497 ASSERT(dpsp
->state
== VLDS_RECV_UNREG_PENDING
);
1498 ASSERT(dpsp
->recv_size
== 0);
1499 ASSERT(dpsp
->recv_cnt
== 0);
1500 ASSERT(dpsp
->recv_headp
== NULL
);
1501 ASSERT(dpsp
->recv_tailp
== NULL
);
1503 mutex_destroy(&dpsp
->recv_lock
);
1504 cv_destroy(&dpsp
->recv_cv
);
1505 DS_FREE(dpsp
, sizeof (vlds_svc_info_t
));
1509 vlds_recvq_get_data(vlds_svc_info_t
*dpsp
, void *buf
, size_t buflen
,
1510 size_t *msglenp
, int mode
)
1512 vlds_recv_hdr_t
*rhp
;
1516 mutex_enter(&dpsp
->recv_lock
);
1517 while (dpsp
->recv_size
== 0) {
1518 ASSERT(dpsp
->recv_cnt
== 0);
1519 if (dpsp
->state
== VLDS_RECV_UNREG_PENDING
)
1522 if (dpsp
->state
== VLDS_RECV_OVERFLOW
) {
1523 DS_DBG_RCVQ(CE_NOTE
, "%s: user data queue overflow",
1525 dpsp
->state
= VLDS_RECV_OK
;
1526 mutex_exit(&dpsp
->recv_lock
);
1530 * Passing in a buflen of 0 allows user to poll for msgs.
1533 mutex_exit(&dpsp
->recv_lock
);
1537 dpsp
->recv_nreaders
+= 1;
1538 rv
= cv_wait_sig(&dpsp
->recv_cv
, &dpsp
->recv_lock
);
1539 dpsp
->recv_nreaders
-= 1;
1541 DS_DBG_RCVQ(CE_NOTE
, "%s: signal EINTR", __func__
);
1542 mutex_exit(&dpsp
->recv_lock
);
1546 if (dpsp
->state
== VLDS_RECV_UNREG_PENDING
) {
1547 DS_DBG_RCVQ(CE_NOTE
, "%s: unreg pending", __func__
);
1548 cv_broadcast(&dpsp
->recv_cv
);
1549 mutex_exit(&dpsp
->recv_lock
);
1552 ASSERT(dpsp
->recv_headp
!= NULL
);
1553 rhp
= dpsp
->recv_headp
;
1556 * Don't transfer truncated data, return EFBIG error if user-supplied
1557 * buffer is too small.
1559 if (rhp
->datasz
> buflen
) {
1560 *msglenp
= rhp
->datasz
;
1561 mutex_exit(&dpsp
->recv_lock
);
1564 if (rhp
== dpsp
->recv_tailp
) {
1565 dpsp
->recv_headp
= NULL
;
1566 dpsp
->recv_tailp
= NULL
;
1568 dpsp
->recv_headp
= rhp
->next
;
1569 ASSERT(dpsp
->recv_headp
!= NULL
);
1571 ASSERT(dpsp
->recv_cnt
> 0);
1572 dpsp
->recv_size
-= rhp
->datasz
;
1573 dpsp
->recv_cnt
-= 1;
1574 mutex_exit(&dpsp
->recv_lock
);
1576 msglen
= rhp
->datasz
;
1577 rv
= ddi_copyout(rhp
->data
, buf
, msglen
, mode
);
1580 DS_DBG_VLDS(CE_NOTE
, "%s: user data dequeued msglen: %ld",
1581 __func__
, rhp
->datasz
);
1582 DS_DUMP_MSG(DS_DBG_FLAG_VLDS
, rhp
->data
, rhp
->datasz
);
1585 DS_FREE(rhp
->data
, rhp
->datasz
);
1586 DS_FREE(rhp
, sizeof (vlds_recv_hdr_t
));
1589 DS_DBG_VLDS(CE_NOTE
, "%s: copyout failed", __func__
);
1597 uint64_t vlds_recv_drain_delay_time
= 1 * MILLISEC
;
1600 vlds_recvq_drain(vlds_svc_info_t
*dpsp
)
1602 vlds_recv_hdr_t
*rhp
, *nextp
;
1604 mutex_enter(&dpsp
->recv_lock
);
1605 dpsp
->state
= VLDS_RECV_UNREG_PENDING
;
1606 for (rhp
= dpsp
->recv_tailp
; rhp
!= NULL
; rhp
= nextp
) {
1608 DS_FREE(rhp
->data
, rhp
->datasz
);
1609 DS_FREE(rhp
, sizeof (vlds_recv_hdr_t
));
1611 dpsp
->recv_headp
= NULL
;
1612 dpsp
->recv_tailp
= NULL
;
1613 dpsp
->recv_size
= 0;
1617 * Make sure other readers have exited.
1619 while (dpsp
->recv_nreaders
> 0) {
1620 cv_broadcast(&dpsp
->recv_cv
);
1621 mutex_exit(&dpsp
->recv_lock
);
1622 delay(vlds_recv_drain_delay_time
);
1623 mutex_enter(&dpsp
->recv_lock
);
1626 mutex_exit(&dpsp
->recv_lock
);
1630 vlds_recvq_put_data(vlds_svc_info_t
*dpsp
, void *buf
, size_t buflen
)
1632 vlds_recv_hdr_t
*rhp
;
1634 mutex_enter(&dpsp
->recv_lock
);
1635 if (dpsp
->state
!= VLDS_RECV_UNREG_PENDING
) {
1637 * If we've already encountered an overflow, or there
1638 * are pending messages and either queue size and
1639 * message limits will be exceeded with this message,
1640 * we mark the recvq as overflowed and return an ENOBUFS
1641 * error. This allows the enqueuing of one big message
1642 * or several little messages.
1644 if ((dpsp
->state
== VLDS_RECV_OVERFLOW
) ||
1645 ((dpsp
->recv_cnt
!= 0) &&
1646 ((dpsp
->recv_size
+ buflen
) > vlds_recvq_maxsize
) ||
1647 ((dpsp
->recv_cnt
+ 1) > vlds_recvq_maxmsg
))) {
1648 DS_DBG_RCVQ(CE_NOTE
, "%s: user data queue overflow",
1650 dpsp
->state
= VLDS_RECV_OVERFLOW
;
1651 cv_broadcast(&dpsp
->recv_cv
);
1652 mutex_exit(&dpsp
->recv_lock
);
1656 DS_DBG_RCVQ(CE_NOTE
, "%s: user data enqueued msglen: %ld",
1658 DS_DUMP_MSG(DS_DBG_FLAG_RCVQ
, buf
, buflen
);
1659 rhp
= DS_MALLOC(sizeof (vlds_recv_hdr_t
));
1660 rhp
->data
= DS_MALLOC(buflen
);
1661 (void) memcpy(rhp
->data
, buf
, buflen
);
1662 rhp
->datasz
= buflen
;
1664 if (dpsp
->recv_headp
== NULL
) {
1665 dpsp
->recv_headp
= rhp
;
1666 dpsp
->recv_tailp
= rhp
;
1668 dpsp
->recv_tailp
->next
= rhp
;
1669 dpsp
->recv_tailp
= rhp
;
1671 dpsp
->recv_size
+= rhp
->datasz
;
1672 dpsp
->recv_cnt
+= 1;
1673 cv_broadcast(&dpsp
->recv_cv
);
1675 mutex_exit(&dpsp
->recv_lock
);
1680 vlds_recv_msg(ds_svc_hdl_t hdl
, void *buf
, size_t buflen
, size_t *msglenp
,
1688 if ((rv
= ds_hdl_get_cbarg(hdl
, &cbarg
)) != 0) {
1689 DS_DBG_VLDS(CE_NOTE
, "%s: handle %lx not found (%d)", __func__
,
1693 ds_cbarg_get_flags(cbarg
, &flags
);
1694 if ((flags
& DSSF_ISUSER
) == 0 || (flags
& DSSF_DATACB_VALID
) != 0) {
1695 DS_DBG_VLDS(CE_NOTE
, "%s: invalid flags: %x", __func__
, flags
);
1698 ds_cbarg_get_drv_per_svc_ptr(cbarg
, &dpsp
);
1700 DS_DBG_VLDS(CE_NOTE
, "%s: recv on non-ready handle: %x",
1704 rv
= vlds_recvq_get_data(dpsp
, buf
, buflen
, msglenp
, mode
);