ds_pri.c revision 7656:2621e50fdf4a
1193323Sed/* 2193323Sed * CDDL HEADER START 3193323Sed * 4193323Sed * The contents of this file are subject to the terms of the 5193323Sed * Common Development and Distribution License (the "License"). 6193323Sed * You may not use this file except in compliance with the License. 7193323Sed * 8193323Sed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9193323Sed * or http://www.opensolaris.org/os/licensing. 10193323Sed * See the License for the specific language governing permissions 11193323Sed * and limitations under the License. 12193323Sed * 13193323Sed * When distributing Covered Code, include this CDDL HEADER in each 14202375Srdivacky * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15202375Srdivacky * If applicable, add the following below this CDDL HEADER, with the 16193323Sed * fields enclosed by brackets "[]" replaced with your own identifying 17193323Sed * information: Portions Copyright [yyyy] [name of copyright owner] 18193323Sed * 19202375Srdivacky * CDDL HEADER END 20202375Srdivacky */ 21202375Srdivacky/* 22202375Srdivacky * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23202375Srdivacky * Use is subject to license terms. 24202375Srdivacky */ 25202375Srdivacky 26202375Srdivacky 27202375Srdivacky/* 28202375Srdivacky * sun4v domain services PRI driver 29202375Srdivacky */ 30202375Srdivacky 31202375Srdivacky#include <sys/types.h> 32193323Sed#include <sys/file.h> 33193323Sed#include <sys/errno.h> 34193323Sed#include <sys/open.h> 35193323Sed#include <sys/cred.h> 36202375Srdivacky#include <sys/uio.h> 37202375Srdivacky#include <sys/stat.h> 38202375Srdivacky#include <sys/ksynch.h> 39202375Srdivacky#include <sys/modctl.h> 40193323Sed#include <sys/conf.h> 41202375Srdivacky#include <sys/devops.h> 42193323Sed#include <sys/debug.h> 43202375Srdivacky#include <sys/cmn_err.h> 44202375Srdivacky#include <sys/ddi.h> 45193323Sed#include <sys/sunddi.h> 46202878Srdivacky#include <sys/ds.h> 47193323Sed 48193323Sed#include <sys/ds_pri.h> 49193323Sed 50193323Sedstatic uint_t ds_pri_debug = 0; 51202375Srdivacky#define DS_PRI_DBG if (ds_pri_debug) printf 52202375Srdivacky 53202375Srdivacky#define DS_PRI_NAME "ds_pri" 54226633Sdim 55226633Sdim#define TEST_HARNESS 56226633Sdim#ifdef TEST_HARNESS 57226633Sdim#define DS_PRI_MAX_PRI_SIZE (64 * 1024) 58193323Sed 59193323Sed#define DSIOC_TEST_REG 97 60#define DSIOC_TEST_UNREG 98 61#define DSIOC_TEST_DATA 99 62 63struct ds_pri_test_data { 64 size_t size; 65 void *data; 66}; 67 68struct ds_pri_test_data32 { 69 size32_t size; 70 caddr32_t data; 71}; 72#endif /* TEST_HARNESS */ 73 74typedef enum { 75 DS_PRI_REQUEST = 0, 76 DS_PRI_DATA = 1, 77 DS_PRI_UPDATE = 2 78} ds_pri_msg_type_t; 79 80typedef struct { 81 struct { 82 uint64_t seq_num; 83 uint64_t type; 84 } hdr; 85 uint8_t data[1]; 86} ds_pri_msg_t; 87 88 /* The following are bit field flags */ 89 /* No service implies no PRI and no outstanding request */ 90typedef enum { 91 DS_PRI_NO_SERVICE = 0x0, 92 DS_PRI_HAS_SERVICE = 0x1, 93 DS_PRI_REQUESTED = 0x2, 94 DS_PRI_HAS_PRI = 0x4 95} ds_pri_flags_t; 96 97struct ds_pri_state { 98 dev_info_t *dip; 99 int instance; 100 101 kmutex_t lock; 102 kcondvar_t cv; 103 104 /* PRI/DS */ 105 ds_pri_flags_t state; 106 uint64_t gencount; 107 ds_svc_hdl_t ds_pri_handle; 108 void *ds_pri; 109 size_t ds_pri_len; 110 uint64_t req_id; 111 uint64_t last_req_id; 112 int num_opens; 113}; 114 115typedef struct ds_pri_state ds_pri_state_t; 116 117static void *ds_pri_statep; 118 119static void request_pri(ds_pri_state_t *sp); 120 121static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 122static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t); 123static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t); 124static int ds_pri_open(dev_t *, int, int, cred_t *); 125static int ds_pri_close(dev_t, int, int, cred_t *); 126static int ds_pri_read(dev_t, struct uio *, cred_t *); 127static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 128 129/* 130 * DS Callbacks 131 */ 132static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 133static void ds_pri_unreg_handler(ds_cb_arg_t arg); 134static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 135 136/* 137 * PRI DS capability registration 138 */ 139 140static ds_ver_t ds_pri_ver_1_0 = { 1, 0 }; 141 142static ds_capability_t ds_pri_cap = { 143 "pri", 144 &ds_pri_ver_1_0, 145 1 146}; 147 148/* 149 * PRI DS Client callback vector 150 */ 151static ds_clnt_ops_t ds_pri_ops = { 152 ds_pri_reg_handler, /* ds_reg_cb */ 153 ds_pri_unreg_handler, /* ds_unreg_cb */ 154 ds_pri_data_handler, /* ds_data_cb */ 155 NULL /* cb_arg */ 156}; 157 158/* 159 * DS PRI driver Ops Vector 160 */ 161static struct cb_ops ds_pri_cb_ops = { 162 ds_pri_open, /* cb_open */ 163 ds_pri_close, /* cb_close */ 164 nodev, /* cb_strategy */ 165 nodev, /* cb_print */ 166 nodev, /* cb_dump */ 167 ds_pri_read, /* cb_read */ 168 nodev, /* cb_write */ 169 ds_pri_ioctl, /* cb_ioctl */ 170 nodev, /* cb_devmap */ 171 nodev, /* cb_mmap */ 172 nodev, /* cb_segmap */ 173 nochpoll, /* cb_chpoll */ 174 ddi_prop_op, /* cb_prop_op */ 175 (struct streamtab *)NULL, /* cb_str */ 176 D_MP | D_64BIT, /* cb_flag */ 177 CB_REV, /* cb_rev */ 178 nodev, /* cb_aread */ 179 nodev /* cb_awrite */ 180}; 181 182static struct dev_ops ds_pri_dev_ops = { 183 DEVO_REV, /* devo_rev */ 184 0, /* devo_refcnt */ 185 ds_pri_getinfo, /* devo_getinfo */ 186 nulldev, /* devo_identify */ 187 nulldev, /* devo_probe */ 188 ds_pri_attach, /* devo_attach */ 189 ds_pri_detach, /* devo_detach */ 190 nodev, /* devo_reset */ 191 &ds_pri_cb_ops, /* devo_cb_ops */ 192 (struct bus_ops *)NULL, /* devo_bus_ops */ 193 nulldev, /* devo_power */ 194 ddi_quiesce_not_needed, /* devo_quiesce */ 195}; 196 197static struct modldrv modldrv = { 198 &mod_driverops, 199 "Domain Services PRI Driver", 200 &ds_pri_dev_ops 201}; 202 203static struct modlinkage modlinkage = { 204 MODREV_1, 205 (void *)&modldrv, 206 NULL 207}; 208 209 210int 211_init(void) 212{ 213 int retval; 214 215 retval = ddi_soft_state_init(&ds_pri_statep, 216 sizeof (ds_pri_state_t), 0); 217 if (retval != 0) 218 return (retval); 219 220 retval = mod_install(&modlinkage); 221 if (retval != 0) { 222 ddi_soft_state_fini(&ds_pri_statep); 223 return (retval); 224 } 225 226 return (retval); 227} 228 229 230int 231_info(struct modinfo *modinfop) 232{ 233 return (mod_info(&modlinkage, modinfop)); 234} 235 236 237int 238_fini(void) 239{ 240 int retval; 241 242 if ((retval = mod_remove(&modlinkage)) != 0) 243 return (retval); 244 245 ddi_soft_state_fini(&ds_pri_statep); 246 247 return (retval); 248} 249 250 251/*ARGSUSED*/ 252static int 253ds_pri_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 254{ 255 ds_pri_state_t *sp; 256 int retval = DDI_FAILURE; 257 258 ASSERT(resultp != NULL); 259 260 switch (cmd) { 261 case DDI_INFO_DEVT2DEVINFO: 262 sp = ddi_get_soft_state(ds_pri_statep, getminor((dev_t)arg)); 263 if (sp != NULL) { 264 *resultp = sp->dip; 265 retval = DDI_SUCCESS; 266 } else 267 *resultp = NULL; 268 break; 269 270 case DDI_INFO_DEVT2INSTANCE: 271 *resultp = (void *)(uintptr_t)getminor((dev_t)arg); 272 retval = DDI_SUCCESS; 273 break; 274 275 default: 276 break; 277 } 278 279 return (retval); 280} 281 282 283static int 284ds_pri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 285{ 286 int instance; 287 ds_pri_state_t *sp; 288 int rv; 289 290 switch (cmd) { 291 case DDI_ATTACH: 292 break; 293 294 case DDI_RESUME: 295 return (DDI_SUCCESS); 296 297 default: 298 return (DDI_FAILURE); 299 } 300 301 instance = ddi_get_instance(dip); 302 303 if (ddi_soft_state_zalloc(ds_pri_statep, instance) != 304 DDI_SUCCESS) { 305 cmn_err(CE_WARN, "%s@%d: Unable to allocate state", 306 DS_PRI_NAME, instance); 307 return (DDI_FAILURE); 308 } 309 sp = ddi_get_soft_state(ds_pri_statep, instance); 310 311 mutex_init(&sp->lock, NULL, MUTEX_DEFAULT, NULL); 312 cv_init(&sp->cv, NULL, CV_DEFAULT, NULL); 313 314 if (ddi_create_minor_node(dip, DS_PRI_NAME, S_IFCHR, instance, 315 DDI_PSEUDO, 0) != DDI_SUCCESS) { 316 cmn_err(CE_WARN, "%s@%d: Unable to create minor node", 317 DS_PRI_NAME, instance); 318 goto fail; 319 } 320 321 if (ds_pri_ops.cb_arg != NULL) 322 goto fail; 323 ds_pri_ops.cb_arg = dip; 324 325 sp->state = DS_PRI_NO_SERVICE; 326 327 /* Until the service registers the handle is invalid */ 328 sp->ds_pri_handle = DS_INVALID_HDL; 329 330 sp->ds_pri = NULL; 331 sp->ds_pri_len = 0; 332 sp->req_id = 0; 333 sp->num_opens = 0; 334 335 if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) { 336 cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv); 337 goto fail; 338 } 339 340 ddi_report_dev(dip); 341 342 return (DDI_SUCCESS); 343 344fail: 345 ddi_remove_minor_node(dip, NULL); 346 cv_destroy(&sp->cv); 347 mutex_destroy(&sp->lock); 348 ddi_soft_state_free(ds_pri_statep, instance); 349 return (DDI_FAILURE); 350 351} 352 353 354/*ARGSUSED*/ 355static int 356ds_pri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 357{ 358 ds_pri_state_t *sp; 359 int instance; 360 int rv; 361 362 instance = ddi_get_instance(dip); 363 sp = ddi_get_soft_state(ds_pri_statep, instance); 364 365 switch (cmd) { 366 case DDI_DETACH: 367 break; 368 369 case DDI_SUSPEND: 370 return (DDI_SUCCESS); 371 372 default: 373 return (DDI_FAILURE); 374 } 375 376 /* This really shouldn't fail - but check anyway */ 377 if ((rv = ds_cap_fini(&ds_pri_cap)) != 0) { 378 cmn_err(CE_WARN, "ds_cap_fini failed: %d", rv); 379 } 380 381 if (sp != NULL && sp->ds_pri_len != 0) 382 kmem_free(sp->ds_pri, sp->ds_pri_len); 383 384 ds_pri_ops.cb_arg = NULL; 385 386 ddi_remove_minor_node(dip, NULL); 387 cv_destroy(&sp->cv); 388 mutex_destroy(&sp->lock); 389 ddi_soft_state_free(ds_pri_statep, instance); 390 391 return (DDI_SUCCESS); 392} 393 394 395/*ARGSUSED*/ 396static int 397ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp) 398{ 399 ds_pri_state_t *sp; 400 int instance; 401 402 if (otyp != OTYP_CHR) 403 return (EINVAL); 404 405 instance = getminor(*devp); 406 sp = ddi_get_soft_state(ds_pri_statep, instance); 407 if (sp == NULL) 408 return (ENXIO); 409 410 mutex_enter(&sp->lock); 411 412 /* 413 * If we're here and the state is DS_PRI_NO_SERVICE then this 414 * means that ds hasn't yet called the registration callback. 415 * A while loop is necessary as we might have been woken up 416 * prematurely, e.g., due to a debugger or "pstack" etc. 417 * Wait here and the callback will signal us when it has completed 418 * its work. 419 */ 420 while (sp->state == DS_PRI_NO_SERVICE) { 421 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 422 mutex_exit(&sp->lock); 423 return (EINTR); 424 } 425 } 426 427 sp->num_opens++; 428 mutex_exit(&sp->lock); 429 430 /* 431 * On open we dont fetch the PRI even if we have a valid service 432 * handle. PRI fetch is essentially lazy and on-demand. 433 */ 434 435 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state); 436 437 return (0); 438} 439 440 441/*ARGSUSED*/ 442static int 443ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp) 444{ 445 int instance; 446 ds_pri_state_t *sp; 447 448 if (otyp != OTYP_CHR) 449 return (EINVAL); 450 451 DS_PRI_DBG("ds_pri_close\n"); 452 453 instance = getminor(dev); 454 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 455 return (ENXIO); 456 457 mutex_enter(&sp->lock); 458 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 459 mutex_exit(&sp->lock); 460 return (0); 461 } 462 463 if (--sp->num_opens > 0) { 464 mutex_exit(&sp->lock); 465 return (0); 466 } 467 468 /* If we have an old PRI - remove it */ 469 if (sp->state & DS_PRI_HAS_PRI) { 470 if (sp->ds_pri != NULL && sp->ds_pri_len > 0) { 471 /* 472 * remove the old data if we have an 473 * outstanding request 474 */ 475 kmem_free(sp->ds_pri, sp->ds_pri_len); 476 sp->ds_pri_len = 0; 477 sp->ds_pri = NULL; 478 } 479 sp->state &= ~DS_PRI_HAS_PRI; 480 } 481 sp->state &= ~DS_PRI_REQUESTED; 482 mutex_exit(&sp->lock); 483 return (0); 484} 485 486 487/*ARGSUSED*/ 488static int 489ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp) 490{ 491 ds_pri_state_t *sp; 492 int instance; 493 size_t len; 494 int retval; 495 caddr_t tmpbufp; 496 497 instance = getminor(dev); 498 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 499 return (ENXIO); 500 501 len = uiop->uio_resid; 502 503 if (len == 0) 504 return (0); 505 506 mutex_enter(&sp->lock); 507 508 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 509 510 /* block or bail if there is no current PRI */ 511 if (!(sp->state & DS_PRI_HAS_PRI)) { 512 DS_PRI_DBG("ds_pri_read: no PRI held\n"); 513 514 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 515 mutex_exit(&sp->lock); 516 return (EAGAIN); 517 } 518 519 while (!(sp->state & DS_PRI_HAS_PRI)) { 520 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 521 request_pri(sp); 522 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 523 mutex_exit(&sp->lock); 524 return (EINTR); 525 } 526 } 527 } 528 529 if (uiop->uio_offset < 0 || uiop->uio_offset > sp->ds_pri_len) { 530 mutex_exit(&sp->lock); 531 return (EINVAL); 532 } 533 534 if (len > (sp->ds_pri_len - uiop->uio_offset)) 535 len = sp->ds_pri_len - uiop->uio_offset; 536 537 /* already checked that offset < ds_pri_len above */ 538 if (len == 0) { 539 mutex_exit(&sp->lock); 540 return (0); 541 } 542 543 /* 544 * We're supposed to move the data out to userland, but 545 * that can suspend because of page faults etc., and meanwhile 546 * other parts of this driver want to update the PRI buffer ... 547 * we could hold the data buffer locked with a flag etc., 548 * but that's still a lock ... a simpler mechanism - if not quite 549 * as performance efficient is to simply clone here the part of 550 * the buffer we care about and then the original can be released 551 * for further updates while the uiomove continues. 552 */ 553 554 tmpbufp = kmem_alloc(len, KM_SLEEP); 555 bcopy(((caddr_t)sp->ds_pri) + uiop->uio_offset, tmpbufp, len); 556 mutex_exit(&sp->lock); 557 558 retval = uiomove(tmpbufp, len, UIO_READ, uiop); 559 560 kmem_free(tmpbufp, len); 561 562 return (retval); 563} 564 565 566/*ARGSUSED*/ 567static int 568ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 569 int *rvalp) 570{ 571 ds_pri_state_t *sp; 572 int instance; 573 574 instance = getminor(dev); 575 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 576 return (ENXIO); 577 578 switch (cmd) { 579 case DSPRI_GETINFO: { 580 struct dspri_info info; 581 582 if (!(mode & FREAD)) 583 return (EACCES); 584 585 /* 586 * We are not guaranteed that ddi_copyout(9F) will read 587 * atomically anything larger than a byte. Therefore we 588 * must duplicate the size before copying it out to the user. 589 */ 590 mutex_enter(&sp->lock); 591 592loop:; 593 if (sp->state & DS_PRI_HAS_PRI) { 594 /* If we have a PRI simply return the info */ 595 info.size = sp->ds_pri_len; 596 info.token = sp->gencount; 597 } else 598 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 599 /* If we have no service return a nil response */ 600 info.size = 0; 601 info.token = 0; 602 } else { 603 request_pri(sp); 604 /* wait for something & check again */ 605 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 606 mutex_exit(&sp->lock); 607 return (EINTR); 608 } 609 goto loop; 610 } 611 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n", 612 info.size, info.token); 613 mutex_exit(&sp->lock); 614 615 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 616 return (EFAULT); 617 break; 618 } 619 620 case DSPRI_WAIT: { 621 uint64_t gencount; 622 623 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount), 624 mode) != 0) 625 return (EFAULT); 626 627 mutex_enter(&sp->lock); 628 629 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n", 630 gencount, sp->gencount); 631 632 while ((sp->state & DS_PRI_HAS_PRI) == 0 || 633 gencount == sp->gencount) { 634 if ((sp->state & DS_PRI_HAS_PRI) == 0) 635 request_pri(sp); 636 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 637 mutex_exit(&sp->lock); 638 return (EINTR); 639 } 640 } 641 mutex_exit(&sp->lock); 642 break; 643 } 644 645 default: 646 return (ENOTTY); 647 } 648 return (0); 649} 650 651 652 /* assumes sp->lock is held when called */ 653static void 654request_pri(ds_pri_state_t *sp) 655{ 656 ds_pri_msg_t reqmsg; 657 658 ASSERT(MUTEX_HELD(&sp->lock)); 659 660 /* If a request is already pending we're done */ 661 if (!(sp->state & DS_PRI_HAS_SERVICE)) 662 return; 663 if (sp->state & DS_PRI_REQUESTED) 664 return; 665 666 /* If we have an old PRI - remove it */ 667 if (sp->state & DS_PRI_HAS_PRI) { 668 ASSERT(sp->ds_pri_len != 0); 669 ASSERT(sp->ds_pri != NULL); 670 671 /* remove the old data if we have an outstanding request */ 672 kmem_free(sp->ds_pri, sp->ds_pri_len); 673 sp->ds_pri_len = 0; 674 sp->ds_pri = NULL; 675 sp->state &= ~DS_PRI_HAS_PRI; 676 } else { 677 ASSERT(sp->ds_pri == NULL); 678 ASSERT(sp->ds_pri_len == 0); 679 } 680 681 reqmsg.hdr.seq_num = ++(sp->req_id); 682 reqmsg.hdr.type = DS_PRI_REQUEST; 683 684 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id); 685 686 /* 687 * Request consists of header only. 688 * We don't care about fail status for ds_send; 689 * if it does fail we will get an unregister callback 690 * from the DS framework and we handle the state change 691 * there. 692 */ 693 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr)); 694 695 sp->state |= DS_PRI_REQUESTED; 696 sp->last_req_id = sp->req_id; 697} 698 699/* 700 * DS Callbacks 701 */ 702/*ARGSUSED*/ 703static void 704ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 705{ 706 dev_info_t *dip = arg; 707 ds_pri_state_t *sp; 708 int instance; 709 710 instance = ddi_get_instance(dip); 711 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 712 return; 713 714 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version " 715 "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 716 717 /* When the domain service comes up automatically req the pri */ 718 mutex_enter(&sp->lock); 719 720 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL); 721 sp->ds_pri_handle = hdl; 722 723 ASSERT(sp->state == DS_PRI_NO_SERVICE); 724 ASSERT(sp->ds_pri == NULL); 725 ASSERT(sp->ds_pri_len == 0); 726 727 /* have service, but no PRI */ 728 sp->state |= DS_PRI_HAS_SERVICE; 729 730 /* 731 * Cannot request a PRI here, because the reg handler cannot 732 * do a DS send operation - we take care of this later. 733 */ 734 735 /* Wake up anyone waiting in open() */ 736 cv_broadcast(&sp->cv); 737 738 mutex_exit(&sp->lock); 739} 740 741 742static void 743ds_pri_unreg_handler(ds_cb_arg_t arg) 744{ 745 dev_info_t *dip = arg; 746 ds_pri_state_t *sp; 747 int instance; 748 749 instance = ddi_get_instance(dip); 750 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 751 return; 752 753 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n"); 754 755 mutex_enter(&sp->lock); 756 757 /* Once the service goes - if we have a PRI at hand free it up */ 758 if (sp->ds_pri_len != 0) { 759 kmem_free(sp->ds_pri, sp->ds_pri_len); 760 sp->ds_pri_len = 0; 761 sp->ds_pri = NULL; 762 } 763 sp->ds_pri_handle = DS_INVALID_HDL; 764 sp->state = DS_PRI_NO_SERVICE; 765 766 mutex_exit(&sp->lock); 767} 768 769 770static void 771ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 772{ 773 dev_info_t *dip = arg; 774 ds_pri_state_t *sp; 775 int instance; 776 void *data; 777 ds_pri_msg_t *msgp; 778 size_t pri_size; 779 780 msgp = (ds_pri_msg_t *)buf; 781 782 /* make sure the header is at least valid */ 783 if (buflen < sizeof (msgp->hdr)) 784 return; 785 786 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, " 787 "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num); 788 789 instance = ddi_get_instance(dip); 790 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 791 return; 792 793 mutex_enter(&sp->lock); 794 795 ASSERT(sp->state & DS_PRI_HAS_SERVICE); 796 797 switch (msgp->hdr.type) { 798 case DS_PRI_DATA: /* in response to a request from us */ 799 break; 800 case DS_PRI_UPDATE: /* aynch notification */ 801 /* our default response to this is to request the PRI */ 802 /* simply issue a request for the new PRI */ 803 request_pri(sp); 804 goto done; 805 default: /* ignore garbage or unknown message types */ 806 goto done; 807 } 808 809 /* 810 * If there is no pending PRI request, then we've received a 811 * bogus data message ... so ignore it. 812 */ 813 814 if (!(sp->state & DS_PRI_REQUESTED)) { 815 cmn_err(CE_WARN, "Received DS pri data without request"); 816 goto done; 817 } 818 819 /* response to a request therefore old PRI must be gone */ 820 ASSERT(!(sp->state & DS_PRI_HAS_PRI)); 821 ASSERT(sp->ds_pri_len == 0); 822 ASSERT(sp->ds_pri == NULL); 823 824 /* response seq_num should match our request seq_num */ 825 if (msgp->hdr.seq_num != sp->last_req_id) { 826 cmn_err(CE_WARN, "Received DS pri data out of sequence with " 827 "request"); 828 goto done; 829 } 830 831 pri_size = buflen - sizeof (msgp->hdr); 832 data = kmem_alloc(pri_size, KM_SLEEP); 833 sp->ds_pri = data; 834 sp->ds_pri_len = pri_size; 835 bcopy(msgp->data, data, sp->ds_pri_len); 836 sp->state &= ~DS_PRI_REQUESTED; 837 sp->state |= DS_PRI_HAS_PRI; 838 839 sp->gencount++; 840 cv_broadcast(&sp->cv); 841 842done:; 843 mutex_exit(&sp->lock); 844} 845