ds_pri.c revision 4109:20d5b06dbce1
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 2007 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 * sun4v domain services PRI driver 30 */ 31 32#include <sys/types.h> 33#include <sys/file.h> 34#include <sys/errno.h> 35#include <sys/open.h> 36#include <sys/cred.h> 37#include <sys/uio.h> 38#include <sys/stat.h> 39#include <sys/ksynch.h> 40#include <sys/modctl.h> 41#include <sys/conf.h> 42#include <sys/devops.h> 43#include <sys/debug.h> 44#include <sys/cmn_err.h> 45#include <sys/ddi.h> 46#include <sys/sunddi.h> 47#include <sys/ds.h> 48 49#include <sys/ds_pri.h> 50 51static uint_t ds_pri_debug = 0; 52#define DS_PRI_DBG if (ds_pri_debug) printf 53 54#define DS_PRI_NAME "ds_pri" 55 56#define TEST_HARNESS 57#ifdef TEST_HARNESS 58#define DS_PRI_MAX_PRI_SIZE (64 * 1024) 59 60#define DSIOC_TEST_REG 97 61#define DSIOC_TEST_UNREG 98 62#define DSIOC_TEST_DATA 99 63 64struct ds_pri_test_data { 65 size_t size; 66 void *data; 67}; 68 69struct ds_pri_test_data32 { 70 size32_t size; 71 caddr32_t data; 72}; 73#endif /* TEST_HARNESS */ 74 75typedef enum { 76 DS_PRI_REQUEST = 0, 77 DS_PRI_DATA = 1, 78 DS_PRI_UPDATE = 2 79} ds_pri_msg_type_t; 80 81typedef struct { 82 struct { 83 uint64_t seq_num; 84 uint64_t type; 85 } hdr; 86 uint8_t data[1]; 87} ds_pri_msg_t; 88 89 /* The following are bit field flags */ 90 /* No service implies no PRI and no outstanding request */ 91typedef enum { 92 DS_PRI_NO_SERVICE = 0x0, 93 DS_PRI_HAS_SERVICE = 0x1, 94 DS_PRI_REQUESTED = 0x2, 95 DS_PRI_HAS_PRI = 0x4 96} ds_pri_flags_t; 97 98struct ds_pri_state { 99 dev_info_t *dip; 100 int instance; 101 102 kmutex_t lock; 103 kcondvar_t cv; 104 105 /* PRI/DS */ 106 ds_pri_flags_t state; 107 uint64_t gencount; 108 ds_svc_hdl_t ds_pri_handle; 109 void *ds_pri; 110 size_t ds_pri_len; 111 uint64_t req_id; 112 uint64_t last_req_id; 113 int num_opens; 114}; 115 116typedef struct ds_pri_state ds_pri_state_t; 117 118static void *ds_pri_statep; 119 120static void request_pri(ds_pri_state_t *sp); 121 122static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 123static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t); 124static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t); 125static int ds_pri_open(dev_t *, int, int, cred_t *); 126static int ds_pri_close(dev_t, int, int, cred_t *); 127static int ds_pri_read(dev_t, struct uio *, cred_t *); 128static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 129 130/* 131 * DS Callbacks 132 */ 133static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 134static void ds_pri_unreg_handler(ds_cb_arg_t arg); 135static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 136 137/* 138 * PRI DS capability registration 139 */ 140 141static ds_ver_t ds_pri_ver_1_0 = { 1, 0 }; 142 143static ds_capability_t ds_pri_cap = { 144 "pri", 145 &ds_pri_ver_1_0, 146 1 147}; 148 149/* 150 * PRI DS Client callback vector 151 */ 152static ds_clnt_ops_t ds_pri_ops = { 153 ds_pri_reg_handler, /* ds_reg_cb */ 154 ds_pri_unreg_handler, /* ds_unreg_cb */ 155 ds_pri_data_handler, /* ds_data_cb */ 156 NULL /* cb_arg */ 157}; 158 159/* 160 * DS PRI driver Ops Vector 161 */ 162static struct cb_ops ds_pri_cb_ops = { 163 ds_pri_open, /* cb_open */ 164 ds_pri_close, /* cb_close */ 165 nodev, /* cb_strategy */ 166 nodev, /* cb_print */ 167 nodev, /* cb_dump */ 168 ds_pri_read, /* cb_read */ 169 nodev, /* cb_write */ 170 ds_pri_ioctl, /* cb_ioctl */ 171 nodev, /* cb_devmap */ 172 nodev, /* cb_mmap */ 173 nodev, /* cb_segmap */ 174 nochpoll, /* cb_chpoll */ 175 ddi_prop_op, /* cb_prop_op */ 176 (struct streamtab *)NULL, /* cb_str */ 177 D_MP | D_64BIT, /* cb_flag */ 178 CB_REV, /* cb_rev */ 179 nodev, /* cb_aread */ 180 nodev /* cb_awrite */ 181}; 182 183static struct dev_ops ds_pri_dev_ops = { 184 DEVO_REV, /* devo_rev */ 185 0, /* devo_refcnt */ 186 ds_pri_getinfo, /* devo_getinfo */ 187 nulldev, /* devo_identify */ 188 nulldev, /* devo_probe */ 189 ds_pri_attach, /* devo_attach */ 190 ds_pri_detach, /* devo_detach */ 191 nodev, /* devo_reset */ 192 &ds_pri_cb_ops, /* devo_cb_ops */ 193 (struct bus_ops *)NULL, /* devo_bus_ops */ 194 nulldev /* devo_power */ 195}; 196 197static struct modldrv modldrv = { 198 &mod_driverops, 199 "Domain Services PRI Driver 1.0", 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 ddi_remove_minor_node(dip, NULL); 385 cv_destroy(&sp->cv); 386 mutex_destroy(&sp->lock); 387 ddi_soft_state_free(ds_pri_statep, instance); 388 389 return (DDI_SUCCESS); 390} 391 392 393/*ARGSUSED*/ 394static int 395ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp) 396{ 397 ds_pri_state_t *sp; 398 int instance; 399 400 if (otyp != OTYP_CHR) 401 return (EINVAL); 402 403 instance = getminor(*devp); 404 sp = ddi_get_soft_state(ds_pri_statep, instance); 405 if (sp == NULL) 406 return (ENXIO); 407 408 mutex_enter(&sp->lock); 409 410 /* 411 * If we're here and the state is DS_PRI_NO_SERVICE then this 412 * means that ds hasn't yet called the registration callback. 413 * A while loop is necessary as we might have been woken up 414 * prematurely, e.g., due to a debugger or "pstack" etc. 415 * Wait here and the callback will signal us when it has completed 416 * its work. 417 */ 418 while (sp->state == DS_PRI_NO_SERVICE) { 419 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 420 mutex_exit(&sp->lock); 421 return (EINTR); 422 } 423 } 424 425 sp->num_opens++; 426 mutex_exit(&sp->lock); 427 428 /* 429 * On open we dont fetch the PRI even if we have a valid service 430 * handle. PRI fetch is essentially lazy and on-demand. 431 */ 432 433 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state); 434 435 return (0); 436} 437 438 439/*ARGSUSED*/ 440static int 441ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp) 442{ 443 int instance; 444 ds_pri_state_t *sp; 445 446 if (otyp != OTYP_CHR) 447 return (EINVAL); 448 449 DS_PRI_DBG("ds_pri_close\n"); 450 451 instance = getminor(dev); 452 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 453 return (ENXIO); 454 455 mutex_enter(&sp->lock); 456 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 457 mutex_exit(&sp->lock); 458 return (0); 459 } 460 461 if (--sp->num_opens > 0) { 462 mutex_exit(&sp->lock); 463 return (0); 464 } 465 466 /* If we have an old PRI - remove it */ 467 if (sp->state & DS_PRI_HAS_PRI) { 468 if (sp->ds_pri != NULL && sp->ds_pri_len > 0) { 469 /* 470 * remove the old data if we have an 471 * outstanding request 472 */ 473 kmem_free(sp->ds_pri, sp->ds_pri_len); 474 sp->ds_pri_len = 0; 475 sp->ds_pri = NULL; 476 } 477 sp->state &= ~DS_PRI_HAS_PRI; 478 } 479 sp->state &= ~DS_PRI_REQUESTED; 480 mutex_exit(&sp->lock); 481 return (0); 482} 483 484 485/*ARGSUSED*/ 486static int 487ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp) 488{ 489 ds_pri_state_t *sp; 490 int instance; 491 size_t len; 492 int retval; 493 caddr_t tmpbufp; 494 495 instance = getminor(dev); 496 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 497 return (ENXIO); 498 499 len = uiop->uio_resid; 500 501 if (len == 0) 502 return (0); 503 504 mutex_enter(&sp->lock); 505 506 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 507 508 /* block or bail if there is no current PRI */ 509 if (!(sp->state & DS_PRI_HAS_PRI)) { 510 DS_PRI_DBG("ds_pri_read: no PRI held\n"); 511 512 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 513 mutex_exit(&sp->lock); 514 return (EAGAIN); 515 } 516 517 while (!(sp->state & DS_PRI_HAS_PRI)) { 518 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 519 request_pri(sp); 520 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 521 mutex_exit(&sp->lock); 522 return (EINTR); 523 } 524 } 525 } 526 527 if (uiop->uio_offset < 0 || uiop->uio_offset > sp->ds_pri_len) { 528 mutex_exit(&sp->lock); 529 return (EINVAL); 530 } 531 532 if (len > (sp->ds_pri_len - uiop->uio_offset)) 533 len = sp->ds_pri_len - uiop->uio_offset; 534 535 /* already checked that offset < ds_pri_len above */ 536 if (len == 0) { 537 mutex_exit(&sp->lock); 538 return (0); 539 } 540 541 /* 542 * We're supposed to move the data out to userland, but 543 * that can suspend because of page faults etc., and meanwhile 544 * other parts of this driver want to update the PRI buffer ... 545 * we could hold the data buffer locked with a flag etc., 546 * but that's still a lock ... a simpler mechanism - if not quite 547 * as performance efficient is to simply clone here the part of 548 * the buffer we care about and then the original can be released 549 * for further updates while the uiomove continues. 550 */ 551 552 tmpbufp = kmem_alloc(len, KM_SLEEP); 553 bcopy(((caddr_t)sp->ds_pri) + uiop->uio_offset, tmpbufp, len); 554 mutex_exit(&sp->lock); 555 556 retval = uiomove(tmpbufp, len, UIO_READ, uiop); 557 558 kmem_free(tmpbufp, len); 559 560 return (retval); 561} 562 563 564/*ARGSUSED*/ 565static int 566ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 567 int *rvalp) 568{ 569 ds_pri_state_t *sp; 570 int instance; 571 572 instance = getminor(dev); 573 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 574 return (ENXIO); 575 576 switch (cmd) { 577 case DSPRI_GETINFO: { 578 struct dspri_info info; 579 580 if (!(mode & FREAD)) 581 return (EACCES); 582 583 /* 584 * We are not guaranteed that ddi_copyout(9F) will read 585 * atomically anything larger than a byte. Therefore we 586 * must duplicate the size before copying it out to the user. 587 */ 588 mutex_enter(&sp->lock); 589 590loop:; 591 if (sp->state & DS_PRI_HAS_PRI) { 592 /* If we have a PRI simply return the info */ 593 info.size = sp->ds_pri_len; 594 info.token = sp->gencount; 595 } else 596 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 597 /* If we have no service return a nil response */ 598 info.size = 0; 599 info.token = 0; 600 } else { 601 request_pri(sp); 602 /* wait for something & check again */ 603 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 604 mutex_exit(&sp->lock); 605 return (EINTR); 606 } 607 goto loop; 608 } 609 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n", 610 info.size, info.token); 611 mutex_exit(&sp->lock); 612 613 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 614 return (EFAULT); 615 break; 616 } 617 618 case DSPRI_WAIT: { 619 uint64_t gencount; 620 621 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount), 622 mode) != 0) 623 return (EFAULT); 624 625 mutex_enter(&sp->lock); 626 627 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n", 628 gencount, sp->gencount); 629 630 while ((sp->state & DS_PRI_HAS_PRI) == 0 || 631 gencount == sp->gencount) { 632 if ((sp->state & DS_PRI_HAS_PRI) == 0) 633 request_pri(sp); 634 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 635 mutex_exit(&sp->lock); 636 return (EINTR); 637 } 638 } 639 mutex_exit(&sp->lock); 640 break; 641 } 642 643 default: 644 return (ENOTTY); 645 } 646 return (0); 647} 648 649 650 /* assumes sp->lock is held when called */ 651static void 652request_pri(ds_pri_state_t *sp) 653{ 654 ds_pri_msg_t reqmsg; 655 656 ASSERT(MUTEX_HELD(&sp->lock)); 657 658 /* If a request is already pending we're done */ 659 if (!(sp->state & DS_PRI_HAS_SERVICE)) 660 return; 661 if (sp->state & DS_PRI_REQUESTED) 662 return; 663 664 /* If we have an old PRI - remove it */ 665 if (sp->state & DS_PRI_HAS_PRI) { 666 ASSERT(sp->ds_pri_len != 0); 667 ASSERT(sp->ds_pri != NULL); 668 669 /* remove the old data if we have an outstanding request */ 670 kmem_free(sp->ds_pri, sp->ds_pri_len); 671 sp->ds_pri_len = 0; 672 sp->ds_pri = NULL; 673 sp->state &= ~DS_PRI_HAS_PRI; 674 } else { 675 ASSERT(sp->ds_pri == NULL); 676 ASSERT(sp->ds_pri_len == 0); 677 } 678 679 reqmsg.hdr.seq_num = ++(sp->req_id); 680 reqmsg.hdr.type = DS_PRI_REQUEST; 681 682 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id); 683 684 /* 685 * Request consists of header only. 686 * We don't care about fail status for ds_send; 687 * if it does fail we will get an unregister callback 688 * from the DS framework and we handle the state change 689 * there. 690 */ 691 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr)); 692 693 sp->state |= DS_PRI_REQUESTED; 694 sp->last_req_id = sp->req_id; 695} 696 697/* 698 * DS Callbacks 699 */ 700/*ARGSUSED*/ 701static void 702ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 703{ 704 dev_info_t *dip = arg; 705 ds_pri_state_t *sp; 706 int instance; 707 708 instance = ddi_get_instance(dip); 709 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 710 return; 711 712 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version " 713 "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 714 715 /* When the domain service comes up automatically req the pri */ 716 mutex_enter(&sp->lock); 717 718 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL); 719 sp->ds_pri_handle = hdl; 720 721 ASSERT(sp->state == DS_PRI_NO_SERVICE); 722 ASSERT(sp->ds_pri == NULL); 723 ASSERT(sp->ds_pri_len == 0); 724 725 /* have service, but no PRI */ 726 sp->state |= DS_PRI_HAS_SERVICE; 727 728 /* 729 * Cannot request a PRI here, because the reg handler cannot 730 * do a DS send operation - we take care of this later. 731 */ 732 733 /* Wake up anyone waiting in open() */ 734 cv_broadcast(&sp->cv); 735 736 mutex_exit(&sp->lock); 737} 738 739 740static void 741ds_pri_unreg_handler(ds_cb_arg_t arg) 742{ 743 dev_info_t *dip = arg; 744 ds_pri_state_t *sp; 745 int instance; 746 747 instance = ddi_get_instance(dip); 748 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 749 return; 750 751 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n"); 752 753 mutex_enter(&sp->lock); 754 755 /* Once the service goes - if we have a PRI at hand free it up */ 756 if (sp->ds_pri_len != 0) { 757 kmem_free(sp->ds_pri, sp->ds_pri_len); 758 sp->ds_pri_len = 0; 759 sp->ds_pri = NULL; 760 } 761 sp->ds_pri_handle = DS_INVALID_HDL; 762 sp->state = DS_PRI_NO_SERVICE; 763 764 mutex_exit(&sp->lock); 765} 766 767 768static void 769ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 770{ 771 dev_info_t *dip = arg; 772 ds_pri_state_t *sp; 773 int instance; 774 void *data; 775 ds_pri_msg_t *msgp; 776 size_t pri_size; 777 778 msgp = (ds_pri_msg_t *)buf; 779 780 /* make sure the header is at least valid */ 781 if (buflen < sizeof (msgp->hdr)) 782 return; 783 784 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, " 785 "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num); 786 787 instance = ddi_get_instance(dip); 788 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 789 return; 790 791 mutex_enter(&sp->lock); 792 793 ASSERT(sp->state & DS_PRI_HAS_SERVICE); 794 795 switch (msgp->hdr.type) { 796 case DS_PRI_DATA: /* in response to a request from us */ 797 break; 798 case DS_PRI_UPDATE: /* aynch notification */ 799 /* our default response to this is to request the PRI */ 800 /* simply issue a request for the new PRI */ 801 request_pri(sp); 802 goto done; 803 default: /* ignore garbage or unknown message types */ 804 goto done; 805 } 806 807 /* 808 * If there is no pending PRI request, then we've received a 809 * bogus data message ... so ignore it. 810 */ 811 812 if (!(sp->state & DS_PRI_REQUESTED)) { 813 cmn_err(CE_WARN, "Received DS pri data without request"); 814 goto done; 815 } 816 817 /* response to a request therefore old PRI must be gone */ 818 ASSERT(!(sp->state & DS_PRI_HAS_PRI)); 819 ASSERT(sp->ds_pri_len == 0); 820 ASSERT(sp->ds_pri == NULL); 821 822 /* response seq_num should match our request seq_num */ 823 if (msgp->hdr.seq_num != sp->last_req_id) { 824 cmn_err(CE_WARN, "Received DS pri data out of sequence with " 825 "request"); 826 goto done; 827 } 828 829 pri_size = buflen - sizeof (msgp->hdr); 830 data = kmem_alloc(pri_size, KM_SLEEP); 831 sp->ds_pri = data; 832 sp->ds_pri_len = pri_size; 833 bcopy(msgp->data, data, sp->ds_pri_len); 834 sp->state &= ~DS_PRI_REQUESTED; 835 sp->state |= DS_PRI_HAS_PRI; 836 837 sp->gencount++; 838 cv_broadcast(&sp->cv); 839 840done:; 841 mutex_exit(&sp->lock); 842} 843