diff options
Diffstat (limited to 'usr/src/uts/sun4u/opl/io/scfd/scfdscp.c')
-rw-r--r-- | usr/src/uts/sun4u/opl/io/scfd/scfdscp.c | 4450 |
1 files changed, 4450 insertions, 0 deletions
diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c b/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c new file mode 100644 index 0000000000..bdee1377b4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c @@ -0,0 +1,4450 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfdscp.h> + +/* + * DSCP control table + */ +scf_dscp_comtbl_t scf_dscp_comtbl; /* DSCP control table */ + +mkey_t scf_dscp_mkey_search[] = { + DSCP_KEY, /* DSCP mailbox interface key */ + DKMD_KEY /* DKMD mailbox interface key */ + /* Add mailbox key */ +}; + +/* + * SCF driver system control intafece function + */ +void scf_dscp_init(void); +void scf_dscp_fini(void); +void scf_dscp_start(uint32_t factor); +void scf_dscp_stop(uint32_t factor); +void scf_dscp_intr(scf_state_t *statep); + +/* + * Timeout function : from SCF driver timer contorol function + */ +void scf_dscp_ack_tout(void); +void scf_dscp_end_tout(void); +void scf_dscp_busy_tout(void); +void scf_dscp_callback_tout(void); +void scf_dscp_callback(void); + +/* + * Interrupt function : from scf_dscp_intr() + */ +void scf_dscp_txack_recv(scf_state_t *statep); +void scf_dscp_txend_recv(scf_state_t *statep); +void scf_dscp_rxreq_recv(scf_state_t *statep); + +/* + * Main and Tx/Rx interface function + */ +void scf_dscp_txend_notice(scf_dscp_main_t *mainp); +void scf_dscp_txrelbusy_notice(scf_dscp_main_t *mainp); +void scf_dscp_rxreq_notice(scf_dscp_main_t *mainp); +void scf_dscp_rxdata_notice(scf_dscp_main_t *mainp); + +/* + * Tx subroutine function + */ +void scf_dscp_send_matrix(void); +void scf_dscp_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p); + +/* + * Rx subroutine function + */ +void scf_dscp_recv_matrix(void); +void scf_dscp_rxack_send(scf_state_t *statep); +void scf_dscp_rxend_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p); + +/* + * subroutine function + */ +void scf_dscp_dscbuff_free_all(void); +void scf_dscp_txdscbuff_free(scf_dscp_main_t *mainp); +void scf_dscp_rxdscbuff_free(scf_dscp_main_t *mainp); +void scf_dscp_rdata_free(scf_dscp_main_t *mainp); +void scf_dscp_event_queue(scf_dscp_main_t *mainp, scf_event_t mevent); +void scf_dscp_event_queue_free(scf_dscp_main_t *mainp); +scf_dscp_main_t *scf_dscp_mkey2mainp(mkey_t mkey); +scf_dscp_main_t *scf_dscp_id2mainp(uint8_t id); +uint16_t scf_dscp_sram_get(void); +void scf_dscp_sram_free(uint16_t offset); + + +/* + * DSCP Driver interface function + */ + +/* + * scf_mb_init() + * + * Description: Initialize the mailbox and register a callback for receiving + * events related to the specified mailbox. + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - mailbox key + * event_handler- handler to be called for all events related + * to a mailbox. It should be called back with + * the event type and the registered argument. + * + * arg - A callback argument to be passed back to the + * event_handler. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * EINVAL - Invalid values. + * EEXIST - Already OPEN. + * EIO - DSCP I/F path not available. + */ +int +scf_mb_init(target_id_t target_id, mkey_t mkey, + void (*event_handler) (scf_event_t mevent, void *arg), void *arg) +{ +#define SCF_FUNC_NAME "scf_mb_init() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_init; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_init; + } + + /* Check "event_handler" address */ + if (event_handler == NULL) { + /* Invalid "event_handler" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, + &event_handler, sizeof (event_handler)); + ret = EINVAL; + goto END_mb_init; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status is halt */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_init; + } + + /* Check main status */ + if (mainp->status != SCF_ST_IDLE) { + /* Main status != A0 */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, + &mainp->status, sizeof (mainp->status)); + ret = EEXIST; + goto END_mb_init; + } + + /* Initialize flag */ + mainp->conn_chk_flag = FLAG_OFF; + mainp->putmsg_busy_flag = FLAG_OFF; + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : INIT_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_INIT_REQ; + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Change main status (B0) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_TXEND_RECV_WAIT); + + /* Save parameter */ + mainp->event_handler = event_handler; + mainp->arg = arg; + mainp->target_id = target_id; + mainp->mkey = mkey; + +/* + * END_mb_init + */ + END_mb_init: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_fini() + * + * Description: Cleanup the mailbox and unregister an event_handler, + * if it is registered. + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - mailbox key + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + */ +int +scf_mb_fini(target_id_t target_id, mkey_t mkey) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_fini() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_fini; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_fini; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status is halt */ + if (mainp->status != SCF_ST_IDLE) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + } + goto END_mb_fini; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : FINI_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_FINI_REQ; + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Change main status (D0) */ + SCF_SET_STATUS(mainp, SCF_ST_CLOSE_TXEND_RECV_WAIT); + + /* TxEND(FINI) receive wait */ + SC_DBG_DRV_TRACE(TC_W_SIG, __LINE__, &mainp->fini_cv, + sizeof (kcondvar_t)); + mainp->fini_wait_flag = FLAG_ON; + while (mainp->fini_wait_flag == FLAG_ON) { + cv_wait(&mainp->fini_cv, &scf_comtbl.all_mutex); + } + + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + break; + + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + break; + + case SCF_ST_IDLE: /* Main status (A0) */ + /* Main status == A0 is NOP */ + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_fini + */ + END_mb_fini: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_putmsg() + * + * Description: Send a message via the mailbox identified by mkey. The message + * need to be sent either completely or none. That is, no partial + * messages should be sent. + * + * If a 0 timeout value is specified, then it should act as + * a non-blocking interface, that is, it should either send + * the message immediately or return appropriate error. + * If a timeout value is specified, then it can blocked + * until either the message is sent successfully or timedout. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_len - Total length of the data to be sent. + * num_sg - Number of scatter/gather elements in the argument sgp. + * sgp - Scatter/gather list pointer. + * timeout - timeout value in milliseconds. If 0 specified, no waiting + * is required. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * EBUSY - Driver is BUSY. + * ENOSPC - Not enough space to send the message. + * EIO - DSCP I/F path not available. + */ +/* ARGSUSED */ +int +scf_mb_putmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_putmsg() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* Current TxDSC address */ + caddr_t wkaddr; /* Working value : buffer address */ + uint32_t wkleng = 0; /* Working value : length */ + uint32_t wkoffset; /* Working value : Tx SRAM offset */ + int ii; /* Working value : counter */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_putmsg; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* Check "data_len" is "maxdatalen" */ + if (data_len > scf_dscp_comtbl.maxdatalen) { + /* Invalid "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Check "data_len" is 0 */ + if (data_len == 0) { + goto END_mb_putmsg; + } + + /* + * Check "num_sg" is not 0, and "sgp" is not NULL + */ + if ((num_sg == 0) || (sgp == NULL)) { + /* Invalid "num_sg" or "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &num_sg, sizeof (num_sg)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get total data length : "num_sg" */ + for (ii = 0; ii < num_sg; ii++) { + if ((sgp[ii].msc_len == 0) || + (sgp[ii].msc_dptr != NULL)) { + /* + * Add total data length + */ + wkleng += sgp[ii].msc_len; + } else { + /* Invalid "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, + __LINE__, &ii, sizeof (ii)); + ret = EINVAL; + goto END_mb_putmsg; + } + } + + /* + * Check "data_len" and "wkleng" + */ + if (data_len != wkleng) { + /* Invalid "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* + * Check Tx SRAM space + */ + if (scf_dscp_comtbl.tx_dsc_count >= + scf_dscp_comtbl.txdsc_busycount) { + /* No space of Tx SRAM */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_dsc_count, + sizeof (scf_dscp_comtbl.tx_dsc_count)); + + /* putmsg ENOSPC counter up */ + mainp->memo_putmsg_enospc_cnt++; + + mainp->putmsg_busy_flag = FLAG_ON; + ret = ENOSPC; + goto END_mb_putmsg; + } + + /* Tx buffer allocation */ + wkaddr = (caddr_t)kmem_zalloc(wkleng, KM_SLEEP); + + /* Get Tx SRAM offset */ + wkoffset = scf_dscp_sram_get(); + /* Check Tx SRAM offset */ + if (wkoffset == TX_SRAM_GET_ERROR) { + /* Tx SRAM offset failure */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &wkoffset, sizeof (wkoffset)); + + /* Send data release */ + kmem_free(wkaddr, wkleng); + + /* putmsg busy counter up */ + mainp->memo_putmsg_busy_cnt++; + + ret = EBUSY; + goto END_mb_putmsg; + } + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : DATA_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = (uint16_t)wkoffset; + dsc_p->dinfo.base.length = wkleng; + dsc_p->dinfo.base.dscp_datap = wkaddr; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_DATA_REQ; + + /* Data copy to Tx buffer */ + for (ii = 0; ii < num_sg; ii++) { + if (sgp[ii].msc_len != 0) { + bcopy(sgp[ii].msc_dptr, wkaddr, + sgp[ii].msc_len); + wkaddr += sgp[ii].msc_len; + } + } + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_SRAM_TRANS_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Tx DATA_REQ counter */ + mainp->memo_tx_data_req_cnt++; + break; + + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Main status == C1 is NOP */ + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_putmsg + */ + END_mb_putmsg: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_canget() + * + * Description: Checks if a message received in the specified mailbox. + * If there is a message received, then the length of the + * message is passed via the argument data_lenp. Otherwise, + * return an appropriate error value. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_lenp - A pointer to uint32_t, in which the size of the message + * is returned. + * + * Return Values: returns 0 if a message is present, otherwise an appropriate + * errno value is returned. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * ENOMSG - No message available. + * EIO - DSCP I/F path not available. + */ +int +scf_mb_canget(target_id_t target_id, mkey_t mkey, uint32_t *data_lenp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_canget() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_rdata_que_t *rdt_p; /* Current receive data queue address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_IN, __LINE__, &mkey, sizeof (mkey)); + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_canget; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_canget; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_canget; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "data_lenp" address */ + if (data_lenp == NULL) { + /* Invalid "data_lenp" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, + &data_lenp, sizeof (data_lenp)); + + ret = EINVAL; + goto END_mb_canget; + } + + /* Check receive data count */ + if (mainp->rd_count != 0) { + /* Set receive data length */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + *data_lenp = rdt_p->length; + } else { + /* Set receive data length is 0 : No messages */ + SC_DBG_DRV_TRACE(TC_MB_CANGET, __LINE__, + &mainp->rd_count, + sizeof (mainp->rd_count)); + *data_lenp = 0; + ret = ENOMSG; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_canget + */ + END_mb_canget: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_getmsg() + * + * Description: Get a message from the specified mailbox. A message need to + * be received either completely or none, that is, no partial + * messages should be received. + * + * If a 0 timeout value is specified, then it should act as a + * non-blocking interface, that is, it should either return + * a message from the mailbox or return appropriate error. + * If a timeout value is specified, then it can blocked + * until either the message is received successfully or timedout. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_len - Total length of data buffers passed via scatter/gather list. + * num_sg - Number of scatter/gather elements in the argument sgp. + * sgp - Scatter/gather list pointer. + * timeout - timeout value in milliseconds. If 0 specified, no waiting + * is required. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * EMSGSIZE - Specified receive data size unmatched. + * ENOMSG - No message available. + * EIO - DSCP I/F path not available. + */ +/* ARGSUSED */ +int +scf_mb_getmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_getmsg() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_rdata_que_t *rdt_p; /* Current receive data queue address */ + caddr_t wkaddr; /* Working value : buffer address */ + uint32_t wkleng = 0; /* Working value : length */ + int ii; /* Working value : counter */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_IN, __LINE__, &mkey, sizeof (mkey)); + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_getmsg; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_getmsg; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_getmsg; + } + + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "data_len" */ + if ((data_len == 0) || + (data_len > scf_dscp_comtbl.maxdatalen)) { + /* Unmatched "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Is num_sg and sgp valid? */ + if ((num_sg == 0) || (sgp == NULL)) { + /* Invalid "num_sg" or "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &num_sg, sizeof (num_sg)); + ret = EINVAL; + goto END_mb_getmsg; + } + /* Is there receive data? */ + if (mainp->rd_count == 0) { + /* No message */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG, __LINE__, + &mainp->rd_count, + sizeof (mainp->rd_count)); + ret = ENOMSG; + goto END_mb_getmsg; + } + + /* Get total data length : "num_sg" */ + for (ii = 0; ii < num_sg; ii++) { + if ((sgp[ii].msc_len == 0) || + (sgp[ii].msc_dptr != NULL)) { + /* + * Add total data length + */ + wkleng += sgp[ii].msc_len; + } else { + /* Invalid "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &sgp, sizeof (sgp)); + ret = EINVAL; + goto END_mb_getmsg; + } + } + /* Check "data_len" and "wkleng" */ + if (data_len != wkleng) { + /* Unmatched "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Get receive data queue address */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + + /* Check "data_len" and receive data length */ + if (data_len != rdt_p->length) { + /* Unmatched data_len */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Data copy to "sgp" */ + wkaddr = rdt_p->rdatap; + for (ii = 0; ii < num_sg; ii++) { + if (sgp[ii].msc_len != 0) { + bcopy(wkaddr, sgp[ii].msc_dptr, + sgp[ii].msc_len); + wkaddr += sgp[ii].msc_len; + } + } + /* Receve data release */ + kmem_free(rdt_p->rdatap, rdt_p->length); + rdt_p->rdatap = NULL; + + /* Update receive data queue */ + if (mainp->rd_get == mainp->rd_last) { + mainp->rd_get = mainp->rd_first; + } else { + mainp->rd_get++; + } + + /* Update receive data queue count */ + mainp->rd_count--; + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_getmsg + */ + END_mb_getmsg: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_flush() + * + * Description: Flush messages from a specified mailbox. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * flush_type - Specifies what type of flush is desired. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned. + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + */ +int +scf_mb_flush(target_id_t target_id, mkey_t mkey, mflush_type_t flush_type) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_flush() " + scf_dscp_main_t *mainp; /* Main table address */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_flush; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_flush; + } + + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + switch (flush_type) { + case MB_FLUSH_SEND: + case MB_FLUSH_RECEIVE: + case MB_FLUSH_ALL: + if (flush_type != MB_FLUSH_RECEIVE) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + } + if (flush_type != MB_FLUSH_SEND) { + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + } + break; + + default: + + /* Invalid "flush_type" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, + &flush_type, sizeof (flush_type)); + ret = EINVAL; + break; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_flush + */ + END_mb_flush: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_ctrl() + * + * Description: This interface provides a way to obtain any specific + * properties of a mailbox, such as maximum size of the + * message which could be transmitted/received etc. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * op - an operation. + * arg - argument specific to the operation. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * ENOTSUP - Not supported. + */ +int +scf_mb_ctrl(target_id_t target_id, mkey_t mkey, uint32_t op, void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_ctrl() " + scf_dscp_main_t *mainp; /* Main table address */ + uint32_t *wkarg; /* Working value : arg */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_ctrl; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_ctrl; + } + + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "arg" address */ + if (arg == NULL) { + /* Invalid "arg" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, + &arg, sizeof (arg)); + ret = EINVAL; + goto END_mb_ctrl; + } + + /* Check "op" */ + switch (op) { + case SCF_MBOP_MAXMSGSIZE: + /* + * Notifies max send/receive + * data size + */ + SC_DBG_DRV_TRACE(TC_MB_CTRL, __LINE__, + &scf_dscp_comtbl.maxdatalen, + sizeof (scf_dscp_comtbl.maxdatalen)); + + /* Setsend/receive data size */ + wkarg = (uint32_t *)arg; + *wkarg = scf_dscp_comtbl.maxdatalen; + break; + + default: + /* Not support */ + SC_DBG_DRV_TRACE(TC_MB_CTRL, __LINE__, &op, + sizeof (op)); + ret = ENOTSUP; + break; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, + __LINE__, &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_ctrl + */ + END_mb_ctrl: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * SCF driver system control intafece function + */ + +/* + * scf_dscp_init() + * + * Description: DSCP control area initialization processing. + * + */ +void +scf_dscp_init(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_init() " + scf_dscp_main_t *mainp = NULL; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_tx_sram_t *sram_p; /* Tx SRAM address */ + int ii; /* Working value : counter */ + int jj; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* + * DSCP common table initialization + */ + /* Set size value */ + scf_dscp_comtbl.maxdatalen = SCF_MB_MAXDATALEN; + scf_dscp_comtbl.total_buffsize = SCF_TOTAL_BUFFSIZE; + scf_dscp_comtbl.txbuffsize = SCF_TXBUFFSIZE; + scf_dscp_comtbl.rxbuffsize = SCF_RXBUFFSIZE; + + /* Set max count */ + scf_dscp_comtbl.txsram_maxcount = SCF_TX_SRAM_MAXCOUNT; + scf_dscp_comtbl.rxsram_maxcount = SCF_RX_SRAM_MAXCOUNT; + scf_dscp_comtbl.txdsc_maxcount = SCF_TXDSC_MAXCOUNT; + scf_dscp_comtbl.rxdsc_maxcount = SCF_RXDSC_MAXCOUNT; + scf_dscp_comtbl.txdsc_busycount = SCF_TXDSC_BUSYCOUNT; + scf_dscp_comtbl.rxdsc_busycount = SCF_RXDSC_BUSYCOUNT; + + /* Set re-try max count */ + scf_dscp_comtbl.tx_ackto_maxretry_cnt = SCF_TX_ACKTO_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_endto_maxretry_cnt = SCF_TX_ENDTO_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_busy_maxretry_cnt = SCF_TX_BUSY_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_interface_maxretry_cnt = SCF_TX_IF_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_nak_maxretry_cnt = SCF_TX_NAK_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_notsup_maxretry_cnt = SCF_TX_NOTSUP_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_prmerr_maxretry_cnt = SCF_TX_PRMERR_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_seqerr_maxretry_cnt = SCF_TX_SEQERR_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_other_maxretry_cnt = SCF_TX_OTHER_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_send_maxretry_cnt = SCF_TX_SEND_MAXRETRAYCOUNT; + + /* TxDSC/RxDSC table allocation */ + scf_dscp_comtbl.tx_dscsize = + sizeof (scf_dscp_dsc_t) * (scf_dscp_comtbl.txdsc_maxcount + + SCF_TXDSC_LOCALCOUNT); + scf_dscp_comtbl.tx_dscp = + (scf_dscp_dsc_t *)kmem_zalloc(scf_dscp_comtbl.tx_dscsize, + KM_SLEEP); + + scf_dscp_comtbl.rx_dscsize = + sizeof (scf_dscp_dsc_t) * (scf_dscp_comtbl.rxdsc_maxcount); + scf_dscp_comtbl.rx_dscp = + (scf_dscp_dsc_t *)kmem_zalloc(scf_dscp_comtbl.rx_dscsize, + KM_SLEEP); + + /* Tx SRAM table allocation */ + scf_dscp_comtbl.tx_sramsize = + sizeof (scf_tx_sram_t) * scf_dscp_comtbl.txsram_maxcount; + scf_dscp_comtbl.tx_sramp = + (scf_tx_sram_t *)kmem_zalloc(scf_dscp_comtbl.tx_sramsize, + KM_SLEEP); + + /* + * TxDSC table initialization + */ + /* Get TxDSC table address */ + dsc_p = scf_dscp_comtbl.tx_dscp; + for (ii = 0; ii < scf_dscp_comtbl.txdsc_maxcount; ii++, dsc_p++) { + /* Init SRAM offset */ + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Set Tx offset */ + scf_dscp_comtbl.tx_first = 0; + scf_dscp_comtbl.tx_last = + (uint16_t)(scf_dscp_comtbl.txdsc_maxcount - 1); + scf_dscp_comtbl.tx_put = 0; + scf_dscp_comtbl.tx_get = 0; + scf_dscp_comtbl.tx_local = (uint16_t)scf_dscp_comtbl.txdsc_maxcount; + scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local].dinfo.base.offset = + DSC_OFFSET_NOTHING; + + /* + * Tx STAM offset initialization + */ + /* Get Tx SRAM table address */ + sram_p = scf_dscp_comtbl.tx_sramp; + for (ii = 0; ii < scf_dscp_comtbl.txsram_maxcount; ii++, sram_p++) { + /* Init SRAM offset */ + sram_p->offset = + (uint16_t)(scf_dscp_comtbl.txbuffsize * ii / + DSC_OFFSET_CONVERT); + } + + /* Set Tx SRAM offset */ + scf_dscp_comtbl.tx_sram_first = 0; + scf_dscp_comtbl.tx_sram_last = (scf_dscp_comtbl.txsram_maxcount - 1); + scf_dscp_comtbl.tx_sram_put = 0; + + /* + * RxDSC table initialization + */ + /* Set Rx offset */ + scf_dscp_comtbl.rx_first = 0; + scf_dscp_comtbl.rx_last = + (uint16_t)(scf_dscp_comtbl.rxdsc_maxcount - 1); + scf_dscp_comtbl.rx_put = 0; + scf_dscp_comtbl.rx_get = 0; + + /* + * Main table initialization + */ + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Set table id */ + mainp->id = ii & DSC_CNTL_MASK_ID; + + /* Set event/recive queue max count */ + mainp->ev_maxcount = SCF_MB_EVQUE_MAXCOUNT; + mainp->rd_maxcount = SCF_RDQUE_MAXCOUNT; + mainp->rd_busycount = SCF_RDQUE_BUSYCOUNT; + + /* Set fint() condition variable */ + cv_init(&mainp->fini_cv, NULL, CV_DRIVER, NULL); + mainp->cv_init_flag = FLAG_ON; + + /* event/receive data queue table allocation */ + mainp->ev_quesize = + sizeof (scf_event_que_t) * mainp->ev_maxcount; + mainp->ev_quep = + (scf_event_que_t *)kmem_zalloc(mainp->ev_quesize, + KM_SLEEP); + mainp->rd_datasize = + sizeof (scf_rdata_que_t) * mainp->ev_maxcount; + mainp->rd_datap = + (scf_rdata_que_t *)kmem_zalloc(mainp->rd_datasize, + KM_SLEEP); + + /* Event queue initialization */ + for (jj = 0; jj < mainp->ev_maxcount; jj++) { + mainp->ev_quep[jj].mevent = (scf_event_t)(-1); + } + mainp->ev_first = 0; + mainp->ev_last = (uint16_t)(mainp->ev_maxcount - 1); + mainp->ev_put = 0; + mainp->ev_get = 0; + + /* Receive data queue initialization */ + mainp->rd_first = 0; + mainp->rd_last = (uint16_t)(mainp->rd_maxcount - 1); + mainp->rd_put = 0; + mainp->rd_get = 0; + } + + /* Initialize success flag ON */ + scf_dscp_comtbl.dscp_init_flag = FLAG_ON; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_fini() + * + * Description: DSCP control area release processing. + * + */ +void +scf_dscp_fini(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_fini() " + scf_dscp_main_t *mainp; /* Main table address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* + * Main table resources release + */ + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* Check fint() condition variable */ + if (mainp->cv_init_flag == FLAG_ON) { + /* Destroy fint() condition variable */ + cv_destroy(&mainp->fini_cv); + mainp->cv_init_flag = FLAG_OFF; + } + + /* Check event queue table allocation */ + if (mainp->ev_quep != NULL) { + /* Event queue table release */ + kmem_free(mainp->ev_quep, mainp->ev_quesize); + mainp->ev_quep = NULL; + } + + /* Check receive data table queue allocation */ + if (mainp->rd_datap != NULL) { + /* Receive data queue table release */ + kmem_free(mainp->rd_datap, mainp->rd_datasize); + mainp->rd_datap = NULL; + } + } + + /* + * DSCP common table resources release + */ + /* All timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + scf_timer_stop(SCF_TIMERCD_DSCP_CALLBACK); + scf_timer_stop(SCF_TIMERCD_DSCP_BUSY); + + /* All DSC buffer release */ + scf_dscp_dscbuff_free_all(); + + /* Check TxDSC table allocation */ + if (scf_dscp_comtbl.tx_dscp != NULL) { + /* TxDSC table release */ + kmem_free(scf_dscp_comtbl.tx_dscp, + scf_dscp_comtbl.tx_dscsize); + scf_dscp_comtbl.tx_dscp = NULL; + } + + /* Check RxDSC table allocation */ + if (scf_dscp_comtbl.rx_dscp != NULL) { + /* RxDSC table release */ + kmem_free(scf_dscp_comtbl.rx_dscp, + scf_dscp_comtbl.rx_dscsize); + scf_dscp_comtbl.rx_dscp = NULL; + } + + /* Check Tx SRAM table allocation */ + if (scf_dscp_comtbl.tx_sramp != NULL) { + /* Tx SRAM table release */ + kmem_free(scf_dscp_comtbl.tx_sramp, + scf_dscp_comtbl.tx_sramsize); + scf_dscp_comtbl.tx_sramp = NULL; + } + + /* Initialize success flag ON */ + scf_dscp_comtbl.dscp_init_flag = FLAG_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_start() + * + * Description: DSCP interface start processing. + * + */ +void +scf_dscp_start(uint32_t factor) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_start() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start factor = 0x%08x", + factor); + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_ON) { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + } + + /* Check pending send TxDSC */ + if (scf_dscp_comtbl.tx_dsc_count != 0) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_TXREQ_SEND_WAIT: /* TxDSC status (SB2) */ + /* Check send data length */ + if (dsc_p->dinfo.base.length != 0) { + /* Try again SRAM transfer */ + + /* Change TxDSC status (SB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_SRAM_TRANS_WAIT); + } + break; + + case SCF_TX_ST_TXACK_RECV_WAIT: /* TxDSC status (SC0) */ + case SCF_TX_ST_TXEND_RECV_WAIT: /* TxDSC status (SC1) */ + /* Try again TxREQ send */ + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + break; + + default: + /* TxDSC status != SB2 or SC0 or SC1 is NOP */ + break; + } + } + + /* Check pending RxDSC */ + while (scf_dscp_comtbl.rx_dsc_count != 0) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_get == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_get++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count--; + + /* RxREQ receive exec flag OFF */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + } + + /* Check SCF path change */ + if (factor == FACTOR_PATH_CHG) { + /* Tx re-try counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + + /* + * SCF path change flag ON : + * local control data send(DSCP_PATH) + */ + scf_dscp_comtbl.dscp_path_flag = FLAG_ON; + } else { + /* SCF online processing */ + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* + * Connect check flag ON : + * local control data send(CONN_CHK) + */ + mainp->conn_chk_flag = FLAG_ON; + break; + + default: + /* Connect check flag OFF */ + mainp->conn_chk_flag = FLAG_OFF; + break; + } + } + } + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_stop() + * + * Description: DSCP interface stop processing. + * + */ +void +scf_dscp_stop(uint32_t factor) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_stop() " + scf_dscp_main_t *mainp; /* Main table address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start factor = 0x%08x", + factor); + + /* Check stop factor */ + if ((factor == FACTOR_PATH_HALT) || (factor == FACTOR_PATH_STOP)) { + /* memo counter up */ + scf_dscp_comtbl.scf_stop_memo_cnt++; + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + + break; + + case SCF_ST_CLOSE_TXEND_RECV_WAIT: + /* Main status (D0) */ + /* Signal to fini() wait */ + mainp->fini_wait_flag = FLAG_OFF; + cv_signal(&mainp->fini_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &mainp->fini_cv, sizeof (kcondvar_t)); + break; + + default: + /* Main status != B0 or C0 or D0 is NOP */ + break; + } + } + } + + /* Tx timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + scf_timer_stop(SCF_TIMERCD_DSCP_BUSY); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_intr() + * + * Description: The corresponding function is called according to the + * interruption factor from SCF. + * + */ +void +scf_dscp_intr(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_intr() " + /* Working value : Interrupt check flag */ + int interrupt = FLAG_OFF; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get DSR register */ + statep->reg_dsr = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + SC_DBG_DRV_TRACE(TC_R_DSR, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + + /* DSR register interrupt clear */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, &statep->scf_regs->DSR, + statep->reg_dsr); + SC_DBG_DRV_TRACE(TC_W_DSR, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + + /* Regster read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + + SCF_DBG_TEST_INTR_DSCP_DSR(statep); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DSR = 0x%02x", statep->reg_dsr); + + if ((statep->reg_dsr & DSR_RxREQ) != 0) { /* RxREQ interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "RxREQ interrupt"); + + interrupt = FLAG_ON; + /* Get RxDCR register */ + statep->reg_rxdcr_c_flag = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_C_FLAG); + SC_DBG_DRV_TRACE(TC_R_RxDCR_C_FLAG, __LINE__, + &statep->reg_rxdcr_c_flag, + sizeof (statep->reg_rxdcr_c_flag)); + + statep->reg_rxdcr_c_offset = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_OFFSET); + SC_DBG_DRV_TRACE(TC_R_RxDCR_OFFSET, __LINE__, + &statep->reg_rxdcr_c_offset, + sizeof (statep->reg_rxdcr_c_offset)); + + statep->reg_rxdcr_c_length = + SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_LENGTH); + SC_DBG_DRV_TRACE(TC_R_RxDCR_LENGTH, __LINE__, + &statep->reg_rxdcr_c_length, + sizeof (statep->reg_rxdcr_c_length)); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXREQ); + + SCF_DBG_TEST_INTR_DSCP_RXTX(statep, statep->reg_dsr); + + SC_DBG_DRV_TRACE(TC_RxREQ, __LINE__, + &statep->reg_rxdcr_c_flag, 8); + + SCFDBGMSG3(SCF_DBGFLAG_REG, "RxDCR = 0x%04x 0x%04x 0x%08x", + statep->reg_rxdcr_c_flag, statep->reg_rxdcr_c_offset, + statep->reg_rxdcr_c_length); + + /* Call RxRERQ interrupt processing */ + scf_dscp_rxreq_recv(statep); + } + + if ((statep->reg_dsr & DSR_TxACK) != 0) { /* TxACK interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "TxACK interrupt"); + + interrupt = FLAG_ON; + + SC_DBG_DRV_TRACE(TC_TxACK, __LINE__, NULL, 0); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXACK); + + /* Call TxACK interrupt processing */ + scf_dscp_txack_recv(statep); + } + + if ((statep->reg_dsr & DSR_TxEND) != 0) { /* TxEND interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "TxEND interrupt"); + + interrupt = FLAG_ON; + + /* Get TxDSR register */ + statep->reg_txdsr_c_flag = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDSR_C_FLAG); + SC_DBG_DRV_TRACE(TC_R_TxDSR_C_FLAG, __LINE__, + &statep->reg_txdsr_c_flag, + sizeof (statep->reg_txdsr_c_flag)); + + statep->reg_txdsr_c_offset = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDSR_OFFSET); + SC_DBG_DRV_TRACE(TC_R_TxDSR_OFFSET, __LINE__, + &statep->reg_txdsr_c_offset, + sizeof (statep->reg_txdsr_c_offset)); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXEND); + + SCF_DBG_TEST_INTR_DSCP_RXTX(statep, DSR_TxEND); + + SC_DBG_DRV_TRACE(TC_TxEND, __LINE__, + &statep->reg_txdsr_c_flag, 4); + + SCFDBGMSG2(SCF_DBGFLAG_REG, "TxDSR = 0x%04x 0x%04x", + statep->reg_txdsr_c_flag, statep->reg_txdsr_c_offset); + + /* Call TxEND interrupt processing */ + scf_dscp_txend_recv(statep); + } + + if (interrupt == FLAG_OFF) { + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + statep->no_int_dsr_cnt++; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Timeout function : from SCF driver timer contorol function + */ + +/* + * scf_dscp_ack_tout() + * + * Description: TxACK reception surveillance timeout processing is performed. + * SCF path change factor. + * + */ +void +scf_dscp_ack_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_ack_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + int path_ret; /* SCF path status return value */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_ack_tout; + } + + /* memo counter up */ + scf_dscp_comtbl.tx_ackto_memo_cnt++; + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXACK_RECV_WAIT) { + /* TxDSC status (SC0) */ + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_ackto_retry_cnt < + scf_dscp_comtbl.tx_ackto_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_ackto_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* TxACK re-try timeout error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_ackto_retry_cnt, + sizeof (scf_dscp_comtbl.tx_ackto_retry_cnt)); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_ONLINE) { + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + cmn_err(CE_WARN, + "%s,DSCP ack response timeout " + "occurred. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_ACKTO); + + /* SCF path change */ + statep->scf_herr |= HERR_DSCP_ACKTO; + scf_path_change(statep); + } + } + } + +/* + * END_dscp_ack_tout + */ + END_dscp_ack_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_end_tout() + * + * Description: TxEND reception surveillance timeout processing is performed. + * SCF path change factor. + * + */ +void +scf_dscp_end_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_end_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + int path_ret; /* SCF path status return value */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_end_tout; + } + + /* memo counter up */ + scf_dscp_comtbl.tx_endto_memo_cnt++; + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXEND_RECV_WAIT) { + /* TxDSC status (SC1) */ + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_endto_retry_cnt < + scf_dscp_comtbl.tx_endto_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_endto_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* TxEND re-try timeout error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_endto_retry_cnt, + sizeof (scf_dscp_comtbl.tx_endto_retry_cnt)); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_ONLINE) { + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + cmn_err(CE_WARN, + "%s,DSCP end response timeout " + "occurred. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_ENDTO); + + /* SCF path change */ + statep->scf_herr |= HERR_DSCP_ENDTO; + scf_path_change(statep); + } + } + } + +/* + * END_dscp_end_tout + */ + END_dscp_end_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_busy_tout() + * + * Description: Busy timeout performs TxREQ transmission again. + * + */ +void +scf_dscp_busy_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_busy_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check pending send TxDSC or local control TxDSC */ + if ((scf_dscp_comtbl.tx_dsc_count == 0) && + (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF)) { + goto END_dscp_busy_tout; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXREQ_SEND_WAIT) { + /* TxDSC status (SB2) */ + /* Call send matrix */ + scf_dscp_send_matrix(); + } + +/* + * END_dscp_busy_tout + */ + END_dscp_busy_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_callback_tout() + * + * Description: Callbak timeout performs soft interrupt again. + * + */ +void +scf_dscp_callback_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_callback_tout() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Soft interrupt : call scf_dscp_callback() */ + if (mutex_tryenter(&scf_comtbl.si_mutex) != 0) { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_ON; + ddi_trigger_softintr(scf_comtbl.scf_softintr_id); + mutex_exit(&scf_comtbl.si_mutex); + } + + /* Callback timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_callback() + * + * Description: Event queue is taken out and a callback entry is called. + * + */ +void +scf_dscp_callback(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_callback() " + scf_dscp_main_t *mainp; /* Main table address */ + /* Working value : event_handler */ + void (*wkevent_handler)(scf_event_t, void *); + scf_event_t wkmevent; /* Working value : mevent */ + void *wkarg; /* Working value : arg */ + /* Working value : next event processing check flag */ + int event_flag = FLAG_OFF; + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check callback entry exec flag */ + if (scf_dscp_comtbl.callback_exec_flag == FLAG_ON) { + goto END_dscp_callback; + } + + /* Set callback entry exec flag */ + scf_dscp_comtbl.callback_exec_flag = FLAG_ON; + +/* + * CALLBACK_START + */ + CALLBACK_START: + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + /* Check all main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check event count */ + if (mainp->ev_count != 0) { + /* Next event processing flag ON */ + event_flag = FLAG_ON; + + /* Get event info */ + wkmevent = mainp->ev_quep[mainp->ev_get].mevent; + + /* Update event queue offset */ + if (mainp->ev_get == mainp->ev_last) { + mainp->ev_get = mainp->ev_first; + } else { + mainp->ev_get++; + } + + /* Update event queue count */ + mainp->ev_count--; + + /* Get callback enntry and arg */ + wkevent_handler = mainp->event_handler; + wkarg = mainp->arg; + + /* Check event_handler address */ + if (wkevent_handler != NULL) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: + /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: + /* Main status (C1) */ + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Call event handler */ + wkevent_handler(wkmevent, wkarg); + + SC_DBG_DRV_TRACE(TC_MB_CALLBACK, + __LINE__, &wkmevent, + sizeof (wkmevent)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, + "DSCP callback mevent = %d", + wkmevent); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + break; + + default: + /* + * Main status != C0 or C1 is NOP + */ + break; + } + } + } + } + + /* Check next event processing */ + if (event_flag == FLAG_ON) { + event_flag = FLAG_OFF; + goto CALLBACK_START; + } + + /* Clear callback entry exec flag */ + scf_dscp_comtbl.callback_exec_flag = FLAG_OFF; + +/* + * END_dscp_callback + */ + END_dscp_callback: + + /* CALLBACK timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + + +/* + * Interrupt function : from scf_dscp_intr() + */ + +/* + * scf_dscp_txack_recv() + * + * Description: TxACK reception processing is performed. + * + */ +/* ARGSUSED */ +void +scf_dscp_txack_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txack_recv() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_txack_recv; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXACK_RECV_WAIT) { + /* TxDSC status (SC0) */ + /* Error counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + + /* TxACK timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + + /* TxEND timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_END); + + /* Change TxDSC status (SC1) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXEND_RECV_WAIT); + } + +/* + * END_dscp_txack_recv + */ + END_dscp_txack_recv: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txend_recv() + * + * Description: TxEND reception is received and processing is carried out by + * completion information. + * + */ +void +scf_dscp_txend_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txend_recv() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_dscreg_t wk_dsc; /* Work TxDSC */ + /* Working value : TxDSC release check flag */ + int norel_txdsc = FLAG_OFF; + /* Working value : SCF path change flag */ + int path_change = FLAG_OFF; + int ii; /* Working value : counter */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_txend_recv; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Save TxDSR status information in TxDSC */ + wk_dsc.base.c_flag = statep->reg_txdsr_c_flag; + dsc_p->dinfo.bdsr.status = wk_dsc.bdsr.status; + SCFDBGMSG1(SCF_DBGFLAG_DSCP, "TxEND status = 0x%02x", + dsc_p->dinfo.bdsr.status); + + /* Check TxREQ offset and TxEND offset */ + if (dsc_p->dinfo.base.offset != statep->reg_txdsr_c_offset) { + goto END_dscp_txend_recv; + } + + /* TxACK and TxEND timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + /* + * Check mainp address or local control data(DSCP_PATH) + */ + if ((mainp == NULL) && + (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL)) { + goto END_dscp_txend_recv; + } + + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_TXACK_RECV_WAIT: + /* TxDSC status (SC0) */ + case SCF_TX_ST_TXEND_RECV_WAIT: + /* TxDSC status (SC1) */ + /* Check TxREQ end status */ + switch (dsc_p->dinfo.bdsr.status) { + case DSC_STATUS_NORMAL: /* Normal end */ + /* Error counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } + break; + + case DSC_STATUS_BUF_BUSY: /* Buffer busy */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_busy_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_busy_retry_cnt < + scf_dscp_comtbl.tx_busy_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_busy_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* TxREQ busy timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_BUSY); + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Buffer busy end re-try error */ + cmn_err(CE_WARN, + "%s,Buffer busy occurred in XSCF. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_INTERFACE: /* Interface error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_interface_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_interface_retry_cnt < + scf_dscp_comtbl.tx_interface_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_interface_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Interface error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the interface error by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Set hard error flag */ + statep->scf_herr |= HERR_DSCP_INTERFACE; + + /* SCF path change flag ON */ + path_change = FLAG_ON; + } + break; + + case DSC_STATUS_CONN_NAK: /* Connection refusal */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_nak_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_nak_retry_cnt < + scf_dscp_comtbl.tx_nak_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_nak_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Connection refusal end re-try error */ + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* Set hard error flag */ + statep->scf_herr |= HERR_DSCP_INTERFACE; + + /* SCF path change flag ON */ + path_change = FLAG_ON; + } + } + break; + + case DSC_STATUS_E_NOT_SUPPORT: /* Not support */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_notsuop_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_notsuop_retry_cnt < + scf_dscp_comtbl.tx_notsup_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_notsuop_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Not support end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the not support command " + "by XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_E_PARAM: /* Parameter error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_prmerr_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_prmerr_retry_cnt < + scf_dscp_comtbl.tx_prmerr_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_prmerr_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Parameter error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the invalid parameter by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_E_SEQUENCE: /* Sequence error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_seqerr_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_seqerr_retry_cnt < + scf_dscp_comtbl.tx_seqerr_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_seqerr_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Sequence error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the sequence error by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + default: /* Other status */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_other_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_other_retry_cnt < + scf_dscp_comtbl.tx_other_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_other_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Other error end re-try error */ + cmn_err(CE_WARN, + "%s,Invalid status value was notified " + "from XSCF. DSCP command = 0x%02x, " + "Status value = 0x%02x\n", + &statep->pathname[0], cmd, + (uchar_t) + dsc_p->dinfo.base.c_flag); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + } + break; + + default: + /* TxDSC status != SC0 or SC1 is NOP */ + break; + } + + /* Check TxDSC not release */ + if (norel_txdsc == FLAG_OFF) { + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + + /* Check use local control TxDSC flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_get == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_get = + scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_get++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count--; + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check putmsg busy release */ + if ((mainp->putmsg_busy_flag == FLAG_ON) && + (scf_dscp_comtbl.tx_dsc_count < + scf_dscp_comtbl.txdsc_busycount)) { + /* putmsg busy flag OFF */ + mainp->putmsg_busy_flag = FLAG_OFF; + + /* TxREL_BUSY notice to main matrix */ + scf_dscp_txrelbusy_notice(mainp); + } + } + } else { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* DSCP path change send flag OFF */ + scf_dscp_comtbl.dscp_path_flag = FLAG_OFF; + } + } + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check SCF path change flag */ + if (path_change == FLAG_OFF) { + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* SCF path change */ + scf_path_change(statep); + } + +/* + * END_dscp_txend_recv + */ + END_dscp_txend_recv: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxreq_recv() + * + * Description: TxREQ reception notifies to a main control matrix. + * + */ +void +scf_dscp_rxreq_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxreq_recv() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + uint16_t offset_low; /* Working value : offset */ + uint16_t offset_hight; /* Working value : offset */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check pending RxDSC */ + if (scf_dscp_comtbl.rx_dsc_count == 0) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_put]; + + /* Save RxDCR information in RxDSC */ + dsc_p->dinfo.base.c_flag = statep->reg_rxdcr_c_flag; + dsc_p->dinfo.base.offset = statep->reg_rxdcr_c_offset; + dsc_p->dinfo.base.length = statep->reg_rxdcr_c_length; + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + dsc_p->dinfo.base.dscp_datap = NULL; + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_put == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_put = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_put++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count++; + + /* RxREQ receive exec flag ON */ + scf_dscp_comtbl.rx_exec_flag = FLAG_ON; + + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + offset_low = (uint16_t)(scf_dscp_comtbl.txbuffsize * + scf_dscp_comtbl.txsram_maxcount / DSC_OFFSET_CONVERT); + + SCF_DBG_MAKE_LOOPBACK(offset_low); + + offset_hight = + (uint16_t)(offset_low + scf_dscp_comtbl.rxbuffsize * + scf_dscp_comtbl.rxsram_maxcount / DSC_OFFSET_CONVERT); + + /* Check mainp address and offset */ + if ((mainp != NULL) && + (((dsc_p->dinfo.base.offset >= offset_low) && + (dsc_p->dinfo.base.offset < offset_hight)) || + (dsc_p->dinfo.base.offset == DSC_OFFSET_NOTHING))) { + /* RxREQ notice to main matrix */ + scf_dscp_rxreq_notice(mainp); + } else { + /* Invalid "id" or "offset" */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Invalid id or offset"); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Main and Tx/Rx interface function + */ + +/* + * scf_dscp_txend_notice() + * + * Description: The TxEND reception is notified of by Tx matrix and handle it + * with data code. + * + */ +void +scf_dscp_txend_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txend_notice() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* TxREQ code check */ + switch (dsc_p->dinfo.bdcr.code) { + case DSC_CNTL_INIT_REQ: /* INIT_REQ */ + /* Check main status */ + if (mainp->status == SCF_ST_EST_TXEND_RECV_WAIT) { + /* Main status (B0) */ + /* Check end status */ + if (dsc_p->dinfo.bdsr.status == DSC_STATUS_NORMAL) { + /* SCF_MB_CONN_OK event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_CONN_OK); + + /* Change main status (C0) */ + SCF_SET_STATUS(mainp, SCF_ST_ESTABLISHED); + } else { + /* Not normal end status */ + + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + } + } + break; + + case DSC_CNTL_FINI_REQ: /* FINI_REQ */ + /* Check main status */ + if (mainp->status == SCF_ST_CLOSE_TXEND_RECV_WAIT) { + /* Main status (D0) */ + /* Signal to fini() wait */ + mainp->fini_wait_flag = FLAG_OFF; + cv_signal(&mainp->fini_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &mainp->fini_cv, + sizeof (kcondvar_t)); + } + break; + + case DSC_CNTL_CONN_CHK: /* CONN_CHK */ + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* CONN_CHK flag OFF */ + mainp->conn_chk_flag = FLAG_OFF; + /* Check end status */ + if (dsc_p->dinfo.bdsr.status != DSC_STATUS_NORMAL) { + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + } + break; + + default: + /* Main status != B0 or C0 is NOP */ + break; + } + break; + + case DSC_CNTL_DATA_REQ: /* DATA_REQ */ + /* Tx DATA_REQ ok counter up */ + mainp->memo_tx_data_req_ok_cnt++; + break; + + default: + /* Undefine TxREQ code is NOP */ + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txrelbusy_notice() + * + * Description: Tx busy release is notified of by Tx matrix and perform event + * queue processing. + * + */ +void +scf_dscp_txrelbusy_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txrelbusy_notice() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { /* Main status (C0) */ + /* SCF_MB_SPACE event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_SPACE); + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxreq_notice() + * + * Description: The RxREQ reception is notified of by Rx matrix and handle it + * with data code. + * + */ +void +scf_dscp_rxreq_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxreq_notice() " + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* RxREQ code check */ + switch (dsc_p->dinfo.bdcr.code) { + case DSC_CNTL_INIT_REQ: /* INIT_REQ */ + /* Set end status : Not support */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_NOT_SUPPORT; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_FINI_REQ: /* FINI_REQ */ + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + break; + + default: + /* Main status != B0 or C0 is NOP */ + break; + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_DATA_REQ: /* DATA_REQ */ + /* Rx DATA_REQ counter up */ + mainp->memo_rx_data_req_cnt++; + + /* Check receive data length */ + if (dsc_p->dinfo.base.length <= scf_dscp_comtbl.maxdatalen) { + /* Check receive data queue space */ + if (mainp->rd_count < mainp->rd_busycount) { + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { + /* Main status (C0) */ + /* Change RxDSC status (RB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXACK_SEND_WAIT); + } else { + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXEND_SEND_WAIT); + } + } else { + /* No space of receive data queue */ + + /* Set end status : Buffer busy */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_BUF_BUSY; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXEND_SEND_WAIT); + } + } else { + /* Invalid deta length */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.length, + sizeof (dsc_p->dinfo.base.length)); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_CONN_CHK: /* CONN_CHK */ + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { + /* Main status (C0) */ + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + } else { + /* Set end status : Connection refusal */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_CONN_NAK; + } + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + default: + /* Invalid RxREQ code */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &dsc_p->dinfo.base.c_flag, + TC_INFO_SIZE); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxdata_notice() + * + * Description: It is notified from a Rx control matrix, the received data are + * read from SRAM, + * and the notice of a receive data event is performed. + * + */ +void +scf_dscp_rxdata_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxdata_notice() " + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + scf_rdata_que_t *rdt_p; /* Receive data queue address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check receive data queue space */ + if (mainp->rd_count < mainp->rd_busycount) { + /* Receive data queing */ + rdt_p = &mainp->rd_datap[mainp->rd_put]; + rdt_p->rdatap = dsc_p->dinfo.base.dscp_datap; + dsc_p->dinfo.base.dscp_datap = NULL; + rdt_p->length = dsc_p->dinfo.base.length; + + /* Update receive data queue offset */ + if (mainp->rd_put == mainp->rd_last) { + mainp->rd_put = mainp->rd_first; + } else { + mainp->rd_put++; + } + + /* Update receive data queue count */ + mainp->rd_count++; + + /* SCF_MB_MSG_DATA event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_MSG_DATA); + + /* Rx DATA_REQ ok counter up */ + mainp->memo_rx_data_req_ok_cnt++; + } else { + /* No space of receive data queue */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &mainp->rd_count, + sizeof (mainp->rd_count)); + SCFDBGMSG(SCF_DBGFLAG_DSCP, + "No space of receive data queue"); + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Buffer busy */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_BUF_BUSY; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + break; + + case SCF_ST_CLOSE_TXEND_RECV_WAIT: /* Main status (D0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + + default: + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &mainp->status, + TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Sequence error"); + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Sequence error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_SEQUENCE; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Tx subroutine function + */ + +/* + * scf_dscp_send_matrix() + * + * Description: The Request to Send by a Tx descriptor state is performed. + * + */ +void +scf_dscp_send_matrix(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_send_matrix() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + /* Working value : next processing check flag */ + int next_send_req = FLAG_OFF; + int path_ret; /* SCF path status return value */ + int timer_ret; /* Timer check return value */ + int ii; /* Working value : counter */ + uint16_t tx_local = scf_dscp_comtbl.tx_local; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + SCF_DBG_MAKE_NO_DSCP_PATH(scf_dscp_comtbl.dscp_path_flag); + +/* + * SEND_MATRIX_START + */ + SEND_MATRIX_START: + + /* Check use local control TxDSC send */ + if ((scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) && + /* Check DSCP path change data send */ + (scf_dscp_comtbl.dscp_path_flag == FLAG_ON)) { + /* Set use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_ON; + + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + + /* Make Tx descriptor : DSCP_PATH */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = DSC_CNTL_LOCAL; + dsc_p->dinfo.bdcr.code = DSC_CNTL_DSCP_PATH; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + } else if ((scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) && + (scf_dscp_comtbl.dscp_path_flag == FLAG_OFF)) { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + + /* Get top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* + * Check DSCP connect data send and not local + * control TxDSC send + */ + if ((mainp->conn_chk_flag == FLAG_OFF) || + (scf_dscp_comtbl.tx_local_use_flag == + FLAG_ON)) { + break; + } + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: + /* Main status (B0) */ + case SCF_ST_ESTABLISHED: + /* Main status (C0) */ + /* + * Set use local control TxDSC flag + */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_ON; + + /* + * Get local data TxDSC address + */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + + /* + * Make Tx descriptor : CONN_CHK + */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & 0x0f; + dsc_p->dinfo.bdcr.code = DSC_CNTL_CONN_CHK; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + break; + + default: + /* + * Clear DSCP connect check flag + */ + mainp->conn_chk_flag = FLAG_OFF; + break; + } + } + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + } + + /* Check pending send TxDSC or local control TxDSC */ + if ((scf_dscp_comtbl.tx_dsc_count == 0) && + (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF)) { + goto END_dscp_send_matrix; + } + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_IDLE: /* TxDSC status (SA0) */ + /* TxDSC status == SA0 is next processing */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_get == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_get = + scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_get++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count--; + } else { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + } + + /* Next processing flag ON */ + next_send_req = FLAG_ON; + break; + + case SCF_TX_ST_SRAM_TRANS_WAIT: /* TxDSC status (SB0) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Data copy to SRAM */ + ii = dsc_p->dinfo.base.offset * DSC_OFFSET_CONVERT; + wk_in_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = (uint8_t *)&statep->scf_dscp_sram->DATA[ii]; + for (ii = 0; ii < dsc_p->dinfo.base.length; + ii++, wk_in_p++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_dscp_sram_handle, + wk_out_p, *wk_in_p); + } + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Next processing flag ON */ + next_send_req = FLAG_ON; + break; + + case SCF_TX_ST_TXREQ_SEND_WAIT: /* TxDSC status (SB2) */ + /* Get timer status */ + timer_ret = scf_timer_check(SCF_TIMERCD_DSCP_BUSY); + /* Check TxREQ busy timer exec */ + if (timer_ret == SCF_TIMER_EXEC) { + break; + } + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + /* TxREQ send */ + scf_dscp_txreq_send(statep, dsc_p); + + /* Check send data length */ + if (dsc_p->dinfo.base.length != 0) { + /* TxACK timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_ACK); + + /* + * Change TxDSC status (SC0) + */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXACK_RECV_WAIT); + } else { + /* TxEND timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_END); + + /* + * Change TxDSC status (SC1) + */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXEND_RECV_WAIT); + } + } + break; + + default: + /* TxDSC status != SA0 or SB0 or SB2 is NOP */ + break; + } + + /* Check next send processing */ + if (next_send_req == FLAG_ON) { + next_send_req = FLAG_OFF; + goto SEND_MATRIX_START; + } + +/* + * END_dscp_send_matrix + */ + END_dscp_send_matrix: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txreq_send() + * + * Description: TxREQ is transmitted by hard access. + * + */ +void +scf_dscp_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txreq_send() " + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + uint32_t wkleng; /* Working value : length */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Set control flag */ + dsc_p->dinfo.bdsr.status = 0; + dsc_p->dinfo.base.c_flag |= DSC_FLAG_DEFAULT; + + /* Write TxDCR register */ + statep->reg_txdcr_c_flag = dsc_p->dinfo.base.c_flag; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_C_FLAG, statep->reg_txdcr_c_flag); + SC_DBG_DRV_TRACE(TC_W_TxDCR_C_FLAG, __LINE__, + &statep->reg_txdcr_c_flag, sizeof (statep->reg_txdcr_c_flag)); + + statep->reg_txdcr_c_offset = dsc_p->dinfo.base.offset; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_OFFSET, statep->reg_txdcr_c_offset); + SC_DBG_DRV_TRACE(TC_W_TxDCR_OFFSET, __LINE__, + &statep->reg_txdcr_c_offset, + sizeof (statep->reg_txdcr_c_offset)); + + statep->reg_txdcr_c_length = dsc_p->dinfo.base.length; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_LENGTH, statep->reg_txdcr_c_length); + SC_DBG_DRV_TRACE(TC_W_TxDCR_LENGTH, __LINE__, + &statep->reg_txdcr_c_length, + sizeof (statep->reg_txdcr_c_length)); + + /* Write DCR register : TxREQ interrupt */ + statep->reg_dcr = DCR_TxREQ; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_TxREQ, __LINE__, &statep->reg_txdcr_c_flag, 8); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + SCFDBGMSG3(SCF_DBGFLAG_REG, "TxDCR = 0x%04x 0x%04x 0x%08x", + statep->reg_txdcr_c_flag, statep->reg_txdcr_c_offset, + statep->reg_txdcr_c_length); + + /* TxREQ send exec flag ON */ + scf_dscp_comtbl.tx_exec_flag = FLAG_ON; + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXREQ); + if (dsc_p->dinfo.base.length != 0) { + wk_in_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = (uint8_t *)&statep->memo_scf_drvtrc.INFO[0]; + if (dsc_p->dinfo.base.length > + sizeof (statep->memo_scf_drvtrc.INFO)) { + wkleng = sizeof (statep->memo_scf_drvtrc.INFO); + } else { + wkleng = dsc_p->dinfo.base.length; + } + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_DSCP_SENDDATA); + } + + SCF_DBG_TEST_TXREQ_SEND(statep, dsc_p); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Rx subroutine function + */ + +/* + * scf_dscp_recv_matrix() + * + * Description: TxREQ received performs the corresponding response request. + * + */ +void +scf_dscp_recv_matrix(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_recv_matrix() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + caddr_t wkaddr; /* Working value : buffer address */ + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + uint32_t wkleng; /* Working value : length */ + uint32_t info_size; + /* Working value : next receive processing check flag */ + int next_resp_req = FLAG_OFF; + int path_ret; /* SCF path status return value */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + +/* + * RECV_MATRIX_START + */ + RECV_MATRIX_START: + + /* Check pending RxDSC */ + if (scf_dscp_comtbl.rx_dsc_count == 0) { + goto END_dscp_recv_matrix; + } + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check RxDSC status */ + switch (dsc_p->status) { + case SCF_RX_ST_RXACK_SEND_WAIT: /* RxDSC status (RB0) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Check receive data length */ + if (dsc_p->dinfo.base.length != 0) { + /* Rx buffer allocation */ + wkaddr = (caddr_t)kmem_zalloc(dsc_p->dinfo.base.length, + KM_NOSLEEP); + + /* Set Rx buffer address */ + dsc_p->dinfo.base.dscp_datap = wkaddr; + + /* RxACK send */ + scf_dscp_rxack_send(statep); + + /* Change RxDSC status (RB1) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_SRAM_TRANS_WAIT); + } else { + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + } + /* Next receive processing flag ON */ + next_resp_req = FLAG_ON; + + break; + + case SCF_RX_ST_SRAM_TRANS_WAIT: /* RxDSC status (RB1) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + /* Check mainp address */ + if (mainp != NULL) { + /* Data copy from SRAM */ + ii = dsc_p->dinfo.base.offset * DSC_OFFSET_CONVERT; + wk_in_p = &statep->scf_dscp_sram->DATA[ii]; + wk_out_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + for (ii = 0; ii < dsc_p->dinfo.base.length; ii++, + wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_dscp_sram_handle, wk_in_p); + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* STAM trace */ + info_size = sizeof (statep->memo_scf_drvtrc.INFO); + if (dsc_p->dinfo.base.length != 0) { + wk_in_p = + (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = &statep->memo_scf_drvtrc.INFO[0]; + if (dsc_p->dinfo.base.length > info_size) { + wkleng = info_size; + } else { + wkleng = dsc_p->dinfo.base.length; + } + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_DSCP_RECVDATA); + } + + /* Receive data notice to main matrix */ + scf_dscp_rxdata_notice(mainp); + } else { + /* Invalid "id" */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Invalid id"); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + + /* Next receive processing flag ON */ + next_resp_req = FLAG_ON; + break; + + case SCF_RX_ST_RXEND_SEND_WAIT: /* RxDSC status (RB3) */ + /* Is SCF path online? */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* RxEND send */ + scf_dscp_rxend_send(statep, dsc_p); + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_get == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_get++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count--; + + /* RxREQ receive exec flag OFF */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + break; + + default: + /* RxDSC status == RA0 is NOP */ + break; + } + + /* Check next receive processing */ + if (next_resp_req == FLAG_ON) { + next_resp_req = FLAG_OFF; + goto RECV_MATRIX_START; + } + +/* + * END_dscp_recv_matrix + */ + END_dscp_recv_matrix: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxack_send() + * + * Description: RxACK is transmitted by hard access. + * + */ +void +scf_dscp_rxack_send(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxack_send() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Write DCR register : RxACK interrupt */ + statep->reg_dcr = DCR_RxACK; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_RxACK, __LINE__, NULL, 0); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxend_send() + * + * Description: RxEND is transmitted by hard access. + * + */ +void +scf_dscp_rxend_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxend_send() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Write RxDSR register */ + statep->reg_rxdsr_c_flag = dsc_p->dinfo.base.c_flag; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDSR_C_FLAG, statep->reg_rxdsr_c_flag); + SC_DBG_DRV_TRACE(TC_W_RxDSR_C_FLAG, __LINE__, &statep->reg_rxdsr_c_flag, + sizeof (statep->reg_rxdsr_c_flag)); + + statep->reg_rxdsr_c_offset = dsc_p->dinfo.base.offset; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDSR_OFFSET, statep->reg_rxdsr_c_offset); + SC_DBG_DRV_TRACE(TC_W_RxDSR_OFFSET, __LINE__, + &statep->reg_rxdsr_c_offset, + sizeof (statep->reg_rxdsr_c_offset)); + + /* Write DCR register : RxEND interrupt */ + statep->reg_dcr = DCR_RxEND; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_RxEND, __LINE__, &statep->reg_rxdsr_c_flag, 4); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + SCFDBGMSG2(SCF_DBGFLAG_REG, "RxDSR = 0x%04x 0x%04x", + statep->reg_rxdsr_c_flag, statep->reg_rxdsr_c_offset); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXEND); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * subroutine function + */ + +/* + * scf_dscp_dscbuff_free_all() + * + * Description: All descripter buffer release processing. + * + */ +void +scf_dscp_dscbuff_free_all(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_dscbuff_free_all() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get TxDSC address */ + dsc_p = scf_dscp_comtbl.tx_dscp; + + if (dsc_p != NULL) { + /* Check TxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.txdsc_maxcount; ii++, + dsc_p++) { + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_IDLE) { + continue; + } + /* TxDSC status not (SA0) */ + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + } + + /* Tx flag initialization */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + scf_dscp_comtbl.dscp_path_flag = FLAG_OFF; + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* TxDSC counter/offset initialization */ + scf_dscp_comtbl.tx_get = scf_dscp_comtbl.tx_put; + scf_dscp_comtbl.tx_dsc_count = 0; + + /* Tx re-try counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + } + + /* Get RxDSC address */ + dsc_p = scf_dscp_comtbl.rx_dscp; + + if (dsc_p != NULL) { + /* Check RxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.rxdsc_maxcount; ii++, + dsc_p++) { + /* Check RxDSC status */ + if (dsc_p->status == SCF_RX_ST_IDLE) { + continue; + } + /* RxDSC status not (RA0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + } + + /* Rx flag initialization */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + + /* RxDSC counter/offset initialization */ + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_put; + scf_dscp_comtbl.rx_dsc_count = 0; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txdscbuff_free() + * + * Description: Tx descripter buffer release processing. + * + */ +void +scf_dscp_txdscbuff_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txdscbuff_free() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + uint16_t wkget; /* Working value : get offset */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get TxDSC offser */ + wkget = scf_dscp_comtbl.tx_get; + + /* Check TxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.tx_dsc_count; ii++) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[wkget]; + + /* Update Tx descriptor offset */ + if (wkget == scf_dscp_comtbl.tx_last) { + wkget = scf_dscp_comtbl.tx_first; + } else { + wkget++; + } + + /* Check main use data */ + if (mainp->id != dsc_p->dinfo.bdcr.id) { + continue; + } + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_SRAM_TRANS_WAIT: + /* TxDSC status not (SB0) */ + case SCF_TX_ST_TXREQ_SEND_WAIT: + /* TxDSC status not (SB2) */ + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + break; + + default: + /* TxDSC status != SB0 or SB2 is NOP */ + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxdscbuff_free() + * + * Description: Rx descripter buffer release processing. + * + */ +void +scf_dscp_rxdscbuff_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxdscbuff_free() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + uint16_t wkget; /* Working value : get offset */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC offser */ + wkget = scf_dscp_comtbl.rx_get; + + /* Check RxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.rx_dsc_count; ii++) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[wkget]; + + /* Update Rx descriptor offset */ + if (wkget == scf_dscp_comtbl.rx_last) { + wkget = scf_dscp_comtbl.rx_first; + } else { + wkget++; + } + + /* Check main use data */ + if (mainp->id != dsc_p->dinfo.bdcr.id) { + continue; + } + /* Check RxDSC status */ + if (dsc_p->status != SCF_RX_ST_IDLE) { + /* TxDSC status not (RA0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Rx flag initialization */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + + /* RxDSC counter/offset initialization */ + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_put; + scf_dscp_comtbl.rx_dsc_count = 0; + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rdata_free() + * + * Description: All receive data buffer release processing. + * + */ +void +scf_dscp_rdata_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rdata_free() " + /* Current receive data queue address */ + scf_rdata_que_t *rdt_p; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + while (mainp->rd_count != 0) { + /* Get receive data queue address */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + + /* Check receive data buffer */ + if (rdt_p->rdatap != NULL) { + /* Receve data release */ + kmem_free(rdt_p->rdatap, rdt_p->length); + rdt_p->rdatap = NULL; + } + + /* Update receive data queue */ + if (mainp->rd_get == mainp->rd_last) { + mainp->rd_get = mainp->rd_first; + } else { + mainp->rd_get++; + } + + /* Update receive data queue count */ + mainp->rd_count--; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_event_queue() + * + * Description: Event queueing processing. + * + */ +void +scf_dscp_event_queue(scf_dscp_main_t *mainp, scf_event_t mevent) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_event_queue() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check DISC ERROR event */ + if (mevent == SCF_MB_DISC_ERROR) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + } + + /* Event queing */ + mainp->ev_quep[mainp->ev_put].mevent = mevent; + + /* Update event queue offset */ + if (mainp->ev_put == mainp->ev_last) { + mainp->ev_put = mainp->ev_first; + } else { + mainp->ev_put++; + } + + /* Update event queue count */ + mainp->ev_count++; + + /* Soft interrupt : call scf_dscp_callback() */ + if (mutex_tryenter(&scf_comtbl.si_mutex) != 0) { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_ON; + ddi_trigger_softintr(scf_comtbl.scf_softintr_id); + mutex_exit(&scf_comtbl.si_mutex); + } + + /* Callback timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_event_queue_free() + * + * Description: Event queue release processing. + * + */ +void +scf_dscp_event_queue_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_event_queue_free() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* All queing event release */ + mainp->ev_get = mainp->ev_put; + mainp->ev_count = 0; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_mkey2mainp() + * + * Description: Get MAIN control table address processing by mkey. + * + */ +scf_dscp_main_t * +scf_dscp_mkey2mainp(mkey_t mkey) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_mkey2mainp() " + /* Return value : Main table address */ + scf_dscp_main_t *mainp = NULL; + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + for (ii = 0; ii < MBIF_MAX; ii++) { + /* Check "mkey" at search table */ + if (mkey == scf_dscp_mkey_search[ii]) { + /* Set mainp address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[ii]; + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); + return (mainp); +} + + +/* + * scf_dscp_id2mainp() + * + * Description: Get MAIN control table address processing by id. + * + */ +scf_dscp_main_t * +scf_dscp_id2mainp(uint8_t id) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_id2mainp() " + /* Return value : Main table address */ + scf_dscp_main_t *mainp = NULL; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check "id" */ + if (id < MBIF_MAX) { + /* Set mainp address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[id]; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); + return (mainp); +} + + +/* + * scf_dscp_sram_get() + * + * Description: Tx SRAM alloc processing. + * + */ +uint16_t +scf_dscp_sram_get(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_sram_get() " + scf_tx_sram_t *sram_p; /* Tx SRAM table address */ + int ii; /* Working value : counter */ + /* Return value : Tx SRAM offset */ + uint16_t offset = TX_SRAM_GET_ERROR; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check Tx SRAM space */ + if (scf_dscp_comtbl.tx_sram_count >= + scf_dscp_comtbl.txsram_maxcount) { + goto END_dscp_sram_get; + } + + /* Check all Tx SRAM table */ + for (ii = 0; ii < scf_dscp_comtbl.txsram_maxcount; ii++) { + /* Get Tx SRAM table address */ + sram_p = &scf_dscp_comtbl.tx_sramp[scf_dscp_comtbl.tx_sram_put]; + + /* Update Tx SRAM offset */ + if (scf_dscp_comtbl.tx_sram_put == + scf_dscp_comtbl.tx_sram_last) { + scf_dscp_comtbl.tx_sram_put = + scf_dscp_comtbl.tx_sram_first; + } else { + scf_dscp_comtbl.tx_sram_put++; + } + + /* Check Tx SRAM use */ + if (sram_p->use_flag == FLAG_OFF) { + /* Tx SRAM use flag ON */ + sram_p->use_flag = FLAG_ON; + + /* Get Tx SRAM offset */ + offset = sram_p->offset; + + /* Update Tx SRAM count */ + scf_dscp_comtbl.tx_sram_count++; + break; + } + } + +/* + * END_dscp_sram_get + */ + END_dscp_sram_get: + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end offset = 0x%04x", + offset); + return (offset); +} + + +/* + * scf_dscp_sram_free() + * + * Description: Tx SRAM release processing + * + */ +void +scf_dscp_sram_free(uint16_t offset) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_sram_free() " + scf_tx_sram_t *sram_p; /* Tx SRAM table address */ + uint16_t wkget; /* Working value : get offset */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start offset = 0x%04x", + offset); + + /* "offset" to Tx SRAM get offset */ + wkget = (uint16_t)(offset + / (scf_dscp_comtbl.txbuffsize / DSC_OFFSET_CONVERT)); + + /* Check Tx SRAM get offset */ + if (wkget < scf_dscp_comtbl.txsram_maxcount) { + /* Get Tx SRAM table address */ + sram_p = &scf_dscp_comtbl.tx_sramp[wkget]; + + /* Check "offset" */ + if (offset == sram_p->offset) { + /* Tx SRAM use flag OFF */ + sram_p->use_flag = FLAG_OFF; + + /* Update Tx SRAM count */ + scf_dscp_comtbl.tx_sram_count--; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} |