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