1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/types.h>
28#include <sys/door.h>
29#include <sys/note.h>
30#include <sys/drctl.h>
31#include <sys/drctl_impl.h>
32#include <sys/ddi.h>
33#include <sys/sunddi.h>
34#include <sys/dr_util.h>
35
36static door_handle_t drctl_dh;	/* Door for upcalls */
37
38
39int
40i_drctl_ioctl(int cmd, intptr_t arg)
41{
42	int rv;
43	drctl_setup_t setup_rqst;
44
45	switch (cmd) {
46	case DRCTL_IOCTL_CONNECT_SERVER:
47		if (ddi_copyin((caddr_t)arg,
48		    &setup_rqst, sizeof (setup_rqst), 0) != 0) {
49			cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed "
50			    "for DRCTL_IOCTL_CONNECT_SERVER");
51			rv = EFAULT;
52			break;
53		}
54
55		drctl_dh = door_ki_lookup(setup_rqst.did);
56		rv = 0;
57		break;
58
59	default:
60		rv = EIO;
61	}
62
63	return (rv);
64}
65
66int
67i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize)
68{
69	int up_err;
70	int rv = 0;
71	door_arg_t door_args;
72	door_handle_t dh = drctl_dh;
73	static const char me[] = "i_drctl_send";
74
75retry:
76	if (dh)
77		door_ki_hold(dh);
78	else
79		return (EIO);
80
81	door_args.data_ptr = (char *)msg;
82	door_args.data_size = size;
83	door_args.desc_ptr = NULL;
84	door_args.desc_num = 0;
85
86	/*
87	 * We don't know the size of the message the daemon
88	 * will pass back to us.  By setting rbuf to NULL,
89	 * we force the door code to allocate a buf of the
90	 * appropriate size.  We must set rsize > 0, however,
91	 * else the door code acts as if no response was
92	 * expected and doesn't pass the data to us.
93	 */
94	door_args.rbuf = NULL;
95	door_args.rsize = 1;
96	DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n",
97	    me, msg, size, (void *)obufp, (void *)osize);
98
99	up_err = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
100	if (up_err == 0) {
101		if (door_args.rbuf == NULL)
102			goto done;
103
104		DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me,
105		    (void *)door_args.rbuf, door_args.rsize);
106
107		if (obufp != NULL) {
108			*obufp = door_args.rbuf;
109			*osize = door_args.rsize;
110			DR_DBG_KMEM("%s: (door) alloc addr %p size %ld\n",
111			    __func__,
112			    (void *)(door_args.rbuf), door_args.rsize);
113		} else {
114			/*
115			 * No output buffer pointer was passed in,
116			 * so the response buffer allocated by the
117			 * door code must be deallocated.
118			 */
119			DR_DBG_KMEM("%s: free addr %p size %ld\n", __func__,
120			    (void *)(door_args.rbuf), door_args.rsize);
121			kmem_free(door_args.rbuf, door_args.rsize);
122		}
123	} else {
124		switch (up_err) {
125		case EINTR:
126			DR_DBG_CTL("%s: door call returned EINTR\n", me);
127			_NOTE(FALLTHROUGH)
128		case EAGAIN:
129			/*
130			 * Server process may be forking, try again.
131			 */
132			door_ki_rele(dh);
133			delay(hz);
134			goto retry;
135		case EBADF:
136		case EINVAL:
137			drctl_dh = NULL;
138			DR_DBG_CTL(
139			    "%s: door call failed with %d\n", me, up_err);
140			rv = EIO;
141			break;
142		default:
143			DR_DBG_CTL("%s: unexpected return "
144			    "code %d from door_ki_upcall\n", me, up_err);
145			rv = EIO;
146			break;
147		}
148	}
149
150done:
151	door_ki_rele(dh);
152	return (rv);
153}
154