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
rmc_comm_request_response(rmc_comm_msg_t * request,rmc_comm_msg_t * response,uint32_t wait_time)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
rmc_comm_request_nowait(rmc_comm_msg_t * request,uint8_t flag)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
rmc_comm_send_req_resp(struct rmc_comm_state * rcs,rmc_comm_msg_t * request,rmc_comm_msg_t * response,uint32_t wait_time)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
rmc_comm_request_response_bp(rmc_comm_msg_t * request_bp,rmc_comm_msg_t * response_bp,uint32_t wait_time)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
rmc_comm_reg_intr(uint8_t msg_type,rmc_comm_intrfunc_t intr_handler,rmc_comm_msg_t * msgbuf,uint_t * state,kmutex_t * lock)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
rmc_comm_unreg_intr(uint8_t msg_type,rmc_comm_intrfunc_t intr_handler)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
rmc_comm_send_srecord_bp(caddr_t buf,int buflen,rmc_comm_msg_t * response_bp,uint32_t wait_time)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
rmc_comm_wait_bp_reply(struct rmc_comm_state * rcs,rmc_comm_dp_state_t * dps,dp_req_resp_t * drr,clock_t stop_clockt)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
rmc_comm_wait_enable_to_send(struct rmc_comm_state * rcs,rmc_comm_dp_state_t * dps)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
rmc_comm_wake_up_next(struct rmc_comm_state * rcs)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
rmc_comm_send_pend_req(caddr_t arg)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
rmc_comm_dreq_thread_start(struct rmc_comm_state * rcs)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
rmc_comm_dreq_thread_kill(struct rmc_comm_state * rcs)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
rmc_comm_drvintf_init(struct rmc_comm_state * rcs)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
rmc_comm_drvintf_fini(struct rmc_comm_state * rcs)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