xref: /onnv-gate/usr/src/uts/sun4v/io/drctl_impl.c (revision 3414:ff9ba99c65c7)
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 /*
23*3414Srsmaeda  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
242309Srsmaeda  * Use is subject to license terms.
252309Srsmaeda  */
262309Srsmaeda 
272309Srsmaeda #pragma ident	"%Z%%M%	%I%	%E% SMI"
282309Srsmaeda 
292309Srsmaeda #include <sys/types.h>
302309Srsmaeda #include <sys/door.h>
312309Srsmaeda #include <sys/note.h>
322309Srsmaeda #include <sys/drctl.h>
332309Srsmaeda #include <sys/drctl_impl.h>
342309Srsmaeda #include <sys/ddi.h>
352309Srsmaeda #include <sys/sunddi.h>
362309Srsmaeda #include <sys/dr_util.h>
372309Srsmaeda 
382309Srsmaeda static door_handle_t drctl_dh;	/* Door for upcalls */
392309Srsmaeda 
402309Srsmaeda 
412309Srsmaeda int
422309Srsmaeda i_drctl_ioctl(int cmd, intptr_t arg)
432309Srsmaeda {
442309Srsmaeda 	int rv;
452309Srsmaeda 	drctl_setup_t setup_rqst;
462309Srsmaeda 
472309Srsmaeda 	switch (cmd) {
482309Srsmaeda 	case DRCTL_IOCTL_CONNECT_SERVER:
492309Srsmaeda 		if (ddi_copyin((caddr_t)arg,
502309Srsmaeda 		    &setup_rqst, sizeof (setup_rqst), 0) != 0) {
512309Srsmaeda 			cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed "
522309Srsmaeda 			    "for DRCTL_IOCTL_CONNECT_SERVER");
532309Srsmaeda 			rv = EFAULT;
542309Srsmaeda 			break;
552309Srsmaeda 		}
562309Srsmaeda 
572309Srsmaeda 		drctl_dh = door_ki_lookup(setup_rqst.did);
582309Srsmaeda 		rv = 0;
592309Srsmaeda 		break;
602309Srsmaeda 
612309Srsmaeda 	default:
622309Srsmaeda 		rv = EIO;
632309Srsmaeda 	}
642309Srsmaeda 
652309Srsmaeda 	return (rv);
662309Srsmaeda }
672309Srsmaeda 
682309Srsmaeda int
692309Srsmaeda i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize)
702309Srsmaeda {
712309Srsmaeda 	int up_err;
722309Srsmaeda 	int rv = 0;
732309Srsmaeda 	door_arg_t door_args;
742309Srsmaeda 	door_handle_t dh = drctl_dh;
752309Srsmaeda 	static const char me[] = "i_drctl_send";
762309Srsmaeda 
772309Srsmaeda retry:
782309Srsmaeda 	if (dh)
792309Srsmaeda 		door_ki_hold(dh);
802309Srsmaeda 	else
812309Srsmaeda 		return (EIO);
822309Srsmaeda 
832309Srsmaeda 	door_args.data_ptr = (char *)msg;
842309Srsmaeda 	door_args.data_size = size;
852309Srsmaeda 	door_args.desc_ptr = NULL;
862309Srsmaeda 	door_args.desc_num = 0;
872309Srsmaeda 
882309Srsmaeda 	/*
892309Srsmaeda 	 * We don't know the size of the message the daemon
902309Srsmaeda 	 * will pass back to us.  By setting rbuf to NULL,
912309Srsmaeda 	 * we force the door code to allocate a buf of the
922309Srsmaeda 	 * appropriate size.  We must set rsize > 0, however,
932309Srsmaeda 	 * else the door code acts as if no response was
942309Srsmaeda 	 * expected and doesn't pass the data to us.
952309Srsmaeda 	 */
962309Srsmaeda 	door_args.rbuf = NULL;
972309Srsmaeda 	door_args.rsize = 1;
982309Srsmaeda 	DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n",
992309Srsmaeda 	    me, msg, size, (void *)obufp, (void *)osize);
1002309Srsmaeda 
1012309Srsmaeda 	up_err = door_ki_upcall(dh, &door_args);
1022309Srsmaeda 	if (up_err == 0) {
103*3414Srsmaeda 		if (door_args.rbuf == NULL)
104*3414Srsmaeda 			goto done;
105*3414Srsmaeda 
106*3414Srsmaeda 		DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me,
107*3414Srsmaeda 		    (void *)door_args.rbuf, door_args.rsize);
108*3414Srsmaeda 
109*3414Srsmaeda 		if (obufp != NULL) {
1102309Srsmaeda 			*obufp = door_args.rbuf;
1112309Srsmaeda 			*osize = door_args.rsize;
112*3414Srsmaeda 		} else {
113*3414Srsmaeda 			/*
114*3414Srsmaeda 			 * No output buffer pointer was passed in,
115*3414Srsmaeda 			 * so the response buffer allocated by the
116*3414Srsmaeda 			 * door code must be deallocated.
117*3414Srsmaeda 			 */
118*3414Srsmaeda 			kmem_free(door_args.rbuf, door_args.rsize);
1192309Srsmaeda 		}
1202309Srsmaeda 	} else {
1212309Srsmaeda 		switch (up_err) {
1222309Srsmaeda 		case EINTR:
1232309Srsmaeda 			DR_DBG_CTL("%s: door call returned EINTR\n", me);
1242309Srsmaeda 			_NOTE(FALLTHROUGH)
1252309Srsmaeda 		case EAGAIN:
1262309Srsmaeda 			/*
1272309Srsmaeda 			 * Server process may be forking, try again.
1282309Srsmaeda 			 */
1292309Srsmaeda 			door_ki_rele(dh);
1302309Srsmaeda 			delay(hz);
1312309Srsmaeda 			goto retry;
1322309Srsmaeda 		case EBADF:
1332309Srsmaeda 		case EINVAL:
1342309Srsmaeda 			drctl_dh = NULL;
1352309Srsmaeda 			DR_DBG_CTL(
1362309Srsmaeda 			    "%s: door call failed with %d\n", me, up_err);
1372309Srsmaeda 			rv = EIO;
1382309Srsmaeda 			break;
1392309Srsmaeda 		default:
1402309Srsmaeda 			DR_DBG_CTL("%s: unexpected return "
1412309Srsmaeda 			    "code %d from door_ki_upcall\n", me, up_err);
1422309Srsmaeda 			rv = EIO;
1432309Srsmaeda 			break;
1442309Srsmaeda 		}
1452309Srsmaeda 	}
1462309Srsmaeda 
147*3414Srsmaeda done:
1482309Srsmaeda 	door_ki_rele(dh);
1492309Srsmaeda 	return (rv);
1502309Srsmaeda }
151