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