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