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