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