11772Sjl139090 /*
21772Sjl139090 * CDDL HEADER START
31772Sjl139090 *
41772Sjl139090 * The contents of this file are subject to the terms of the
51772Sjl139090 * Common Development and Distribution License (the "License").
61772Sjl139090 * You may not use this file except in compliance with the License.
71772Sjl139090 *
81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090 * or http://www.opensolaris.org/os/licensing.
101772Sjl139090 * See the License for the specific language governing permissions
111772Sjl139090 * and limitations under the License.
121772Sjl139090 *
131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090 *
191772Sjl139090 * CDDL HEADER END
201772Sjl139090 */
211772Sjl139090 /*
2210248SZachary.Kissel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
231772Sjl139090 * Use is subject to license terms.
241772Sjl139090 */
251772Sjl139090
261772Sjl139090
271772Sjl139090 /*
281772Sjl139090 * OPL IPSec Key Management Driver.
291772Sjl139090 *
301772Sjl139090 * This driver runs on a OPL Domain. It processes requests received
311772Sjl139090 * from the OPL Service Processor (SP) via mailbox message. It passes
321772Sjl139090 * these requests to the sckmd daemon by means of an /ioctl interface.
331772Sjl139090 *
341772Sjl139090 * Requests received from the SP consist of IPsec security associations
351772Sjl139090 * (SAs) needed to secure the communication between SC and Domain daemons
361772Sjl139090 * communicating using DSCP.
371772Sjl139090 */
381772Sjl139090
391772Sjl139090 #include <sys/types.h>
401772Sjl139090 #include <sys/cmn_err.h>
411772Sjl139090 #include <sys/kmem.h>
421772Sjl139090 #include <sys/errno.h>
431772Sjl139090 #include <sys/file.h>
441772Sjl139090 #include <sys/open.h>
451772Sjl139090 #include <sys/stat.h>
461772Sjl139090 #include <sys/conf.h>
471772Sjl139090 #include <sys/ddi.h>
481772Sjl139090 #include <sys/cmn_err.h>
491772Sjl139090 #include <sys/sunddi.h>
501772Sjl139090 #include <sys/sunndi.h>
511772Sjl139090 #include <sys/ddi_impldefs.h>
521772Sjl139090 #include <sys/ndi_impldefs.h>
531772Sjl139090 #include <sys/modctl.h>
541772Sjl139090 #include <sys/disp.h>
551772Sjl139090 #include <sys/note.h>
561772Sjl139090 #include <sys/byteorder.h>
571772Sjl139090 #include <sys/sdt.h>
581772Sjl139090
591772Sjl139090 #include <sys/scfd/scfdscpif.h>
601772Sjl139090 #include <sys/oplkm_msg.h>
611772Sjl139090 #include <sys/sckm_io.h>
621772Sjl139090 #include <sys/oplkm.h>
631772Sjl139090
641772Sjl139090 #define OKM_NODENAME "oplkmdrv" /* Node name */
651772Sjl139090 #define OKM_TARGET_ID 0 /* Target ID */
661772Sjl139090 #define OKM_SM_TOUT 5000 /* small timeout (5msec) */
671772Sjl139090 #define OKM_LG_TOUT 50000 /* large timeout (50msec) */
681772Sjl139090 #define OKM_MB_TOUT 10000000 /* Mailbox timeout (10sec) */
691772Sjl139090
701772Sjl139090 okms_t okms_global; /* Global instance structure */
711772Sjl139090
721772Sjl139090 #ifdef DEBUG
731772Sjl139090 uint32_t okm_debug = DBG_WARN;
741772Sjl139090 #endif
751772Sjl139090
761772Sjl139090 /*
771772Sjl139090 * Prototypes for the module related functions.
781772Sjl139090 */
791772Sjl139090 int okm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
801772Sjl139090 int okm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
811772Sjl139090 int okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
821772Sjl139090 int okm_open(dev_t *devp, int flag, int otyp, struct cred *cred);
831772Sjl139090 int okm_close(dev_t dev, int flag, int otyp, struct cred *cred);
841772Sjl139090 int okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag,
851772Sjl139090 cred_t *cred, int *rvalp);
861772Sjl139090
871772Sjl139090 /*
881772Sjl139090 * Prototypes for the internal functions.
891772Sjl139090 */
901772Sjl139090 int okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp,
911772Sjl139090 intptr_t data, int flag);
921772Sjl139090 int okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len,
931772Sjl139090 sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag);
941772Sjl139090 int okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply);
951772Sjl139090 void okm_event_handler(scf_event_t event, void *arg);
961772Sjl139090 int okm_send_reply(okms_t *okmsp, uint32_t transid, uint32_t status,
971772Sjl139090 uint32_t sadb_err, uint32_t sadb_ver);
981772Sjl139090 int block_until_ready(okms_t *okmsp);
991772Sjl139090 static int okm_copyin_ioctl_getreq(intptr_t userarg,
1001772Sjl139090 sckm_ioctl_getreq_t *driverarg, int flag);
1011772Sjl139090 static int okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg,
1021772Sjl139090 intptr_t userarg, int flag);
1031772Sjl139090 static void okm_cleanup(okms_t *okmsp);
1041772Sjl139090 static int okm_mbox_init(okms_t *okmsp);
1051772Sjl139090 static void okm_mbox_fini(okms_t *okmsp);
1061772Sjl139090 static clock_t okm_timeout_val(int error);
1071772Sjl139090
1081772Sjl139090
1091772Sjl139090 struct cb_ops okm_cb_ops = {
1101772Sjl139090 okm_open, /* open */
1111772Sjl139090 okm_close, /* close */
1121772Sjl139090 nodev, /* strategy */
1131772Sjl139090 nodev, /* print */
1141772Sjl139090 nodev, /* dump */
1151772Sjl139090 nodev, /* read */
1161772Sjl139090 nodev, /* write */
1171772Sjl139090 okm_ioctl, /* ioctl */
1181772Sjl139090 nodev, /* devmap */
1191772Sjl139090 nodev, /* mmap */
1201772Sjl139090 nodev, /* segmap */
1211772Sjl139090 nochpoll, /* poll */
1221772Sjl139090 ddi_prop_op, /* prop_op */
1231772Sjl139090 0, /* streamtab */
1241772Sjl139090 D_NEW | D_MP /* Driver compatibility flag */
1251772Sjl139090 };
1261772Sjl139090
1271772Sjl139090 struct dev_ops okm_ops = {
1281772Sjl139090 DEVO_REV, /* devo_rev, */
1291772Sjl139090 0, /* refcnt */
1301772Sjl139090 okm_info, /* get_dev_info */
1311772Sjl139090 nulldev, /* identify */
1321772Sjl139090 nulldev, /* probe */
1331772Sjl139090 okm_attach, /* attach */
1341772Sjl139090 okm_detach, /* detach */
1351772Sjl139090 nodev, /* reset */
1361772Sjl139090 &okm_cb_ops, /* driver operations */
1377656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* no bus operations */
1387656SSherry.Moore@Sun.COM NULL, /* power */
1397656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1401772Sjl139090 };
1411772Sjl139090
1421772Sjl139090 struct modldrv modldrv = {
1431772Sjl139090 &mod_driverops,
1447656SSherry.Moore@Sun.COM "OPL Key Management Driver",
1451772Sjl139090 &okm_ops,
1461772Sjl139090 };
1471772Sjl139090
1481772Sjl139090 struct modlinkage modlinkage = {
1491772Sjl139090 MODREV_1,
1501772Sjl139090 &modldrv,
1511772Sjl139090 NULL
1521772Sjl139090 };
1531772Sjl139090
1541772Sjl139090
1551772Sjl139090 /*
1561772Sjl139090 * _init - Module's init routine.
1571772Sjl139090 */
1581772Sjl139090 int
_init(void)1591772Sjl139090 _init(void)
1601772Sjl139090 {
1611772Sjl139090 int ret;
1621772Sjl139090
1631772Sjl139090 if ((ret = mod_install(&modlinkage)) != 0) {
1641772Sjl139090 cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
1651772Sjl139090 }
1661772Sjl139090 return (ret);
1671772Sjl139090 }
1681772Sjl139090
1691772Sjl139090 /*
1701772Sjl139090 * _fini - Module's fini routine.
1711772Sjl139090 */
1721772Sjl139090 int
_fini(void)1731772Sjl139090 _fini(void)
1741772Sjl139090 {
1751772Sjl139090 int ret;
1761772Sjl139090
1771772Sjl139090 if ((ret = mod_remove(&modlinkage)) != 0) {
1781772Sjl139090 return (ret);
1791772Sjl139090 }
1801772Sjl139090 return (ret);
1811772Sjl139090 }
1821772Sjl139090
1831772Sjl139090 /*
1841772Sjl139090 * _info - Module's info routine.
1851772Sjl139090 */
1861772Sjl139090 int
_info(struct modinfo * modinfop)1871772Sjl139090 _info(struct modinfo *modinfop)
1881772Sjl139090 {
1891772Sjl139090 return (mod_info(&modlinkage, modinfop));
1901772Sjl139090 }
1911772Sjl139090
1921772Sjl139090 /*
1931772Sjl139090 * okm_attach - Module's attach routine.
1941772Sjl139090 *
1951772Sjl139090 * Description: Initializes the modules state structure and create
1961772Sjl139090 * the minor device node.
1971772Sjl139090 */
1981772Sjl139090 int
okm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1991772Sjl139090 okm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2001772Sjl139090 {
2011772Sjl139090 int instance;
2021772Sjl139090 okms_t *okmsp = &okms_global;
2031772Sjl139090
2041772Sjl139090 instance = ddi_get_instance(dip);
2051772Sjl139090
2061772Sjl139090 /* Only one instance is supported. */
2071772Sjl139090 if (instance != 0) {
2081772Sjl139090 return (DDI_FAILURE);
2091772Sjl139090 }
2101772Sjl139090
2111772Sjl139090 if (cmd != DDI_ATTACH) {
2121772Sjl139090 return (DDI_FAILURE);
2131772Sjl139090 }
2141772Sjl139090
2151772Sjl139090 okmsp->km_dip = dip;
2168459SJerry.Gilliam@Sun.COM okmsp->km_major = ddi_driver_major(dip);
2171772Sjl139090 okmsp->km_inst = instance;
2181772Sjl139090
2191772Sjl139090 /*
2201772Sjl139090 * Get an interrupt block cookie corresponding to the
2211772Sjl139090 * interrupt priority of the event handler.
2221772Sjl139090 * Assert that the event priority is not redefined to
2231772Sjl139090 * some other priority.
2241772Sjl139090 */
2251772Sjl139090 /* LINTED */
2261772Sjl139090 ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
2271772Sjl139090 if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
2281772Sjl139090 &okmsp->km_ibcookie) != DDI_SUCCESS) {
2291772Sjl139090 cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
2301772Sjl139090 return (DDI_FAILURE);
2311772Sjl139090 }
2321772Sjl139090 mutex_init(&okmsp->km_lock, NULL, MUTEX_DRIVER,
2331772Sjl139090 (void *)okmsp->km_ibcookie);
2341772Sjl139090 okmsp->km_clean |= OKM_CLEAN_LOCK;
2351772Sjl139090 cv_init(&okmsp->km_wait, NULL, CV_DRIVER, NULL);
2361772Sjl139090 okmsp->km_clean |= OKM_CLEAN_CV;
2371772Sjl139090
2381772Sjl139090 /*
2391772Sjl139090 * set clean_node ahead as remove_node has to be called even
2401772Sjl139090 * if create node fails.
2411772Sjl139090 */
2421772Sjl139090 okmsp->km_clean |= OKM_CLEAN_NODE;
2431772Sjl139090 if (ddi_create_minor_node(dip, OKM_NODENAME, S_IFCHR,
2441772Sjl139090 instance, NULL, NULL) == DDI_FAILURE) {
2451772Sjl139090 cmn_err(CE_WARN, "Device node creation failed");
2461772Sjl139090 okm_cleanup(okmsp);
2471772Sjl139090 return (DDI_FAILURE);
2481772Sjl139090 }
2491772Sjl139090
2501772Sjl139090 ddi_set_driver_private(dip, (caddr_t)okmsp);
2511772Sjl139090 ddi_report_dev(dip);
2521772Sjl139090 return (DDI_SUCCESS);
2531772Sjl139090 }
2541772Sjl139090
2551772Sjl139090 /*
2561772Sjl139090 * okm_detach - Module's detach routine.
2571772Sjl139090 *
2581772Sjl139090 * Description: Cleans up the module's state structures and any other
2591772Sjl139090 * relevant data.
2601772Sjl139090 */
2611772Sjl139090 int
okm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2621772Sjl139090 okm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2631772Sjl139090 {
2641772Sjl139090 okms_t *okmsp;
2651772Sjl139090
2661772Sjl139090 if (cmd != DDI_DETACH) {
2671772Sjl139090 return (DDI_FAILURE);
2681772Sjl139090 }
2691772Sjl139090
2701772Sjl139090 if ((okmsp = ddi_get_driver_private(dip)) == NULL) {
2711772Sjl139090 return (DDI_FAILURE);
2721772Sjl139090 }
2731772Sjl139090
2741772Sjl139090 mutex_enter(&okmsp->km_lock);
2751772Sjl139090 /*
2761772Sjl139090 * Check if the mailbox is still in use.
2771772Sjl139090 */
2781772Sjl139090 if (okmsp->km_state & OKM_MB_INITED) {
2791772Sjl139090 mutex_exit(&okmsp->km_lock);
2801772Sjl139090 cmn_err(CE_WARN, "Detach failure: Mailbox in use");
2811772Sjl139090 return (DDI_FAILURE);
2821772Sjl139090 }
2831772Sjl139090 mutex_exit(&okmsp->km_lock);
2841772Sjl139090 okm_cleanup(okmsp);
2851772Sjl139090 ddi_set_driver_private(dip, NULL);
2861772Sjl139090 return (DDI_SUCCESS);
2871772Sjl139090 }
2881772Sjl139090
2891772Sjl139090 /*
2901772Sjl139090 * okm_info - Module's info routine.
2911772Sjl139090 */
2921772Sjl139090 /* ARGSUSED */
2931772Sjl139090 int
okm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2941772Sjl139090 okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2951772Sjl139090 {
29610248SZachary.Kissel@Sun.COM okms_t *okmsp = &okms_global;
2971772Sjl139090 minor_t minor;
2981772Sjl139090 int ret = DDI_FAILURE;
2991772Sjl139090
3001772Sjl139090 switch (infocmd) {
3011772Sjl139090 case DDI_INFO_DEVT2DEVINFO:
30210248SZachary.Kissel@Sun.COM /*
30310248SZachary.Kissel@Sun.COM * We have the case here where the minor number
30410248SZachary.Kissel@Sun.COM * is the same as the instance number. So, just
30510248SZachary.Kissel@Sun.COM * make sure we have the right minor node in our
30610248SZachary.Kissel@Sun.COM * global state. If we don't, set the result to NULL.
30710248SZachary.Kissel@Sun.COM */
3081772Sjl139090 minor = getminor((dev_t)arg);
30910248SZachary.Kissel@Sun.COM if (okmsp->km_inst != minor) {
3101772Sjl139090 *result = NULL;
3111772Sjl139090 } else {
3121772Sjl139090 *result = okmsp->km_dip;
3131772Sjl139090 ret = DDI_SUCCESS;
3141772Sjl139090 }
3151772Sjl139090 break;
3161772Sjl139090
3171772Sjl139090 case DDI_INFO_DEVT2INSTANCE:
3181772Sjl139090 minor = getminor((dev_t)arg);
3191772Sjl139090 *result = (void *)(uintptr_t)minor;
3201772Sjl139090 ret = DDI_SUCCESS;
3211772Sjl139090
3221772Sjl139090 default:
3231772Sjl139090 break;
3241772Sjl139090 }
3251772Sjl139090 return (ret);
3261772Sjl139090 }
3271772Sjl139090
3281772Sjl139090 /*
3291772Sjl139090 * okm_open - Device open routine.
3301772Sjl139090 *
3311772Sjl139090 * Description: Initializes the mailbox and waits until the mailbox
3321772Sjl139090 * gets connected. Only one open at a time is supported.
3331772Sjl139090 */
3341772Sjl139090 /*ARGSUSED*/
3351772Sjl139090 int
okm_open(dev_t * devp,int flag,int otyp,struct cred * cred)3361772Sjl139090 okm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
3371772Sjl139090 {
3381772Sjl139090 okms_t *okmsp = &okms_global;
3391772Sjl139090 int ret = 0;
3401772Sjl139090
3411772Sjl139090 DPRINTF(DBG_DRV, ("okm_open: called\n"));
3421772Sjl139090 mutex_enter(&okmsp->km_lock);
3431772Sjl139090 if (okmsp->km_state & OKM_OPENED) {
3441772Sjl139090 /* Only one open supported */
3451772Sjl139090 mutex_exit(&okmsp->km_lock);
3461772Sjl139090 DPRINTF(DBG_WARN, ("okm_open: already opened\n"));
3471772Sjl139090 return (EBUSY);
3481772Sjl139090 }
3491772Sjl139090 okmsp->km_state |= OKM_OPENED;
3501772Sjl139090 ret = block_until_ready(okmsp);
3511772Sjl139090 if (ret != 0) {
3521772Sjl139090 okmsp->km_state &= ~OKM_OPENED;
3531772Sjl139090 }
3541772Sjl139090 mutex_exit(&okmsp->km_lock);
3551772Sjl139090 DPRINTF(DBG_DRV, ("okm_open: ret=%d\n", ret));
3561772Sjl139090 return (ret);
3571772Sjl139090 }
3581772Sjl139090
3591772Sjl139090 /*
3601772Sjl139090 * block_until_ready - Function to wait until the mailbox is ready to use.
3611772Sjl139090 *
3621772Sjl139090 * Description: It initializes the mailbox and waits for the mailbox
3631772Sjl139090 * state to transition to connected.
3641772Sjl139090 */
3651772Sjl139090 int
block_until_ready(okms_t * okmsp)3661772Sjl139090 block_until_ready(okms_t *okmsp)
3671772Sjl139090 {
3681772Sjl139090 int ret = 0;
3691772Sjl139090
3701772Sjl139090 DPRINTF(DBG_DRV, ("block_until_ready: called\n"));
3711772Sjl139090 ASSERT(MUTEX_HELD(&okmsp->km_lock));
3721772Sjl139090
3731772Sjl139090 if (okmsp->km_state & OKM_MB_DISC) {
3741772Sjl139090 DPRINTF(DBG_DRV, ("block_until_ready: closing the mailbox\n"));
3751772Sjl139090 okm_mbox_fini(okmsp);
3761772Sjl139090 }
3771772Sjl139090 if (okmsp->km_state & OKM_MB_CONN) {
3781772Sjl139090 DPRINTF(DBG_DRV, ("block_until_ready: mailbox connected\n"));
3791772Sjl139090 return (0);
3801772Sjl139090 }
3811772Sjl139090 /*
3821772Sjl139090 * Initialize mailbox.
3831772Sjl139090 */
3841772Sjl139090 if ((ret = okm_mbox_init(okmsp)) != 0) {
3851772Sjl139090 DPRINTF(DBG_MBOX,
3861772Sjl139090 ("block_until_ready: mailbox init failed ret=%d\n", ret));
3871772Sjl139090 return (ret);
3881772Sjl139090 }
3891772Sjl139090 DPRINTF(DBG_DRV, ("block_until_ready: ret=%d", ret));
3901772Sjl139090 return (ret);
3911772Sjl139090 }
3921772Sjl139090
3931772Sjl139090 /*
3941772Sjl139090 * okm_close - Device close routine.
3951772Sjl139090 *
3961772Sjl139090 * Description: Closes the mailbox.
3971772Sjl139090 */
3981772Sjl139090 /*ARGSUSED*/
3991772Sjl139090 int
okm_close(dev_t dev,int flag,int otyp,struct cred * cred)4001772Sjl139090 okm_close(dev_t dev, int flag, int otyp, struct cred *cred)
4011772Sjl139090 {
4021772Sjl139090 okms_t *okmsp = &okms_global;
4031772Sjl139090
4041772Sjl139090 DPRINTF(DBG_DRV, ("okm_close: called\n"));
4051772Sjl139090 /* Close the lower layer first */
4061772Sjl139090 mutex_enter(&okmsp->km_lock);
4071772Sjl139090 okm_mbox_fini(okmsp);
4081772Sjl139090 okmsp->km_state = 0;
4091772Sjl139090 mutex_exit(&okmsp->km_lock);
4101772Sjl139090 return (0);
4111772Sjl139090 }
4121772Sjl139090
4131772Sjl139090
4141772Sjl139090 /*
4151772Sjl139090 * okm_ioctl - Device ioctl routine.
4161772Sjl139090 *
4171772Sjl139090 * Description: Processes ioctls from the daemon.
4181772Sjl139090 */
4191772Sjl139090 /*ARGSUSED*/
4201772Sjl139090 int
okm_ioctl(dev_t dev,int cmd,intptr_t data,int flag,cred_t * cred,int * rvalp)4211772Sjl139090 okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
4221772Sjl139090 {
4231772Sjl139090 okms_t *okmsp = &okms_global;
4241772Sjl139090 sckm_ioctl_getreq_t ireq;
4251772Sjl139090 sckm_ioctl_status_t istatus;
4261772Sjl139090 int ret = 0;
4271772Sjl139090
4281772Sjl139090 switch (cmd) {
4291772Sjl139090 case SCKM_IOCTL_GETREQ:
4301772Sjl139090
4311772Sjl139090 DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ\n"));
4321772Sjl139090 if (okm_copyin_ioctl_getreq(data, &ireq, flag)) {
4331772Sjl139090 return (EFAULT);
4341772Sjl139090 }
4351772Sjl139090
4361772Sjl139090 ret = okm_get_req(okmsp, &ireq, data, flag);
4371772Sjl139090 DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ ret=%d\n", ret));
4381772Sjl139090 break;
4391772Sjl139090
4401772Sjl139090 case SCKM_IOCTL_STATUS:
4411772Sjl139090
4421772Sjl139090 DPRINTF(DBG_DRV, ("okm_ioctl: STATUS\n"));
4431772Sjl139090 if (ddi_copyin((caddr_t)data, &istatus,
4441772Sjl139090 sizeof (sckm_ioctl_status_t), flag)) {
4451772Sjl139090 return (EFAULT);
4461772Sjl139090 }
4471772Sjl139090 ret = okm_process_status(okmsp, &istatus);
4481772Sjl139090 DPRINTF(DBG_DRV, ("okm_ioctl: STATUS ret=%d\n", ret));
4491772Sjl139090 break;
4501772Sjl139090
4511772Sjl139090 default:
4521772Sjl139090 DPRINTF(DBG_DRV, ("okm_ioctl: UNKNOWN ioctl\n"));
4531772Sjl139090 ret = EINVAL;
4541772Sjl139090 }
4551772Sjl139090 return (ret);
4561772Sjl139090 }
4571772Sjl139090
4581772Sjl139090 /*
4591772Sjl139090 * okm_get_req - Get a request from the mailbox.
4601772Sjl139090 *
4611772Sjl139090 * Description: It blocks until a message is received, then processes
4621772Sjl139090 * the message and returns it to the requestor.
4631772Sjl139090 */
4641772Sjl139090 int
okm_get_req(okms_t * okmsp,sckm_ioctl_getreq_t * ireqp,intptr_t data,int flag)4651772Sjl139090 okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag)
4661772Sjl139090 {
4671772Sjl139090 okm_req_hdr_t *reqp;
4681772Sjl139090 caddr_t msgbuf;
4691772Sjl139090 uint32_t len;
4701772Sjl139090 int ret;
4711772Sjl139090
4721772Sjl139090 DPRINTF(DBG_DRV, ("okm_getreq: called\n"));
4731772Sjl139090 mutex_enter(&okmsp->km_lock);
4741772Sjl139090 if ((ret = block_until_ready(okmsp)) != 0) {
4751772Sjl139090 mutex_exit(&okmsp->km_lock);
4761772Sjl139090 DPRINTF(DBG_WARN, ("okm_getreq: failed ret=%d\n", ret));
4771772Sjl139090 return (ret);
4781772Sjl139090 }
4791772Sjl139090
4801772Sjl139090 if (okmsp->km_reqp != NULL) {
4811772Sjl139090 DPRINTF(DBG_DRV, ("okm_getreq: req cached\n"));
4821772Sjl139090 reqp = okmsp->km_reqp;
4831772Sjl139090 len = okmsp->km_reqlen;
4841772Sjl139090 okmsp->km_reqp = NULL;
4851772Sjl139090 okmsp->km_reqlen = 0;
4861772Sjl139090 } else {
4871772Sjl139090 retry:
4881772Sjl139090 while (OKM_MBOX_READY(okmsp) &&
4891772Sjl139090 ((ret = scf_mb_canget(okmsp->km_target,
4901772Sjl139090 okmsp->km_key, &len)) != 0)) {
4911772Sjl139090 if (ret != ENOMSG) {
4921772Sjl139090 DPRINTF(DBG_WARN, ("okm_getreq: Unknown "
4931772Sjl139090 "mbox failure=%d\n", ret));
4941772Sjl139090 mutex_exit(&okmsp->km_lock);
4951772Sjl139090 return (EIO);
4961772Sjl139090 }
4971772Sjl139090 DPRINTF(DBG_MBOX, ("okm_getreq: waiting for mesg\n"));
4981772Sjl139090 if (cv_wait_sig(&okmsp->km_wait,
4991772Sjl139090 &okmsp->km_lock) <= 0) {
5001772Sjl139090 mutex_exit(&okmsp->km_lock);
5011772Sjl139090 DPRINTF(DBG_DRV, ("okm_getreq:interrupted\n"));
5021772Sjl139090 return (EINTR);
5031772Sjl139090 }
5041772Sjl139090 }
5051772Sjl139090 if (!OKM_MBOX_READY(okmsp)) {
5061772Sjl139090 mutex_exit(&okmsp->km_lock);
5071772Sjl139090 DPRINTF(DBG_WARN, ("okm_getreq: mailbox not ready\n"));
5081772Sjl139090 return (EIO);
5091772Sjl139090 }
5101772Sjl139090 ASSERT(len != 0);
5111772Sjl139090 msgbuf = kmem_alloc(len, KM_SLEEP);
5121772Sjl139090 okmsp->km_sg_rcv.msc_dptr = msgbuf;
5131772Sjl139090 okmsp->km_sg_rcv.msc_len = len;
5141772Sjl139090
5151772Sjl139090 DPRINTF(DBG_MBOX, ("okm_getreq: getmsg\n"));
5161772Sjl139090 ret = scf_mb_getmsg(okmsp->km_target, okmsp->km_key, len, 1,
5171772Sjl139090 &okmsp->km_sg_rcv, 0);
5181772Sjl139090 if (ret == ENOMSG || ret == EMSGSIZE) {
5191772Sjl139090 kmem_free(msgbuf, len);
5201772Sjl139090 DPRINTF(DBG_MBOX, ("okm_getreq: nomsg ret=%d\n", ret));
5211772Sjl139090 goto retry;
5221772Sjl139090 } else if (ret != 0) {
5231772Sjl139090 kmem_free(msgbuf, len);
5241772Sjl139090 mutex_exit(&okmsp->km_lock);
5251772Sjl139090 DPRINTF(DBG_WARN,
5261772Sjl139090 ("okm_getreq: Unknown mbox failure=%d\n", ret));
5271772Sjl139090 return (EIO);
5281772Sjl139090 }
5291772Sjl139090
5301772Sjl139090 /* check message length */
5311772Sjl139090 if (len < sizeof (okm_req_hdr_t)) {
5321772Sjl139090 /* protocol error, drop message */
5331772Sjl139090 kmem_free(msgbuf, len);
5341772Sjl139090 mutex_exit(&okmsp->km_lock);
5351772Sjl139090 DPRINTF(DBG_WARN, ("okm_getreq: Bad message\n"));
5361772Sjl139090 return (EBADMSG);
5371772Sjl139090 }
5381772Sjl139090
5391772Sjl139090 reqp = (okm_req_hdr_t *)msgbuf;
5401772Sjl139090 reqp->krq_version = ntohl(reqp->krq_version);
5411772Sjl139090 reqp->krq_transid = ntohl(reqp->krq_transid);
5421772Sjl139090 reqp->krq_cmd = ntohl(reqp->krq_cmd);
5431772Sjl139090 reqp->krq_reserved = ntohl(reqp->krq_reserved);
5441772Sjl139090
5451772Sjl139090 /* check version of the message received */
5461772Sjl139090 if (reqp->krq_version != OKM_PROTOCOL_VERSION) {
547*11311SSurya.Prakki@Sun.COM (void) okm_send_reply(okmsp, reqp->krq_transid,
5481772Sjl139090 OKM_ERR_VERSION, 0, 0);
5491772Sjl139090 kmem_free(msgbuf, len);
5501772Sjl139090 mutex_exit(&okmsp->km_lock);
5511772Sjl139090 DPRINTF(DBG_WARN, ("okm_getreq: Unknown version=%d\n",
5521772Sjl139090 reqp->krq_version));
5531772Sjl139090 return (EBADMSG);
5541772Sjl139090 }
5551772Sjl139090 }
5561772Sjl139090
5571772Sjl139090 /* process message */
5581772Sjl139090 ret = okm_process_req(okmsp, reqp, len, ireqp, data, flag);
5591772Sjl139090 if (okmsp->km_reqp == NULL) {
5601772Sjl139090 /*
5611772Sjl139090 * The message is not saved, so free the buffer.
5621772Sjl139090 */
5631772Sjl139090 kmem_free(reqp, len);
5641772Sjl139090 }
5651772Sjl139090 mutex_exit(&okmsp->km_lock);
5661772Sjl139090 DPRINTF(DBG_DRV, ("okm_getreq: ret=%d\n", ret));
5671772Sjl139090 return (ret);
5681772Sjl139090 }
5691772Sjl139090
5701772Sjl139090
5711772Sjl139090 /*
5721772Sjl139090 * okm_process_req - Process the request.
5731772Sjl139090 *
5741772Sjl139090 * Description: Validate the request and then give the request to the
5751772Sjl139090 * daemon.
5761772Sjl139090 */
5771772Sjl139090 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)5781772Sjl139090 okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len,
5791772Sjl139090 sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag)
5801772Sjl139090 {
5811772Sjl139090 void *req_datap = (void *)(((char *)reqp) + sizeof (okm_req_hdr_t));
5821772Sjl139090 int sadb_msglen = len - sizeof (okm_req_hdr_t);
5831772Sjl139090
5841772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_req: called\n"));
5851772Sjl139090 DUMP_REQ(reqp, len);
5861772Sjl139090
5871772Sjl139090 switch (reqp->krq_cmd) {
5881772Sjl139090 case OKM_MSG_SADB:
5891772Sjl139090 /* sanity check request */
5901772Sjl139090 if (sadb_msglen <= 0) {
591*11311SSurya.Prakki@Sun.COM (void) okm_send_reply(okmsp, reqp->krq_transid,
5921772Sjl139090 OKM_ERR_SADB_MSG, 0, 0);
5931772Sjl139090 DPRINTF(DBG_WARN, ("okm_process_req: bad message\n"));
5941772Sjl139090 return (EBADMSG);
5951772Sjl139090 }
5961772Sjl139090
5971772Sjl139090 /*
5981772Sjl139090 * Save the message, prior to giving it to the daemon.
5991772Sjl139090 */
6001772Sjl139090 okmsp->km_reqp = reqp;
6011772Sjl139090 okmsp->km_reqlen = len;
6021772Sjl139090
6031772Sjl139090 if (ireqp->buf_len < len) {
6041772Sjl139090 DPRINTF(DBG_WARN,
6051772Sjl139090 ("okm_process_req: not enough space\n"));
6061772Sjl139090 return (ENOSPC);
6071772Sjl139090 }
6081772Sjl139090
6091772Sjl139090 ireqp->transid = reqp->krq_transid;
6101772Sjl139090 ireqp->type = SCKM_IOCTL_REQ_SADB;
6111772Sjl139090 if (ddi_copyout(req_datap, ireqp->buf, sadb_msglen, flag)) {
6121772Sjl139090 DPRINTF(DBG_WARN,
6131772Sjl139090 ("okm_process_req: copyout failed\n"));
6141772Sjl139090 return (EFAULT);
6151772Sjl139090 }
6161772Sjl139090 ireqp->buf_len = sadb_msglen;
6171772Sjl139090 if (okm_copyout_ioctl_getreq(ireqp, data, flag)) {
6181772Sjl139090 DPRINTF(DBG_WARN,
6191772Sjl139090 ("okm_process_req: copyout failed\n"));
6201772Sjl139090 return (EFAULT);
6211772Sjl139090 }
6221772Sjl139090 break;
6231772Sjl139090
6241772Sjl139090 default:
6251772Sjl139090 cmn_err(CE_WARN, "Unknown cmd 0x%x received", reqp->krq_cmd);
6261772Sjl139090 /*
6271772Sjl139090 * Received an unknown command, send corresponding
6281772Sjl139090 * error message.
6291772Sjl139090 */
630*11311SSurya.Prakki@Sun.COM (void) okm_send_reply(okmsp, reqp->krq_transid,
631*11311SSurya.Prakki@Sun.COM OKM_ERR_BAD_CMD, 0, 0);
6321772Sjl139090 return (EBADMSG);
6331772Sjl139090 }
6341772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_req: ret=0\n"));
6351772Sjl139090 return (0);
6361772Sjl139090 }
6371772Sjl139090
6381772Sjl139090 /*
6391772Sjl139090 * okm_process_status - Process the status from the daemon.
6401772Sjl139090 *
6411772Sjl139090 * Description: Processes the status received from the daemon and sends
6421772Sjl139090 * corresponding message to the SP.
6431772Sjl139090 */
6441772Sjl139090 int
okm_process_status(okms_t * okmsp,sckm_ioctl_status_t * ireply)6451772Sjl139090 okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply)
6461772Sjl139090 {
6471772Sjl139090 uint32_t status;
6481772Sjl139090 uint32_t sadb_msg_errno = 0;
6491772Sjl139090 uint32_t sadb_msg_version = 0;
6501772Sjl139090 okm_req_hdr_t *reqp = okmsp->km_reqp;
6511772Sjl139090 int ret;
6521772Sjl139090
6531772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: called\n"));
6541772Sjl139090 mutex_enter(&okmsp->km_lock);
6551772Sjl139090 if ((ret = block_until_ready(okmsp)) != 0) {
6561772Sjl139090 mutex_exit(&okmsp->km_lock);
6571772Sjl139090 DPRINTF(DBG_WARN,
6581772Sjl139090 ("okm_process_status: Unknown failure=%d\n", ret));
6591772Sjl139090 return (ret);
6601772Sjl139090 }
6611772Sjl139090
6621772Sjl139090 /* fail if no status is expected, or if it does not match */
6631772Sjl139090 if (!okmsp->km_reqp || (reqp->krq_transid != ireply->transid)) {
6641772Sjl139090 mutex_exit(&okmsp->km_lock);
6651772Sjl139090 DPRINTF(DBG_WARN,
6661772Sjl139090 ("okm_process_status: req/transid mismatch\n"));
6671772Sjl139090 return (EINVAL);
6681772Sjl139090 }
6691772Sjl139090
6701772Sjl139090 switch (ireply->status) {
6711772Sjl139090 case SCKM_IOCTL_STAT_SUCCESS:
6721772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: SUCCESS\n"));
6731772Sjl139090 status = OKM_SUCCESS;
6741772Sjl139090 break;
6751772Sjl139090 case SCKM_IOCTL_STAT_ERR_PFKEY:
6761772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: PFKEY ERROR\n"));
6771772Sjl139090 status = OKM_ERR_SADB_PFKEY;
6781772Sjl139090 sadb_msg_errno = ireply->sadb_msg_errno;
6791772Sjl139090 break;
6801772Sjl139090 case SCKM_IOCTL_STAT_ERR_REQ:
6811772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: REQ ERROR\n"));
6821772Sjl139090 status = OKM_ERR_DAEMON;
6831772Sjl139090 break;
6841772Sjl139090 case SCKM_IOCTL_STAT_ERR_VERSION:
6851772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: SADB VERSION ERROR\n"));
6861772Sjl139090 status = OKM_ERR_SADB_VERSION;
6871772Sjl139090 sadb_msg_version = ireply->sadb_msg_version;
6881772Sjl139090 break;
6891772Sjl139090 case SCKM_IOCTL_STAT_ERR_TIMEOUT:
6901772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: TIMEOUT ERR\n"));
6911772Sjl139090 status = OKM_ERR_SADB_TIMEOUT;
6921772Sjl139090 break;
6931772Sjl139090 case SCKM_IOCTL_STAT_ERR_OTHER:
6941772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: OTHER ERR\n"));
6951772Sjl139090 status = OKM_ERR_DAEMON;
6961772Sjl139090 break;
6971772Sjl139090 case SCKM_IOCTL_STAT_ERR_SADB_TYPE:
6981772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: SADB TYPE ERR\n"));
6991772Sjl139090 status = OKM_ERR_SADB_BAD_TYPE;
7001772Sjl139090 break;
7011772Sjl139090 default:
7021772Sjl139090 cmn_err(CE_WARN, "SCKM daemon returned invalid status %d\n",
7031772Sjl139090 ireply->status);
7041772Sjl139090 status = OKM_ERR_DAEMON;
7051772Sjl139090 }
7061772Sjl139090 ret = okm_send_reply(okmsp, ireply->transid, status,
7071772Sjl139090 sadb_msg_errno, sadb_msg_version);
7081772Sjl139090 /*
7091772Sjl139090 * Clean up the cached request now.
7101772Sjl139090 */
7111772Sjl139090 if (ret == 0) {
7121772Sjl139090 kmem_free(okmsp->km_reqp, okmsp->km_reqlen);
7131772Sjl139090 okmsp->km_reqp = NULL;
7141772Sjl139090 okmsp->km_reqlen = 0;
7151772Sjl139090 }
7161772Sjl139090 mutex_exit(&okmsp->km_lock);
7171772Sjl139090 DPRINTF(DBG_DRV, ("okm_process_status: ret=%d\n", ret));
7181772Sjl139090 return (ret);
7191772Sjl139090 }
7201772Sjl139090
7211772Sjl139090 /*
7221772Sjl139090 * okm_copyin_ioctl_getreq - copy-in the ioctl request from the daemon.
7231772Sjl139090 */
7241772Sjl139090
7251772Sjl139090 static int
okm_copyin_ioctl_getreq(intptr_t userarg,sckm_ioctl_getreq_t * driverarg,int flag)7261772Sjl139090 okm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg,
7271772Sjl139090 int flag)
7281772Sjl139090 {
7291772Sjl139090 #ifdef _MULTI_DATAMODEL
7301772Sjl139090 switch (ddi_model_convert_from(flag & FMODELS)) {
7311772Sjl139090 case DDI_MODEL_ILP32: {
7321772Sjl139090 sckm_ioctl_getreq32_t driverarg32;
7331772Sjl139090 if (ddi_copyin((caddr_t)userarg, &driverarg32,
7341772Sjl139090 sizeof (sckm_ioctl_getreq32_t), flag)) {
7351772Sjl139090 return (EFAULT);
7361772Sjl139090 }
7371772Sjl139090 driverarg->transid = driverarg32.transid;
7381772Sjl139090 driverarg->type = driverarg32.type;
7391772Sjl139090 driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf;
7401772Sjl139090 driverarg->buf_len = driverarg32.buf_len;
7411772Sjl139090 break;
7421772Sjl139090 }
7431772Sjl139090 case DDI_MODEL_NONE: {
7441772Sjl139090 if (ddi_copyin((caddr_t)userarg, &driverarg,
7451772Sjl139090 sizeof (sckm_ioctl_getreq_t), flag)) {
7461772Sjl139090 return (EFAULT);
7471772Sjl139090 }
7481772Sjl139090 break;
7491772Sjl139090 }
7501772Sjl139090 }
7511772Sjl139090 #else /* ! _MULTI_DATAMODEL */
7521772Sjl139090 if (ddi_copyin((caddr_t)userarg, &driverarg,
7531772Sjl139090 sizeof (sckm_ioctl_getreq_t), flag)) {
7541772Sjl139090 return (EFAULT);
7551772Sjl139090 }
7561772Sjl139090 #endif /* _MULTI_DATAMODEL */
7571772Sjl139090 return (0);
7581772Sjl139090 }
7591772Sjl139090
7601772Sjl139090
7611772Sjl139090 /*
7621772Sjl139090 * okm_copyout_ioctl_getreq - copy-out the request to the daemon.
7631772Sjl139090 */
7641772Sjl139090 static int
okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t * driverarg,intptr_t userarg,int flag)7651772Sjl139090 okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg,
7661772Sjl139090 int flag)
7671772Sjl139090 {
7681772Sjl139090 #ifdef _MULTI_DATAMODEL
7691772Sjl139090 switch (ddi_model_convert_from(flag & FMODELS)) {
7701772Sjl139090 case DDI_MODEL_ILP32: {
7711772Sjl139090 sckm_ioctl_getreq32_t driverarg32;
7721772Sjl139090 driverarg32.transid = driverarg->transid;
7731772Sjl139090 driverarg32.type = driverarg->type;
7741772Sjl139090 driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf;
7751772Sjl139090 driverarg32.buf_len = driverarg->buf_len;
7761772Sjl139090 if (ddi_copyout(&driverarg32, (caddr_t)userarg,
7771772Sjl139090 sizeof (sckm_ioctl_getreq32_t), flag)) {
7781772Sjl139090 return (EFAULT);
7791772Sjl139090 }
7801772Sjl139090 break;
7811772Sjl139090 }
7821772Sjl139090 case DDI_MODEL_NONE:
7831772Sjl139090 if (ddi_copyout(driverarg, (caddr_t)userarg,
7841772Sjl139090 sizeof (sckm_ioctl_getreq_t), flag)) {
7851772Sjl139090 return (EFAULT);
7861772Sjl139090 }
7871772Sjl139090 break;
7881772Sjl139090 }
7891772Sjl139090 #else /* ! _MULTI_DATAMODEL */
7901772Sjl139090 if (ddi_copyout(driverarg, (caddr_t)userarg,
7911772Sjl139090 sizeof (sckm_ioctl_getreq_t), flag)) {
7921772Sjl139090 return (EFAULT);
7931772Sjl139090 }
7941772Sjl139090 #endif /* _MULTI_DATAMODEL */
7951772Sjl139090 return (0);
7961772Sjl139090 }
7971772Sjl139090
7981772Sjl139090 /*
7991772Sjl139090 * okm_cleanup - Cleanup routine.
8001772Sjl139090 */
8011772Sjl139090 static void
okm_cleanup(okms_t * okmsp)8021772Sjl139090 okm_cleanup(okms_t *okmsp)
8031772Sjl139090 {
8041772Sjl139090
8051772Sjl139090 ASSERT(okmsp != NULL);
8061772Sjl139090 if (okmsp->km_clean & OKM_CLEAN_NODE) {
8071772Sjl139090 ddi_remove_minor_node(okmsp->km_dip, NULL);
8081772Sjl139090 }
8091772Sjl139090 if (okmsp->km_clean & OKM_CLEAN_LOCK)
8101772Sjl139090 mutex_destroy(&okmsp->km_lock);
8111772Sjl139090 if (okmsp->km_clean & OKM_CLEAN_CV)
8121772Sjl139090 cv_destroy(&okmsp->km_wait);
8131772Sjl139090 if (okmsp->km_reqp != NULL) {
8141772Sjl139090 kmem_free(okmsp->km_reqp, okmsp->km_reqlen);
8151772Sjl139090 okmsp->km_reqp = NULL;
8161772Sjl139090 okmsp->km_reqlen = 0;
8171772Sjl139090 }
8181772Sjl139090 ddi_set_driver_private(okmsp->km_dip, NULL);
8191772Sjl139090 }
8201772Sjl139090
8211772Sjl139090 /*
8221772Sjl139090 * okm_mbox_init - Mailbox specific initialization.
8231772Sjl139090 */
8241772Sjl139090 static int
okm_mbox_init(okms_t * okmsp)8251772Sjl139090 okm_mbox_init(okms_t *okmsp)
8261772Sjl139090 {
8271772Sjl139090 int ret;
8281772Sjl139090 clock_t tout;
8291772Sjl139090
8301772Sjl139090 ASSERT(MUTEX_HELD(&okmsp->km_lock));
8311772Sjl139090 okmsp->km_target = OKM_TARGET_ID;
8321772Sjl139090 okmsp->km_key = DKMD_KEY;
8331772Sjl139090 okmsp->km_state &= ~OKM_MB_INITED;
8341772Sjl139090
8351772Sjl139090 /* Iterate until mailbox gets connected */
8361772Sjl139090 while (!(okmsp->km_state & OKM_MB_CONN)) {
8371772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_init: calling mb_init\n"));
8381772Sjl139090 ret = scf_mb_init(okmsp->km_target, okmsp->km_key,
8391772Sjl139090 okm_event_handler, (void *)okmsp);
8401772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret));
8411772Sjl139090
8422126Sraghuram if (ret != 0) {
8432126Sraghuram DPRINTF(DBG_MBOX,
8442126Sraghuram ("okm_mbox_init: failed ret =%d\n", ret));
8452126Sraghuram DTRACE_PROBE1(okm_mbox_fail, int, ret);
8462126Sraghuram } else {
8471772Sjl139090 okmsp->km_state |= OKM_MB_INITED;
8481772Sjl139090
8491772Sjl139090 /* Block until the mailbox is ready to communicate. */
8501772Sjl139090 while (!(okmsp->km_state &
8511772Sjl139090 (OKM_MB_CONN | OKM_MB_DISC))) {
8521772Sjl139090
8531772Sjl139090 if (cv_wait_sig(&okmsp->km_wait,
8541772Sjl139090 &okmsp->km_lock) <= 0) {
8551772Sjl139090 /* interrupted */
8561772Sjl139090 ret = EINTR;
8571772Sjl139090 break;
8581772Sjl139090 }
8591772Sjl139090 }
8601772Sjl139090 }
8611772Sjl139090
8621772Sjl139090 if ((ret != 0) || (okmsp->km_state & OKM_MB_DISC)) {
8631772Sjl139090
8642126Sraghuram if (okmsp->km_state & OKM_MB_INITED) {
8652126Sraghuram (void) scf_mb_fini(okmsp->km_target,
8662126Sraghuram okmsp->km_key);
8672126Sraghuram }
8682126Sraghuram if (okmsp->km_state & OKM_MB_DISC) {
8692126Sraghuram DPRINTF(DBG_WARN,
8702126Sraghuram ("okm_mbox_init: mbox DISC_ERROR\n"));
8712126Sraghuram DTRACE_PROBE1(okm_mbox_fail,
8722126Sraghuram int, OKM_MB_DISC);
8732126Sraghuram }
8742126Sraghuram
8752126Sraghuram okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_DISC |
8762126Sraghuram OKM_MB_CONN);
8772126Sraghuram
8782126Sraghuram if (ret == EINTR) {
8792126Sraghuram return (ret);
8802126Sraghuram }
8811772Sjl139090
8821772Sjl139090 /*
8831772Sjl139090 * If there was failure, then wait for
8841772Sjl139090 * OKM_MB_TOUT secs and retry again.
8851772Sjl139090 */
8861772Sjl139090
8871772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_init: waiting...\n"));
88811066Srafael.vanoni@sun.com tout = drv_usectohz(OKM_MB_TOUT);
88911066Srafael.vanoni@sun.com ret = cv_reltimedwait_sig(&okmsp->km_wait,
89011066Srafael.vanoni@sun.com &okmsp->km_lock, tout, TR_CLOCK_TICK);
8911772Sjl139090 if (ret == 0) {
8921772Sjl139090 /* if interrupted, return immediately. */
8931772Sjl139090 DPRINTF(DBG_MBOX,
8941772Sjl139090 ("okm_mbox_init: interrupted\n"));
8951772Sjl139090 return (EINTR);
8961772Sjl139090 }
8971772Sjl139090 }
8981772Sjl139090 }
8991772Sjl139090
9001772Sjl139090 ret = scf_mb_ctrl(okmsp->km_target, okmsp->km_key,
9011772Sjl139090 SCF_MBOP_MAXMSGSIZE, &okmsp->km_maxsz);
9021772Sjl139090
9031772Sjl139090 /*
9041772Sjl139090 * The max msg size should be at least the size of reply
9051772Sjl139090 * we need to send.
9061772Sjl139090 */
9071772Sjl139090 if ((ret == 0) && (okmsp->km_maxsz < sizeof (okm_rep_hdr_t))) {
9081772Sjl139090 cmn_err(CE_WARN, "Max message size expected >= %ld "
9091772Sjl139090 "but found %d\n", sizeof (okm_rep_hdr_t), okmsp->km_maxsz);
9101772Sjl139090 ret = EIO;
9111772Sjl139090 }
9121772Sjl139090 if (ret != 0) {
9131772Sjl139090 okmsp->km_state &= ~OKM_MB_INITED;
9141772Sjl139090 (void) scf_mb_fini(okmsp->km_target, okmsp->km_key);
9151772Sjl139090 }
9161772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret));
9171772Sjl139090 return (ret);
9181772Sjl139090 }
9191772Sjl139090
9201772Sjl139090 /*
9211772Sjl139090 * okm_mbox_fini - Mailbox de-initialization.
9221772Sjl139090 */
9231772Sjl139090 static void
okm_mbox_fini(okms_t * okmsp)9241772Sjl139090 okm_mbox_fini(okms_t *okmsp)
9251772Sjl139090 {
9261772Sjl139090 int ret = 0;
9271772Sjl139090
9281772Sjl139090 ASSERT(MUTEX_HELD(&okmsp->km_lock));
9291772Sjl139090 if (okmsp->km_state & OKM_MB_INITED) {
9301772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_fini: calling mb_fini\n"));
9311772Sjl139090 ret = scf_mb_fini(okmsp->km_target, okmsp->km_key);
9321772Sjl139090 DPRINTF(DBG_MBOX, ("okm_mbox_fini: mb_fini ret=%d\n", ret));
9331772Sjl139090 if (ret != 0) {
9341772Sjl139090 cmn_err(CE_WARN,
9351772Sjl139090 "Failed to close the Mailbox error=%d", ret);
9361772Sjl139090 }
9371772Sjl139090 okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_CONN | OKM_MB_DISC);
9381772Sjl139090 }
9391772Sjl139090 }
9401772Sjl139090
9411772Sjl139090 /*
9421772Sjl139090 * okm_event_handler - Mailbox event handler.
9431772Sjl139090 *
9441772Sjl139090 * Description: Implements a state machine to handle all the mailbox
9451772Sjl139090 * events. For each event, it sets the appropriate state
9461772Sjl139090 * flag and wakes up the threads waiting for that event.
9471772Sjl139090 */
9481772Sjl139090 void
okm_event_handler(scf_event_t event,void * arg)9491772Sjl139090 okm_event_handler(scf_event_t event, void *arg)
9501772Sjl139090 {
9511772Sjl139090 okms_t *okmsp = (okms_t *)arg;
9521772Sjl139090
9531772Sjl139090 DPRINTF(DBG_MBOX, ("okm_event_handler: called\n"));
9541772Sjl139090 ASSERT(okmsp != NULL);
9551772Sjl139090 mutex_enter(&okmsp->km_lock);
9561772Sjl139090 if (!(okmsp->km_state & OKM_MB_INITED)) {
9571772Sjl139090 /*
9581772Sjl139090 * Ignore all events if the state flag indicates that the
9591772Sjl139090 * mailbox not initialized, this may happen during the close.
9601772Sjl139090 */
9611772Sjl139090 mutex_exit(&okmsp->km_lock);
9621772Sjl139090 DPRINTF(DBG_MBOX,
9631772Sjl139090 ("okm_event_handler: event=0x%X - mailbox not inited \n",
9641772Sjl139090 event));
9651772Sjl139090 return;
9661772Sjl139090 }
9671772Sjl139090 switch (event) {
9681772Sjl139090 case SCF_MB_CONN_OK:
9691772Sjl139090 DPRINTF(DBG_MBOX, ("okm_event_handler: Event CONN_OK\n"));
9701772Sjl139090 /*
9711772Sjl139090 * Now the mailbox is ready to use, lets wake up
9721772Sjl139090 * any one waiting for this event.
9731772Sjl139090 */
9741772Sjl139090 okmsp->km_state |= OKM_MB_CONN;
9751772Sjl139090 cv_broadcast(&okmsp->km_wait);
9761772Sjl139090 break;
9771772Sjl139090
9781772Sjl139090 case SCF_MB_MSG_DATA:
9791772Sjl139090 DPRINTF(DBG_MBOX, ("okm_event_handler: Event MSG_DATA\n"));
9801772Sjl139090 /*
9811772Sjl139090 * A message is available in the mailbox,
9821772Sjl139090 * wakeup if any one is ready to read the message.
9831772Sjl139090 */
9841772Sjl139090 if (OKM_MBOX_READY(okmsp)) {
9851772Sjl139090 cv_broadcast(&okmsp->km_wait);
9861772Sjl139090 }
9871772Sjl139090 break;
9881772Sjl139090
9891772Sjl139090 case SCF_MB_SPACE:
9901772Sjl139090 DPRINTF(DBG_MBOX, ("okm_event_handler: Event MB_SPACE\n"));
9911772Sjl139090 /*
9921772Sjl139090 * Now the mailbox is ready to transmit, lets
9931772Sjl139090 * wakeup if any one is waiting to write.
9941772Sjl139090 */
9951772Sjl139090 if (OKM_MBOX_READY(okmsp)) {
9961772Sjl139090 cv_broadcast(&okmsp->km_wait);
9971772Sjl139090 }
9981772Sjl139090 break;
9991772Sjl139090 case SCF_MB_DISC_ERROR:
10001772Sjl139090 DPRINTF(DBG_MBOX, ("okm_event_handler: Event DISC_ERROR\n"));
10011772Sjl139090 okmsp->km_state &= ~OKM_MB_CONN;
10021772Sjl139090 okmsp->km_state |= OKM_MB_DISC;
10031772Sjl139090 cv_broadcast(&okmsp->km_wait);
10041772Sjl139090 break;
10051772Sjl139090 default:
10061772Sjl139090 cmn_err(CE_WARN, "Unexpected event received\n");
10071772Sjl139090 }
10081772Sjl139090 mutex_exit(&okmsp->km_lock);
10091772Sjl139090 }
10101772Sjl139090
10111772Sjl139090 /*
10121772Sjl139090 * okm_send_reply - Send a mailbox reply message.
10131772Sjl139090 */
10141772Sjl139090 int
okm_send_reply(okms_t * okmsp,uint32_t transid,uint32_t status,uint32_t sadb_err,uint32_t sadb_ver)10151772Sjl139090 okm_send_reply(okms_t *okmsp, uint32_t transid,
10161772Sjl139090 uint32_t status, uint32_t sadb_err, uint32_t sadb_ver)
10171772Sjl139090 {
10181772Sjl139090 okm_rep_hdr_t reply;
10191772Sjl139090 int ret = EIO;
10201772Sjl139090
10211772Sjl139090 DPRINTF(DBG_DRV, ("okm_send_reply: called\n"));
10221772Sjl139090 ASSERT(MUTEX_HELD(&okmsp->km_lock));
10231772Sjl139090 reply.krp_version = htonl(OKM_PROTOCOL_VERSION);
10241772Sjl139090 reply.krp_transid = htonl(transid);
10251772Sjl139090 reply.krp_status = htonl(status);
10261772Sjl139090 reply.krp_sadb_errno = htonl(sadb_err);
10271772Sjl139090 reply.krp_sadb_version = htonl(sadb_ver);
10281772Sjl139090 okmsp->km_sg_tx.msc_dptr = (caddr_t)&reply;
10291772Sjl139090 okmsp->km_sg_tx.msc_len = sizeof (reply);
10301772Sjl139090 DUMP_REPLY(&reply);
10311772Sjl139090
10321772Sjl139090 while (OKM_MBOX_READY(okmsp)) {
10331772Sjl139090 DPRINTF(DBG_MBOX, ("okm_send_reply: sending reply\n"));
10341772Sjl139090 ret = scf_mb_putmsg(okmsp->km_target, okmsp->km_key,
10351772Sjl139090 sizeof (reply), 1, &okmsp->km_sg_tx, 0);
10361772Sjl139090 DPRINTF(DBG_MBOX, ("okm_send_reply: putmsg ret=%d\n", ret));
10371772Sjl139090 if (ret == EBUSY || ret == ENOSPC) {
10381772Sjl139090 /* mailbox is busy, poll/retry */
10391772Sjl139090 if (cv_timedwait_sig(&okmsp->km_wait,
10401772Sjl139090 &okmsp->km_lock, okm_timeout_val(ret)) == 0) {
10411772Sjl139090 /* interrupted */
10421772Sjl139090 ret = EINTR;
10431772Sjl139090 DPRINTF(DBG_DRV,
10441772Sjl139090 ("okm_send_reply: interrupted\n"));
10451772Sjl139090 break;
10461772Sjl139090 }
10471772Sjl139090 } else {
10481772Sjl139090 break;
10491772Sjl139090 }
10501772Sjl139090 }
10511772Sjl139090 DPRINTF(DBG_DRV, ("okm_send_reply: ret=%d\n", ret));
10521772Sjl139090 return (ret);
10531772Sjl139090 }
10541772Sjl139090
10551772Sjl139090 /*
10561772Sjl139090 * okm_timeout_val -- Return appropriate timeout value.
10571772Sjl139090 *
10581772Sjl139090 * A small timeout value is returned for EBUSY as the mailbox busy
10591772Sjl139090 * condition may go away sooner and we are expected to poll.
10601772Sjl139090 *
10611772Sjl139090 * A larger timeout value is returned for ENOSPC case, as the condition
10621772Sjl139090 * depends on the peer to release buffer space.
10631772Sjl139090 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
10641772Sjl139090 * used for reliability purposes.
10651772Sjl139090 */
10661772Sjl139090 static clock_t
okm_timeout_val(int error)10671772Sjl139090 okm_timeout_val(int error)
10681772Sjl139090 {
10691772Sjl139090 clock_t tval;
10701772Sjl139090
10711772Sjl139090 ASSERT(error == EBUSY || error == ENOSPC);
10721772Sjl139090
10731772Sjl139090 if (error == EBUSY) {
10741772Sjl139090 tval = OKM_SM_TOUT;
10751772Sjl139090 } else {
10761772Sjl139090 tval = OKM_LG_TOUT;
10771772Sjl139090 }
10781772Sjl139090 return (drv_usectohz(tval));
10791772Sjl139090 }
10801772Sjl139090
10811772Sjl139090 #ifdef DEBUG
10821772Sjl139090 static void
okm_print_req(okm_req_hdr_t * reqp,uint32_t len)10831772Sjl139090 okm_print_req(okm_req_hdr_t *reqp, uint32_t len)
10841772Sjl139090 {
10851772Sjl139090 uint8_t *datap = (uint8_t *)(((char *)reqp) + sizeof (okm_req_hdr_t));
10861772Sjl139090 int msglen = len - sizeof (okm_req_hdr_t);
10871772Sjl139090 int i, j;
10881772Sjl139090 #define BYTES_PER_LINE 20
10891772Sjl139090 char bytestr[BYTES_PER_LINE * 3 + 1];
10901772Sjl139090
10911772Sjl139090 if (!(okm_debug & DBG_MESG))
10921772Sjl139090 return;
10931772Sjl139090 printf("OKM: Request ver=%d transid=%d cmd=%s\n",
10941772Sjl139090 reqp->krq_version, reqp->krq_transid,
10951772Sjl139090 ((reqp->krq_cmd == OKM_MSG_SADB) ? "MSG_SADB" : "UNKNOWN"));
10961772Sjl139090 for (i = 0; i < msglen; ) {
10971772Sjl139090 for (j = 0; (j < BYTES_PER_LINE) && (i < msglen); j++, i++) {
1098*11311SSurya.Prakki@Sun.COM (void) sprintf(&bytestr[j * 3], "%02X ", datap[i]);
10991772Sjl139090 }
11001772Sjl139090 if (j != 0) {
11011772Sjl139090 printf("\t%s\n", bytestr);
11021772Sjl139090 }
11031772Sjl139090 }
11041772Sjl139090 }
11051772Sjl139090
11061772Sjl139090 static void
okm_print_rep(okm_rep_hdr_t * repp)11071772Sjl139090 okm_print_rep(okm_rep_hdr_t *repp)
11081772Sjl139090 {
11091772Sjl139090 if (!(okm_debug & DBG_MESG))
11101772Sjl139090 return;
11111772Sjl139090 printf("OKM: Reply Ver=%d Transid=%d Status=%d ",
11121772Sjl139090 repp->krp_version, repp->krp_transid, repp->krp_status);
11131772Sjl139090 printf("Sadb_errno=%d Sadb_ver=%d\n", repp->krp_sadb_errno,
11141772Sjl139090 repp->krp_sadb_version);
11151772Sjl139090 }
11161772Sjl139090 #endif
1117