xref: /illumos-gate/usr/src/uts/sun4u/opl/io/oplkmdrv.c (revision bbe1232e)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2125cf1a30Sjl /*
226074f19fSZach Kissel  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2325cf1a30Sjl  * Use is subject to license terms.
2425cf1a30Sjl  */
2525cf1a30Sjl 
2625cf1a30Sjl 
2725cf1a30Sjl /*
2825cf1a30Sjl  * OPL IPSec Key Management Driver.
2925cf1a30Sjl  *
3025cf1a30Sjl  * This driver runs on a OPL Domain. It processes requests received
3125cf1a30Sjl  * from the OPL Service Processor (SP) via mailbox message. It passes
3225cf1a30Sjl  * these requests to the sckmd daemon by means of an /ioctl interface.
3325cf1a30Sjl  *
3425cf1a30Sjl  * Requests received from the SP consist of IPsec security associations
3525cf1a30Sjl  * (SAs) needed to secure the communication between SC and Domain daemons
3625cf1a30Sjl  * communicating using DSCP.
3725cf1a30Sjl  */
3825cf1a30Sjl 
3925cf1a30Sjl #include <sys/types.h>
4025cf1a30Sjl #include <sys/cmn_err.h>
4125cf1a30Sjl #include <sys/kmem.h>
4225cf1a30Sjl #include <sys/errno.h>
4325cf1a30Sjl #include <sys/file.h>
4425cf1a30Sjl #include <sys/open.h>
4525cf1a30Sjl #include <sys/stat.h>
4625cf1a30Sjl #include <sys/conf.h>
4725cf1a30Sjl #include <sys/ddi.h>
4825cf1a30Sjl #include <sys/cmn_err.h>
4925cf1a30Sjl #include <sys/sunddi.h>
5025cf1a30Sjl #include <sys/sunndi.h>
5125cf1a30Sjl #include <sys/ddi_impldefs.h>
5225cf1a30Sjl #include <sys/ndi_impldefs.h>
5325cf1a30Sjl #include <sys/modctl.h>
5425cf1a30Sjl #include <sys/disp.h>
5525cf1a30Sjl #include <sys/note.h>
5625cf1a30Sjl #include <sys/byteorder.h>
5725cf1a30Sjl #include <sys/sdt.h>
5825cf1a30Sjl 
5925cf1a30Sjl #include <sys/scfd/scfdscpif.h>
6025cf1a30Sjl #include <sys/oplkm_msg.h>
6125cf1a30Sjl #include <sys/sckm_io.h>
6225cf1a30Sjl #include <sys/oplkm.h>
6325cf1a30Sjl 
6425cf1a30Sjl #define	OKM_NODENAME	"oplkmdrv"		/* Node name */
6525cf1a30Sjl #define	OKM_TARGET_ID	0			/* Target ID */
6625cf1a30Sjl #define	OKM_SM_TOUT	5000			/* small timeout (5msec) */
6725cf1a30Sjl #define	OKM_LG_TOUT	50000			/* large timeout (50msec) */
6825cf1a30Sjl #define	OKM_MB_TOUT	10000000		/* Mailbox timeout (10sec) */
6925cf1a30Sjl 
7025cf1a30Sjl okms_t okms_global;				/* Global instance structure */
7125cf1a30Sjl 
7225cf1a30Sjl #ifdef DEBUG
7325cf1a30Sjl uint32_t okm_debug = DBG_WARN;
7425cf1a30Sjl #endif
7525cf1a30Sjl 
7625cf1a30Sjl /*
7725cf1a30Sjl  * Prototypes for the module related functions.
7825cf1a30Sjl  */
7925cf1a30Sjl int okm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
8025cf1a30Sjl int okm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
8125cf1a30Sjl int okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
8225cf1a30Sjl int okm_open(dev_t *devp, int flag, int otyp, struct cred *cred);
8325cf1a30Sjl int okm_close(dev_t dev, int flag, int otyp, struct cred *cred);
8425cf1a30Sjl int okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag,
8525cf1a30Sjl 		cred_t *cred, int *rvalp);
8625cf1a30Sjl 
8725cf1a30Sjl /*
8825cf1a30Sjl  * Prototypes for the internal functions.
8925cf1a30Sjl  */
9025cf1a30Sjl int okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp,
9125cf1a30Sjl     intptr_t data, int flag);
9225cf1a30Sjl int okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len,
9325cf1a30Sjl     sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag);
9425cf1a30Sjl int okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply);
9525cf1a30Sjl void okm_event_handler(scf_event_t event, void *arg);
9625cf1a30Sjl int okm_send_reply(okms_t *okmsp, uint32_t transid, uint32_t status,
9725cf1a30Sjl     uint32_t sadb_err, uint32_t sadb_ver);
9825cf1a30Sjl int block_until_ready(okms_t *okmsp);
9925cf1a30Sjl static int okm_copyin_ioctl_getreq(intptr_t userarg,
10025cf1a30Sjl     sckm_ioctl_getreq_t *driverarg, int flag);
10125cf1a30Sjl static int okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg,
10225cf1a30Sjl     intptr_t userarg, int flag);
10325cf1a30Sjl static void okm_cleanup(okms_t *okmsp);
10425cf1a30Sjl static int okm_mbox_init(okms_t *okmsp);
10525cf1a30Sjl static void okm_mbox_fini(okms_t *okmsp);
10625cf1a30Sjl static clock_t okm_timeout_val(int error);
10725cf1a30Sjl 
10825cf1a30Sjl 
10925cf1a30Sjl struct cb_ops okm_cb_ops = {
11025cf1a30Sjl 	okm_open,		/* open */
11125cf1a30Sjl 	okm_close,		/* close */
11225cf1a30Sjl 	nodev,			/* strategy */
11325cf1a30Sjl 	nodev,			/* print */
11425cf1a30Sjl 	nodev,			/* dump */
11525cf1a30Sjl 	nodev,			/* read */
11625cf1a30Sjl 	nodev,			/* write */
11725cf1a30Sjl 	okm_ioctl,		/* ioctl */
11825cf1a30Sjl 	nodev,			/* devmap */
11925cf1a30Sjl 	nodev,			/* mmap */
12025cf1a30Sjl 	nodev,			/* segmap */
12125cf1a30Sjl 	nochpoll,		/* poll */
12225cf1a30Sjl 	ddi_prop_op,		/* prop_op */
12325cf1a30Sjl 	0,			/* streamtab  */
12425cf1a30Sjl 	D_NEW | D_MP		/* Driver compatibility flag */
12525cf1a30Sjl };
12625cf1a30Sjl 
12725cf1a30Sjl struct dev_ops okm_ops = {
12825cf1a30Sjl 	DEVO_REV,		/* devo_rev, */
12925cf1a30Sjl 	0,			/* refcnt  */
13025cf1a30Sjl 	okm_info,		/* get_dev_info */
13125cf1a30Sjl 	nulldev,		/* identify */
13225cf1a30Sjl 	nulldev,		/* probe */
13325cf1a30Sjl 	okm_attach,		/* attach */
13425cf1a30Sjl 	okm_detach,		/* detach */
13525cf1a30Sjl 	nodev,			/* reset */
13625cf1a30Sjl 	&okm_cb_ops,		/* driver operations */
13719397407SSherry Moore 	(struct bus_ops *)0,	/* no bus operations */
13819397407SSherry Moore 	NULL,			/* power */
13919397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
14025cf1a30Sjl };
14125cf1a30Sjl 
14225cf1a30Sjl struct modldrv modldrv = {
14325cf1a30Sjl 	&mod_driverops,
14419397407SSherry Moore 	"OPL Key Management Driver",
14525cf1a30Sjl 	&okm_ops,
14625cf1a30Sjl };
14725cf1a30Sjl 
14825cf1a30Sjl struct modlinkage modlinkage = {
14925cf1a30Sjl 	MODREV_1,
15025cf1a30Sjl 	&modldrv,
15125cf1a30Sjl 	NULL
15225cf1a30Sjl };
15325cf1a30Sjl 
15425cf1a30Sjl 
15525cf1a30Sjl /*
15625cf1a30Sjl  * _init - Module's init routine.
15725cf1a30Sjl  */
15825cf1a30Sjl int
_init(void)15925cf1a30Sjl _init(void)
16025cf1a30Sjl {
16125cf1a30Sjl 	int ret;
16225cf1a30Sjl 
16325cf1a30Sjl 	if ((ret = mod_install(&modlinkage)) != 0) {
16425cf1a30Sjl 		cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
16525cf1a30Sjl 	}
16625cf1a30Sjl 	return (ret);
16725cf1a30Sjl }
16825cf1a30Sjl 
16925cf1a30Sjl /*
17025cf1a30Sjl  * _fini - Module's fini routine.
17125cf1a30Sjl  */
17225cf1a30Sjl int
_fini(void)17325cf1a30Sjl _fini(void)
17425cf1a30Sjl {
17525cf1a30Sjl 	int ret;
17625cf1a30Sjl 
17725cf1a30Sjl 	if ((ret = mod_remove(&modlinkage)) != 0) {
17825cf1a30Sjl 		return (ret);
17925cf1a30Sjl 	}
18025cf1a30Sjl 	return (ret);
18125cf1a30Sjl }
18225cf1a30Sjl 
18325cf1a30Sjl /*
18425cf1a30Sjl  * _info - Module's info routine.
18525cf1a30Sjl  */
18625cf1a30Sjl int
_info(struct modinfo * modinfop)18725cf1a30Sjl _info(struct modinfo *modinfop)
18825cf1a30Sjl {
18925cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
19025cf1a30Sjl }
19125cf1a30Sjl 
19225cf1a30Sjl /*
19325cf1a30Sjl  * okm_attach - Module's attach routine.
19425cf1a30Sjl  *
19525cf1a30Sjl  * Description:	Initializes the modules state structure and create
19625cf1a30Sjl  *		the minor device node.
19725cf1a30Sjl  */
19825cf1a30Sjl int
okm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)19925cf1a30Sjl okm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
20025cf1a30Sjl {
20125cf1a30Sjl 	int instance;
20225cf1a30Sjl 	okms_t *okmsp = &okms_global;
20325cf1a30Sjl 
20425cf1a30Sjl 	instance = ddi_get_instance(dip);
20525cf1a30Sjl 
20625cf1a30Sjl 	/* Only one instance is supported.  */
20725cf1a30Sjl 	if (instance != 0) {
20825cf1a30Sjl 		return (DDI_FAILURE);
20925cf1a30Sjl 	}
21025cf1a30Sjl 
21125cf1a30Sjl 	if (cmd != DDI_ATTACH) {
21225cf1a30Sjl 		return (DDI_FAILURE);
21325cf1a30Sjl 	}
21425cf1a30Sjl 
21525cf1a30Sjl 	okmsp->km_dip = dip;
2165c066ec2SJerry Gilliam 	okmsp->km_major = ddi_driver_major(dip);
21725cf1a30Sjl 	okmsp->km_inst = instance;
21825cf1a30Sjl 
21925cf1a30Sjl 	/*
22025cf1a30Sjl 	 * Get an interrupt block cookie corresponding to the
22125cf1a30Sjl 	 * interrupt priority of the event handler.
22225cf1a30Sjl 	 * Assert that the event priority is not redefined to
22325cf1a30Sjl 	 * some other priority.
22425cf1a30Sjl 	 */
22525cf1a30Sjl 	/* LINTED */
22625cf1a30Sjl 	ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
22725cf1a30Sjl 	if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
22825cf1a30Sjl 	    &okmsp->km_ibcookie) != DDI_SUCCESS) {
22925cf1a30Sjl 		cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
23025cf1a30Sjl 		return (DDI_FAILURE);
23125cf1a30Sjl 	}
23225cf1a30Sjl 	mutex_init(&okmsp->km_lock, NULL, MUTEX_DRIVER,
23325cf1a30Sjl 	    (void *)okmsp->km_ibcookie);
23425cf1a30Sjl 	okmsp->km_clean |= OKM_CLEAN_LOCK;
23525cf1a30Sjl 	cv_init(&okmsp->km_wait, NULL, CV_DRIVER, NULL);
23625cf1a30Sjl 	okmsp->km_clean |= OKM_CLEAN_CV;
23725cf1a30Sjl 
23825cf1a30Sjl 	/*
23925cf1a30Sjl 	 * set clean_node ahead as remove_node has to be called even
24025cf1a30Sjl 	 * if create node fails.
24125cf1a30Sjl 	 */
24225cf1a30Sjl 	okmsp->km_clean |= OKM_CLEAN_NODE;
24325cf1a30Sjl 	if (ddi_create_minor_node(dip, OKM_NODENAME, S_IFCHR,
244*bbe1232eSToomas Soome 	    instance, NULL, 0) == DDI_FAILURE) {
24525cf1a30Sjl 		cmn_err(CE_WARN, "Device node creation failed");
24625cf1a30Sjl 		okm_cleanup(okmsp);
24725cf1a30Sjl 		return (DDI_FAILURE);
24825cf1a30Sjl 	}
24925cf1a30Sjl 
25025cf1a30Sjl 	ddi_set_driver_private(dip, (caddr_t)okmsp);
25125cf1a30Sjl 	ddi_report_dev(dip);
25225cf1a30Sjl 	return (DDI_SUCCESS);
25325cf1a30Sjl }
25425cf1a30Sjl 
25525cf1a30Sjl /*
25625cf1a30Sjl  * okm_detach - Module's detach routine.
25725cf1a30Sjl  *
25825cf1a30Sjl  * Description:	Cleans up the module's state structures and any other
25925cf1a30Sjl  *		relevant data.
26025cf1a30Sjl  */
26125cf1a30Sjl int
okm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)26225cf1a30Sjl okm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
26325cf1a30Sjl {
26425cf1a30Sjl 	okms_t *okmsp;
26525cf1a30Sjl 
26625cf1a30Sjl 	if (cmd != DDI_DETACH) {
26725cf1a30Sjl 		return (DDI_FAILURE);
26825cf1a30Sjl 	}
26925cf1a30Sjl 
27025cf1a30Sjl 	if ((okmsp = ddi_get_driver_private(dip)) == NULL) {
27125cf1a30Sjl 		return (DDI_FAILURE);
27225cf1a30Sjl 	}
27325cf1a30Sjl 
27425cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
27525cf1a30Sjl 	/*
27625cf1a30Sjl 	 * Check if the mailbox is still in use.
27725cf1a30Sjl 	 */
27825cf1a30Sjl 	if (okmsp->km_state & OKM_MB_INITED) {
27925cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
28025cf1a30Sjl 		cmn_err(CE_WARN, "Detach failure: Mailbox in use");
28125cf1a30Sjl 		return (DDI_FAILURE);
28225cf1a30Sjl 	}
28325cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
28425cf1a30Sjl 	okm_cleanup(okmsp);
28525cf1a30Sjl 	ddi_set_driver_private(dip, NULL);
28625cf1a30Sjl 	return (DDI_SUCCESS);
28725cf1a30Sjl }
28825cf1a30Sjl 
28925cf1a30Sjl /*
29025cf1a30Sjl  * okm_info - Module's info routine.
29125cf1a30Sjl  */
29225cf1a30Sjl /* ARGSUSED */
29325cf1a30Sjl int
okm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)29425cf1a30Sjl okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
29525cf1a30Sjl {
2966074f19fSZach Kissel 	okms_t	*okmsp = &okms_global;
29725cf1a30Sjl 	minor_t	minor;
29825cf1a30Sjl 	int	ret = DDI_FAILURE;
29925cf1a30Sjl 
30025cf1a30Sjl 	switch (infocmd) {
30125cf1a30Sjl 	case DDI_INFO_DEVT2DEVINFO:
3026074f19fSZach Kissel 		/*
3036074f19fSZach Kissel 		 * We have the case here where the minor number
3046074f19fSZach Kissel 		 * is the same as the instance number. So, just
3056074f19fSZach Kissel 		 * make sure we have the right minor node in our
3066074f19fSZach Kissel 		 * global state. If we don't, set the result to NULL.
3076074f19fSZach Kissel 		 */
30825cf1a30Sjl 		minor = getminor((dev_t)arg);
3096074f19fSZach Kissel 		if (okmsp->km_inst != minor) {
31025cf1a30Sjl 			*result = NULL;
31125cf1a30Sjl 		} else {
31225cf1a30Sjl 			*result = okmsp->km_dip;
31325cf1a30Sjl 			ret = DDI_SUCCESS;
31425cf1a30Sjl 		}
31525cf1a30Sjl 		break;
31625cf1a30Sjl 
31725cf1a30Sjl 	case DDI_INFO_DEVT2INSTANCE:
31825cf1a30Sjl 		minor = getminor((dev_t)arg);
31925cf1a30Sjl 		*result = (void *)(uintptr_t)minor;
32025cf1a30Sjl 		ret = DDI_SUCCESS;
32125cf1a30Sjl 
32225cf1a30Sjl 	default:
32325cf1a30Sjl 		break;
32425cf1a30Sjl 	}
32525cf1a30Sjl 	return (ret);
32625cf1a30Sjl }
32725cf1a30Sjl 
32825cf1a30Sjl /*
32925cf1a30Sjl  * okm_open - Device open routine.
33025cf1a30Sjl  *
33125cf1a30Sjl  * Description:	Initializes the mailbox and waits until the mailbox
33225cf1a30Sjl  *		gets connected. Only one open at a time is supported.
33325cf1a30Sjl  */
33425cf1a30Sjl /*ARGSUSED*/
33525cf1a30Sjl int
okm_open(dev_t * devp,int flag,int otyp,struct cred * cred)33625cf1a30Sjl okm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
33725cf1a30Sjl {
33825cf1a30Sjl 	okms_t *okmsp = &okms_global;
33925cf1a30Sjl 	int ret = 0;
34025cf1a30Sjl 
34125cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_open: called\n"));
34225cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
34325cf1a30Sjl 	if (okmsp->km_state & OKM_OPENED) {
34425cf1a30Sjl 		/* Only one open supported */
34525cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
34625cf1a30Sjl 		DPRINTF(DBG_WARN, ("okm_open: already opened\n"));
34725cf1a30Sjl 		return (EBUSY);
34825cf1a30Sjl 	}
34925cf1a30Sjl 	okmsp->km_state |= OKM_OPENED;
35025cf1a30Sjl 	ret = block_until_ready(okmsp);
35125cf1a30Sjl 	if (ret != 0) {
35225cf1a30Sjl 		okmsp->km_state &= ~OKM_OPENED;
35325cf1a30Sjl 	}
35425cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
35525cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_open: ret=%d\n", ret));
35625cf1a30Sjl 	return (ret);
35725cf1a30Sjl }
35825cf1a30Sjl 
35925cf1a30Sjl /*
36025cf1a30Sjl  * block_until_ready - Function to wait until the mailbox is ready to use.
36125cf1a30Sjl  *
36225cf1a30Sjl  * Description:	It initializes the mailbox and waits for the mailbox
36325cf1a30Sjl  *		state to transition to connected.
36425cf1a30Sjl  */
36525cf1a30Sjl int
block_until_ready(okms_t * okmsp)36625cf1a30Sjl block_until_ready(okms_t *okmsp)
36725cf1a30Sjl {
36825cf1a30Sjl 	int ret = 0;
36925cf1a30Sjl 
37025cf1a30Sjl 	DPRINTF(DBG_DRV, ("block_until_ready: called\n"));
37125cf1a30Sjl 	ASSERT(MUTEX_HELD(&okmsp->km_lock));
37225cf1a30Sjl 
37325cf1a30Sjl 	if (okmsp->km_state & OKM_MB_DISC) {
37425cf1a30Sjl 		DPRINTF(DBG_DRV, ("block_until_ready: closing the mailbox\n"));
37525cf1a30Sjl 		okm_mbox_fini(okmsp);
37625cf1a30Sjl 	}
37725cf1a30Sjl 	if (okmsp->km_state & OKM_MB_CONN) {
37825cf1a30Sjl 		DPRINTF(DBG_DRV, ("block_until_ready: mailbox connected\n"));
37925cf1a30Sjl 		return (0);
38025cf1a30Sjl 	}
38125cf1a30Sjl 	/*
38225cf1a30Sjl 	 * Initialize mailbox.
38325cf1a30Sjl 	 */
38425cf1a30Sjl 	if ((ret = okm_mbox_init(okmsp)) != 0) {
38525cf1a30Sjl 		DPRINTF(DBG_MBOX,
38625cf1a30Sjl 		    ("block_until_ready: mailbox init failed ret=%d\n", ret));
38725cf1a30Sjl 		return (ret);
38825cf1a30Sjl 	}
38925cf1a30Sjl 	DPRINTF(DBG_DRV, ("block_until_ready: ret=%d", ret));
39025cf1a30Sjl 	return (ret);
39125cf1a30Sjl }
39225cf1a30Sjl 
39325cf1a30Sjl /*
39425cf1a30Sjl  * okm_close - Device close routine.
39525cf1a30Sjl  *
39625cf1a30Sjl  * Description: Closes the mailbox.
39725cf1a30Sjl  */
39825cf1a30Sjl /*ARGSUSED*/
39925cf1a30Sjl int
okm_close(dev_t dev,int flag,int otyp,struct cred * cred)40025cf1a30Sjl okm_close(dev_t dev, int flag, int otyp, struct cred *cred)
40125cf1a30Sjl {
40225cf1a30Sjl 	okms_t *okmsp = &okms_global;
40325cf1a30Sjl 
40425cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_close: called\n"));
40525cf1a30Sjl 	/* Close the lower layer first */
40625cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
40725cf1a30Sjl 	okm_mbox_fini(okmsp);
40825cf1a30Sjl 	okmsp->km_state = 0;
40925cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
41025cf1a30Sjl 	return (0);
41125cf1a30Sjl }
41225cf1a30Sjl 
41325cf1a30Sjl 
41425cf1a30Sjl /*
41525cf1a30Sjl  * okm_ioctl - Device ioctl routine.
41625cf1a30Sjl  *
41725cf1a30Sjl  * Description:	Processes ioctls from the daemon.
41825cf1a30Sjl  */
41925cf1a30Sjl /*ARGSUSED*/
42025cf1a30Sjl int
okm_ioctl(dev_t dev,int cmd,intptr_t data,int flag,cred_t * cred,int * rvalp)42125cf1a30Sjl okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
42225cf1a30Sjl {
42325cf1a30Sjl 	okms_t *okmsp = &okms_global;
42425cf1a30Sjl 	sckm_ioctl_getreq_t ireq;
42525cf1a30Sjl 	sckm_ioctl_status_t istatus;
42625cf1a30Sjl 	int ret = 0;
42725cf1a30Sjl 
42825cf1a30Sjl 	switch (cmd) {
42925cf1a30Sjl 	case SCKM_IOCTL_GETREQ:
43025cf1a30Sjl 
43125cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ\n"));
43225cf1a30Sjl 		if (okm_copyin_ioctl_getreq(data, &ireq, flag)) {
43325cf1a30Sjl 			return (EFAULT);
43425cf1a30Sjl 		}
43525cf1a30Sjl 
43625cf1a30Sjl 		ret = okm_get_req(okmsp, &ireq, data, flag);
43725cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ ret=%d\n", ret));
43825cf1a30Sjl 		break;
43925cf1a30Sjl 
44025cf1a30Sjl 	case SCKM_IOCTL_STATUS:
44125cf1a30Sjl 
44225cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_ioctl: STATUS\n"));
44325cf1a30Sjl 		if (ddi_copyin((caddr_t)data, &istatus,
44425cf1a30Sjl 		    sizeof (sckm_ioctl_status_t), flag)) {
44525cf1a30Sjl 			return (EFAULT);
44625cf1a30Sjl 		}
44725cf1a30Sjl 		ret = okm_process_status(okmsp, &istatus);
44825cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_ioctl: STATUS ret=%d\n", ret));
44925cf1a30Sjl 		break;
45025cf1a30Sjl 
45125cf1a30Sjl 	default:
45225cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_ioctl: UNKNOWN ioctl\n"));
45325cf1a30Sjl 		ret = EINVAL;
45425cf1a30Sjl 	}
45525cf1a30Sjl 	return (ret);
45625cf1a30Sjl }
45725cf1a30Sjl 
45825cf1a30Sjl /*
45925cf1a30Sjl  * okm_get_req - Get a request from the mailbox.
46025cf1a30Sjl  *
46125cf1a30Sjl  * Description:	It blocks until a message is received, then processes
46225cf1a30Sjl  *		the message and returns it to the requestor.
46325cf1a30Sjl  */
46425cf1a30Sjl int
okm_get_req(okms_t * okmsp,sckm_ioctl_getreq_t * ireqp,intptr_t data,int flag)46525cf1a30Sjl okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag)
46625cf1a30Sjl {
46725cf1a30Sjl 	okm_req_hdr_t *reqp;
46825cf1a30Sjl 	caddr_t msgbuf;
46925cf1a30Sjl 	uint32_t len;
47025cf1a30Sjl 	int ret;
47125cf1a30Sjl 
47225cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_getreq: called\n"));
47325cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
47425cf1a30Sjl 	if ((ret = block_until_ready(okmsp)) != 0) {
47525cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
47625cf1a30Sjl 		DPRINTF(DBG_WARN, ("okm_getreq: failed ret=%d\n", ret));
47725cf1a30Sjl 		return (ret);
47825cf1a30Sjl 	}
47925cf1a30Sjl 
48025cf1a30Sjl 	if (okmsp->km_reqp != NULL) {
48125cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_getreq: req cached\n"));
48225cf1a30Sjl 		reqp = okmsp->km_reqp;
48325cf1a30Sjl 		len = okmsp->km_reqlen;
48425cf1a30Sjl 		okmsp->km_reqp = NULL;
48525cf1a30Sjl 		okmsp->km_reqlen = 0;
48625cf1a30Sjl 	} else {
48725cf1a30Sjl retry:
48825cf1a30Sjl 		while (OKM_MBOX_READY(okmsp) &&
48925cf1a30Sjl 		    ((ret = scf_mb_canget(okmsp->km_target,
49025cf1a30Sjl 		    okmsp->km_key, &len)) != 0)) {
49125cf1a30Sjl 			if (ret != ENOMSG) {
49225cf1a30Sjl 				DPRINTF(DBG_WARN, ("okm_getreq: Unknown "
49325cf1a30Sjl 				    "mbox failure=%d\n", ret));
49425cf1a30Sjl 				mutex_exit(&okmsp->km_lock);
49525cf1a30Sjl 				return (EIO);
49625cf1a30Sjl 			}
49725cf1a30Sjl 			DPRINTF(DBG_MBOX, ("okm_getreq: waiting for mesg\n"));
49825cf1a30Sjl 			if (cv_wait_sig(&okmsp->km_wait,
49925cf1a30Sjl 			    &okmsp->km_lock) <= 0) {
50025cf1a30Sjl 				mutex_exit(&okmsp->km_lock);
50125cf1a30Sjl 				DPRINTF(DBG_DRV, ("okm_getreq:interrupted\n"));
50225cf1a30Sjl 				return (EINTR);
50325cf1a30Sjl 			}
50425cf1a30Sjl 		}
50525cf1a30Sjl 		if (!OKM_MBOX_READY(okmsp)) {
50625cf1a30Sjl 			mutex_exit(&okmsp->km_lock);
50725cf1a30Sjl 			DPRINTF(DBG_WARN, ("okm_getreq: mailbox not ready\n"));
50825cf1a30Sjl 			return (EIO);
50925cf1a30Sjl 		}
51025cf1a30Sjl 		ASSERT(len != 0);
51125cf1a30Sjl 		msgbuf = kmem_alloc(len, KM_SLEEP);
51225cf1a30Sjl 		okmsp->km_sg_rcv.msc_dptr = msgbuf;
51325cf1a30Sjl 		okmsp->km_sg_rcv.msc_len = len;
51425cf1a30Sjl 
51525cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_getreq: getmsg\n"));
51625cf1a30Sjl 		ret = scf_mb_getmsg(okmsp->km_target, okmsp->km_key, len, 1,
51725cf1a30Sjl 		    &okmsp->km_sg_rcv, 0);
51825cf1a30Sjl 		if (ret == ENOMSG || ret == EMSGSIZE) {
51925cf1a30Sjl 			kmem_free(msgbuf, len);
52025cf1a30Sjl 			DPRINTF(DBG_MBOX, ("okm_getreq: nomsg ret=%d\n", ret));
52125cf1a30Sjl 			goto retry;
52225cf1a30Sjl 		} else if (ret != 0) {
52325cf1a30Sjl 			kmem_free(msgbuf, len);
52425cf1a30Sjl 			mutex_exit(&okmsp->km_lock);
52525cf1a30Sjl 			DPRINTF(DBG_WARN,
52625cf1a30Sjl 			    ("okm_getreq: Unknown mbox failure=%d\n", ret));
52725cf1a30Sjl 			return (EIO);
52825cf1a30Sjl 		}
52925cf1a30Sjl 
53025cf1a30Sjl 		/* check message length */
53125cf1a30Sjl 		if (len < sizeof (okm_req_hdr_t)) {
53225cf1a30Sjl 			/* protocol error, drop message */
53325cf1a30Sjl 			kmem_free(msgbuf, len);
53425cf1a30Sjl 			mutex_exit(&okmsp->km_lock);
53525cf1a30Sjl 			DPRINTF(DBG_WARN, ("okm_getreq: Bad message\n"));
53625cf1a30Sjl 			return (EBADMSG);
53725cf1a30Sjl 		}
53825cf1a30Sjl 
53925cf1a30Sjl 		reqp = (okm_req_hdr_t *)msgbuf;
54025cf1a30Sjl 		reqp->krq_version = ntohl(reqp->krq_version);
54125cf1a30Sjl 		reqp->krq_transid = ntohl(reqp->krq_transid);
54225cf1a30Sjl 		reqp->krq_cmd = ntohl(reqp->krq_cmd);
54325cf1a30Sjl 		reqp->krq_reserved = ntohl(reqp->krq_reserved);
54425cf1a30Sjl 
54525cf1a30Sjl 		/* check version of the message received */
54625cf1a30Sjl 		if (reqp->krq_version != OKM_PROTOCOL_VERSION) {
54707d06da5SSurya Prakki 			(void) okm_send_reply(okmsp, reqp->krq_transid,
54825cf1a30Sjl 			    OKM_ERR_VERSION, 0, 0);
54925cf1a30Sjl 			kmem_free(msgbuf, len);
55025cf1a30Sjl 			mutex_exit(&okmsp->km_lock);
55125cf1a30Sjl 			DPRINTF(DBG_WARN, ("okm_getreq: Unknown version=%d\n",
55225cf1a30Sjl 			    reqp->krq_version));
55325cf1a30Sjl 			return (EBADMSG);
55425cf1a30Sjl 		}
55525cf1a30Sjl 	}
55625cf1a30Sjl 
55725cf1a30Sjl 	/* process message */
55825cf1a30Sjl 	ret = okm_process_req(okmsp, reqp, len, ireqp, data, flag);
55925cf1a30Sjl 	if (okmsp->km_reqp == NULL) {
56025cf1a30Sjl 		/*
56125cf1a30Sjl 		 * The message is not saved, so free the buffer.
56225cf1a30Sjl 		 */
56325cf1a30Sjl 		kmem_free(reqp, len);
56425cf1a30Sjl 	}
56525cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
56625cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_getreq: ret=%d\n", ret));
56725cf1a30Sjl 	return (ret);
56825cf1a30Sjl }
56925cf1a30Sjl 
57025cf1a30Sjl 
57125cf1a30Sjl /*
57225cf1a30Sjl  * okm_process_req - Process the request.
57325cf1a30Sjl  *
57425cf1a30Sjl  * Description:	Validate the request and then give the request to the
57525cf1a30Sjl  *		daemon.
57625cf1a30Sjl  */
57725cf1a30Sjl int
okm_process_req(okms_t * okmsp,okm_req_hdr_t * reqp,uint32_t len,sckm_ioctl_getreq_t * ireqp,intptr_t data,int flag)57825cf1a30Sjl okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len,
57925cf1a30Sjl     sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag)
58025cf1a30Sjl {
58125cf1a30Sjl 	void *req_datap = (void *)(((char *)reqp) + sizeof (okm_req_hdr_t));
58225cf1a30Sjl 	int sadb_msglen = len - sizeof (okm_req_hdr_t);
58325cf1a30Sjl 
58425cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_process_req: called\n"));
58525cf1a30Sjl 	DUMP_REQ(reqp, len);
58625cf1a30Sjl 
58725cf1a30Sjl 	switch (reqp->krq_cmd) {
58825cf1a30Sjl 	case OKM_MSG_SADB:
58925cf1a30Sjl 		/* sanity check request */
59025cf1a30Sjl 		if (sadb_msglen <= 0) {
59107d06da5SSurya Prakki 			(void) okm_send_reply(okmsp, reqp->krq_transid,
59225cf1a30Sjl 			    OKM_ERR_SADB_MSG, 0, 0);
59325cf1a30Sjl 			DPRINTF(DBG_WARN, ("okm_process_req: bad message\n"));
59425cf1a30Sjl 			return (EBADMSG);
59525cf1a30Sjl 		}
59625cf1a30Sjl 
59725cf1a30Sjl 		/*
59825cf1a30Sjl 		 * Save the message, prior to giving it to the daemon.
59925cf1a30Sjl 		 */
60025cf1a30Sjl 		okmsp->km_reqp = reqp;
60125cf1a30Sjl 		okmsp->km_reqlen = len;
60225cf1a30Sjl 
60325cf1a30Sjl 		if (ireqp->buf_len < len) {
60425cf1a30Sjl 			DPRINTF(DBG_WARN,
60525cf1a30Sjl 			    ("okm_process_req: not enough space\n"));
60625cf1a30Sjl 			return (ENOSPC);
60725cf1a30Sjl 		}
60825cf1a30Sjl 
60925cf1a30Sjl 		ireqp->transid = reqp->krq_transid;
61025cf1a30Sjl 		ireqp->type = SCKM_IOCTL_REQ_SADB;
61125cf1a30Sjl 		if (ddi_copyout(req_datap, ireqp->buf, sadb_msglen, flag)) {
61225cf1a30Sjl 			DPRINTF(DBG_WARN,
61325cf1a30Sjl 			    ("okm_process_req: copyout failed\n"));
61425cf1a30Sjl 			return (EFAULT);
61525cf1a30Sjl 		}
61625cf1a30Sjl 		ireqp->buf_len = sadb_msglen;
61725cf1a30Sjl 		if (okm_copyout_ioctl_getreq(ireqp, data, flag)) {
61825cf1a30Sjl 			DPRINTF(DBG_WARN,
61925cf1a30Sjl 			    ("okm_process_req: copyout failed\n"));
62025cf1a30Sjl 			return (EFAULT);
62125cf1a30Sjl 		}
62225cf1a30Sjl 		break;
62325cf1a30Sjl 
62425cf1a30Sjl 	default:
62525cf1a30Sjl 		cmn_err(CE_WARN, "Unknown cmd 0x%x received", reqp->krq_cmd);
62625cf1a30Sjl 		/*
62725cf1a30Sjl 		 * Received an unknown command, send corresponding
62825cf1a30Sjl 		 * error message.
62925cf1a30Sjl 		 */
63007d06da5SSurya Prakki 		(void) okm_send_reply(okmsp, reqp->krq_transid,
63107d06da5SSurya Prakki 		    OKM_ERR_BAD_CMD, 0, 0);
63225cf1a30Sjl 		return (EBADMSG);
63325cf1a30Sjl 	}
63425cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_process_req: ret=0\n"));
63525cf1a30Sjl 	return (0);
63625cf1a30Sjl }
63725cf1a30Sjl 
63825cf1a30Sjl /*
63925cf1a30Sjl  * okm_process_status - Process the status from the daemon.
64025cf1a30Sjl  *
64125cf1a30Sjl  * Description:	Processes the status received from the daemon and sends
64225cf1a30Sjl  *		corresponding message to the SP.
64325cf1a30Sjl  */
64425cf1a30Sjl int
okm_process_status(okms_t * okmsp,sckm_ioctl_status_t * ireply)64525cf1a30Sjl okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply)
64625cf1a30Sjl {
64725cf1a30Sjl 	uint32_t status;
64825cf1a30Sjl 	uint32_t sadb_msg_errno = 0;
64925cf1a30Sjl 	uint32_t sadb_msg_version = 0;
65025cf1a30Sjl 	okm_req_hdr_t *reqp = okmsp->km_reqp;
65125cf1a30Sjl 	int ret;
65225cf1a30Sjl 
65325cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_process_status: called\n"));
65425cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
65525cf1a30Sjl 	if ((ret = block_until_ready(okmsp)) != 0) {
65625cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
65725cf1a30Sjl 		DPRINTF(DBG_WARN,
65825cf1a30Sjl 		    ("okm_process_status: Unknown failure=%d\n", ret));
65925cf1a30Sjl 		return (ret);
66025cf1a30Sjl 	}
66125cf1a30Sjl 
66225cf1a30Sjl 	/* fail if no status is expected, or if it does not match */
66325cf1a30Sjl 	if (!okmsp->km_reqp || (reqp->krq_transid != ireply->transid)) {
66425cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
66525cf1a30Sjl 		DPRINTF(DBG_WARN,
66625cf1a30Sjl 		    ("okm_process_status: req/transid mismatch\n"));
66725cf1a30Sjl 		return (EINVAL);
66825cf1a30Sjl 	}
66925cf1a30Sjl 
67025cf1a30Sjl 	switch (ireply->status) {
67125cf1a30Sjl 	case SCKM_IOCTL_STAT_SUCCESS:
67225cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: SUCCESS\n"));
67325cf1a30Sjl 		status = OKM_SUCCESS;
67425cf1a30Sjl 		break;
67525cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_PFKEY:
67625cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: PFKEY ERROR\n"));
67725cf1a30Sjl 		status = OKM_ERR_SADB_PFKEY;
67825cf1a30Sjl 		sadb_msg_errno = ireply->sadb_msg_errno;
67925cf1a30Sjl 		break;
68025cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_REQ:
68125cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: REQ ERROR\n"));
68225cf1a30Sjl 		status = OKM_ERR_DAEMON;
68325cf1a30Sjl 		break;
68425cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_VERSION:
68525cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: SADB VERSION ERROR\n"));
68625cf1a30Sjl 		status = OKM_ERR_SADB_VERSION;
68725cf1a30Sjl 		sadb_msg_version = ireply->sadb_msg_version;
68825cf1a30Sjl 		break;
68925cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_TIMEOUT:
69025cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: TIMEOUT ERR\n"));
69125cf1a30Sjl 		status = OKM_ERR_SADB_TIMEOUT;
69225cf1a30Sjl 		break;
69325cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_OTHER:
69425cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: OTHER ERR\n"));
69525cf1a30Sjl 		status = OKM_ERR_DAEMON;
69625cf1a30Sjl 		break;
69725cf1a30Sjl 	case SCKM_IOCTL_STAT_ERR_SADB_TYPE:
69825cf1a30Sjl 		DPRINTF(DBG_DRV, ("okm_process_status: SADB TYPE ERR\n"));
69925cf1a30Sjl 		status = OKM_ERR_SADB_BAD_TYPE;
70025cf1a30Sjl 		break;
70125cf1a30Sjl 	default:
70225cf1a30Sjl 		cmn_err(CE_WARN, "SCKM daemon returned invalid status %d\n",
70325cf1a30Sjl 		    ireply->status);
70425cf1a30Sjl 		status = OKM_ERR_DAEMON;
70525cf1a30Sjl 	}
70625cf1a30Sjl 	ret = okm_send_reply(okmsp, ireply->transid, status,
70725cf1a30Sjl 	    sadb_msg_errno, sadb_msg_version);
70825cf1a30Sjl 	/*
70925cf1a30Sjl 	 * Clean up the cached request now.
71025cf1a30Sjl 	 */
71125cf1a30Sjl 	if (ret == 0) {
71225cf1a30Sjl 		kmem_free(okmsp->km_reqp, okmsp->km_reqlen);
71325cf1a30Sjl 		okmsp->km_reqp = NULL;
71425cf1a30Sjl 		okmsp->km_reqlen = 0;
71525cf1a30Sjl 	}
71625cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
71725cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_process_status: ret=%d\n", ret));
71825cf1a30Sjl 	return (ret);
71925cf1a30Sjl }
72025cf1a30Sjl 
72125cf1a30Sjl /*
72225cf1a30Sjl  * okm_copyin_ioctl_getreq - copy-in the ioctl request from the daemon.
72325cf1a30Sjl  */
72425cf1a30Sjl 
72525cf1a30Sjl static int
okm_copyin_ioctl_getreq(intptr_t userarg,sckm_ioctl_getreq_t * driverarg,int flag)72625cf1a30Sjl okm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg,
72725cf1a30Sjl     int flag)
72825cf1a30Sjl {
72925cf1a30Sjl #ifdef _MULTI_DATAMODEL
73025cf1a30Sjl 	switch (ddi_model_convert_from(flag & FMODELS)) {
73125cf1a30Sjl 	case DDI_MODEL_ILP32: {
73225cf1a30Sjl 		sckm_ioctl_getreq32_t driverarg32;
73325cf1a30Sjl 		if (ddi_copyin((caddr_t)userarg, &driverarg32,
73425cf1a30Sjl 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
73525cf1a30Sjl 			return (EFAULT);
73625cf1a30Sjl 		}
73725cf1a30Sjl 		driverarg->transid = driverarg32.transid;
73825cf1a30Sjl 		driverarg->type = driverarg32.type;
73925cf1a30Sjl 		driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf;
74025cf1a30Sjl 		driverarg->buf_len = driverarg32.buf_len;
74125cf1a30Sjl 		break;
74225cf1a30Sjl 	}
74325cf1a30Sjl 	case DDI_MODEL_NONE: {
74425cf1a30Sjl 		if (ddi_copyin((caddr_t)userarg, &driverarg,
74525cf1a30Sjl 		    sizeof (sckm_ioctl_getreq_t), flag)) {
74625cf1a30Sjl 			return (EFAULT);
74725cf1a30Sjl 		}
74825cf1a30Sjl 		break;
74925cf1a30Sjl 	}
75025cf1a30Sjl 	}
75125cf1a30Sjl #else /* ! _MULTI_DATAMODEL */
75225cf1a30Sjl 	if (ddi_copyin((caddr_t)userarg, &driverarg,
75325cf1a30Sjl 	    sizeof (sckm_ioctl_getreq_t), flag)) {
75425cf1a30Sjl 		return (EFAULT);
75525cf1a30Sjl 	}
75625cf1a30Sjl #endif /* _MULTI_DATAMODEL */
75725cf1a30Sjl 	return (0);
75825cf1a30Sjl }
75925cf1a30Sjl 
76025cf1a30Sjl 
76125cf1a30Sjl /*
76225cf1a30Sjl  * okm_copyout_ioctl_getreq - copy-out the request to the daemon.
76325cf1a30Sjl  */
76425cf1a30Sjl static int
okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t * driverarg,intptr_t userarg,int flag)76525cf1a30Sjl okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg,
76625cf1a30Sjl     int flag)
76725cf1a30Sjl {
76825cf1a30Sjl #ifdef _MULTI_DATAMODEL
76925cf1a30Sjl 	switch (ddi_model_convert_from(flag & FMODELS)) {
77025cf1a30Sjl 	case DDI_MODEL_ILP32: {
77125cf1a30Sjl 		sckm_ioctl_getreq32_t driverarg32;
77225cf1a30Sjl 		driverarg32.transid = driverarg->transid;
77325cf1a30Sjl 		driverarg32.type = driverarg->type;
77425cf1a30Sjl 		driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf;
77525cf1a30Sjl 		driverarg32.buf_len = driverarg->buf_len;
77625cf1a30Sjl 		if (ddi_copyout(&driverarg32, (caddr_t)userarg,
77725cf1a30Sjl 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
77825cf1a30Sjl 			return (EFAULT);
77925cf1a30Sjl 		}
78025cf1a30Sjl 		break;
78125cf1a30Sjl 	}
78225cf1a30Sjl 	case DDI_MODEL_NONE:
78325cf1a30Sjl 		if (ddi_copyout(driverarg, (caddr_t)userarg,
78425cf1a30Sjl 		    sizeof (sckm_ioctl_getreq_t), flag)) {
78525cf1a30Sjl 			return (EFAULT);
78625cf1a30Sjl 		}
78725cf1a30Sjl 		break;
78825cf1a30Sjl 	}
78925cf1a30Sjl #else /* ! _MULTI_DATAMODEL */
79025cf1a30Sjl 	if (ddi_copyout(driverarg, (caddr_t)userarg,
79125cf1a30Sjl 	    sizeof (sckm_ioctl_getreq_t), flag)) {
79225cf1a30Sjl 		return (EFAULT);
79325cf1a30Sjl 	}
79425cf1a30Sjl #endif /* _MULTI_DATAMODEL */
79525cf1a30Sjl 	return (0);
79625cf1a30Sjl }
79725cf1a30Sjl 
79825cf1a30Sjl /*
79925cf1a30Sjl  * okm_cleanup - Cleanup routine.
80025cf1a30Sjl  */
80125cf1a30Sjl static void
okm_cleanup(okms_t * okmsp)80225cf1a30Sjl okm_cleanup(okms_t *okmsp)
80325cf1a30Sjl {
80425cf1a30Sjl 
80525cf1a30Sjl 	ASSERT(okmsp != NULL);
80625cf1a30Sjl 	if (okmsp->km_clean & OKM_CLEAN_NODE) {
80725cf1a30Sjl 		ddi_remove_minor_node(okmsp->km_dip, NULL);
80825cf1a30Sjl 	}
80925cf1a30Sjl 	if (okmsp->km_clean & OKM_CLEAN_LOCK)
81025cf1a30Sjl 		mutex_destroy(&okmsp->km_lock);
81125cf1a30Sjl 	if (okmsp->km_clean & OKM_CLEAN_CV)
81225cf1a30Sjl 		cv_destroy(&okmsp->km_wait);
81325cf1a30Sjl 	if (okmsp->km_reqp != NULL) {
81425cf1a30Sjl 		kmem_free(okmsp->km_reqp, okmsp->km_reqlen);
81525cf1a30Sjl 		okmsp->km_reqp = NULL;
81625cf1a30Sjl 		okmsp->km_reqlen = 0;
81725cf1a30Sjl 	}
81825cf1a30Sjl 	ddi_set_driver_private(okmsp->km_dip, NULL);
81925cf1a30Sjl }
82025cf1a30Sjl 
82125cf1a30Sjl /*
82225cf1a30Sjl  * okm_mbox_init - Mailbox specific initialization.
82325cf1a30Sjl  */
82425cf1a30Sjl static int
okm_mbox_init(okms_t * okmsp)82525cf1a30Sjl okm_mbox_init(okms_t *okmsp)
82625cf1a30Sjl {
82725cf1a30Sjl 	int ret;
82825cf1a30Sjl 	clock_t tout;
82925cf1a30Sjl 
83025cf1a30Sjl 	ASSERT(MUTEX_HELD(&okmsp->km_lock));
83125cf1a30Sjl 	okmsp->km_target = OKM_TARGET_ID;
83225cf1a30Sjl 	okmsp->km_key = DKMD_KEY;
83325cf1a30Sjl 	okmsp->km_state &= ~OKM_MB_INITED;
83425cf1a30Sjl 
83525cf1a30Sjl 	/* Iterate until mailbox gets connected */
83625cf1a30Sjl 	while (!(okmsp->km_state & OKM_MB_CONN)) {
83725cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_mbox_init: calling mb_init\n"));
83825cf1a30Sjl 		ret = scf_mb_init(okmsp->km_target, okmsp->km_key,
83925cf1a30Sjl 		    okm_event_handler, (void *)okmsp);
84025cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret));
84125cf1a30Sjl 
842030f3a8fSraghuram 		if (ret != 0) {
843030f3a8fSraghuram 			DPRINTF(DBG_MBOX,
844030f3a8fSraghuram 			    ("okm_mbox_init: failed ret =%d\n", ret));
845030f3a8fSraghuram 			DTRACE_PROBE1(okm_mbox_fail, int, ret);
846030f3a8fSraghuram 		} else {
84725cf1a30Sjl 			okmsp->km_state |= OKM_MB_INITED;
84825cf1a30Sjl 
84925cf1a30Sjl 			/* Block until the mailbox is ready to communicate. */
85025cf1a30Sjl 			while (!(okmsp->km_state &
85125cf1a30Sjl 			    (OKM_MB_CONN | OKM_MB_DISC))) {
85225cf1a30Sjl 
85325cf1a30Sjl 				if (cv_wait_sig(&okmsp->km_wait,
85425cf1a30Sjl 				    &okmsp->km_lock) <= 0) {
85525cf1a30Sjl 					/* interrupted */
85625cf1a30Sjl 					ret = EINTR;
85725cf1a30Sjl 					break;
85825cf1a30Sjl 				}
85925cf1a30Sjl 			}
86025cf1a30Sjl 		}
86125cf1a30Sjl 
862030f3a8fSraghuram 		if ((ret != 0) || (okmsp->km_state & OKM_MB_DISC)) {
86325cf1a30Sjl 
864030f3a8fSraghuram 			if (okmsp->km_state & OKM_MB_INITED) {
865030f3a8fSraghuram 				(void) scf_mb_fini(okmsp->km_target,
866030f3a8fSraghuram 				    okmsp->km_key);
867030f3a8fSraghuram 			}
868030f3a8fSraghuram 			if (okmsp->km_state & OKM_MB_DISC) {
869030f3a8fSraghuram 				DPRINTF(DBG_WARN,
870030f3a8fSraghuram 				    ("okm_mbox_init: mbox DISC_ERROR\n"));
871030f3a8fSraghuram 				DTRACE_PROBE1(okm_mbox_fail,
872030f3a8fSraghuram 				    int, OKM_MB_DISC);
873030f3a8fSraghuram 			}
87425cf1a30Sjl 
875030f3a8fSraghuram 			okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_DISC |
876030f3a8fSraghuram 			    OKM_MB_CONN);
87725cf1a30Sjl 
878030f3a8fSraghuram 			if (ret == EINTR) {
879030f3a8fSraghuram 				return (ret);
880030f3a8fSraghuram 			}
88125cf1a30Sjl 
88225cf1a30Sjl 			/*
88325cf1a30Sjl 			 * If there was failure, then wait for
88425cf1a30Sjl 			 * OKM_MB_TOUT secs and retry again.
88525cf1a30Sjl 			 */
88625cf1a30Sjl 
88725cf1a30Sjl 			DPRINTF(DBG_MBOX, ("okm_mbox_init: waiting...\n"));
888d3d50737SRafael Vanoni 			tout = drv_usectohz(OKM_MB_TOUT);
889d3d50737SRafael Vanoni 			ret = cv_reltimedwait_sig(&okmsp->km_wait,
890d3d50737SRafael Vanoni 			    &okmsp->km_lock, tout, TR_CLOCK_TICK);
89125cf1a30Sjl 			if (ret == 0) {
89225cf1a30Sjl 				/* if interrupted, return immediately. */
89325cf1a30Sjl 				DPRINTF(DBG_MBOX,
89425cf1a30Sjl 				    ("okm_mbox_init: interrupted\n"));
89525cf1a30Sjl 				return (EINTR);
89625cf1a30Sjl 			}
89725cf1a30Sjl 		}
89825cf1a30Sjl 	}
89925cf1a30Sjl 
90025cf1a30Sjl 	ret = scf_mb_ctrl(okmsp->km_target, okmsp->km_key,
90125cf1a30Sjl 	    SCF_MBOP_MAXMSGSIZE, &okmsp->km_maxsz);
90225cf1a30Sjl 
90325cf1a30Sjl 	/*
90425cf1a30Sjl 	 * The max msg size should be at least the size of reply
90525cf1a30Sjl 	 * we need to send.
90625cf1a30Sjl 	 */
90725cf1a30Sjl 	if ((ret == 0) && (okmsp->km_maxsz < sizeof (okm_rep_hdr_t))) {
90825cf1a30Sjl 		cmn_err(CE_WARN, "Max message size expected >= %ld "
90925cf1a30Sjl 		    "but found %d\n", sizeof (okm_rep_hdr_t), okmsp->km_maxsz);
91025cf1a30Sjl 		ret = EIO;
91125cf1a30Sjl 	}
91225cf1a30Sjl 	if (ret != 0) {
91325cf1a30Sjl 		okmsp->km_state &= ~OKM_MB_INITED;
91425cf1a30Sjl 		(void) scf_mb_fini(okmsp->km_target, okmsp->km_key);
91525cf1a30Sjl 	}
91625cf1a30Sjl 	DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret));
91725cf1a30Sjl 	return (ret);
91825cf1a30Sjl }
91925cf1a30Sjl 
92025cf1a30Sjl /*
92125cf1a30Sjl  * okm_mbox_fini - Mailbox de-initialization.
92225cf1a30Sjl  */
92325cf1a30Sjl static void
okm_mbox_fini(okms_t * okmsp)92425cf1a30Sjl okm_mbox_fini(okms_t *okmsp)
92525cf1a30Sjl {
92625cf1a30Sjl 	int ret = 0;
92725cf1a30Sjl 
92825cf1a30Sjl 	ASSERT(MUTEX_HELD(&okmsp->km_lock));
92925cf1a30Sjl 	if (okmsp->km_state & OKM_MB_INITED) {
93025cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_mbox_fini: calling mb_fini\n"));
93125cf1a30Sjl 		ret = scf_mb_fini(okmsp->km_target, okmsp->km_key);
93225cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_mbox_fini: mb_fini ret=%d\n", ret));
93325cf1a30Sjl 		if (ret != 0) {
93425cf1a30Sjl 			cmn_err(CE_WARN,
93525cf1a30Sjl 			    "Failed to close the Mailbox error=%d", ret);
93625cf1a30Sjl 		}
93725cf1a30Sjl 		okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_CONN | OKM_MB_DISC);
93825cf1a30Sjl 	}
93925cf1a30Sjl }
94025cf1a30Sjl 
94125cf1a30Sjl /*
94225cf1a30Sjl  * okm_event_handler - Mailbox event handler.
94325cf1a30Sjl  *
94425cf1a30Sjl  * Description:	Implements a state machine to handle all the mailbox
94525cf1a30Sjl  *		events. For each event, it sets the appropriate state
94625cf1a30Sjl  *		flag and wakes up the threads waiting for that event.
94725cf1a30Sjl  */
94825cf1a30Sjl void
okm_event_handler(scf_event_t event,void * arg)94925cf1a30Sjl okm_event_handler(scf_event_t event, void *arg)
95025cf1a30Sjl {
95125cf1a30Sjl 	okms_t *okmsp = (okms_t *)arg;
95225cf1a30Sjl 
95325cf1a30Sjl 	DPRINTF(DBG_MBOX, ("okm_event_handler: called\n"));
95425cf1a30Sjl 	ASSERT(okmsp != NULL);
95525cf1a30Sjl 	mutex_enter(&okmsp->km_lock);
95625cf1a30Sjl 	if (!(okmsp->km_state & OKM_MB_INITED)) {
95725cf1a30Sjl 		/*
95825cf1a30Sjl 		 * Ignore all events if the state flag indicates that the
95925cf1a30Sjl 		 * mailbox not initialized, this may happen during the close.
96025cf1a30Sjl 		 */
96125cf1a30Sjl 		mutex_exit(&okmsp->km_lock);
96225cf1a30Sjl 		DPRINTF(DBG_MBOX,
96325cf1a30Sjl 		    ("okm_event_handler: event=0x%X - mailbox not inited \n",
96425cf1a30Sjl 		    event));
96525cf1a30Sjl 		return;
96625cf1a30Sjl 	}
96725cf1a30Sjl 	switch (event) {
96825cf1a30Sjl 	case SCF_MB_CONN_OK:
96925cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_event_handler: Event CONN_OK\n"));
97025cf1a30Sjl 		/*
97125cf1a30Sjl 		 * Now the mailbox is ready to use, lets wake up
97225cf1a30Sjl 		 * any one waiting for this event.
97325cf1a30Sjl 		 */
97425cf1a30Sjl 		okmsp->km_state |= OKM_MB_CONN;
97525cf1a30Sjl 		cv_broadcast(&okmsp->km_wait);
97625cf1a30Sjl 		break;
97725cf1a30Sjl 
97825cf1a30Sjl 	case SCF_MB_MSG_DATA:
97925cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_event_handler: Event MSG_DATA\n"));
98025cf1a30Sjl 		/*
98125cf1a30Sjl 		 * A message is available in the mailbox,
98225cf1a30Sjl 		 * wakeup if any one is ready to read the message.
98325cf1a30Sjl 		 */
98425cf1a30Sjl 		if (OKM_MBOX_READY(okmsp)) {
98525cf1a30Sjl 			cv_broadcast(&okmsp->km_wait);
98625cf1a30Sjl 		}
98725cf1a30Sjl 		break;
98825cf1a30Sjl 
98925cf1a30Sjl 	case SCF_MB_SPACE:
99025cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_event_handler: Event MB_SPACE\n"));
99125cf1a30Sjl 		/*
99225cf1a30Sjl 		 * Now the mailbox is ready to transmit, lets
99325cf1a30Sjl 		 * wakeup if any one is waiting to write.
99425cf1a30Sjl 		 */
99525cf1a30Sjl 		if (OKM_MBOX_READY(okmsp)) {
99625cf1a30Sjl 			cv_broadcast(&okmsp->km_wait);
99725cf1a30Sjl 		}
99825cf1a30Sjl 		break;
99925cf1a30Sjl 	case SCF_MB_DISC_ERROR:
100025cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_event_handler: Event DISC_ERROR\n"));
100125cf1a30Sjl 		okmsp->km_state &= ~OKM_MB_CONN;
100225cf1a30Sjl 		okmsp->km_state |= OKM_MB_DISC;
100325cf1a30Sjl 		cv_broadcast(&okmsp->km_wait);
100425cf1a30Sjl 		break;
100525cf1a30Sjl 	default:
100625cf1a30Sjl 		cmn_err(CE_WARN, "Unexpected event received\n");
100725cf1a30Sjl 	}
100825cf1a30Sjl 	mutex_exit(&okmsp->km_lock);
100925cf1a30Sjl }
101025cf1a30Sjl 
101125cf1a30Sjl /*
101225cf1a30Sjl  * okm_send_reply - Send a mailbox reply message.
101325cf1a30Sjl  */
101425cf1a30Sjl int
okm_send_reply(okms_t * okmsp,uint32_t transid,uint32_t status,uint32_t sadb_err,uint32_t sadb_ver)101525cf1a30Sjl okm_send_reply(okms_t *okmsp, uint32_t transid,
101625cf1a30Sjl     uint32_t status, uint32_t sadb_err, uint32_t sadb_ver)
101725cf1a30Sjl {
101825cf1a30Sjl 	okm_rep_hdr_t reply;
101925cf1a30Sjl 	int ret = EIO;
102025cf1a30Sjl 
102125cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_send_reply: called\n"));
102225cf1a30Sjl 	ASSERT(MUTEX_HELD(&okmsp->km_lock));
102325cf1a30Sjl 	reply.krp_version = htonl(OKM_PROTOCOL_VERSION);
102425cf1a30Sjl 	reply.krp_transid = htonl(transid);
102525cf1a30Sjl 	reply.krp_status = htonl(status);
102625cf1a30Sjl 	reply.krp_sadb_errno = htonl(sadb_err);
102725cf1a30Sjl 	reply.krp_sadb_version = htonl(sadb_ver);
102825cf1a30Sjl 	okmsp->km_sg_tx.msc_dptr = (caddr_t)&reply;
102925cf1a30Sjl 	okmsp->km_sg_tx.msc_len = sizeof (reply);
103025cf1a30Sjl 	DUMP_REPLY(&reply);
103125cf1a30Sjl 
103225cf1a30Sjl 	while (OKM_MBOX_READY(okmsp)) {
103325cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_send_reply: sending reply\n"));
103425cf1a30Sjl 		ret = scf_mb_putmsg(okmsp->km_target, okmsp->km_key,
103525cf1a30Sjl 		    sizeof (reply), 1, &okmsp->km_sg_tx, 0);
103625cf1a30Sjl 		DPRINTF(DBG_MBOX, ("okm_send_reply: putmsg ret=%d\n", ret));
103725cf1a30Sjl 		if (ret == EBUSY || ret == ENOSPC) {
103825cf1a30Sjl 			/* mailbox is busy, poll/retry */
103925cf1a30Sjl 			if (cv_timedwait_sig(&okmsp->km_wait,
104025cf1a30Sjl 			    &okmsp->km_lock, okm_timeout_val(ret)) == 0) {
104125cf1a30Sjl 				/* interrupted */
104225cf1a30Sjl 				ret = EINTR;
104325cf1a30Sjl 				DPRINTF(DBG_DRV,
104425cf1a30Sjl 				    ("okm_send_reply: interrupted\n"));
104525cf1a30Sjl 				break;
104625cf1a30Sjl 			}
104725cf1a30Sjl 		} else {
104825cf1a30Sjl 			break;
104925cf1a30Sjl 		}
105025cf1a30Sjl 	}
105125cf1a30Sjl 	DPRINTF(DBG_DRV, ("okm_send_reply: ret=%d\n", ret));
105225cf1a30Sjl 	return (ret);
105325cf1a30Sjl }
105425cf1a30Sjl 
105525cf1a30Sjl /*
105625cf1a30Sjl  * okm_timeout_val -- Return appropriate timeout value.
105725cf1a30Sjl  *
105825cf1a30Sjl  * A small timeout value is returned for EBUSY as the mailbox busy
105925cf1a30Sjl  * condition may go away sooner and we are expected to poll.
106025cf1a30Sjl  *
106125cf1a30Sjl  * A larger timeout value is returned for ENOSPC case, as the condition
106225cf1a30Sjl  * depends on the peer to release buffer space.
106325cf1a30Sjl  * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
106425cf1a30Sjl  * used for reliability purposes.
106525cf1a30Sjl  */
106625cf1a30Sjl static clock_t
okm_timeout_val(int error)106725cf1a30Sjl okm_timeout_val(int error)
106825cf1a30Sjl {
106925cf1a30Sjl 	clock_t tval;
107025cf1a30Sjl 
107125cf1a30Sjl 	ASSERT(error == EBUSY || error == ENOSPC);
107225cf1a30Sjl 
107325cf1a30Sjl 	if (error == EBUSY) {
107425cf1a30Sjl 		tval = OKM_SM_TOUT;
107525cf1a30Sjl 	} else {
107625cf1a30Sjl 		tval = OKM_LG_TOUT;
107725cf1a30Sjl 	}
107825cf1a30Sjl 	return (drv_usectohz(tval));
107925cf1a30Sjl }
108025cf1a30Sjl 
108125cf1a30Sjl #ifdef DEBUG
108225cf1a30Sjl static void
okm_print_req(okm_req_hdr_t * reqp,uint32_t len)108325cf1a30Sjl okm_print_req(okm_req_hdr_t *reqp, uint32_t len)
108425cf1a30Sjl {
108525cf1a30Sjl 	uint8_t *datap = (uint8_t *)(((char *)reqp) + sizeof (okm_req_hdr_t));
108625cf1a30Sjl 	int msglen = len - sizeof (okm_req_hdr_t);
108725cf1a30Sjl 	int i, j;
108825cf1a30Sjl #define	BYTES_PER_LINE	20
108925cf1a30Sjl 	char bytestr[BYTES_PER_LINE * 3 + 1];
109025cf1a30Sjl 
109125cf1a30Sjl 	if (!(okm_debug & DBG_MESG))
109225cf1a30Sjl 		return;
109325cf1a30Sjl 	printf("OKM: Request  ver=%d transid=%d cmd=%s\n",
109425cf1a30Sjl 	    reqp->krq_version, reqp->krq_transid,
109525cf1a30Sjl 	    ((reqp->krq_cmd == OKM_MSG_SADB) ? "MSG_SADB" : "UNKNOWN"));
109625cf1a30Sjl 	for (i = 0; i < msglen; ) {
109725cf1a30Sjl 		for (j = 0; (j < BYTES_PER_LINE) && (i < msglen); j++, i++) {
109807d06da5SSurya Prakki 			(void) sprintf(&bytestr[j * 3], "%02X ", datap[i]);
109925cf1a30Sjl 		}
110025cf1a30Sjl 		if (j != 0) {
110125cf1a30Sjl 			printf("\t%s\n", bytestr);
110225cf1a30Sjl 		}
110325cf1a30Sjl 	}
110425cf1a30Sjl }
110525cf1a30Sjl 
110625cf1a30Sjl static void
okm_print_rep(okm_rep_hdr_t * repp)110725cf1a30Sjl okm_print_rep(okm_rep_hdr_t *repp)
110825cf1a30Sjl {
110925cf1a30Sjl 	if (!(okm_debug & DBG_MESG))
111025cf1a30Sjl 		return;
111125cf1a30Sjl 	printf("OKM: Reply Ver=%d Transid=%d Status=%d ",
111225cf1a30Sjl 	    repp->krp_version, repp->krp_transid, repp->krp_status);
111325cf1a30Sjl 	printf("Sadb_errno=%d Sadb_ver=%d\n", repp->krp_sadb_errno,
111425cf1a30Sjl 	    repp->krp_sadb_version);
111525cf1a30Sjl }
111625cf1a30Sjl #endif
1117