2127f26023
for possible buffer overflow problems. Replaced most sprintf()'s with snprintf(); for others cases, added terminating NUL bytes where appropriate, replaced constants like "16" with sizeof(), etc. These changes include several bug fixes, but most changes are for maintainability's sake. Any instance where it wasn't "immediately obvious" that a buffer overflow could not occur was made safer. Reviewed by: Bruce Evans <bde@zeta.org.au> Reviewed by: Matthew Dillon <dillon@apollo.backplane.com> Reviewed by: Mike Spengler <mks@networkcs.com>
448 lines
8.7 KiB
C
448 lines
8.7 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* 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.3 1998/10/31 20:06:52 phk Exp $
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* FORE Systems 200-Series Adapter Support
|
|
* ---------------------------------------
|
|
*
|
|
* Command queue management
|
|
*
|
|
*/
|
|
|
|
#include <dev/hfa/fore_include.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $Id: fore_command.c,v 1.3 1998/10/31 20:06:52 phk Exp $");
|
|
#endif
|
|
|
|
/*
|
|
* 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;
|
|
snprintf(fup->fu_config.ac_hard_vers,
|
|
sizeof(fup->fu_config.ac_hard_vers),
|
|
"%ld.%ld.%ld",
|
|
(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 %ld\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;
|
|
}
|
|
|