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