xref: /titanic_52/usr/src/uts/sun4v/io/drctl_impl.c (revision c40d696f8f0e05103b3795dd37198e00ae7ef955)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/door.h>
31 #include <sys/note.h>
32 #include <sys/drctl.h>
33 #include <sys/drctl_impl.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/dr_util.h>
37 
38 static door_handle_t drctl_dh;	/* Door for upcalls */
39 
40 
41 int
42 i_drctl_ioctl(int cmd, intptr_t arg)
43 {
44 	int rv;
45 	drctl_setup_t setup_rqst;
46 
47 	switch (cmd) {
48 	case DRCTL_IOCTL_CONNECT_SERVER:
49 		if (ddi_copyin((caddr_t)arg,
50 		    &setup_rqst, sizeof (setup_rqst), 0) != 0) {
51 			cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed "
52 			    "for DRCTL_IOCTL_CONNECT_SERVER");
53 			rv = EFAULT;
54 			break;
55 		}
56 
57 		drctl_dh = door_ki_lookup(setup_rqst.did);
58 		rv = 0;
59 		break;
60 
61 	default:
62 		rv = EIO;
63 	}
64 
65 	return (rv);
66 }
67 
68 int
69 i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize)
70 {
71 	int up_err;
72 	int rv = 0;
73 	door_arg_t door_args;
74 	door_handle_t dh = drctl_dh;
75 	static const char me[] = "i_drctl_send";
76 
77 retry:
78 	if (dh)
79 		door_ki_hold(dh);
80 	else
81 		return (EIO);
82 
83 	door_args.data_ptr = (char *)msg;
84 	door_args.data_size = size;
85 	door_args.desc_ptr = NULL;
86 	door_args.desc_num = 0;
87 
88 	/*
89 	 * We don't know the size of the message the daemon
90 	 * will pass back to us.  By setting rbuf to NULL,
91 	 * we force the door code to allocate a buf of the
92 	 * appropriate size.  We must set rsize > 0, however,
93 	 * else the door code acts as if no response was
94 	 * expected and doesn't pass the data to us.
95 	 */
96 	door_args.rbuf = NULL;
97 	door_args.rsize = 1;
98 	DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n",
99 	    me, msg, size, (void *)obufp, (void *)osize);
100 
101 	up_err = door_ki_upcall(dh, &door_args);
102 	if (up_err == 0) {
103 		if (door_args.rbuf == NULL)
104 			goto done;
105 
106 		DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me,
107 		    (void *)door_args.rbuf, door_args.rsize);
108 
109 		if (obufp != NULL) {
110 			*obufp = door_args.rbuf;
111 			*osize = door_args.rsize;
112 		} else {
113 			/*
114 			 * No output buffer pointer was passed in,
115 			 * so the response buffer allocated by the
116 			 * door code must be deallocated.
117 			 */
118 			kmem_free(door_args.rbuf, door_args.rsize);
119 		}
120 	} else {
121 		switch (up_err) {
122 		case EINTR:
123 			DR_DBG_CTL("%s: door call returned EINTR\n", me);
124 			_NOTE(FALLTHROUGH)
125 		case EAGAIN:
126 			/*
127 			 * Server process may be forking, try again.
128 			 */
129 			door_ki_rele(dh);
130 			delay(hz);
131 			goto retry;
132 		case EBADF:
133 		case EINVAL:
134 			drctl_dh = NULL;
135 			DR_DBG_CTL(
136 			    "%s: door call failed with %d\n", me, up_err);
137 			rv = EIO;
138 			break;
139 		default:
140 			DR_DBG_CTL("%s: unexpected return "
141 			    "code %d from door_ki_upcall\n", me, up_err);
142 			rv = EIO;
143 			break;
144 		}
145 	}
146 
147 done:
148 	door_ki_rele(dh);
149 	return (rv);
150 }
151