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 721d4b38e0Srsmaeda main(int argc, char **argv) 731d4b38e0Srsmaeda { 741d4b38e0Srsmaeda int opt; 7520046e4cSjm22469 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 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 /* 16120046e4cSjm22469 * Initialize file descriptors. Do not touch stderr 16220046e4cSjm22469 * which is initialized by SMF to point to the drd 16320046e4cSjm22469 * 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 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 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 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 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: 4018fea755aSjm22469 (*drd_backend->io_config_request)(rsrcs, nrsrc); 4028fea755aSjm22469 break; 4038fea755aSjm22469 4041d4b38e0Srsmaeda case DRCTL_IO_CONFIG_NOTIFY: 4058fea755aSjm22469 (*drd_backend->io_config_notify)(rsrcs, nrsrc); 4068fea755aSjm22469 break; 4078fea755aSjm22469 4081d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_REQUEST: 4098fea755aSjm22469 (*drd_backend->io_unconfig_request)(rsrcs, nrsrc); 4108fea755aSjm22469 break; 4118fea755aSjm22469 4121d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_NOTIFY: 4138fea755aSjm22469 (*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