12309Srsmaeda /*
22309Srsmaeda * CDDL HEADER START
32309Srsmaeda *
42309Srsmaeda * The contents of this file are subject to the terms of the
52309Srsmaeda * Common Development and Distribution License (the "License").
62309Srsmaeda * You may not use this file except in compliance with the License.
72309Srsmaeda *
82309Srsmaeda * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92309Srsmaeda * or http://www.opensolaris.org/os/licensing.
102309Srsmaeda * See the License for the specific language governing permissions
112309Srsmaeda * and limitations under the License.
122309Srsmaeda *
132309Srsmaeda * When distributing Covered Code, include this CDDL HEADER in each
142309Srsmaeda * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152309Srsmaeda * If applicable, add the following below this CDDL HEADER, with the
162309Srsmaeda * fields enclosed by brackets "[]" replaced with your own identifying
172309Srsmaeda * information: Portions Copyright [yyyy] [name of copyright owner]
182309Srsmaeda *
192309Srsmaeda * CDDL HEADER END
202309Srsmaeda */
212309Srsmaeda
222309Srsmaeda /*
236997Sjwadams * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
242309Srsmaeda * Use is subject to license terms.
252309Srsmaeda */
262309Srsmaeda
272309Srsmaeda #include <sys/types.h>
282309Srsmaeda #include <sys/door.h>
292309Srsmaeda #include <sys/note.h>
302309Srsmaeda #include <sys/drctl.h>
312309Srsmaeda #include <sys/drctl_impl.h>
322309Srsmaeda #include <sys/ddi.h>
332309Srsmaeda #include <sys/sunddi.h>
342309Srsmaeda #include <sys/dr_util.h>
352309Srsmaeda
362309Srsmaeda static door_handle_t drctl_dh; /* Door for upcalls */
372309Srsmaeda
382309Srsmaeda
392309Srsmaeda int
i_drctl_ioctl(int cmd,intptr_t arg)402309Srsmaeda i_drctl_ioctl(int cmd, intptr_t arg)
412309Srsmaeda {
422309Srsmaeda int rv;
432309Srsmaeda drctl_setup_t setup_rqst;
442309Srsmaeda
452309Srsmaeda switch (cmd) {
462309Srsmaeda case DRCTL_IOCTL_CONNECT_SERVER:
472309Srsmaeda if (ddi_copyin((caddr_t)arg,
482309Srsmaeda &setup_rqst, sizeof (setup_rqst), 0) != 0) {
492309Srsmaeda cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed "
502309Srsmaeda "for DRCTL_IOCTL_CONNECT_SERVER");
512309Srsmaeda rv = EFAULT;
522309Srsmaeda break;
532309Srsmaeda }
542309Srsmaeda
552309Srsmaeda drctl_dh = door_ki_lookup(setup_rqst.did);
562309Srsmaeda rv = 0;
572309Srsmaeda break;
582309Srsmaeda
592309Srsmaeda default:
602309Srsmaeda rv = EIO;
612309Srsmaeda }
622309Srsmaeda
632309Srsmaeda return (rv);
642309Srsmaeda }
652309Srsmaeda
662309Srsmaeda int
i_drctl_send(void * msg,size_t size,void ** obufp,size_t * osize)672309Srsmaeda i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize)
682309Srsmaeda {
692309Srsmaeda int up_err;
702309Srsmaeda int rv = 0;
712309Srsmaeda door_arg_t door_args;
722309Srsmaeda door_handle_t dh = drctl_dh;
732309Srsmaeda static const char me[] = "i_drctl_send";
742309Srsmaeda
752309Srsmaeda retry:
762309Srsmaeda if (dh)
772309Srsmaeda door_ki_hold(dh);
782309Srsmaeda else
792309Srsmaeda return (EIO);
802309Srsmaeda
812309Srsmaeda door_args.data_ptr = (char *)msg;
822309Srsmaeda door_args.data_size = size;
832309Srsmaeda door_args.desc_ptr = NULL;
842309Srsmaeda door_args.desc_num = 0;
852309Srsmaeda
862309Srsmaeda /*
872309Srsmaeda * We don't know the size of the message the daemon
882309Srsmaeda * will pass back to us. By setting rbuf to NULL,
892309Srsmaeda * we force the door code to allocate a buf of the
902309Srsmaeda * appropriate size. We must set rsize > 0, however,
912309Srsmaeda * else the door code acts as if no response was
922309Srsmaeda * expected and doesn't pass the data to us.
932309Srsmaeda */
942309Srsmaeda door_args.rbuf = NULL;
952309Srsmaeda door_args.rsize = 1;
962309Srsmaeda DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n",
972309Srsmaeda me, msg, size, (void *)obufp, (void *)osize);
982309Srsmaeda
996997Sjwadams up_err = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
1002309Srsmaeda if (up_err == 0) {
1013414Srsmaeda if (door_args.rbuf == NULL)
1023414Srsmaeda goto done;
1033414Srsmaeda
1043414Srsmaeda DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me,
1053414Srsmaeda (void *)door_args.rbuf, door_args.rsize);
1063414Srsmaeda
1073414Srsmaeda if (obufp != NULL) {
1082309Srsmaeda *obufp = door_args.rbuf;
1092309Srsmaeda *osize = door_args.rsize;
110*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: (door) alloc addr %p size %ld\n",
111*7899SJames.Marks@Sun.COM __func__,
112*7899SJames.Marks@Sun.COM (void *)(door_args.rbuf), door_args.rsize);
1133414Srsmaeda } else {
1143414Srsmaeda /*
1153414Srsmaeda * No output buffer pointer was passed in,
1163414Srsmaeda * so the response buffer allocated by the
1173414Srsmaeda * door code must be deallocated.
1183414Srsmaeda */
119*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n", __func__,
120*7899SJames.Marks@Sun.COM (void *)(door_args.rbuf), door_args.rsize);
1213414Srsmaeda kmem_free(door_args.rbuf, door_args.rsize);
1222309Srsmaeda }
1232309Srsmaeda } else {
1242309Srsmaeda switch (up_err) {
1252309Srsmaeda case EINTR:
1262309Srsmaeda DR_DBG_CTL("%s: door call returned EINTR\n", me);
1272309Srsmaeda _NOTE(FALLTHROUGH)
1282309Srsmaeda case EAGAIN:
1292309Srsmaeda /*
1302309Srsmaeda * Server process may be forking, try again.
1312309Srsmaeda */
1322309Srsmaeda door_ki_rele(dh);
1332309Srsmaeda delay(hz);
1342309Srsmaeda goto retry;
1352309Srsmaeda case EBADF:
1362309Srsmaeda case EINVAL:
1372309Srsmaeda drctl_dh = NULL;
1382309Srsmaeda DR_DBG_CTL(
1392309Srsmaeda "%s: door call failed with %d\n", me, up_err);
1402309Srsmaeda rv = EIO;
1412309Srsmaeda break;
1422309Srsmaeda default:
1432309Srsmaeda DR_DBG_CTL("%s: unexpected return "
1442309Srsmaeda "code %d from door_ki_upcall\n", me, up_err);
1452309Srsmaeda rv = EIO;
1462309Srsmaeda break;
1472309Srsmaeda }
1482309Srsmaeda }
1492309Srsmaeda
1503414Srsmaeda done:
1512309Srsmaeda door_ki_rele(dh);
1522309Srsmaeda return (rv);
1532309Srsmaeda }
154