summaryrefslogtreecommitdiffstats
path: root/sys/dev/hfa/fore_command.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hfa/fore_command.c')
-rw-r--r--sys/dev/hfa/fore_command.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/sys/dev/hfa/fore_command.c b/sys/dev/hfa/fore_command.c
new file mode 100644
index 0000000..29b99c6
--- /dev/null
+++ b/sys/dev/hfa/fore_command.c
@@ -0,0 +1,445 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Command queue management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+/*
+ * Local variables
+ */
+static struct t_atm_cause fore_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_TEMPORARY_FAILURE,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Allocate Command Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 allocations successful
+ * else allocation failed
+ */
+int
+fore_cmd_allocate(fup)
+ Fore_unit *fup;
+{
+ caddr_t memp;
+
+ /*
+ * Allocate non-cacheable memory for command status words
+ */
+ memp = atm_dev_alloc(sizeof(Q_status) * CMD_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_cmd_stat = (Q_status *) memp;
+
+ memp = DMA_GET_ADDR(fup->fu_cmd_stat, sizeof(Q_status) * CMD_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_cmd_statd = (Q_status *) memp;
+
+ /*
+ * Allocate memory for statistics buffer
+ */
+ memp = atm_dev_alloc(sizeof(Fore_stats), FORE_STATS_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_stats = (Fore_stats *) memp;
+
+#ifdef FORE_PCI
+ /*
+ * Allocate memory for PROM buffer
+ */
+ memp = atm_dev_alloc(sizeof(Fore_prom), FORE_PROM_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_prom = (Fore_prom *) memp;
+#endif
+
+ return (0);
+}
+
+
+/*
+ * Command Queue Initialization
+ *
+ * Allocate and initialize the host-resident command queue structures
+ * and then initialize the CP-resident queue structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+ Cmd_queue *cqp;
+ H_cmd_queue *hcp;
+ Q_status *qsp;
+ Q_status *qsp_dma;
+ int i;
+
+ /*
+ * Point to CP-resident command queue
+ */
+ cqp = (Cmd_queue *)(fup->fu_ram + CP_READ(aap->aali_cmd_q));
+
+ /*
+ * Point to host-resident command queue structures
+ */
+ hcp = fup->fu_cmd_q;
+ qsp = fup->fu_cmd_stat;
+ qsp_dma = fup->fu_cmd_statd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < CMD_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hcp->hcq_cpelem = cqp;
+ hcp->hcq_status = qsp;
+ if (i == (CMD_QUELEN - 1))
+ hcp->hcq_next = fup->fu_cmd_q;
+ else
+ hcp->hcq_next = hcp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cmdq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hcp++;
+ qsp++;
+ qsp_dma++;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_cmd_head = fup->fu_cmd_tail = fup->fu_cmd_q;
+
+ return;
+}
+
+
+/*
+ * Drain Command Queue
+ *
+ * This function will process and free all completed entries at the head
+ * of the command queue.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_drain(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+ Fore_vcc *fvp;
+
+ /*
+ * Process each completed entry
+ */
+ while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) {
+
+ hcp = fup->fu_cmd_head;
+
+ /*
+ * Process command completion
+ */
+ switch (hcp->hcq_code) {
+
+ case CMD_ACT_VCCIN:
+ case CMD_ACT_VCCOUT:
+ fvp = hcp->hcq_arg;
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * VCC activation failed - just abort vcc
+ */
+ if (fvp)
+ atm_cm_abort(fvp->fv_connvc,
+ &fore_cause);
+ fup->fu_pif.pif_cmderrors++;
+ } else {
+ /*
+ * Successful VCC activation
+ */
+ if (fvp) {
+ fvp->fv_state = CVS_ACTIVE;
+ fup->fu_open_vcc++;
+ }
+ }
+ break;
+
+ case CMD_DACT_VCCIN:
+ case CMD_DACT_VCCOUT:
+ fvp = hcp->hcq_arg;
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * VCC dactivation failed - whine
+ */
+ log(LOG_ERR,
+ "fore_cmd_drain: DACT failed, vcc=(%d,%d)\n",
+ fvp->fv_connvc->cvc_vcc->vc_vpi,
+ fvp->fv_connvc->cvc_vcc->vc_vci);
+ fup->fu_pif.pif_cmderrors++;
+ } else {
+ /*
+ * Successful VCC dactivation - so what?
+ */
+ }
+ break;
+
+ case CMD_GET_STATS:
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * Couldn't get stats
+ */
+ fup->fu_pif.pif_cmderrors++;
+ fup->fu_stats_ret = EIO;
+ } else {
+ /*
+ * Stats are now in unit buffer
+ */
+ fup->fu_stats_ret = 0;
+ }
+ DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd,
+ sizeof(Fore_cp_stats), 0);
+ fup->fu_flags &= ~FUF_STATCMD;
+
+ /*
+ * Flush received stats data
+ */
+#ifdef VAC
+ if (vac)
+ vac_pageflush((addr_t)fup->fu_stats);
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /*
+ * Little endian machines receives the stats in
+ * wrong byte order. Instead of swapping in user
+ * land, swap here so that everything going out
+ * of the kernel is in correct host order.
+ */
+ {
+ u_long *bp = (u_long *)fup->fu_stats;
+ int loop;
+
+ for ( loop = 0; loop < sizeof(Fore_cp_stats)/
+ sizeof(long); loop++, bp++ )
+ *bp = ntohl(*bp);
+ }
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+ /*
+ * Poke whoever is waiting on the stats
+ */
+ wakeup((caddr_t)&fup->fu_stats);
+ break;
+
+#ifdef FORE_PCI
+ case CMD_GET_PROM:
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * Couldn't get PROM data
+ */
+ fup->fu_pif.pif_cmderrors++;
+ log(LOG_ERR,
+ "fore_cmd_drain: %s%d: GET_PROM failed\n",
+ fup->fu_pif.pif_name,
+ fup->fu_pif.pif_unit);
+ } else {
+ Fore_prom *fp = fup->fu_prom;
+
+ /*
+ * Flush received PROM data
+ */
+#ifdef VAC
+ if (vac)
+ vac_pageflush((addr_t)fp);
+#endif
+ /*
+ * Copy PROM info into config areas
+ */
+ KM_COPY(&fp->pr_mac[2],
+ &fup->fu_pif.pif_macaddr,
+ sizeof(struct mac_addr));
+ fup->fu_config.ac_macaddr =
+ fup->fu_pif.pif_macaddr;
+ sprintf(fup->fu_config.ac_hard_vers, "%d.%d.%d",
+ (fp->pr_hwver >> 16) & 0xff,
+ (fp->pr_hwver >> 8) & 0xff,
+ fp->pr_hwver & 0xff);
+ fup->fu_config.ac_serial = fp->pr_serno;
+ }
+
+ DMA_FREE_ADDR(fup->fu_prom, fup->fu_promd,
+ sizeof(Fore_prom), 0);
+ break;
+#endif /* FORE_PCI */
+
+ default:
+ log(LOG_ERR, "fore_cmd_drain: unknown command %d\n",
+ hcp->hcq_code);
+ }
+
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hcp->hcq_status = QSTAT_FREE;
+ fup->fu_cmd_head = hcp->hcq_next;
+ }
+
+ return;
+}
+
+
+/*
+ * Free Command Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_free(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+
+ /*
+ * Deal with any commands left on the queue
+ */
+ if (fup->fu_flags & CUF_INITED) {
+ while (*fup->fu_cmd_head->hcq_status != QSTAT_FREE) {
+ hcp = fup->fu_cmd_head;
+
+ switch (hcp->hcq_code) {
+
+ case CMD_GET_STATS:
+ /*
+ * Just in case someone is sleeping on this
+ */
+ fup->fu_stats_ret = EIO;
+ wakeup((caddr_t)&fup->fu_stats);
+ break;
+ }
+
+ *hcp->hcq_status = QSTAT_FREE;
+ fup->fu_cmd_head = hcp->hcq_next;
+ }
+ }
+
+ /*
+ * Free the statistics buffer
+ */
+ if (fup->fu_stats) {
+ atm_dev_free(fup->fu_stats);
+ fup->fu_stats = NULL;
+ }
+
+#ifdef FORE_PCI
+ /*
+ * Free the PROM buffer
+ */
+ if (fup->fu_prom) {
+ atm_dev_free(fup->fu_prom);
+ fup->fu_prom = NULL;
+ }
+#endif
+
+ /*
+ * Free the status words
+ */
+ if (fup->fu_cmd_stat) {
+ if (fup->fu_cmd_statd) {
+ DMA_FREE_ADDR(fup->fu_cmd_stat, fup->fu_cmd_statd,
+ sizeof(Q_status) * CMD_QUELEN,
+ ATM_DEV_NONCACHE);
+ }
+ atm_dev_free((void *)fup->fu_cmd_stat);
+ fup->fu_cmd_stat = NULL;
+ fup->fu_cmd_statd = NULL;
+ }
+
+ return;
+}
+
OpenPOWER on IntegriCloud