1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * fcode helper driver -- provide priv. access and kernel communication 31*0Sstevel@tonic-gate * to the userland fcode interpreter. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/cred.h> 35*0Sstevel@tonic-gate #include <sys/mman.h> 36*0Sstevel@tonic-gate #include <sys/kmem.h> 37*0Sstevel@tonic-gate #include <sys/conf.h> 38*0Sstevel@tonic-gate #include <sys/ddi.h> 39*0Sstevel@tonic-gate #include <sys/sunddi.h> 40*0Sstevel@tonic-gate #include <sys/sunndi.h> 41*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 42*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 43*0Sstevel@tonic-gate #include <sys/modctl.h> 44*0Sstevel@tonic-gate #include <sys/stat.h> 45*0Sstevel@tonic-gate #include <sys/fcode.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate static int fc_max_opens = 32; /* Up to this many simultaneous opens */ 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * Soft state associated with each instance of driver open. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate static struct fc_state { 53*0Sstevel@tonic-gate int state; /* available flag or active state */ 54*0Sstevel@tonic-gate struct fc_request *req; /* Active Request */ 55*0Sstevel@tonic-gate } *fc_states; 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #define FC_STATE_INACTIVE 0 /* Unopen, available for use */ 58*0Sstevel@tonic-gate #define FC_STATE_OPEN 1 /* Inital open */ 59*0Sstevel@tonic-gate #define FC_STATE_READ_DONE 2 /* blocking read done */ 60*0Sstevel@tonic-gate #define FC_STATE_IN_PROGRESS 3 /* FC_GET_PARAMETERS done, active */ 61*0Sstevel@tonic-gate #define FC_STATE_VALIDATED 4 /* FC_VALIDATE done, active */ 62*0Sstevel@tonic-gate #define FC_STATE_ACTIVE(s) ((s) != 0) 63*0Sstevel@tonic-gate #define FC_STATE_AVAILABLE(s) ((s) == FC_STATE_INACTIVE) 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static kmutex_t fc_open_lock; /* serialize instance assignment */ 66*0Sstevel@tonic-gate static kcondvar_t fc_open_cv; /* wait for available open */ 67*0Sstevel@tonic-gate static int fc_open_count; /* number of current open instance */ 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate static int fc_open(dev_t *, int, int, cred_t *); 70*0Sstevel@tonic-gate static int fc_close(dev_t, int, int, cred_t *); 71*0Sstevel@tonic-gate static int fc_read(dev_t, struct uio *, cred_t *); 72*0Sstevel@tonic-gate static int fc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 73*0Sstevel@tonic-gate static int fc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 74*0Sstevel@tonic-gate static int fc_attach(dev_info_t *, ddi_attach_cmd_t cmd); 75*0Sstevel@tonic-gate static int fc_detach(dev_info_t *, ddi_detach_cmd_t cmd); 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate static int fc_get_parameters(dev_t, intptr_t, int, cred_t *, int *); 78*0Sstevel@tonic-gate static int fc_get_my_args(dev_t, intptr_t, int, cred_t *, int *); 79*0Sstevel@tonic-gate static int fc_run_priv(dev_t, intptr_t, int, cred_t *, int *); 80*0Sstevel@tonic-gate static int fc_validate(dev_t, intptr_t, int, cred_t *, int *); 81*0Sstevel@tonic-gate static int fc_get_fcode(dev_t, intptr_t, int, cred_t *, int *); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static struct cb_ops fc_cb_ops = { 84*0Sstevel@tonic-gate fc_open, /* open */ 85*0Sstevel@tonic-gate fc_close, /* close */ 86*0Sstevel@tonic-gate nodev, /* strategy */ 87*0Sstevel@tonic-gate nodev, /* print */ 88*0Sstevel@tonic-gate nodev, /* dump */ 89*0Sstevel@tonic-gate fc_read, /* read */ 90*0Sstevel@tonic-gate nodev, /* write */ 91*0Sstevel@tonic-gate fc_ioctl, /* ioctl */ 92*0Sstevel@tonic-gate nodev, /* devmap */ 93*0Sstevel@tonic-gate nodev, /* mmap */ 94*0Sstevel@tonic-gate nodev, /* segmap */ 95*0Sstevel@tonic-gate nochpoll, /* poll */ 96*0Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 97*0Sstevel@tonic-gate NULL, /* streamtab */ 98*0Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 99*0Sstevel@tonic-gate }; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate static struct dev_ops fcode_ops = { 102*0Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 103*0Sstevel@tonic-gate 0, /* refcnt */ 104*0Sstevel@tonic-gate fc_info, /* info */ 105*0Sstevel@tonic-gate nulldev, /* identify */ 106*0Sstevel@tonic-gate nulldev, /* probe */ 107*0Sstevel@tonic-gate fc_attach, /* attach */ 108*0Sstevel@tonic-gate fc_detach, /* detach */ 109*0Sstevel@tonic-gate nodev, /* reset */ 110*0Sstevel@tonic-gate &fc_cb_ops, /* driver operations */ 111*0Sstevel@tonic-gate NULL /* bus operations */ 112*0Sstevel@tonic-gate }; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Module linkage information for the kernel. 116*0Sstevel@tonic-gate */ 117*0Sstevel@tonic-gate static struct modldrv modldrv = { 118*0Sstevel@tonic-gate &mod_driverops, 119*0Sstevel@tonic-gate "FCode driver %I%", 120*0Sstevel@tonic-gate &fcode_ops 121*0Sstevel@tonic-gate }; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 124*0Sstevel@tonic-gate MODREV_1, 125*0Sstevel@tonic-gate &modldrv, 126*0Sstevel@tonic-gate NULL 127*0Sstevel@tonic-gate }; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate #ifndef lint 130*0Sstevel@tonic-gate static char _depends_on[] = "misc/fcodem"; 131*0Sstevel@tonic-gate #endif 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate int 134*0Sstevel@tonic-gate _init(void) 135*0Sstevel@tonic-gate { 136*0Sstevel@tonic-gate int error; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate mutex_init(&fc_open_lock, NULL, MUTEX_DRIVER, NULL); 139*0Sstevel@tonic-gate cv_init(&fc_open_cv, NULL, CV_DRIVER, NULL); 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate error = mod_install(&modlinkage); 142*0Sstevel@tonic-gate if (error != 0) { 143*0Sstevel@tonic-gate mutex_destroy(&fc_open_lock); 144*0Sstevel@tonic-gate cv_destroy(&fc_open_cv); 145*0Sstevel@tonic-gate return (error); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate return (0); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate int 152*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 153*0Sstevel@tonic-gate { 154*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate int 158*0Sstevel@tonic-gate _fini(void) 159*0Sstevel@tonic-gate { 160*0Sstevel@tonic-gate int error; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate error = mod_remove(&modlinkage); 163*0Sstevel@tonic-gate if (error != 0) { 164*0Sstevel@tonic-gate return (error); 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate mutex_destroy(&fc_open_lock); 168*0Sstevel@tonic-gate cv_destroy(&fc_open_cv); 169*0Sstevel@tonic-gate return (0); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate static dev_info_t *fc_dip; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /*ARGSUSED*/ 175*0Sstevel@tonic-gate static int 176*0Sstevel@tonic-gate fc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 177*0Sstevel@tonic-gate { 178*0Sstevel@tonic-gate int error = DDI_FAILURE; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate switch (infocmd) { 181*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 182*0Sstevel@tonic-gate *result = (void *)fc_dip; 183*0Sstevel@tonic-gate error = DDI_SUCCESS; 184*0Sstevel@tonic-gate break; 185*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 186*0Sstevel@tonic-gate /* All dev_t's map to the same, single instance */ 187*0Sstevel@tonic-gate *result = (void *)0; 188*0Sstevel@tonic-gate error = DDI_SUCCESS; 189*0Sstevel@tonic-gate break; 190*0Sstevel@tonic-gate default: 191*0Sstevel@tonic-gate break; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate return (error); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static int 198*0Sstevel@tonic-gate fc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate int error = DDI_FAILURE; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate switch (cmd) { 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate case DDI_ATTACH: 205*0Sstevel@tonic-gate fc_open_count = 0; 206*0Sstevel@tonic-gate fc_states = kmem_zalloc( 207*0Sstevel@tonic-gate fc_max_opens * sizeof (struct fc_state), KM_SLEEP); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (ddi_create_minor_node(dip, "fcode", S_IFCHR, 210*0Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 211*0Sstevel@tonic-gate kmem_free(fc_states, 212*0Sstevel@tonic-gate fc_max_opens * sizeof (struct fc_state)); 213*0Sstevel@tonic-gate error = DDI_FAILURE; 214*0Sstevel@tonic-gate } else { 215*0Sstevel@tonic-gate fc_dip = dip; 216*0Sstevel@tonic-gate ddi_report_dev(dip); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate error = DDI_SUCCESS; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate break; 221*0Sstevel@tonic-gate default: 222*0Sstevel@tonic-gate error = DDI_FAILURE; 223*0Sstevel@tonic-gate break; 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate return (error); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate static int 230*0Sstevel@tonic-gate fc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 231*0Sstevel@tonic-gate { 232*0Sstevel@tonic-gate int error = DDI_FAILURE; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate switch (cmd) { 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate case DDI_DETACH: 237*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 238*0Sstevel@tonic-gate fc_dip = NULL; 239*0Sstevel@tonic-gate kmem_free(fc_states, fc_max_opens * sizeof (struct fc_state)); 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate error = DDI_SUCCESS; 242*0Sstevel@tonic-gate break; 243*0Sstevel@tonic-gate default: 244*0Sstevel@tonic-gate error = DDI_FAILURE; 245*0Sstevel@tonic-gate break; 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate return (error); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * Allow multiple opens by tweaking the dev_t such that it looks like each 253*0Sstevel@tonic-gate * open is getting a different minor device. Each minor gets a separate 254*0Sstevel@tonic-gate * entry in the fc_states[] table. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate /*ARGSUSED*/ 257*0Sstevel@tonic-gate static int 258*0Sstevel@tonic-gate fc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 259*0Sstevel@tonic-gate { 260*0Sstevel@tonic-gate int m; 261*0Sstevel@tonic-gate struct fc_state *st; 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate if (getminor(*devp) != 0) 264*0Sstevel@tonic-gate return (EINVAL); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate mutex_enter(&fc_open_lock); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate while (fc_open_count >= fc_max_opens) { 269*0Sstevel@tonic-gate /* 270*0Sstevel@tonic-gate * maximum open instance reached, wait for a close 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate FC_DEBUG0(1, CE_WARN, 273*0Sstevel@tonic-gate "fcode: Maximum fcode open reached, waiting for exit\n"); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate if (cv_wait_sig(&fc_open_cv, &fc_open_lock) == 0) { 276*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 277*0Sstevel@tonic-gate return (EINTR); 278*0Sstevel@tonic-gate /*NOTREACHED*/ 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate fc_open_count++; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate for (m = 0, st = fc_states; m < fc_max_opens; m++, st++) { 284*0Sstevel@tonic-gate if (FC_STATE_ACTIVE(st->state)) 285*0Sstevel@tonic-gate continue; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate st->state = FC_STATE_OPEN; 288*0Sstevel@tonic-gate st->req = 0; 289*0Sstevel@tonic-gate break; /* It's ours. */ 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate ASSERT(m < fc_max_opens); 294*0Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), (minor_t)(m + 1)); 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "fc_open: open count = %d (%d)\n", 297*0Sstevel@tonic-gate fc_open_count, m + 1); 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate return (0); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /*ARGSUSED*/ 303*0Sstevel@tonic-gate static int 304*0Sstevel@tonic-gate fc_close(dev_t dev, int flag, int otype, cred_t *cred_p) 305*0Sstevel@tonic-gate { 306*0Sstevel@tonic-gate struct fc_state *st; 307*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 308*0Sstevel@tonic-gate struct fc_request *fp; 309*0Sstevel@tonic-gate struct fc_client_interface *cp; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate st = fc_states + m; 312*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * The close indicates we're done with this request. 316*0Sstevel@tonic-gate * If we haven't validated this request, then something 317*0Sstevel@tonic-gate * bad may have happened (ie: perhaps the user program was 318*0Sstevel@tonic-gate * killed), so we should invalidate it, then close the session. 319*0Sstevel@tonic-gate */ 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (st->state == FC_STATE_READ_DONE) { 322*0Sstevel@tonic-gate fp = st->req; 323*0Sstevel@tonic-gate fp->error = FC_ERROR; 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (st->state > FC_STATE_READ_DONE) { 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 329*0Sstevel@tonic-gate fp = st->req; 330*0Sstevel@tonic-gate ASSERT(fp); 331*0Sstevel@tonic-gate ASSERT(fp->ap_ops); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate if (st->state != FC_STATE_VALIDATED) { 334*0Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, 335*0Sstevel@tonic-gate "fc_close: Send invalidate cmd\n"); 336*0Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_INVALIDATE); 337*0Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 338*0Sstevel@tonic-gate fp->error = FC_ERROR; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate bzero(cp, sizeof (struct fc_client_interface)); 342*0Sstevel@tonic-gate FC_DEBUG0(9, CE_CONT, "fc_close: Sending exit cmd\n"); 343*0Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_EXIT); 344*0Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate kmem_free(cp, sizeof (struct fc_client_interface)); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Mark the request as done ... 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate if ((fp = st->req) != NULL) 353*0Sstevel@tonic-gate fc_finish_request(fp); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate /* 356*0Sstevel@tonic-gate * rectify count and signal any waiters 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate mutex_enter(&fc_open_lock); 359*0Sstevel@tonic-gate st->state = FC_STATE_INACTIVE; 360*0Sstevel@tonic-gate st->req = 0; 361*0Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "fc_close: open count = %d (%d)\n", 362*0Sstevel@tonic-gate fc_open_count, m + 1); 363*0Sstevel@tonic-gate if (fc_open_count >= fc_max_opens) { 364*0Sstevel@tonic-gate cv_broadcast(&fc_open_cv); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate fc_open_count--; 367*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate return (0); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /*ARGSUSED*/ 373*0Sstevel@tonic-gate static int 374*0Sstevel@tonic-gate fc_read(dev_t dev, struct uio *uio, cred_t *cred) 375*0Sstevel@tonic-gate { 376*0Sstevel@tonic-gate struct fc_state *st; 377*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 378*0Sstevel@tonic-gate struct fc_request *fp; 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate st = fc_states + m; 381*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * Wait for a internal request for the interpreter 385*0Sstevel@tonic-gate * and sleep till one arrives. When one arrives, 386*0Sstevel@tonic-gate * return from the read. (No data is actually returned). 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate if (st->state != FC_STATE_OPEN) { 390*0Sstevel@tonic-gate cmn_err(CE_CONT, "fc_read: Wrong state (%d) for read\n", 391*0Sstevel@tonic-gate st->state); 392*0Sstevel@tonic-gate return (EINVAL); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /* 396*0Sstevel@tonic-gate * Wait for a request, allowing the wait to be interrupted. 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate if ((fp = fc_get_request()) == NULL) 399*0Sstevel@tonic-gate return (EINTR); 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_read: request fp: %p\n", fp); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * Update our state and store the request pointer. 405*0Sstevel@tonic-gate */ 406*0Sstevel@tonic-gate mutex_enter(&fc_open_lock); 407*0Sstevel@tonic-gate st->req = fp; 408*0Sstevel@tonic-gate st->state = FC_STATE_READ_DONE; 409*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate return (0); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /*ARGSUSED*/ 415*0Sstevel@tonic-gate static int 416*0Sstevel@tonic-gate fc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 417*0Sstevel@tonic-gate { 418*0Sstevel@tonic-gate struct fc_state *st; 419*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate if (m >= fc_max_opens) { 422*0Sstevel@tonic-gate return (EINVAL); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate st = fc_states + m; 426*0Sstevel@tonic-gate ASSERT(FC_STATE_ACTIVE(st->state)); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate switch (cmd) { 429*0Sstevel@tonic-gate case FC_GET_PARAMETERS: 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * This should be the first command and is used to 432*0Sstevel@tonic-gate * return data about the request, including the 433*0Sstevel@tonic-gate * the fcode address and size and the unit address 434*0Sstevel@tonic-gate * of the new child. The fcode offset,size can later 435*0Sstevel@tonic-gate * be used as an offset in an mmap request to allow 436*0Sstevel@tonic-gate * the fcode to be mapped in. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate return (fc_get_parameters(dev, arg, mode, credp, rvalp)); 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate case FC_GET_MY_ARGS: 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Get the inital setting of my-args. This should be done 443*0Sstevel@tonic-gate * after FC_GET_PARAMETERS. 444*0Sstevel@tonic-gate */ 445*0Sstevel@tonic-gate return (fc_get_my_args(dev, arg, mode, credp, rvalp)); 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate case FC_RUN_PRIV: 448*0Sstevel@tonic-gate /* 449*0Sstevel@tonic-gate * Run a priveledged op on behalf of the interpreter, 450*0Sstevel@tonic-gate * or download device tree data from the interpreter. 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate return (fc_run_priv(dev, arg, mode, credp, rvalp)); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate case FC_VALIDATE: 455*0Sstevel@tonic-gate /* 456*0Sstevel@tonic-gate * The interpreter is done, mark state as done, validating 457*0Sstevel@tonic-gate * the data downloaded into the kernel. 458*0Sstevel@tonic-gate */ 459*0Sstevel@tonic-gate return (fc_validate(dev, arg, mode, credp, rvalp)); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate case FC_GET_FCODE_DATA: 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * Copy out device fcode to user buffer. 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate return (fc_get_fcode(dev, arg, mode, credp, rvalp)); 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate /* 469*0Sstevel@tonic-gate * Invalid ioctl command 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate return (ENOTTY); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* 475*0Sstevel@tonic-gate * fc_get_parameters: Get information about the current request. 476*0Sstevel@tonic-gate * The input 'arg' is a pointer to 'struct fc_parameters' which 477*0Sstevel@tonic-gate * we write back to the caller with the information from the req 478*0Sstevel@tonic-gate * structure. 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /*ARGSUSED*/ 482*0Sstevel@tonic-gate static int 483*0Sstevel@tonic-gate fc_get_parameters(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate struct fc_state *st; 486*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 487*0Sstevel@tonic-gate fco_handle_t rp; 488*0Sstevel@tonic-gate struct fc_parameters *fcp; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate st = fc_states + m; 491*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate /* 494*0Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_READ_DONE 495*0Sstevel@tonic-gate */ 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate if (st->state != FC_STATE_READ_DONE) { 498*0Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_get_parameters: " 499*0Sstevel@tonic-gate "wrong state (%d)\n", st->state); 500*0Sstevel@tonic-gate return (EINVAL); 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate ASSERT(st->req != NULL); 504*0Sstevel@tonic-gate rp = st->req->handle; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_parameters fp: %p\n", st->req); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * Create and copyout the attachment point ihandle, 510*0Sstevel@tonic-gate * the fcode kaddr,len and the unit address. 511*0Sstevel@tonic-gate * Note how we treat ihandles and phandles (they are the same thing 512*0Sstevel@tonic-gate * only accross this interface ... a dev_info_t *.) 513*0Sstevel@tonic-gate */ 514*0Sstevel@tonic-gate fcp = kmem_zalloc(sizeof (struct fc_parameters), KM_SLEEP); 515*0Sstevel@tonic-gate fcp->fcode_size = rp->fcode_size; 516*0Sstevel@tonic-gate (void) strncpy(fcp->unit_address, rp->unit_address, 517*0Sstevel@tonic-gate sizeof (fcp->unit_address) - 1); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * XXX - APA This needs to be made more bus independant. 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if (rp->bus_args) { 523*0Sstevel@tonic-gate bcopy(rp->bus_args, &fcp->config_address, sizeof (int)); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: config_address=%x\n", 526*0Sstevel@tonic-gate fcp->config_address); 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate } else { 529*0Sstevel@tonic-gate FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_parameters " 530*0Sstevel@tonic-gate "There are no bus specific arguments\n"); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate if (copyout(fcp, (void *)arg, sizeof (struct fc_parameters)) == -1) { 533*0Sstevel@tonic-gate kmem_free(fcp, sizeof (struct fc_parameters)); 534*0Sstevel@tonic-gate return (EFAULT); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate kmem_free(fcp, sizeof (struct fc_parameters)); 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* 539*0Sstevel@tonic-gate * Update our state 540*0Sstevel@tonic-gate */ 541*0Sstevel@tonic-gate mutex_enter(&fc_open_lock); 542*0Sstevel@tonic-gate st->state = FC_STATE_IN_PROGRESS; 543*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate return (0); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * fc_get_my_args: Get the initial setting for my-args. 550*0Sstevel@tonic-gate * The input 'arg' is a pointer where the my-arg string is written 551*0Sstevel@tonic-gate * to. The string is NULL terminated. 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /*ARGSUSED*/ 555*0Sstevel@tonic-gate static int 556*0Sstevel@tonic-gate fc_get_my_args(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate struct fc_state *st; 559*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 560*0Sstevel@tonic-gate fco_handle_t rp; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate st = fc_states + m; 563*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_READ_DONE 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 570*0Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_get_my_args: " 571*0Sstevel@tonic-gate "wrong state (%d)\n", st->state); 572*0Sstevel@tonic-gate return (EINVAL); 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate ASSERT(st->req != NULL); 576*0Sstevel@tonic-gate rp = st->req->handle; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args fp: %p\n", st->req); 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate if (rp->my_args == NULL) { 581*0Sstevel@tonic-gate FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_my_args " 582*0Sstevel@tonic-gate "There are no bus specific my-args\n"); 583*0Sstevel@tonic-gate return (EINVAL); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate if (strlen(rp->my_args) > FC_GET_MY_ARGS_BUFLEN) { 587*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args " 588*0Sstevel@tonic-gate "my-args is larger than %d\n", FC_GET_MY_ARGS_BUFLEN); 589*0Sstevel@tonic-gate return (EINVAL); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate if (copyout(rp->my_args, (void *)arg, strlen(rp->my_args) + 1) == -1) { 594*0Sstevel@tonic-gate return (EFAULT); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate return (0); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate /*ARGSUSED*/ 601*0Sstevel@tonic-gate static int 602*0Sstevel@tonic-gate fc_run_priv(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 603*0Sstevel@tonic-gate { 604*0Sstevel@tonic-gate struct fc_state *st; 605*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 606*0Sstevel@tonic-gate struct fc_request *fp; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate struct fc_client_interface tc, *cp, *ap; 609*0Sstevel@tonic-gate size_t csize; 610*0Sstevel@tonic-gate int nresults, nargs, error; 611*0Sstevel@tonic-gate char *name; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate ap = (struct fc_client_interface *)arg; 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate st = fc_states + m; 616*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_IN_PROGRESS 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 623*0Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_run_priv: wrong state (%d)\n", 624*0Sstevel@tonic-gate st->state); 625*0Sstevel@tonic-gate return (EINVAL); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * Get the first three cells to figure out how large the buffer 630*0Sstevel@tonic-gate * needs to be; allocate it and copy it in. The array is variable 631*0Sstevel@tonic-gate * sized based on the fixed portion plus the given number of arg. 632*0Sstevel@tonic-gate * cells and given number of result cells. 633*0Sstevel@tonic-gate */ 634*0Sstevel@tonic-gate if (copyin((void *)arg, &tc, 3 * sizeof (fc_cell_t))) { 635*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 636*0Sstevel@tonic-gate "fault copying in first 2 cells from %p\n", arg); 637*0Sstevel@tonic-gate return (EFAULT); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate /* 641*0Sstevel@tonic-gate * XXX We should probably limit #args and #results to something 642*0Sstevel@tonic-gate * reasonable without blindly copying it in. 643*0Sstevel@tonic-gate */ 644*0Sstevel@tonic-gate nresults = fc_cell2int(tc.nresults); /* save me for later */ 645*0Sstevel@tonic-gate nargs = fc_cell2int(tc.nargs); 646*0Sstevel@tonic-gate csize = (FCC_FIXED_CELLS + nargs + nresults) * sizeof (fc_cell_t); 647*0Sstevel@tonic-gate cp = kmem_zalloc(csize, KM_SLEEP); 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Don't bother copying in the result cells 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate if (copyin((void *)arg, cp, csize - (nresults * sizeof (fc_cell_t)))) { 652*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 653*0Sstevel@tonic-gate "fault copying in argument array from %p\n", arg); 654*0Sstevel@tonic-gate kmem_free(cp, csize); 655*0Sstevel@tonic-gate return (EFAULT); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * reset the error fields. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate cp->error = fc_int2cell(0); 661*0Sstevel@tonic-gate cp->priv_error = fc_int2cell(0); 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * Copy in the service name into our copy of the array. 665*0Sstevel@tonic-gate * Later, be careful not to copy out the svc name pointer. 666*0Sstevel@tonic-gate */ 667*0Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 668*0Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(cp->svc_name), name, 669*0Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 670*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 671*0Sstevel@tonic-gate "fault copying in service name from %p\n", 672*0Sstevel@tonic-gate fc_cell2ptr(cp->svc_name)); 673*0Sstevel@tonic-gate kmem_free(cp, csize); 674*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 675*0Sstevel@tonic-gate return (EFAULT); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(name); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate FC_DEBUG3(7, CE_CONT, "fc_ioctl: fc_run_priv: " 680*0Sstevel@tonic-gate "service name <%s> nargs %d nresults %d\n", 681*0Sstevel@tonic-gate name, fc_cell2int(cp->nargs), fc_cell2int(cp->nresults)); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Call the driver's ops function to provide the service 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate fp = st->req; 687*0Sstevel@tonic-gate ASSERT(fp->ap_ops); 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate error = fp->ap_ops(fp->ap_dip, fp->handle, cp); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate /* 692*0Sstevel@tonic-gate * If error is non-zero, we need to log the error and 693*0Sstevel@tonic-gate * the service name, and write back the error to the 694*0Sstevel@tonic-gate * callers argument array. 695*0Sstevel@tonic-gate */ 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if (error || cp->error) { 698*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 699*0Sstevel@tonic-gate "service name <%s> was unserviced\n", name); 700*0Sstevel@tonic-gate cp->error = FC_ERR_SVC_NAME; 701*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 702*0Sstevel@tonic-gate error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 703*0Sstevel@tonic-gate error |= copyout(&cp->nresults, &ap->nresults, 704*0Sstevel@tonic-gate sizeof (fc_cell_t)); 705*0Sstevel@tonic-gate kmem_free(cp, csize); 706*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 707*0Sstevel@tonic-gate if (error) { 708*0Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 709*0Sstevel@tonic-gate "fault copying out error result\n"); 710*0Sstevel@tonic-gate return (EFAULT); 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate return (0); 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate if (cp->priv_error) { 716*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 717*0Sstevel@tonic-gate "service name <%s> caused a priv violation\n", name); 718*0Sstevel@tonic-gate cp->priv_error = FC_PRIV_ERROR; 719*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 720*0Sstevel@tonic-gate error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 721*0Sstevel@tonic-gate error |= copyout(&cp->priv_error, &ap->priv_error, 722*0Sstevel@tonic-gate sizeof (fc_cell_t)); 723*0Sstevel@tonic-gate error |= copyout(&cp->nresults, &ap->nresults, 724*0Sstevel@tonic-gate sizeof (fc_cell_t)); 725*0Sstevel@tonic-gate kmem_free(cp, csize); 726*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 727*0Sstevel@tonic-gate if (error) { 728*0Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 729*0Sstevel@tonic-gate "fault copying out priv error result\n"); 730*0Sstevel@tonic-gate return (EFAULT); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate return (0); 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * We believe we have a successful result at this point, thus we 737*0Sstevel@tonic-gate * have to copy out the actual number of result cells to be 738*0Sstevel@tonic-gate * returned, the two error fields and each of the results. 739*0Sstevel@tonic-gate */ 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) > nresults) 742*0Sstevel@tonic-gate cmn_err(CE_PANIC, "fc_ioctl: fc_run_priv: " 743*0Sstevel@tonic-gate "results (from ops function) overflow\n"); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate error = copyout(&cp->nresults, &ap->nresults, sizeof (fc_cell_t)); 746*0Sstevel@tonic-gate error |= copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 747*0Sstevel@tonic-gate error |= copyout(&cp->priv_error, &ap->priv_error, sizeof (fc_cell_t)); 748*0Sstevel@tonic-gate if ((error == 0) && cp->nresults) 749*0Sstevel@tonic-gate error |= copyout(&fc_result(cp, 0), &(ap->v[nargs]), 750*0Sstevel@tonic-gate cp->nresults * sizeof (fc_cell_t)); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate kmem_free(cp, csize); 753*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate if (error) { 756*0Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 757*0Sstevel@tonic-gate "fault copying out (good) results\n"); 758*0Sstevel@tonic-gate return (EFAULT); 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate return (0); 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate /*ARGSUSED*/ 764*0Sstevel@tonic-gate static int 765*0Sstevel@tonic-gate fc_validate(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 766*0Sstevel@tonic-gate { 767*0Sstevel@tonic-gate struct fc_state *st; 768*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 769*0Sstevel@tonic-gate struct fc_request *fp; 770*0Sstevel@tonic-gate struct fc_client_interface *cp; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate st = fc_states + m; 773*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate /* 776*0Sstevel@tonic-gate * It's an error if we're not in state FC_STATE_IN_PROGRESS 777*0Sstevel@tonic-gate */ 778*0Sstevel@tonic-gate if (st->state != FC_STATE_IN_PROGRESS) { 779*0Sstevel@tonic-gate cmn_err(CE_CONT, "fc_ioctl: fc_validate: wrong state (%d)\n", 780*0Sstevel@tonic-gate st->state); 781*0Sstevel@tonic-gate return (EINVAL); 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate FC_DEBUG0(2, CE_CONT, "fc_ioctl: fc_validate: Sending validate cmd\n"); 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate /* 787*0Sstevel@tonic-gate * Send a "validate" command down the line. 788*0Sstevel@tonic-gate * The command has no arguments and no results. 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 791*0Sstevel@tonic-gate cp->svc_name = fc_ptr2cell(FC_SVC_VALIDATE); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate fp = st->req; 794*0Sstevel@tonic-gate ASSERT(fp->ap_ops); 795*0Sstevel@tonic-gate (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate kmem_free(cp, sizeof (struct fc_client_interface)); 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate /* 800*0Sstevel@tonic-gate * Update our state. 801*0Sstevel@tonic-gate */ 802*0Sstevel@tonic-gate mutex_enter(&fc_open_lock); 803*0Sstevel@tonic-gate st->state = FC_STATE_VALIDATED; 804*0Sstevel@tonic-gate mutex_exit(&fc_open_lock); 805*0Sstevel@tonic-gate return (0); 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate /* 809*0Sstevel@tonic-gate * fc_get_fcode: Copy out device fcode to user buffer. 810*0Sstevel@tonic-gate * The input 'arg' is a pointer to 'fc_fcode_info_t' which 811*0Sstevel@tonic-gate * should have fcode_size field set. The fcode_ptr field is a 812*0Sstevel@tonic-gate * pointer to a user buffer of fcode_size. 813*0Sstevel@tonic-gate */ 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /*ARGSUSED*/ 816*0Sstevel@tonic-gate static int 817*0Sstevel@tonic-gate fc_get_fcode(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 818*0Sstevel@tonic-gate { 819*0Sstevel@tonic-gate struct fc_state *st; 820*0Sstevel@tonic-gate int m = (int)getminor(dev) - 1; 821*0Sstevel@tonic-gate fco_handle_t rp; 822*0Sstevel@tonic-gate struct fc_fcode_info fcode_info; 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate st = fc_states + m; 825*0Sstevel@tonic-gate ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate ASSERT(st->req != NULL); 828*0Sstevel@tonic-gate rp = st->req->handle; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_fcode fp: %p\n", st->req); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate /* 833*0Sstevel@tonic-gate * Get the fc_fcode_info structure from userland. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate if (copyin((void *)arg, &fcode_info, sizeof (fc_fcode_info_t))) { 836*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 837*0Sstevel@tonic-gate "fault copying in fcode_info from %p\n", arg); 838*0Sstevel@tonic-gate return (EFAULT); 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate /* 842*0Sstevel@tonic-gate * Validate that buffer size is what we expect. 843*0Sstevel@tonic-gate */ 844*0Sstevel@tonic-gate if (fcode_info.fcode_size != rp->fcode_size) { 845*0Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "fc_ioctl: fc_get_fcode " 846*0Sstevel@tonic-gate "requested size (0x%x) doesn't match real size (0x%x)\n", 847*0Sstevel@tonic-gate fcode_info.fcode_size, rp->fcode_size); 848*0Sstevel@tonic-gate return (EINVAL); 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate /* 852*0Sstevel@tonic-gate * Copyout the fcode. 853*0Sstevel@tonic-gate */ 854*0Sstevel@tonic-gate if (copyout(rp->fcode, fcode_info.fcode_ptr, rp->fcode_size) == -1) { 855*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 856*0Sstevel@tonic-gate "fault copying out fcode to %p\n", fcode_info.fcode_ptr); 857*0Sstevel@tonic-gate return (EFAULT); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate return (0); 861*0Sstevel@tonic-gate } 862