xref: /illumos-gate/usr/src/uts/sun4v/io/drctl_impl.c (revision 88b620a7)
11d4b38e0Srsmaeda /*
21d4b38e0Srsmaeda  * CDDL HEADER START
31d4b38e0Srsmaeda  *
41d4b38e0Srsmaeda  * The contents of this file are subject to the terms of the
51d4b38e0Srsmaeda  * Common Development and Distribution License (the "License").
61d4b38e0Srsmaeda  * You may not use this file except in compliance with the License.
71d4b38e0Srsmaeda  *
81d4b38e0Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91d4b38e0Srsmaeda  * or http://www.opensolaris.org/os/licensing.
101d4b38e0Srsmaeda  * See the License for the specific language governing permissions
111d4b38e0Srsmaeda  * and limitations under the License.
121d4b38e0Srsmaeda  *
131d4b38e0Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
141d4b38e0Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151d4b38e0Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
161d4b38e0Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
171d4b38e0Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
181d4b38e0Srsmaeda  *
191d4b38e0Srsmaeda  * CDDL HEADER END
201d4b38e0Srsmaeda  */
211d4b38e0Srsmaeda 
221d4b38e0Srsmaeda /*
23323a81d9Sjwadams  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241d4b38e0Srsmaeda  * Use is subject to license terms.
251d4b38e0Srsmaeda  */
261d4b38e0Srsmaeda 
271d4b38e0Srsmaeda #include <sys/types.h>
281d4b38e0Srsmaeda #include <sys/door.h>
291d4b38e0Srsmaeda #include <sys/note.h>
301d4b38e0Srsmaeda #include <sys/drctl.h>
311d4b38e0Srsmaeda #include <sys/drctl_impl.h>
321d4b38e0Srsmaeda #include <sys/ddi.h>
331d4b38e0Srsmaeda #include <sys/sunddi.h>
341d4b38e0Srsmaeda #include <sys/dr_util.h>
351d4b38e0Srsmaeda 
361d4b38e0Srsmaeda static door_handle_t drctl_dh;	/* Door for upcalls */
371d4b38e0Srsmaeda 
381d4b38e0Srsmaeda 
391d4b38e0Srsmaeda int
i_drctl_ioctl(int cmd,intptr_t arg)401d4b38e0Srsmaeda i_drctl_ioctl(int cmd, intptr_t arg)
411d4b38e0Srsmaeda {
421d4b38e0Srsmaeda 	int rv;
431d4b38e0Srsmaeda 	drctl_setup_t setup_rqst;
441d4b38e0Srsmaeda 
451d4b38e0Srsmaeda 	switch (cmd) {
461d4b38e0Srsmaeda 	case DRCTL_IOCTL_CONNECT_SERVER:
471d4b38e0Srsmaeda 		if (ddi_copyin((caddr_t)arg,
481d4b38e0Srsmaeda 		    &setup_rqst, sizeof (setup_rqst), 0) != 0) {
491d4b38e0Srsmaeda 			cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed "
501d4b38e0Srsmaeda 			    "for DRCTL_IOCTL_CONNECT_SERVER");
511d4b38e0Srsmaeda 			rv = EFAULT;
521d4b38e0Srsmaeda 			break;
531d4b38e0Srsmaeda 		}
541d4b38e0Srsmaeda 
551d4b38e0Srsmaeda 		drctl_dh = door_ki_lookup(setup_rqst.did);
561d4b38e0Srsmaeda 		rv = 0;
571d4b38e0Srsmaeda 		break;
581d4b38e0Srsmaeda 
591d4b38e0Srsmaeda 	default:
601d4b38e0Srsmaeda 		rv = EIO;
611d4b38e0Srsmaeda 	}
621d4b38e0Srsmaeda 
631d4b38e0Srsmaeda 	return (rv);
641d4b38e0Srsmaeda }
651d4b38e0Srsmaeda 
661d4b38e0Srsmaeda int
i_drctl_send(void * msg,size_t size,void ** obufp,size_t * osize)671d4b38e0Srsmaeda i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize)
681d4b38e0Srsmaeda {
691d4b38e0Srsmaeda 	int up_err;
701d4b38e0Srsmaeda 	int rv = 0;
711d4b38e0Srsmaeda 	door_arg_t door_args;
721d4b38e0Srsmaeda 	door_handle_t dh = drctl_dh;
731d4b38e0Srsmaeda 	static const char me[] = "i_drctl_send";
741d4b38e0Srsmaeda 
751d4b38e0Srsmaeda retry:
761d4b38e0Srsmaeda 	if (dh)
771d4b38e0Srsmaeda 		door_ki_hold(dh);
781d4b38e0Srsmaeda 	else
791d4b38e0Srsmaeda 		return (EIO);
801d4b38e0Srsmaeda 
811d4b38e0Srsmaeda 	door_args.data_ptr = (char *)msg;
821d4b38e0Srsmaeda 	door_args.data_size = size;
831d4b38e0Srsmaeda 	door_args.desc_ptr = NULL;
841d4b38e0Srsmaeda 	door_args.desc_num = 0;
851d4b38e0Srsmaeda 
861d4b38e0Srsmaeda 	/*
871d4b38e0Srsmaeda 	 * We don't know the size of the message the daemon
881d4b38e0Srsmaeda 	 * will pass back to us.  By setting rbuf to NULL,
891d4b38e0Srsmaeda 	 * we force the door code to allocate a buf of the
901d4b38e0Srsmaeda 	 * appropriate size.  We must set rsize > 0, however,
911d4b38e0Srsmaeda 	 * else the door code acts as if no response was
921d4b38e0Srsmaeda 	 * expected and doesn't pass the data to us.
931d4b38e0Srsmaeda 	 */
941d4b38e0Srsmaeda 	door_args.rbuf = NULL;
951d4b38e0Srsmaeda 	door_args.rsize = 1;
961d4b38e0Srsmaeda 	DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n",
971d4b38e0Srsmaeda 	    me, msg, size, (void *)obufp, (void *)osize);
981d4b38e0Srsmaeda 
99323a81d9Sjwadams 	up_err = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
1001d4b38e0Srsmaeda 	if (up_err == 0) {
1010c86d1bbSrsmaeda 		if (door_args.rbuf == NULL)
1020c86d1bbSrsmaeda 			goto done;
1030c86d1bbSrsmaeda 
1040c86d1bbSrsmaeda 		DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me,
1050c86d1bbSrsmaeda 		    (void *)door_args.rbuf, door_args.rsize);
1060c86d1bbSrsmaeda 
1070c86d1bbSrsmaeda 		if (obufp != NULL) {
1081d4b38e0Srsmaeda 			*obufp = door_args.rbuf;
1091d4b38e0Srsmaeda 			*osize = door_args.rsize;
11099c7e855SJames Marks - Sun Microsystems 			DR_DBG_KMEM("%s: (door) alloc addr %p size %ld\n",
11199c7e855SJames Marks - Sun Microsystems 			    __func__,
11299c7e855SJames Marks - Sun Microsystems 			    (void *)(door_args.rbuf), door_args.rsize);
1130c86d1bbSrsmaeda 		} else {
1140c86d1bbSrsmaeda 			/*
1150c86d1bbSrsmaeda 			 * No output buffer pointer was passed in,
1160c86d1bbSrsmaeda 			 * so the response buffer allocated by the
1170c86d1bbSrsmaeda 			 * door code must be deallocated.
1180c86d1bbSrsmaeda 			 */
11999c7e855SJames Marks - Sun Microsystems 			DR_DBG_KMEM("%s: free addr %p size %ld\n", __func__,
12099c7e855SJames Marks - Sun Microsystems 			    (void *)(door_args.rbuf), door_args.rsize);
1210c86d1bbSrsmaeda 			kmem_free(door_args.rbuf, door_args.rsize);
1221d4b38e0Srsmaeda 		}
1231d4b38e0Srsmaeda 	} else {
1241d4b38e0Srsmaeda 		switch (up_err) {
1251d4b38e0Srsmaeda 		case EINTR:
1261d4b38e0Srsmaeda 			DR_DBG_CTL("%s: door call returned EINTR\n", me);
127*88b620a7SToomas Soome 			/* FALLTHROUGH */
1281d4b38e0Srsmaeda 		case EAGAIN:
1291d4b38e0Srsmaeda 			/*
1301d4b38e0Srsmaeda 			 * Server process may be forking, try again.
1311d4b38e0Srsmaeda 			 */
1321d4b38e0Srsmaeda 			door_ki_rele(dh);
1331d4b38e0Srsmaeda 			delay(hz);
1341d4b38e0Srsmaeda 			goto retry;
1351d4b38e0Srsmaeda 		case EBADF:
1361d4b38e0Srsmaeda 		case EINVAL:
1371d4b38e0Srsmaeda 			drctl_dh = NULL;
1381d4b38e0Srsmaeda 			DR_DBG_CTL(
1391d4b38e0Srsmaeda 			    "%s: door call failed with %d\n", me, up_err);
1401d4b38e0Srsmaeda 			rv = EIO;
1411d4b38e0Srsmaeda 			break;
1421d4b38e0Srsmaeda 		default:
1431d4b38e0Srsmaeda 			DR_DBG_CTL("%s: unexpected return "
1441d4b38e0Srsmaeda 			    "code %d from door_ki_upcall\n", me, up_err);
1451d4b38e0Srsmaeda 			rv = EIO;
1461d4b38e0Srsmaeda 			break;
1471d4b38e0Srsmaeda 		}
1481d4b38e0Srsmaeda 	}
1491d4b38e0Srsmaeda 
1500c86d1bbSrsmaeda done:
1511d4b38e0Srsmaeda 	door_ki_rele(dh);
1521d4b38e0Srsmaeda 	return (rv);
1531d4b38e0Srsmaeda }
154