103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
503831d35Sstevel * Common Development and Distribution License (the "License").
603831d35Sstevel * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel
2203831d35Sstevel /*
23*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2403831d35Sstevel * Use is subject to license terms.
2503831d35Sstevel */
2603831d35Sstevel
2703831d35Sstevel /*
2803831d35Sstevel * provide the interface to the layered drivers (send request/receive
2903831d35Sstevel * response to the RMC
3003831d35Sstevel *
3103831d35Sstevel */
3203831d35Sstevel
3303831d35Sstevel /*
3403831d35Sstevel * Header files
3503831d35Sstevel */
3603831d35Sstevel #include <sys/conf.h>
3703831d35Sstevel #include <sys/callb.h>
3803831d35Sstevel #include <sys/cyclic.h>
3903831d35Sstevel #include <sys/membar.h>
4003831d35Sstevel #include <sys/modctl.h>
4103831d35Sstevel #include <sys/strlog.h>
4203831d35Sstevel #include <sys/sunddi.h>
4303831d35Sstevel #include <sys/ddi.h>
4403831d35Sstevel #include <sys/types.h>
4503831d35Sstevel #include <sys/disp.h>
4603831d35Sstevel #include <sys/rmc_comm_dp.h>
4703831d35Sstevel #include <sys/rmc_comm_dp_boot.h>
4803831d35Sstevel #include <sys/rmc_comm_drvintf.h>
4903831d35Sstevel #include <sys/rmc_comm.h>
5003831d35Sstevel
5103831d35Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t);
5203831d35Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t);
5303831d35Sstevel
5403831d35Sstevel static int rmc_comm_send_req_resp(struct rmc_comm_state *rcs,
5503831d35Sstevel rmc_comm_msg_t *request, rmc_comm_msg_t *response, uint32_t wait_time);
5603831d35Sstevel static int rmc_comm_wait_bp_reply(struct rmc_comm_state *,
5703831d35Sstevel rmc_comm_dp_state_t *, dp_req_resp_t *, clock_t);
5803831d35Sstevel static void rmc_comm_wait_enable_to_send(struct rmc_comm_state *,
5903831d35Sstevel rmc_comm_dp_state_t *);
6003831d35Sstevel static void rmc_comm_wake_up_next(struct rmc_comm_state *);
6103831d35Sstevel static void rmc_comm_send_pend_req(caddr_t arg);
6203831d35Sstevel static int rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs);
6303831d35Sstevel static void rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs);
6403831d35Sstevel
6503831d35Sstevel /*
6603831d35Sstevel * leaf driver to use this function to send a request to the remote side (RMC)
6703831d35Sstevel * and wait for a reply
6803831d35Sstevel */
6903831d35Sstevel int
rmc_comm_request_response(rmc_comm_msg_t * request,rmc_comm_msg_t * response,uint32_t wait_time)7003831d35Sstevel rmc_comm_request_response(rmc_comm_msg_t *request,
7103831d35Sstevel rmc_comm_msg_t *response, uint32_t wait_time)
7203831d35Sstevel {
7303831d35Sstevel struct rmc_comm_state *rcs;
7452f4394bSjfrank int err;
7503831d35Sstevel
7603831d35Sstevel /*
7703831d35Sstevel * get the soft state struct (instance 0)
7803831d35Sstevel */
7903831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
8003831d35Sstevel "rmc_comm_request_response")) == NULL)
8103831d35Sstevel return (RCENOSOFTSTATE);
8203831d35Sstevel
8352f4394bSjfrank do {
8452f4394bSjfrank err = rmc_comm_send_req_resp(rcs, request, response, wait_time);
8552f4394bSjfrank } while (err == RCEGENERIC);
8652f4394bSjfrank return (err);
8703831d35Sstevel }
8803831d35Sstevel
8903831d35Sstevel /*
9003831d35Sstevel * leaf driver to use this function to send a request to the remote side (RMC)
9103831d35Sstevel * without waiting for a reply. If flag is RMC_COMM_DREQ_URGENT, the request
9203831d35Sstevel * message is sent once-off (an eventual pending request is aborted). This
9303831d35Sstevel * flag must only be used when try to send a request in critical condition
9403831d35Sstevel * (while the system is shutting down for instance and the CPU signature
9503831d35Sstevel * has to be sent). Otherwise, the request is stored in a temporary location
9603831d35Sstevel * and delivered by a thread.
9703831d35Sstevel */
9803831d35Sstevel int
rmc_comm_request_nowait(rmc_comm_msg_t * request,uint8_t flag)9903831d35Sstevel rmc_comm_request_nowait(rmc_comm_msg_t *request, uint8_t flag)
10003831d35Sstevel {
10103831d35Sstevel struct rmc_comm_state *rcs;
10203831d35Sstevel rmc_comm_dp_state_t *dps;
10303831d35Sstevel rmc_comm_drvintf_state_t *dis;
10403831d35Sstevel dp_message_t req;
10503831d35Sstevel int err = RCNOERR;
10603831d35Sstevel uint8_t flags = 0;
10703831d35Sstevel
10803831d35Sstevel /*
10903831d35Sstevel * get the soft state struct (instance 0)
11003831d35Sstevel */
11103831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
11203831d35Sstevel "rmc_comm_request_response")) == NULL)
11303831d35Sstevel return (RCENOSOFTSTATE);
11403831d35Sstevel
11503831d35Sstevel /*
11603831d35Sstevel * just a sanity check...
11703831d35Sstevel */
11803831d35Sstevel if (request == NULL) {
11903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqnowait, invalid args\n"));
12003831d35Sstevel return (RCEINVARG);
12103831d35Sstevel }
12203831d35Sstevel
12303831d35Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) {
12403831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
12503831d35Sstevel "reqnowait, ctrl msg not allowed! req type=%x\n",
12603831d35Sstevel request->msg_type));
12703831d35Sstevel return (RCEINVARG);
12803831d35Sstevel }
12903831d35Sstevel
13003831d35Sstevel if (flag == RMC_COMM_DREQ_URGENT) {
13103831d35Sstevel /*
13203831d35Sstevel * Send this request with high priority i.e. abort eventual
13303831d35Sstevel * request/response pending sessions.
13403831d35Sstevel */
13503831d35Sstevel
13603831d35Sstevel dps = &rcs->dp_state;
13703831d35Sstevel
13803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "going to send request=%x (URG)\n",
13903831d35Sstevel request->msg_type));
14003831d35Sstevel
1416fa6856eSarutz /*
1426fa6856eSarutz * Handle the case where we are called during panic
1436fa6856eSarutz * processing. If that occurs, then another thread in
1446fa6856eSarutz * rmc_comm might have been idled by panic() while
1456fa6856eSarutz * holding dp_mutex. As a result, do not unconditionally
1466fa6856eSarutz * grab dp_mutex.
1476fa6856eSarutz */
1486fa6856eSarutz if (ddi_in_panic() != 0) {
1496fa6856eSarutz if (mutex_tryenter(dps->dp_mutex) == 0) {
1506fa6856eSarutz return (RCENODATALINK);
1516fa6856eSarutz }
1526fa6856eSarutz } else {
15303831d35Sstevel mutex_enter(dps->dp_mutex);
1546fa6856eSarutz }
15503831d35Sstevel
15603831d35Sstevel /*
15703831d35Sstevel * send the request only if the protocol data link is up.
15803831d35Sstevel * it is pointless to send it in the other case.
15903831d35Sstevel */
16003831d35Sstevel if (dps->data_link_ok) {
16103831d35Sstevel
16203831d35Sstevel /*
16303831d35Sstevel * clean up an eventual pending request/response session
16403831d35Sstevel * (save its current status)
16503831d35Sstevel */
16603831d35Sstevel if (dps->pending_request) {
16703831d35Sstevel flags = dps->req_resp.flags;
16803831d35Sstevel rmc_comm_dp_mcleanup(rcs);
16903831d35Sstevel }
17003831d35Sstevel
17103831d35Sstevel /*
17203831d35Sstevel * send the request message
17303831d35Sstevel */
17403831d35Sstevel req.msg_type = request->msg_type;
17503831d35Sstevel req.msg_buf = (uint8_t *)request->msg_buf;
17603831d35Sstevel req.msg_msglen = (uint16_t)request->msg_len;
17703831d35Sstevel
17803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x (URG)\n",
17903831d35Sstevel request->msg_type));
18003831d35Sstevel
18103831d35Sstevel err = rmc_comm_dp_msend(rcs, &req);
18203831d35Sstevel
18303831d35Sstevel /*
18403831d35Sstevel * wait for fifos to drain
18503831d35Sstevel */
18603831d35Sstevel rmc_comm_serdev_drain(rcs);
18703831d35Sstevel
18803831d35Sstevel /*
18903831d35Sstevel * clean up the current session
19003831d35Sstevel */
19103831d35Sstevel rmc_comm_dp_mcleanup(rcs);
19203831d35Sstevel
19303831d35Sstevel /*
19403831d35Sstevel * abort an old session (if any)
19503831d35Sstevel */
19603831d35Sstevel if (dps->pending_request) {
19703831d35Sstevel dps->req_resp.flags = flags;
19803831d35Sstevel dp_wake_up_waiter(rcs, MSG_ERROR);
19903831d35Sstevel }
20003831d35Sstevel }
20103831d35Sstevel
20203831d35Sstevel mutex_exit(dps->dp_mutex);
20303831d35Sstevel
20403831d35Sstevel } else {
20503831d35Sstevel
20603831d35Sstevel /*
20703831d35Sstevel * Get an 'independent' thread (rmc_comm_send_pend_req)
20803831d35Sstevel * to send this request (since the calling thread does not
20903831d35Sstevel * want to wait). Copy the request in the drvintf state
21003831d35Sstevel * structure and signal the thread.
21103831d35Sstevel */
21203831d35Sstevel
21303831d35Sstevel dis = &rcs->drvi_state;
21403831d35Sstevel
21503831d35Sstevel mutex_enter(dis->dreq_mutex);
21603831d35Sstevel
21703831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) {
21803831d35Sstevel
21903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "get to send request=%x\n",
22003831d35Sstevel request->msg_type));
22103831d35Sstevel
22203831d35Sstevel /*
22303831d35Sstevel * copy the request in a temporary location
22403831d35Sstevel * (drvinf_state structure) and signal the thread
22503831d35Sstevel * that a request message has to be delivered
22603831d35Sstevel */
22703831d35Sstevel
22803831d35Sstevel if (request->msg_len < DP_MAX_MSGLEN) {
22903831d35Sstevel dis->dreq_request.msg_type = request->msg_type;
23003831d35Sstevel dis->dreq_request.msg_len = request->msg_len;
23103831d35Sstevel dis->dreq_request.msg_buf =
23203831d35Sstevel dis->dreq_request_buf;
23303831d35Sstevel bcopy(request->msg_buf,
23403831d35Sstevel dis->dreq_request.msg_buf,
23503831d35Sstevel request->msg_len);
23603831d35Sstevel
23703831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_PROCESS;
23803831d35Sstevel cv_signal(dis->dreq_sig_cv);
23903831d35Sstevel
24003831d35Sstevel } else {
24103831d35Sstevel /*
24203831d35Sstevel * not enough space to hold the request
24303831d35Sstevel */
24403831d35Sstevel err = RCEREPTOOBIG;
24503831d35Sstevel }
24603831d35Sstevel } else {
24703831d35Sstevel
24803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "cannot get to send "
24903831d35Sstevel "request=%x (busy)\n", request->msg_type));
25003831d35Sstevel
25103831d35Sstevel /*
25203831d35Sstevel * only one request per time can be processed.
25303831d35Sstevel * the thread is either busy (RMC_COMM_DREQ_ST_PROCESS)
25403831d35Sstevel * or terminating (RMC_COMM_DREQ_ST_EXIT)
25503831d35Sstevel */
25603831d35Sstevel err = RCEGENERIC;
25703831d35Sstevel }
25803831d35Sstevel
25903831d35Sstevel mutex_exit(dis->dreq_mutex);
26003831d35Sstevel }
26103831d35Sstevel
26203831d35Sstevel return (err);
26303831d35Sstevel }
26403831d35Sstevel
26503831d35Sstevel /*
26603831d35Sstevel * Function used to send a request and (eventually) wait for a response.
26703831d35Sstevel * It can be called from a leaf driver (via rmc_comm_request_response) or
26803831d35Sstevel * from the thread in charge of sending 'no-wait' requests
26903831d35Sstevel * (rmc_comm_send_pend_req).
27003831d35Sstevel */
27103831d35Sstevel 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)27203831d35Sstevel rmc_comm_send_req_resp(struct rmc_comm_state *rcs, rmc_comm_msg_t *request,
27303831d35Sstevel rmc_comm_msg_t *response, uint32_t wait_time)
27403831d35Sstevel {
27503831d35Sstevel rmc_comm_dp_state_t *dps;
27603831d35Sstevel dp_req_resp_t *drr;
27703831d35Sstevel dp_message_t *exp_resp;
27803831d35Sstevel dp_message_t req;
279*d3d50737SRafael Vanoni clock_t resend_clockt, delta;
28003831d35Sstevel clock_t stop_clockt;
28103831d35Sstevel int err;
28203831d35Sstevel
28303831d35Sstevel
28403831d35Sstevel /*
28503831d35Sstevel * just a sanity check...
28603831d35Sstevel */
28703831d35Sstevel if (request == NULL) {
28803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp, invalid args\n"));
28903831d35Sstevel return (RCEINVARG);
29003831d35Sstevel }
29103831d35Sstevel
29203831d35Sstevel /*
29303831d35Sstevel * drivers cannot send control messages at all. They are meant to
29403831d35Sstevel * be used at low level only.
29503831d35Sstevel */
29603831d35Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) {
29703831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
29803831d35Sstevel "reqresp, ctrl msg not allowed! req type=%x\n",
29903831d35Sstevel request->msg_type));
30003831d35Sstevel return (RCEINVARG);
30103831d35Sstevel }
30203831d35Sstevel
30303831d35Sstevel dps = &rcs->dp_state;
30403831d35Sstevel drr = &dps->req_resp;
30503831d35Sstevel exp_resp = &drr->response;
30603831d35Sstevel
3076fa6856eSarutz /*
3086fa6856eSarutz * Handle the case where we are called during panic
3096fa6856eSarutz * processing. If that occurs, then another thread in
3106fa6856eSarutz * rmc_comm might have been idled by panic() while
3116fa6856eSarutz * holding dp_mutex. As a result, do not unconditionally
3126fa6856eSarutz * grab dp_mutex.
3136fa6856eSarutz */
3146fa6856eSarutz if (ddi_in_panic() != 0) {
3156fa6856eSarutz if (mutex_tryenter(dps->dp_mutex) == 0) {
3166fa6856eSarutz return (RCENODATALINK);
3176fa6856eSarutz }
3186fa6856eSarutz } else {
31903831d35Sstevel mutex_enter(dps->dp_mutex);
3206fa6856eSarutz }
32103831d35Sstevel
32203831d35Sstevel /*
32303831d35Sstevel * if the data link set up is suspended, just return.
32403831d35Sstevel * the only time that this can happen is during firmware download
32503831d35Sstevel * (see rmc_comm_request_response_bp). Basically, the data link is
32603831d35Sstevel * down and the timer for setting up the data link is not running.
32703831d35Sstevel */
32803831d35Sstevel if (!dps->data_link_ok &&
32903831d35Sstevel dps->timer_link_setup == (timeout_id_t)0) {
33003831d35Sstevel
33103831d35Sstevel mutex_exit(dps->dp_mutex);
33203831d35Sstevel return (RCENODATALINK);
33303831d35Sstevel }
33403831d35Sstevel
33503831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d, req type=%x\n",
33603831d35Sstevel dps->pending_request, request->msg_type));
33703831d35Sstevel
33803831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
33903831d35Sstevel
34003831d35Sstevel /*
34103831d35Sstevel * We now have control of the RMC.
34203831d35Sstevel * Place a lower limit on the shortest amount of time to be
34303831d35Sstevel * waited before timing out while communicating with the RMC
34403831d35Sstevel */
34503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT)
34603831d35Sstevel wait_time = DP_MIN_TIMEOUT;
34703831d35Sstevel
34803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
34903831d35Sstevel
35003831d35Sstevel /*
35103831d35Sstevel * initialization of the request/response data structure
35203831d35Sstevel */
35303831d35Sstevel drr->flags = 0;
35403831d35Sstevel drr->error_status = 0;
35503831d35Sstevel
35603831d35Sstevel /*
35703831d35Sstevel * set the 'expected reply' buffer: get the buffer already allocated
35803831d35Sstevel * for the response (if a reply is expected!)
35903831d35Sstevel */
36003831d35Sstevel if (response != NULL) {
36103831d35Sstevel exp_resp->msg_type = response->msg_type;
36203831d35Sstevel exp_resp->msg_buf = (uint8_t *)response->msg_buf;
36303831d35Sstevel exp_resp->msg_msglen = (uint16_t)response->msg_bytes;
36403831d35Sstevel exp_resp->msg_bufsiz = (uint16_t)response->msg_len;
36503831d35Sstevel } else {
36603831d35Sstevel exp_resp->msg_type = DP_NULL_MSG;
36703831d35Sstevel exp_resp->msg_buf = (uint8_t)NULL;
36803831d35Sstevel exp_resp->msg_bufsiz = (uint16_t)0;
36903831d35Sstevel exp_resp->msg_msglen = (uint16_t)0;
37003831d35Sstevel }
37103831d35Sstevel
37203831d35Sstevel /*
37303831d35Sstevel * send the request message
37403831d35Sstevel */
37503831d35Sstevel req.msg_type = request->msg_type;
37603831d35Sstevel req.msg_buf = (uint8_t *)request->msg_buf;
37703831d35Sstevel req.msg_msglen = (uint16_t)request->msg_len;
37803831d35Sstevel
37903831d35Sstevel /*
38003831d35Sstevel * send the message and wait for the reply or ACKnowledgment
38103831d35Sstevel * re-send the message if reply/ACK is not received in the
38203831d35Sstevel * timeframe defined
38303831d35Sstevel */
38403831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x\n", request->msg_type));
38503831d35Sstevel
386*d3d50737SRafael Vanoni delta = drv_usectohz(TX_RETRY_TIME * 1000);
387*d3d50737SRafael Vanoni
38803831d35Sstevel while ((err = rmc_comm_dp_msend(rcs, &req)) == RCNOERR) {
38903831d35Sstevel
390*d3d50737SRafael Vanoni resend_clockt = ddi_get_lbolt() + delta;
39103831d35Sstevel
39203831d35Sstevel /*
39303831d35Sstevel * wait for a reply or an acknowledgement
39403831d35Sstevel */
395*d3d50737SRafael Vanoni (void) cv_reltimedwait(drr->cv_wait_reply, dps->dp_mutex,
396*d3d50737SRafael Vanoni delta, TR_CLOCK_TICK);
39703831d35Sstevel
39803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
39903831d35Sstevel "reqresp send status: flags=%02x req=%x resp=%x tick=%ld\n",
40003831d35Sstevel drr->flags, request->msg_type,
40103831d35Sstevel response ? response->msg_type : -1,
40203831d35Sstevel stop_clockt - resend_clockt));
40303831d35Sstevel
40403831d35Sstevel /*
40503831d35Sstevel * Check for error condition first
40603831d35Sstevel * Then, check if the command has been replied/ACKed
40703831d35Sstevel * Then, check if it has timeout and if there is any
40803831d35Sstevel * time left to resend the message.
40903831d35Sstevel */
41003831d35Sstevel if ((drr->flags & MSG_ERROR) != 0) {
41103831d35Sstevel if (drr->error_status == 0) {
41203831d35Sstevel err = RCEGENERIC;
41303831d35Sstevel } else {
41403831d35Sstevel err = drr->error_status;
41503831d35Sstevel }
41603831d35Sstevel break;
41703831d35Sstevel
41803831d35Sstevel } else if (response != NULL &&
41903831d35Sstevel (drr->flags & MSG_REPLY_RXED) != 0) {
42003831d35Sstevel /*
42103831d35Sstevel * yes! here is the reply
42203831d35Sstevel */
42303831d35Sstevel
42403831d35Sstevel /*
42503831d35Sstevel * get the actual length of the msg
42603831d35Sstevel * a negative value means that the reply message
42703831d35Sstevel * was too big for the receiver buffer
42803831d35Sstevel */
42903831d35Sstevel response->msg_bytes = exp_resp->msg_msglen;
43003831d35Sstevel if (response->msg_bytes < 0)
43103831d35Sstevel err = RCEREPTOOBIG;
43203831d35Sstevel else
43303831d35Sstevel err = RCNOERR;
43403831d35Sstevel break;
43503831d35Sstevel
43603831d35Sstevel } else if (response == NULL && (drr->flags & MSG_ACKED) != 0) {
43703831d35Sstevel /*
43803831d35Sstevel * yes! message has been acknowledged
43903831d35Sstevel */
44003831d35Sstevel
44103831d35Sstevel err = RCNOERR;
44203831d35Sstevel break;
44303831d35Sstevel
44403831d35Sstevel } else if ((stop_clockt - resend_clockt) <= 0) {
44503831d35Sstevel /*
44603831d35Sstevel * no more time left. set the error code,
44703831d35Sstevel * exit the loop
44803831d35Sstevel */
44903831d35Sstevel
45003831d35Sstevel err = RCETIMEOUT;
45103831d35Sstevel break;
45203831d35Sstevel }
45303831d35Sstevel }
45403831d35Sstevel
45503831d35Sstevel rmc_comm_dp_mcleanup(rcs);
45603831d35Sstevel
45703831d35Sstevel rmc_comm_wake_up_next(rcs);
45803831d35Sstevel
45903831d35Sstevel mutex_exit(dps->dp_mutex);
46003831d35Sstevel
46103831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp end: err=%d, request=%x\n",
46203831d35Sstevel err, request->msg_type));
46303831d35Sstevel
46403831d35Sstevel return (err);
46503831d35Sstevel }
46603831d35Sstevel
46703831d35Sstevel /*
46803831d35Sstevel * Function used to send a BP (Boot Prom) message and get the reply.
46903831d35Sstevel * BP protocol is provided only to support firmware download.
47003831d35Sstevel *
47103831d35Sstevel * This function will look for the following key BP protocol commands:
47203831d35Sstevel * BP_OBP_BOOTINIT: the data link is brought down so that request/response
47303831d35Sstevel * sessions cannot be started. The reason why is that this command will cause
47403831d35Sstevel * RMC fw to jump to the boot monitor (BOOTMON_FLASH) and data protocol is not
47503831d35Sstevel * operational. In this context, RMC fw will only be using the BP protocol.
47603831d35Sstevel * BP_OBP_RESET: data link setup timer is resumed. This command cause the RMC
47703831d35Sstevel * to reboot and hence become operational.
47803831d35Sstevel */
47903831d35Sstevel int
rmc_comm_request_response_bp(rmc_comm_msg_t * request_bp,rmc_comm_msg_t * response_bp,uint32_t wait_time)48003831d35Sstevel rmc_comm_request_response_bp(rmc_comm_msg_t *request_bp,
48103831d35Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time)
48203831d35Sstevel {
48303831d35Sstevel struct rmc_comm_state *rcs;
48403831d35Sstevel rmc_comm_dp_state_t *dps;
48503831d35Sstevel dp_req_resp_t *drr;
48603831d35Sstevel dp_message_t *resp_bp;
48703831d35Sstevel bp_msg_t *bp_msg;
48803831d35Sstevel clock_t stop_clockt;
48903831d35Sstevel int err = RCNOERR;
49003831d35Sstevel boolean_t bootinit_sent = 0;
49103831d35Sstevel
49203831d35Sstevel /*
49303831d35Sstevel * get the soft state struct (instance 0)
49403831d35Sstevel */
49503831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
49603831d35Sstevel "rmc_comm_request_response_bp")) == NULL)
49703831d35Sstevel return (RCENOSOFTSTATE);
49803831d35Sstevel
49903831d35Sstevel /*
50003831d35Sstevel * sanity check: request_bp buffer must always be provided
50103831d35Sstevel */
50203831d35Sstevel if (request_bp == NULL) {
50303831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp_bp, invalid args\n"));
50403831d35Sstevel return (RCEINVARG);
50503831d35Sstevel }
50603831d35Sstevel
50703831d35Sstevel bp_msg = (bp_msg_t *)request_bp->msg_buf;
50803831d35Sstevel
50903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request_bp=%x\n", bp_msg->cmd));
51003831d35Sstevel
51103831d35Sstevel /*
51203831d35Sstevel * only BP message can be sent
51303831d35Sstevel */
51403831d35Sstevel if (!IS_BOOT_MSG(bp_msg->cmd)) {
51503831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
51603831d35Sstevel "reqresp_bp, only BP msg are allowed! type=%x\n",
51703831d35Sstevel bp_msg->cmd));
51803831d35Sstevel return (RCEINVARG);
51903831d35Sstevel }
52003831d35Sstevel
52103831d35Sstevel dps = &rcs->dp_state;
52203831d35Sstevel drr = &dps->req_resp;
52303831d35Sstevel resp_bp = &drr->response;
52403831d35Sstevel
52503831d35Sstevel mutex_enter(dps->dp_mutex);
52603831d35Sstevel
52703831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
52803831d35Sstevel
52903831d35Sstevel /*
53003831d35Sstevel * Now, before sending the message, just check what it is being sent
53103831d35Sstevel * and take action accordingly.
53203831d35Sstevel *
53303831d35Sstevel * is it BP_OBP_BOOTINIT or BP_OBP_RESET command?
53403831d35Sstevel */
53503831d35Sstevel if (bp_msg->cmd == BP_OBP_BOOTINIT) {
53603831d35Sstevel
53703831d35Sstevel /*
53803831d35Sstevel * bring down the protocol data link
53903831d35Sstevel * (must be done before aborting a request/response session)
54003831d35Sstevel */
54103831d35Sstevel dps->data_link_ok = 0;
54203831d35Sstevel dps->timer_link_setup = (timeout_id_t)0;
54303831d35Sstevel
54403831d35Sstevel bootinit_sent = 1;
54503831d35Sstevel
54603831d35Sstevel } else if (bp_msg->cmd == BP_OBP_RESET) {
54703831d35Sstevel
54803831d35Sstevel /*
54903831d35Sstevel * restart the data link set up timer. RMC is coming up...
55003831d35Sstevel */
55103831d35Sstevel
55203831d35Sstevel dp_reset(rcs, INITIAL_SEQID, 0, 1);
55303831d35Sstevel }
55403831d35Sstevel
55503831d35Sstevel /*
55603831d35Sstevel * initialization of the request/response data structure
55703831d35Sstevel */
55803831d35Sstevel drr->flags = 0;
55903831d35Sstevel drr->error_status = 0;
56003831d35Sstevel
56103831d35Sstevel /*
56203831d35Sstevel * set the reply buffer: get the buffer already allocated
56303831d35Sstevel * for the response
56403831d35Sstevel */
56503831d35Sstevel if (response_bp != NULL) {
56603831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "expect BP reply. len=%d\n",
56703831d35Sstevel response_bp->msg_len));
56803831d35Sstevel
56903831d35Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf;
57003831d35Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len;
57103831d35Sstevel }
57203831d35Sstevel
57303831d35Sstevel /*
57403831d35Sstevel * send the BP message and wait for the reply
57503831d35Sstevel */
57603831d35Sstevel
57703831d35Sstevel rmc_comm_bp_msend(rcs, bp_msg);
57803831d35Sstevel
57903831d35Sstevel if (response_bp != NULL) {
58003831d35Sstevel
58103831d35Sstevel /*
58203831d35Sstevel * place a lower limit on the shortest amount of time to be
58303831d35Sstevel * waited before timing out while communicating with the RMC
58403831d35Sstevel */
58503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT)
58603831d35Sstevel wait_time = DP_MIN_TIMEOUT;
58703831d35Sstevel
58803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
58903831d35Sstevel
59003831d35Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr,
59103831d35Sstevel stop_clockt)) == RCNOERR) {
59203831d35Sstevel
59303831d35Sstevel /*
59403831d35Sstevel * get the actual length of the msg
59503831d35Sstevel * a negative value means that the reply message
59603831d35Sstevel * was too big for the receiver buffer
59703831d35Sstevel */
59803831d35Sstevel response_bp->msg_bytes = resp_bp->msg_msglen;
59903831d35Sstevel if (response_bp->msg_bytes < 0) {
60003831d35Sstevel err = RCEREPTOOBIG;
60103831d35Sstevel
60203831d35Sstevel } else if (bootinit_sent) {
60303831d35Sstevel
60403831d35Sstevel /*
60503831d35Sstevel * BOOTINIT cmd may fail. In this is the case,
60603831d35Sstevel * the RMC is still operational. Hence, we
60703831d35Sstevel * try (once) to set up the data link
60803831d35Sstevel * protocol.
60903831d35Sstevel */
61003831d35Sstevel bp_msg = (bp_msg_t *)response_bp->msg_buf;
61103831d35Sstevel
61203831d35Sstevel if (bp_msg->cmd == BP_RSC_BOOTFAIL &&
61303831d35Sstevel bp_msg->dat1 == BP_DAT1_REJECTED) {
61403831d35Sstevel (void) rmc_comm_dp_ctlsend(rcs,
61503831d35Sstevel DP_CTL_START);
61603831d35Sstevel }
61703831d35Sstevel }
61803831d35Sstevel }
61903831d35Sstevel }
62003831d35Sstevel
62103831d35Sstevel rmc_comm_dp_mcleanup(rcs);
62203831d35Sstevel
62303831d35Sstevel rmc_comm_wake_up_next(rcs);
62403831d35Sstevel
62503831d35Sstevel mutex_exit(dps->dp_mutex);
62603831d35Sstevel
62703831d35Sstevel return (err);
62803831d35Sstevel }
62903831d35Sstevel
63003831d35Sstevel
63103831d35Sstevel /*
63203831d35Sstevel * to register for an asynchronous (via soft interrupt) notification
63303831d35Sstevel * of a message from the remote side (RMC)
63403831d35Sstevel */
63503831d35Sstevel 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)63603831d35Sstevel rmc_comm_reg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler,
63703831d35Sstevel rmc_comm_msg_t *msgbuf, uint_t *state, kmutex_t *lock)
63803831d35Sstevel {
63903831d35Sstevel struct rmc_comm_state *rcs;
64003831d35Sstevel dp_msg_intr_t *msgintr;
64103831d35Sstevel int err = RCNOERR;
64203831d35Sstevel
64303831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_reg_intr")) == NULL)
64403831d35Sstevel return (RCENOSOFTSTATE);
64503831d35Sstevel
64603831d35Sstevel mutex_enter(rcs->dp_state.dp_mutex);
64703831d35Sstevel
64803831d35Sstevel msgintr = &rcs->dp_state.msg_intr;
64903831d35Sstevel
65003831d35Sstevel /*
65103831d35Sstevel * lock is required. If it is not defined, the
65203831d35Sstevel * interrupt handler routine cannot be registered.
65303831d35Sstevel */
65403831d35Sstevel if (lock == NULL) {
65503831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex);
65603831d35Sstevel return (RCEINVARG);
65703831d35Sstevel }
65803831d35Sstevel
65903831d35Sstevel /*
66003831d35Sstevel * only one interrupt handler can be registered.
66103831d35Sstevel */
66203831d35Sstevel if (msgintr->intr_handler == NULL) {
66303831d35Sstevel
66403831d35Sstevel if (ddi_add_softintr(rcs->dip, DDI_SOFTINT_HIGH,
66503831d35Sstevel &msgintr->intr_id, NULL, NULL, intr_handler,
66603831d35Sstevel (caddr_t)msgbuf) == DDI_SUCCESS) {
66703831d35Sstevel
66803831d35Sstevel msgintr->intr_handler = intr_handler;
66903831d35Sstevel msgintr->intr_lock = lock;
67003831d35Sstevel msgintr->intr_state = state;
67103831d35Sstevel msgintr->intr_msg_type = msg_type;
67203831d35Sstevel msgintr->intr_arg = (caddr_t)msgbuf;
67303831d35Sstevel } else {
67403831d35Sstevel err = RCECANTREGINTR;
67503831d35Sstevel }
67603831d35Sstevel } else {
67703831d35Sstevel err = RCEALREADYREG;
67803831d35Sstevel }
67903831d35Sstevel
68003831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex);
68103831d35Sstevel
68203831d35Sstevel return (err);
68303831d35Sstevel }
68403831d35Sstevel
68503831d35Sstevel /*
68603831d35Sstevel * To unregister for asynchronous notifications
68703831d35Sstevel */
68803831d35Sstevel int
rmc_comm_unreg_intr(uint8_t msg_type,rmc_comm_intrfunc_t intr_handler)68903831d35Sstevel rmc_comm_unreg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler)
69003831d35Sstevel {
69103831d35Sstevel struct rmc_comm_state *rcs;
69203831d35Sstevel dp_msg_intr_t *msgintr;
69303831d35Sstevel int err = RCNOERR;
69403831d35Sstevel
69503831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_unreg_intr")) == NULL)
69603831d35Sstevel return (RCENOSOFTSTATE);
69703831d35Sstevel
69803831d35Sstevel mutex_enter(rcs->dp_state.dp_mutex);
69903831d35Sstevel
70003831d35Sstevel msgintr = &rcs->dp_state.msg_intr;
70103831d35Sstevel
70203831d35Sstevel if (msgintr->intr_handler != NULL &&
70303831d35Sstevel msgintr->intr_msg_type == msg_type &&
70403831d35Sstevel msgintr->intr_handler == intr_handler) {
70503831d35Sstevel
70603831d35Sstevel ddi_remove_softintr(msgintr->intr_id);
70703831d35Sstevel msgintr->intr_handler = NULL;
70803831d35Sstevel msgintr->intr_id = 0;
70903831d35Sstevel msgintr->intr_msg_type = 0;
71003831d35Sstevel msgintr->intr_arg = NULL;
71103831d35Sstevel msgintr->intr_lock = NULL;
71203831d35Sstevel msgintr->intr_state = NULL;
71303831d35Sstevel } else {
71403831d35Sstevel err = RCEGENERIC;
71503831d35Sstevel }
71603831d35Sstevel
71703831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex);
71803831d35Sstevel
71903831d35Sstevel return (err);
72003831d35Sstevel }
72103831d35Sstevel
72203831d35Sstevel /*
72303831d35Sstevel * To send raw data (firmware s-records) down to the RMC.
72403831d35Sstevel * It is provided only to support firmware download.
72503831d35Sstevel */
72603831d35Sstevel int
rmc_comm_send_srecord_bp(caddr_t buf,int buflen,rmc_comm_msg_t * response_bp,uint32_t wait_time)72703831d35Sstevel rmc_comm_send_srecord_bp(caddr_t buf, int buflen,
72803831d35Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time)
72903831d35Sstevel {
73003831d35Sstevel struct rmc_comm_state *rcs;
73103831d35Sstevel rmc_comm_dp_state_t *dps;
73203831d35Sstevel dp_req_resp_t *drr;
73303831d35Sstevel dp_message_t *resp_bp;
73403831d35Sstevel clock_t stop_clockt;
73503831d35Sstevel int err;
73603831d35Sstevel
73703831d35Sstevel /*
73803831d35Sstevel * get the soft state struct (instance 0)
73903831d35Sstevel */
74003831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
74103831d35Sstevel "rmc_comm_request_response_bp")) == NULL)
74203831d35Sstevel return (RCENOSOFTSTATE);
74303831d35Sstevel
74403831d35Sstevel /*
74503831d35Sstevel * sanity check: response_bp buffer must always be provided
74603831d35Sstevel */
74703831d35Sstevel if (buf == NULL || response_bp == NULL) {
74803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp,invalid args\n"));
74903831d35Sstevel return (RCEINVARG);
75003831d35Sstevel }
75103831d35Sstevel
75203831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp, buflen=%d\n", buflen));
75303831d35Sstevel
75403831d35Sstevel dps = &rcs->dp_state;
75503831d35Sstevel drr = &dps->req_resp;
75603831d35Sstevel resp_bp = &drr->response;
75703831d35Sstevel
75803831d35Sstevel mutex_enter(dps->dp_mutex);
75903831d35Sstevel
76003831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
76103831d35Sstevel
76203831d35Sstevel /*
76303831d35Sstevel * initialization of the request/response data structure
76403831d35Sstevel */
76503831d35Sstevel drr->flags = 0;
76603831d35Sstevel drr->error_status = 0;
76703831d35Sstevel
76803831d35Sstevel /*
76903831d35Sstevel * set the reply buffer: get the buffer already allocated
77003831d35Sstevel * for the response
77103831d35Sstevel */
77203831d35Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf;
77303831d35Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len;
77403831d35Sstevel
77503831d35Sstevel /*
77603831d35Sstevel * send raw data (s-record) and wait for the reply (BP message)
77703831d35Sstevel */
77803831d35Sstevel
77903831d35Sstevel rmc_comm_bp_srecsend(rcs, (char *)buf, buflen);
78003831d35Sstevel
78103831d35Sstevel /*
78203831d35Sstevel * place a lower limit on the shortest amount of time to be
78303831d35Sstevel * waited before timing out while communicating with the RMC
78403831d35Sstevel */
78503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT)
78603831d35Sstevel wait_time = DP_MIN_TIMEOUT;
78703831d35Sstevel
78803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
78903831d35Sstevel
79003831d35Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr,
79103831d35Sstevel stop_clockt)) == RCNOERR) {
79203831d35Sstevel /*
79303831d35Sstevel * get the actual length of the msg
79403831d35Sstevel * a negative value means that the reply message
79503831d35Sstevel * was too big for the receiver buffer
79603831d35Sstevel */
79703831d35Sstevel response_bp->msg_bytes = resp_bp->msg_msglen;
79803831d35Sstevel if (response_bp->msg_bytes < 0) {
79903831d35Sstevel err = RCEREPTOOBIG;
80003831d35Sstevel }
80103831d35Sstevel }
80203831d35Sstevel
80303831d35Sstevel rmc_comm_dp_mcleanup(rcs);
80403831d35Sstevel
80503831d35Sstevel rmc_comm_wake_up_next(rcs);
80603831d35Sstevel
80703831d35Sstevel mutex_exit(dps->dp_mutex);
80803831d35Sstevel
80903831d35Sstevel return (err);
81003831d35Sstevel }
81103831d35Sstevel
81203831d35Sstevel /*
81303831d35Sstevel * To wait for (any) BP message to be received.
81403831d35Sstevel * (dp_mutex must be held)
81503831d35Sstevel */
81603831d35Sstevel 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)81703831d35Sstevel rmc_comm_wait_bp_reply(struct rmc_comm_state *rcs, rmc_comm_dp_state_t *dps,
81803831d35Sstevel dp_req_resp_t *drr, clock_t stop_clockt)
81903831d35Sstevel {
82003831d35Sstevel clock_t clockleft = 1;
82103831d35Sstevel int err = RCNOERR;
82203831d35Sstevel
82303831d35Sstevel clockleft = cv_timedwait(drr->cv_wait_reply, dps->dp_mutex,
82403831d35Sstevel stop_clockt);
82503831d35Sstevel
82603831d35Sstevel
82703831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
82803831d35Sstevel "reqresp_bp, send: flags=%02x, clktick left=%ld\n",
82903831d35Sstevel drr->flags, clockleft));
83003831d35Sstevel
83103831d35Sstevel /*
83203831d35Sstevel * Check for error condition first.
83303831d35Sstevel * Then, check if it has timeout.
83403831d35Sstevel * Then, check if the command has been replied.
83503831d35Sstevel */
83603831d35Sstevel if ((drr->flags & MSG_ERROR) != 0) {
83703831d35Sstevel
83803831d35Sstevel err = RCEGENERIC;
83903831d35Sstevel
84003831d35Sstevel } else if (clockleft <= 0) {
84103831d35Sstevel /*
84203831d35Sstevel * timeout
84303831d35Sstevel */
84403831d35Sstevel
84503831d35Sstevel err = RCETIMEOUT;
84603831d35Sstevel
84703831d35Sstevel } else if ((drr->flags & MSG_RXED_BP) == 0) {
84803831d35Sstevel
84903831d35Sstevel err = RCEGENERIC;
85003831d35Sstevel }
85103831d35Sstevel
85203831d35Sstevel return (err);
85303831d35Sstevel }
85403831d35Sstevel
85503831d35Sstevel /*
85603831d35Sstevel * Wait for the pending_request flag to be cleared and acquire it for our
85703831d35Sstevel * own use. The caller is then allowed to start a new request/response
85803831d35Sstevel * session with the RMC.
85903831d35Sstevel * Note that all send-receive actions to the RMC include a time-out, so
86003831d35Sstevel * the pending-request must eventually go away - even if the RMC is down.
86103831d35Sstevel * Hence there is no need to timeout the wait action of this function.
86203831d35Sstevel * (dp_mutex must be held on entry).
86303831d35Sstevel */
86403831d35Sstevel static void
rmc_comm_wait_enable_to_send(struct rmc_comm_state * rcs,rmc_comm_dp_state_t * dps)86503831d35Sstevel rmc_comm_wait_enable_to_send(struct rmc_comm_state *rcs,
86603831d35Sstevel rmc_comm_dp_state_t *dps)
86703831d35Sstevel {
86803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d\n",
86903831d35Sstevel dps->pending_request));
87003831d35Sstevel
87103831d35Sstevel /*
87203831d35Sstevel * A new message can actually grab the lock before the thread
87303831d35Sstevel * that has just been signaled. Therefore, we need to double
87403831d35Sstevel * check to make sure that pending_request is not already set
87503831d35Sstevel * after we wake up.
87603831d35Sstevel *
87703831d35Sstevel * Potentially this could mean starvation for certain unfortunate
87803831d35Sstevel * threads that keep getting woken up and putting back to sleep.
87903831d35Sstevel * But the window of such contention is very small to begin with.
88003831d35Sstevel */
88103831d35Sstevel
88203831d35Sstevel while (dps->pending_request) {
88303831d35Sstevel /*
88403831d35Sstevel * just 'sit and wait' until there are no pending requests
88503831d35Sstevel */
88603831d35Sstevel
88703831d35Sstevel cv_wait(dps->cv_ok_to_send, dps->dp_mutex);
88803831d35Sstevel }
88903831d35Sstevel
89003831d35Sstevel /*
89103831d35Sstevel * now a request/response can be started. Set the flag so that nobody
89203831d35Sstevel * else will be able to send anything.
89303831d35Sstevel */
89403831d35Sstevel dps->pending_request = 1;
89503831d35Sstevel }
89603831d35Sstevel
89703831d35Sstevel /*
89803831d35Sstevel * To wake up one of the threads (if any) waiting for starting a
89903831d35Sstevel * request/response session.
90003831d35Sstevel * (dp_mutex must be held)
90103831d35Sstevel */
90203831d35Sstevel static void
rmc_comm_wake_up_next(struct rmc_comm_state * rcs)90303831d35Sstevel rmc_comm_wake_up_next(struct rmc_comm_state *rcs)
90403831d35Sstevel {
90503831d35Sstevel /*
90603831d35Sstevel * wake up eventual waiting threads...
90703831d35Sstevel */
90803831d35Sstevel
90903831d35Sstevel rcs->dp_state.pending_request = 0;
91003831d35Sstevel cv_signal(rcs->dp_state.cv_ok_to_send);
91103831d35Sstevel }
91203831d35Sstevel
91303831d35Sstevel
91403831d35Sstevel /*
91503831d35Sstevel * thread which delivers pending request message to the rmc. Some leaf drivers
91603831d35Sstevel * cannot afford to wait for a request to be replied/ACKed. Hence, a request
91703831d35Sstevel * message is stored temporarily in the state structure and this thread
91803831d35Sstevel * gets woken up to deliver it.
91903831d35Sstevel */
92003831d35Sstevel static void
rmc_comm_send_pend_req(caddr_t arg)92103831d35Sstevel rmc_comm_send_pend_req(caddr_t arg)
92203831d35Sstevel {
92303831d35Sstevel struct rmc_comm_state *rcs;
92403831d35Sstevel rmc_comm_drvintf_state_t *dis;
92503831d35Sstevel callb_cpr_t cprinfo;
92603831d35Sstevel
92703831d35Sstevel if (arg == NULL) {
92803831d35Sstevel thread_exit();
92903831d35Sstevel /* NOTREACHED */
93003831d35Sstevel }
93103831d35Sstevel
93203831d35Sstevel rcs = (struct rmc_comm_state *)arg;
93303831d35Sstevel dis = &rcs->drvi_state;
93403831d35Sstevel
93503831d35Sstevel CALLB_CPR_INIT(&cprinfo, dis->dreq_mutex, callb_generic_cpr,
93603831d35Sstevel "rmc_comm_send_pend_req");
93703831d35Sstevel
93803831d35Sstevel mutex_enter(dis->dreq_mutex);
93903831d35Sstevel
94003831d35Sstevel if (dis->dreq_state <= RMC_COMM_DREQ_ST_READY)
94103831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT;
94203831d35Sstevel
94303831d35Sstevel for (;;) {
94403831d35Sstevel
94503831d35Sstevel /*
94603831d35Sstevel * Wait for someone to tell me to continue.
94703831d35Sstevel */
94803831d35Sstevel while (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) {
94903831d35Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
95003831d35Sstevel cv_wait(dis->dreq_sig_cv, dis->dreq_mutex);
95103831d35Sstevel CALLB_CPR_SAFE_END(&cprinfo, dis->dreq_mutex);
95203831d35Sstevel }
95303831d35Sstevel
95403831d35Sstevel /* RMC_COMM_DREQ_ST_EXIT implies signal by _detach(). */
95503831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_EXIT) {
95603831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED;
95703831d35Sstevel dis->dreq_tid = 0;
95803831d35Sstevel
95903831d35Sstevel /* dis->dreq_mutex is held at this point! */
96003831d35Sstevel CALLB_CPR_EXIT(&cprinfo);
96103831d35Sstevel
96203831d35Sstevel thread_exit();
96303831d35Sstevel /* NOTREACHED */
96403831d35Sstevel }
96503831d35Sstevel
96603831d35Sstevel ASSERT(dis->dreq_state == RMC_COMM_DREQ_ST_PROCESS);
96703831d35Sstevel mutex_exit(dis->dreq_mutex);
96803831d35Sstevel
96903831d35Sstevel /*
97003831d35Sstevel * deliver the request (and wait...)
97103831d35Sstevel */
97252f4394bSjfrank while (rmc_comm_send_req_resp(rcs, &dis->dreq_request, NULL,
97352f4394bSjfrank RMC_COMM_DREQ_DEFAULT_TIME) == RCEGENERIC) {
97452f4394bSjfrank }
97503831d35Sstevel
97603831d35Sstevel mutex_enter(dis->dreq_mutex);
97703831d35Sstevel if (dis->dreq_state != RMC_COMM_DREQ_ST_EXIT)
97803831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT;
97903831d35Sstevel }
98003831d35Sstevel }
98103831d35Sstevel
98203831d35Sstevel /*
98303831d35Sstevel * start thread to deal with pending requests to be delivered asynchronously
98403831d35Sstevel * (i.e. leaf driver do not have to/cannot wait for a reply/ACk of a request)
98503831d35Sstevel */
98603831d35Sstevel static int
rmc_comm_dreq_thread_start(struct rmc_comm_state * rcs)98703831d35Sstevel rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs)
98803831d35Sstevel {
98903831d35Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state;
99003831d35Sstevel int err = 0;
99103831d35Sstevel kthread_t *tp;
99203831d35Sstevel
99303831d35Sstevel mutex_enter(dis->dreq_mutex);
99403831d35Sstevel
99503831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_NOTSTARTED) {
99603831d35Sstevel
99703831d35Sstevel tp = thread_create(NULL, 0, rmc_comm_send_pend_req,
99803831d35Sstevel (caddr_t)rcs, 0, &p0, TS_RUN, maxclsyspri);
99903831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_READY;
100003831d35Sstevel dis->dreq_tid = tp->t_did;
100103831d35Sstevel }
100203831d35Sstevel
100303831d35Sstevel mutex_exit(dis->dreq_mutex);
100403831d35Sstevel
100503831d35Sstevel return (err);
100603831d35Sstevel }
100703831d35Sstevel
100803831d35Sstevel /*
100903831d35Sstevel * stop the thread (to deliver pending request messages)
101003831d35Sstevel */
101103831d35Sstevel static void
rmc_comm_dreq_thread_kill(struct rmc_comm_state * rcs)101203831d35Sstevel rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs)
101303831d35Sstevel {
101403831d35Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state;
101503831d35Sstevel kt_did_t tid;
101603831d35Sstevel
101703831d35Sstevel mutex_enter(dis->dreq_mutex);
101803831d35Sstevel tid = dis->dreq_tid;
101903831d35Sstevel if (tid != 0) {
102003831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_EXIT;
102103831d35Sstevel dis->dreq_tid = 0;
102203831d35Sstevel cv_signal(dis->dreq_sig_cv);
102303831d35Sstevel }
102403831d35Sstevel mutex_exit(dis->dreq_mutex);
102503831d35Sstevel
102603831d35Sstevel /*
102703831d35Sstevel * Wait for rmc_comm_send_pend_req() to finish
102803831d35Sstevel */
102903831d35Sstevel if (tid != 0)
103003831d35Sstevel thread_join(tid);
103103831d35Sstevel }
103203831d35Sstevel
103303831d35Sstevel /*
103403831d35Sstevel * init function - start thread to deal with pending requests (no-wait requests)
103503831d35Sstevel */
103603831d35Sstevel int
rmc_comm_drvintf_init(struct rmc_comm_state * rcs)103703831d35Sstevel rmc_comm_drvintf_init(struct rmc_comm_state *rcs)
103803831d35Sstevel {
103903831d35Sstevel int err = 0;
104003831d35Sstevel
104103831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_init\n"));
104203831d35Sstevel rcs->drvi_state.dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED;
104303831d35Sstevel rcs->drvi_state.dreq_tid = 0;
104403831d35Sstevel
104503831d35Sstevel mutex_init(rcs->drvi_state.dreq_mutex, NULL, MUTEX_DRIVER, NULL);
104603831d35Sstevel cv_init(rcs->drvi_state.dreq_sig_cv, NULL, CV_DRIVER, NULL);
104703831d35Sstevel
104803831d35Sstevel err = rmc_comm_dreq_thread_start(rcs);
104903831d35Sstevel if (err != 0) {
105003831d35Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv);
105103831d35Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex);
105203831d35Sstevel }
105303831d35Sstevel
105403831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "thread started? err=%d\n", err));
105503831d35Sstevel
105603831d35Sstevel return (err);
105703831d35Sstevel }
105803831d35Sstevel
105903831d35Sstevel /*
106003831d35Sstevel * fini function - kill thread to deal with pending requests (no-wait requests)
106103831d35Sstevel */
106203831d35Sstevel void
rmc_comm_drvintf_fini(struct rmc_comm_state * rcs)106303831d35Sstevel rmc_comm_drvintf_fini(struct rmc_comm_state *rcs)
106403831d35Sstevel {
106503831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:stop thread\n"));
106603831d35Sstevel
106703831d35Sstevel rmc_comm_dreq_thread_kill(rcs);
106803831d35Sstevel
106903831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:destroy Mx/CVs\n"));
107003831d35Sstevel
107103831d35Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv);
107203831d35Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex);
107303831d35Sstevel }
1074