11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel /*
281708Sstevel * provide the interface to the layered drivers (send request/receive
291708Sstevel * response to the RMC
301708Sstevel *
311708Sstevel */
321708Sstevel
331708Sstevel /*
341708Sstevel * Header files
351708Sstevel */
361708Sstevel #include <sys/conf.h>
371708Sstevel #include <sys/callb.h>
381708Sstevel #include <sys/cyclic.h>
391708Sstevel #include <sys/membar.h>
401708Sstevel #include <sys/modctl.h>
411708Sstevel #include <sys/strlog.h>
421708Sstevel #include <sys/sunddi.h>
431708Sstevel #include <sys/ddi.h>
441708Sstevel #include <sys/types.h>
451708Sstevel #include <sys/disp.h>
461708Sstevel #include <sys/rmc_comm_dp.h>
471708Sstevel #include <sys/rmc_comm_dp_boot.h>
481708Sstevel #include <sys/rmc_comm_drvintf.h>
491708Sstevel #include <sys/rmc_comm.h>
501708Sstevel
511708Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t);
521708Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t);
531708Sstevel
541708Sstevel static int rmc_comm_send_req_resp(struct rmc_comm_state *rcs,
551708Sstevel rmc_comm_msg_t *request, rmc_comm_msg_t *response, uint32_t wait_time);
561708Sstevel static int rmc_comm_wait_bp_reply(struct rmc_comm_state *,
571708Sstevel rmc_comm_dp_state_t *, dp_req_resp_t *, clock_t);
581708Sstevel static void rmc_comm_wait_enable_to_send(struct rmc_comm_state *,
591708Sstevel rmc_comm_dp_state_t *);
601708Sstevel static void rmc_comm_wake_up_next(struct rmc_comm_state *);
611708Sstevel static void rmc_comm_send_pend_req(caddr_t arg);
621708Sstevel static int rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs);
631708Sstevel static void rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs);
641708Sstevel
651708Sstevel /*
661708Sstevel * leaf driver to use this function to send a request to the remote side (RMC)
671708Sstevel * and wait for a reply
681708Sstevel */
691708Sstevel int
rmc_comm_request_response(rmc_comm_msg_t * request,rmc_comm_msg_t * response,uint32_t wait_time)701708Sstevel rmc_comm_request_response(rmc_comm_msg_t *request,
711708Sstevel rmc_comm_msg_t *response, uint32_t wait_time)
721708Sstevel {
731708Sstevel struct rmc_comm_state *rcs;
743482Sjfrank int err;
751708Sstevel
761708Sstevel /*
771708Sstevel * get the soft state struct (instance 0)
781708Sstevel */
791708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
80*11066Srafael.vanoni@sun.com "rmc_comm_request_response")) == NULL)
811708Sstevel return (RCENOSOFTSTATE);
821708Sstevel
833482Sjfrank do {
843482Sjfrank err = rmc_comm_send_req_resp(rcs, request, response, wait_time);
853482Sjfrank } while (err == RCEGENERIC);
863482Sjfrank return (err);
871708Sstevel }
881708Sstevel
891708Sstevel /*
901708Sstevel * leaf driver to use this function to send a request to the remote side (RMC)
911708Sstevel * without waiting for a reply. If flag is RMC_COMM_DREQ_URGENT, the request
921708Sstevel * message is sent once-off (an eventual pending request is aborted). This
931708Sstevel * flag must only be used when try to send a request in critical condition
941708Sstevel * (while the system is shutting down for instance and the CPU signature
951708Sstevel * has to be sent). Otherwise, the request is stored in a temporary location
961708Sstevel * and delivered by a thread.
971708Sstevel */
981708Sstevel int
rmc_comm_request_nowait(rmc_comm_msg_t * request,uint8_t flag)991708Sstevel rmc_comm_request_nowait(rmc_comm_msg_t *request, uint8_t flag)
1001708Sstevel {
1011708Sstevel struct rmc_comm_state *rcs;
1021708Sstevel rmc_comm_dp_state_t *dps;
1031708Sstevel rmc_comm_drvintf_state_t *dis;
1041708Sstevel dp_message_t req;
1051708Sstevel int err = RCNOERR;
1061708Sstevel uint8_t flags = 0;
1071708Sstevel
1081708Sstevel /*
1091708Sstevel * get the soft state struct (instance 0)
1101708Sstevel */
1111708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
112*11066Srafael.vanoni@sun.com "rmc_comm_request_response")) == NULL)
1131708Sstevel return (RCENOSOFTSTATE);
1141708Sstevel
1151708Sstevel /*
1161708Sstevel * just a sanity check...
1171708Sstevel */
1181708Sstevel if (request == NULL) {
1191708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqnowait, invalid args\n"));
1201708Sstevel return (RCEINVARG);
1211708Sstevel }
1221708Sstevel
1231708Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) {
1241708Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
1251708Sstevel "reqnowait, ctrl msg not allowed! req type=%x\n",
1261708Sstevel request->msg_type));
1271708Sstevel return (RCEINVARG);
1281708Sstevel }
1291708Sstevel
1301708Sstevel if (flag == RMC_COMM_DREQ_URGENT) {
1311708Sstevel /*
1321708Sstevel * Send this request with high priority i.e. abort eventual
1331708Sstevel * request/response pending sessions.
1341708Sstevel */
1351708Sstevel
1361708Sstevel dps = &rcs->dp_state;
1371708Sstevel
1381708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "going to send request=%x (URG)\n",
1391708Sstevel request->msg_type));
1401708Sstevel
1412749Sarutz /*
1422749Sarutz * Handle the case where we are called during panic
1432749Sarutz * processing. If that occurs, then another thread in
1442749Sarutz * rmc_comm might have been idled by panic() while
1452749Sarutz * holding dp_mutex. As a result, do not unconditionally
1462749Sarutz * grab dp_mutex.
1472749Sarutz */
1482749Sarutz if (ddi_in_panic() != 0) {
1492749Sarutz if (mutex_tryenter(dps->dp_mutex) == 0) {
1502749Sarutz return (RCENODATALINK);
1512749Sarutz }
1522749Sarutz } else {
1532749Sarutz mutex_enter(dps->dp_mutex);
1542749Sarutz }
1551708Sstevel
1561708Sstevel /*
1571708Sstevel * send the request only if the protocol data link is up.
1581708Sstevel * it is pointless to send it in the other case.
1591708Sstevel */
1601708Sstevel if (dps->data_link_ok) {
1611708Sstevel
1621708Sstevel /*
1631708Sstevel * clean up an eventual pending request/response session
1641708Sstevel * (save its current status)
1651708Sstevel */
1661708Sstevel if (dps->pending_request) {
1671708Sstevel flags = dps->req_resp.flags;
1681708Sstevel rmc_comm_dp_mcleanup(rcs);
1691708Sstevel }
1701708Sstevel
1711708Sstevel /*
1721708Sstevel * send the request message
1731708Sstevel */
1741708Sstevel req.msg_type = request->msg_type;
1751708Sstevel req.msg_buf = (uint8_t *)request->msg_buf;
1761708Sstevel req.msg_msglen = (uint16_t)request->msg_len;
1771708Sstevel
1781708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x (URG)\n",
1791708Sstevel request->msg_type));
1801708Sstevel
1811708Sstevel err = rmc_comm_dp_msend(rcs, &req);
1821708Sstevel
1831708Sstevel /*
1841708Sstevel * wait for fifos to drain
1851708Sstevel */
1861708Sstevel rmc_comm_serdev_drain(rcs);
1871708Sstevel
1881708Sstevel /*
1891708Sstevel * clean up the current session
1901708Sstevel */
1911708Sstevel rmc_comm_dp_mcleanup(rcs);
1921708Sstevel
1931708Sstevel /*
1941708Sstevel * abort an old session (if any)
1951708Sstevel */
1961708Sstevel if (dps->pending_request) {
1971708Sstevel dps->req_resp.flags = flags;
1981708Sstevel dp_wake_up_waiter(rcs, MSG_ERROR);
1991708Sstevel }
2001708Sstevel }
2011708Sstevel
2021708Sstevel mutex_exit(dps->dp_mutex);
2031708Sstevel
2041708Sstevel } else {
2051708Sstevel
2061708Sstevel /*
2071708Sstevel * Get an 'independent' thread (rmc_comm_send_pend_req)
2081708Sstevel * to send this request (since the calling thread does not
2091708Sstevel * want to wait). Copy the request in the drvintf state
2101708Sstevel * structure and signal the thread.
2111708Sstevel */
2121708Sstevel
2131708Sstevel dis = &rcs->drvi_state;
2141708Sstevel
2151708Sstevel mutex_enter(dis->dreq_mutex);
2161708Sstevel
2171708Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) {
2181708Sstevel
2191708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "get to send request=%x\n",
2201708Sstevel request->msg_type));
2211708Sstevel
2221708Sstevel /*
2231708Sstevel * copy the request in a temporary location
2241708Sstevel * (drvinf_state structure) and signal the thread
2251708Sstevel * that a request message has to be delivered
2261708Sstevel */
2271708Sstevel
2281708Sstevel if (request->msg_len < DP_MAX_MSGLEN) {
2291708Sstevel dis->dreq_request.msg_type = request->msg_type;
2301708Sstevel dis->dreq_request.msg_len = request->msg_len;
2311708Sstevel dis->dreq_request.msg_buf =
2321708Sstevel dis->dreq_request_buf;
2331708Sstevel bcopy(request->msg_buf,
2341708Sstevel dis->dreq_request.msg_buf,
2351708Sstevel request->msg_len);
2361708Sstevel
2371708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_PROCESS;
2381708Sstevel cv_signal(dis->dreq_sig_cv);
2391708Sstevel
2401708Sstevel } else {
2411708Sstevel /*
2421708Sstevel * not enough space to hold the request
2431708Sstevel */
2441708Sstevel err = RCEREPTOOBIG;
2451708Sstevel }
2461708Sstevel } else {
2471708Sstevel
2481708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "cannot get to send "
2491708Sstevel "request=%x (busy)\n", request->msg_type));
2501708Sstevel
2511708Sstevel /*
2521708Sstevel * only one request per time can be processed.
2531708Sstevel * the thread is either busy (RMC_COMM_DREQ_ST_PROCESS)
2541708Sstevel * or terminating (RMC_COMM_DREQ_ST_EXIT)
2551708Sstevel */
2561708Sstevel err = RCEGENERIC;
2571708Sstevel }
2581708Sstevel
2591708Sstevel mutex_exit(dis->dreq_mutex);
2601708Sstevel }
2611708Sstevel
2621708Sstevel return (err);
2631708Sstevel }
2641708Sstevel
2651708Sstevel /*
2661708Sstevel * Function used to send a request and (eventually) wait for a response.
2671708Sstevel * It can be called from a leaf driver (via rmc_comm_request_response) or
2681708Sstevel * from the thread in charge of sending 'no-wait' requests
2691708Sstevel * (rmc_comm_send_pend_req).
2701708Sstevel */
2711708Sstevel 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)2721708Sstevel rmc_comm_send_req_resp(struct rmc_comm_state *rcs, rmc_comm_msg_t *request,
2731708Sstevel rmc_comm_msg_t *response, uint32_t wait_time)
2741708Sstevel {
2751708Sstevel rmc_comm_dp_state_t *dps;
2761708Sstevel dp_req_resp_t *drr;
2771708Sstevel dp_message_t *exp_resp;
2781708Sstevel dp_message_t req;
279*11066Srafael.vanoni@sun.com clock_t resend_clockt, delta;
2801708Sstevel clock_t stop_clockt;
2811708Sstevel int err;
2821708Sstevel
2831708Sstevel
2841708Sstevel /*
2851708Sstevel * just a sanity check...
2861708Sstevel */
2871708Sstevel if (request == NULL) {
2881708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp, invalid args\n"));
2891708Sstevel return (RCEINVARG);
2901708Sstevel }
2911708Sstevel
2921708Sstevel /*
2931708Sstevel * drivers cannot send control messages at all. They are meant to
2941708Sstevel * be used at low level only.
2951708Sstevel */
2961708Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) {
2971708Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
2981708Sstevel "reqresp, ctrl msg not allowed! req type=%x\n",
2991708Sstevel request->msg_type));
3001708Sstevel return (RCEINVARG);
3011708Sstevel }
3021708Sstevel
3031708Sstevel dps = &rcs->dp_state;
3041708Sstevel drr = &dps->req_resp;
3051708Sstevel exp_resp = &drr->response;
3061708Sstevel
3072749Sarutz /*
3082749Sarutz * Handle the case where we are called during panic
3092749Sarutz * processing. If that occurs, then another thread in
3102749Sarutz * rmc_comm might have been idled by panic() while
3112749Sarutz * holding dp_mutex. As a result, do not unconditionally
3122749Sarutz * grab dp_mutex.
3132749Sarutz */
3142749Sarutz if (ddi_in_panic() != 0) {
3152749Sarutz if (mutex_tryenter(dps->dp_mutex) == 0) {
3162749Sarutz return (RCENODATALINK);
3172749Sarutz }
3182749Sarutz } else {
3192749Sarutz mutex_enter(dps->dp_mutex);
3202749Sarutz }
3211708Sstevel
3221708Sstevel /*
3231708Sstevel * if the data link set up is suspended, just return.
3241708Sstevel * the only time that this can happen is during firmware download
3251708Sstevel * (see rmc_comm_request_response_bp). Basically, the data link is
3261708Sstevel * down and the timer for setting up the data link is not running.
3271708Sstevel */
3281708Sstevel if (!dps->data_link_ok &&
3291708Sstevel dps->timer_link_setup == (timeout_id_t)0) {
3301708Sstevel
3311708Sstevel mutex_exit(dps->dp_mutex);
3321708Sstevel return (RCENODATALINK);
3331708Sstevel }
3341708Sstevel
3351708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d, req type=%x\n",
3361708Sstevel dps->pending_request, request->msg_type));
3371708Sstevel
3381708Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
3391708Sstevel
3401708Sstevel /*
3411708Sstevel * We now have control of the RMC.
3421708Sstevel * Place a lower limit on the shortest amount of time to be
3431708Sstevel * waited before timing out while communicating with the RMC
3441708Sstevel */
3451708Sstevel if (wait_time < DP_MIN_TIMEOUT)
3461708Sstevel wait_time = DP_MIN_TIMEOUT;
3471708Sstevel
3481708Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
3491708Sstevel
3501708Sstevel /*
3511708Sstevel * initialization of the request/response data structure
3521708Sstevel */
3531708Sstevel drr->flags = 0;
3541708Sstevel drr->error_status = 0;
3551708Sstevel
3561708Sstevel /*
3571708Sstevel * set the 'expected reply' buffer: get the buffer already allocated
3581708Sstevel * for the response (if a reply is expected!)
3591708Sstevel */
3601708Sstevel if (response != NULL) {
3611708Sstevel exp_resp->msg_type = response->msg_type;
3621708Sstevel exp_resp->msg_buf = (uint8_t *)response->msg_buf;
3631708Sstevel exp_resp->msg_msglen = (uint16_t)response->msg_bytes;
3641708Sstevel exp_resp->msg_bufsiz = (uint16_t)response->msg_len;
3651708Sstevel } else {
3661708Sstevel exp_resp->msg_type = DP_NULL_MSG;
3671708Sstevel exp_resp->msg_buf = (uint8_t)NULL;
3681708Sstevel exp_resp->msg_bufsiz = (uint16_t)0;
3691708Sstevel exp_resp->msg_msglen = (uint16_t)0;
3701708Sstevel }
3711708Sstevel
3721708Sstevel /*
3731708Sstevel * send the request message
3741708Sstevel */
3751708Sstevel req.msg_type = request->msg_type;
3761708Sstevel req.msg_buf = (uint8_t *)request->msg_buf;
3771708Sstevel req.msg_msglen = (uint16_t)request->msg_len;
3781708Sstevel
3791708Sstevel /*
3801708Sstevel * send the message and wait for the reply or ACKnowledgment
3811708Sstevel * re-send the message if reply/ACK is not received in the
3821708Sstevel * timeframe defined
3831708Sstevel */
3841708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x\n", request->msg_type));
3851708Sstevel
386*11066Srafael.vanoni@sun.com delta = drv_usectohz(TX_RETRY_TIME * 1000);
387*11066Srafael.vanoni@sun.com
3881708Sstevel while ((err = rmc_comm_dp_msend(rcs, &req)) == RCNOERR) {
3891708Sstevel
390*11066Srafael.vanoni@sun.com resend_clockt = ddi_get_lbolt() + delta;
3911708Sstevel
3921708Sstevel /*
3931708Sstevel * wait for a reply or an acknowledgement
3941708Sstevel */
395*11066Srafael.vanoni@sun.com (void) cv_reltimedwait(drr->cv_wait_reply, dps->dp_mutex,
396*11066Srafael.vanoni@sun.com delta, TR_CLOCK_TICK);
3971708Sstevel
3981708Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
3991708Sstevel "reqresp send status: flags=%02x req=%x resp=%x tick=%ld\n",
4001708Sstevel drr->flags, request->msg_type,
4011708Sstevel response ? response->msg_type : -1,
4021708Sstevel stop_clockt - resend_clockt));
4031708Sstevel
4041708Sstevel /*
4051708Sstevel * Check for error condition first
4061708Sstevel * Then, check if the command has been replied/ACKed
4071708Sstevel * Then, check if it has timeout and if there is any
4081708Sstevel * time left to resend the message.
4091708Sstevel */
4101708Sstevel if ((drr->flags & MSG_ERROR) != 0) {
4111708Sstevel if (drr->error_status == 0) {
4121708Sstevel err = RCEGENERIC;
4131708Sstevel } else {
4141708Sstevel err = drr->error_status;
4151708Sstevel }
4161708Sstevel break;
4171708Sstevel
4181708Sstevel } else if (response != NULL &&
4191708Sstevel (drr->flags & MSG_REPLY_RXED) != 0) {
4201708Sstevel /*
4211708Sstevel * yes! here is the reply
4221708Sstevel */
4231708Sstevel
4241708Sstevel /*
4251708Sstevel * get the actual length of the msg
4261708Sstevel * a negative value means that the reply message
4271708Sstevel * was too big for the receiver buffer
4281708Sstevel */
4291708Sstevel response->msg_bytes = exp_resp->msg_msglen;
4301708Sstevel if (response->msg_bytes < 0)
4311708Sstevel err = RCEREPTOOBIG;
4321708Sstevel else
4331708Sstevel err = RCNOERR;
4341708Sstevel break;
4351708Sstevel
4361708Sstevel } else if (response == NULL && (drr->flags & MSG_ACKED) != 0) {
4371708Sstevel /*
4381708Sstevel * yes! message has been acknowledged
4391708Sstevel */
4401708Sstevel
4411708Sstevel err = RCNOERR;
4421708Sstevel break;
4431708Sstevel
4441708Sstevel } else if ((stop_clockt - resend_clockt) <= 0) {
4451708Sstevel /*
4461708Sstevel * no more time left. set the error code,
4471708Sstevel * exit the loop
4481708Sstevel */
4491708Sstevel
4501708Sstevel err = RCETIMEOUT;
4511708Sstevel break;
4521708Sstevel }
4531708Sstevel }
4541708Sstevel
4551708Sstevel rmc_comm_dp_mcleanup(rcs);
4561708Sstevel
4571708Sstevel rmc_comm_wake_up_next(rcs);
4581708Sstevel
4591708Sstevel mutex_exit(dps->dp_mutex);
4601708Sstevel
4611708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp end: err=%d, request=%x\n",
4621708Sstevel err, request->msg_type));
4631708Sstevel
4641708Sstevel return (err);
4651708Sstevel }
4661708Sstevel
4671708Sstevel /*
4681708Sstevel * Function used to send a BP (Boot Prom) message and get the reply.
4691708Sstevel * BP protocol is provided only to support firmware download.
4701708Sstevel *
4711708Sstevel * This function will look for the following key BP protocol commands:
4721708Sstevel * BP_OBP_BOOTINIT: the data link is brought down so that request/response
4731708Sstevel * sessions cannot be started. The reason why is that this command will cause
4741708Sstevel * RMC fw to jump to the boot monitor (BOOTMON_FLASH) and data protocol is not
4751708Sstevel * operational. In this context, RMC fw will only be using the BP protocol.
4761708Sstevel * BP_OBP_RESET: data link setup timer is resumed. This command cause the RMC
4771708Sstevel * to reboot and hence become operational.
4781708Sstevel */
4791708Sstevel int
rmc_comm_request_response_bp(rmc_comm_msg_t * request_bp,rmc_comm_msg_t * response_bp,uint32_t wait_time)4801708Sstevel rmc_comm_request_response_bp(rmc_comm_msg_t *request_bp,
4811708Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time)
4821708Sstevel {
4831708Sstevel struct rmc_comm_state *rcs;
4841708Sstevel rmc_comm_dp_state_t *dps;
4851708Sstevel dp_req_resp_t *drr;
4861708Sstevel dp_message_t *resp_bp;
4871708Sstevel bp_msg_t *bp_msg;
4881708Sstevel clock_t stop_clockt;
4891708Sstevel int err = RCNOERR;
4901708Sstevel boolean_t bootinit_sent = 0;
4911708Sstevel
4921708Sstevel /*
4931708Sstevel * get the soft state struct (instance 0)
4941708Sstevel */
4951708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
496*11066Srafael.vanoni@sun.com "rmc_comm_request_response_bp")) == NULL)
4971708Sstevel return (RCENOSOFTSTATE);
4981708Sstevel
4991708Sstevel /*
5001708Sstevel * sanity check: request_bp buffer must always be provided
5011708Sstevel */
5021708Sstevel if (request_bp == NULL) {
5031708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp_bp, invalid args\n"));
5041708Sstevel return (RCEINVARG);
5051708Sstevel }
5061708Sstevel
5071708Sstevel bp_msg = (bp_msg_t *)request_bp->msg_buf;
5081708Sstevel
5091708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request_bp=%x\n", bp_msg->cmd));
5101708Sstevel
5111708Sstevel /*
5121708Sstevel * only BP message can be sent
5131708Sstevel */
5141708Sstevel if (!IS_BOOT_MSG(bp_msg->cmd)) {
5151708Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
5161708Sstevel "reqresp_bp, only BP msg are allowed! type=%x\n",
5171708Sstevel bp_msg->cmd));
5181708Sstevel return (RCEINVARG);
5191708Sstevel }
5201708Sstevel
5211708Sstevel dps = &rcs->dp_state;
5221708Sstevel drr = &dps->req_resp;
5231708Sstevel resp_bp = &drr->response;
5241708Sstevel
5251708Sstevel mutex_enter(dps->dp_mutex);
5261708Sstevel
5271708Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
5281708Sstevel
5291708Sstevel /*
5301708Sstevel * Now, before sending the message, just check what it is being sent
5311708Sstevel * and take action accordingly.
5321708Sstevel *
5331708Sstevel * is it BP_OBP_BOOTINIT or BP_OBP_RESET command?
5341708Sstevel */
5351708Sstevel if (bp_msg->cmd == BP_OBP_BOOTINIT) {
5361708Sstevel
5371708Sstevel /*
5381708Sstevel * bring down the protocol data link
5391708Sstevel * (must be done before aborting a request/response session)
5401708Sstevel */
5411708Sstevel dps->data_link_ok = 0;
5421708Sstevel dps->timer_link_setup = (timeout_id_t)0;
5431708Sstevel
5441708Sstevel bootinit_sent = 1;
5451708Sstevel
5461708Sstevel } else if (bp_msg->cmd == BP_OBP_RESET) {
5471708Sstevel
5481708Sstevel /*
5491708Sstevel * restart the data link set up timer. RMC is coming up...
5501708Sstevel */
5511708Sstevel
5521708Sstevel dp_reset(rcs, INITIAL_SEQID, 0, 1);
5531708Sstevel }
5541708Sstevel
5551708Sstevel /*
5561708Sstevel * initialization of the request/response data structure
5571708Sstevel */
5581708Sstevel drr->flags = 0;
5591708Sstevel drr->error_status = 0;
5601708Sstevel
5611708Sstevel /*
5621708Sstevel * set the reply buffer: get the buffer already allocated
5631708Sstevel * for the response
5641708Sstevel */
5651708Sstevel if (response_bp != NULL) {
5661708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "expect BP reply. len=%d\n",
5671708Sstevel response_bp->msg_len));
5681708Sstevel
5691708Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf;
5701708Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len;
5711708Sstevel }
5721708Sstevel
5731708Sstevel /*
5741708Sstevel * send the BP message and wait for the reply
5751708Sstevel */
5761708Sstevel
5771708Sstevel rmc_comm_bp_msend(rcs, bp_msg);
5781708Sstevel
5791708Sstevel if (response_bp != NULL) {
5801708Sstevel
5811708Sstevel /*
5821708Sstevel * place a lower limit on the shortest amount of time to be
5831708Sstevel * waited before timing out while communicating with the RMC
5841708Sstevel */
5851708Sstevel if (wait_time < DP_MIN_TIMEOUT)
5861708Sstevel wait_time = DP_MIN_TIMEOUT;
5871708Sstevel
5881708Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
5891708Sstevel
5901708Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr,
5911708Sstevel stop_clockt)) == RCNOERR) {
5921708Sstevel
5931708Sstevel /*
5941708Sstevel * get the actual length of the msg
5951708Sstevel * a negative value means that the reply message
5961708Sstevel * was too big for the receiver buffer
5971708Sstevel */
5981708Sstevel response_bp->msg_bytes = resp_bp->msg_msglen;
5991708Sstevel if (response_bp->msg_bytes < 0) {
6001708Sstevel err = RCEREPTOOBIG;
6011708Sstevel
6021708Sstevel } else if (bootinit_sent) {
6031708Sstevel
6041708Sstevel /*
6051708Sstevel * BOOTINIT cmd may fail. In this is the case,
6061708Sstevel * the RMC is still operational. Hence, we
6071708Sstevel * try (once) to set up the data link
6081708Sstevel * protocol.
6091708Sstevel */
6101708Sstevel bp_msg = (bp_msg_t *)response_bp->msg_buf;
6111708Sstevel
6121708Sstevel if (bp_msg->cmd == BP_RSC_BOOTFAIL &&
6131708Sstevel bp_msg->dat1 == BP_DAT1_REJECTED) {
6141708Sstevel (void) rmc_comm_dp_ctlsend(rcs,
6151708Sstevel DP_CTL_START);
6161708Sstevel }
6171708Sstevel }
6181708Sstevel }
6191708Sstevel }
6201708Sstevel
6211708Sstevel rmc_comm_dp_mcleanup(rcs);
6221708Sstevel
6231708Sstevel rmc_comm_wake_up_next(rcs);
6241708Sstevel
6251708Sstevel mutex_exit(dps->dp_mutex);
6261708Sstevel
6271708Sstevel return (err);
6281708Sstevel }
6291708Sstevel
6301708Sstevel
6311708Sstevel /*
6321708Sstevel * to register for an asynchronous (via soft interrupt) notification
6331708Sstevel * of a message from the remote side (RMC)
6341708Sstevel */
6351708Sstevel 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)6361708Sstevel rmc_comm_reg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler,
6371708Sstevel rmc_comm_msg_t *msgbuf, uint_t *state, kmutex_t *lock)
6381708Sstevel {
6391708Sstevel struct rmc_comm_state *rcs;
6401708Sstevel dp_msg_intr_t *msgintr;
6411708Sstevel int err = RCNOERR;
6421708Sstevel
6431708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_reg_intr")) == NULL)
6441708Sstevel return (RCENOSOFTSTATE);
6451708Sstevel
6461708Sstevel mutex_enter(rcs->dp_state.dp_mutex);
6471708Sstevel
6481708Sstevel msgintr = &rcs->dp_state.msg_intr;
6491708Sstevel
6501708Sstevel /*
6511708Sstevel * lock is required. If it is not defined, the
6521708Sstevel * interrupt handler routine cannot be registered.
6531708Sstevel */
6541708Sstevel if (lock == NULL) {
6551708Sstevel mutex_exit(rcs->dp_state.dp_mutex);
6561708Sstevel return (RCEINVARG);
6571708Sstevel }
6581708Sstevel
6591708Sstevel /*
6601708Sstevel * only one interrupt handler can be registered.
6611708Sstevel */
6621708Sstevel if (msgintr->intr_handler == NULL) {
6631708Sstevel
6641708Sstevel if (ddi_add_softintr(rcs->dip, DDI_SOFTINT_HIGH,
6651708Sstevel &msgintr->intr_id, NULL, NULL, intr_handler,
6661708Sstevel (caddr_t)msgbuf) == DDI_SUCCESS) {
6671708Sstevel
6681708Sstevel msgintr->intr_handler = intr_handler;
6691708Sstevel msgintr->intr_lock = lock;
6701708Sstevel msgintr->intr_state = state;
6711708Sstevel msgintr->intr_msg_type = msg_type;
6721708Sstevel msgintr->intr_arg = (caddr_t)msgbuf;
6731708Sstevel } else {
6741708Sstevel err = RCECANTREGINTR;
6751708Sstevel }
6761708Sstevel } else {
6771708Sstevel err = RCEALREADYREG;
6781708Sstevel }
6791708Sstevel
6801708Sstevel mutex_exit(rcs->dp_state.dp_mutex);
6811708Sstevel
6821708Sstevel return (err);
6831708Sstevel }
6841708Sstevel
6851708Sstevel /*
6861708Sstevel * To unregister for asynchronous notifications
6871708Sstevel */
6881708Sstevel int
rmc_comm_unreg_intr(uint8_t msg_type,rmc_comm_intrfunc_t intr_handler)6891708Sstevel rmc_comm_unreg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler)
6901708Sstevel {
6911708Sstevel struct rmc_comm_state *rcs;
6921708Sstevel dp_msg_intr_t *msgintr;
6931708Sstevel int err = RCNOERR;
6941708Sstevel
6951708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_unreg_intr")) == NULL)
6961708Sstevel return (RCENOSOFTSTATE);
6971708Sstevel
6981708Sstevel mutex_enter(rcs->dp_state.dp_mutex);
6991708Sstevel
7001708Sstevel msgintr = &rcs->dp_state.msg_intr;
7011708Sstevel
7021708Sstevel if (msgintr->intr_handler != NULL &&
703*11066Srafael.vanoni@sun.com msgintr->intr_msg_type == msg_type &&
704*11066Srafael.vanoni@sun.com msgintr->intr_handler == intr_handler) {
7051708Sstevel
7061708Sstevel ddi_remove_softintr(msgintr->intr_id);
7071708Sstevel msgintr->intr_handler = NULL;
7081708Sstevel msgintr->intr_id = 0;
7091708Sstevel msgintr->intr_msg_type = 0;
7101708Sstevel msgintr->intr_arg = NULL;
7111708Sstevel msgintr->intr_lock = NULL;
7121708Sstevel msgintr->intr_state = NULL;
7131708Sstevel } else {
7141708Sstevel err = RCEGENERIC;
7151708Sstevel }
7161708Sstevel
7171708Sstevel mutex_exit(rcs->dp_state.dp_mutex);
7181708Sstevel
7191708Sstevel return (err);
7201708Sstevel }
7211708Sstevel
7221708Sstevel /*
7231708Sstevel * To send raw data (firmware s-records) down to the RMC.
7241708Sstevel * It is provided only to support firmware download.
7251708Sstevel */
7261708Sstevel int
rmc_comm_send_srecord_bp(caddr_t buf,int buflen,rmc_comm_msg_t * response_bp,uint32_t wait_time)7271708Sstevel rmc_comm_send_srecord_bp(caddr_t buf, int buflen,
7281708Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time)
7291708Sstevel {
7301708Sstevel struct rmc_comm_state *rcs;
7311708Sstevel rmc_comm_dp_state_t *dps;
7321708Sstevel dp_req_resp_t *drr;
7331708Sstevel dp_message_t *resp_bp;
7341708Sstevel clock_t stop_clockt;
7351708Sstevel int err;
7361708Sstevel
7371708Sstevel /*
7381708Sstevel * get the soft state struct (instance 0)
7391708Sstevel */
7401708Sstevel if ((rcs = rmc_comm_getstate(NULL, 0,
741*11066Srafael.vanoni@sun.com "rmc_comm_request_response_bp")) == NULL)
7421708Sstevel return (RCENOSOFTSTATE);
7431708Sstevel
7441708Sstevel /*
7451708Sstevel * sanity check: response_bp buffer must always be provided
7461708Sstevel */
7471708Sstevel if (buf == NULL || response_bp == NULL) {
7481708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp,invalid args\n"));
7491708Sstevel return (RCEINVARG);
7501708Sstevel }
7511708Sstevel
7521708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp, buflen=%d\n", buflen));
7531708Sstevel
7541708Sstevel dps = &rcs->dp_state;
7551708Sstevel drr = &dps->req_resp;
7561708Sstevel resp_bp = &drr->response;
7571708Sstevel
7581708Sstevel mutex_enter(dps->dp_mutex);
7591708Sstevel
7601708Sstevel rmc_comm_wait_enable_to_send(rcs, dps);
7611708Sstevel
7621708Sstevel /*
7631708Sstevel * initialization of the request/response data structure
7641708Sstevel */
7651708Sstevel drr->flags = 0;
7661708Sstevel drr->error_status = 0;
7671708Sstevel
7681708Sstevel /*
7691708Sstevel * set the reply buffer: get the buffer already allocated
7701708Sstevel * for the response
7711708Sstevel */
7721708Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf;
7731708Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len;
7741708Sstevel
7751708Sstevel /*
7761708Sstevel * send raw data (s-record) and wait for the reply (BP message)
7771708Sstevel */
7781708Sstevel
7791708Sstevel rmc_comm_bp_srecsend(rcs, (char *)buf, buflen);
7801708Sstevel
7811708Sstevel /*
7821708Sstevel * place a lower limit on the shortest amount of time to be
7831708Sstevel * waited before timing out while communicating with the RMC
7841708Sstevel */
7851708Sstevel if (wait_time < DP_MIN_TIMEOUT)
7861708Sstevel wait_time = DP_MIN_TIMEOUT;
7871708Sstevel
7881708Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000);
7891708Sstevel
7901708Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr,
7911708Sstevel stop_clockt)) == RCNOERR) {
7921708Sstevel /*
7931708Sstevel * get the actual length of the msg
7941708Sstevel * a negative value means that the reply message
7951708Sstevel * was too big for the receiver buffer
7961708Sstevel */
7971708Sstevel response_bp->msg_bytes = resp_bp->msg_msglen;
7981708Sstevel if (response_bp->msg_bytes < 0) {
7991708Sstevel err = RCEREPTOOBIG;
8001708Sstevel }
8011708Sstevel }
8021708Sstevel
8031708Sstevel rmc_comm_dp_mcleanup(rcs);
8041708Sstevel
8051708Sstevel rmc_comm_wake_up_next(rcs);
8061708Sstevel
8071708Sstevel mutex_exit(dps->dp_mutex);
8081708Sstevel
8091708Sstevel return (err);
8101708Sstevel }
8111708Sstevel
8121708Sstevel /*
8131708Sstevel * To wait for (any) BP message to be received.
8141708Sstevel * (dp_mutex must be held)
8151708Sstevel */
8161708Sstevel 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)8171708Sstevel rmc_comm_wait_bp_reply(struct rmc_comm_state *rcs, rmc_comm_dp_state_t *dps,
8181708Sstevel dp_req_resp_t *drr, clock_t stop_clockt)
8191708Sstevel {
8201708Sstevel clock_t clockleft = 1;
8211708Sstevel int err = RCNOERR;
8221708Sstevel
8231708Sstevel clockleft = cv_timedwait(drr->cv_wait_reply, dps->dp_mutex,
8241708Sstevel stop_clockt);
8251708Sstevel
8261708Sstevel
8271708Sstevel DPRINTF(rcs, DAPI, (CE_CONT,
8281708Sstevel "reqresp_bp, send: flags=%02x, clktick left=%ld\n",
8291708Sstevel drr->flags, clockleft));
8301708Sstevel
8311708Sstevel /*
8321708Sstevel * Check for error condition first.
8331708Sstevel * Then, check if it has timeout.
8341708Sstevel * Then, check if the command has been replied.
8351708Sstevel */
8361708Sstevel if ((drr->flags & MSG_ERROR) != 0) {
8371708Sstevel
8381708Sstevel err = RCEGENERIC;
8391708Sstevel
8401708Sstevel } else if (clockleft <= 0) {
8411708Sstevel /*
8421708Sstevel * timeout
8431708Sstevel */
8441708Sstevel
8451708Sstevel err = RCETIMEOUT;
8461708Sstevel
8471708Sstevel } else if ((drr->flags & MSG_RXED_BP) == 0) {
8481708Sstevel
8491708Sstevel err = RCEGENERIC;
8501708Sstevel }
8511708Sstevel
8521708Sstevel return (err);
8531708Sstevel }
8541708Sstevel
8551708Sstevel /*
8561708Sstevel * Wait for the pending_request flag to be cleared and acquire it for our
8571708Sstevel * own use. The caller is then allowed to start a new request/response
8581708Sstevel * session with the RMC.
8591708Sstevel * Note that all send-receive actions to the RMC include a time-out, so
8601708Sstevel * the pending-request must eventually go away - even if the RMC is down.
8611708Sstevel * Hence there is no need to timeout the wait action of this function.
8621708Sstevel * (dp_mutex must be held on entry).
8631708Sstevel */
8641708Sstevel static void
rmc_comm_wait_enable_to_send(struct rmc_comm_state * rcs,rmc_comm_dp_state_t * dps)8651708Sstevel rmc_comm_wait_enable_to_send(struct rmc_comm_state *rcs,
8661708Sstevel rmc_comm_dp_state_t *dps)
8671708Sstevel {
8681708Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d\n",
8691708Sstevel dps->pending_request));
8701708Sstevel
8711708Sstevel /*
8721708Sstevel * A new message can actually grab the lock before the thread
8731708Sstevel * that has just been signaled. Therefore, we need to double
8741708Sstevel * check to make sure that pending_request is not already set
8751708Sstevel * after we wake up.
8761708Sstevel *
8771708Sstevel * Potentially this could mean starvation for certain unfortunate
8781708Sstevel * threads that keep getting woken up and putting back to sleep.
8791708Sstevel * But the window of such contention is very small to begin with.
8801708Sstevel */
8811708Sstevel
8821708Sstevel while (dps->pending_request) {
8831708Sstevel /*
8841708Sstevel * just 'sit and wait' until there are no pending requests
8851708Sstevel */
8861708Sstevel
8871708Sstevel cv_wait(dps->cv_ok_to_send, dps->dp_mutex);
8881708Sstevel }
8891708Sstevel
8901708Sstevel /*
8911708Sstevel * now a request/response can be started. Set the flag so that nobody
8921708Sstevel * else will be able to send anything.
8931708Sstevel */
8941708Sstevel dps->pending_request = 1;
8951708Sstevel }
8961708Sstevel
8971708Sstevel /*
8981708Sstevel * To wake up one of the threads (if any) waiting for starting a
8991708Sstevel * request/response session.
9001708Sstevel * (dp_mutex must be held)
9011708Sstevel */
9021708Sstevel static void
rmc_comm_wake_up_next(struct rmc_comm_state * rcs)9031708Sstevel rmc_comm_wake_up_next(struct rmc_comm_state *rcs)
9041708Sstevel {
9051708Sstevel /*
9061708Sstevel * wake up eventual waiting threads...
9071708Sstevel */
9081708Sstevel
9091708Sstevel rcs->dp_state.pending_request = 0;
9101708Sstevel cv_signal(rcs->dp_state.cv_ok_to_send);
9111708Sstevel }
9121708Sstevel
9131708Sstevel
9141708Sstevel /*
9151708Sstevel * thread which delivers pending request message to the rmc. Some leaf drivers
9161708Sstevel * cannot afford to wait for a request to be replied/ACKed. Hence, a request
9171708Sstevel * message is stored temporarily in the state structure and this thread
9181708Sstevel * gets woken up to deliver it.
9191708Sstevel */
9201708Sstevel static void
rmc_comm_send_pend_req(caddr_t arg)9211708Sstevel rmc_comm_send_pend_req(caddr_t arg)
9221708Sstevel {
9231708Sstevel struct rmc_comm_state *rcs;
9241708Sstevel rmc_comm_drvintf_state_t *dis;
9251708Sstevel callb_cpr_t cprinfo;
9261708Sstevel
9271708Sstevel if (arg == NULL) {
9281708Sstevel thread_exit();
9291708Sstevel /* NOTREACHED */
9301708Sstevel }
9311708Sstevel
9321708Sstevel rcs = (struct rmc_comm_state *)arg;
9331708Sstevel dis = &rcs->drvi_state;
9341708Sstevel
9351708Sstevel CALLB_CPR_INIT(&cprinfo, dis->dreq_mutex, callb_generic_cpr,
9361708Sstevel "rmc_comm_send_pend_req");
9371708Sstevel
9381708Sstevel mutex_enter(dis->dreq_mutex);
9391708Sstevel
9401708Sstevel if (dis->dreq_state <= RMC_COMM_DREQ_ST_READY)
9411708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT;
9421708Sstevel
9431708Sstevel for (;;) {
9441708Sstevel
9451708Sstevel /*
9461708Sstevel * Wait for someone to tell me to continue.
9471708Sstevel */
9481708Sstevel while (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) {
9491708Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
9501708Sstevel cv_wait(dis->dreq_sig_cv, dis->dreq_mutex);
9511708Sstevel CALLB_CPR_SAFE_END(&cprinfo, dis->dreq_mutex);
9521708Sstevel }
9531708Sstevel
9541708Sstevel /* RMC_COMM_DREQ_ST_EXIT implies signal by _detach(). */
9551708Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_EXIT) {
9561708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED;
9571708Sstevel dis->dreq_tid = 0;
9581708Sstevel
9591708Sstevel /* dis->dreq_mutex is held at this point! */
9601708Sstevel CALLB_CPR_EXIT(&cprinfo);
9611708Sstevel
9621708Sstevel thread_exit();
9631708Sstevel /* NOTREACHED */
9641708Sstevel }
9651708Sstevel
9661708Sstevel ASSERT(dis->dreq_state == RMC_COMM_DREQ_ST_PROCESS);
9671708Sstevel mutex_exit(dis->dreq_mutex);
9681708Sstevel
9691708Sstevel /*
9701708Sstevel * deliver the request (and wait...)
9711708Sstevel */
9723482Sjfrank while (rmc_comm_send_req_resp(rcs, &dis->dreq_request, NULL,
9733482Sjfrank RMC_COMM_DREQ_DEFAULT_TIME) == RCEGENERIC) {
9743482Sjfrank }
9751708Sstevel
9761708Sstevel mutex_enter(dis->dreq_mutex);
9771708Sstevel if (dis->dreq_state != RMC_COMM_DREQ_ST_EXIT)
9781708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT;
9791708Sstevel }
9801708Sstevel }
9811708Sstevel
9821708Sstevel /*
9831708Sstevel * start thread to deal with pending requests to be delivered asynchronously
9841708Sstevel * (i.e. leaf driver do not have to/cannot wait for a reply/ACk of a request)
9851708Sstevel */
9861708Sstevel static int
rmc_comm_dreq_thread_start(struct rmc_comm_state * rcs)9871708Sstevel rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs)
9881708Sstevel {
9891708Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state;
9901708Sstevel int err = 0;
9911708Sstevel kthread_t *tp;
9921708Sstevel
9931708Sstevel mutex_enter(dis->dreq_mutex);
9941708Sstevel
9951708Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_NOTSTARTED) {
9961708Sstevel
9971708Sstevel tp = thread_create(NULL, 0, rmc_comm_send_pend_req,
9981708Sstevel (caddr_t)rcs, 0, &p0, TS_RUN, maxclsyspri);
9991708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_READY;
10001708Sstevel dis->dreq_tid = tp->t_did;
10011708Sstevel }
10021708Sstevel
10031708Sstevel mutex_exit(dis->dreq_mutex);
10041708Sstevel
10051708Sstevel return (err);
10061708Sstevel }
10071708Sstevel
10081708Sstevel /*
10091708Sstevel * stop the thread (to deliver pending request messages)
10101708Sstevel */
10111708Sstevel static void
rmc_comm_dreq_thread_kill(struct rmc_comm_state * rcs)10121708Sstevel rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs)
10131708Sstevel {
10141708Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state;
10151708Sstevel kt_did_t tid;
10161708Sstevel
10171708Sstevel mutex_enter(dis->dreq_mutex);
10181708Sstevel tid = dis->dreq_tid;
10191708Sstevel if (tid != 0) {
10201708Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_EXIT;
10211708Sstevel dis->dreq_tid = 0;
10221708Sstevel cv_signal(dis->dreq_sig_cv);
10231708Sstevel }
10241708Sstevel mutex_exit(dis->dreq_mutex);
10251708Sstevel
10261708Sstevel /*
10271708Sstevel * Wait for rmc_comm_send_pend_req() to finish
10281708Sstevel */
10291708Sstevel if (tid != 0)
10301708Sstevel thread_join(tid);
10311708Sstevel }
10321708Sstevel
10331708Sstevel /*
10341708Sstevel * init function - start thread to deal with pending requests (no-wait requests)
10351708Sstevel */
10361708Sstevel int
rmc_comm_drvintf_init(struct rmc_comm_state * rcs)10371708Sstevel rmc_comm_drvintf_init(struct rmc_comm_state *rcs)
10381708Sstevel {
10391708Sstevel int err = 0;
10401708Sstevel
10411708Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_init\n"));
10421708Sstevel rcs->drvi_state.dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED;
10431708Sstevel rcs->drvi_state.dreq_tid = 0;
10441708Sstevel
10451708Sstevel mutex_init(rcs->drvi_state.dreq_mutex, NULL, MUTEX_DRIVER, NULL);
10461708Sstevel cv_init(rcs->drvi_state.dreq_sig_cv, NULL, CV_DRIVER, NULL);
10471708Sstevel
10481708Sstevel err = rmc_comm_dreq_thread_start(rcs);
10491708Sstevel if (err != 0) {
10501708Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv);
10511708Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex);
10521708Sstevel }
10531708Sstevel
10541708Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "thread started? err=%d\n", err));
10551708Sstevel
10561708Sstevel return (err);
10571708Sstevel }
10581708Sstevel
10591708Sstevel /*
10601708Sstevel * fini function - kill thread to deal with pending requests (no-wait requests)
10611708Sstevel */
10621708Sstevel void
rmc_comm_drvintf_fini(struct rmc_comm_state * rcs)10631708Sstevel rmc_comm_drvintf_fini(struct rmc_comm_state *rcs)
10641708Sstevel {
10651708Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:stop thread\n"));
10661708Sstevel
10671708Sstevel rmc_comm_dreq_thread_kill(rcs);
10681708Sstevel
10691708Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:destroy Mx/CVs\n"));
10701708Sstevel
10711708Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv);
10721708Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex);
10731708Sstevel }
1074