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 36 static door_handle_t drctl_dh; /* Door for upcalls */ 37 38 39 int 40 i_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 66 int 67 i_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 75 retry: 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 150 done: 151 door_ki_rele(dh); 152 return (rv); 153 } 154