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