xref: /onnv-gate/usr/src/cmd/drd/drd.c (revision 10106:b235491976d3)
12309Srsmaeda /*
22309Srsmaeda  * CDDL HEADER START
32309Srsmaeda  *
42309Srsmaeda  * The contents of this file are subject to the terms of the
52309Srsmaeda  * Common Development and Distribution License (the "License").
62309Srsmaeda  * You may not use this file except in compliance with the License.
72309Srsmaeda  *
82309Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92309Srsmaeda  * or http://www.opensolaris.org/os/licensing.
102309Srsmaeda  * See the License for the specific language governing permissions
112309Srsmaeda  * and limitations under the License.
122309Srsmaeda  *
132309Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
142309Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152309Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
162309Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
172309Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
182309Srsmaeda  *
192309Srsmaeda  * CDDL HEADER END
202309Srsmaeda  */
212309Srsmaeda 
222309Srsmaeda /*
23*10106SJason.Beloro@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242309Srsmaeda  * Use is subject to license terms.
252309Srsmaeda  */
262309Srsmaeda 
272309Srsmaeda /*
282309Srsmaeda  * sun4v DR daemon
292309Srsmaeda  */
302309Srsmaeda 
312309Srsmaeda #include <stdio.h>
322309Srsmaeda #include <stdlib.h>
332309Srsmaeda #include <unistd.h>
342309Srsmaeda #include <string.h>
352309Srsmaeda #include <strings.h>
362309Srsmaeda #include <fcntl.h>
372309Srsmaeda #include <errno.h>
382309Srsmaeda #include <libgen.h>
392309Srsmaeda #include <syslog.h>
402309Srsmaeda #include <door.h>
412309Srsmaeda #include <assert.h>
422309Srsmaeda #include <sys/types.h>
432309Srsmaeda #include <sys/stat.h>
442309Srsmaeda 
452309Srsmaeda #include <sys/drctl_impl.h>
462309Srsmaeda #include <sys/drctl.h>
472309Srsmaeda #include "drd.h"
482309Srsmaeda 
492309Srsmaeda boolean_t drd_debug = B_FALSE;
502309Srsmaeda boolean_t drd_daemonized = B_FALSE;
512309Srsmaeda 
522309Srsmaeda #define	DRD_DOOR_FILE		"/tmp/drd_door"
532309Srsmaeda #define	DRD_DOOR_RETURN_ERR()	(void) door_return(NULL, 0, NULL, 0)
542309Srsmaeda 
552309Srsmaeda static char *cmdname;
562309Srsmaeda static int drctl_fd;
572309Srsmaeda static drctl_rsrc_t *drd_result = NULL;
582309Srsmaeda 
592309Srsmaeda /*
602309Srsmaeda  * Currently, the only supported backend is for the Reconfiguration
612309Srsmaeda  * Coordination Manager (RCM). When there are other backends, this
622309Srsmaeda  * variable should be set dynamically.
632309Srsmaeda  */
642309Srsmaeda static drd_backend_t *drd_backend = &drd_rcm_backend;
652309Srsmaeda 
662309Srsmaeda static void drd_daemonize(void);
672309Srsmaeda static int drd_init_drctl_dev(boolean_t standalone);
682309Srsmaeda static int drd_init_door_server(boolean_t standalone);
692309Srsmaeda static void drd_door_server(void *, char *, size_t, door_desc_t *, uint_t);
702309Srsmaeda 
712309Srsmaeda int
main(int argc,char ** argv)722309Srsmaeda main(int argc, char **argv)
732309Srsmaeda {
742309Srsmaeda 	int		opt;
753263Sjm22469 	boolean_t	standalone = B_FALSE;
762309Srsmaeda 
772309Srsmaeda 	cmdname = basename(argv[0]);
782309Srsmaeda 
792309Srsmaeda 	/*
802309Srsmaeda 	 * Process command line arguments
812309Srsmaeda 	 */
822309Srsmaeda 	opterr = 0;	/* disable getopt error messages */
832309Srsmaeda 	while ((opt = getopt(argc, argv, "ds")) != EOF) {
842309Srsmaeda 
852309Srsmaeda 		switch (opt) {
862309Srsmaeda 		case 'd':
872309Srsmaeda 			drd_debug = B_TRUE;
882309Srsmaeda 			break;
892309Srsmaeda 		case 's':
902309Srsmaeda 			standalone = B_TRUE;
912309Srsmaeda 			break;
922309Srsmaeda 		default:
932309Srsmaeda 			drd_err("unkown option: -%c", optopt);
942309Srsmaeda 			exit(1);
952309Srsmaeda 		}
962309Srsmaeda 	}
972309Srsmaeda 
982309Srsmaeda 	drd_dbg("initializing %s...", cmdname);
992309Srsmaeda 
1002309Srsmaeda 	/* must be root */
1012309Srsmaeda 	if (geteuid() != 0) {
1022309Srsmaeda 		drd_err("permission denied: must run as root");
1032309Srsmaeda 		exit(1);
1042309Srsmaeda 	}
1052309Srsmaeda 
1062309Srsmaeda 	/* open the drctl device */
1072309Srsmaeda 	if (drd_init_drctl_dev(standalone) != 0) {
1082309Srsmaeda 		drd_err("unable to initialize drctl device");
1092309Srsmaeda 		exit(1);
1102309Srsmaeda 	}
1112309Srsmaeda 
1122309Srsmaeda 	/* daemonize */
1132309Srsmaeda 	if (!standalone) {
1142309Srsmaeda 		drd_daemonize();
1152309Srsmaeda 	}
1162309Srsmaeda 
1172309Srsmaeda 	/* initialize door server */
1182309Srsmaeda 	if (drd_init_door_server(standalone) != 0) {
1192309Srsmaeda 		drd_err("unable to initialize door server");
1202309Srsmaeda 		exit(1);
1212309Srsmaeda 	}
1222309Srsmaeda 
1232309Srsmaeda 	/* initialize the backend */
1242309Srsmaeda 	if ((*drd_backend->init)() != 0) {
1252309Srsmaeda 		drd_err("unable to initialize backend processor");
1262309Srsmaeda 		exit(1);
1272309Srsmaeda 	}
1282309Srsmaeda 
1292309Srsmaeda 	/* loop forever */
1302309Srsmaeda 	for (;;) {
1312309Srsmaeda 		pause();
1322309Srsmaeda 	}
1332309Srsmaeda 
1342309Srsmaeda 	/*NOTREACHED*/
1352309Srsmaeda 	return (0);
1362309Srsmaeda }
1372309Srsmaeda 
1382309Srsmaeda static void
drd_daemonize(void)1392309Srsmaeda drd_daemonize(void)
1402309Srsmaeda {
1412309Srsmaeda 	pid_t	pid;
1422309Srsmaeda 
1432309Srsmaeda 	if ((pid = fork()) == -1) {
1442309Srsmaeda 		drd_err("failed to fork: %s", strerror(errno));
1452309Srsmaeda 		exit(1);
1462309Srsmaeda 	}
1472309Srsmaeda 
1482309Srsmaeda 	if (pid != 0) {
1492309Srsmaeda 		/* parent */
1502309Srsmaeda 		exit(0);
1512309Srsmaeda 	}
1522309Srsmaeda 
1532309Srsmaeda 	/*
1542309Srsmaeda 	 * Initialize child process
1552309Srsmaeda 	 */
1562309Srsmaeda 	(void) setsid();
1572309Srsmaeda 	(void) chdir("/");
1582309Srsmaeda 	(void) umask(0);
1592309Srsmaeda 
1602309Srsmaeda 	/*
1613263Sjm22469 	 * Initialize file descriptors. Do not touch stderr
1623263Sjm22469 	 * which is initialized by SMF to point to the drd
1633263Sjm22469 	 * specific log file.
1642309Srsmaeda 	 */
1652309Srsmaeda 	assert(drctl_fd == (STDERR_FILENO + 1));
1662309Srsmaeda 
1672309Srsmaeda 	(void) close(STDIN_FILENO);
1682309Srsmaeda 	(void) open("/dev/null", O_RDWR);
1692309Srsmaeda 	(void) dup2(STDIN_FILENO, STDOUT_FILENO);
1702309Srsmaeda 
1712309Srsmaeda 	closefrom(drctl_fd + 1);
1722309Srsmaeda 
1732309Srsmaeda 	/* initialize logging */
1742309Srsmaeda 	openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
1752309Srsmaeda 
1762309Srsmaeda 	drd_daemonized = B_TRUE;
1772309Srsmaeda }
1782309Srsmaeda 
1792309Srsmaeda static int
drd_init_drctl_dev(boolean_t standalone)1802309Srsmaeda drd_init_drctl_dev(boolean_t standalone)
1812309Srsmaeda {
1822309Srsmaeda 	void (*drd_output)(char *, ...);
1832309Srsmaeda 
1842309Srsmaeda 	drd_output = (standalone) ? drd_info : drd_err;
1852309Srsmaeda 
1862309Srsmaeda 	/* open the drctl device */
1872309Srsmaeda 	if ((drctl_fd = open(DRCTL_DEV, O_RDWR)) == -1) {
1882309Srsmaeda 		drd_output("open %s failed: %s", DRCTL_DEV, strerror(errno));
1892309Srsmaeda 		return ((standalone) ? 0 : -1);
1902309Srsmaeda 	}
1912309Srsmaeda 
1922309Srsmaeda 	return (0);
1932309Srsmaeda }
1942309Srsmaeda 
1952309Srsmaeda static int
drd_init_door_server(boolean_t standalone)1962309Srsmaeda drd_init_door_server(boolean_t standalone)
1972309Srsmaeda {
1982309Srsmaeda 	int		door_fd;
1992309Srsmaeda 	int		dbg_fd;
2002309Srsmaeda 	drctl_setup_t	setup;
2012309Srsmaeda 
2022309Srsmaeda 	assert((drctl_fd != -1) || standalone);
2032309Srsmaeda 
2042309Srsmaeda 	/* create the door */
2052309Srsmaeda 	if ((door_fd = door_create(drd_door_server, NULL, 0)) == -1) {
2062309Srsmaeda 		drd_err("door_create failed: %s", strerror(errno));
2072309Srsmaeda 		return (-1);
2082309Srsmaeda 	}
2092309Srsmaeda 
2102309Srsmaeda 	if (drctl_fd != -1) {
2112309Srsmaeda 
2122309Srsmaeda 		setup.did = door_fd;
2132309Srsmaeda 
2142309Srsmaeda 		/* send the door descriptor to drctl */
2152309Srsmaeda 		if (ioctl(drctl_fd, DRCTL_IOCTL_CONNECT_SERVER, &setup) == -1) {
2162309Srsmaeda 			drd_err("drctl ioctl failed: %s", strerror(errno));
2172309Srsmaeda 			(void) door_revoke(door_fd);
2182309Srsmaeda 			return (-1);
2192309Srsmaeda 		}
2202309Srsmaeda 
2212309Srsmaeda 		drd_dbg("connection to drctl established");
2222309Srsmaeda 
2232309Srsmaeda 		/* setup is complete in daemon mode */
2242309Srsmaeda 		if (!standalone) {
2252309Srsmaeda 			return (0);
2262309Srsmaeda 		}
2272309Srsmaeda 	}
2282309Srsmaeda 
2292309Srsmaeda 	/*
2302309Srsmaeda 	 * At this point, the daemon is running in standalone
2312309Srsmaeda 	 * mode for testing purposes. This allows the daemon
2322309Srsmaeda 	 * to be controlled directly through a door exported
2332309Srsmaeda 	 * to the filesystem. No drctl device is required in
2342309Srsmaeda 	 * this mode.
2352309Srsmaeda 	 */
2362309Srsmaeda 
2372309Srsmaeda 	/* create the door file */
2382309Srsmaeda 	unlink(DRD_DOOR_FILE);
2392309Srsmaeda 	if ((dbg_fd = creat(DRD_DOOR_FILE, 0644)) == -1) {
2402309Srsmaeda 		drd_err("failed to create door file '%s': %s",
2412309Srsmaeda 		    DRD_DOOR_FILE, strerror(errno));
2422309Srsmaeda 		(void) door_revoke(door_fd);
2432309Srsmaeda 		return (-1);
2442309Srsmaeda 	}
2452309Srsmaeda 	close(dbg_fd);
2462309Srsmaeda 
2472309Srsmaeda 	/* attach the door file to the door descriptor */
2482309Srsmaeda 	if (fattach(door_fd, DRD_DOOR_FILE) == -1) {
2492309Srsmaeda 		drd_err("failed to fattach door file '%s': %s",
2502309Srsmaeda 		    DRD_DOOR_FILE, strerror(errno));
2512309Srsmaeda 		unlink(DRD_DOOR_FILE);
2522309Srsmaeda 		(void) door_revoke(door_fd);
2532309Srsmaeda 		return (-1);
2542309Srsmaeda 	}
2552309Srsmaeda 
2562309Srsmaeda 	drd_dbg("door server attached to '%s'", DRD_DOOR_FILE);
2572309Srsmaeda 
2582309Srsmaeda 	return (0);
2592309Srsmaeda }
2602309Srsmaeda 
2612309Srsmaeda static size_t
drd_pack_response(drctl_rsrc_t * rsrcs,int nrsrc)2622309Srsmaeda drd_pack_response(drctl_rsrc_t *rsrcs, int nrsrc)
2632309Srsmaeda {
2642309Srsmaeda 	drctl_rsrc_t	*orsrcsp;
2652309Srsmaeda 	void		*resizep;
2662309Srsmaeda 	size_t		osize;
2672309Srsmaeda 	char		*str;
2682309Srsmaeda 	size_t		offset;
2692309Srsmaeda 	char		*off;
2702309Srsmaeda 	int		idx;
2712309Srsmaeda 	size_t		len;
2722309Srsmaeda 
2732309Srsmaeda 	drd_dbg("drd_pack_response...");
2742309Srsmaeda 
2752309Srsmaeda 	/*
2762309Srsmaeda 	 * Deallocate the global response buffer if it is
2772309Srsmaeda 	 * in use. This assumes that there will only ever
2782309Srsmaeda 	 * be one pending operation in the daemon. This is
2792309Srsmaeda 	 * enforced by the kernel.
2802309Srsmaeda 	 */
2812309Srsmaeda 	s_free(drd_result);
2822309Srsmaeda 
2832309Srsmaeda 	orsrcsp = calloc(sizeof (*orsrcsp), nrsrc);
2842309Srsmaeda 	osize = sizeof (*orsrcsp) * nrsrc;
2852309Srsmaeda 	bcopy(rsrcs, orsrcsp, osize);
2862309Srsmaeda 
2872309Srsmaeda 	offset = osize;
2882309Srsmaeda 
2892309Srsmaeda 	/*
2902309Srsmaeda 	 * Loop through all the resources and concatenate
2912309Srsmaeda 	 * all the error strings to the end of the resource
2922309Srsmaeda 	 * array. Also, update the offset field of each
2932309Srsmaeda 	 * resource.
2942309Srsmaeda 	 */
2952309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
2962309Srsmaeda 
2972309Srsmaeda 		str = (char *)(uintptr_t)rsrcs[idx].offset;
2982309Srsmaeda 
2992309Srsmaeda 		/* skip if no error string */
3002309Srsmaeda 		if (str == NULL)
3012309Srsmaeda 			continue;
3022309Srsmaeda 
3032309Srsmaeda 		len = strlen(str) + 1;
3042309Srsmaeda 
3052309Srsmaeda 		/* increase the size of the buffer */
3062309Srsmaeda 		resizep = realloc(orsrcsp, osize + len);
3072309Srsmaeda 		if (resizep == NULL) {
3082309Srsmaeda 			drd_err("realloc failed: %s", strerror(errno));
3092309Srsmaeda 			s_free(orsrcsp);
3102309Srsmaeda 
3112309Srsmaeda 			/* clean up any remaining strings */
3122309Srsmaeda 			while (idx < nrsrc) {
3132309Srsmaeda 				str = (char *)(uintptr_t)rsrcs[idx++].offset;
3142309Srsmaeda 				s_free(str);
3152309Srsmaeda 			}
3162309Srsmaeda 			return (0);
3172309Srsmaeda 		}
3182309Srsmaeda 
3192309Srsmaeda 		orsrcsp = resizep;
3202309Srsmaeda 
3212309Srsmaeda 		/* copy the error string into the response */
3222309Srsmaeda 		off = (char *)orsrcsp + offset;
3232309Srsmaeda 		bcopy(str, off, len);
3242309Srsmaeda 		orsrcsp[idx].offset = offset;
3252309Srsmaeda 
3262309Srsmaeda 		/*
3272309Srsmaeda 		 * Now that the error string has been copied
3282309Srsmaeda 		 * into the response message, the memory that
3292309Srsmaeda 		 * was allocated for it is no longer needed.
3302309Srsmaeda 		 */
3312309Srsmaeda 		s_free(str);
3322309Srsmaeda 		rsrcs[idx].offset = 0;
3332309Srsmaeda 
3342309Srsmaeda 		/* update size and offset */
3352309Srsmaeda 		offset += len;
3362309Srsmaeda 		osize += len;
3372309Srsmaeda 	}
3382309Srsmaeda 
3392309Srsmaeda 	drd_result = orsrcsp;
3402309Srsmaeda 	return (osize);
3412309Srsmaeda }
3422309Srsmaeda 
3432309Srsmaeda /*ARGSUSED*/
3442309Srsmaeda static void
drd_door_server(void * cookie,char * argp,size_t arg_sz,door_desc_t * dp,uint_t n_desc)3452309Srsmaeda drd_door_server(void *cookie, char *argp, size_t arg_sz, door_desc_t *dp,
3462309Srsmaeda     uint_t n_desc)
3472309Srsmaeda {
3482309Srsmaeda 	drd_msg_t	*msg = (drd_msg_t *)(uintptr_t)argp;
3492309Srsmaeda 	drctl_rsrc_t	*rsrcs;
3502309Srsmaeda 	size_t		osize;
3512309Srsmaeda 	int		nrsrc;
3522309Srsmaeda 
3532309Srsmaeda 	drd_dbg("drd_door_server...");
3542309Srsmaeda 	drd_dbg("message received: %d bytes", arg_sz);
3552309Srsmaeda 
3562309Srsmaeda 	/* sanity check incoming arg */
3572309Srsmaeda 	if ((argp == NULL) || (arg_sz == 0))
3582309Srsmaeda 		DRD_DOOR_RETURN_ERR();
3592309Srsmaeda 
3602309Srsmaeda 	drd_dbg("  cmd=%d, count=%d, flags=%d", msg->cmd,
3612309Srsmaeda 	    msg->count, msg->flags);
3622309Srsmaeda 
3632309Srsmaeda 	rsrcs = (drctl_rsrc_t *)(uintptr_t)msg->data;
3642309Srsmaeda 	nrsrc = msg->count;
3652309Srsmaeda 
3662309Srsmaeda 	/* pass off to backend for processing */
3672309Srsmaeda 	switch (msg->cmd) {
3682309Srsmaeda 	case DRCTL_CPU_CONFIG_REQUEST:
3692309Srsmaeda 		(*drd_backend->cpu_config_request)(rsrcs, nrsrc);
3702309Srsmaeda 		break;
3712309Srsmaeda 
3722309Srsmaeda 	case DRCTL_CPU_CONFIG_NOTIFY:
3732309Srsmaeda 		(*drd_backend->cpu_config_notify)(rsrcs, nrsrc);
3742309Srsmaeda 		break;
3752309Srsmaeda 
3762309Srsmaeda 	case DRCTL_CPU_UNCONFIG_REQUEST:
3772309Srsmaeda 		(*drd_backend->cpu_unconfig_request)(rsrcs, nrsrc);
3782309Srsmaeda 		break;
3792309Srsmaeda 
3802309Srsmaeda 	case DRCTL_CPU_UNCONFIG_NOTIFY:
3812309Srsmaeda 		(*drd_backend->cpu_unconfig_notify)(rsrcs, nrsrc);
3822309Srsmaeda 		break;
3832309Srsmaeda 
3842309Srsmaeda 	case DRCTL_MEM_CONFIG_REQUEST:
385*10106SJason.Beloro@Sun.COM 		(*drd_backend->mem_config_request)(rsrcs, nrsrc);
386*10106SJason.Beloro@Sun.COM 		break;
387*10106SJason.Beloro@Sun.COM 
3882309Srsmaeda 	case DRCTL_MEM_CONFIG_NOTIFY:
389*10106SJason.Beloro@Sun.COM 		(*drd_backend->mem_config_notify)(rsrcs, nrsrc);
390*10106SJason.Beloro@Sun.COM 		break;
391*10106SJason.Beloro@Sun.COM 
3922309Srsmaeda 	case DRCTL_MEM_UNCONFIG_REQUEST:
393*10106SJason.Beloro@Sun.COM 		(*drd_backend->mem_unconfig_request)(rsrcs, nrsrc);
394*10106SJason.Beloro@Sun.COM 		break;
395*10106SJason.Beloro@Sun.COM 
3962309Srsmaeda 	case DRCTL_MEM_UNCONFIG_NOTIFY:
397*10106SJason.Beloro@Sun.COM 		(*drd_backend->mem_unconfig_notify)(rsrcs, nrsrc);
3982309Srsmaeda 		break;
3992309Srsmaeda 
4002309Srsmaeda 	case DRCTL_IO_CONFIG_REQUEST:
4016441Sjm22469 		(*drd_backend->io_config_request)(rsrcs, nrsrc);
4026441Sjm22469 		break;
4036441Sjm22469 
4042309Srsmaeda 	case DRCTL_IO_CONFIG_NOTIFY:
4056441Sjm22469 		(*drd_backend->io_config_notify)(rsrcs, nrsrc);
4066441Sjm22469 		break;
4076441Sjm22469 
4082309Srsmaeda 	case DRCTL_IO_UNCONFIG_REQUEST:
4096441Sjm22469 		(*drd_backend->io_unconfig_request)(rsrcs, nrsrc);
4106441Sjm22469 		break;
4116441Sjm22469 
4122309Srsmaeda 	case DRCTL_IO_UNCONFIG_NOTIFY:
4136441Sjm22469 		(*drd_backend->io_unconfig_notify)(rsrcs, nrsrc);
4142309Srsmaeda 		break;
4152309Srsmaeda 
4162309Srsmaeda 	default:
4172309Srsmaeda 		drd_err("unknown command: %d", msg->cmd);
4182309Srsmaeda 		DRD_DOOR_RETURN_ERR();
4192309Srsmaeda 		break;
4202309Srsmaeda 	}
4212309Srsmaeda 
4222309Srsmaeda 	osize = drd_pack_response(rsrcs, nrsrc);
4232309Srsmaeda 	if (osize == 0)
4242309Srsmaeda 		DRD_DOOR_RETURN_ERR();
4252309Srsmaeda 
4262309Srsmaeda 	(void) door_return((char *)drd_result, osize, NULL, 0);
4272309Srsmaeda }
428