diff options
Diffstat (limited to 'sys/dev/hfa/fore_command.c')
-rw-r--r-- | sys/dev/hfa/fore_command.c | 445 |
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; +} + |