193383Smdodd/*	$NetBSD: pdq.c,v 1.33 2001/11/13 13:14:43 lukem Exp $	*/
293383Smdodd
321826Sjoerg/*-
421826Sjoerg * Copyright (c) 1995,1996 Matt Thomas <matt@3am-software.com>
521826Sjoerg * All rights reserved.
621826Sjoerg *
721826Sjoerg * Redistribution and use in source and binary forms, with or without
821826Sjoerg * modification, are permitted provided that the following conditions
921826Sjoerg * are met:
1021826Sjoerg * 1. Redistributions of source code must retain the above copyright
1121826Sjoerg *    notice, this list of conditions and the following disclaimer.
1221826Sjoerg * 2. The name of the author may not be used to endorse or promote products
1393383Smdodd *    derived from this software without specific prior written permission
1421826Sjoerg *
1521826Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1621826Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1721826Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1821826Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1921826Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2021826Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121826Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2221826Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2321826Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2421826Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2521826Sjoerg *
2693383Smdodd * Id: pdq.c,v 1.32 1997/06/05 01:56:35 thomas Exp
2721826Sjoerg *
2821826Sjoerg */
2921826Sjoerg
30119418Sobrien#include <sys/cdefs.h>
31119418Sobrien__FBSDID("$FreeBSD$");
32119418Sobrien
3321826Sjoerg/*
3421826Sjoerg * DEC PDQ FDDI Controller O/S independent code
3521826Sjoerg *
3693383Smdodd * This module should work any on PDQ based board.  Note that changes for
3721826Sjoerg * MIPS and Alpha architectures (or any other architecture which requires
3821826Sjoerg * a flushing of memory or write buffers and/or has incoherent caches)
3921826Sjoerg * have yet to be made.
4021826Sjoerg *
4121826Sjoerg * However, it is expected that the PDQ_CSR_WRITE macro will cause a
4221826Sjoerg * flushing of the write buffers.
4321826Sjoerg */
4421826Sjoerg
4593383Smdodd
4621826Sjoerg#define	PDQ_HWSUPPORT	/* for pdq.h */
4721826Sjoerg
4893383Smdodd/*
4993383Smdodd * What a botch having to specific includes for FreeBSD!
5093383Smdodd */
5193383Smdodd#include <dev/pdq/pdq_freebsd.h>
5221830Sjoerg#include <dev/pdq/pdqreg.h>
5321826Sjoerg
5421826Sjoerg#define	PDQ_ROUNDUP(n, x)	(((n) + ((x) - 1)) & ~((x) - 1))
5521826Sjoerg#define	PDQ_CMD_RX_ALIGNMENT	16
5621826Sjoerg
5721826Sjoerg#if (defined(PDQTEST) && !defined(PDQ_NOPRINTF)) || defined(PDQVERBOSE)
5821826Sjoerg#define	PDQ_PRINTF(x)	printf x
5921826Sjoerg#else
6021826Sjoerg#define	PDQ_PRINTF(x)	do { } while (0)
6121826Sjoerg#endif
6221826Sjoerg
6321826Sjoergstatic const char * const pdq_halt_codes[] = {
6421826Sjoerg    "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault",
6521826Sjoerg    "Software Fault", "Hardware Fault", "PC Trace Path Test",
66298955Spfg    "DMA Error", "Image CRC Error", "Adapter Processor Error"
6721826Sjoerg};
6821826Sjoerg
6921826Sjoergstatic const char * const pdq_adapter_states[] = {
7021826Sjoerg    "Reset", "Upgrade", "DMA Unavailable", "DMA Available",
7121826Sjoerg    "Link Available", "Link Unavailable", "Halted", "Ring Member"
7221826Sjoerg};
7321826Sjoerg
7421826Sjoerg/*
7521826Sjoerg * The following are used in conjunction with
7621826Sjoerg * unsolicited events
7721826Sjoerg */
7821826Sjoergstatic const char * const pdq_entities[] = {
7921826Sjoerg    "Station", "Link", "Phy Port"
8021826Sjoerg};
8121826Sjoerg
8221826Sjoergstatic const char * const pdq_station_events[] = {
8393383Smdodd    "Unknown Event #0",
8421826Sjoerg    "Trace Received"
8521826Sjoerg};
8621826Sjoerg
8721826Sjoergstatic const char * const pdq_station_arguments[] = {
8821826Sjoerg    "Reason"
8921826Sjoerg};
9021826Sjoerg
9121826Sjoergstatic const char * const pdq_link_events[] = {
9221826Sjoerg    "Transmit Underrun",
9321826Sjoerg    "Transmit Failed",
9421826Sjoerg    "Block Check Error (CRC)",
9521826Sjoerg    "Frame Status Error",
9621826Sjoerg    "PDU Length Error",
9721826Sjoerg    NULL,
9821826Sjoerg    NULL,
9921826Sjoerg    "Receive Data Overrun",
10021826Sjoerg    NULL,
10121826Sjoerg    "No User Buffer",
10221826Sjoerg    "Ring Initialization Initiated",
10321826Sjoerg    "Ring Initialization Received",
10421826Sjoerg    "Ring Beacon Initiated",
10521826Sjoerg    "Duplicate Address Failure",
10621826Sjoerg    "Duplicate Token Detected",
10721826Sjoerg    "Ring Purger Error",
10821826Sjoerg    "FCI Strip Error",
10921826Sjoerg    "Trace Initiated",
11021826Sjoerg    "Directed Beacon Received",
11121826Sjoerg};
11221826Sjoerg
11321826Sjoergstatic const char * const pdq_link_arguments[] = {
11421826Sjoerg    "Reason",
11521826Sjoerg    "Data Link Header",
11621826Sjoerg    "Source",
11721826Sjoerg    "Upstream Neighbor"
11821826Sjoerg};
11921826Sjoerg
12021826Sjoergstatic const char * const pdq_phy_events[] = {
12121826Sjoerg    "LEM Error Monitor Reject",
12221826Sjoerg    "Elasticy Buffer Error",
12321826Sjoerg    "Link Confidence Test Reject"
12421826Sjoerg};
12521826Sjoerg
12621826Sjoergstatic const char * const pdq_phy_arguments[] = {
12721826Sjoerg    "Direction"
12821826Sjoerg};
12921826Sjoerg
13021826Sjoergstatic const char * const * const pdq_event_arguments[] = {
13121826Sjoerg    pdq_station_arguments,
13221826Sjoerg    pdq_link_arguments,
13321826Sjoerg    pdq_phy_arguments
13421826Sjoerg};
13521826Sjoerg
13621826Sjoergstatic const char * const * const pdq_event_codes[] = {
13721826Sjoerg    pdq_station_events,
13821826Sjoerg    pdq_link_events,
13921826Sjoerg    pdq_phy_events
14021826Sjoerg};
14121826Sjoerg
14221826Sjoergstatic const char * const pdq_station_types[] = {
14321826Sjoerg    "SAS", "DAC", "SAC", "NAC", "DAS"
14421826Sjoerg};
14521826Sjoerg
14621826Sjoergstatic const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" };
14721826Sjoerg
14821826Sjoergstatic const char pdq_phy_types[] = "ABSM";
14921826Sjoerg
15021826Sjoergstatic const char * const pdq_pmd_types0[] = {
15121826Sjoerg    "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2",
15221826Sjoerg    "ANSI Sonet"
15321826Sjoerg};
15421826Sjoerg
15521826Sjoergstatic const char * const pdq_pmd_types100[] = {
15621826Sjoerg    "Low Power", "Thin Wire", "Shielded Twisted Pair",
15721826Sjoerg    "Unshielded Twisted Pair"
15821826Sjoerg};
15921826Sjoerg
16021826Sjoergstatic const char * const * const pdq_pmd_types[] = {
16121826Sjoerg    pdq_pmd_types0, pdq_pmd_types100
16221826Sjoerg};
16321826Sjoerg
16421826Sjoergstatic const char * const pdq_descriptions[] = {
16521826Sjoerg    "DEFPA PCI",
16621826Sjoerg    "DEFEA EISA",
16721826Sjoerg    "DEFTA TC",
16821826Sjoerg    "DEFAA Futurebus",
16921826Sjoerg    "DEFQA Q-bus",
17021826Sjoerg};
17121826Sjoerg
17221826Sjoergstatic void
17321826Sjoergpdq_print_fddi_chars(
17421826Sjoerg    pdq_t *pdq,
17521826Sjoerg    const pdq_response_status_chars_get_t *rsp)
17621826Sjoerg{
17721826Sjoerg    const char hexchars[] = "0123456789abcdef";
17821826Sjoerg
17921826Sjoerg    printf(
18021826Sjoerg	   PDQ_OS_PREFIX
18121826Sjoerg	   "DEC %s FDDI %s Controller\n",
18221826Sjoerg	   PDQ_OS_PREFIX_ARGS,
18321826Sjoerg	   pdq_descriptions[pdq->pdq_type],
18421826Sjoerg	   pdq_station_types[rsp->status_chars_get.station_type]);
18521826Sjoerg
18621826Sjoerg    printf(PDQ_OS_PREFIX "FDDI address %c%c:%c%c:%c%c:%c%c:%c%c:%c%c, FW=%c%c%c%c, HW=%c",
18721826Sjoerg	   PDQ_OS_PREFIX_ARGS,
18821826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4],
18921826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F],
19021826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4],
19121826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F],
19221826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4],
19321826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F],
19421826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4],
19521826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F],
19621826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4],
19721826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F],
19821826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4],
19921826Sjoerg	   hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F],
20021826Sjoerg	   pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
20121826Sjoerg	   pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3],
20221826Sjoerg	   rsp->status_chars_get.module_rev.fwrev_bytes[0]);
20321826Sjoerg
20421826Sjoerg    if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) {
20521826Sjoerg	printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]);
20621826Sjoerg    }
20721826Sjoerg
20821826Sjoerg    printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)",
20921826Sjoerg	   PDQ_OS_PREFIX_ARGS,
21021826Sjoerg	   rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "",
21121826Sjoerg	   pdq_phy_types[rsp->status_chars_get.phy_type[0]],
21221826Sjoerg	   pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]);
21321826Sjoerg
21421826Sjoerg    if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
21521826Sjoerg	printf(", FDDI Port[B] = %c (PMD = %s)",
21621826Sjoerg	       pdq_phy_types[rsp->status_chars_get.phy_type[1]],
21721826Sjoerg	       pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]);
21821826Sjoerg
21921826Sjoerg    printf("\n");
22093383Smdodd
22193383Smdodd    pdq_os_update_status(pdq, rsp);
22221826Sjoerg}
22321826Sjoerg
22421826Sjoergstatic void
22521826Sjoergpdq_init_csrs(
22621826Sjoerg    pdq_csrs_t *csrs,
22721826Sjoerg    pdq_bus_t bus,
22821826Sjoerg    pdq_bus_memaddr_t csr_base,
22921826Sjoerg    size_t csrsize)
23021826Sjoerg{
23121826Sjoerg    csrs->csr_bus = bus;
23221826Sjoerg    csrs->csr_base = csr_base;
23321826Sjoerg    csrs->csr_port_reset		= PDQ_CSR_OFFSET(csr_base,  0 * csrsize);
23421826Sjoerg    csrs->csr_host_data			= PDQ_CSR_OFFSET(csr_base,  1 * csrsize);
23521826Sjoerg    csrs->csr_port_control		= PDQ_CSR_OFFSET(csr_base,  2 * csrsize);
23621826Sjoerg    csrs->csr_port_data_a		= PDQ_CSR_OFFSET(csr_base,  3 * csrsize);
23721826Sjoerg    csrs->csr_port_data_b		= PDQ_CSR_OFFSET(csr_base,  4 * csrsize);
23821826Sjoerg    csrs->csr_port_status		= PDQ_CSR_OFFSET(csr_base,  5 * csrsize);
23921826Sjoerg    csrs->csr_host_int_type_0		= PDQ_CSR_OFFSET(csr_base,  6 * csrsize);
24021826Sjoerg    csrs->csr_host_int_enable		= PDQ_CSR_OFFSET(csr_base,  7 * csrsize);
24121826Sjoerg    csrs->csr_type_2_producer		= PDQ_CSR_OFFSET(csr_base,  8 * csrsize);
24221826Sjoerg    csrs->csr_cmd_response_producer	= PDQ_CSR_OFFSET(csr_base, 10 * csrsize);
24321826Sjoerg    csrs->csr_cmd_request_producer	= PDQ_CSR_OFFSET(csr_base, 11 * csrsize);
24421826Sjoerg    csrs->csr_host_smt_producer		= PDQ_CSR_OFFSET(csr_base, 12 * csrsize);
24521826Sjoerg    csrs->csr_unsolicited_producer	= PDQ_CSR_OFFSET(csr_base, 13 * csrsize);
24621826Sjoerg}
24721826Sjoerg
24821826Sjoergstatic void
24921826Sjoergpdq_init_pci_csrs(
25021826Sjoerg    pdq_pci_csrs_t *csrs,
25121826Sjoerg    pdq_bus_t bus,
25221826Sjoerg    pdq_bus_memaddr_t csr_base,
25321826Sjoerg    size_t csrsize)
25421826Sjoerg{
25521826Sjoerg    csrs->csr_bus = bus;
25621826Sjoerg    csrs->csr_base = csr_base;
25721826Sjoerg    csrs->csr_pfi_mode_control	= PDQ_CSR_OFFSET(csr_base, 16 * csrsize);
25821826Sjoerg    csrs->csr_pfi_status	= PDQ_CSR_OFFSET(csr_base, 17 * csrsize);
25921826Sjoerg    csrs->csr_fifo_write	= PDQ_CSR_OFFSET(csr_base, 18 * csrsize);
26021826Sjoerg    csrs->csr_fifo_read		= PDQ_CSR_OFFSET(csr_base, 19 * csrsize);
26121826Sjoerg}
26221826Sjoerg
26321826Sjoergstatic void
26421826Sjoergpdq_flush_databuf_queue(
26593383Smdodd    pdq_t *pdq,
26621826Sjoerg    pdq_databuf_queue_t *q)
26721826Sjoerg{
26821826Sjoerg    PDQ_OS_DATABUF_T *pdu;
26921826Sjoerg    for (;;) {
27021826Sjoerg	PDQ_OS_DATABUF_DEQUEUE(q, pdu);
27121826Sjoerg	if (pdu == NULL)
27221826Sjoerg	    return;
27393383Smdodd	PDQ_OS_DATABUF_FREE(pdq, pdu);
27421826Sjoerg    }
27521826Sjoerg}
27621826Sjoerg
27721826Sjoergstatic pdq_boolean_t
27821826Sjoergpdq_do_port_control(
27921826Sjoerg    const pdq_csrs_t * const csrs,
28021826Sjoerg    pdq_uint32_t cmd)
28121826Sjoerg{
28221826Sjoerg    int cnt = 0;
28321826Sjoerg    PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
28421826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_control, PDQ_PCTL_CMD_ERROR | cmd);
28521826Sjoerg    while ((PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000)
28621826Sjoerg	cnt++;
28721826Sjoerg    PDQ_PRINTF(("CSR cmd spun %d times\n", cnt));
28821826Sjoerg    if (PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) {
28921826Sjoerg	PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
29021826Sjoerg	return (PDQ_CSR_READ(csrs, csr_port_control) & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE;
29121826Sjoerg    }
29221826Sjoerg    /* adapter failure */
29321826Sjoerg    PDQ_ASSERT(0);
29421826Sjoerg    return PDQ_FALSE;
29521826Sjoerg}
29621826Sjoerg
29721826Sjoergstatic void
29821826Sjoergpdq_read_mla(
29921826Sjoerg    const pdq_csrs_t * const csrs,
30021826Sjoerg    pdq_lanaddr_t *hwaddr)
30121826Sjoerg{
30221826Sjoerg    pdq_uint32_t data;
30321826Sjoerg
30421826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
30521826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
30621826Sjoerg    data = PDQ_CSR_READ(csrs, csr_host_data);
30721826Sjoerg
30821826Sjoerg    hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF;
30921826Sjoerg    hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF;
31021826Sjoerg    hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF;
31121826Sjoerg    hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF;
31221826Sjoerg
31321826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_a, 1);
31421826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
31521826Sjoerg    data = PDQ_CSR_READ(csrs, csr_host_data);
31621826Sjoerg
31721826Sjoerg    hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF;
31821826Sjoerg    hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF;
31921826Sjoerg}
32021826Sjoerg
32121826Sjoergstatic void
32221826Sjoergpdq_read_fwrev(
32321826Sjoerg    const pdq_csrs_t * const csrs,
32421826Sjoerg    pdq_fwrev_t *fwrev)
32521826Sjoerg{
32621826Sjoerg    pdq_uint32_t data;
32721826Sjoerg
32821826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ);
32921826Sjoerg    data = PDQ_CSR_READ(csrs, csr_host_data);
33021826Sjoerg
33121826Sjoerg    fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF;
33221826Sjoerg    fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF;
33321826Sjoerg    fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF;
33421826Sjoerg    fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF;
33521826Sjoerg}
33621826Sjoerg
33721826Sjoergstatic pdq_boolean_t
33821826Sjoergpdq_read_error_log(
33921826Sjoerg    pdq_t *pdq,
34021826Sjoerg    pdq_response_error_log_get_t *log_entry)
34121826Sjoerg{
34221826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
34321826Sjoerg    pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry;
34421826Sjoerg
34521826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START);
34621826Sjoerg
34721826Sjoerg    while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) {
34821826Sjoerg	*ptr++ = PDQ_CSR_READ(csrs, csr_host_data);
34921826Sjoerg	if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry))
35021826Sjoerg	    break;
35121826Sjoerg    }
35221826Sjoerg    return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE;
35321826Sjoerg}
35421826Sjoerg
35521826Sjoergstatic pdq_chip_rev_t
35621826Sjoergpdq_read_chiprev(
35721826Sjoerg    const pdq_csrs_t * const csrs)
35821826Sjoerg{
35921826Sjoerg    pdq_uint32_t data;
36021826Sjoerg
36121826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_PDQ_REV_GET);
36221826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
36321826Sjoerg    data = PDQ_CSR_READ(csrs, csr_host_data);
36421826Sjoerg
36521826Sjoerg    return (pdq_chip_rev_t) data;
36621826Sjoerg}
36721826Sjoerg
36821826Sjoergstatic const struct {
36921826Sjoerg    size_t cmd_len;
37021826Sjoerg    size_t rsp_len;
37121826Sjoerg    const char *cmd_name;
37221826Sjoerg} pdq_cmd_info[] = {
37321826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 0 - PDQC_START */
37421826Sjoerg      sizeof(pdq_response_generic_t),
37521826Sjoerg      "Start"
37621826Sjoerg    },
37721826Sjoerg    { sizeof(pdq_cmd_filter_set_t),		/* 1 - PDQC_FILTER_SET */
37821826Sjoerg      sizeof(pdq_response_generic_t),
37921826Sjoerg      "Filter Set"
38021826Sjoerg    },
38121826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 2 - PDQC_FILTER_GET */
38221826Sjoerg      sizeof(pdq_response_filter_get_t),
38321826Sjoerg      "Filter Get"
38421826Sjoerg    },
38521826Sjoerg    { sizeof(pdq_cmd_chars_set_t),		/* 3 - PDQC_CHARS_SET */
38621826Sjoerg      sizeof(pdq_response_generic_t),
38721826Sjoerg      "Chars Set"
38821826Sjoerg    },
38921826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 4 - PDQC_STATUS_CHARS_GET */
39021826Sjoerg      sizeof(pdq_response_status_chars_get_t),
39121826Sjoerg      "Status Chars Get"
39221826Sjoerg    },
39321826Sjoerg#if 0
39421826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 5 - PDQC_COUNTERS_GET */
39521826Sjoerg      sizeof(pdq_response_counters_get_t),
39621826Sjoerg      "Counters Get"
39721826Sjoerg    },
39821826Sjoerg    { sizeof(pdq_cmd_counters_set_t),		/* 6 - PDQC_COUNTERS_SET */
39921826Sjoerg      sizeof(pdq_response_generic_t),
40021826Sjoerg      "Counters Set"
40121826Sjoerg    },
40221826Sjoerg#else
40321826Sjoerg    { 0, 0, "Counters Get" },
40421826Sjoerg    { 0, 0, "Counters Set" },
40521826Sjoerg#endif
40621826Sjoerg    { sizeof(pdq_cmd_addr_filter_set_t),	/* 7 - PDQC_ADDR_FILTER_SET */
40721826Sjoerg      sizeof(pdq_response_generic_t),
40821826Sjoerg      "Addr Filter Set"
40921826Sjoerg    },
41021826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 8 - PDQC_ADDR_FILTER_GET */
41121826Sjoerg      sizeof(pdq_response_addr_filter_get_t),
41221826Sjoerg      "Addr Filter Get"
41321826Sjoerg    },
41421826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 9 - PDQC_ERROR_LOG_CLEAR */
41521826Sjoerg      sizeof(pdq_response_generic_t),
41621826Sjoerg      "Error Log Clear"
41721826Sjoerg    },
41821826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 10 - PDQC_ERROR_LOG_SET */
41921826Sjoerg      sizeof(pdq_response_generic_t),
42021826Sjoerg      "Error Log Set"
42121826Sjoerg    },
42221826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 11 - PDQC_FDDI_MIB_GET */
42321826Sjoerg      sizeof(pdq_response_generic_t),
42421826Sjoerg      "FDDI MIB Get"
42521826Sjoerg    },
42621826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 12 - PDQC_DEC_EXT_MIB_GET */
42721826Sjoerg      sizeof(pdq_response_generic_t),
42821826Sjoerg      "DEC Ext MIB Get"
42921826Sjoerg    },
43021826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 13 - PDQC_DEC_SPECIFIC_GET */
43121826Sjoerg      sizeof(pdq_response_generic_t),
43221826Sjoerg      "DEC Specific Get"
43321826Sjoerg    },
43421826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 14 - PDQC_SNMP_SET */
43521826Sjoerg      sizeof(pdq_response_generic_t),
43621826Sjoerg      "SNMP Set"
43721826Sjoerg    },
43821826Sjoerg    { 0, 0, "N/A" },
43921826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 16 - PDQC_SMT_MIB_GET */
44021826Sjoerg      sizeof(pdq_response_generic_t),
44121826Sjoerg      "SMT MIB Get"
44221826Sjoerg    },
44321826Sjoerg    { sizeof(pdq_cmd_generic_t),		/* 17 - PDQC_SMT_MIB_SET */
44421826Sjoerg      sizeof(pdq_response_generic_t),
44521826Sjoerg      "SMT MIB Set",
44621826Sjoerg    },
44793383Smdodd    { 0, 0, "Bogus CMD" },
44821826Sjoerg};
44921826Sjoerg
45021826Sjoergstatic void
45121826Sjoergpdq_queue_commands(
45221826Sjoerg    pdq_t *pdq)
45321826Sjoerg{
45421826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
45521826Sjoerg    pdq_command_info_t * const ci = &pdq->pdq_command_info;
45621826Sjoerg    pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
45793383Smdodd    pdq_txdesc_t * const txd = &dbp->pdqdb_command_requests[ci->ci_request_producer];
45821826Sjoerg    pdq_cmd_code_t op;
45921826Sjoerg    pdq_uint32_t cmdlen, rsplen, mask;
46021826Sjoerg
46121826Sjoerg    /*
46221826Sjoerg     * If there are commands or responses active or there aren't
46321826Sjoerg     * any pending commands, then don't queue any more.
46421826Sjoerg     */
46521826Sjoerg    if (ci->ci_command_active || ci->ci_pending_commands == 0)
46621826Sjoerg	return;
46721826Sjoerg
46821826Sjoerg    /*
46921826Sjoerg     * Determine which command needs to be queued.
47021826Sjoerg     */
47121826Sjoerg    op = PDQC_SMT_MIB_SET;
47221826Sjoerg    for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1)
47321826Sjoerg	op = (pdq_cmd_code_t) ((int) op - 1);
47421826Sjoerg    /*
47521826Sjoerg     * Obtain the sizes needed for the command and response.
47621826Sjoerg     * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is
47721826Sjoerg     * always properly aligned.
47821826Sjoerg     */
47921826Sjoerg    cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT);
48021826Sjoerg    rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT);
48121826Sjoerg    if (cmdlen < rsplen)
48221826Sjoerg	cmdlen = rsplen;
48321826Sjoerg    /*
48421826Sjoerg     * Since only one command at a time will be queued, there will always
48521826Sjoerg     * be enough space.
48621826Sjoerg     */
48721826Sjoerg
48821826Sjoerg    /*
48921826Sjoerg     * Obtain and fill in the descriptor for the command (descriptor is
49021826Sjoerg     * pre-initialized)
49121826Sjoerg     */
49293383Smdodd    txd->txd_seg_len = cmdlen;
49321826Sjoerg
49421826Sjoerg    /*
49521826Sjoerg     * Clear the command area, set the opcode, and the command from the pending
49621826Sjoerg     * mask.
49721826Sjoerg     */
49821826Sjoerg
49993383Smdodd    ci->ci_queued_commands[ci->ci_request_producer] = op;
50093383Smdodd#if defined(PDQVERBOSE)
50193383Smdodd    ((pdq_response_generic_t *) ci->ci_response_bufstart)->generic_op = PDQC_BOGUS_CMD;
50293383Smdodd#endif
50393383Smdodd    PDQ_OS_MEMZERO(ci->ci_request_bufstart, cmdlen);
50493383Smdodd    *(pdq_cmd_code_t *) ci->ci_request_bufstart = op;
50521826Sjoerg    ci->ci_pending_commands &= ~mask;
50621826Sjoerg
50721826Sjoerg    /*
50821826Sjoerg     * Fill in the command area, if needed.
50921826Sjoerg     */
51021826Sjoerg    switch (op) {
51121826Sjoerg	case PDQC_FILTER_SET: {
51293383Smdodd	    pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_request_bufstart;
51321826Sjoerg	    unsigned idx = 0;
51421826Sjoerg	    filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM;
51521826Sjoerg	    filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
51621826Sjoerg	    idx++;
51721826Sjoerg	    filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM;
51821826Sjoerg	    filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
51921826Sjoerg	    idx++;
52021826Sjoerg	    filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM;
52121826Sjoerg	    filter_set->filter_set_items[idx].filter_state = ((pdq->pdq_flags & (PDQ_PROMISC|PDQ_PASS_SMT)) == (PDQ_PROMISC|PDQ_PASS_SMT) ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
52221826Sjoerg	    idx++;
52321826Sjoerg	    filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER;
52421826Sjoerg	    filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
52521826Sjoerg	    idx++;
52621826Sjoerg	    filter_set->filter_set_items[idx].item_code = PDQI_EOL;
52721826Sjoerg	    break;
52821826Sjoerg	}
52921826Sjoerg	case PDQC_ADDR_FILTER_SET: {
53093383Smdodd	    pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_request_bufstart;
53121826Sjoerg	    pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses;
53221826Sjoerg	    addr->lanaddr_bytes[0] = 0xFF;
53321826Sjoerg	    addr->lanaddr_bytes[1] = 0xFF;
53421826Sjoerg	    addr->lanaddr_bytes[2] = 0xFF;
53521826Sjoerg	    addr->lanaddr_bytes[3] = 0xFF;
53621826Sjoerg	    addr->lanaddr_bytes[4] = 0xFF;
53721826Sjoerg	    addr->lanaddr_bytes[5] = 0xFF;
53821826Sjoerg	    addr++;
53921826Sjoerg	    pdq_os_addr_fill(pdq, addr, 61);
54021826Sjoerg	    break;
54121826Sjoerg	}
54293383Smdodd	case PDQC_SNMP_SET: {
54393383Smdodd	    pdq_cmd_snmp_set_t *snmp_set = (pdq_cmd_snmp_set_t *) ci->ci_request_bufstart;
54493383Smdodd	    unsigned idx = 0;
54593383Smdodd	    snmp_set->snmp_set_items[idx].item_code = PDQSNMP_FULL_DUPLEX_ENABLE;
54693383Smdodd	    snmp_set->snmp_set_items[idx].item_value = (pdq->pdq_flags & PDQ_WANT_FDX ? 1 : 2);
54793383Smdodd	    snmp_set->snmp_set_items[idx].item_port = 0;
54893383Smdodd	    idx++;
54993383Smdodd	    snmp_set->snmp_set_items[idx].item_code = PDQSNMP_EOL;
55093383Smdodd	    break;
55193383Smdodd	}
55221826Sjoerg	default: {	/* to make gcc happy */
55321826Sjoerg	    break;
55421826Sjoerg	}
55521826Sjoerg    }
55693383Smdodd
55793383Smdodd
55821826Sjoerg    /*
55993383Smdodd     * Sync the command request buffer and descriptor, then advance
56093383Smdodd     * the request producer index.
56193383Smdodd     */
56293383Smdodd    PDQ_OS_CMDRQST_PRESYNC(pdq, txd->txd_seg_len);
56393383Smdodd    PDQ_OS_DESC_PRESYNC(pdq, txd, sizeof(pdq_txdesc_t));
56493383Smdodd    PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
56593383Smdodd
56693383Smdodd    /*
56793383Smdodd     * Sync the command response buffer and advance the response
56893383Smdodd     * producer index (descriptor is already pre-initialized)
56993383Smdodd     */
57093383Smdodd    PDQ_OS_CMDRSP_PRESYNC(pdq, PDQ_SIZE_COMMAND_RESPONSE);
57193383Smdodd    PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
57293383Smdodd    /*
57321826Sjoerg     * At this point the command is done.  All that needs to be done is to
57421826Sjoerg     * produce it to the PDQ.
57521826Sjoerg     */
57621826Sjoerg    PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n",
57721826Sjoerg		pdq_cmd_info[op].cmd_name));
57821826Sjoerg
57921826Sjoerg    ci->ci_command_active++;
58021826Sjoerg    PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, ci->ci_response_producer | (ci->ci_response_completion << 8));
58121826Sjoerg    PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, ci->ci_request_producer | (ci->ci_request_completion << 8));
58221826Sjoerg}
58321826Sjoerg
58421826Sjoergstatic void
58521826Sjoergpdq_process_command_responses(
58621826Sjoerg    pdq_t * const pdq)
58721826Sjoerg{
58821826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
58921826Sjoerg    pdq_command_info_t * const ci = &pdq->pdq_command_info;
59021826Sjoerg    volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp;
59121826Sjoerg    pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
59221826Sjoerg    const pdq_response_generic_t *rspgen;
59321826Sjoerg
59421826Sjoerg    /*
59521826Sjoerg     * We have to process the command and response in tandem so
59621826Sjoerg     * just wait for the response to be consumed.  If it has been
59721826Sjoerg     * consumed then the command must have been as well.
59821826Sjoerg     */
59921826Sjoerg
60021826Sjoerg    if (cbp->pdqcb_command_response == ci->ci_response_completion)
60121826Sjoerg	return;
60221826Sjoerg
60321826Sjoerg    PDQ_ASSERT(cbp->pdqcb_command_request != ci->ci_request_completion);
60421826Sjoerg
60593383Smdodd    PDQ_OS_CMDRSP_POSTSYNC(pdq, PDQ_SIZE_COMMAND_RESPONSE);
60693383Smdodd    rspgen = (const pdq_response_generic_t *) ci->ci_response_bufstart;
60793383Smdodd    PDQ_ASSERT(rspgen->generic_op == ci->ci_queued_commands[ci->ci_request_completion]);
60821826Sjoerg    PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS);
60993383Smdodd    PDQ_PRINTF(("PDQ Process Command Response: %s completed (status=%d [0x%x])\n",
61021826Sjoerg		pdq_cmd_info[rspgen->generic_op].cmd_name,
61193383Smdodd		rspgen->generic_status, rspgen->generic_status));
61221826Sjoerg
61321826Sjoerg    if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) {
61421826Sjoerg	pdq->pdq_flags &= ~PDQ_PRINTCHARS;
61521826Sjoerg	pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen);
61693383Smdodd    } else if (rspgen->generic_op == PDQC_DEC_EXT_MIB_GET) {
61793383Smdodd	pdq->pdq_flags &= ~PDQ_IS_FDX;
61893383Smdodd	if (((const pdq_response_dec_ext_mib_get_t *)rspgen)->dec_ext_mib_get.fdx_operational)
61993383Smdodd	    pdq->pdq_flags |= PDQ_IS_FDX;
62021826Sjoerg    }
62121826Sjoerg
62221826Sjoerg    PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
62321826Sjoerg    PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
62421826Sjoerg    ci->ci_command_active = 0;
62521826Sjoerg
62621826Sjoerg    if (ci->ci_pending_commands != 0) {
62721826Sjoerg	pdq_queue_commands(pdq);
62821826Sjoerg    } else {
62921826Sjoerg	PDQ_CSR_WRITE(csrs, csr_cmd_response_producer,
63021826Sjoerg		      ci->ci_response_producer | (ci->ci_response_completion << 8));
63121826Sjoerg	PDQ_CSR_WRITE(csrs, csr_cmd_request_producer,
63221826Sjoerg		      ci->ci_request_producer | (ci->ci_request_completion << 8));
63321826Sjoerg    }
63421826Sjoerg}
63521826Sjoerg
63621826Sjoerg/*
63721826Sjoerg * This following routine processes unsolicited events.
63821826Sjoerg * In addition, it also fills the unsolicited queue with
63921826Sjoerg * event buffers so it can be used to initialize the queue
64021826Sjoerg * as well.
64121826Sjoerg */
64221826Sjoergstatic void
64321826Sjoergpdq_process_unsolicited_events(
64421826Sjoerg    pdq_t *pdq)
64521826Sjoerg{
64621826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
64721826Sjoerg    pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info;
64821826Sjoerg    volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
64921826Sjoerg    pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
65021826Sjoerg
65121826Sjoerg    /*
65221826Sjoerg     * Process each unsolicited event (if any).
65321826Sjoerg     */
65421826Sjoerg
65521826Sjoerg    while (cbp->pdqcb_unsolicited_event != ui->ui_completion) {
65693383Smdodd	const pdq_unsolicited_event_t *event;
65721826Sjoerg	event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
65893383Smdodd	PDQ_OS_UNSOL_EVENT_POSTSYNC(pdq, event);
65921826Sjoerg
66021826Sjoerg	switch (event->event_type) {
66121826Sjoerg	    case PDQ_UNSOLICITED_EVENT: {
66293383Smdodd		int bad_event = 0;
66393383Smdodd		switch (event->event_entity) {
66493383Smdodd		    case PDQ_ENTITY_STATION: {
66593383Smdodd			bad_event = event->event_code.value >= PDQ_STATION_EVENT_MAX;
66693383Smdodd			break;
66793383Smdodd		    }
66893383Smdodd		    case PDQ_ENTITY_LINK: {
66993383Smdodd			bad_event = event->event_code.value >= PDQ_LINK_EVENT_MAX;
67093383Smdodd			break;
67193383Smdodd		    }
67293383Smdodd		    case PDQ_ENTITY_PHY_PORT: {
67393383Smdodd			bad_event = event->event_code.value >= PDQ_PHY_EVENT_MAX;
67493383Smdodd			break;
67593383Smdodd		    }
67693383Smdodd		    default: {
67793383Smdodd			bad_event = 1;
67893383Smdodd			break;
67993383Smdodd		    }
68093383Smdodd		}
68193383Smdodd		if (bad_event) {
68293383Smdodd		    break;
68393383Smdodd		}
68421826Sjoerg		printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s",
68521826Sjoerg		       PDQ_OS_PREFIX_ARGS,
68621826Sjoerg		       pdq_entities[event->event_entity],
68721826Sjoerg		       pdq_event_codes[event->event_entity][event->event_code.value]);
68821826Sjoerg		if (event->event_entity == PDQ_ENTITY_PHY_PORT)
68921826Sjoerg		    printf("[%d]", event->event_index);
69021826Sjoerg		printf("\n");
69121826Sjoerg		break;
69221826Sjoerg	    }
69321826Sjoerg	    case PDQ_UNSOLICITED_COUNTERS: {
69421826Sjoerg		break;
69521826Sjoerg	    }
69621826Sjoerg	}
69793383Smdodd	PDQ_OS_UNSOL_EVENT_PRESYNC(pdq, event);
69821826Sjoerg	PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
69921826Sjoerg	ui->ui_free++;
70021826Sjoerg    }
70121826Sjoerg
70221826Sjoerg    /*
70321826Sjoerg     * Now give back the event buffers back to the PDQ.
70421826Sjoerg     */
70521826Sjoerg    PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
70621826Sjoerg    ui->ui_free = 0;
70721826Sjoerg
70821826Sjoerg    PDQ_CSR_WRITE(csrs, csr_unsolicited_producer,
70921826Sjoerg		  ui->ui_producer | (ui->ui_completion << 8));
71021826Sjoerg}
71121826Sjoerg
71221826Sjoergstatic void
71321826Sjoergpdq_process_received_data(
71421826Sjoerg    pdq_t *pdq,
71521826Sjoerg    pdq_rx_info_t *rx,
71621826Sjoerg    pdq_rxdesc_t *receives,
71721826Sjoerg    pdq_uint32_t completion_goal,
71821826Sjoerg    pdq_uint32_t ring_mask)
71921826Sjoerg{
72021826Sjoerg    pdq_uint32_t completion = rx->rx_completion;
72121826Sjoerg    pdq_uint32_t producer = rx->rx_producer;
72221826Sjoerg    PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers;
72321826Sjoerg    pdq_rxdesc_t *rxd;
72421826Sjoerg    pdq_uint32_t idx;
72521826Sjoerg
72621826Sjoerg    while (completion != completion_goal) {
72721826Sjoerg	PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu;
72821826Sjoerg	pdq_uint8_t *dataptr;
72921826Sjoerg	pdq_uint32_t fc, datalen, pdulen, segcnt;
73021826Sjoerg	pdq_rxstatus_t status;
73121826Sjoerg
73221826Sjoerg	fpdu = lpdu = buffers[completion];
73321826Sjoerg	PDQ_ASSERT(fpdu != NULL);
73493383Smdodd	PDQ_OS_RXPDU_POSTSYNC(pdq, fpdu, 0, sizeof(u_int32_t));
73521826Sjoerg	dataptr = PDQ_OS_DATABUF_PTR(fpdu);
73621826Sjoerg	status = *(pdq_rxstatus_t *) dataptr;
73793383Smdodd	if (status.rxs_rcc_badpdu == 0) {
73893383Smdodd	    datalen = status.rxs_len;
73993383Smdodd	    PDQ_OS_RXPDU_POSTSYNC(pdq, fpdu, sizeof(u_int32_t),
74093383Smdodd				  PDQ_RX_FC_OFFSET + 1 - sizeof(u_int32_t));
74121826Sjoerg	    fc = dataptr[PDQ_RX_FC_OFFSET];
74221826Sjoerg	    switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) {
74321826Sjoerg		case PDQ_FDDI_LLC_ASYNC:
74421826Sjoerg		case PDQ_FDDI_LLC_SYNC:
74521826Sjoerg		case PDQ_FDDI_IMP_ASYNC:
74621826Sjoerg		case PDQ_FDDI_IMP_SYNC: {
74721826Sjoerg		    if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) {
74821826Sjoerg			PDQ_PRINTF(("discard: bad length %d\n", datalen));
74921826Sjoerg			goto discard_frame;
75021826Sjoerg		    }
75121826Sjoerg		    break;
75221826Sjoerg		}
75321826Sjoerg		case PDQ_FDDI_SMT: {
75421826Sjoerg		    if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN)
75521826Sjoerg			goto discard_frame;
75621826Sjoerg		    break;
75721826Sjoerg		}
75821826Sjoerg		default: {
75921826Sjoerg		    PDQ_PRINTF(("discard: bad fc 0x%x\n", fc));
76021826Sjoerg		    goto discard_frame;
76121826Sjoerg		}
76221826Sjoerg	    }
76321826Sjoerg	    /*
76421826Sjoerg	     * Update the lengths of the data buffers now that we know
76521826Sjoerg	     * the real length.
76621826Sjoerg	     */
76793383Smdodd	    pdulen = datalen + (PDQ_RX_FC_OFFSET - PDQ_OS_HDR_OFFSET) - 4 /* CRC */;
76893383Smdodd	    segcnt = (pdulen + PDQ_OS_HDR_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE;
76993383Smdodd	    PDQ_OS_DATABUF_ALLOC(pdq, npdu);
77021826Sjoerg	    if (npdu == NULL) {
77121826Sjoerg		PDQ_PRINTF(("discard: no databuf #0\n"));
77221826Sjoerg		goto discard_frame;
77321826Sjoerg	    }
77421826Sjoerg	    buffers[completion] = npdu;
77521826Sjoerg	    for (idx = 1; idx < segcnt; idx++) {
77693383Smdodd		PDQ_OS_DATABUF_ALLOC(pdq, npdu);
77721826Sjoerg		if (npdu == NULL) {
77821826Sjoerg		    PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
77993383Smdodd		    PDQ_OS_DATABUF_FREE(pdq, fpdu);
78021826Sjoerg		    goto discard_frame;
78121826Sjoerg		}
78221826Sjoerg		PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]);
78321826Sjoerg		lpdu = PDQ_OS_DATABUF_NEXT(lpdu);
78421826Sjoerg		buffers[(completion + idx) & ring_mask] = npdu;
78521826Sjoerg	    }
78621826Sjoerg	    PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
78721826Sjoerg	    for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
78821826Sjoerg		buffers[(producer + idx) & ring_mask] =
78921826Sjoerg		    buffers[(completion + idx) & ring_mask];
79021826Sjoerg		buffers[(completion + idx) & ring_mask] = NULL;
79121826Sjoerg	    }
79293383Smdodd	    PDQ_OS_DATABUF_ADJ(fpdu, PDQ_OS_HDR_OFFSET);
79321826Sjoerg	    if (segcnt == 1) {
79421826Sjoerg		PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen);
79521826Sjoerg	    } else {
79693383Smdodd		PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_OS_HDR_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE);
79721826Sjoerg	    }
79893383Smdodd	    /*
79993383Smdodd	     * Do not pass to protocol if packet was received promiscuously
80093383Smdodd	     */
80193383Smdodd	    pdq_os_receive_pdu(pdq, fpdu, pdulen,
80293383Smdodd			       status.rxs_rcc_dd < PDQ_RXS_RCC_DD_CAM_MATCH);
80321826Sjoerg	    rx->rx_free += PDQ_RX_SEGCNT;
80421826Sjoerg	    PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask);
80521826Sjoerg	    PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask);
80621826Sjoerg	    continue;
80721826Sjoerg	} else {
80821826Sjoerg	    PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status,
80921826Sjoerg			status.rxs_rcc_badpdu, status.rxs_rcc_badcrc,
81021826Sjoerg			status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e));
81121826Sjoerg	    if (status.rxs_rcc_reason == 7)
81221826Sjoerg		goto discard_frame;
81346568Speter	    if (status.rxs_rcc_reason != 0) {
81421826Sjoerg		/* hardware fault */
81593383Smdodd		if (status.rxs_rcc_badcrc) {
81693383Smdodd		    printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n",
81793383Smdodd			   PDQ_OS_PREFIX_ARGS,
81893383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+1],
81993383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+2],
82093383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+3],
82193383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+4],
82293383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+5],
82393383Smdodd			   dataptr[PDQ_RX_FC_OFFSET+6]);
82493383Smdodd		    /* rx->rx_badcrc++; */
82593383Smdodd		} else if (status.rxs_fsc == 0 || status.rxs_fsb_e == 1) {
82693383Smdodd		    /* rx->rx_frame_status_errors++; */
82793383Smdodd		} else {
82893383Smdodd		    /* hardware fault */
82993383Smdodd		}
83046568Speter	    }
83121826Sjoerg	}
83221826Sjoerg      discard_frame:
83321826Sjoerg	/*
83421826Sjoerg	 * Discarded frames go right back on the queue; therefore
83521826Sjoerg	 * ring entries were freed.
83621826Sjoerg	 */
83721826Sjoerg	for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
83821826Sjoerg	    buffers[producer] = buffers[completion];
83921826Sjoerg	    buffers[completion] = NULL;
84021826Sjoerg	    rxd = &receives[rx->rx_producer];
84121826Sjoerg	    if (idx == 0) {
84221826Sjoerg		rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
84321826Sjoerg	    } else {
84421826Sjoerg		rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
84521826Sjoerg	    }
84621826Sjoerg	    rxd->rxd_pa_hi = 0;
84721826Sjoerg	    rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
84893383Smdodd	    rxd->rxd_pa_lo = PDQ_OS_DATABUF_BUSPA(pdq, buffers[rx->rx_producer]);
84993383Smdodd	    PDQ_OS_RXPDU_PRESYNC(pdq, buffers[rx->rx_producer], 0, PDQ_OS_DATABUF_SIZE);
85093383Smdodd	    PDQ_OS_DESC_PRESYNC(pdq, rxd, sizeof(*rxd));
85121826Sjoerg	    PDQ_ADVANCE(rx->rx_producer, 1, ring_mask);
85221826Sjoerg	    PDQ_ADVANCE(producer, 1, ring_mask);
85321826Sjoerg	    PDQ_ADVANCE(completion, 1, ring_mask);
85421826Sjoerg	}
85521826Sjoerg    }
85621826Sjoerg    rx->rx_completion = completion;
85721826Sjoerg
85821826Sjoerg    while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) {
85921826Sjoerg	PDQ_OS_DATABUF_T *pdu;
86021826Sjoerg	/*
86121826Sjoerg	 * Allocate the needed number of data buffers.
86221826Sjoerg	 * Try to obtain them from our free queue before
86321826Sjoerg	 * asking the system for more.
86421826Sjoerg	 */
86521826Sjoerg	for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
86621826Sjoerg	    if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) {
86793383Smdodd		PDQ_OS_DATABUF_ALLOC(pdq, pdu);
86821826Sjoerg		if (pdu == NULL)
86921826Sjoerg		    break;
87021826Sjoerg		buffers[(rx->rx_producer + idx) & ring_mask] = pdu;
87121826Sjoerg	    }
87221826Sjoerg	    rxd = &receives[(rx->rx_producer + idx) & ring_mask];
87321826Sjoerg	    if (idx == 0) {
87421826Sjoerg		rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
87521826Sjoerg	    } else {
87621826Sjoerg		rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
87721826Sjoerg	    }
87821826Sjoerg	    rxd->rxd_pa_hi = 0;
87921826Sjoerg	    rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
88093383Smdodd	    rxd->rxd_pa_lo = PDQ_OS_DATABUF_BUSPA(pdq, pdu);
88193383Smdodd	    PDQ_OS_RXPDU_PRESYNC(pdq, pdu, 0, PDQ_OS_DATABUF_SIZE);
88293383Smdodd	    PDQ_OS_DESC_PRESYNC(pdq, rxd, sizeof(*rxd));
88321826Sjoerg	}
88421826Sjoerg	if (idx < PDQ_RX_SEGCNT) {
88521826Sjoerg	    /*
88621826Sjoerg	     * We didn't get all databufs required to complete a new
88721826Sjoerg	     * receive buffer.  Keep the ones we got and retry a bit
88821826Sjoerg	     * later for the rest.
88921826Sjoerg	     */
89021826Sjoerg	    break;
89121826Sjoerg	}
89221826Sjoerg	PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask);
89321826Sjoerg	rx->rx_free -= PDQ_RX_SEGCNT;
89421826Sjoerg    }
89521826Sjoerg}
89621826Sjoerg
89793383Smdoddstatic void pdq_process_transmitted_data(pdq_t *pdq);
89893383Smdodd
89921826Sjoergpdq_boolean_t
90021826Sjoergpdq_queue_transmit_data(
90121826Sjoerg    pdq_t *pdq,
90221826Sjoerg    PDQ_OS_DATABUF_T *pdu)
90321826Sjoerg{
90493383Smdodd    pdq_tx_info_t * const tx = &pdq->pdq_tx_info;
90593383Smdodd    pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
90621826Sjoerg    pdq_uint32_t producer = tx->tx_producer;
90721826Sjoerg    pdq_txdesc_t *eop = NULL;
90821826Sjoerg    PDQ_OS_DATABUF_T *pdu0;
90921826Sjoerg    pdq_uint32_t freecnt;
91093383Smdodd#if defined(PDQ_BUS_DMA)
91193383Smdodd    bus_dmamap_t map;
91293383Smdodd#endif
91321826Sjoerg
91493383Smdodd  again:
91593383Smdodd    if (PDQ_RX_FC_OFFSET == PDQ_OS_HDR_OFFSET) {
91693383Smdodd	freecnt = tx->tx_free - 1;
91793383Smdodd    } else {
91893383Smdodd	freecnt = tx->tx_free;
91993383Smdodd    }
92093383Smdodd    /*
92193383Smdodd     * Need 2 or more descriptors to be able to send.
92293383Smdodd     */
92393383Smdodd    if (freecnt == 0) {
92493383Smdodd	pdq->pdq_intrmask |= PDQ_HOST_INT_TX_ENABLE;
92593383Smdodd	PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask);
92621826Sjoerg	return PDQ_FALSE;
92793383Smdodd    }
92821826Sjoerg
92993383Smdodd    if (PDQ_RX_FC_OFFSET == PDQ_OS_HDR_OFFSET) {
93093383Smdodd	dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc;
93193383Smdodd	PDQ_OS_DESC_PRESYNC(pdq, &dbp->pdqdb_transmits[producer], sizeof(pdq_txdesc_t));
93293383Smdodd	PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
93393383Smdodd    }
93421826Sjoerg
93593383Smdodd#if defined(PDQ_BUS_DMA)
93693383Smdodd    map = M_GETCTX(pdu, bus_dmamap_t);
93793383Smdodd    if (freecnt >= map->dm_nsegs) {
93893383Smdodd	int idx;
93993383Smdodd	for (idx = 0; idx < map->dm_nsegs; idx++) {
94093383Smdodd	    /*
94193383Smdodd	     * Initialize the transmit descriptor
94293383Smdodd	     */
94393383Smdodd	    eop = &dbp->pdqdb_transmits[producer];
94493383Smdodd	    eop->txd_seg_len = map->dm_segs[idx].ds_len;
94593383Smdodd	    eop->txd_pa_lo = map->dm_segs[idx].ds_addr;
94693383Smdodd	    eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
94793383Smdodd	    PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t));
94893383Smdodd	    freecnt--;
94993383Smdodd	    PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
95093383Smdodd	}
95193383Smdodd	pdu0 = NULL;
95293383Smdodd    } else {
95393383Smdodd	pdu0 = pdu;
95493383Smdodd    }
95593383Smdodd#else
95621826Sjoerg    for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) {
95721826Sjoerg	pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0);
95821826Sjoerg	const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0);
95921826Sjoerg
96021826Sjoerg	/*
96121826Sjoerg	 * The first segment is limited to the space remaining in
96221826Sjoerg	 * page.  All segments after that can be up to a full page
96321826Sjoerg	 * in size.
96421826Sjoerg	 */
96521826Sjoerg	fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1));
96621826Sjoerg	while (datalen > 0 && freecnt > 0) {
96721826Sjoerg	    pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen);
96821826Sjoerg
96921826Sjoerg	    /*
97021826Sjoerg	     * Initialize the transmit descriptor
97121826Sjoerg	     */
97221826Sjoerg	    eop = &dbp->pdqdb_transmits[producer];
97321826Sjoerg	    eop->txd_seg_len = seglen;
97493383Smdodd	    eop->txd_pa_lo = PDQ_OS_VA_TO_BUSPA(pdq, dataptr);
97521826Sjoerg	    eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
97693383Smdodd	    PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t));
97721826Sjoerg	    datalen -= seglen;
97821826Sjoerg	    dataptr += seglen;
97921826Sjoerg	    fraglen = PDQ_OS_PAGESIZE;
98021826Sjoerg	    freecnt--;
98121826Sjoerg	    PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
98221826Sjoerg	}
98321826Sjoerg	pdu0 = PDQ_OS_DATABUF_NEXT(pdu0);
98421826Sjoerg    }
98593383Smdodd#endif /* defined(PDQ_BUS_DMA) */
98621826Sjoerg    if (pdu0 != NULL) {
98793383Smdodd	unsigned completion = tx->tx_completion;
98821826Sjoerg	PDQ_ASSERT(freecnt == 0);
98993383Smdodd	PDQ_OS_CONSUMER_POSTSYNC(pdq);
99093383Smdodd	pdq_process_transmitted_data(pdq);
99193383Smdodd	if (completion != tx->tx_completion) {
99293383Smdodd	    producer = tx->tx_producer;
99393383Smdodd	    eop = NULL;
99493383Smdodd	    goto again;
99593383Smdodd	}
99621826Sjoerg	/*
99721826Sjoerg	 * If we still have data to process then the ring was too full
99821826Sjoerg	 * to store the PDU.  Return FALSE so the caller will requeue
99921826Sjoerg	 * the PDU for later.
100021826Sjoerg	 */
100193383Smdodd	pdq->pdq_intrmask |= PDQ_HOST_INT_TX_ENABLE;
100293383Smdodd	PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask);
100321826Sjoerg	return PDQ_FALSE;
100421826Sjoerg    }
100521826Sjoerg    /*
100621826Sjoerg     * Everything went fine.  Finish it up.
100721826Sjoerg     */
100821826Sjoerg    tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt;
100993383Smdodd    if (PDQ_RX_FC_OFFSET != PDQ_OS_HDR_OFFSET) {
101093383Smdodd	dbp->pdqdb_transmits[tx->tx_producer].txd_sop = 1;
101193383Smdodd	PDQ_OS_DESC_PRESYNC(pdq, &dbp->pdqdb_transmits[tx->tx_producer],
101293383Smdodd	    sizeof(pdq_txdesc_t));
101393383Smdodd    }
101421826Sjoerg    eop->txd_eop = 1;
101593383Smdodd    PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t));
101621826Sjoerg    PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu);
101721826Sjoerg    tx->tx_producer = producer;
101821826Sjoerg    tx->tx_free = freecnt;
101921826Sjoerg    PDQ_DO_TYPE2_PRODUCER(pdq);
102021826Sjoerg    return PDQ_TRUE;
102121826Sjoerg}
102221826Sjoerg
102321826Sjoergstatic void
102421826Sjoergpdq_process_transmitted_data(
102521826Sjoerg    pdq_t *pdq)
102621826Sjoerg{
102721826Sjoerg    pdq_tx_info_t *tx = &pdq->pdq_tx_info;
102821826Sjoerg    volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
102921826Sjoerg    pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
103021826Sjoerg    pdq_uint32_t completion = tx->tx_completion;
103193383Smdodd    int reclaimed = 0;
103221826Sjoerg
103321826Sjoerg    while (completion != cbp->pdqcb_transmits) {
103421826Sjoerg	PDQ_OS_DATABUF_T *pdu;
103521826Sjoerg	pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion];
103621826Sjoerg	PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1);
103721826Sjoerg	PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1);
103821826Sjoerg	PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
103921826Sjoerg	pdq_os_transmit_done(pdq, pdu);
104021826Sjoerg	tx->tx_free += descriptor_count;
104193383Smdodd	reclaimed = 1;
104221826Sjoerg	PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits));
104321826Sjoerg    }
104421826Sjoerg    if (tx->tx_completion != completion) {
104521826Sjoerg	tx->tx_completion = completion;
104693383Smdodd	pdq->pdq_intrmask &= ~PDQ_HOST_INT_TX_ENABLE;
104793383Smdodd	PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask);
104821826Sjoerg	pdq_os_restart_transmitter(pdq);
104921826Sjoerg    }
105093383Smdodd    if (reclaimed)
105193383Smdodd	PDQ_DO_TYPE2_PRODUCER(pdq);
105221826Sjoerg}
105321826Sjoerg
105421826Sjoergvoid
105521826Sjoergpdq_flush_transmitter(
105621826Sjoerg    pdq_t *pdq)
105721826Sjoerg{
105821826Sjoerg    volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp;
105921826Sjoerg    pdq_tx_info_t *tx = &pdq->pdq_tx_info;
106021826Sjoerg
106121826Sjoerg    for (;;) {
106221826Sjoerg	PDQ_OS_DATABUF_T *pdu;
106321826Sjoerg	PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
106421826Sjoerg	if (pdu == NULL)
106521826Sjoerg	    break;
106621826Sjoerg	/*
106721826Sjoerg	 * Don't call transmit done since the packet never made it
106821826Sjoerg	 * out on the wire.
106921826Sjoerg	 */
107093383Smdodd	PDQ_OS_DATABUF_FREE(pdq, pdu);
107121826Sjoerg    }
107221826Sjoerg
107321826Sjoerg    tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
107493383Smdodd    cbp->pdqcb_transmits = tx->tx_completion = tx->tx_producer;
107593383Smdodd    PDQ_OS_CONSUMER_PRESYNC(pdq);
107621826Sjoerg
107721826Sjoerg    PDQ_DO_TYPE2_PRODUCER(pdq);
107821826Sjoerg}
107921826Sjoerg
108021826Sjoergvoid
108121826Sjoergpdq_hwreset(
108221826Sjoerg    pdq_t *pdq)
108321826Sjoerg{
108421826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
108521826Sjoerg    pdq_state_t state;
108621826Sjoerg    int cnt;
108721826Sjoerg
108821826Sjoerg    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
108921826Sjoerg    if (state == PDQS_DMA_UNAVAILABLE)
109021826Sjoerg	return;
109121826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_a,
109293383Smdodd		  (state == PDQS_HALTED && pdq->pdq_type != PDQ_DEFTA) ? 0 : PDQ_PRESET_SKIP_SELFTEST);
109321826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_reset, 1);
109421826Sjoerg    PDQ_OS_USEC_DELAY(100);
109521826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_reset, 0);
109693383Smdodd    for (cnt = 100000;;cnt--) {
109721826Sjoerg	PDQ_OS_USEC_DELAY(1000);
109821826Sjoerg	state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
109921826Sjoerg	if (state == PDQS_DMA_UNAVAILABLE || cnt == 0)
110021826Sjoerg	    break;
110121826Sjoerg    }
110293383Smdodd    PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 100000 - cnt));
110321826Sjoerg    PDQ_OS_USEC_DELAY(10000);
110421826Sjoerg    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
110521826Sjoerg    PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
110621826Sjoerg    PDQ_ASSERT(cnt > 0);
110721826Sjoerg}
110821826Sjoerg
110921826Sjoerg/*
111021826Sjoerg * The following routine brings the PDQ from whatever state it is
111121826Sjoerg * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET).
111221826Sjoerg */
111321826Sjoergpdq_state_t
111421826Sjoergpdq_stop(
111521826Sjoerg    pdq_t *pdq)
111621826Sjoerg{
111721826Sjoerg    pdq_state_t state;
111821826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
111921826Sjoerg    int cnt, pass = 0, idx;
112021826Sjoerg    PDQ_OS_DATABUF_T **buffers;
112121826Sjoerg
112221826Sjoerg  restart:
112321826Sjoerg    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
112421826Sjoerg    if (state != PDQS_DMA_UNAVAILABLE) {
112521826Sjoerg	pdq_hwreset(pdq);
112621826Sjoerg	state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
112721826Sjoerg	PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
112821826Sjoerg    }
112921826Sjoerg#if 0
113021826Sjoerg    switch (state) {
113121826Sjoerg	case PDQS_RING_MEMBER:
113221826Sjoerg	case PDQS_LINK_UNAVAILABLE:
113321826Sjoerg	case PDQS_LINK_AVAILABLE: {
113421826Sjoerg	    PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_LINK_UNINIT);
113521826Sjoerg	    PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
113621826Sjoerg	    pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
113721826Sjoerg	    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
113821826Sjoerg	    PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
1139102412Scharnier	    /* FALLTHROUGH */
114021826Sjoerg	}
114121826Sjoerg	case PDQS_DMA_AVAILABLE: {
114221826Sjoerg	    PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
114321826Sjoerg	    PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
114421826Sjoerg	    pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT);
114521826Sjoerg	    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
114621826Sjoerg	    PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
1147102412Scharnier	    /* FALLTHROUGH */
114821826Sjoerg	}
114921826Sjoerg	case PDQS_DMA_UNAVAILABLE: {
115021826Sjoerg	    break;
115121826Sjoerg	}
115221826Sjoerg    }
115321826Sjoerg#endif
115421826Sjoerg    /*
115521826Sjoerg     * Now we should be in DMA_UNAVAILABLE.  So bring the PDQ into
115621826Sjoerg     * DMA_AVAILABLE.
115721826Sjoerg     */
115821826Sjoerg
115921826Sjoerg    /*
116021826Sjoerg     * Obtain the hardware address and firmware revisions
116121826Sjoerg     * (MLA = my long address which is FDDI speak for hardware address)
116221826Sjoerg     */
116321826Sjoerg    pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr);
116421826Sjoerg    pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev);
116521826Sjoerg    pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs);
116621826Sjoerg
116721826Sjoerg    if (pdq->pdq_type == PDQ_DEFPA) {
116821826Sjoerg	/*
116921826Sjoerg	 * Disable interrupts and DMA.
117021826Sjoerg	 */
117121826Sjoerg	PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 0);
117221826Sjoerg	PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x10);
117321826Sjoerg    }
117421826Sjoerg
117521826Sjoerg    /*
117621826Sjoerg     * Flush all the databuf queues.
117721826Sjoerg     */
117893383Smdodd    pdq_flush_databuf_queue(pdq, &pdq->pdq_tx_info.tx_txq);
117993383Smdodd    pdq->pdq_flags &= ~(PDQ_TXOK|PDQ_IS_ONRING|PDQ_IS_FDX);
118021826Sjoerg    buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers;
118121826Sjoerg    for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) {
118221826Sjoerg	if (buffers[idx] != NULL) {
118393383Smdodd	    PDQ_OS_DATABUF_FREE(pdq, buffers[idx]);
118421826Sjoerg	    buffers[idx] = NULL;
118521826Sjoerg	}
118621826Sjoerg    }
118721826Sjoerg    pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
118821826Sjoerg    buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers;
118921826Sjoerg    for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) {
119021826Sjoerg	if (buffers[idx] != NULL) {
119193383Smdodd	    PDQ_OS_DATABUF_FREE(pdq, buffers[idx]);
119221826Sjoerg	    buffers[idx] = NULL;
119321826Sjoerg	}
119421826Sjoerg    }
119521826Sjoerg    pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
119621826Sjoerg
119721826Sjoerg    /*
119821826Sjoerg     * Reset the consumer indexes to 0.
119921826Sjoerg     */
120021826Sjoerg    pdq->pdq_cbp->pdqcb_receives = 0;
120121826Sjoerg    pdq->pdq_cbp->pdqcb_transmits = 0;
120221826Sjoerg    pdq->pdq_cbp->pdqcb_host_smt = 0;
120321826Sjoerg    pdq->pdq_cbp->pdqcb_unsolicited_event = 0;
120421826Sjoerg    pdq->pdq_cbp->pdqcb_command_response = 0;
120521826Sjoerg    pdq->pdq_cbp->pdqcb_command_request = 0;
120693383Smdodd    PDQ_OS_CONSUMER_PRESYNC(pdq);
120721826Sjoerg
120821826Sjoerg    /*
120921826Sjoerg     * Reset the producer and completion indexes to 0.
121021826Sjoerg     */
121121826Sjoerg    pdq->pdq_command_info.ci_request_producer = 0;
121221826Sjoerg    pdq->pdq_command_info.ci_response_producer = 0;
121321826Sjoerg    pdq->pdq_command_info.ci_request_completion = 0;
121421826Sjoerg    pdq->pdq_command_info.ci_response_completion = 0;
121521826Sjoerg    pdq->pdq_unsolicited_info.ui_producer = 0;
121621826Sjoerg    pdq->pdq_unsolicited_info.ui_completion = 0;
121721826Sjoerg    pdq->pdq_rx_info.rx_producer = 0;
121821826Sjoerg    pdq->pdq_rx_info.rx_completion = 0;
121921826Sjoerg    pdq->pdq_tx_info.tx_producer = 0;
122021826Sjoerg    pdq->pdq_tx_info.tx_completion = 0;
122121826Sjoerg    pdq->pdq_host_smt_info.rx_producer = 0;
122221826Sjoerg    pdq->pdq_host_smt_info.rx_completion = 0;
122321826Sjoerg
122421826Sjoerg    pdq->pdq_command_info.ci_command_active = 0;
122521826Sjoerg    pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
122621826Sjoerg    pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
122721826Sjoerg
122821826Sjoerg    /*
122921826Sjoerg     * Allow the DEFPA to do DMA.  Then program the physical
123021826Sjoerg     * addresses of the consumer and descriptor blocks.
123121826Sjoerg     */
123221826Sjoerg    if (pdq->pdq_type == PDQ_DEFPA) {
123321826Sjoerg#ifdef PDQTEST
123421826Sjoerg	PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
123521826Sjoerg		      PDQ_PFI_MODE_DMA_ENABLE);
123621826Sjoerg#else
123721826Sjoerg	PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
123821826Sjoerg		      PDQ_PFI_MODE_DMA_ENABLE
123921826Sjoerg	    /*|PDQ_PFI_MODE_PFI_PCI_INTR*/|PDQ_PFI_MODE_PDQ_PCI_INTR);
124021826Sjoerg#endif
124121826Sjoerg    }
124221826Sjoerg
124321826Sjoerg    /*
124421826Sjoerg     * Make sure the unsolicited queue has events ...
124521826Sjoerg     */
124621826Sjoerg    pdq_process_unsolicited_events(pdq);
124721826Sjoerg
124893383Smdodd    if ((pdq->pdq_type == PDQ_DEFEA && pdq->pdq_chip_rev == PDQ_CHIP_REV_E)
124993383Smdodd	    || pdq->pdq_type == PDQ_DEFTA)
125021826Sjoerg	PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_16LW);
125121826Sjoerg    else
125221826Sjoerg	PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_8LW);
125321826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_DMA_BURST_SIZE_SET);
125421826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
125521826Sjoerg
125693383Smdodd    /*
125793383Smdodd     * Make sure there isn't stale information in the caches before
125893383Smdodd     * tell the adapter about the blocks it's going to use.
125993383Smdodd     */
126093383Smdodd    PDQ_OS_CONSUMER_PRESYNC(pdq);
126193383Smdodd
126221826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
126393383Smdodd    PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_consumer_block);
126421826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK);
126521826Sjoerg
126621826Sjoerg    PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
126793383Smdodd#if !defined(BYTE_ORDER) || BYTE_ORDER == LITTLE_ENDIAN
126893383Smdodd    PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_descriptor_block | PDQ_DMA_INIT_LW_BSWAP_DATA);
126993383Smdodd#else
127093383Smdodd    PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_descriptor_block | PDQ_DMA_INIT_LW_BSWAP_DATA | PDQ_DMA_INIT_LW_BSWAP_LITERAL);
127193383Smdodd#endif
127221826Sjoerg    pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT);
127321826Sjoerg
127421826Sjoerg    for (cnt = 0; cnt < 1000; cnt++) {
127521826Sjoerg	state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
127621826Sjoerg	if (state == PDQS_HALTED) {
127721826Sjoerg	    if (pass > 0)
127821826Sjoerg		return PDQS_HALTED;
127921826Sjoerg	    pass = 1;
128021826Sjoerg	    goto restart;
128121826Sjoerg	}
128221826Sjoerg	if (state == PDQS_DMA_AVAILABLE) {
128321826Sjoerg	    PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt));
128421826Sjoerg	    break;
128521826Sjoerg	}
128621826Sjoerg	PDQ_OS_USEC_DELAY(1000);
128721826Sjoerg    }
128821826Sjoerg    PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
128921826Sjoerg
129021826Sjoerg    PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
129193383Smdodd    pdq->pdq_intrmask = 0;
129293383Smdodd      /* PDQ_HOST_INT_STATE_CHANGE
129321826Sjoerg	|PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE
1294297793Spfg	|PDQ_HOST_INT_UNSOL_ENABLE */
129593383Smdodd    PDQ_CSR_WRITE(csrs, csr_host_int_enable, pdq->pdq_intrmask);
129621826Sjoerg
129721826Sjoerg    /*
129821826Sjoerg     * Any other command but START should be valid.
129921826Sjoerg     */
130021826Sjoerg    pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START));
130121826Sjoerg    if (pdq->pdq_flags & PDQ_PRINTCHARS)
130221826Sjoerg	pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
130321826Sjoerg    pdq_queue_commands(pdq);
130421826Sjoerg
130521826Sjoerg    if (pdq->pdq_flags & PDQ_PRINTCHARS) {
130621826Sjoerg	/*
130721826Sjoerg	 * Now wait (up to 100ms) for the command(s) to finish.
130821826Sjoerg	 */
130921826Sjoerg	for (cnt = 0; cnt < 1000; cnt++) {
131093383Smdodd	    PDQ_OS_CONSUMER_POSTSYNC(pdq);
131121826Sjoerg	    pdq_process_command_responses(pdq);
131221826Sjoerg	    if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion)
131321826Sjoerg		break;
131421826Sjoerg	    PDQ_OS_USEC_DELAY(1000);
131521826Sjoerg	}
131621826Sjoerg	state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
131721826Sjoerg    }
131821826Sjoerg
131921826Sjoerg    return state;
132021826Sjoerg}
132121826Sjoerg
132221826Sjoergvoid
132321826Sjoergpdq_run(
132421826Sjoerg    pdq_t *pdq)
132521826Sjoerg{
132621826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
132721826Sjoerg    pdq_state_t state;
132821826Sjoerg
132921826Sjoerg    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
133021826Sjoerg    PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE);
133121826Sjoerg    PDQ_ASSERT(state != PDQS_RESET);
133221826Sjoerg    PDQ_ASSERT(state != PDQS_HALTED);
133321826Sjoerg    PDQ_ASSERT(state != PDQS_UPGRADE);
133421826Sjoerg    PDQ_ASSERT(state != PDQS_RING_MEMBER);
133521826Sjoerg    switch (state) {
133621826Sjoerg	case PDQS_DMA_AVAILABLE: {
133721826Sjoerg	    /*
133821826Sjoerg	     * The PDQ after being reset screws up some of its state.
133921826Sjoerg	     * So we need to clear all the errors/interrupts so the real
134021826Sjoerg	     * ones will get through.
134121826Sjoerg	     */
134221826Sjoerg	    PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
134393383Smdodd	    pdq->pdq_intrmask = PDQ_HOST_INT_STATE_CHANGE
134493383Smdodd		|PDQ_HOST_INT_XMT_DATA_FLUSH|PDQ_HOST_INT_FATAL_ERROR
134593383Smdodd		|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE
134693383Smdodd		|PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE;
134793383Smdodd	    PDQ_CSR_WRITE(csrs, csr_host_int_enable, pdq->pdq_intrmask);
134821826Sjoerg	    /*
134921826Sjoerg	     * Set the MAC and address filters and start up the PDQ.
135021826Sjoerg	     */
135121826Sjoerg	    pdq_process_unsolicited_events(pdq);
135221826Sjoerg	    pdq_process_received_data(pdq, &pdq->pdq_rx_info,
135321826Sjoerg				      pdq->pdq_dbp->pdqdb_receives,
135421826Sjoerg				      pdq->pdq_cbp->pdqcb_receives,
135521826Sjoerg				      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
135621826Sjoerg	    PDQ_DO_TYPE2_PRODUCER(pdq);
135721826Sjoerg	    if (pdq->pdq_flags & PDQ_PASS_SMT) {
135821826Sjoerg		pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
135921826Sjoerg					  pdq->pdq_dbp->pdqdb_host_smt,
136021826Sjoerg					  pdq->pdq_cbp->pdqcb_host_smt,
136121826Sjoerg					  PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
136221826Sjoerg		PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
136321826Sjoerg			      pdq->pdq_host_smt_info.rx_producer
136421826Sjoerg			          | (pdq->pdq_host_smt_info.rx_completion << 8));
136521826Sjoerg	    }
136621826Sjoerg	    pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
136793383Smdodd		| PDQ_BITMASK(PDQC_ADDR_FILTER_SET)
136893383Smdodd		| PDQ_BITMASK(PDQC_SNMP_SET)
136993383Smdodd		| PDQ_BITMASK(PDQC_START);
137021826Sjoerg	    if (pdq->pdq_flags & PDQ_PRINTCHARS)
137121826Sjoerg		pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
137221826Sjoerg	    pdq_queue_commands(pdq);
137321826Sjoerg	    break;
137421826Sjoerg	}
137521826Sjoerg	case PDQS_LINK_UNAVAILABLE:
137621826Sjoerg	case PDQS_LINK_AVAILABLE: {
137721826Sjoerg	    pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
137893383Smdodd		| PDQ_BITMASK(PDQC_ADDR_FILTER_SET)
137993383Smdodd		| PDQ_BITMASK(PDQC_SNMP_SET);
138021826Sjoerg	    if (pdq->pdq_flags & PDQ_PRINTCHARS)
138121826Sjoerg		pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
138221826Sjoerg	    if (pdq->pdq_flags & PDQ_PASS_SMT) {
138321826Sjoerg		pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
138421826Sjoerg					  pdq->pdq_dbp->pdqdb_host_smt,
138521826Sjoerg					  pdq->pdq_cbp->pdqcb_host_smt,
138621826Sjoerg					  PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
138721826Sjoerg		PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
138821826Sjoerg			      pdq->pdq_host_smt_info.rx_producer
138921826Sjoerg			          | (pdq->pdq_host_smt_info.rx_completion << 8));
139021826Sjoerg	    }
139121826Sjoerg	    pdq_process_unsolicited_events(pdq);
139221826Sjoerg	    pdq_queue_commands(pdq);
139321826Sjoerg	    break;
139421826Sjoerg	}
139521826Sjoerg	case PDQS_RING_MEMBER: {
139621826Sjoerg	}
139721826Sjoerg	default: {	/* to make gcc happy */
139821826Sjoerg	    break;
139921826Sjoerg	}
140021826Sjoerg    }
140121826Sjoerg}
140221826Sjoerg
140321826Sjoergint
140421826Sjoergpdq_interrupt(
140521826Sjoerg    pdq_t *pdq)
140621826Sjoerg{
140721826Sjoerg    const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
140821826Sjoerg    pdq_uint32_t data;
140921826Sjoerg    int progress = 0;
141021826Sjoerg
141121826Sjoerg    if (pdq->pdq_type == PDQ_DEFPA)
141221826Sjoerg	PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
141321826Sjoerg
141421826Sjoerg    while ((data = PDQ_CSR_READ(csrs, csr_port_status)) & PDQ_PSTS_INTR_PENDING) {
141521826Sjoerg	progress = 1;
141621826Sjoerg	PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data));
141793383Smdodd	PDQ_OS_CONSUMER_POSTSYNC(pdq);
141821826Sjoerg	if (data & PDQ_PSTS_RCV_DATA_PENDING) {
141921826Sjoerg	    pdq_process_received_data(pdq, &pdq->pdq_rx_info,
142021826Sjoerg				      pdq->pdq_dbp->pdqdb_receives,
142121826Sjoerg				      pdq->pdq_cbp->pdqcb_receives,
142221826Sjoerg				      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
142321826Sjoerg	    PDQ_DO_TYPE2_PRODUCER(pdq);
142421826Sjoerg	}
142521826Sjoerg	if (data & PDQ_PSTS_HOST_SMT_PENDING) {
142621826Sjoerg	    pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
142721826Sjoerg				      pdq->pdq_dbp->pdqdb_host_smt,
142821826Sjoerg				      pdq->pdq_cbp->pdqcb_host_smt,
142921826Sjoerg				      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
143021826Sjoerg	    PDQ_DO_HOST_SMT_PRODUCER(pdq);
143121826Sjoerg	}
143293383Smdodd	/* if (data & PDQ_PSTS_XMT_DATA_PENDING) */
143321826Sjoerg	    pdq_process_transmitted_data(pdq);
143421826Sjoerg	if (data & PDQ_PSTS_UNSOL_PENDING)
143521826Sjoerg	    pdq_process_unsolicited_events(pdq);
143621826Sjoerg	if (data & PDQ_PSTS_CMD_RSP_PENDING)
143721826Sjoerg	    pdq_process_command_responses(pdq);
143821826Sjoerg	if (data & PDQ_PSTS_TYPE_0_PENDING) {
143921826Sjoerg	    data = PDQ_CSR_READ(csrs, csr_host_int_type_0);
144021826Sjoerg	    if (data & PDQ_HOST_INT_STATE_CHANGE) {
144121826Sjoerg		pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
144221826Sjoerg		printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]);
144321826Sjoerg		if (state == PDQS_LINK_UNAVAILABLE) {
144493383Smdodd		    pdq->pdq_flags &= ~(PDQ_TXOK|PDQ_IS_ONRING|PDQ_IS_FDX);
144521826Sjoerg		} else if (state == PDQS_LINK_AVAILABLE) {
144693383Smdodd		    if (pdq->pdq_flags & PDQ_WANT_FDX) {
144793383Smdodd			pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_DEC_EXT_MIB_GET);
144893383Smdodd			pdq_queue_commands(pdq);
144993383Smdodd		    }
145093383Smdodd		    pdq->pdq_flags |= PDQ_TXOK|PDQ_IS_ONRING;
145121826Sjoerg		    pdq_os_restart_transmitter(pdq);
145221826Sjoerg		} else if (state == PDQS_HALTED) {
145321826Sjoerg		    pdq_response_error_log_get_t log_entry;
145421826Sjoerg		    pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(csrs, csr_port_status));
145521826Sjoerg		    printf(": halt code = %d (%s)\n",
145621826Sjoerg			   halt_code, pdq_halt_codes[halt_code]);
145721826Sjoerg		    if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) {
145821826Sjoerg			PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
145921826Sjoerg			       PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
146021826Sjoerg			       data & PDQ_HOST_INT_FATAL_ERROR));
146121826Sjoerg		    }
146293383Smdodd		    PDQ_OS_MEMZERO(&log_entry, sizeof(log_entry));
146393383Smdodd		    if (pdq_read_error_log(pdq, &log_entry)) {
146493383Smdodd			PDQ_PRINTF(("  Error log Entry:\n"));
146593383Smdodd			PDQ_PRINTF(("    CMD Status           = %d (0x%x)\n",
146693383Smdodd				    log_entry.error_log_get_status,
146793383Smdodd				    log_entry.error_log_get_status));
146893383Smdodd			PDQ_PRINTF(("    Event Status         = %d (0x%x)\n",
146993383Smdodd				    log_entry.error_log_get_event_status,
147093383Smdodd				    log_entry.error_log_get_event_status));
147193383Smdodd			PDQ_PRINTF(("    Caller Id            = %d (0x%x)\n",
147293383Smdodd				    log_entry.error_log_get_caller_id,
147393383Smdodd				    log_entry.error_log_get_caller_id));
147493383Smdodd			PDQ_PRINTF(("    Write Count          = %d (0x%x)\n",
147593383Smdodd				    log_entry.error_log_get_write_count,
147693383Smdodd				    log_entry.error_log_get_write_count));
147793383Smdodd			PDQ_PRINTF(("    FRU Implication Mask = %d (0x%x)\n",
147893383Smdodd				    log_entry.error_log_get_fru_implication_mask,
147993383Smdodd				    log_entry.error_log_get_fru_implication_mask));
148093383Smdodd			PDQ_PRINTF(("    Test ID              = %d (0x%x)\n",
148193383Smdodd				    log_entry.error_log_get_test_id,
148293383Smdodd				    log_entry.error_log_get_test_id));
148393383Smdodd		    }
148421826Sjoerg		    pdq_stop(pdq);
148521826Sjoerg		    if (pdq->pdq_flags & PDQ_RUNNING)
148621826Sjoerg			pdq_run(pdq);
148721826Sjoerg		    return 1;
148821826Sjoerg		}
148921826Sjoerg		printf("\n");
149021826Sjoerg		PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_STATE_CHANGE);
149121826Sjoerg	    }
149221826Sjoerg	    if (data & PDQ_HOST_INT_FATAL_ERROR) {
149321826Sjoerg		pdq_stop(pdq);
149421826Sjoerg		if (pdq->pdq_flags & PDQ_RUNNING)
149521826Sjoerg		    pdq_run(pdq);
149621826Sjoerg		return 1;
149721826Sjoerg	    }
149821826Sjoerg	    if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) {
149921826Sjoerg		printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS);
150021826Sjoerg		pdq->pdq_flags &= ~PDQ_TXOK;
150121826Sjoerg		pdq_flush_transmitter(pdq);
150221826Sjoerg		pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE);
150321826Sjoerg		PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_XMT_DATA_FLUSH);
150421826Sjoerg	    }
150521826Sjoerg	}
150621826Sjoerg	if (pdq->pdq_type == PDQ_DEFPA)
150721826Sjoerg	    PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
150821826Sjoerg    }
150921826Sjoerg    return progress;
151021826Sjoerg}
151121826Sjoerg
151221826Sjoergpdq_t *
151321826Sjoergpdq_initialize(
151421826Sjoerg    pdq_bus_t bus,
151521826Sjoerg    pdq_bus_memaddr_t csr_base,
151621826Sjoerg    const char *name,
151721826Sjoerg    int unit,
151821826Sjoerg    void *ctx,
151921826Sjoerg    pdq_type_t type)
152021826Sjoerg{
152121826Sjoerg    pdq_t *pdq;
152221826Sjoerg    pdq_state_t state;
152393383Smdodd    pdq_descriptor_block_t *dbp;
152493383Smdodd#if !defined(PDQ_BUS_DMA)
152521826Sjoerg    const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE;
152621826Sjoerg    pdq_uint8_t *p;
152793383Smdodd#endif
152821826Sjoerg    int idx;
152921826Sjoerg
153021826Sjoerg    PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192);
153121826Sjoerg    PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64);
153221826Sjoerg    PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET);
153321826Sjoerg    PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET);
153421826Sjoerg    PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET);
153521826Sjoerg    PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET);
153621826Sjoerg    PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET);
153721826Sjoerg    PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET);
153821826Sjoerg    PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512);
153921826Sjoerg
154021826Sjoerg    pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t));
154121826Sjoerg    if (pdq == NULL) {
154221826Sjoerg	PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq)));
154321826Sjoerg	return NULL;
154421826Sjoerg    }
154521826Sjoerg    PDQ_OS_MEMZERO(pdq, sizeof(pdq_t));
154621826Sjoerg    pdq->pdq_type = type;
154721826Sjoerg    pdq->pdq_unit = unit;
154821826Sjoerg    pdq->pdq_os_ctx = (void *) ctx;
154921826Sjoerg    pdq->pdq_os_name = name;
155021826Sjoerg    pdq->pdq_flags = PDQ_PRINTCHARS;
155121826Sjoerg    /*
155221826Sjoerg     * Allocate the additional data structures required by
155321826Sjoerg     * the PDQ driver.  Allocate a contiguous region of memory
155421826Sjoerg     * for the descriptor block.  We need to allocated enough
155521826Sjoerg     * to guarantee that we will a get 8KB block of memory aligned
155621826Sjoerg     * on a 8KB boundary.  This turns to require that we allocate
155721826Sjoerg     * (N*2 - 1 page) pages of memory.  On machine with less than
155821826Sjoerg     * a 8KB page size, it mean we will allocate more memory than
155921826Sjoerg     * we need.  The extra will be used for the unsolicited event
156021826Sjoerg     * buffers (though on machines with 8KB pages we will to allocate
156121826Sjoerg     * them separately since there will be nothing left overs.)
156221826Sjoerg     */
156393383Smdodd#if defined(PDQ_OS_MEMALLOC_CONTIG)
156421826Sjoerg    p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes);
156593383Smdodd
1566105507Sphk    if (p == NULL)
1567135577Sstefanf	printf("%s() - PDQ_OS_MEMALLOC_CONTIG() failed!\n", __func__);
156893383Smdodd
156921826Sjoerg    if (p != NULL) {
157093383Smdodd	pdq_physaddr_t physaddr = PDQ_OS_VA_TO_BUSPA(pdq, p);
157121826Sjoerg	/*
157221826Sjoerg	 * Assert that we really got contiguous memory.  This isn't really
157321826Sjoerg	 * needed on systems that actually have physical contiguous allocation
157421826Sjoerg	 * routines, but on those systems that don't ...
157521826Sjoerg	 */
157621826Sjoerg	for (idx = PDQ_OS_PAGESIZE; idx < 0x2000; idx += PDQ_OS_PAGESIZE) {
157793383Smdodd	    if (PDQ_OS_VA_TO_BUSPA(pdq, p + idx) - physaddr != idx)
157821826Sjoerg		goto cleanup_and_return;
157921826Sjoerg	}
158093383Smdodd	if (physaddr & 0x1FFF) {
158121826Sjoerg	    pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p;
158293383Smdodd	    pdq->pdq_unsolicited_info.ui_pa_bufstart = physaddr;
158393383Smdodd	    pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - (physaddr & 0x1FFF)];
158493383Smdodd	    pdq->pdq_pa_descriptor_block = physaddr & ~0x1FFFUL;
158521826Sjoerg	} else {
158621826Sjoerg	    pdq->pdq_dbp = (pdq_descriptor_block_t *) p;
158793383Smdodd	    pdq->pdq_pa_descriptor_block = physaddr;
158821826Sjoerg	    pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000];
158993383Smdodd	    pdq->pdq_unsolicited_info.ui_pa_bufstart = physaddr + 0x2000;
159021826Sjoerg	}
159121826Sjoerg    }
159293383Smdodd    pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer;
159393383Smdodd    pdq->pdq_pa_consumer_block = PDQ_DB_BUSPA(pdq, pdq->pdq_cbp);
159421826Sjoerg    if (contig_bytes == sizeof(pdq_descriptor_block_t)) {
159521826Sjoerg	pdq->pdq_unsolicited_info.ui_events =
159621826Sjoerg	    (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC(
159721826Sjoerg		PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
159821826Sjoerg    }
159993383Smdodd#else
160093383Smdodd    if (pdq_os_memalloc_contig(pdq))
160193383Smdodd	goto cleanup_and_return;
160293383Smdodd#endif
160321826Sjoerg
160421826Sjoerg    /*
160521826Sjoerg     * Make sure everything got allocated.  If not, free what did
160621826Sjoerg     * get allocated and return.
160721826Sjoerg     */
160821826Sjoerg    if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) {
160921826Sjoerg      cleanup_and_return:
161093383Smdodd#ifdef PDQ_OS_MEMFREE_CONTIG
161121826Sjoerg	if (p /* pdq->pdq_dbp */ != NULL)
161221826Sjoerg	    PDQ_OS_MEMFREE_CONTIG(p /* pdq->pdq_dbp */, contig_bytes);
161321826Sjoerg	if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL)
161421826Sjoerg	    PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events,
161521826Sjoerg			   PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
161693383Smdodd#endif
161721826Sjoerg	PDQ_OS_MEMFREE(pdq, sizeof(pdq_t));
161821826Sjoerg	return NULL;
161921826Sjoerg    }
162093383Smdodd    dbp = pdq->pdq_dbp;
162121826Sjoerg
162293383Smdodd    PDQ_PRINTF(("\nPDQ Descriptor Block = " PDQ_OS_PTR_FMT " (PA = 0x%x)\n", dbp, pdq->pdq_pa_descriptor_block));
162393383Smdodd    PDQ_PRINTF(("    Receive Queue          = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_receives));
162493383Smdodd    PDQ_PRINTF(("    Transmit Queue         = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_transmits));
162593383Smdodd    PDQ_PRINTF(("    Host SMT Queue         = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_host_smt));
162693383Smdodd    PDQ_PRINTF(("    Command Response Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_command_responses));
162793383Smdodd    PDQ_PRINTF(("    Command Request Queue  = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_command_requests));
162821826Sjoerg    PDQ_PRINTF(("PDQ Consumer Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_cbp));
162921826Sjoerg
163021826Sjoerg    /*
163121826Sjoerg     * Zero out the descriptor block.  Not really required but
163221826Sjoerg     * it pays to be neat.  This will also zero out the consumer
163321826Sjoerg     * block, command pool, and buffer pointers for the receive
163421826Sjoerg     * host_smt rings.
163521826Sjoerg     */
163693383Smdodd    PDQ_OS_MEMZERO(dbp, sizeof(*dbp));
163721826Sjoerg
163821826Sjoerg    /*
163921826Sjoerg     * Initialize the CSR references.
164021826Sjoerg     * the DEFAA (FutureBus+) skips a longword between registers
164121826Sjoerg     */
164221826Sjoerg    pdq_init_csrs(&pdq->pdq_csrs, bus, csr_base, pdq->pdq_type == PDQ_DEFAA ? 2 : 1);
164321826Sjoerg    if (pdq->pdq_type == PDQ_DEFPA)
164421826Sjoerg	pdq_init_pci_csrs(&pdq->pdq_pci_csrs, bus, csr_base, 1);
164521826Sjoerg
164693383Smdodd    PDQ_PRINTF(("PDQ CSRs: BASE = " PDQ_OS_CSR_FMT "\n", pdq->pdq_csrs.csr_base));
164793383Smdodd    PDQ_PRINTF(("    Port Reset                = " PDQ_OS_CSR_FMT " [0x%08x]\n",
164821826Sjoerg	   pdq->pdq_csrs.csr_port_reset, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_reset)));
164993383Smdodd    PDQ_PRINTF(("    Host Data                 = " PDQ_OS_CSR_FMT " [0x%08x]\n",
165021826Sjoerg	   pdq->pdq_csrs.csr_host_data, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_data)));
165193383Smdodd    PDQ_PRINTF(("    Port Control              = " PDQ_OS_CSR_FMT " [0x%08x]\n",
165221826Sjoerg	   pdq->pdq_csrs.csr_port_control, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_control)));
165393383Smdodd    PDQ_PRINTF(("    Port Data A               = " PDQ_OS_CSR_FMT " [0x%08x]\n",
165421826Sjoerg	   pdq->pdq_csrs.csr_port_data_a, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_a)));
165593383Smdodd    PDQ_PRINTF(("    Port Data B               = " PDQ_OS_CSR_FMT " [0x%08x]\n",
165621826Sjoerg	   pdq->pdq_csrs.csr_port_data_b, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_b)));
165793383Smdodd    PDQ_PRINTF(("    Port Status               = " PDQ_OS_CSR_FMT " [0x%08x]\n",
165821826Sjoerg	   pdq->pdq_csrs.csr_port_status, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)));
165993383Smdodd    PDQ_PRINTF(("    Host Int Type 0           = " PDQ_OS_CSR_FMT " [0x%08x]\n",
166021826Sjoerg	   pdq->pdq_csrs.csr_host_int_type_0, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0)));
166193383Smdodd    PDQ_PRINTF(("    Host Int Enable           = " PDQ_OS_CSR_FMT " [0x%08x]\n",
166221826Sjoerg	   pdq->pdq_csrs.csr_host_int_enable, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_enable)));
166393383Smdodd    PDQ_PRINTF(("    Type 2 Producer           = " PDQ_OS_CSR_FMT " [0x%08x]\n",
166421826Sjoerg	   pdq->pdq_csrs.csr_type_2_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_type_2_producer)));
166593383Smdodd    PDQ_PRINTF(("    Command Response Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n",
166621826Sjoerg	   pdq->pdq_csrs.csr_cmd_response_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_response_producer)));
166793383Smdodd    PDQ_PRINTF(("    Command Request Producer  = " PDQ_OS_CSR_FMT " [0x%08x]\n",
166821826Sjoerg	   pdq->pdq_csrs.csr_cmd_request_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_request_producer)));
166993383Smdodd    PDQ_PRINTF(("    Host SMT Producer         = " PDQ_OS_CSR_FMT " [0x%08x]\n",
167021826Sjoerg	   pdq->pdq_csrs.csr_host_smt_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_smt_producer)));
167193383Smdodd    PDQ_PRINTF(("    Unsolicited Producer      = " PDQ_OS_CSR_FMT " [0x%08x]\n",
167221826Sjoerg	   pdq->pdq_csrs.csr_unsolicited_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_unsolicited_producer)));
167321826Sjoerg
167421826Sjoerg    /*
167521826Sjoerg     * Initialize the command information block
167621826Sjoerg     */
167793383Smdodd    pdq->pdq_command_info.ci_request_bufstart = dbp->pdqdb_cmd_request_buf;
167893383Smdodd    pdq->pdq_command_info.ci_pa_request_bufstart = PDQ_DB_BUSPA(pdq, pdq->pdq_command_info.ci_request_bufstart);
167993383Smdodd    pdq->pdq_command_info.ci_pa_request_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_command_requests);
168093383Smdodd    PDQ_PRINTF(("PDQ Command Request Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n",
168193383Smdodd		pdq->pdq_command_info.ci_request_bufstart,
168293383Smdodd		pdq->pdq_command_info.ci_pa_request_bufstart));
168393383Smdodd    for (idx = 0; idx < sizeof(dbp->pdqdb_command_requests)/sizeof(dbp->pdqdb_command_requests[0]); idx++) {
168493383Smdodd	pdq_txdesc_t *txd = &dbp->pdqdb_command_requests[idx];
168521826Sjoerg
168693383Smdodd	txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_request_bufstart;
168721826Sjoerg	txd->txd_eop = txd->txd_sop = 1;
168821826Sjoerg	txd->txd_pa_hi = 0;
168921826Sjoerg    }
169093383Smdodd    PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_command_requests,
169193383Smdodd			sizeof(dbp->pdqdb_command_requests));
169221826Sjoerg
169393383Smdodd    pdq->pdq_command_info.ci_response_bufstart = dbp->pdqdb_cmd_response_buf;
169493383Smdodd    pdq->pdq_command_info.ci_pa_response_bufstart = PDQ_DB_BUSPA(pdq, pdq->pdq_command_info.ci_response_bufstart);
169593383Smdodd    pdq->pdq_command_info.ci_pa_response_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_command_responses);
169693383Smdodd    PDQ_PRINTF(("PDQ Command Response Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n",
169793383Smdodd		pdq->pdq_command_info.ci_response_bufstart,
169893383Smdodd		pdq->pdq_command_info.ci_pa_response_bufstart));
169993383Smdodd    for (idx = 0; idx < sizeof(dbp->pdqdb_command_responses)/sizeof(dbp->pdqdb_command_responses[0]); idx++) {
170093383Smdodd	pdq_rxdesc_t *rxd = &dbp->pdqdb_command_responses[idx];
170193383Smdodd
170293383Smdodd	rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_response_bufstart;
170321826Sjoerg	rxd->rxd_sop = 1;
170421826Sjoerg	rxd->rxd_seg_cnt = 0;
170521826Sjoerg	rxd->rxd_seg_len_lo = 0;
170693383Smdodd	rxd->rxd_seg_len_hi = PDQ_SIZE_COMMAND_RESPONSE / 16;
170721826Sjoerg    }
170893383Smdodd    PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_command_responses,
170993383Smdodd			sizeof(dbp->pdqdb_command_responses));
171021826Sjoerg
171121826Sjoerg    /*
171221826Sjoerg     * Initialize the unsolicited event information block
171321826Sjoerg     */
171421826Sjoerg    pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
171593383Smdodd    pdq->pdq_unsolicited_info.ui_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_unsolicited_events);
171693383Smdodd    PDQ_PRINTF(("PDQ Unsolicit Event Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n",
171793383Smdodd		pdq->pdq_unsolicited_info.ui_events,
171893383Smdodd		pdq->pdq_unsolicited_info.ui_pa_bufstart));
171993383Smdodd    for (idx = 0; idx < sizeof(dbp->pdqdb_unsolicited_events)/sizeof(dbp->pdqdb_unsolicited_events[0]); idx++) {
172093383Smdodd	pdq_rxdesc_t *rxd = &dbp->pdqdb_unsolicited_events[idx];
172121826Sjoerg	pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
172221826Sjoerg
172321826Sjoerg	rxd->rxd_sop = 1;
172421826Sjoerg	rxd->rxd_seg_cnt = 0;
172521826Sjoerg	rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16;
172621826Sjoerg	rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event
172721826Sjoerg	    - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events;
172821826Sjoerg	rxd->rxd_pa_hi = 0;
172993383Smdodd	PDQ_OS_UNSOL_EVENT_PRESYNC(pdq, event);
173021826Sjoerg    }
173193383Smdodd    PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_unsolicited_events,
173293383Smdodd			sizeof(dbp->pdqdb_unsolicited_events));
173393383Smdodd
173421826Sjoerg    /*
173521826Sjoerg     * Initialize the receive information blocks (normal and SMT).
173621826Sjoerg     */
173793383Smdodd    pdq->pdq_rx_info.rx_buffers = pdq->pdq_receive_buffers;
173893383Smdodd    pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(dbp->pdqdb_receives);
173921826Sjoerg    pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8;
174093383Smdodd    pdq->pdq_rx_info.rx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_receives);
174121826Sjoerg
174293383Smdodd    pdq->pdq_host_smt_info.rx_buffers = pdq->pdq_host_smt_buffers;
174393383Smdodd    pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(dbp->pdqdb_host_smt);
174421826Sjoerg    pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3;
174593383Smdodd    pdq->pdq_host_smt_info.rx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_host_smt);
174621826Sjoerg
174721826Sjoerg    /*
174821826Sjoerg     * Initialize the transmit information block.
174921826Sjoerg     */
175093383Smdodd    dbp->pdqdb_tx_hdr[0] = PDQ_FDDI_PH0;
175193383Smdodd    dbp->pdqdb_tx_hdr[1] = PDQ_FDDI_PH1;
175293383Smdodd    dbp->pdqdb_tx_hdr[2] = PDQ_FDDI_PH2;
175393383Smdodd    pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(dbp->pdqdb_transmits);
175493383Smdodd    pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = 3;
175521826Sjoerg    pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1;
175693383Smdodd    pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_DB_BUSPA(pdq, dbp->pdqdb_tx_hdr);
175793383Smdodd    pdq->pdq_tx_info.tx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_transmits);
175821826Sjoerg
175921826Sjoerg    state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
176021826Sjoerg    PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
176121826Sjoerg
176221826Sjoerg    /*
176321826Sjoerg     * Stop the PDQ if it is running and put it into a known state.
176421826Sjoerg     */
176521826Sjoerg    state = pdq_stop(pdq);
176621826Sjoerg
176721826Sjoerg    PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
176821826Sjoerg    PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
176921826Sjoerg    /*
177021826Sjoerg     * If the adapter is not the state we expect, then the initialization
177121826Sjoerg     * failed.  Cleanup and exit.
177221826Sjoerg     */
177321826Sjoerg#if defined(PDQVERBOSE)
177421826Sjoerg    if (state == PDQS_HALTED) {
177521826Sjoerg	pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
177621826Sjoerg	printf("Halt code = %d (%s)\n", halt_code, pdq_halt_codes[halt_code]);
177721826Sjoerg	if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA)
177821826Sjoerg	    PDQ_PRINTF(("PFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
177921826Sjoerg		       PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
178021826Sjoerg		       PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0) & PDQ_HOST_INT_FATAL_ERROR));
178121826Sjoerg    }
178221826Sjoerg#endif
178321826Sjoerg    if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE)
178421826Sjoerg	goto cleanup_and_return;
178521826Sjoerg
178621826Sjoerg    PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
178721826Sjoerg	   pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1],
178821826Sjoerg	   pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3],
178921826Sjoerg	   pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5]));
179021826Sjoerg    PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n",
179121826Sjoerg	   pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
179221826Sjoerg	   pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3]));
179321826Sjoerg    PDQ_PRINTF(("PDQ Chip Revision = "));
179421826Sjoerg    switch (pdq->pdq_chip_rev) {
179521826Sjoerg	case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break;
179621826Sjoerg	case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break;
179721826Sjoerg	case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break;
179821826Sjoerg	default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev));
179921826Sjoerg    }
180021826Sjoerg    PDQ_PRINTF(("\n"));
180121826Sjoerg
180221826Sjoerg    return pdq;
180321826Sjoerg}
1804