10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*762Sdhain * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * fcode helper driver -- provide priv. access and kernel communication 310Sstevel@tonic-gate * to the userland fcode interpreter. 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/cred.h> 350Sstevel@tonic-gate #include <sys/mman.h> 360Sstevel@tonic-gate #include <sys/kmem.h> 370Sstevel@tonic-gate #include <sys/conf.h> 380Sstevel@tonic-gate #include <sys/ddi.h> 390Sstevel@tonic-gate #include <sys/sunddi.h> 400Sstevel@tonic-gate #include <sys/sunndi.h> 410Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 420Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 430Sstevel@tonic-gate #include <sys/modctl.h> 440Sstevel@tonic-gate #include <sys/stat.h> 450Sstevel@tonic-gate #include <sys/fcode.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate static int fc_max_opens = 32; /* Up to this many simultaneous opens */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * Soft state associated with each instance of driver open. 510Sstevel@tonic-gate */ 520Sstevel@tonic-gate static struct fc_state { 530Sstevel@tonic-gate int state; /* available flag or active state */ 540Sstevel@tonic-gate struct fc_request *req; /* Active Request */ 550Sstevel@tonic-gate } *fc_states; 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define FC_STATE_INACTIVE 0 /* Unopen, available for use */ 580Sstevel@tonic-gate #define FC_STATE_OPEN 1 /* Inital open */ 590Sstevel@tonic-gate #define FC_STATE_READ_DONE 2 /* blocking read done */ 600Sstevel@tonic-gate #define FC_STATE_IN_PROGRESS 3 /* FC_GET_PARAMETERS done, active */ 610Sstevel@tonic-gate #define FC_STATE_VALIDATED 4 /* FC_VALIDATE done, active */ 62*762Sdhain #define FC_STATE_ERROR_SET 5 /* FC_SET_FCODE_ERROR done, active */ 630Sstevel@tonic-gate #define FC_STATE_ACTIVE(s) ((s) != 0) 640Sstevel@tonic-gate #define FC_STATE_AVAILABLE(s) ((s) == FC_STATE_INACTIVE) 650Sstevel@tonic-gate 660Sstevel@tonic-gate static kmutex_t fc_open_lock; /* serialize instance assignment */ 670Sstevel@tonic-gate static kcondvar_t fc_open_cv; /* wait for available open */ 680Sstevel@tonic-gate static int fc_open_count; /* number of current open instance */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate static int fc_open(dev_t *, int, int, cred_t *); 710Sstevel@tonic-gate static int fc_close(dev_t, int, int, cred_t *); 720Sstevel@tonic-gate static int fc_read(dev_t, struct uio *, cred_t *); 730Sstevel@tonic-gate static int fc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 740Sstevel@tonic-gate static int fc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 750Sstevel@tonic-gate static int fc_attach(dev_info_t *, ddi_attach_cmd_t cmd); 760Sstevel@tonic-gate static int fc_detach(dev_info_t *, ddi_detach_cmd_t cmd); 770Sstevel@tonic-gate 780Sstevel@tonic-gate static int fc_get_parameters(dev_t, intptr_t, int, cred_t *, int *); 790Sstevel@tonic-gate static int fc_get_my_args(dev_t, intptr_t, int, cred_t *, int *); 800Sstevel@tonic-gate static int fc_run_priv(dev_t, intptr_t, int, cred_t *, int *); 810Sstevel@tonic-gate static int fc_validate(dev_t, intptr_t, int, cred_t *, int *); 820Sstevel@tonic-gate static int fc_get_fcode(dev_t, intptr_t, int, cred_t *, int *); 83*762Sdhain static int fc_set_fcode_error(dev_t, intptr_t, int, cred_t *, int *); 840Sstevel@tonic-gate 850Sstevel@tonic-gate static struct cb_ops fc_cb_ops = { 860Sstevel@tonic-gate fc_open, /* open */ 870Sstevel@tonic-gate fc_close, /* close */ 880Sstevel@tonic-gate nodev, /* strategy */ 890Sstevel@tonic-gate nodev, /* print */ 900Sstevel@tonic-gate nodev, /* dump */ 910Sstevel@tonic-gate fc_read, /* read */ 920Sstevel@tonic-gate nodev, /* write */ 930Sstevel@tonic-gate fc_ioctl, /* ioctl */ 940Sstevel@tonic-gate nodev, /* devmap */ 950Sstevel@tonic-gate nodev, /* mmap */ 960Sstevel@tonic-gate nodev, /* segmap */ 970Sstevel@tonic-gate nochpoll, /* poll */ 980Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 990Sstevel@tonic-gate NULL, /* streamtab */ 1000Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 1010Sstevel@tonic-gate }; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static struct dev_ops fcode_ops = { 1040Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1050Sstevel@tonic-gate 0, /* refcnt */ 1060Sstevel@tonic-gate fc_info, /* info */ 1070Sstevel@tonic-gate nulldev, /* identify */ 1080Sstevel@tonic-gate nulldev, /* probe */ 1090Sstevel@tonic-gate fc_attach, /* attach */ 1100Sstevel@tonic-gate fc_detach, /* detach */ 1110Sstevel@tonic-gate nodev, /* reset */ 1120Sstevel@tonic-gate &fc_cb_ops, /* driver operations */ 1130Sstevel@tonic-gate NULL /* bus operations */ 1140Sstevel@tonic-gate }; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * Module linkage information for the kernel. 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate static struct modldrv modldrv = { 1200Sstevel@tonic-gate &mod_driverops, 1210Sstevel@tonic-gate "FCode driver %I%", 1220Sstevel@tonic-gate &fcode_ops 1230Sstevel@tonic-gate }; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate static struct modlinkage modlinkage = { 1260Sstevel@tonic-gate MODREV_1, 1270Sstevel@tonic-gate &modldrv, 1280Sstevel@tonic-gate NULL 1290Sstevel@tonic-gate }; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate #ifndef lint 1320Sstevel@tonic-gate static char _depends_on[] = "misc/fcodem"; 1330Sstevel@tonic-gate #endif 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate int 1360Sstevel@tonic-gate _init(void) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate int error; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate mutex_init(&fc_open_lock, NULL, MUTEX_DRIVER, NULL); 1410Sstevel@tonic-gate cv_init(&fc_open_cv, NULL, CV_DRIVER, NULL); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate error = mod_install(&modlinkage); 1440Sstevel@tonic-gate if (error != 0) { 1450Sstevel@tonic-gate mutex_destroy(&fc_open_lock); 1460Sstevel@tonic-gate cv_destroy(&fc_open_cv); 1470Sstevel@tonic-gate return (error); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate return (0); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate int 1540Sstevel@tonic-gate _info(struct modinfo *modinfop) 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate int 1600Sstevel@tonic-gate _fini(void) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate int error; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate error = mod_remove(&modlinkage); 1650Sstevel@tonic-gate if (error != 0) { 1660Sstevel@tonic-gate return (error); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate mutex_destroy(&fc_open_lock); 1700Sstevel@tonic-gate cv_destroy(&fc_open_cv); 1710Sstevel@tonic-gate return (0); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static dev_info_t *fc_dip; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /*ARGSUSED*/ 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate fc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate int error = DDI_FAILURE; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate switch (infocmd) { 1830Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1840Sstevel@tonic-gate *result = (void *)fc_dip; 1850Sstevel@tonic-gate error = DDI_SUCCESS; 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1880Sstevel@tonic-gate /* All dev_t's map to the same, single instance */ 1890Sstevel@tonic-gate *result = (void *)0; 1900Sstevel@tonic-gate error = DDI_SUCCESS; 1910Sstevel@tonic-gate break; 1920Sstevel@tonic-gate default: 1930Sstevel@tonic-gate break; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate return (error); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate static int 2000Sstevel@tonic-gate fc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate int error = DDI_FAILURE; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate switch (cmd) { 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate case DDI_ATTACH: 2070Sstevel@tonic-gate fc_open_count = 0; 2080Sstevel@tonic-gate fc_states = kmem_zalloc( 2090Sstevel@tonic-gate fc_max_opens * sizeof (struct fc_state), KM_SLEEP); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate if (ddi_create_minor_node(dip, "fcode", S_IFCHR, 2120Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2130Sstevel@tonic-gate kmem_free(fc_states, 2140Sstevel@tonic-gate fc_max_opens * sizeof (struct fc_state)); 2150Sstevel@tonic-gate error = DDI_FAILURE; 2160Sstevel@tonic-gate } else { 2170Sstevel@tonic-gate fc_dip = dip; 2180Sstevel@tonic-gate ddi_report_dev(dip); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate error = DDI_SUCCESS; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate break; 2230Sstevel@tonic-gate default: 2240Sstevel@tonic-gate error = DDI_FAILURE; 2250Sstevel@tonic-gate break; 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate return (error); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate static int 2320Sstevel@tonic-gate fc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate int error = DDI_FAILURE; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate switch (cmd) { 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate case DDI_DETACH: 2390Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2400Sstevel@tonic-gate fc_dip = NULL; 2410Sstevel@tonic-gate kmem_free(fc_states, fc_max_opens * sizeof (struct fc_state)); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate error = DDI_SUCCESS; 2440Sstevel@tonic-gate break; 2450Sstevel@tonic-gate default: 2460Sstevel@tonic-gate error = DDI_FAILURE; 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate return (error); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* 2540Sstevel@tonic-gate * Allow multiple opens by tweaking the dev_t such that it looks like each 2550Sstevel@tonic-gate * open is getting a different minor device. Each minor gets a separate 2560Sstevel@tonic-gate * entry in the fc_states[] table. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate /*ARGSUSED*/ 2590Sstevel@tonic-gate static int 2600Sstevel@tonic-gate fc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 2610Sstevel@tonic-gate { 2620Sstevel@tonic-gate int m; 2630Sstevel@tonic-gate struct fc_state *st; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (getminor(*devp) != 0) 2660Sstevel@tonic-gate return (EINVAL); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate mutex_enter(&fc_open_lock); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate while (fc_open_count >= fc_max_opens) { 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * maximum open instance reached, wait for a close 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate FC_DEBUG0(1, CE_WARN, 2750Sstevel@tonic-gate "fcode: Maximum fcode open reached, waiting for exit\n"); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if (cv_wait_sig(&fc_open_cv, &fc_open_lock) == 0) { 2780Sstevel@tonic-gate mutex_exit(&fc_open_lock); 2790Sstevel@tonic-gate return (EINTR); 2800Sstevel@tonic-gate /*NOTREACHED*/ 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate fc_open_count++; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate for (m = 0, st = fc_states; m < fc_max_opens; m++, st++) { 2860Sstevel@tonic-gate if (FC_STATE_ACTIVE(st->state)) 2870Sstevel@tonic-gate continue; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate st->state = FC_STATE_OPEN; 2900Sstevel@tonic-gate st->req = 0; 2910Sstevel@tonic-gate break; /* It's ours. */ 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate mutex_exit(&fc_open_lock); 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate ASSERT(m < fc_max_opens); 2960Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), (minor_t)(m + 1)); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "fc_open: open count = %d (%d)\n", 2990Sstevel@tonic-gate fc_open_count, m + 1); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate return (0); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /*ARGSUSED*/ 3050Sstevel@tonic-gate static int 3060Sstevel@tonic-gate fc_close(dev_t dev, int flag, int otype, cred_t *cred_p) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate struct fc_state *st; 3090Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 3100Sstevel@tonic-gate struct fc_request *fp; 3110Sstevel@tonic-gate struct fc_client_interface *cp; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate st = fc_states + m; 3140Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * The close indicates we're done with this request. 3180Sstevel@tonic-gate * If we haven't validated this request, then something 3190Sstevel@tonic-gate * bad may have happened (ie: perhaps the user program was 3200Sstevel@tonic-gate * killed), so we should invalidate it, then close the session. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (st->state == FC_STATE_READ_DONE) { 3240Sstevel@tonic-gate fp = st->req; 3250Sstevel@tonic-gate fp->error = FC_ERROR; 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate if (st->state > FC_STATE_READ_DONE) { 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 3310Sstevel@tonic-gate fp = st->req; 3320Sstevel@tonic-gate ASSERT(fp); 3330Sstevel@tonic-gate ASSERT(fp->ap_ops); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (st->state != FC_STATE_VALIDATED) { 3360Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, 3370Sstevel@tonic-gate "fc_close: Send invalidate cmd\n"); 3380Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_INVALIDATE); 3390Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 340*762Sdhain if ((st->state != FC_STATE_ERROR_SET) || 341*762Sdhain (fp->error == FC_SUCCESS)) { 342*762Sdhain fp->error = FC_ERROR; 343*762Sdhain } 344*762Sdhain /* 345*762Sdhain * else - fp->error already set by userland interpreter 346*762Sdhain */ 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate bzero(cp, sizeof (struct fc_client_interface)); 3500Sstevel@tonic-gate FC_DEBUG0(9, CE_CONT, "fc_close: Sending exit cmd\n"); 3510Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_EXIT); 3520Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate kmem_free(cp, sizeof (struct fc_client_interface)); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * Mark the request as done ... 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate if ((fp = st->req) != NULL) 3610Sstevel@tonic-gate fc_finish_request(fp); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * rectify count and signal any waiters 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate mutex_enter(&fc_open_lock); 3670Sstevel@tonic-gate st->state = FC_STATE_INACTIVE; 3680Sstevel@tonic-gate st->req = 0; 3690Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "fc_close: open count = %d (%d)\n", 3700Sstevel@tonic-gate fc_open_count, m + 1); 3710Sstevel@tonic-gate if (fc_open_count >= fc_max_opens) { 3720Sstevel@tonic-gate cv_broadcast(&fc_open_cv); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate fc_open_count--; 3750Sstevel@tonic-gate mutex_exit(&fc_open_lock); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate return (0); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /*ARGSUSED*/ 3810Sstevel@tonic-gate static int 3820Sstevel@tonic-gate fc_read(dev_t dev, struct uio *uio, cred_t *cred) 3830Sstevel@tonic-gate { 3840Sstevel@tonic-gate struct fc_state *st; 3850Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 3860Sstevel@tonic-gate struct fc_request *fp; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate st = fc_states + m; 3890Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate /* 3920Sstevel@tonic-gate * Wait for a internal request for the interpreter 3930Sstevel@tonic-gate * and sleep till one arrives. When one arrives, 3940Sstevel@tonic-gate * return from the read. (No data is actually returned). 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate if (st->state != FC_STATE_OPEN) { 3980Sstevel@tonic-gate cmn_err(CE_CONT, "fc_read: Wrong state (%d) for read\n", 3990Sstevel@tonic-gate st->state); 4000Sstevel@tonic-gate return (EINVAL); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Wait for a request, allowing the wait to be interrupted. 4050Sstevel@tonic-gate */ 4060Sstevel@tonic-gate if ((fp = fc_get_request()) == NULL) 4070Sstevel@tonic-gate return (EINTR); 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_read: request fp: %p\n", fp); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * Update our state and store the request pointer. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate mutex_enter(&fc_open_lock); 4150Sstevel@tonic-gate st->req = fp; 4160Sstevel@tonic-gate st->state = FC_STATE_READ_DONE; 4170Sstevel@tonic-gate mutex_exit(&fc_open_lock); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate return (0); 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /*ARGSUSED*/ 4230Sstevel@tonic-gate static int 4240Sstevel@tonic-gate fc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate struct fc_state *st; 4270Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate if (m >= fc_max_opens) { 4300Sstevel@tonic-gate return (EINVAL); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate st = fc_states + m; 4340Sstevel@tonic-gate ASSERT(FC_STATE_ACTIVE(st->state)); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate switch (cmd) { 4370Sstevel@tonic-gate case FC_GET_PARAMETERS: 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * This should be the first command and is used to 4400Sstevel@tonic-gate * return data about the request, including the 4410Sstevel@tonic-gate * the fcode address and size and the unit address 4420Sstevel@tonic-gate * of the new child. The fcode offset,size can later 4430Sstevel@tonic-gate * be used as an offset in an mmap request to allow 4440Sstevel@tonic-gate * the fcode to be mapped in. 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate return (fc_get_parameters(dev, arg, mode, credp, rvalp)); 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate case FC_GET_MY_ARGS: 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Get the inital setting of my-args. This should be done 4510Sstevel@tonic-gate * after FC_GET_PARAMETERS. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate return (fc_get_my_args(dev, arg, mode, credp, rvalp)); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate case FC_RUN_PRIV: 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * Run a priveledged op on behalf of the interpreter, 4580Sstevel@tonic-gate * or download device tree data from the interpreter. 4590Sstevel@tonic-gate */ 4600Sstevel@tonic-gate return (fc_run_priv(dev, arg, mode, credp, rvalp)); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate case FC_VALIDATE: 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * The interpreter is done, mark state as done, validating 4650Sstevel@tonic-gate * the data downloaded into the kernel. 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate return (fc_validate(dev, arg, mode, credp, rvalp)); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate case FC_GET_FCODE_DATA: 4700Sstevel@tonic-gate /* 4710Sstevel@tonic-gate * Copy out device fcode to user buffer. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate return (fc_get_fcode(dev, arg, mode, credp, rvalp)); 4740Sstevel@tonic-gate 475*762Sdhain 476*762Sdhain case FC_SET_FCODE_ERROR: 477*762Sdhain /* 478*762Sdhain * Copy in interpreter error status 479*762Sdhain */ 480*762Sdhain return (fc_set_fcode_error(dev, arg, mode, credp, rvalp)); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * Invalid ioctl command 4840Sstevel@tonic-gate */ 4850Sstevel@tonic-gate return (ENOTTY); 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* 4890Sstevel@tonic-gate * fc_get_parameters: Get information about the current request. 4900Sstevel@tonic-gate * The input 'arg' is a pointer to 'struct fc_parameters' which 4910Sstevel@tonic-gate * we write back to the caller with the information from the req 4920Sstevel@tonic-gate * structure. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /*ARGSUSED*/ 4960Sstevel@tonic-gate static int 4970Sstevel@tonic-gate fc_get_parameters(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 4980Sstevel@tonic-gate { 4990Sstevel@tonic-gate struct fc_state *st; 5000Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 5010Sstevel@tonic-gate fco_handle_t rp; 5020Sstevel@tonic-gate struct fc_parameters *fcp; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate st = fc_states + m; 5050Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_READ_DONE 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate if (st->state != FC_STATE_READ_DONE) { 5120Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_get_parameters: " 5130Sstevel@tonic-gate "wrong state (%d)\n", st->state); 5140Sstevel@tonic-gate return (EINVAL); 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate ASSERT(st->req != NULL); 5180Sstevel@tonic-gate rp = st->req->handle; 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_parameters fp: %p\n", st->req); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * Create and copyout the attachment point ihandle, 5240Sstevel@tonic-gate * the fcode kaddr,len and the unit address. 5250Sstevel@tonic-gate * Note how we treat ihandles and phandles (they are the same thing 5260Sstevel@tonic-gate * only accross this interface ... a dev_info_t *.) 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate fcp = kmem_zalloc(sizeof (struct fc_parameters), KM_SLEEP); 5290Sstevel@tonic-gate fcp->fcode_size = rp->fcode_size; 5300Sstevel@tonic-gate (void) strncpy(fcp->unit_address, rp->unit_address, 5310Sstevel@tonic-gate sizeof (fcp->unit_address) - 1); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * XXX - APA This needs to be made more bus independant. 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate if (rp->bus_args) { 5370Sstevel@tonic-gate bcopy(rp->bus_args, &fcp->config_address, sizeof (int)); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: config_address=%x\n", 5400Sstevel@tonic-gate fcp->config_address); 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate } else { 5430Sstevel@tonic-gate FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_parameters " 5440Sstevel@tonic-gate "There are no bus specific arguments\n"); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate if (copyout(fcp, (void *)arg, sizeof (struct fc_parameters)) == -1) { 5470Sstevel@tonic-gate kmem_free(fcp, sizeof (struct fc_parameters)); 5480Sstevel@tonic-gate return (EFAULT); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate kmem_free(fcp, sizeof (struct fc_parameters)); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * Update our state 5540Sstevel@tonic-gate */ 5550Sstevel@tonic-gate mutex_enter(&fc_open_lock); 5560Sstevel@tonic-gate st->state = FC_STATE_IN_PROGRESS; 5570Sstevel@tonic-gate mutex_exit(&fc_open_lock); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate return (0); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* 5630Sstevel@tonic-gate * fc_get_my_args: Get the initial setting for my-args. 5640Sstevel@tonic-gate * The input 'arg' is a pointer where the my-arg string is written 5650Sstevel@tonic-gate * to. The string is NULL terminated. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate /*ARGSUSED*/ 5690Sstevel@tonic-gate static int 5700Sstevel@tonic-gate fc_get_my_args(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 5710Sstevel@tonic-gate { 5720Sstevel@tonic-gate struct fc_state *st; 5730Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 5740Sstevel@tonic-gate fco_handle_t rp; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate st = fc_states + m; 5770Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_READ_DONE 5810Sstevel@tonic-gate */ 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 5840Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_get_my_args: " 5850Sstevel@tonic-gate "wrong state (%d)\n", st->state); 5860Sstevel@tonic-gate return (EINVAL); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate ASSERT(st->req != NULL); 5900Sstevel@tonic-gate rp = st->req->handle; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args fp: %p\n", st->req); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (rp->my_args == NULL) { 5950Sstevel@tonic-gate FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_my_args " 5960Sstevel@tonic-gate "There are no bus specific my-args\n"); 5970Sstevel@tonic-gate return (EINVAL); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (strlen(rp->my_args) > FC_GET_MY_ARGS_BUFLEN) { 6010Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args " 6020Sstevel@tonic-gate "my-args is larger than %d\n", FC_GET_MY_ARGS_BUFLEN); 6030Sstevel@tonic-gate return (EINVAL); 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate if (copyout(rp->my_args, (void *)arg, strlen(rp->my_args) + 1) == -1) { 6080Sstevel@tonic-gate return (EFAULT); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate return (0); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /*ARGSUSED*/ 6150Sstevel@tonic-gate static int 6160Sstevel@tonic-gate fc_run_priv(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 6170Sstevel@tonic-gate { 6180Sstevel@tonic-gate struct fc_state *st; 6190Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 6200Sstevel@tonic-gate struct fc_request *fp; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate struct fc_client_interface tc, *cp, *ap; 6230Sstevel@tonic-gate size_t csize; 6240Sstevel@tonic-gate int nresults, nargs, error; 6250Sstevel@tonic-gate char *name; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate ap = (struct fc_client_interface *)arg; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate st = fc_states + m; 6300Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_IN_PROGRESS 6340Sstevel@tonic-gate */ 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 6370Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_run_priv: wrong state (%d)\n", 6380Sstevel@tonic-gate st->state); 6390Sstevel@tonic-gate return (EINVAL); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * Get the first three cells to figure out how large the buffer 6440Sstevel@tonic-gate * needs to be; allocate it and copy it in. The array is variable 6450Sstevel@tonic-gate * sized based on the fixed portion plus the given number of arg. 6460Sstevel@tonic-gate * cells and given number of result cells. 6470Sstevel@tonic-gate */ 6480Sstevel@tonic-gate if (copyin((void *)arg, &tc, 3 * sizeof (fc_cell_t))) { 6490Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 6500Sstevel@tonic-gate "fault copying in first 2 cells from %p\n", arg); 6510Sstevel@tonic-gate return (EFAULT); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * XXX We should probably limit #args and #results to something 6560Sstevel@tonic-gate * reasonable without blindly copying it in. 6570Sstevel@tonic-gate */ 6580Sstevel@tonic-gate nresults = fc_cell2int(tc.nresults); /* save me for later */ 6590Sstevel@tonic-gate nargs = fc_cell2int(tc.nargs); 6600Sstevel@tonic-gate csize = (FCC_FIXED_CELLS + nargs + nresults) * sizeof (fc_cell_t); 6610Sstevel@tonic-gate cp = kmem_zalloc(csize, KM_SLEEP); 6620Sstevel@tonic-gate /* 6630Sstevel@tonic-gate * Don't bother copying in the result cells 6640Sstevel@tonic-gate */ 6650Sstevel@tonic-gate if (copyin((void *)arg, cp, csize - (nresults * sizeof (fc_cell_t)))) { 6660Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 6670Sstevel@tonic-gate "fault copying in argument array from %p\n", arg); 6680Sstevel@tonic-gate kmem_free(cp, csize); 6690Sstevel@tonic-gate return (EFAULT); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate * reset the error fields. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate cp->error = fc_int2cell(0); 6750Sstevel@tonic-gate cp->priv_error = fc_int2cell(0); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * Copy in the service name into our copy of the array. 6790Sstevel@tonic-gate * Later, be careful not to copy out the svc name pointer. 6800Sstevel@tonic-gate */ 6810Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 6820Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(cp->svc_name), name, 6830Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 6840Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 6850Sstevel@tonic-gate "fault copying in service name from %p\n", 6860Sstevel@tonic-gate fc_cell2ptr(cp->svc_name)); 6870Sstevel@tonic-gate kmem_free(cp, csize); 6880Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 6890Sstevel@tonic-gate return (EFAULT); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(name); 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate FC_DEBUG3(7, CE_CONT, "fc_ioctl: fc_run_priv: " 6940Sstevel@tonic-gate "service name <%s> nargs %d nresults %d\n", 6950Sstevel@tonic-gate name, fc_cell2int(cp->nargs), fc_cell2int(cp->nresults)); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate /* 6980Sstevel@tonic-gate * Call the driver's ops function to provide the service 6990Sstevel@tonic-gate */ 7000Sstevel@tonic-gate fp = st->req; 7010Sstevel@tonic-gate ASSERT(fp->ap_ops); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate error = fp->ap_ops(fp->ap_dip, fp->handle, cp); 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * If error is non-zero, we need to log the error and 7070Sstevel@tonic-gate * the service name, and write back the error to the 7080Sstevel@tonic-gate * callers argument array. 7090Sstevel@tonic-gate */ 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (error || cp->error) { 7120Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 7130Sstevel@tonic-gate "service name <%s> was unserviced\n", name); 7140Sstevel@tonic-gate cp->error = FC_ERR_SVC_NAME; 7150Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 7160Sstevel@tonic-gate error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 7170Sstevel@tonic-gate error |= copyout(&cp->nresults, &ap->nresults, 7180Sstevel@tonic-gate sizeof (fc_cell_t)); 7190Sstevel@tonic-gate kmem_free(cp, csize); 7200Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 7210Sstevel@tonic-gate if (error) { 7220Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 7230Sstevel@tonic-gate "fault copying out error result\n"); 7240Sstevel@tonic-gate return (EFAULT); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate return (0); 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if (cp->priv_error) { 7300Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 7310Sstevel@tonic-gate "service name <%s> caused a priv violation\n", name); 7320Sstevel@tonic-gate cp->priv_error = FC_PRIV_ERROR; 7330Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 7340Sstevel@tonic-gate error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 7350Sstevel@tonic-gate error |= copyout(&cp->priv_error, &ap->priv_error, 7360Sstevel@tonic-gate sizeof (fc_cell_t)); 7370Sstevel@tonic-gate error |= copyout(&cp->nresults, &ap->nresults, 7380Sstevel@tonic-gate sizeof (fc_cell_t)); 7390Sstevel@tonic-gate kmem_free(cp, csize); 7400Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 7410Sstevel@tonic-gate if (error) { 7420Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 7430Sstevel@tonic-gate "fault copying out priv error result\n"); 7440Sstevel@tonic-gate return (EFAULT); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate return (0); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * We believe we have a successful result at this point, thus we 7510Sstevel@tonic-gate * have to copy out the actual number of result cells to be 7520Sstevel@tonic-gate * returned, the two error fields and each of the results. 7530Sstevel@tonic-gate */ 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (fc_cell2int(cp->nresults) > nresults) 7560Sstevel@tonic-gate cmn_err(CE_PANIC, "fc_ioctl: fc_run_priv: " 7570Sstevel@tonic-gate "results (from ops function) overflow\n"); 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate error = copyout(&cp->nresults, &ap->nresults, sizeof (fc_cell_t)); 7600Sstevel@tonic-gate error |= copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 7610Sstevel@tonic-gate error |= copyout(&cp->priv_error, &ap->priv_error, sizeof (fc_cell_t)); 7620Sstevel@tonic-gate if ((error == 0) && cp->nresults) 7630Sstevel@tonic-gate error |= copyout(&fc_result(cp, 0), &(ap->v[nargs]), 7640Sstevel@tonic-gate cp->nresults * sizeof (fc_cell_t)); 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate kmem_free(cp, csize); 7670Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate if (error) { 7700Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 7710Sstevel@tonic-gate "fault copying out (good) results\n"); 7720Sstevel@tonic-gate return (EFAULT); 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate return (0); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /*ARGSUSED*/ 7780Sstevel@tonic-gate static int 7790Sstevel@tonic-gate fc_validate(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 7800Sstevel@tonic-gate { 7810Sstevel@tonic-gate struct fc_state *st; 7820Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 7830Sstevel@tonic-gate struct fc_request *fp; 7840Sstevel@tonic-gate struct fc_client_interface *cp; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate st = fc_states + m; 7870Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /* 7900Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_IN_PROGRESS 7910Sstevel@tonic-gate */ 7920Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 7930Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_validate: wrong state (%d)\n", 7940Sstevel@tonic-gate st->state); 7950Sstevel@tonic-gate return (EINVAL); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate FC_DEBUG0(2, CE_CONT, "fc_ioctl: fc_validate: Sending validate cmd\n"); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * Send a "validate" command down the line. 8020Sstevel@tonic-gate * The command has no arguments and no results. 8030Sstevel@tonic-gate */ 8040Sstevel@tonic-gate cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 8050Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_VALIDATE); 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate fp = st->req; 8080Sstevel@tonic-gate ASSERT(fp->ap_ops); 8090Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate kmem_free(cp, sizeof (struct fc_client_interface)); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate /* 8140Sstevel@tonic-gate * Update our state. 8150Sstevel@tonic-gate */ 8160Sstevel@tonic-gate mutex_enter(&fc_open_lock); 8170Sstevel@tonic-gate st->state = FC_STATE_VALIDATED; 8180Sstevel@tonic-gate mutex_exit(&fc_open_lock); 8190Sstevel@tonic-gate return (0); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * fc_get_fcode: Copy out device fcode to user buffer. 8240Sstevel@tonic-gate * The input 'arg' is a pointer to 'fc_fcode_info_t' which 8250Sstevel@tonic-gate * should have fcode_size field set. The fcode_ptr field is a 8260Sstevel@tonic-gate * pointer to a user buffer of fcode_size. 8270Sstevel@tonic-gate */ 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /*ARGSUSED*/ 8300Sstevel@tonic-gate static int 8310Sstevel@tonic-gate fc_get_fcode(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 8320Sstevel@tonic-gate { 8330Sstevel@tonic-gate struct fc_state *st; 8340Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 8350Sstevel@tonic-gate fco_handle_t rp; 8360Sstevel@tonic-gate struct fc_fcode_info fcode_info; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate st = fc_states + m; 8390Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate ASSERT(st->req != NULL); 8420Sstevel@tonic-gate rp = st->req->handle; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_fcode fp: %p\n", st->req); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * Get the fc_fcode_info structure from userland. 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate if (copyin((void *)arg, &fcode_info, sizeof (fc_fcode_info_t))) { 8500Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 8510Sstevel@tonic-gate "fault copying in fcode_info from %p\n", arg); 8520Sstevel@tonic-gate return (EFAULT); 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /* 8560Sstevel@tonic-gate * Validate that buffer size is what we expect. 8570Sstevel@tonic-gate */ 8580Sstevel@tonic-gate if (fcode_info.fcode_size != rp->fcode_size) { 8590Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "fc_ioctl: fc_get_fcode " 8600Sstevel@tonic-gate "requested size (0x%x) doesn't match real size (0x%x)\n", 8610Sstevel@tonic-gate fcode_info.fcode_size, rp->fcode_size); 8620Sstevel@tonic-gate return (EINVAL); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* 8660Sstevel@tonic-gate * Copyout the fcode. 8670Sstevel@tonic-gate */ 8680Sstevel@tonic-gate if (copyout(rp->fcode, fcode_info.fcode_ptr, rp->fcode_size) == -1) { 8690Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 8700Sstevel@tonic-gate "fault copying out fcode to %p\n", fcode_info.fcode_ptr); 8710Sstevel@tonic-gate return (EFAULT); 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate return (0); 8750Sstevel@tonic-gate } 876*762Sdhain 877*762Sdhain /* 878*762Sdhain * fc_set_fcode_error: Copy in fcode error. 879*762Sdhain * The input 'arg' is a pointer to int which 880*762Sdhain * should have the appropriate error code set. 881*762Sdhain */ 882*762Sdhain 883*762Sdhain /*ARGSUSED*/ 884*762Sdhain static int 885*762Sdhain fc_set_fcode_error(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 886*762Sdhain { 887*762Sdhain struct fc_state *st; 888*762Sdhain struct fc_request *fp; 889*762Sdhain int m = (int)getminor(dev) - 1; 890*762Sdhain int status; 891*762Sdhain 892*762Sdhain st = fc_states + m; 893*762Sdhain ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 894*762Sdhain 895*762Sdhain ASSERT(st->req != NULL); 896*762Sdhain fp = st->req; 897*762Sdhain 898*762Sdhain FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_set_fcode_error fp: %p\n", fp); 899*762Sdhain 900*762Sdhain /* 901*762Sdhain * Get the error code from userland. 902*762Sdhain * We expect these to be negative values to denote 903*762Sdhain * interpreter errors. 904*762Sdhain */ 905*762Sdhain if (copyin((void *)arg, &status, sizeof (int))) { 906*762Sdhain FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_set_fcode_error " 907*762Sdhain "fault copying in status from %p\n", arg); 908*762Sdhain return (EFAULT); 909*762Sdhain } 910*762Sdhain 911*762Sdhain if (!FC_ERROR_VALID(status)) { 912*762Sdhain FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_set_fcode_error " 913*762Sdhain "invalid error code specified %i\n", status); 914*762Sdhain return (EINVAL); 915*762Sdhain } 916*762Sdhain fp->error = status; 917*762Sdhain mutex_enter(&fc_open_lock); 918*762Sdhain st->state = FC_STATE_ERROR_SET; 919*762Sdhain mutex_exit(&fc_open_lock); 920*762Sdhain 921*762Sdhain return (0); 922*762Sdhain } 923