xref: /illumos-gate/usr/src/cmd/drd/drd.c (revision 9853d9e8)
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 /*
23*9853d9e8SJason Beloro  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241d4b38e0Srsmaeda  * Use is subject to license terms.
251d4b38e0Srsmaeda  */
261d4b38e0Srsmaeda 
271d4b38e0Srsmaeda /*
281d4b38e0Srsmaeda  * sun4v DR daemon
291d4b38e0Srsmaeda  */
301d4b38e0Srsmaeda 
311d4b38e0Srsmaeda #include <stdio.h>
321d4b38e0Srsmaeda #include <stdlib.h>
331d4b38e0Srsmaeda #include <unistd.h>
341d4b38e0Srsmaeda #include <string.h>
351d4b38e0Srsmaeda #include <strings.h>
361d4b38e0Srsmaeda #include <fcntl.h>
371d4b38e0Srsmaeda #include <errno.h>
381d4b38e0Srsmaeda #include <libgen.h>
391d4b38e0Srsmaeda #include <syslog.h>
401d4b38e0Srsmaeda #include <door.h>
411d4b38e0Srsmaeda #include <assert.h>
421d4b38e0Srsmaeda #include <sys/types.h>
431d4b38e0Srsmaeda #include <sys/stat.h>
441d4b38e0Srsmaeda 
451d4b38e0Srsmaeda #include <sys/drctl_impl.h>
461d4b38e0Srsmaeda #include <sys/drctl.h>
471d4b38e0Srsmaeda #include "drd.h"
481d4b38e0Srsmaeda 
491d4b38e0Srsmaeda boolean_t drd_debug = B_FALSE;
501d4b38e0Srsmaeda boolean_t drd_daemonized = B_FALSE;
511d4b38e0Srsmaeda 
521d4b38e0Srsmaeda #define	DRD_DOOR_FILE		"/tmp/drd_door"
531d4b38e0Srsmaeda #define	DRD_DOOR_RETURN_ERR()	(void) door_return(NULL, 0, NULL, 0)
541d4b38e0Srsmaeda 
551d4b38e0Srsmaeda static char *cmdname;
561d4b38e0Srsmaeda static int drctl_fd;
571d4b38e0Srsmaeda static drctl_rsrc_t *drd_result = NULL;
581d4b38e0Srsmaeda 
591d4b38e0Srsmaeda /*
601d4b38e0Srsmaeda  * Currently, the only supported backend is for the Reconfiguration
611d4b38e0Srsmaeda  * Coordination Manager (RCM). When there are other backends, this
621d4b38e0Srsmaeda  * variable should be set dynamically.
631d4b38e0Srsmaeda  */
641d4b38e0Srsmaeda static drd_backend_t *drd_backend = &drd_rcm_backend;
651d4b38e0Srsmaeda 
661d4b38e0Srsmaeda static void drd_daemonize(void);
671d4b38e0Srsmaeda static int drd_init_drctl_dev(boolean_t standalone);
681d4b38e0Srsmaeda static int drd_init_door_server(boolean_t standalone);
691d4b38e0Srsmaeda static void drd_door_server(void *, char *, size_t, door_desc_t *, uint_t);
701d4b38e0Srsmaeda 
711d4b38e0Srsmaeda int
main(int argc,char ** argv)721d4b38e0Srsmaeda main(int argc, char **argv)
731d4b38e0Srsmaeda {
741d4b38e0Srsmaeda 	int		opt;
7520046e4cSjm 	boolean_t	standalone = B_FALSE;
761d4b38e0Srsmaeda 
771d4b38e0Srsmaeda 	cmdname = basename(argv[0]);
781d4b38e0Srsmaeda 
791d4b38e0Srsmaeda 	/*
801d4b38e0Srsmaeda 	 * Process command line arguments
811d4b38e0Srsmaeda 	 */
821d4b38e0Srsmaeda 	opterr = 0;	/* disable getopt error messages */
831d4b38e0Srsmaeda 	while ((opt = getopt(argc, argv, "ds")) != EOF) {
841d4b38e0Srsmaeda 
851d4b38e0Srsmaeda 		switch (opt) {
861d4b38e0Srsmaeda 		case 'd':
871d4b38e0Srsmaeda 			drd_debug = B_TRUE;
881d4b38e0Srsmaeda 			break;
891d4b38e0Srsmaeda 		case 's':
901d4b38e0Srsmaeda 			standalone = B_TRUE;
911d4b38e0Srsmaeda 			break;
921d4b38e0Srsmaeda 		default:
931d4b38e0Srsmaeda 			drd_err("unkown option: -%c", optopt);
941d4b38e0Srsmaeda 			exit(1);
951d4b38e0Srsmaeda 		}
961d4b38e0Srsmaeda 	}
971d4b38e0Srsmaeda 
981d4b38e0Srsmaeda 	drd_dbg("initializing %s...", cmdname);
991d4b38e0Srsmaeda 
1001d4b38e0Srsmaeda 	/* must be root */
1011d4b38e0Srsmaeda 	if (geteuid() != 0) {
1021d4b38e0Srsmaeda 		drd_err("permission denied: must run as root");
1031d4b38e0Srsmaeda 		exit(1);
1041d4b38e0Srsmaeda 	}
1051d4b38e0Srsmaeda 
1061d4b38e0Srsmaeda 	/* open the drctl device */
1071d4b38e0Srsmaeda 	if (drd_init_drctl_dev(standalone) != 0) {
1081d4b38e0Srsmaeda 		drd_err("unable to initialize drctl device");
1091d4b38e0Srsmaeda 		exit(1);
1101d4b38e0Srsmaeda 	}
1111d4b38e0Srsmaeda 
1121d4b38e0Srsmaeda 	/* daemonize */
1131d4b38e0Srsmaeda 	if (!standalone) {
1141d4b38e0Srsmaeda 		drd_daemonize();
1151d4b38e0Srsmaeda 	}
1161d4b38e0Srsmaeda 
1171d4b38e0Srsmaeda 	/* initialize door server */
1181d4b38e0Srsmaeda 	if (drd_init_door_server(standalone) != 0) {
1191d4b38e0Srsmaeda 		drd_err("unable to initialize door server");
1201d4b38e0Srsmaeda 		exit(1);
1211d4b38e0Srsmaeda 	}
1221d4b38e0Srsmaeda 
1231d4b38e0Srsmaeda 	/* initialize the backend */
1241d4b38e0Srsmaeda 	if ((*drd_backend->init)() != 0) {
1251d4b38e0Srsmaeda 		drd_err("unable to initialize backend processor");
1261d4b38e0Srsmaeda 		exit(1);
1271d4b38e0Srsmaeda 	}
1281d4b38e0Srsmaeda 
1291d4b38e0Srsmaeda 	/* loop forever */
1301d4b38e0Srsmaeda 	for (;;) {
1311d4b38e0Srsmaeda 		pause();
1321d4b38e0Srsmaeda 	}
1331d4b38e0Srsmaeda 
1341d4b38e0Srsmaeda 	/*NOTREACHED*/
1351d4b38e0Srsmaeda 	return (0);
1361d4b38e0Srsmaeda }
1371d4b38e0Srsmaeda 
1381d4b38e0Srsmaeda static void
drd_daemonize(void)1391d4b38e0Srsmaeda drd_daemonize(void)
1401d4b38e0Srsmaeda {
1411d4b38e0Srsmaeda 	pid_t	pid;
1421d4b38e0Srsmaeda 
1431d4b38e0Srsmaeda 	if ((pid = fork()) == -1) {
1441d4b38e0Srsmaeda 		drd_err("failed to fork: %s", strerror(errno));
1451d4b38e0Srsmaeda 		exit(1);
1461d4b38e0Srsmaeda 	}
1471d4b38e0Srsmaeda 
1481d4b38e0Srsmaeda 	if (pid != 0) {
1491d4b38e0Srsmaeda 		/* parent */
1501d4b38e0Srsmaeda 		exit(0);
1511d4b38e0Srsmaeda 	}
1521d4b38e0Srsmaeda 
1531d4b38e0Srsmaeda 	/*
1541d4b38e0Srsmaeda 	 * Initialize child process
1551d4b38e0Srsmaeda 	 */
1561d4b38e0Srsmaeda 	(void) setsid();
1571d4b38e0Srsmaeda 	(void) chdir("/");
1581d4b38e0Srsmaeda 	(void) umask(0);
1591d4b38e0Srsmaeda 
1601d4b38e0Srsmaeda 	/*
16120046e4cSjm 	 * Initialize file descriptors. Do not touch stderr
16220046e4cSjm 	 * which is initialized by SMF to point to the drd
16320046e4cSjm 	 * specific log file.
1641d4b38e0Srsmaeda 	 */
1651d4b38e0Srsmaeda 	assert(drctl_fd == (STDERR_FILENO + 1));
1661d4b38e0Srsmaeda 
1671d4b38e0Srsmaeda 	(void) close(STDIN_FILENO);
1681d4b38e0Srsmaeda 	(void) open("/dev/null", O_RDWR);
1691d4b38e0Srsmaeda 	(void) dup2(STDIN_FILENO, STDOUT_FILENO);
1701d4b38e0Srsmaeda 
1711d4b38e0Srsmaeda 	closefrom(drctl_fd + 1);
1721d4b38e0Srsmaeda 
1731d4b38e0Srsmaeda 	/* initialize logging */
1741d4b38e0Srsmaeda 	openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
1751d4b38e0Srsmaeda 
1761d4b38e0Srsmaeda 	drd_daemonized = B_TRUE;
1771d4b38e0Srsmaeda }
1781d4b38e0Srsmaeda 
1791d4b38e0Srsmaeda static int
drd_init_drctl_dev(boolean_t standalone)1801d4b38e0Srsmaeda drd_init_drctl_dev(boolean_t standalone)
1811d4b38e0Srsmaeda {
1821d4b38e0Srsmaeda 	void (*drd_output)(char *, ...);
1831d4b38e0Srsmaeda 
1841d4b38e0Srsmaeda 	drd_output = (standalone) ? drd_info : drd_err;
1851d4b38e0Srsmaeda 
1861d4b38e0Srsmaeda 	/* open the drctl device */
1871d4b38e0Srsmaeda 	if ((drctl_fd = open(DRCTL_DEV, O_RDWR)) == -1) {
1881d4b38e0Srsmaeda 		drd_output("open %s failed: %s", DRCTL_DEV, strerror(errno));
1891d4b38e0Srsmaeda 		return ((standalone) ? 0 : -1);
1901d4b38e0Srsmaeda 	}
1911d4b38e0Srsmaeda 
1921d4b38e0Srsmaeda 	return (0);
1931d4b38e0Srsmaeda }
1941d4b38e0Srsmaeda 
1951d4b38e0Srsmaeda static int
drd_init_door_server(boolean_t standalone)1961d4b38e0Srsmaeda drd_init_door_server(boolean_t standalone)
1971d4b38e0Srsmaeda {
1981d4b38e0Srsmaeda 	int		door_fd;
1991d4b38e0Srsmaeda 	int		dbg_fd;
2001d4b38e0Srsmaeda 	drctl_setup_t	setup;
2011d4b38e0Srsmaeda 
2021d4b38e0Srsmaeda 	assert((drctl_fd != -1) || standalone);
2031d4b38e0Srsmaeda 
2041d4b38e0Srsmaeda 	/* create the door */
2051d4b38e0Srsmaeda 	if ((door_fd = door_create(drd_door_server, NULL, 0)) == -1) {
2061d4b38e0Srsmaeda 		drd_err("door_create failed: %s", strerror(errno));
2071d4b38e0Srsmaeda 		return (-1);
2081d4b38e0Srsmaeda 	}
2091d4b38e0Srsmaeda 
2101d4b38e0Srsmaeda 	if (drctl_fd != -1) {
2111d4b38e0Srsmaeda 
2121d4b38e0Srsmaeda 		setup.did = door_fd;
2131d4b38e0Srsmaeda 
2141d4b38e0Srsmaeda 		/* send the door descriptor to drctl */
2151d4b38e0Srsmaeda 		if (ioctl(drctl_fd, DRCTL_IOCTL_CONNECT_SERVER, &setup) == -1) {
2161d4b38e0Srsmaeda 			drd_err("drctl ioctl failed: %s", strerror(errno));
2171d4b38e0Srsmaeda 			(void) door_revoke(door_fd);
2181d4b38e0Srsmaeda 			return (-1);
2191d4b38e0Srsmaeda 		}
2201d4b38e0Srsmaeda 
2211d4b38e0Srsmaeda 		drd_dbg("connection to drctl established");
2221d4b38e0Srsmaeda 
2231d4b38e0Srsmaeda 		/* setup is complete in daemon mode */
2241d4b38e0Srsmaeda 		if (!standalone) {
2251d4b38e0Srsmaeda 			return (0);
2261d4b38e0Srsmaeda 		}
2271d4b38e0Srsmaeda 	}
2281d4b38e0Srsmaeda 
2291d4b38e0Srsmaeda 	/*
2301d4b38e0Srsmaeda 	 * At this point, the daemon is running in standalone
2311d4b38e0Srsmaeda 	 * mode for testing purposes. This allows the daemon
2321d4b38e0Srsmaeda 	 * to be controlled directly through a door exported
2331d4b38e0Srsmaeda 	 * to the filesystem. No drctl device is required in
2341d4b38e0Srsmaeda 	 * this mode.
2351d4b38e0Srsmaeda 	 */
2361d4b38e0Srsmaeda 
2371d4b38e0Srsmaeda 	/* create the door file */
2381d4b38e0Srsmaeda 	unlink(DRD_DOOR_FILE);
2391d4b38e0Srsmaeda 	if ((dbg_fd = creat(DRD_DOOR_FILE, 0644)) == -1) {
2401d4b38e0Srsmaeda 		drd_err("failed to create door file '%s': %s",
2411d4b38e0Srsmaeda 		    DRD_DOOR_FILE, strerror(errno));
2421d4b38e0Srsmaeda 		(void) door_revoke(door_fd);
2431d4b38e0Srsmaeda 		return (-1);
2441d4b38e0Srsmaeda 	}
2451d4b38e0Srsmaeda 	close(dbg_fd);
2461d4b38e0Srsmaeda 
2471d4b38e0Srsmaeda 	/* attach the door file to the door descriptor */
2481d4b38e0Srsmaeda 	if (fattach(door_fd, DRD_DOOR_FILE) == -1) {
2491d4b38e0Srsmaeda 		drd_err("failed to fattach door file '%s': %s",
2501d4b38e0Srsmaeda 		    DRD_DOOR_FILE, strerror(errno));
2511d4b38e0Srsmaeda 		unlink(DRD_DOOR_FILE);
2521d4b38e0Srsmaeda 		(void) door_revoke(door_fd);
2531d4b38e0Srsmaeda 		return (-1);
2541d4b38e0Srsmaeda 	}
2551d4b38e0Srsmaeda 
2561d4b38e0Srsmaeda 	drd_dbg("door server attached to '%s'", DRD_DOOR_FILE);
2571d4b38e0Srsmaeda 
2581d4b38e0Srsmaeda 	return (0);
2591d4b38e0Srsmaeda }
2601d4b38e0Srsmaeda 
2611d4b38e0Srsmaeda static size_t
drd_pack_response(drctl_rsrc_t * rsrcs,int nrsrc)2621d4b38e0Srsmaeda drd_pack_response(drctl_rsrc_t *rsrcs, int nrsrc)
2631d4b38e0Srsmaeda {
2641d4b38e0Srsmaeda 	drctl_rsrc_t	*orsrcsp;
2651d4b38e0Srsmaeda 	void		*resizep;
2661d4b38e0Srsmaeda 	size_t		osize;
2671d4b38e0Srsmaeda 	char		*str;
2681d4b38e0Srsmaeda 	size_t		offset;
2691d4b38e0Srsmaeda 	char		*off;
2701d4b38e0Srsmaeda 	int		idx;
2711d4b38e0Srsmaeda 	size_t		len;
2721d4b38e0Srsmaeda 
2731d4b38e0Srsmaeda 	drd_dbg("drd_pack_response...");
2741d4b38e0Srsmaeda 
2751d4b38e0Srsmaeda 	/*
2761d4b38e0Srsmaeda 	 * Deallocate the global response buffer if it is
2771d4b38e0Srsmaeda 	 * in use. This assumes that there will only ever
2781d4b38e0Srsmaeda 	 * be one pending operation in the daemon. This is
2791d4b38e0Srsmaeda 	 * enforced by the kernel.
2801d4b38e0Srsmaeda 	 */
2811d4b38e0Srsmaeda 	s_free(drd_result);
2821d4b38e0Srsmaeda 
2831d4b38e0Srsmaeda 	orsrcsp = calloc(sizeof (*orsrcsp), nrsrc);
2841d4b38e0Srsmaeda 	osize = sizeof (*orsrcsp) * nrsrc;
2851d4b38e0Srsmaeda 	bcopy(rsrcs, orsrcsp, osize);
2861d4b38e0Srsmaeda 
2871d4b38e0Srsmaeda 	offset = osize;
2881d4b38e0Srsmaeda 
2891d4b38e0Srsmaeda 	/*
2901d4b38e0Srsmaeda 	 * Loop through all the resources and concatenate
2911d4b38e0Srsmaeda 	 * all the error strings to the end of the resource
2921d4b38e0Srsmaeda 	 * array. Also, update the offset field of each
2931d4b38e0Srsmaeda 	 * resource.
2941d4b38e0Srsmaeda 	 */
2951d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
2961d4b38e0Srsmaeda 
2971d4b38e0Srsmaeda 		str = (char *)(uintptr_t)rsrcs[idx].offset;
2981d4b38e0Srsmaeda 
2991d4b38e0Srsmaeda 		/* skip if no error string */
3001d4b38e0Srsmaeda 		if (str == NULL)
3011d4b38e0Srsmaeda 			continue;
3021d4b38e0Srsmaeda 
3031d4b38e0Srsmaeda 		len = strlen(str) + 1;
3041d4b38e0Srsmaeda 
3051d4b38e0Srsmaeda 		/* increase the size of the buffer */
3061d4b38e0Srsmaeda 		resizep = realloc(orsrcsp, osize + len);
3071d4b38e0Srsmaeda 		if (resizep == NULL) {
3081d4b38e0Srsmaeda 			drd_err("realloc failed: %s", strerror(errno));
3091d4b38e0Srsmaeda 			s_free(orsrcsp);
3101d4b38e0Srsmaeda 
3111d4b38e0Srsmaeda 			/* clean up any remaining strings */
3121d4b38e0Srsmaeda 			while (idx < nrsrc) {
3131d4b38e0Srsmaeda 				str = (char *)(uintptr_t)rsrcs[idx++].offset;
3141d4b38e0Srsmaeda 				s_free(str);
3151d4b38e0Srsmaeda 			}
3161d4b38e0Srsmaeda 			return (0);
3171d4b38e0Srsmaeda 		}
3181d4b38e0Srsmaeda 
3191d4b38e0Srsmaeda 		orsrcsp = resizep;
3201d4b38e0Srsmaeda 
3211d4b38e0Srsmaeda 		/* copy the error string into the response */
3221d4b38e0Srsmaeda 		off = (char *)orsrcsp + offset;
3231d4b38e0Srsmaeda 		bcopy(str, off, len);
3241d4b38e0Srsmaeda 		orsrcsp[idx].offset = offset;
3251d4b38e0Srsmaeda 
3261d4b38e0Srsmaeda 		/*
3271d4b38e0Srsmaeda 		 * Now that the error string has been copied
3281d4b38e0Srsmaeda 		 * into the response message, the memory that
3291d4b38e0Srsmaeda 		 * was allocated for it is no longer needed.
3301d4b38e0Srsmaeda 		 */
3311d4b38e0Srsmaeda 		s_free(str);
3321d4b38e0Srsmaeda 		rsrcs[idx].offset = 0;
3331d4b38e0Srsmaeda 
3341d4b38e0Srsmaeda 		/* update size and offset */
3351d4b38e0Srsmaeda 		offset += len;
3361d4b38e0Srsmaeda 		osize += len;
3371d4b38e0Srsmaeda 	}
3381d4b38e0Srsmaeda 
3391d4b38e0Srsmaeda 	drd_result = orsrcsp;
3401d4b38e0Srsmaeda 	return (osize);
3411d4b38e0Srsmaeda }
3421d4b38e0Srsmaeda 
3431d4b38e0Srsmaeda /*ARGSUSED*/
3441d4b38e0Srsmaeda static void
drd_door_server(void * cookie,char * argp,size_t arg_sz,door_desc_t * dp,uint_t n_desc)3451d4b38e0Srsmaeda drd_door_server(void *cookie, char *argp, size_t arg_sz, door_desc_t *dp,
3461d4b38e0Srsmaeda     uint_t n_desc)
3471d4b38e0Srsmaeda {
3481d4b38e0Srsmaeda 	drd_msg_t	*msg = (drd_msg_t *)(uintptr_t)argp;
3491d4b38e0Srsmaeda 	drctl_rsrc_t	*rsrcs;
3501d4b38e0Srsmaeda 	size_t		osize;
3511d4b38e0Srsmaeda 	int		nrsrc;
3521d4b38e0Srsmaeda 
3531d4b38e0Srsmaeda 	drd_dbg("drd_door_server...");
3541d4b38e0Srsmaeda 	drd_dbg("message received: %d bytes", arg_sz);
3551d4b38e0Srsmaeda 
3561d4b38e0Srsmaeda 	/* sanity check incoming arg */
3571d4b38e0Srsmaeda 	if ((argp == NULL) || (arg_sz == 0))
3581d4b38e0Srsmaeda 		DRD_DOOR_RETURN_ERR();
3591d4b38e0Srsmaeda 
3601d4b38e0Srsmaeda 	drd_dbg("  cmd=%d, count=%d, flags=%d", msg->cmd,
3611d4b38e0Srsmaeda 	    msg->count, msg->flags);
3621d4b38e0Srsmaeda 
3631d4b38e0Srsmaeda 	rsrcs = (drctl_rsrc_t *)(uintptr_t)msg->data;
3641d4b38e0Srsmaeda 	nrsrc = msg->count;
3651d4b38e0Srsmaeda 
3661d4b38e0Srsmaeda 	/* pass off to backend for processing */
3671d4b38e0Srsmaeda 	switch (msg->cmd) {
3681d4b38e0Srsmaeda 	case DRCTL_CPU_CONFIG_REQUEST:
3691d4b38e0Srsmaeda 		(*drd_backend->cpu_config_request)(rsrcs, nrsrc);
3701d4b38e0Srsmaeda 		break;
3711d4b38e0Srsmaeda 
3721d4b38e0Srsmaeda 	case DRCTL_CPU_CONFIG_NOTIFY:
3731d4b38e0Srsmaeda 		(*drd_backend->cpu_config_notify)(rsrcs, nrsrc);
3741d4b38e0Srsmaeda 		break;
3751d4b38e0Srsmaeda 
3761d4b38e0Srsmaeda 	case DRCTL_CPU_UNCONFIG_REQUEST:
3771d4b38e0Srsmaeda 		(*drd_backend->cpu_unconfig_request)(rsrcs, nrsrc);
3781d4b38e0Srsmaeda 		break;
3791d4b38e0Srsmaeda 
3801d4b38e0Srsmaeda 	case DRCTL_CPU_UNCONFIG_NOTIFY:
3811d4b38e0Srsmaeda 		(*drd_backend->cpu_unconfig_notify)(rsrcs, nrsrc);
3821d4b38e0Srsmaeda 		break;
3831d4b38e0Srsmaeda 
3841d4b38e0Srsmaeda 	case DRCTL_MEM_CONFIG_REQUEST:
385*9853d9e8SJason Beloro 		(*drd_backend->mem_config_request)(rsrcs, nrsrc);
386*9853d9e8SJason Beloro 		break;
387*9853d9e8SJason Beloro 
3881d4b38e0Srsmaeda 	case DRCTL_MEM_CONFIG_NOTIFY:
389*9853d9e8SJason Beloro 		(*drd_backend->mem_config_notify)(rsrcs, nrsrc);
390*9853d9e8SJason Beloro 		break;
391*9853d9e8SJason Beloro 
3921d4b38e0Srsmaeda 	case DRCTL_MEM_UNCONFIG_REQUEST:
393*9853d9e8SJason Beloro 		(*drd_backend->mem_unconfig_request)(rsrcs, nrsrc);
394*9853d9e8SJason Beloro 		break;
395*9853d9e8SJason Beloro 
3961d4b38e0Srsmaeda 	case DRCTL_MEM_UNCONFIG_NOTIFY:
397*9853d9e8SJason Beloro 		(*drd_backend->mem_unconfig_notify)(rsrcs, nrsrc);
3981d4b38e0Srsmaeda 		break;
3991d4b38e0Srsmaeda 
4001d4b38e0Srsmaeda 	case DRCTL_IO_CONFIG_REQUEST:
4018fea755aSjm 		(*drd_backend->io_config_request)(rsrcs, nrsrc);
4028fea755aSjm 		break;
4038fea755aSjm 
4041d4b38e0Srsmaeda 	case DRCTL_IO_CONFIG_NOTIFY:
4058fea755aSjm 		(*drd_backend->io_config_notify)(rsrcs, nrsrc);
4068fea755aSjm 		break;
4078fea755aSjm 
4081d4b38e0Srsmaeda 	case DRCTL_IO_UNCONFIG_REQUEST:
4098fea755aSjm 		(*drd_backend->io_unconfig_request)(rsrcs, nrsrc);
4108fea755aSjm 		break;
4118fea755aSjm 
4121d4b38e0Srsmaeda 	case DRCTL_IO_UNCONFIG_NOTIFY:
4138fea755aSjm 		(*drd_backend->io_unconfig_notify)(rsrcs, nrsrc);
4141d4b38e0Srsmaeda 		break;
4151d4b38e0Srsmaeda 
4161d4b38e0Srsmaeda 	default:
4171d4b38e0Srsmaeda 		drd_err("unknown command: %d", msg->cmd);
4181d4b38e0Srsmaeda 		DRD_DOOR_RETURN_ERR();
4191d4b38e0Srsmaeda 		break;
4201d4b38e0Srsmaeda 	}
4211d4b38e0Srsmaeda 
4221d4b38e0Srsmaeda 	osize = drd_pack_response(rsrcs, nrsrc);
4231d4b38e0Srsmaeda 	if (osize == 0)
4241d4b38e0Srsmaeda 		DRD_DOOR_RETURN_ERR();
4251d4b38e0Srsmaeda 
4261d4b38e0Srsmaeda 	(void) door_return((char *)drd_result, osize, NULL, 0);
4271d4b38e0Srsmaeda }
428