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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * provide the interface to the layered drivers (send request/receive 29 * response to the RMC 30 * 31 */ 32 33 /* 34 * Header files 35 */ 36 #include <sys/conf.h> 37 #include <sys/callb.h> 38 #include <sys/cyclic.h> 39 #include <sys/membar.h> 40 #include <sys/modctl.h> 41 #include <sys/strlog.h> 42 #include <sys/sunddi.h> 43 #include <sys/ddi.h> 44 #include <sys/types.h> 45 #include <sys/disp.h> 46 #include <sys/rmc_comm_dp.h> 47 #include <sys/rmc_comm_dp_boot.h> 48 #include <sys/rmc_comm_drvintf.h> 49 #include <sys/rmc_comm.h> 50 51 void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t); 52 void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t); 53 54 static int rmc_comm_send_req_resp(struct rmc_comm_state *rcs, 55 rmc_comm_msg_t *request, rmc_comm_msg_t *response, uint32_t wait_time); 56 static int rmc_comm_wait_bp_reply(struct rmc_comm_state *, 57 rmc_comm_dp_state_t *, dp_req_resp_t *, clock_t); 58 static void rmc_comm_wait_enable_to_send(struct rmc_comm_state *, 59 rmc_comm_dp_state_t *); 60 static void rmc_comm_wake_up_next(struct rmc_comm_state *); 61 static void rmc_comm_send_pend_req(caddr_t arg); 62 static int rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs); 63 static void rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs); 64 65 /* 66 * leaf driver to use this function to send a request to the remote side (RMC) 67 * and wait for a reply 68 */ 69 int 70 rmc_comm_request_response(rmc_comm_msg_t *request, 71 rmc_comm_msg_t *response, uint32_t wait_time) 72 { 73 struct rmc_comm_state *rcs; 74 int err; 75 76 /* 77 * get the soft state struct (instance 0) 78 */ 79 if ((rcs = rmc_comm_getstate(NULL, 0, 80 "rmc_comm_request_response")) == NULL) 81 return (RCENOSOFTSTATE); 82 83 do { 84 err = rmc_comm_send_req_resp(rcs, request, response, wait_time); 85 } while (err == RCEGENERIC); 86 return (err); 87 } 88 89 /* 90 * leaf driver to use this function to send a request to the remote side (RMC) 91 * without waiting for a reply. If flag is RMC_COMM_DREQ_URGENT, the request 92 * message is sent once-off (an eventual pending request is aborted). This 93 * flag must only be used when try to send a request in critical condition 94 * (while the system is shutting down for instance and the CPU signature 95 * has to be sent). Otherwise, the request is stored in a temporary location 96 * and delivered by a thread. 97 */ 98 int 99 rmc_comm_request_nowait(rmc_comm_msg_t *request, uint8_t flag) 100 { 101 struct rmc_comm_state *rcs; 102 rmc_comm_dp_state_t *dps; 103 rmc_comm_drvintf_state_t *dis; 104 dp_message_t req; 105 int err = RCNOERR; 106 uint8_t flags = 0; 107 108 /* 109 * get the soft state struct (instance 0) 110 */ 111 if ((rcs = rmc_comm_getstate(NULL, 0, 112 "rmc_comm_request_response")) == NULL) 113 return (RCENOSOFTSTATE); 114 115 /* 116 * just a sanity check... 117 */ 118 if (request == NULL) { 119 DPRINTF(rcs, DAPI, (CE_CONT, "reqnowait, invalid args\n")); 120 return (RCEINVARG); 121 } 122 123 if (!IS_NUMBERED_MSG(request->msg_type)) { 124 DPRINTF(rcs, DAPI, (CE_CONT, 125 "reqnowait, ctrl msg not allowed! req type=%x\n", 126 request->msg_type)); 127 return (RCEINVARG); 128 } 129 130 if (flag == RMC_COMM_DREQ_URGENT) { 131 /* 132 * Send this request with high priority i.e. abort eventual 133 * request/response pending sessions. 134 */ 135 136 dps = &rcs->dp_state; 137 138 DPRINTF(rcs, DAPI, (CE_CONT, "going to send request=%x (URG)\n", 139 request->msg_type)); 140 141 /* 142 * Handle the case where we are called during panic 143 * processing. If that occurs, then another thread in 144 * rmc_comm might have been idled by panic() while 145 * holding dp_mutex. As a result, do not unconditionally 146 * grab dp_mutex. 147 */ 148 if (ddi_in_panic() != 0) { 149 if (mutex_tryenter(dps->dp_mutex) == 0) { 150 return (RCENODATALINK); 151 } 152 } else { 153 mutex_enter(dps->dp_mutex); 154 } 155 156 /* 157 * send the request only if the protocol data link is up. 158 * it is pointless to send it in the other case. 159 */ 160 if (dps->data_link_ok) { 161 162 /* 163 * clean up an eventual pending request/response session 164 * (save its current status) 165 */ 166 if (dps->pending_request) { 167 flags = dps->req_resp.flags; 168 rmc_comm_dp_mcleanup(rcs); 169 } 170 171 /* 172 * send the request message 173 */ 174 req.msg_type = request->msg_type; 175 req.msg_buf = (uint8_t *)request->msg_buf; 176 req.msg_msglen = (uint16_t)request->msg_len; 177 178 DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x (URG)\n", 179 request->msg_type)); 180 181 err = rmc_comm_dp_msend(rcs, &req); 182 183 /* 184 * wait for fifos to drain 185 */ 186 rmc_comm_serdev_drain(rcs); 187 188 /* 189 * clean up the current session 190 */ 191 rmc_comm_dp_mcleanup(rcs); 192 193 /* 194 * abort an old session (if any) 195 */ 196 if (dps->pending_request) { 197 dps->req_resp.flags = flags; 198 dp_wake_up_waiter(rcs, MSG_ERROR); 199 } 200 } 201 202 mutex_exit(dps->dp_mutex); 203 204 } else { 205 206 /* 207 * Get an 'independent' thread (rmc_comm_send_pend_req) 208 * to send this request (since the calling thread does not 209 * want to wait). Copy the request in the drvintf state 210 * structure and signal the thread. 211 */ 212 213 dis = &rcs->drvi_state; 214 215 mutex_enter(dis->dreq_mutex); 216 217 if (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) { 218 219 DPRINTF(rcs, DAPI, (CE_CONT, "get to send request=%x\n", 220 request->msg_type)); 221 222 /* 223 * copy the request in a temporary location 224 * (drvinf_state structure) and signal the thread 225 * that a request message has to be delivered 226 */ 227 228 if (request->msg_len < DP_MAX_MSGLEN) { 229 dis->dreq_request.msg_type = request->msg_type; 230 dis->dreq_request.msg_len = request->msg_len; 231 dis->dreq_request.msg_buf = 232 dis->dreq_request_buf; 233 bcopy(request->msg_buf, 234 dis->dreq_request.msg_buf, 235 request->msg_len); 236 237 dis->dreq_state = RMC_COMM_DREQ_ST_PROCESS; 238 cv_signal(dis->dreq_sig_cv); 239 240 } else { 241 /* 242 * not enough space to hold the request 243 */ 244 err = RCEREPTOOBIG; 245 } 246 } else { 247 248 DPRINTF(rcs, DAPI, (CE_CONT, "cannot get to send " 249 "request=%x (busy)\n", request->msg_type)); 250 251 /* 252 * only one request per time can be processed. 253 * the thread is either busy (RMC_COMM_DREQ_ST_PROCESS) 254 * or terminating (RMC_COMM_DREQ_ST_EXIT) 255 */ 256 err = RCEGENERIC; 257 } 258 259 mutex_exit(dis->dreq_mutex); 260 } 261 262 return (err); 263 } 264 265 /* 266 * Function used to send a request and (eventually) wait for a response. 267 * It can be called from a leaf driver (via rmc_comm_request_response) or 268 * from the thread in charge of sending 'no-wait' requests 269 * (rmc_comm_send_pend_req). 270 */ 271 static int 272 rmc_comm_send_req_resp(struct rmc_comm_state *rcs, rmc_comm_msg_t *request, 273 rmc_comm_msg_t *response, uint32_t wait_time) 274 { 275 rmc_comm_dp_state_t *dps; 276 dp_req_resp_t *drr; 277 dp_message_t *exp_resp; 278 dp_message_t req; 279 clock_t resend_clockt, delta; 280 clock_t stop_clockt; 281 int err; 282 283 284 /* 285 * just a sanity check... 286 */ 287 if (request == NULL) { 288 DPRINTF(rcs, DAPI, (CE_CONT, "reqresp, invalid args\n")); 289 return (RCEINVARG); 290 } 291 292 /* 293 * drivers cannot send control messages at all. They are meant to 294 * be used at low level only. 295 */ 296 if (!IS_NUMBERED_MSG(request->msg_type)) { 297 DPRINTF(rcs, DAPI, (CE_CONT, 298 "reqresp, ctrl msg not allowed! req type=%x\n", 299 request->msg_type)); 300 return (RCEINVARG); 301 } 302 303 dps = &rcs->dp_state; 304 drr = &dps->req_resp; 305 exp_resp = &drr->response; 306 307 /* 308 * Handle the case where we are called during panic 309 * processing. If that occurs, then another thread in 310 * rmc_comm might have been idled by panic() while 311 * holding dp_mutex. As a result, do not unconditionally 312 * grab dp_mutex. 313 */ 314 if (ddi_in_panic() != 0) { 315 if (mutex_tryenter(dps->dp_mutex) == 0) { 316 return (RCENODATALINK); 317 } 318 } else { 319 mutex_enter(dps->dp_mutex); 320 } 321 322 /* 323 * if the data link set up is suspended, just return. 324 * the only time that this can happen is during firmware download 325 * (see rmc_comm_request_response_bp). Basically, the data link is 326 * down and the timer for setting up the data link is not running. 327 */ 328 if (!dps->data_link_ok && 329 dps->timer_link_setup == (timeout_id_t)0) { 330 331 mutex_exit(dps->dp_mutex); 332 return (RCENODATALINK); 333 } 334 335 DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d, req type=%x\n", 336 dps->pending_request, request->msg_type)); 337 338 rmc_comm_wait_enable_to_send(rcs, dps); 339 340 /* 341 * We now have control of the RMC. 342 * Place a lower limit on the shortest amount of time to be 343 * waited before timing out while communicating with the RMC 344 */ 345 if (wait_time < DP_MIN_TIMEOUT) 346 wait_time = DP_MIN_TIMEOUT; 347 348 stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 349 350 /* 351 * initialization of the request/response data structure 352 */ 353 drr->flags = 0; 354 drr->error_status = 0; 355 356 /* 357 * set the 'expected reply' buffer: get the buffer already allocated 358 * for the response (if a reply is expected!) 359 */ 360 if (response != NULL) { 361 exp_resp->msg_type = response->msg_type; 362 exp_resp->msg_buf = (uint8_t *)response->msg_buf; 363 exp_resp->msg_msglen = response->msg_bytes; 364 exp_resp->msg_bufsiz = response->msg_len; 365 } else { 366 exp_resp->msg_type = DP_NULL_MSG; 367 exp_resp->msg_buf = NULL; 368 exp_resp->msg_bufsiz = 0; 369 exp_resp->msg_msglen = 0; 370 } 371 372 /* 373 * send the request message 374 */ 375 req.msg_type = request->msg_type; 376 req.msg_buf = (uint8_t *)request->msg_buf; 377 req.msg_msglen = request->msg_len; 378 379 /* 380 * send the message and wait for the reply or ACKnowledgment 381 * re-send the message if reply/ACK is not received in the 382 * timeframe defined 383 */ 384 DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x\n", request->msg_type)); 385 386 delta = drv_usectohz(TX_RETRY_TIME * 1000); 387 388 while ((err = rmc_comm_dp_msend(rcs, &req)) == RCNOERR) { 389 390 resend_clockt = ddi_get_lbolt() + delta; 391 392 /* 393 * wait for a reply or an acknowledgement 394 */ 395 (void) cv_reltimedwait(drr->cv_wait_reply, dps->dp_mutex, 396 delta, TR_CLOCK_TICK); 397 398 DPRINTF(rcs, DAPI, (CE_CONT, 399 "reqresp send status: flags=%02x req=%x resp=%x tick=%ld\n", 400 drr->flags, request->msg_type, 401 response ? response->msg_type : -1, 402 stop_clockt - resend_clockt)); 403 404 /* 405 * Check for error condition first 406 * Then, check if the command has been replied/ACKed 407 * Then, check if it has timeout and if there is any 408 * time left to resend the message. 409 */ 410 if ((drr->flags & MSG_ERROR) != 0) { 411 if (drr->error_status == 0) { 412 err = RCEGENERIC; 413 } else { 414 err = drr->error_status; 415 } 416 break; 417 418 } else if (response != NULL && 419 (drr->flags & MSG_REPLY_RXED) != 0) { 420 /* 421 * yes! here is the reply 422 */ 423 424 /* 425 * get the actual length of the msg 426 * a negative value means that the reply message 427 * was too big for the receiver buffer 428 */ 429 response->msg_bytes = exp_resp->msg_msglen; 430 if (response->msg_bytes < 0) 431 err = RCEREPTOOBIG; 432 else 433 err = RCNOERR; 434 break; 435 436 } else if (response == NULL && (drr->flags & MSG_ACKED) != 0) { 437 /* 438 * yes! message has been acknowledged 439 */ 440 441 err = RCNOERR; 442 break; 443 444 } else if ((stop_clockt - resend_clockt) <= 0) { 445 /* 446 * no more time left. set the error code, 447 * exit the loop 448 */ 449 450 err = RCETIMEOUT; 451 break; 452 } 453 } 454 455 rmc_comm_dp_mcleanup(rcs); 456 457 rmc_comm_wake_up_next(rcs); 458 459 mutex_exit(dps->dp_mutex); 460 461 DPRINTF(rcs, DAPI, (CE_CONT, "reqresp end: err=%d, request=%x\n", 462 err, request->msg_type)); 463 464 return (err); 465 } 466 467 /* 468 * Function used to send a BP (Boot Prom) message and get the reply. 469 * BP protocol is provided only to support firmware download. 470 * 471 * This function will look for the following key BP protocol commands: 472 * BP_OBP_BOOTINIT: the data link is brought down so that request/response 473 * sessions cannot be started. The reason why is that this command will cause 474 * RMC fw to jump to the boot monitor (BOOTMON_FLASH) and data protocol is not 475 * operational. In this context, RMC fw will only be using the BP protocol. 476 * BP_OBP_RESET: data link setup timer is resumed. This command cause the RMC 477 * to reboot and hence become operational. 478 */ 479 int 480 rmc_comm_request_response_bp(rmc_comm_msg_t *request_bp, 481 rmc_comm_msg_t *response_bp, uint32_t wait_time) 482 { 483 struct rmc_comm_state *rcs; 484 rmc_comm_dp_state_t *dps; 485 dp_req_resp_t *drr; 486 dp_message_t *resp_bp; 487 bp_msg_t *bp_msg; 488 clock_t stop_clockt; 489 int err = RCNOERR; 490 boolean_t bootinit_sent = 0; 491 492 /* 493 * get the soft state struct (instance 0) 494 */ 495 if ((rcs = rmc_comm_getstate(NULL, 0, 496 "rmc_comm_request_response_bp")) == NULL) 497 return (RCENOSOFTSTATE); 498 499 /* 500 * sanity check: request_bp buffer must always be provided 501 */ 502 if (request_bp == NULL) { 503 DPRINTF(rcs, DAPI, (CE_CONT, "reqresp_bp, invalid args\n")); 504 return (RCEINVARG); 505 } 506 507 bp_msg = (bp_msg_t *)request_bp->msg_buf; 508 509 DPRINTF(rcs, DAPI, (CE_CONT, "send request_bp=%x\n", bp_msg->cmd)); 510 511 /* 512 * only BP message can be sent 513 */ 514 if (!IS_BOOT_MSG(bp_msg->cmd)) { 515 DPRINTF(rcs, DAPI, (CE_CONT, 516 "reqresp_bp, only BP msg are allowed! type=%x\n", 517 bp_msg->cmd)); 518 return (RCEINVARG); 519 } 520 521 dps = &rcs->dp_state; 522 drr = &dps->req_resp; 523 resp_bp = &drr->response; 524 525 mutex_enter(dps->dp_mutex); 526 527 rmc_comm_wait_enable_to_send(rcs, dps); 528 529 /* 530 * Now, before sending the message, just check what it is being sent 531 * and take action accordingly. 532 * 533 * is it BP_OBP_BOOTINIT or BP_OBP_RESET command? 534 */ 535 if (bp_msg->cmd == BP_OBP_BOOTINIT) { 536 537 /* 538 * bring down the protocol data link 539 * (must be done before aborting a request/response session) 540 */ 541 dps->data_link_ok = 0; 542 dps->timer_link_setup = (timeout_id_t)0; 543 544 bootinit_sent = 1; 545 546 } else if (bp_msg->cmd == BP_OBP_RESET) { 547 548 /* 549 * restart the data link set up timer. RMC is coming up... 550 */ 551 552 dp_reset(rcs, INITIAL_SEQID, 0, 1); 553 } 554 555 /* 556 * initialization of the request/response data structure 557 */ 558 drr->flags = 0; 559 drr->error_status = 0; 560 561 /* 562 * set the reply buffer: get the buffer already allocated 563 * for the response 564 */ 565 if (response_bp != NULL) { 566 DPRINTF(rcs, DAPI, (CE_CONT, "expect BP reply. len=%d\n", 567 response_bp->msg_len)); 568 569 resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf; 570 resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len; 571 } 572 573 /* 574 * send the BP message and wait for the reply 575 */ 576 577 rmc_comm_bp_msend(rcs, bp_msg); 578 579 if (response_bp != NULL) { 580 581 /* 582 * place a lower limit on the shortest amount of time to be 583 * waited before timing out while communicating with the RMC 584 */ 585 if (wait_time < DP_MIN_TIMEOUT) 586 wait_time = DP_MIN_TIMEOUT; 587 588 stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 589 590 if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr, 591 stop_clockt)) == RCNOERR) { 592 593 /* 594 * get the actual length of the msg 595 * a negative value means that the reply message 596 * was too big for the receiver buffer 597 */ 598 response_bp->msg_bytes = resp_bp->msg_msglen; 599 if (response_bp->msg_bytes < 0) { 600 err = RCEREPTOOBIG; 601 602 } else if (bootinit_sent) { 603 604 /* 605 * BOOTINIT cmd may fail. In this is the case, 606 * the RMC is still operational. Hence, we 607 * try (once) to set up the data link 608 * protocol. 609 */ 610 bp_msg = (bp_msg_t *)response_bp->msg_buf; 611 612 if (bp_msg->cmd == BP_RSC_BOOTFAIL && 613 bp_msg->dat1 == BP_DAT1_REJECTED) { 614 (void) rmc_comm_dp_ctlsend(rcs, 615 DP_CTL_START); 616 } 617 } 618 } 619 } 620 621 rmc_comm_dp_mcleanup(rcs); 622 623 rmc_comm_wake_up_next(rcs); 624 625 mutex_exit(dps->dp_mutex); 626 627 return (err); 628 } 629 630 631 /* 632 * to register for an asynchronous (via soft interrupt) notification 633 * of a message from the remote side (RMC) 634 */ 635 int 636 rmc_comm_reg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler, 637 rmc_comm_msg_t *msgbuf, uint_t *state, kmutex_t *lock) 638 { 639 struct rmc_comm_state *rcs; 640 dp_msg_intr_t *msgintr; 641 int err = RCNOERR; 642 643 if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_reg_intr")) == NULL) 644 return (RCENOSOFTSTATE); 645 646 mutex_enter(rcs->dp_state.dp_mutex); 647 648 msgintr = &rcs->dp_state.msg_intr; 649 650 /* 651 * lock is required. If it is not defined, the 652 * interrupt handler routine cannot be registered. 653 */ 654 if (lock == NULL) { 655 mutex_exit(rcs->dp_state.dp_mutex); 656 return (RCEINVARG); 657 } 658 659 /* 660 * only one interrupt handler can be registered. 661 */ 662 if (msgintr->intr_handler == NULL) { 663 664 if (ddi_add_softintr(rcs->dip, DDI_SOFTINT_HIGH, 665 &msgintr->intr_id, NULL, NULL, intr_handler, 666 (caddr_t)msgbuf) == DDI_SUCCESS) { 667 668 msgintr->intr_handler = intr_handler; 669 msgintr->intr_lock = lock; 670 msgintr->intr_state = state; 671 msgintr->intr_msg_type = msg_type; 672 msgintr->intr_arg = (caddr_t)msgbuf; 673 } else { 674 err = RCECANTREGINTR; 675 } 676 } else { 677 err = RCEALREADYREG; 678 } 679 680 mutex_exit(rcs->dp_state.dp_mutex); 681 682 return (err); 683 } 684 685 /* 686 * To unregister for asynchronous notifications 687 */ 688 int 689 rmc_comm_unreg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler) 690 { 691 struct rmc_comm_state *rcs; 692 dp_msg_intr_t *msgintr; 693 int err = RCNOERR; 694 695 if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_unreg_intr")) == NULL) 696 return (RCENOSOFTSTATE); 697 698 mutex_enter(rcs->dp_state.dp_mutex); 699 700 msgintr = &rcs->dp_state.msg_intr; 701 702 if (msgintr->intr_handler != NULL && 703 msgintr->intr_msg_type == msg_type && 704 msgintr->intr_handler == intr_handler) { 705 706 ddi_remove_softintr(msgintr->intr_id); 707 msgintr->intr_handler = NULL; 708 msgintr->intr_id = 0; 709 msgintr->intr_msg_type = 0; 710 msgintr->intr_arg = NULL; 711 msgintr->intr_lock = NULL; 712 msgintr->intr_state = NULL; 713 } else { 714 err = RCEGENERIC; 715 } 716 717 mutex_exit(rcs->dp_state.dp_mutex); 718 719 return (err); 720 } 721 722 /* 723 * To send raw data (firmware s-records) down to the RMC. 724 * It is provided only to support firmware download. 725 */ 726 int 727 rmc_comm_send_srecord_bp(caddr_t buf, int buflen, 728 rmc_comm_msg_t *response_bp, uint32_t wait_time) 729 { 730 struct rmc_comm_state *rcs; 731 rmc_comm_dp_state_t *dps; 732 dp_req_resp_t *drr; 733 dp_message_t *resp_bp; 734 clock_t stop_clockt; 735 int err; 736 737 /* 738 * get the soft state struct (instance 0) 739 */ 740 if ((rcs = rmc_comm_getstate(NULL, 0, 741 "rmc_comm_request_response_bp")) == NULL) 742 return (RCENOSOFTSTATE); 743 744 /* 745 * sanity check: response_bp buffer must always be provided 746 */ 747 if (buf == NULL || response_bp == NULL) { 748 DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp,invalid args\n")); 749 return (RCEINVARG); 750 } 751 752 DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp, buflen=%d\n", buflen)); 753 754 dps = &rcs->dp_state; 755 drr = &dps->req_resp; 756 resp_bp = &drr->response; 757 758 mutex_enter(dps->dp_mutex); 759 760 rmc_comm_wait_enable_to_send(rcs, dps); 761 762 /* 763 * initialization of the request/response data structure 764 */ 765 drr->flags = 0; 766 drr->error_status = 0; 767 768 /* 769 * set the reply buffer: get the buffer already allocated 770 * for the response 771 */ 772 resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf; 773 resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len; 774 775 /* 776 * send raw data (s-record) and wait for the reply (BP message) 777 */ 778 779 rmc_comm_bp_srecsend(rcs, (char *)buf, buflen); 780 781 /* 782 * place a lower limit on the shortest amount of time to be 783 * waited before timing out while communicating with the RMC 784 */ 785 if (wait_time < DP_MIN_TIMEOUT) 786 wait_time = DP_MIN_TIMEOUT; 787 788 stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 789 790 if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr, 791 stop_clockt)) == RCNOERR) { 792 /* 793 * get the actual length of the msg 794 * a negative value means that the reply message 795 * was too big for the receiver buffer 796 */ 797 response_bp->msg_bytes = resp_bp->msg_msglen; 798 if (response_bp->msg_bytes < 0) { 799 err = RCEREPTOOBIG; 800 } 801 } 802 803 rmc_comm_dp_mcleanup(rcs); 804 805 rmc_comm_wake_up_next(rcs); 806 807 mutex_exit(dps->dp_mutex); 808 809 return (err); 810 } 811 812 /* 813 * To wait for (any) BP message to be received. 814 * (dp_mutex must be held) 815 */ 816 static int 817 rmc_comm_wait_bp_reply(struct rmc_comm_state *rcs, rmc_comm_dp_state_t *dps, 818 dp_req_resp_t *drr, clock_t stop_clockt) 819 { 820 clock_t clockleft = 1; 821 int err = RCNOERR; 822 823 clockleft = cv_timedwait(drr->cv_wait_reply, dps->dp_mutex, 824 stop_clockt); 825 826 827 DPRINTF(rcs, DAPI, (CE_CONT, 828 "reqresp_bp, send: flags=%02x, clktick left=%ld\n", 829 drr->flags, clockleft)); 830 831 /* 832 * Check for error condition first. 833 * Then, check if it has timeout. 834 * Then, check if the command has been replied. 835 */ 836 if ((drr->flags & MSG_ERROR) != 0) { 837 838 err = RCEGENERIC; 839 840 } else if (clockleft <= 0) { 841 /* 842 * timeout 843 */ 844 845 err = RCETIMEOUT; 846 847 } else if ((drr->flags & MSG_RXED_BP) == 0) { 848 849 err = RCEGENERIC; 850 } 851 852 return (err); 853 } 854 855 /* 856 * Wait for the pending_request flag to be cleared and acquire it for our 857 * own use. The caller is then allowed to start a new request/response 858 * session with the RMC. 859 * Note that all send-receive actions to the RMC include a time-out, so 860 * the pending-request must eventually go away - even if the RMC is down. 861 * Hence there is no need to timeout the wait action of this function. 862 * (dp_mutex must be held on entry). 863 */ 864 static void 865 rmc_comm_wait_enable_to_send(struct rmc_comm_state *rcs, 866 rmc_comm_dp_state_t *dps) 867 { 868 DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d\n", 869 dps->pending_request)); 870 871 /* 872 * A new message can actually grab the lock before the thread 873 * that has just been signaled. Therefore, we need to double 874 * check to make sure that pending_request is not already set 875 * after we wake up. 876 * 877 * Potentially this could mean starvation for certain unfortunate 878 * threads that keep getting woken up and putting back to sleep. 879 * But the window of such contention is very small to begin with. 880 */ 881 882 while (dps->pending_request) { 883 /* 884 * just 'sit and wait' until there are no pending requests 885 */ 886 887 cv_wait(dps->cv_ok_to_send, dps->dp_mutex); 888 } 889 890 /* 891 * now a request/response can be started. Set the flag so that nobody 892 * else will be able to send anything. 893 */ 894 dps->pending_request = 1; 895 } 896 897 /* 898 * To wake up one of the threads (if any) waiting for starting a 899 * request/response session. 900 * (dp_mutex must be held) 901 */ 902 static void 903 rmc_comm_wake_up_next(struct rmc_comm_state *rcs) 904 { 905 /* 906 * wake up eventual waiting threads... 907 */ 908 909 rcs->dp_state.pending_request = 0; 910 cv_signal(rcs->dp_state.cv_ok_to_send); 911 } 912 913 914 /* 915 * thread which delivers pending request message to the rmc. Some leaf drivers 916 * cannot afford to wait for a request to be replied/ACKed. Hence, a request 917 * message is stored temporarily in the state structure and this thread 918 * gets woken up to deliver it. 919 */ 920 static void 921 rmc_comm_send_pend_req(caddr_t arg) 922 { 923 struct rmc_comm_state *rcs; 924 rmc_comm_drvintf_state_t *dis; 925 callb_cpr_t cprinfo; 926 927 if (arg == NULL) { 928 thread_exit(); 929 /* NOTREACHED */ 930 } 931 932 rcs = (struct rmc_comm_state *)arg; 933 dis = &rcs->drvi_state; 934 935 CALLB_CPR_INIT(&cprinfo, dis->dreq_mutex, callb_generic_cpr, 936 "rmc_comm_send_pend_req"); 937 938 mutex_enter(dis->dreq_mutex); 939 940 if (dis->dreq_state <= RMC_COMM_DREQ_ST_READY) 941 dis->dreq_state = RMC_COMM_DREQ_ST_WAIT; 942 943 for (;;) { 944 945 /* 946 * Wait for someone to tell me to continue. 947 */ 948 while (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) { 949 CALLB_CPR_SAFE_BEGIN(&cprinfo); 950 cv_wait(dis->dreq_sig_cv, dis->dreq_mutex); 951 CALLB_CPR_SAFE_END(&cprinfo, dis->dreq_mutex); 952 } 953 954 /* RMC_COMM_DREQ_ST_EXIT implies signal by _detach(). */ 955 if (dis->dreq_state == RMC_COMM_DREQ_ST_EXIT) { 956 dis->dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED; 957 dis->dreq_tid = 0; 958 959 /* dis->dreq_mutex is held at this point! */ 960 CALLB_CPR_EXIT(&cprinfo); 961 962 thread_exit(); 963 /* NOTREACHED */ 964 } 965 966 ASSERT(dis->dreq_state == RMC_COMM_DREQ_ST_PROCESS); 967 mutex_exit(dis->dreq_mutex); 968 969 /* 970 * deliver the request (and wait...) 971 */ 972 while (rmc_comm_send_req_resp(rcs, &dis->dreq_request, NULL, 973 RMC_COMM_DREQ_DEFAULT_TIME) == RCEGENERIC) { 974 } 975 976 mutex_enter(dis->dreq_mutex); 977 if (dis->dreq_state != RMC_COMM_DREQ_ST_EXIT) 978 dis->dreq_state = RMC_COMM_DREQ_ST_WAIT; 979 } 980 } 981 982 /* 983 * start thread to deal with pending requests to be delivered asynchronously 984 * (i.e. leaf driver do not have to/cannot wait for a reply/ACk of a request) 985 */ 986 static int 987 rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs) 988 { 989 rmc_comm_drvintf_state_t *dis = &rcs->drvi_state; 990 int err = 0; 991 kthread_t *tp; 992 993 mutex_enter(dis->dreq_mutex); 994 995 if (dis->dreq_state == RMC_COMM_DREQ_ST_NOTSTARTED) { 996 997 tp = thread_create(NULL, 0, rmc_comm_send_pend_req, 998 (caddr_t)rcs, 0, &p0, TS_RUN, maxclsyspri); 999 dis->dreq_state = RMC_COMM_DREQ_ST_READY; 1000 dis->dreq_tid = tp->t_did; 1001 } 1002 1003 mutex_exit(dis->dreq_mutex); 1004 1005 return (err); 1006 } 1007 1008 /* 1009 * stop the thread (to deliver pending request messages) 1010 */ 1011 static void 1012 rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs) 1013 { 1014 rmc_comm_drvintf_state_t *dis = &rcs->drvi_state; 1015 kt_did_t tid; 1016 1017 mutex_enter(dis->dreq_mutex); 1018 tid = dis->dreq_tid; 1019 if (tid != 0) { 1020 dis->dreq_state = RMC_COMM_DREQ_ST_EXIT; 1021 dis->dreq_tid = 0; 1022 cv_signal(dis->dreq_sig_cv); 1023 } 1024 mutex_exit(dis->dreq_mutex); 1025 1026 /* 1027 * Wait for rmc_comm_send_pend_req() to finish 1028 */ 1029 if (tid != 0) 1030 thread_join(tid); 1031 } 1032 1033 /* 1034 * init function - start thread to deal with pending requests (no-wait requests) 1035 */ 1036 int 1037 rmc_comm_drvintf_init(struct rmc_comm_state *rcs) 1038 { 1039 int err = 0; 1040 1041 DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_init\n")); 1042 rcs->drvi_state.dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED; 1043 rcs->drvi_state.dreq_tid = 0; 1044 1045 mutex_init(rcs->drvi_state.dreq_mutex, NULL, MUTEX_DRIVER, NULL); 1046 cv_init(rcs->drvi_state.dreq_sig_cv, NULL, CV_DRIVER, NULL); 1047 1048 err = rmc_comm_dreq_thread_start(rcs); 1049 if (err != 0) { 1050 cv_destroy(rcs->drvi_state.dreq_sig_cv); 1051 mutex_destroy(rcs->drvi_state.dreq_mutex); 1052 } 1053 1054 DPRINTF(rcs, DGEN, (CE_CONT, "thread started? err=%d\n", err)); 1055 1056 return (err); 1057 } 1058 1059 /* 1060 * fini function - kill thread to deal with pending requests (no-wait requests) 1061 */ 1062 void 1063 rmc_comm_drvintf_fini(struct rmc_comm_state *rcs) 1064 { 1065 DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:stop thread\n")); 1066 1067 rmc_comm_dreq_thread_kill(rcs); 1068 1069 DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:destroy Mx/CVs\n")); 1070 1071 cv_destroy(rcs->drvi_state.dreq_sig_cv); 1072 mutex_destroy(rcs->drvi_state.dreq_mutex); 1073 } 1074