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