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