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 */ 25 26 /* 27 * av1394 CMP (Connection Management Procedures) 28 */ 29 #include <sys/1394/targets/av1394/av1394_impl.h> 30 31 /* configuration routines */ 32 static void av1394_cmp_cleanup(av1394_inst_t *icp); 33 34 /* ioctl routines */ 35 static int av1394_ioctl_plug_init_local(av1394_inst_t *, 36 iec61883_plug_init_t *); 37 static int av1394_ioctl_plug_init_remote(av1394_inst_t *, 38 iec61883_plug_init_t *); 39 40 /* local PCR routines */ 41 static int av1394_pcr_init(av1394_inst_t *, int, uint32_t); 42 static void av1394_pcr_fini(av1394_inst_t *, int); 43 static int av1394_pcr_alloc_addr(av1394_inst_t *, uint64_t, 44 t1394_addr_handle_t *); 45 static void av1394_pcr_free_addr(av1394_inst_t *, t1394_addr_handle_t *); 46 static int av1394_pcr_make_ph(int, int, int); 47 static int av1394_pcr_ph2idx(int); 48 static av1394_pcr_t *av1394_pcr_ph2pcr(av1394_cmp_t *, int); 49 static uint64_t av1394_pcr_idx2addr(int); 50 static int av1394_pcr_idx2num(int); 51 static boolean_t av1394_pcr_idx_is_mpr(int); 52 static boolean_t av1394_pcr_ph_is_mpr(int); 53 static boolean_t av1394_pcr_ph_is_remote(int); 54 55 /* callbacks */ 56 static void av1394_pcr_recv_read_request(cmd1394_cmd_t *); 57 static void av1394_pcr_recv_lock_request(cmd1394_cmd_t *); 58 59 /* remote PCR routines */ 60 static int av1394_pcr_remote_read(av1394_inst_t *, int, uint32_t *); 61 static int av1394_pcr_remote_cas(av1394_inst_t *, int, uint32_t *, 62 uint32_t, uint32_t); 63 64 int 65 av1394_cmp_init(av1394_inst_t *avp) 66 { 67 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 68 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie; 69 int ret; 70 71 ret = t1394_cmp_register(avp->av_t1394_hdl, NULL, 0); 72 73 if (ret == DDI_SUCCESS) { 74 rw_init(&cmp->cmp_pcr_rwlock, NULL, RW_DRIVER, ibc); 75 } 76 77 return (ret); 78 } 79 80 void 81 av1394_cmp_fini(av1394_inst_t *avp) 82 { 83 av1394_cmp_cleanup(avp); 84 } 85 86 void 87 av1394_cmp_bus_reset(av1394_inst_t *avp) 88 { 89 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 90 int i; 91 92 /* reset PCR values */ 93 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 94 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 95 if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) { 96 continue; 97 } 98 if (cmp->cmp_pcr[i]) { 99 if (i < AV1394_IMPR_IDX) { 100 cmp->cmp_pcr[i]->pcr_val &= 101 ~AV1394_OPCR_BR_CLEAR_MASK; 102 } else { 103 cmp->cmp_pcr[i]->pcr_val &= 104 ~AV1394_IPCR_BR_CLEAR_MASK; 105 } 106 } 107 } 108 rw_exit(&cmp->cmp_pcr_rwlock); 109 } 110 111 /* 112 * on close, free iPCRs and oPCRs not finalized by application 113 */ 114 void 115 av1394_cmp_close(av1394_inst_t *avp) 116 { 117 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 118 int i; 119 120 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 121 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 122 if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) { 123 continue; 124 } 125 if (cmp->cmp_pcr[i]) { 126 av1394_pcr_fini(avp, i); 127 } 128 } 129 rw_exit(&cmp->cmp_pcr_rwlock); 130 } 131 132 /* 133 * 134 * --- ioctls 135 * 136 * IEC61883_PLUG_INIT 137 */ 138 int 139 av1394_ioctl_plug_init(av1394_inst_t *avp, void *arg, int mode) 140 { 141 int ret = 0; 142 iec61883_plug_init_t pi; 143 144 if (ddi_copyin(arg, &pi, sizeof (pi), mode) != 0) { 145 return (EFAULT); 146 } 147 148 /* check arguments */ 149 if (((pi.pi_type != IEC61883_PLUG_IN) && 150 (pi.pi_type != IEC61883_PLUG_OUT) && 151 (pi.pi_type != IEC61883_PLUG_MASTER_IN) && 152 (pi.pi_type != IEC61883_PLUG_MASTER_OUT)) || 153 (((pi.pi_num < 0) || (pi.pi_num >= AV1394_NPCR)) && 154 (pi.pi_num != IEC61883_PLUG_ANY))) { 155 return (EINVAL); 156 } 157 158 if (pi.pi_loc == IEC61883_LOC_LOCAL) { 159 ret = av1394_ioctl_plug_init_local(avp, &pi); 160 } else if (pi.pi_loc == IEC61883_LOC_REMOTE) { 161 ret = av1394_ioctl_plug_init_remote(avp, &pi); 162 } else { 163 ret = EINVAL; 164 } 165 166 if (ret == 0) { 167 if (ddi_copyout(&pi, arg, sizeof (pi), mode) != 0) { 168 ret = EFAULT; 169 } 170 } 171 172 return (ret); 173 } 174 175 /* 176 * IEC61883_PLUG_FINI 177 */ 178 /*ARGSUSED*/ 179 int 180 av1394_ioctl_plug_fini(av1394_inst_t *avp, void *arg, int mode) 181 { 182 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 183 int ret; 184 int ph; 185 186 ph = (int)(intptr_t)arg; 187 188 if (av1394_pcr_ph_is_remote(ph) || av1394_pcr_ph_is_mpr(ph)) { 189 return (0); 190 } 191 192 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 193 if (av1394_pcr_ph2pcr(cmp, ph) != NULL) { 194 av1394_pcr_fini(avp, av1394_pcr_ph2idx(ph)); 195 ret = 0; 196 } else { 197 ret = EINVAL; 198 } 199 rw_exit(&cmp->cmp_pcr_rwlock); 200 201 return (ret); 202 } 203 204 /* 205 * IEC61883_PLUG_REG_READ 206 */ 207 int 208 av1394_ioctl_plug_reg_read(av1394_inst_t *avp, void *arg, int mode) 209 { 210 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 211 int ret = 0; 212 iec61883_plug_reg_val_t pr; 213 int ph; 214 av1394_pcr_t *pcr; 215 216 if (ddi_copyin(arg, &pr, sizeof (pr), mode) != 0) { 217 return (EFAULT); 218 } 219 ph = pr.pr_handle; 220 221 if (av1394_pcr_ph_is_remote(ph)) { 222 ret = av1394_pcr_remote_read(avp, ph, &pr.pr_val); 223 } else { 224 switch (av1394_pcr_ph2idx(ph)) { 225 case AV1394_OMPR_IDX: 226 ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_OMPR, 227 &pr.pr_val); 228 break; 229 case AV1394_IMPR_IDX: 230 ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_IMPR, 231 &pr.pr_val); 232 break; 233 default: 234 rw_enter(&cmp->cmp_pcr_rwlock, RW_READER); 235 if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) { 236 pr.pr_val = pcr->pcr_val; 237 } else { 238 ret = EINVAL; 239 } 240 rw_exit(&cmp->cmp_pcr_rwlock); 241 } 242 } 243 244 if (ret == 0) { 245 if (ddi_copyout(&pr, arg, sizeof (pr), mode) != 0) { 246 ret = EFAULT; 247 } 248 } 249 250 return (ret); 251 } 252 253 /* 254 * IEC61883_PLUG_REG_CAS 255 */ 256 int 257 av1394_ioctl_plug_reg_cas(av1394_inst_t *avp, void *arg, int mode) 258 { 259 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 260 int ret = 0; 261 iec61883_plug_reg_lock_t pl; 262 int ph; 263 av1394_pcr_t *pcr; 264 265 if (ddi_copyin(arg, &pl, sizeof (pl), mode) != 0) { 266 return (EFAULT); 267 } 268 ph = pl.pl_handle; 269 270 if (av1394_pcr_ph_is_remote(ph)) { 271 ret = av1394_pcr_remote_cas(avp, ph, 272 &pl.pl_old, pl.pl_data, pl.pl_arg); 273 } else { 274 switch (av1394_pcr_ph2idx(ph)) { 275 case AV1394_OMPR_IDX: 276 ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_OMPR, 277 pl.pl_arg, pl.pl_data, &pl.pl_old); 278 break; 279 case AV1394_IMPR_IDX: 280 ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_IMPR, 281 pl.pl_arg, pl.pl_data, &pl.pl_old); 282 break; 283 default: 284 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 285 if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) { 286 /* compare_swap */ 287 pl.pl_old = pcr->pcr_val; 288 if (pcr->pcr_val == pl.pl_arg) { 289 pcr->pcr_val = pl.pl_data; 290 } 291 } else { 292 ret = EINVAL; 293 } 294 rw_exit(&cmp->cmp_pcr_rwlock); 295 } 296 } 297 298 if (ret == 0) { 299 if (ddi_copyout(&pl, arg, sizeof (pl), mode) != 0) { 300 ret = EFAULT; 301 } 302 } 303 304 return (ret); 305 } 306 307 308 /* 309 * 310 * --- configuration routines 311 * 312 */ 313 static void 314 av1394_cmp_cleanup(av1394_inst_t *avp) 315 { 316 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 317 int i; 318 319 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 320 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 321 if (cmp->cmp_pcr[i]) { 322 av1394_pcr_fini(avp, i); 323 } 324 } 325 rw_exit(&cmp->cmp_pcr_rwlock); 326 rw_destroy(&cmp->cmp_pcr_rwlock); 327 (void) t1394_cmp_unregister(avp->av_t1394_hdl); 328 } 329 330 331 /* 332 * 333 * --- ioctl routines 334 * 335 * IEC61883_PLUG_INIT for local plugs 336 */ 337 static int 338 av1394_ioctl_plug_init_local(av1394_inst_t *avp, iec61883_plug_init_t *pip) 339 { 340 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 341 int err; 342 int ph; /* plug handle */ 343 int idx, max_idx; /* plug index */ 344 345 /* MPR's are a special case */ 346 if ((pip->pi_type == IEC61883_PLUG_MASTER_IN) || 347 (pip->pi_type == IEC61883_PLUG_MASTER_OUT)) { 348 pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, 349 pip->pi_type, 0); 350 return (0); 351 } 352 353 /* PCR */ 354 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 355 if (pip->pi_num == IEC61883_PLUG_ANY) { 356 if (pip->pi_type == IEC61883_PLUG_OUT) { 357 idx = AV1394_OPCR0_IDX; 358 max_idx = idx + AV1394_PCR_ADDR_NOPCR - 1; 359 } else { 360 ASSERT(pip->pi_type == IEC61883_PLUG_IN); 361 idx = AV1394_IPCR0_IDX; 362 max_idx = idx + AV1394_PCR_ADDR_NIPCR - 1; 363 } 364 365 /* find unused PCR */ 366 for (; idx <= max_idx; idx++) { 367 if (cmp->cmp_pcr[idx] != NULL) { 368 continue; 369 } 370 err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL); 371 if (err == DDI_SUCCESS) { 372 break; 373 } 374 } 375 } else { 376 ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num); 377 idx = max_idx = av1394_pcr_ph2idx(ph); 378 379 /* create PCR if not already */ 380 if (cmp->cmp_pcr[idx] == NULL) { 381 err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL); 382 } 383 } 384 385 rw_exit(&cmp->cmp_pcr_rwlock); 386 387 if ((err != DDI_SUCCESS) || (idx > max_idx)) { 388 return (EBUSY); 389 } 390 pip->pi_rnum = av1394_pcr_idx2num(idx); 391 pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, 392 pip->pi_rnum); 393 394 return (0); 395 } 396 397 /* 398 * IEC61883_PLUG_INIT for remote plugs 399 */ 400 static int 401 av1394_ioctl_plug_init_remote(av1394_inst_t *avp, iec61883_plug_init_t *pip) 402 { 403 int ph; 404 uint32_t val; 405 int ret; 406 407 if (pip->pi_num == IEC61883_PLUG_ANY) { 408 return (EINVAL); 409 } 410 411 ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num); 412 413 /* check PCR existance by attempting to read it */ 414 if ((ret = av1394_pcr_remote_read(avp, ph, &val)) == 0) { 415 pip->pi_handle = ph; 416 pip->pi_rnum = pip->pi_num; 417 } 418 419 return (ret); 420 } 421 422 423 /* 424 * 425 * --- plug routines 426 * 427 * initialize a PCR 428 */ 429 static int 430 av1394_pcr_init(av1394_inst_t *avp, int idx, uint32_t val) 431 { 432 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 433 av1394_pcr_t *pcr; 434 uint64_t addr; 435 int ret; 436 437 pcr = kmem_zalloc(sizeof (av1394_pcr_t), KM_SLEEP); 438 pcr->pcr_val = val; 439 cmp->cmp_pcr[idx] = pcr; 440 441 addr = av1394_pcr_idx2addr(idx); 442 ret = av1394_pcr_alloc_addr(avp, addr, &pcr->pcr_addr_hdl); 443 if (ret != DDI_SUCCESS) { 444 kmem_free(pcr, sizeof (av1394_pcr_t)); 445 cmp->cmp_pcr[idx] = NULL; 446 } 447 448 return (ret); 449 } 450 451 /* 452 * finalize a PCR 453 */ 454 static void 455 av1394_pcr_fini(av1394_inst_t *avp, int idx) 456 { 457 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 458 459 av1394_pcr_free_addr(avp, &cmp->cmp_pcr[idx]->pcr_addr_hdl); 460 kmem_free(cmp->cmp_pcr[idx], sizeof (av1394_pcr_t)); 461 cmp->cmp_pcr[idx] = NULL; 462 } 463 464 /* 465 * allocate CSR address for a PCR 466 */ 467 static int 468 av1394_pcr_alloc_addr(av1394_inst_t *avp, uint64_t addr, 469 t1394_addr_handle_t *hdlp) 470 { 471 t1394_alloc_addr_t aa; 472 int ret; 473 int result; 474 475 bzero(&aa, sizeof (aa)); 476 aa.aa_address = addr; 477 aa.aa_length = 4; 478 aa.aa_type = T1394_ADDR_FIXED; 479 aa.aa_enable = T1394_ADDR_RDENBL | T1394_ADDR_LKENBL; 480 aa.aa_evts.recv_read_request = av1394_pcr_recv_read_request; 481 aa.aa_evts.recv_lock_request = av1394_pcr_recv_lock_request; 482 aa.aa_arg = avp; 483 484 ret = t1394_alloc_addr(avp->av_t1394_hdl, &aa, 0, &result); 485 if (ret == DDI_SUCCESS) { 486 *hdlp = aa.aa_hdl; 487 } 488 489 return (ret); 490 } 491 492 /* 493 * free CSR address occupied by a PCR 494 */ 495 static void 496 av1394_pcr_free_addr(av1394_inst_t *avp, t1394_addr_handle_t *hdlp) 497 { 498 (void) t1394_free_addr(avp->av_t1394_hdl, hdlp, 0); 499 } 500 501 /* 502 * make plug handle. range checking should be performed by caller 503 */ 504 static int 505 av1394_pcr_make_ph(int loc, int type, int num) 506 { 507 int ph; 508 509 switch (type) { 510 case IEC61883_PLUG_IN: 511 ph = num + AV1394_IPCR0_IDX; 512 break; 513 case IEC61883_PLUG_OUT: 514 ph = num + AV1394_OPCR0_IDX; 515 break; 516 case IEC61883_PLUG_MASTER_IN: 517 ph = AV1394_IMPR_IDX; 518 break; 519 case IEC61883_PLUG_MASTER_OUT: 520 ph = AV1394_OMPR_IDX; 521 break; 522 default: 523 ASSERT(0); 524 } 525 526 if (loc == IEC61883_LOC_REMOTE) { 527 ph |= AV1394_PCR_REMOTE; 528 } 529 530 return (ph); 531 } 532 533 /* 534 * convert plug handle to PCR index 535 */ 536 static int 537 av1394_pcr_ph2idx(int ph) 538 { 539 return (ph & ~AV1394_PCR_REMOTE); 540 } 541 542 /* 543 * convert plug handle to PCR pointer 544 */ 545 static av1394_pcr_t * 546 av1394_pcr_ph2pcr(av1394_cmp_t *cmp, int ph) 547 { 548 int idx = av1394_pcr_ph2idx(ph); 549 550 if ((idx >= 0) && (idx < NELEM(cmp->cmp_pcr))) { 551 return (cmp->cmp_pcr[idx]); 552 } else { 553 return (NULL); 554 } 555 } 556 557 /* 558 * convert PCR index to CSR address 559 */ 560 static uint64_t 561 av1394_pcr_idx2addr(int idx) 562 { 563 return (AV1394_PCR_ADDR_START + idx * 4); 564 } 565 566 /* 567 * convert PCR index to number 568 */ 569 static int 570 av1394_pcr_idx2num(int idx) 571 { 572 ASSERT(!av1394_pcr_idx_is_mpr(idx)); 573 574 return ((idx - 1) % 32); 575 } 576 577 /* 578 * returns B_TRUE if a master plug 579 */ 580 static boolean_t 581 av1394_pcr_idx_is_mpr(int idx) 582 { 583 return (idx % 32 == 0); 584 } 585 586 static boolean_t 587 av1394_pcr_ph_is_mpr(int ph) 588 { 589 return (av1394_pcr_ph2idx(ph) % 32 == 0); 590 } 591 592 /* 593 * returns B_TRUE if a remote plug 594 */ 595 static boolean_t 596 av1394_pcr_ph_is_remote(int ph) 597 { 598 return ((ph & AV1394_PCR_REMOTE) != 0); 599 } 600 601 602 /* 603 * 604 * --- callbacks 605 * 606 */ 607 static void 608 av1394_pcr_recv_read_request(cmd1394_cmd_t *req) 609 { 610 av1394_inst_t *avp = req->cmd_callback_arg; 611 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 612 int idx; /* PCR index */ 613 av1394_pcr_t *pcr; 614 615 idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4; 616 617 if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) { 618 req->cmd_result = IEEE1394_RESP_TYPE_ERROR; 619 } else if ((idx >= NELEM(cmp->cmp_pcr)) || 620 ((pcr = cmp->cmp_pcr[idx]) == NULL)) { 621 req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR; 622 } else { 623 /* read */ 624 rw_enter(&cmp->cmp_pcr_rwlock, RW_READER); 625 req->cmd_u.q.quadlet_data = pcr->pcr_val; 626 rw_exit(&cmp->cmp_pcr_rwlock); 627 628 req->cmd_result = IEEE1394_RESP_COMPLETE; 629 } 630 631 (void) t1394_recv_request_done(avp->av_t1394_hdl, req, 0); 632 } 633 634 static void 635 av1394_pcr_recv_lock_request(cmd1394_cmd_t *req) 636 { 637 av1394_inst_t *avp = req->cmd_callback_arg; 638 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 639 int idx; /* PCR index */ 640 av1394_pcr_t *pcr; 641 642 idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4; 643 644 if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) || 645 (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) { 646 req->cmd_result = IEEE1394_RESP_TYPE_ERROR; 647 } else if ((idx >= NELEM(cmp->cmp_pcr)) || 648 ((pcr = cmp->cmp_pcr[idx]) == NULL)) { 649 req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR; 650 } else { 651 /* compare_swap */ 652 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 653 if (pcr->pcr_val == req->cmd_u.l32.arg_value) { 654 pcr->pcr_val = req->cmd_u.l32.data_value; 655 } 656 req->cmd_u.l32.old_value = pcr->pcr_val; 657 rw_exit(&cmp->cmp_pcr_rwlock); 658 659 req->cmd_result = IEEE1394_RESP_COMPLETE; 660 } 661 662 (void) t1394_recv_request_done(avp->av_t1394_hdl, req, 0); 663 } 664 665 666 /* 667 * 668 * --- remote PCR routines 669 * 670 * read specified PCR on the remote node 671 */ 672 static int 673 av1394_pcr_remote_read(av1394_inst_t *avp, int ph, uint32_t *valp) 674 { 675 cmd1394_cmd_t *cmd; 676 int ret = 0; 677 int err; 678 679 ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd); 680 if (ret != DDI_SUCCESS) { 681 return (ENOMEM); 682 } 683 684 cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph)); 685 cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD; 686 cmd->cmd_options = CMD1394_BLOCKING; 687 688 if (((err = t1394_read(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) && 689 (cmd->cmd_result == CMD1394_CMDSUCCESS)) { 690 *valp = cmd->cmd_u.q.quadlet_data; 691 } else { 692 ret = EIO; 693 } 694 695 err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd); 696 ASSERT(err == DDI_SUCCESS); 697 698 return (ret); 699 } 700 701 /* 702 * compare_swap specified PCR on the remote node 703 */ 704 static int 705 av1394_pcr_remote_cas(av1394_inst_t *avp, int ph, uint32_t *old_valuep, 706 uint32_t data_value, uint32_t arg_value) 707 { 708 cmd1394_cmd_t *cmd; 709 int ret = 0; 710 int err; 711 712 ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd); 713 if (ret != DDI_SUCCESS) { 714 return (ENOMEM); 715 } 716 717 cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph)); 718 cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 719 cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP; 720 cmd->cmd_u.l32.data_value = data_value; 721 cmd->cmd_u.l32.arg_value = arg_value; 722 cmd->cmd_u.l32.num_retries = 0; 723 cmd->cmd_options = CMD1394_BLOCKING; 724 725 if (((err = t1394_lock(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) && 726 (cmd->cmd_result == CMD1394_CMDSUCCESS)) { 727 *old_valuep = cmd->cmd_u.l32.old_value; 728 } else { 729 ret = EIO; 730 } 731 732 err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd); 733 ASSERT(err == DDI_SUCCESS); 734 735 return (ret); 736 } 737