[BACK]Return to pdq.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/pdq.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: pdq.c,v 1.13 2007/02/14 00:53:48 jsg Exp $    */
                      2: /*     $NetBSD: pdq.c,v 1.9 1996/10/13 01:37:26 christos Exp $ */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1995,1996 Matt Thomas <matt@3am-software.com>
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. The name of the author may not be used to endorse or promote products
                     14:  *    derived from this software without specific prior written permission
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  *
                     27:  * Id: pdq.c,v 1.27 1996/06/07 20:02:25 thomas Exp
                     28:  *
                     29:  */
                     30:
                     31: /*
                     32:  * DEC PDQ FDDI Controller O/S independent code
                     33:  *
                     34:  * This module should work any PDQ based board.  Note that changes for
                     35:  * MIPS and Alpha architectures (or any other architecture which requires
                     36:  * a flushing of memory or write buffers and/or has incoherent caches)
                     37:  * have yet to be made.
                     38:  *
                     39:  * However, it is expected that the PDQ_CSR_WRITE macro will cause a
                     40:  * flushing of the write buffers.
                     41:  */
                     42:
                     43: #define        PDQ_HWSUPPORT   /* for pdq.h */
                     44:
                     45: #include "pdqvar.h"
                     46: #include "pdqreg.h"
                     47:
                     48: #define        PDQ_ROUNDUP(n, x)       (((n) + ((x) - 1)) & ~((x) - 1))
                     49: #define        PDQ_CMD_RX_ALIGNMENT    16
                     50:
                     51: #if (defined(PDQTEST) && !defined(PDQ_NOPRINTF)) || defined(PDQVERBOSE)
                     52: #define        PDQ_PRINTF(x)   printf x
                     53: #else
                     54: #define        PDQ_PRINTF(x)   do { } while (0)
                     55: #endif
                     56:
                     57: static const char * const pdq_halt_codes[] = {
                     58:     "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault",
                     59:     "Software Fault", "Hardware Fault", "PC Trace Path Test",
                     60:     "DMA Error", "Image CRC Error", "Adapter Processer Error"
                     61: };
                     62:
                     63: static const char * const pdq_adapter_states[] = {
                     64:     "Reset", "Upgrade", "DMA Unavailable", "DMA Available",
                     65:     "Link Available", "Link Unavailable", "Halted", "Ring Member"
                     66: };
                     67:
                     68: /*
                     69:  * The following are used in conjunction with
                     70:  * unsolicited events
                     71:  */
                     72: static const char * const pdq_entities[] = {
                     73:     "Station", "Link", "Phy Port"
                     74: };
                     75:
                     76: static const char * const pdq_station_events[] = {
                     77:     "Trace Received"
                     78: };
                     79:
                     80: static const char * const pdq_station_arguments[] = {
                     81:     "Reason"
                     82: };
                     83:
                     84: static const char * const pdq_link_events[] = {
                     85:     "Transmit Underrun",
                     86:     "Transmit Failed",
                     87:     "Block Check Error (CRC)",
                     88:     "Frame Status Error",
                     89:     "PDU Length Error",
                     90:     NULL,
                     91:     NULL,
                     92:     "Receive Data Overrun",
                     93:     NULL,
                     94:     "No User Buffer",
                     95:     "Ring Initialization Initiated",
                     96:     "Ring Initialization Received",
                     97:     "Ring Beacon Initiated",
                     98:     "Duplicate Address Failure",
                     99:     "Duplicate Token Detected",
                    100:     "Ring Purger Error",
                    101:     "FCI Strip Error",
                    102:     "Trace Initiated",
                    103:     "Directed Beacon Received",
                    104: };
                    105:
                    106: static const char * const pdq_link_arguments[] = {
                    107:     "Reason",
                    108:     "Data Link Header",
                    109:     "Source",
                    110:     "Upstream Neighbor"
                    111: };
                    112:
                    113: static const char * const pdq_phy_events[] = {
                    114:     "LEM Error Monitor Reject",
                    115:     "Elasticy Buffer Error",
                    116:     "Link Confidence Test Reject"
                    117: };
                    118:
                    119: static const char * const pdq_phy_arguments[] = {
                    120:     "Direction"
                    121: };
                    122:
                    123: static const char * const * const pdq_event_arguments[] = {
                    124:     pdq_station_arguments,
                    125:     pdq_link_arguments,
                    126:     pdq_phy_arguments
                    127: };
                    128:
                    129: static const char * const * const pdq_event_codes[] = {
                    130:     pdq_station_events,
                    131:     pdq_link_events,
                    132:     pdq_phy_events
                    133: };
                    134: 
                    135: static const char * const pdq_station_types[] = {
                    136:     "SAS", "DAC", "SAC", "NAC", "DAS"
                    137: };
                    138:
                    139: static const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" };
                    140:
                    141: static const char pdq_phy_types[] = "ABSM";
                    142:
                    143: static const char * const pdq_pmd_types0[] = {
                    144:     "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2",
                    145:     "ANSI Sonet"
                    146: };
                    147:
                    148: static const char * const pdq_pmd_types100[] = {
                    149:     "Low Power", "Thin Wire", "Shielded Twisted Pair",
                    150:     "Unshielded Twisted Pair"
                    151: };
                    152:
                    153: static const char * const * const pdq_pmd_types[] = {
                    154:     pdq_pmd_types0, pdq_pmd_types100
                    155: };
                    156:
                    157: static const char * const pdq_descriptions[] = {
                    158:     "DEFPA PCI",
                    159:     "DEFEA EISA",
                    160:     "DEFTA TC",
                    161:     "DEFAA Futurebus",
                    162:     "DEFQA Q-bus",
                    163: };
                    164:
                    165: static void
                    166: pdq_print_fddi_chars(
                    167:     pdq_t *pdq,
                    168:     const pdq_response_status_chars_get_t *rsp)
                    169: {
                    170:     const char hexchars[] = "0123456789abcdef";
                    171:
                    172:     printf(PDQ_OS_PREFIX "DEC %s FDDI %s Controller\n",
                    173:           PDQ_OS_PREFIX_ARGS, pdq_descriptions[pdq->pdq_type],
                    174:           pdq_station_types[rsp->status_chars_get.station_type]);
                    175:
                    176:     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",
                    177:           PDQ_OS_PREFIX_ARGS,
                    178:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4],
                    179:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F],
                    180:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4],
                    181:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F],
                    182:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4],
                    183:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F],
                    184:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4],
                    185:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F],
                    186:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4],
                    187:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F],
                    188:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4],
                    189:           hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F],
                    190:           pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
                    191:           pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3],
                    192:           rsp->status_chars_get.module_rev.fwrev_bytes[0]);
                    193:
                    194:     if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) {
                    195:        printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]);
                    196:     }
                    197:
                    198:     printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)",
                    199:           PDQ_OS_PREFIX_ARGS,
                    200:           rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "",
                    201:           pdq_phy_types[rsp->status_chars_get.phy_type[0]],
                    202:           pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]);
                    203:
                    204:     if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
                    205:        printf(", FDDI Port[B] = %c (PMD = %s)",
                    206:               pdq_phy_types[rsp->status_chars_get.phy_type[1]],
                    207:               pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]);
                    208:
                    209:     printf("\n");
                    210: }
                    211: 
                    212: static void
                    213: pdq_init_csrs(
                    214:     pdq_csrs_t *csrs,
                    215:     pdq_bus_t bus,
                    216:     pdq_bus_memaddr_t csr_base,
                    217:     size_t csrsize)
                    218: {
                    219:     csrs->csr_bus = bus;
                    220:     csrs->csr_base = csr_base;
                    221:     csrs->csr_port_reset               = PDQ_CSR_OFFSET(csr_base,  0 * csrsize);
                    222:     csrs->csr_host_data                        = PDQ_CSR_OFFSET(csr_base,  1 * csrsize);
                    223:     csrs->csr_port_control             = PDQ_CSR_OFFSET(csr_base,  2 * csrsize);
                    224:     csrs->csr_port_data_a              = PDQ_CSR_OFFSET(csr_base,  3 * csrsize);
                    225:     csrs->csr_port_data_b              = PDQ_CSR_OFFSET(csr_base,  4 * csrsize);
                    226:     csrs->csr_port_status              = PDQ_CSR_OFFSET(csr_base,  5 * csrsize);
                    227:     csrs->csr_host_int_type_0          = PDQ_CSR_OFFSET(csr_base,  6 * csrsize);
                    228:     csrs->csr_host_int_enable          = PDQ_CSR_OFFSET(csr_base,  7 * csrsize);
                    229:     csrs->csr_type_2_producer          = PDQ_CSR_OFFSET(csr_base,  8 * csrsize);
                    230:     csrs->csr_cmd_response_producer    = PDQ_CSR_OFFSET(csr_base, 10 * csrsize);
                    231:     csrs->csr_cmd_request_producer     = PDQ_CSR_OFFSET(csr_base, 11 * csrsize);
                    232:     csrs->csr_host_smt_producer                = PDQ_CSR_OFFSET(csr_base, 12 * csrsize);
                    233:     csrs->csr_unsolicited_producer     = PDQ_CSR_OFFSET(csr_base, 13 * csrsize);
                    234: }
                    235:
                    236: static void
                    237: pdq_init_pci_csrs(
                    238:     pdq_pci_csrs_t *csrs,
                    239:     pdq_bus_t bus,
                    240:     pdq_bus_memaddr_t csr_base,
                    241:     size_t csrsize)
                    242: {
                    243:     csrs->csr_bus = bus;
                    244:     csrs->csr_base = csr_base;
                    245:     csrs->csr_pfi_mode_control = PDQ_CSR_OFFSET(csr_base, 16 * csrsize);
                    246:     csrs->csr_pfi_status       = PDQ_CSR_OFFSET(csr_base, 17 * csrsize);
                    247:     csrs->csr_fifo_write       = PDQ_CSR_OFFSET(csr_base, 18 * csrsize);
                    248:     csrs->csr_fifo_read                = PDQ_CSR_OFFSET(csr_base, 19 * csrsize);
                    249: }
                    250: 
                    251: static void
                    252: pdq_flush_databuf_queue(
                    253:     pdq_databuf_queue_t *q)
                    254: {
                    255:     PDQ_OS_DATABUF_T *pdu;
                    256:     for (;;) {
                    257:        PDQ_OS_DATABUF_DEQUEUE(q, pdu);
                    258:        if (pdu == NULL)
                    259:            return;
                    260:        PDQ_OS_DATABUF_FREE(pdu);
                    261:     }
                    262: }
                    263: 
                    264: static pdq_boolean_t
                    265: pdq_do_port_control(
                    266:     const pdq_csrs_t * const csrs,
                    267:     pdq_uint32_t cmd)
                    268: {
                    269:     int cnt = 0;
                    270:     PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
                    271:     PDQ_CSR_WRITE(csrs, csr_port_control, PDQ_PCTL_CMD_ERROR | cmd);
                    272:     while ((PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000)
                    273:        cnt++;
                    274:     PDQ_PRINTF(("CSR cmd spun %d times\n", cnt));
                    275:     if (PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) {
                    276:        PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
                    277:        return (PDQ_CSR_READ(csrs, csr_port_control) & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE;
                    278:     }
                    279:     /* adapter failure */
                    280:     PDQ_ASSERT(0);
                    281:     return PDQ_FALSE;
                    282: }
                    283:
                    284: static void
                    285: pdq_read_mla(
                    286:     const pdq_csrs_t * const csrs,
                    287:     pdq_lanaddr_t *hwaddr)
                    288: {
                    289:     pdq_uint32_t data;
                    290:
                    291:     PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
                    292:     pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
                    293:     data = PDQ_CSR_READ(csrs, csr_host_data);
                    294:
                    295:     hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF;
                    296:     hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF;
                    297:     hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF;
                    298:     hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF;
                    299:
                    300:     PDQ_CSR_WRITE(csrs, csr_port_data_a, 1);
                    301:     pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
                    302:     data = PDQ_CSR_READ(csrs, csr_host_data);
                    303:
                    304:     hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF;
                    305:     hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF;
                    306: }
                    307:
                    308: static void
                    309: pdq_read_fwrev(
                    310:     const pdq_csrs_t * const csrs,
                    311:     pdq_fwrev_t *fwrev)
                    312: {
                    313:     pdq_uint32_t data;
                    314:
                    315:     pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ);
                    316:     data = PDQ_CSR_READ(csrs, csr_host_data);
                    317:
                    318:     fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF;
                    319:     fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF;
                    320:     fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF;
                    321:     fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF;
                    322: }
                    323:
                    324: static pdq_boolean_t
                    325: pdq_read_error_log(
                    326:     pdq_t *pdq,
                    327:     pdq_response_error_log_get_t *log_entry)
                    328: {
                    329:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    330:     pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry;
                    331:
                    332:     pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START);
                    333:
                    334:     while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) {
                    335:        *ptr++ = PDQ_CSR_READ(csrs, csr_host_data);
                    336:        if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry))
                    337:            break;
                    338:     }
                    339:     return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE;
                    340: }
                    341:
                    342: static pdq_chip_rev_t
                    343: pdq_read_chiprev(
                    344:     const pdq_csrs_t * const csrs)
                    345: {
                    346:     pdq_uint32_t data;
                    347:
                    348:     PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_PDQ_REV_GET);
                    349:     pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
                    350:     data = PDQ_CSR_READ(csrs, csr_host_data);
                    351:
                    352:     return (pdq_chip_rev_t) data;
                    353: }
                    354: 
                    355: static const struct {
                    356:     size_t cmd_len;
                    357:     size_t rsp_len;
                    358:     const char *cmd_name;
                    359: } pdq_cmd_info[] = {
                    360:     { sizeof(pdq_cmd_generic_t),               /* 0 - PDQC_START */
                    361:       sizeof(pdq_response_generic_t),
                    362:       "Start"
                    363:     },
                    364:     { sizeof(pdq_cmd_filter_set_t),            /* 1 - PDQC_FILTER_SET */
                    365:       sizeof(pdq_response_generic_t),
                    366:       "Filter Set"
                    367:     },
                    368:     { sizeof(pdq_cmd_generic_t),               /* 2 - PDQC_FILTER_GET */
                    369:       sizeof(pdq_response_filter_get_t),
                    370:       "Filter Get"
                    371:     },
                    372:     { sizeof(pdq_cmd_chars_set_t),             /* 3 - PDQC_CHARS_SET */
                    373:       sizeof(pdq_response_generic_t),
                    374:       "Chars Set"
                    375:     },
                    376:     { sizeof(pdq_cmd_generic_t),               /* 4 - PDQC_STATUS_CHARS_GET */
                    377:       sizeof(pdq_response_status_chars_get_t),
                    378:       "Status Chars Get"
                    379:     },
                    380: #if 0
                    381:     { sizeof(pdq_cmd_generic_t),               /* 5 - PDQC_COUNTERS_GET */
                    382:       sizeof(pdq_response_counters_get_t),
                    383:       "Counters Get"
                    384:     },
                    385:     { sizeof(pdq_cmd_counters_set_t),          /* 6 - PDQC_COUNTERS_SET */
                    386:       sizeof(pdq_response_generic_t),
                    387:       "Counters Set"
                    388:     },
                    389: #else
                    390:     { 0, 0, "Counters Get" },
                    391:     { 0, 0, "Counters Set" },
                    392: #endif
                    393:     { sizeof(pdq_cmd_addr_filter_set_t),       /* 7 - PDQC_ADDR_FILTER_SET */
                    394:       sizeof(pdq_response_generic_t),
                    395:       "Addr Filter Set"
                    396:     },
                    397:     { sizeof(pdq_cmd_generic_t),               /* 8 - PDQC_ADDR_FILTER_GET */
                    398:       sizeof(pdq_response_addr_filter_get_t),
                    399:       "Addr Filter Get"
                    400:     },
                    401: #if 0
                    402:     { sizeof(pdq_cmd_generic_t),               /* 9 - PDQC_ERROR_LOG_CLEAR */
                    403:       sizeof(pdq_response_generic_t),
                    404:       "Error Log Clear"
                    405:     },
                    406:     { sizeof(pdq_cmd_generic_t),               /* 10 - PDQC_ERROR_LOG_SET */
                    407:       sizeof(pdq_response_generic_t),
                    408:       "Error Log Set"
                    409:     },
                    410:     { sizeof(pdq_cmd_generic_t),               /* 11 - PDQC_FDDI_MIB_GET */
                    411:       sizeof(pdq_response_generic_t),
                    412:       "FDDI MIB Get"
                    413:     },
                    414:     { sizeof(pdq_cmd_generic_t),               /* 12 - PDQC_DEC_EXT_MIB_GET */
                    415:       sizeof(pdq_response_generic_t),
                    416:       "DEC Ext MIB Get"
                    417:     },
                    418:     { sizeof(pdq_cmd_generic_t),               /* 13 - PDQC_DEC_SPECIFIC_GET */
                    419:       sizeof(pdq_response_generic_t),
                    420:       "DEC Specific Get"
                    421:     },
                    422:     { sizeof(pdq_cmd_generic_t),               /* 14 - PDQC_SNMP_SET */
                    423:       sizeof(pdq_response_generic_t),
                    424:       "SNMP Set"
                    425:     },
                    426:     { 0, 0, "N/A" },
                    427:     { sizeof(pdq_cmd_generic_t),               /* 16 - PDQC_SMT_MIB_GET */
                    428:       sizeof(pdq_response_generic_t),
                    429:       "SMT MIB Get"
                    430:     },
                    431:     { sizeof(pdq_cmd_generic_t),               /* 17 - PDQC_SMT_MIB_SET */
                    432:       sizeof(pdq_response_generic_t),
                    433:       "SMT MIB Set",
                    434:     },
                    435: #endif
                    436: };
                    437:
                    438: static void
                    439: pdq_queue_commands(
                    440:     pdq_t *pdq)
                    441: {
                    442:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    443:     pdq_command_info_t * const ci = &pdq->pdq_command_info;
                    444:     pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
                    445:     pdq_cmd_code_t op;
                    446:     pdq_uint32_t cmdlen, rsplen, mask;
                    447:
                    448:     /*
                    449:      * If there are commands or responses active or there aren't
                    450:      * any pending commands, then don't queue any more.
                    451:      */
                    452:     if (ci->ci_command_active || ci->ci_pending_commands == 0)
                    453:        return;
                    454:
                    455:     /*
                    456:      * Determine which command needs to be queued.
                    457:      */
                    458:     op = PDQC_SMT_MIB_SET;
                    459:     for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1)
                    460:        op = (pdq_cmd_code_t) ((int) op - 1);
                    461:     /*
                    462:      * Obtain the sizes needed for the command and response.
                    463:      * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is
                    464:      * always properly aligned.
                    465:      */
                    466:     cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT);
                    467:     rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT);
                    468:     if (cmdlen < rsplen)
                    469:        cmdlen = rsplen;
                    470:     /*
                    471:      * Since only one command at a time will be queued, there will always
                    472:      * be enough space.
                    473:      */
                    474:
                    475:     /*
                    476:      * Obtain and fill in the descriptor for the command (descriptor is
                    477:      * pre-initialized)
                    478:      */
                    479:     dbp->pdqdb_command_requests[ci->ci_request_producer].txd_seg_len = cmdlen;
                    480:     PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
                    481:
                    482:     /*
                    483:      * Obtain and fill in the descriptor for the response (descriptor is
                    484:      * pre-initialized)
                    485:      */
                    486:     dbp->pdqdb_command_responses[ci->ci_response_producer].rxd_seg_len_hi = cmdlen / 16;
                    487:     PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
                    488:
                    489:     /*
                    490:      * Clear the command area, set the opcode, and the command from the pending
                    491:      * mask.
                    492:      */
                    493:
                    494:     PDQ_OS_MEMZERO(ci->ci_bufstart, cmdlen);
                    495:     *(pdq_cmd_code_t *) ci->ci_bufstart = op;
                    496:     ci->ci_pending_commands &= ~mask;
                    497:
                    498:     /*
                    499:      * Fill in the command area, if needed.
                    500:      */
                    501:     switch (op) {
                    502:        case PDQC_FILTER_SET: {
                    503:            pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_bufstart;
                    504:            unsigned idx = 0;
                    505:            filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM;
                    506:            filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
                    507:            idx++;
                    508:            filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM;
                    509:            filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
                    510:            idx++;
                    511:            filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM;
                    512:            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);
                    513:            idx++;
                    514:            filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER;
                    515:            filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
                    516:            idx++;
                    517:            filter_set->filter_set_items[idx].item_code = PDQI_EOL;
                    518:            break;
                    519:        }
                    520:        case PDQC_ADDR_FILTER_SET: {
                    521:            pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_bufstart;
                    522:            pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses;
                    523:            addr->lanaddr_bytes[0] = 0xFF;
                    524:            addr->lanaddr_bytes[1] = 0xFF;
                    525:            addr->lanaddr_bytes[2] = 0xFF;
                    526:            addr->lanaddr_bytes[3] = 0xFF;
                    527:            addr->lanaddr_bytes[4] = 0xFF;
                    528:            addr->lanaddr_bytes[5] = 0xFF;
                    529:            addr++;
                    530:            pdq_os_addr_fill(pdq, addr, 61);
                    531:            break;
                    532:        }
                    533:        default:
                    534:            break;
                    535:     }
                    536:     /*
                    537:      * At this point the command is done.  All that needs to be done is to
                    538:      * produce it to the PDQ.
                    539:      */
                    540:     PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n",
                    541:                pdq_cmd_info[op].cmd_name));
                    542:
                    543:     ci->ci_command_active++;
                    544:     PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, ci->ci_response_producer | (ci->ci_response_completion << 8));
                    545:     PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, ci->ci_request_producer | (ci->ci_request_completion << 8));
                    546: }
                    547: 
                    548: static void
                    549: pdq_process_command_responses(
                    550:     pdq_t * const pdq)
                    551: {
                    552:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    553:     pdq_command_info_t * const ci = &pdq->pdq_command_info;
                    554:     volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp;
                    555:     pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
                    556:     const pdq_response_generic_t *rspgen;
                    557:
                    558:     /*
                    559:      * We have to process the command and response in tandem so
                    560:      * just wait for the response to be consumed.  If it has been
                    561:      * consumed then the command must have been as well.
                    562:      */
                    563:
                    564:     if (cbp->pdqcb_command_response == ci->ci_response_completion)
                    565:        return;
                    566:
                    567:     PDQ_ASSERT(cbp->pdqcb_command_request != ci->ci_request_completion);
                    568:
                    569:     rspgen = (const pdq_response_generic_t *) ci->ci_bufstart;
                    570:     PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS);
                    571:     PDQ_PRINTF(("PDQ Process Command Response: %s completed (status=%d)\n",
                    572:                pdq_cmd_info[rspgen->generic_op].cmd_name,
                    573:                rspgen->generic_status));
                    574:
                    575:     if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) {
                    576:        pdq->pdq_flags &= ~PDQ_PRINTCHARS;
                    577:        pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen);
                    578:     }
                    579:
                    580:     PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
                    581:     PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
                    582:     ci->ci_command_active = 0;
                    583:
                    584:     if (ci->ci_pending_commands != 0) {
                    585:        pdq_queue_commands(pdq);
                    586:     } else {
                    587:        PDQ_CSR_WRITE(csrs, csr_cmd_response_producer,
                    588:                      ci->ci_response_producer | (ci->ci_response_completion << 8));
                    589:        PDQ_CSR_WRITE(csrs, csr_cmd_request_producer,
                    590:                      ci->ci_request_producer | (ci->ci_request_completion << 8));
                    591:     }
                    592: }
                    593: 
                    594: /*
                    595:  * This following routine processes unsolicited events.
                    596:  * In addition, it also fills the unsolicited queue with
                    597:  * event buffers so it can be used to initialize the queue
                    598:  * as well.
                    599:  */
                    600: static void
                    601: pdq_process_unsolicited_events(
                    602:     pdq_t *pdq)
                    603: {
                    604:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    605:     pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info;
                    606:     volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
                    607:     pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
                    608:     const pdq_unsolicited_event_t *event;
                    609:     pdq_rxdesc_t *rxd;
                    610:
                    611:     /*
                    612:      * Process each unsolicited event (if any).
                    613:      */
                    614:
                    615:     while (cbp->pdqcb_unsolicited_event != ui->ui_completion) {
                    616:        rxd = &dbp->pdqdb_unsolicited_events[ui->ui_completion];
                    617:        event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
                    618:
                    619:        switch (event->event_type) {
                    620:            case PDQ_UNSOLICITED_EVENT: {
                    621:                printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s",
                    622:                       PDQ_OS_PREFIX_ARGS,
                    623:                       pdq_entities[event->event_entity],
                    624:                       pdq_event_codes[event->event_entity][event->event_code.value]);
                    625:                if (event->event_entity == PDQ_ENTITY_PHY_PORT)
                    626:                    printf("[%d]", event->event_index);
                    627:                printf("\n");
                    628:                break;
                    629:            }
                    630:            case PDQ_UNSOLICITED_COUNTERS: {
                    631:                break;
                    632:            }
                    633:        }
                    634:        PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
                    635:        ui->ui_free++;
                    636:     }
                    637:
                    638:     /*
                    639:      * Now give back the event buffers back to the PDQ.
                    640:      */
                    641:     PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
                    642:     ui->ui_free = 0;
                    643:
                    644:     PDQ_CSR_WRITE(csrs, csr_unsolicited_producer,
                    645:                  ui->ui_producer | (ui->ui_completion << 8));
                    646: }
                    647: 
                    648: static void
                    649: pdq_process_received_data(
                    650:     pdq_t *pdq,
                    651:     pdq_rx_info_t *rx,
                    652:     pdq_rxdesc_t *receives,
                    653:     pdq_uint32_t completion_goal,
                    654:     pdq_uint32_t ring_mask)
                    655: {
                    656:     pdq_uint32_t completion = rx->rx_completion;
                    657:     pdq_uint32_t producer = rx->rx_producer;
                    658:     PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers;
                    659:     pdq_rxdesc_t *rxd;
                    660:     pdq_uint32_t idx;
                    661:
                    662:     while (completion != completion_goal) {
                    663:        PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu;
                    664:        pdq_uint8_t *dataptr;
                    665:        pdq_uint32_t fc, datalen, pdulen, segcnt;
                    666:        pdq_rxstatus_t status;
                    667:
                    668:        fpdu = lpdu = buffers[completion];
                    669:        PDQ_ASSERT(fpdu != NULL);
                    670:
                    671:        dataptr = PDQ_OS_DATABUF_PTR(fpdu);
                    672:        status = *(pdq_rxstatus_t *) dataptr;
                    673:        if ((status.rxs_status & 0x200000) == 0) {
                    674:            datalen = status.rxs_status & 0x1FFF;
                    675:            fc = dataptr[PDQ_RX_FC_OFFSET];
                    676:            switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) {
                    677:                case PDQ_FDDI_LLC_ASYNC:
                    678:                case PDQ_FDDI_LLC_SYNC:
                    679:                case PDQ_FDDI_IMP_ASYNC:
                    680:                case PDQ_FDDI_IMP_SYNC: {
                    681:                    if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) {
                    682:                        PDQ_PRINTF(("discard: bad length %d\n", datalen));
                    683:                        goto discard_frame;
                    684:                    }
                    685:                    break;
                    686:                }
                    687:                case PDQ_FDDI_SMT: {
                    688:                    if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN)
                    689:                        goto discard_frame;
                    690:                    break;
                    691:                }
                    692:                default: {
                    693:                    PDQ_PRINTF(("discard: bad fc 0x%x\n", fc));
                    694:                    goto discard_frame;
                    695:                }
                    696:            }
                    697:            /*
                    698:             * Update the lengths of the data buffers now that we know
                    699:             * the real length.
                    700:             */
                    701:            pdulen = datalen - 4 /* CRC */;
                    702:            segcnt = (pdulen + PDQ_RX_FC_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE;
                    703:            PDQ_OS_DATABUF_ALLOC(npdu);
                    704:            if (npdu == NULL) {
                    705:                PDQ_PRINTF(("discard: no databuf #0\n"));
                    706:                goto discard_frame;
                    707:            }
                    708:            buffers[completion] = npdu;
                    709:            for (idx = 1; idx < segcnt; idx++) {
                    710:                PDQ_OS_DATABUF_ALLOC(npdu);
                    711:                if (npdu == NULL) {
                    712:                    PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
                    713:                    PDQ_OS_DATABUF_FREE(fpdu);
                    714:                    goto discard_frame;
                    715:                }
                    716:                PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]);
                    717:                lpdu = PDQ_OS_DATABUF_NEXT(lpdu);
                    718:                buffers[(completion + idx) & ring_mask] = npdu;
                    719:            }
                    720:            PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
                    721:            for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
                    722:                buffers[(producer + idx) & ring_mask] =
                    723:                    buffers[(completion + idx) & ring_mask];
                    724:                buffers[(completion + idx) & ring_mask] = NULL;
                    725:            }
                    726:            PDQ_OS_DATABUF_ADJ(fpdu, PDQ_RX_FC_OFFSET);
                    727:            if (segcnt == 1) {
                    728:                PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen);
                    729:            } else {
                    730:                PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_RX_FC_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE);
                    731:            }
                    732:            pdq_os_receive_pdu(pdq, fpdu, pdulen);
                    733:            rx->rx_free += PDQ_RX_SEGCNT;
                    734:            PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask);
                    735:            PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask);
                    736:            continue;
                    737:        } else {
                    738:            PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status,
                    739:                        status.rxs_rcc_badpdu, status.rxs_rcc_badcrc,
                    740:                        status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e));
                    741:            if (status.rxs_rcc_reason == 7)
                    742:                goto discard_frame;
                    743:            if (status.rxs_rcc_reason != 0) {
                    744:                /* hardware fault */
                    745:            }
                    746:            if (status.rxs_rcc_badcrc) {
                    747:                printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n",
                    748:                       PDQ_OS_PREFIX_ARGS,
                    749:                       dataptr[PDQ_RX_FC_OFFSET+1],
                    750:                       dataptr[PDQ_RX_FC_OFFSET+2],
                    751:                       dataptr[PDQ_RX_FC_OFFSET+3],
                    752:                       dataptr[PDQ_RX_FC_OFFSET+4],
                    753:                       dataptr[PDQ_RX_FC_OFFSET+5],
                    754:                       dataptr[PDQ_RX_FC_OFFSET+6]);
                    755:                /* rx->rx_badcrc++; */
                    756:            } else if (status.rxs_fsc == 0 || status.rxs_fsb_e == 1) {
                    757:                /* rx->rx_frame_status_errors++; */
                    758:            } else {
                    759:                /* hardware fault */
                    760:            }
                    761:        }
                    762:       discard_frame:
                    763:        /*
                    764:         * Discarded frames go right back on the queue; therefore
                    765:         * ring entries were freed.
                    766:         */
                    767:        for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
                    768:            buffers[producer] = buffers[completion];
                    769:            buffers[completion] = NULL;
                    770:            rxd = &receives[rx->rx_producer];
                    771:            if (idx == 0) {
                    772:                rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
                    773:            } else {
                    774:                rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
                    775:            }
                    776:            rxd->rxd_pa_hi = 0;
                    777:            rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
                    778:            rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(buffers[rx->rx_producer]));
                    779:            PDQ_ADVANCE(rx->rx_producer, 1, ring_mask);
                    780:            PDQ_ADVANCE(producer, 1, ring_mask);
                    781:            PDQ_ADVANCE(completion, 1, ring_mask);
                    782:        }
                    783:     }
                    784:     rx->rx_completion = completion;
                    785:
                    786:     while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) {
                    787:        PDQ_OS_DATABUF_T *pdu;
                    788:        /*
                    789:         * Allocate the needed number of data buffers.
                    790:         * Try to obtain them from our free queue before
                    791:         * asking the system for more.
                    792:         */
                    793:        for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
                    794:            if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) {
                    795:                PDQ_OS_DATABUF_ALLOC(pdu);
                    796:                if (pdu == NULL)
                    797:                    break;
                    798:                buffers[(rx->rx_producer + idx) & ring_mask] = pdu;
                    799:            }
                    800:            rxd = &receives[(rx->rx_producer + idx) & ring_mask];
                    801:            if (idx == 0) {
                    802:                rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
                    803:            } else {
                    804:                rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
                    805:            }
                    806:            rxd->rxd_pa_hi = 0;
                    807:            rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
                    808:            rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(pdu));
                    809:        }
                    810:        if (idx < PDQ_RX_SEGCNT) {
                    811:            /*
                    812:             * We didn't get all databufs required to complete a new
                    813:             * receive buffer.  Keep the ones we got and retry a bit
                    814:             * later for the rest.
                    815:             */
                    816:            break;
                    817:        }
                    818:        PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask);
                    819:        rx->rx_free -= PDQ_RX_SEGCNT;
                    820:     }
                    821: }
                    822: 
                    823: pdq_boolean_t
                    824: pdq_queue_transmit_data(
                    825:     pdq_t *pdq,
                    826:     PDQ_OS_DATABUF_T *pdu)
                    827: {
                    828:     pdq_tx_info_t *tx = &pdq->pdq_tx_info;
                    829:     pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
                    830:     pdq_uint32_t producer = tx->tx_producer;
                    831:     pdq_txdesc_t *eop = NULL;
                    832:     PDQ_OS_DATABUF_T *pdu0;
                    833:     pdq_uint32_t freecnt;
                    834:
                    835:     if (tx->tx_free < 1)
                    836:        return PDQ_FALSE;
                    837:
                    838:     dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc;
                    839:     PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
                    840:
                    841:     for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) {
                    842:        pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0);
                    843:        const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0);
                    844:
                    845:        /*
                    846:         * The first segment is limited to the space remaining in
                    847:         * page.  All segments after that can be up to a full page
                    848:         * in size.
                    849:         */
                    850:        fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1));
                    851:        while (datalen > 0 && freecnt > 0) {
                    852:            pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen);
                    853:
                    854:            /*
                    855:             * Initialize the transmit descriptor
                    856:             */
                    857:            eop = &dbp->pdqdb_transmits[producer];
                    858:            eop->txd_seg_len = seglen;
                    859:            eop->txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, dataptr);
                    860:            eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
                    861:
                    862:            datalen -= seglen;
                    863:            dataptr += seglen;
                    864:            fraglen = PDQ_OS_PAGESIZE;
                    865:            freecnt--;
                    866:            PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
                    867:        }
                    868:        pdu0 = PDQ_OS_DATABUF_NEXT(pdu0);
                    869:     }
                    870:     if (pdu0 != NULL) {
                    871:        PDQ_ASSERT(freecnt == 0);
                    872:        /*
                    873:         * If we still have data to process then the ring was too full
                    874:         * to store the PDU.  Return FALSE so the caller will requeue
                    875:         * the PDU for later.
                    876:         */
                    877:        return PDQ_FALSE;
                    878:     }
                    879:     /*
                    880:      * Everything went fine.  Finish it up.
                    881:      */
                    882:     tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt;
                    883:     eop->txd_eop = 1;
                    884:     PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu);
                    885:     tx->tx_producer = producer;
                    886:     tx->tx_free = freecnt;
                    887:     PDQ_DO_TYPE2_PRODUCER(pdq);
                    888:     return PDQ_TRUE;
                    889: }
                    890: 
                    891: static void
                    892: pdq_process_transmitted_data(
                    893:     pdq_t *pdq)
                    894: {
                    895:     pdq_tx_info_t *tx = &pdq->pdq_tx_info;
                    896:     volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
                    897:     pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
                    898:     pdq_uint32_t completion = tx->tx_completion;
                    899:
                    900:     while (completion != cbp->pdqcb_transmits) {
                    901:        PDQ_OS_DATABUF_T *pdu;
                    902:        pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion];
                    903:        PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1);
                    904:        PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1);
                    905:        PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
                    906:        pdq_os_transmit_done(pdq, pdu);
                    907:        tx->tx_free += descriptor_count;
                    908:
                    909:        PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits));
                    910:     }
                    911:     if (tx->tx_completion != completion) {
                    912:        tx->tx_completion = completion;
                    913:        pdq_os_restart_transmitter(pdq);
                    914:     }
                    915:     PDQ_DO_TYPE2_PRODUCER(pdq);
                    916: }
                    917: 
                    918: void
                    919: pdq_flush_transmitter(
                    920:     pdq_t *pdq)
                    921: {
                    922:     volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp;
                    923:     pdq_tx_info_t *tx = &pdq->pdq_tx_info;
                    924:
                    925:     for (;;) {
                    926:        PDQ_OS_DATABUF_T *pdu;
                    927:        PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
                    928:        if (pdu == NULL)
                    929:            break;
                    930:        /*
                    931:         * Don't call transmit done since the packet never made it
                    932:         * out on the wire.
                    933:         */
                    934:        PDQ_OS_DATABUF_FREE(pdu);
                    935:     }
                    936:
                    937:     tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
                    938:     tx->tx_completion = cbp->pdqcb_transmits = tx->tx_producer;
                    939:
                    940:     PDQ_DO_TYPE2_PRODUCER(pdq);
                    941: }
                    942: 
                    943: void
                    944: pdq_hwreset(
                    945:     pdq_t *pdq)
                    946: {
                    947:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    948:     pdq_state_t state;
                    949:     int cnt;
                    950:
                    951:     state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                    952:     if (state == PDQS_DMA_UNAVAILABLE)
                    953:        return;
                    954:     PDQ_CSR_WRITE(csrs, csr_port_data_a,
                    955:                  (state == PDQS_HALTED) ? 0 : PDQ_PRESET_SKIP_SELFTEST);
                    956:     PDQ_CSR_WRITE(csrs, csr_port_reset, 1);
                    957:     PDQ_OS_USEC_DELAY(100);
                    958:     PDQ_CSR_WRITE(csrs, csr_port_reset, 0);
                    959:     for (cnt = 45000;;cnt--) {
                    960:        PDQ_OS_USEC_DELAY(1000);
                    961:        state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                    962:        if (state == PDQS_DMA_UNAVAILABLE || cnt == 0)
                    963:            break;
                    964:     }
                    965:     PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 45000 - cnt));
                    966:     PDQ_OS_USEC_DELAY(10000);
                    967:     state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                    968:     PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
                    969:     PDQ_ASSERT(cnt > 0);
                    970: }
                    971: 
                    972: /*
                    973:  * The following routine brings the PDQ from whatever state it is
                    974:  * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET).
                    975:  */
                    976: pdq_state_t
                    977: pdq_stop(
                    978:     pdq_t *pdq)
                    979: {
                    980:     pdq_state_t state;
                    981:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                    982:     int cnt, pass = 0, idx;
                    983:     PDQ_OS_DATABUF_T **buffers;
                    984:
                    985:   restart:
                    986:     state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                    987:     if (state != PDQS_DMA_UNAVAILABLE) {
                    988:        pdq_hwreset(pdq);
                    989:        state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                    990:        PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
                    991:     }
                    992: #if 0
                    993:     switch (state) {
                    994:        case PDQS_RING_MEMBER:
                    995:        case PDQS_LINK_UNAVAILABLE:
                    996:        case PDQS_LINK_AVAILABLE: {
                    997:            PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_LINK_UNINIT);
                    998:            PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
                    999:            pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
                   1000:            state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1001:            PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
                   1002:            /* FALLTHROUGH */
                   1003:        }
                   1004:        case PDQS_DMA_AVAILABLE: {
                   1005:            PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
                   1006:            PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
                   1007:            pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT);
                   1008:            state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1009:            PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
                   1010:            /* FALLTHROUGH */
                   1011:        }
                   1012:        case PDQS_DMA_UNAVAILABLE: {
                   1013:            break;
                   1014:        }
                   1015:     }
                   1016: #endif
                   1017:     /*
                   1018:      * Now we should be in DMA_UNAVAILABLE.  So bring the PDQ into
                   1019:      * DMA_AVAILABLE.
                   1020:      */
                   1021:
                   1022:     /*
                   1023:      * Obtain the hardware address and firmware revisions
                   1024:      * (MLA = my long address which is FDDI speak for hardware address)
                   1025:      */
                   1026:     pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr);
                   1027:     pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev);
                   1028:     pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs);
                   1029:
                   1030:     if (pdq->pdq_type == PDQ_DEFPA) {
                   1031:        /*
                   1032:         * Disable interrupts and DMA.
                   1033:         */
                   1034:        PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 0);
                   1035:        PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x10);
                   1036:     }
                   1037:
                   1038:     /*
                   1039:      * Flush all the databuf queues.
                   1040:      */
                   1041:     pdq_flush_databuf_queue(&pdq->pdq_tx_info.tx_txq);
                   1042:     pdq->pdq_flags &= ~PDQ_TXOK;
                   1043:     buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers;
                   1044:     for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) {
                   1045:        if (buffers[idx] != NULL) {
                   1046:            PDQ_OS_DATABUF_FREE(buffers[idx]);
                   1047:            buffers[idx] = NULL;
                   1048:        }
                   1049:     }
                   1050:     pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
                   1051:     buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers;
                   1052:     for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) {
                   1053:        if (buffers[idx] != NULL) {
                   1054:            PDQ_OS_DATABUF_FREE(buffers[idx]);
                   1055:            buffers[idx] = NULL;
                   1056:        }
                   1057:     }
                   1058:     pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
                   1059:
                   1060:     /*
                   1061:      * Reset the consumer indexes to 0.
                   1062:      */
                   1063:     pdq->pdq_cbp->pdqcb_receives = 0;
                   1064:     pdq->pdq_cbp->pdqcb_transmits = 0;
                   1065:     pdq->pdq_cbp->pdqcb_host_smt = 0;
                   1066:     pdq->pdq_cbp->pdqcb_unsolicited_event = 0;
                   1067:     pdq->pdq_cbp->pdqcb_command_response = 0;
                   1068:     pdq->pdq_cbp->pdqcb_command_request = 0;
                   1069:
                   1070:     /*
                   1071:      * Reset the producer and completion indexes to 0.
                   1072:      */
                   1073:     pdq->pdq_command_info.ci_request_producer = 0;
                   1074:     pdq->pdq_command_info.ci_response_producer = 0;
                   1075:     pdq->pdq_command_info.ci_request_completion = 0;
                   1076:     pdq->pdq_command_info.ci_response_completion = 0;
                   1077:     pdq->pdq_unsolicited_info.ui_producer = 0;
                   1078:     pdq->pdq_unsolicited_info.ui_completion = 0;
                   1079:     pdq->pdq_rx_info.rx_producer = 0;
                   1080:     pdq->pdq_rx_info.rx_completion = 0;
                   1081:     pdq->pdq_tx_info.tx_producer = 0;
                   1082:     pdq->pdq_tx_info.tx_completion = 0;
                   1083:     pdq->pdq_host_smt_info.rx_producer = 0;
                   1084:     pdq->pdq_host_smt_info.rx_completion = 0;
                   1085:
                   1086:     pdq->pdq_command_info.ci_command_active = 0;
                   1087:     pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
                   1088:     pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
                   1089:
                   1090:     /*
                   1091:      * Allow the DEFPA to do DMA.  Then program the physical
                   1092:      * addresses of the consumer and descriptor blocks.
                   1093:      */
                   1094:     if (pdq->pdq_type == PDQ_DEFPA) {
                   1095: #ifdef PDQTEST
                   1096:        PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
                   1097:                      PDQ_PFI_MODE_DMA_ENABLE);
                   1098: #else
                   1099:        PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
                   1100:                      PDQ_PFI_MODE_DMA_ENABLE
                   1101:            /*|PDQ_PFI_MODE_PFI_PCI_INTR*/|PDQ_PFI_MODE_PDQ_PCI_INTR);
                   1102: #endif
                   1103:     }
                   1104:
                   1105:     /*
                   1106:      * Make sure the unsolicited queue has events ...
                   1107:      */
                   1108:     pdq_process_unsolicited_events(pdq);
                   1109:
                   1110:     if (pdq->pdq_type == PDQ_DEFEA && pdq->pdq_chip_rev == PDQ_CHIP_REV_E)
                   1111:        PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_16LW);
                   1112:     else
                   1113:        PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_8LW);
                   1114:     PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_DMA_BURST_SIZE_SET);
                   1115:     pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
                   1116:
                   1117:     PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
                   1118:     PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_OS_VA_TO_PA(pdq, pdq->pdq_cbp));
                   1119:     pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK);
                   1120:
                   1121:     PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
                   1122:     PDQ_CSR_WRITE(csrs, csr_port_data_a,
                   1123:                  PDQ_OS_VA_TO_PA(pdq, pdq->pdq_dbp) | PDQ_DMA_INIT_LW_BSWAP_DATA);
                   1124:     pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT);
                   1125:
                   1126:     for (cnt = 0; cnt < 1000; cnt++) {
                   1127:        state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1128:        if (state == PDQS_HALTED) {
                   1129:            if (pass > 0)
                   1130:                return PDQS_HALTED;
                   1131:            pass = 1;
                   1132:            goto restart;
                   1133:        }
                   1134:        if (state == PDQS_DMA_AVAILABLE) {
                   1135:            PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt));
                   1136:            break;
                   1137:        }
                   1138:        PDQ_OS_USEC_DELAY(1000);
                   1139:     }
                   1140:     PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
                   1141:
                   1142:     PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
                   1143:     PDQ_CSR_WRITE(csrs, csr_host_int_enable, 0) /* PDQ_HOST_INT_STATE_CHANGE
                   1144:        |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE
                   1145:        |PDQ_HOST_INT_UNSOL_ENABLE */;
                   1146:
                   1147:     /*
                   1148:      * Any other command but START should be valid.
                   1149:      */
                   1150:     pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START));
                   1151:     if (pdq->pdq_flags & PDQ_PRINTCHARS)
                   1152:        pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
                   1153:     pdq_queue_commands(pdq);
                   1154:
                   1155:     if (pdq->pdq_flags & PDQ_PRINTCHARS) {
                   1156:        /*
                   1157:         * Now wait (up to 100ms) for the command(s) to finish.
                   1158:         */
                   1159:        for (cnt = 0; cnt < 1000; cnt++) {
                   1160:            pdq_process_command_responses(pdq);
                   1161:            if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion)
                   1162:                break;
                   1163:            PDQ_OS_USEC_DELAY(1000);
                   1164:        }
                   1165:        state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1166:     }
                   1167:
                   1168:     return state;
                   1169: }
                   1170: 
                   1171: void
                   1172: pdq_run(
                   1173:     pdq_t *pdq)
                   1174: {
                   1175:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                   1176:     pdq_state_t state;
                   1177:
                   1178:     state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1179:     PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE);
                   1180:     PDQ_ASSERT(state != PDQS_RESET);
                   1181:     PDQ_ASSERT(state != PDQS_HALTED);
                   1182:     PDQ_ASSERT(state != PDQS_UPGRADE);
                   1183:     PDQ_ASSERT(state != PDQS_RING_MEMBER);
                   1184:     switch (state) {
                   1185:        case PDQS_DMA_AVAILABLE: {
                   1186:            /*
                   1187:             * The PDQ after being reset screws up some of its state.
                   1188:             * So we need to clear all the errors/interrupts so the real
                   1189:             * ones will get through.
                   1190:             */
                   1191:            PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
                   1192:            PDQ_CSR_WRITE(csrs, csr_host_int_enable, PDQ_HOST_INT_STATE_CHANGE|PDQ_HOST_INT_XMT_DATA_FLUSH
                   1193:                |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE
                   1194:                |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_TX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE);
                   1195:            /*
                   1196:             * Set the MAC and address filters and start up the PDQ.
                   1197:             */
                   1198:            pdq_process_unsolicited_events(pdq);
                   1199:            pdq_process_received_data(pdq, &pdq->pdq_rx_info,
                   1200:                                      pdq->pdq_dbp->pdqdb_receives,
                   1201:                                      pdq->pdq_cbp->pdqcb_receives,
                   1202:                                      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
                   1203:            PDQ_DO_TYPE2_PRODUCER(pdq);
                   1204:            if (pdq->pdq_flags & PDQ_PASS_SMT) {
                   1205:                pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
                   1206:                                          pdq->pdq_dbp->pdqdb_host_smt,
                   1207:                                          pdq->pdq_cbp->pdqcb_host_smt,
                   1208:                                          PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
                   1209:                PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
                   1210:                              pdq->pdq_host_smt_info.rx_producer
                   1211:                                  | (pdq->pdq_host_smt_info.rx_completion << 8));
                   1212:            }
                   1213:            pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
                   1214:                | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) | PDQ_BITMASK(PDQC_START);
                   1215:            if (pdq->pdq_flags & PDQ_PRINTCHARS)
                   1216:                pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
                   1217:            pdq_queue_commands(pdq);
                   1218:            break;
                   1219:        }
                   1220:        case PDQS_LINK_UNAVAILABLE:
                   1221:        case PDQS_LINK_AVAILABLE: {
                   1222:            pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
                   1223:                | PDQ_BITMASK(PDQC_ADDR_FILTER_SET);
                   1224:            if (pdq->pdq_flags & PDQ_PRINTCHARS)
                   1225:                pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
                   1226:            if (pdq->pdq_flags & PDQ_PASS_SMT) {
                   1227:                pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
                   1228:                                          pdq->pdq_dbp->pdqdb_host_smt,
                   1229:                                          pdq->pdq_cbp->pdqcb_host_smt,
                   1230:                                          PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
                   1231:                PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
                   1232:                              pdq->pdq_host_smt_info.rx_producer
                   1233:                                  | (pdq->pdq_host_smt_info.rx_completion << 8));
                   1234:            }
                   1235:            pdq_process_unsolicited_events(pdq);
                   1236:            pdq_queue_commands(pdq);
                   1237:            break;
                   1238:        }
                   1239:        case PDQS_RING_MEMBER: {
                   1240:        }
                   1241:        default:
                   1242:            break;
                   1243:     }
                   1244: }
                   1245: 
                   1246: int
                   1247: pdq_interrupt(
                   1248:     pdq_t *pdq)
                   1249: {
                   1250:     const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
                   1251:     pdq_uint32_t data;
                   1252:     int progress = 0;
                   1253:
                   1254:     if (pdq->pdq_type == PDQ_DEFPA)
                   1255:        PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
                   1256:
                   1257:     while ((data = PDQ_CSR_READ(csrs, csr_port_status)) & PDQ_PSTS_INTR_PENDING) {
                   1258:        progress = 1;
                   1259:        PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data));
                   1260:        if (data & PDQ_PSTS_RCV_DATA_PENDING) {
                   1261:            pdq_process_received_data(pdq, &pdq->pdq_rx_info,
                   1262:                                      pdq->pdq_dbp->pdqdb_receives,
                   1263:                                      pdq->pdq_cbp->pdqcb_receives,
                   1264:                                      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
                   1265:            PDQ_DO_TYPE2_PRODUCER(pdq);
                   1266:        }
                   1267:        if (data & PDQ_PSTS_HOST_SMT_PENDING) {
                   1268:            pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
                   1269:                                      pdq->pdq_dbp->pdqdb_host_smt,
                   1270:                                      pdq->pdq_cbp->pdqcb_host_smt,
                   1271:                                      PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
                   1272:            PDQ_DO_HOST_SMT_PRODUCER(pdq);
                   1273:        }
                   1274:        if (data & PDQ_PSTS_XMT_DATA_PENDING)
                   1275:            pdq_process_transmitted_data(pdq);
                   1276:        if (data & PDQ_PSTS_UNSOL_PENDING)
                   1277:            pdq_process_unsolicited_events(pdq);
                   1278:        if (data & PDQ_PSTS_CMD_RSP_PENDING)
                   1279:            pdq_process_command_responses(pdq);
                   1280:        if (data & PDQ_PSTS_TYPE_0_PENDING) {
                   1281:            data = PDQ_CSR_READ(csrs, csr_host_int_type_0);
                   1282:            if (data & PDQ_HOST_INT_STATE_CHANGE) {
                   1283:                pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
                   1284:                printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]);
                   1285:                if (state == PDQS_LINK_UNAVAILABLE) {
                   1286:                    pdq->pdq_flags &= ~PDQ_TXOK;
                   1287:                } else if (state == PDQS_LINK_AVAILABLE) {
                   1288:                    pdq->pdq_flags |= PDQ_TXOK;
                   1289:                    pdq_os_restart_transmitter(pdq);
                   1290:                } else if (state == PDQS_HALTED) {
                   1291:                    pdq_response_error_log_get_t log_entry;
                   1292:                    pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(csrs, csr_port_status));
                   1293:                    printf(": halt code = %d (%s)\n",
                   1294:                           halt_code, pdq_halt_codes[halt_code]);
                   1295:                    if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) {
                   1296:                        PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
                   1297:                               PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
                   1298:                               data & PDQ_HOST_INT_FATAL_ERROR));
                   1299:                    }
                   1300:                    pdq_read_error_log(pdq, &log_entry);
                   1301:                    pdq_stop(pdq);
                   1302:                    if (pdq->pdq_flags & PDQ_RUNNING)
                   1303:                        pdq_run(pdq);
                   1304:                    return 1;
                   1305:                }
                   1306:                printf("\n");
                   1307:                PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_STATE_CHANGE);
                   1308:            }
                   1309:            if (data & PDQ_HOST_INT_FATAL_ERROR) {
                   1310:                pdq_stop(pdq);
                   1311:                if (pdq->pdq_flags & PDQ_RUNNING)
                   1312:                    pdq_run(pdq);
                   1313:                return 1;
                   1314:            }
                   1315:            if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) {
                   1316:                printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS);
                   1317:                pdq->pdq_flags &= ~PDQ_TXOK;
                   1318:                pdq_flush_transmitter(pdq);
                   1319:                pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE);
                   1320:                PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_XMT_DATA_FLUSH);
                   1321:            }
                   1322:        }
                   1323:        if (pdq->pdq_type == PDQ_DEFPA)
                   1324:            PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
                   1325:     }
                   1326:     return progress;
                   1327: }
                   1328: 
                   1329: pdq_t *
                   1330: pdq_initialize(
                   1331:     pdq_bus_t bus,
                   1332:     pdq_bus_memaddr_t csr_base,
                   1333:     const char *name,
                   1334:     int unit,
                   1335:     void *ctx,
                   1336:     pdq_type_t type)
                   1337: {
                   1338:     pdq_t *pdq;
                   1339:     pdq_state_t state;
                   1340:     const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE;
                   1341:     pdq_uint8_t *p;
                   1342:     int idx;
                   1343:
                   1344:     PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192);
                   1345:     PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64);
                   1346:     PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET);
                   1347:     PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET);
                   1348:     PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET);
                   1349:     PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET);
                   1350:     PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET);
                   1351:     PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET);
                   1352:     PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512);
                   1353:
                   1354:     pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t));
                   1355:     if (pdq == NULL) {
                   1356:        PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq)));
                   1357:        return NULL;
                   1358:     }
                   1359:     PDQ_OS_MEMZERO(pdq, sizeof(pdq_t));
                   1360:     pdq->pdq_type = type;
                   1361:     pdq->pdq_unit = unit;
                   1362:     pdq->pdq_os_ctx = (void *) ctx;
                   1363:     pdq->pdq_os_name = name;
                   1364:     pdq->pdq_flags = PDQ_PRINTCHARS;
                   1365:     /*
                   1366:      * Allocate the additional data structures required by
                   1367:      * the PDQ driver.  Allocate a contiguous region of memory
                   1368:      * for the descriptor block.  We need to allocated enough
                   1369:      * to guarantee that we will a get 8KB block of memory aligned
                   1370:      * on a 8KB boundary.  This turns to require that we allocate
                   1371:      * (N*2 - 1 page) pages of memory.  On machine with less than
                   1372:      * a 8KB page size, it mean we will allocate more memory than
                   1373:      * we need.  The extra will be used for the unsolicited event
                   1374:      * buffers (though on machines with 8KB pages we will to allocate
                   1375:      * them separately since there will be nothing left overs.)
                   1376:      */
                   1377:     p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes);
                   1378:     if (p != NULL) {
                   1379:        pdq_physaddr_t physaddr = PDQ_OS_VA_TO_PA(pdq, p);
                   1380:        /*
                   1381:         * Assert that we really got contiguous memory.  This isn't really
                   1382:         * needed on systems that actually have physical contiguous allocation
                   1383:         * routines, but on those systems that don't ...
                   1384:         */
                   1385:        for (idx = PDQ_OS_PAGESIZE; idx < 0x2000; idx += PDQ_OS_PAGESIZE) {
                   1386:            if (PDQ_OS_VA_TO_PA(pdq, p + idx) - physaddr != idx)
                   1387:                goto cleanup_and_return;
                   1388:        }
                   1389:        physaddr &= 0x1FFF;
                   1390:        if (physaddr) {
                   1391:            pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p;
                   1392:            pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - physaddr];
                   1393:        } else {
                   1394:            pdq->pdq_dbp = (pdq_descriptor_block_t *) p;
                   1395:            pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000];
                   1396:        }
                   1397:     }
                   1398:     if (contig_bytes == sizeof(pdq_descriptor_block_t)) {
                   1399:        pdq->pdq_unsolicited_info.ui_events =
                   1400:            (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC(
                   1401:                PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
                   1402:     }
                   1403:
                   1404:     /*
                   1405:      * Make sure everything got allocated.  If not, free what did
                   1406:      * get allocated and return.
                   1407:      */
                   1408:     if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) {
                   1409:       cleanup_and_return:
                   1410:        if (p /* pdq->pdq_dbp */ != NULL)
                   1411:            PDQ_OS_MEMFREE_CONTIG(p /* pdq->pdq_dbp */, contig_bytes);
                   1412:        if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL)
                   1413:            PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events,
                   1414:                           PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
                   1415:        PDQ_OS_MEMFREE(pdq, sizeof(pdq_t));
                   1416:        return NULL;
                   1417:     }
                   1418:
                   1419:     pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer;
                   1420:     pdq->pdq_command_info.ci_bufstart = (pdq_uint8_t *) pdq->pdq_dbp->pdqdb_command_pool;
                   1421:     pdq->pdq_rx_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_receive_buffers;
                   1422:
                   1423:     pdq->pdq_host_smt_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_host_smt_buffers;
                   1424:
                   1425:     PDQ_PRINTF(("\nPDQ Descriptor Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp));
                   1426:     PDQ_PRINTF(("    Receive Queue          = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_receives));
                   1427:     PDQ_PRINTF(("    Transmit Queue         = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_transmits));
                   1428:     PDQ_PRINTF(("    Host SMT Queue         = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_host_smt));
                   1429:     PDQ_PRINTF(("    Command Response Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_responses));
                   1430:     PDQ_PRINTF(("    Command Request Queue  = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_requests));
                   1431:     PDQ_PRINTF(("PDQ Consumer Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_cbp));
                   1432:
                   1433:     /*
                   1434:      * Zero out the descriptor block.  Not really required but
                   1435:      * it pays to be neat.  This will also zero out the consumer
                   1436:      * block, command pool, and buffer pointers for the receive
                   1437:      * host_smt rings.
                   1438:      */
                   1439:     PDQ_OS_MEMZERO(pdq->pdq_dbp, sizeof(*pdq->pdq_dbp));
                   1440:
                   1441:     /*
                   1442:      * Initialize the CSR references.
                   1443:      * the DEFAA (FutureBus+) skips a longword between registers
                   1444:      */
                   1445:     pdq_init_csrs(&pdq->pdq_csrs, bus, csr_base, pdq->pdq_type == PDQ_DEFAA ? 2 : 1);
                   1446:     if (pdq->pdq_type == PDQ_DEFPA)
                   1447:        pdq_init_pci_csrs(&pdq->pdq_pci_csrs, bus, csr_base, 1);
                   1448:
                   1449:     PDQ_PRINTF(("PDQ CSRs: BASE = " PDQ_OS_PTR_FMT "\n", pdq->pdq_csrs.csr_base));
                   1450:     PDQ_PRINTF(("    Port Reset                = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1451:           pdq->pdq_csrs.csr_port_reset, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_reset)));
                   1452:     PDQ_PRINTF(("    Host Data                 = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1453:           pdq->pdq_csrs.csr_host_data, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_data)));
                   1454:     PDQ_PRINTF(("    Port Control              = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1455:           pdq->pdq_csrs.csr_port_control, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_control)));
                   1456:     PDQ_PRINTF(("    Port Data A               = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1457:           pdq->pdq_csrs.csr_port_data_a, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_a)));
                   1458:     PDQ_PRINTF(("    Port Data B               = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1459:           pdq->pdq_csrs.csr_port_data_b, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_b)));
                   1460:     PDQ_PRINTF(("    Port Status               = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1461:           pdq->pdq_csrs.csr_port_status, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)));
                   1462:     PDQ_PRINTF(("    Host Int Type 0           = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1463:           pdq->pdq_csrs.csr_host_int_type_0, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0)));
                   1464:     PDQ_PRINTF(("    Host Int Enable           = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1465:           pdq->pdq_csrs.csr_host_int_enable, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_enable)));
                   1466:     PDQ_PRINTF(("    Type 2 Producer           = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1467:           pdq->pdq_csrs.csr_type_2_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_type_2_producer)));
                   1468:     PDQ_PRINTF(("    Command Response Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1469:           pdq->pdq_csrs.csr_cmd_response_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_response_producer)));
                   1470:     PDQ_PRINTF(("    Command Request Producer  = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1471:           pdq->pdq_csrs.csr_cmd_request_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_request_producer)));
                   1472:     PDQ_PRINTF(("    Host SMT Producer         = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1473:           pdq->pdq_csrs.csr_host_smt_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_smt_producer)));
                   1474:     PDQ_PRINTF(("    Unsolicited Producer      = " PDQ_OS_PTR_FMT " [0x%08x]\n",
                   1475:           pdq->pdq_csrs.csr_unsolicited_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_unsolicited_producer)));
                   1476:
                   1477:     /*
                   1478:      * Initialize the command information block
                   1479:      */
                   1480:     pdq->pdq_command_info.ci_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_command_info.ci_bufstart);
                   1481:     for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_requests)/sizeof(pdq->pdq_dbp->pdqdb_command_requests[0]); idx++) {
                   1482:        pdq_txdesc_t *txd = &pdq->pdq_dbp->pdqdb_command_requests[idx];
                   1483:
                   1484:        txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
                   1485:        txd->txd_eop = txd->txd_sop = 1;
                   1486:        txd->txd_pa_hi = 0;
                   1487:     }
                   1488:     for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_responses)/sizeof(pdq->pdq_dbp->pdqdb_command_responses[0]); idx++) {
                   1489:        pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_command_responses[idx];
                   1490:
                   1491:        rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
                   1492:        rxd->rxd_sop = 1;
                   1493:        rxd->rxd_seg_cnt = 0;
                   1494:        rxd->rxd_seg_len_lo = 0;
                   1495:     }
                   1496:
                   1497:     /*
                   1498:      * Initialize the unsolicited event information block
                   1499:      */
                   1500:     pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
                   1501:     pdq->pdq_unsolicited_info.ui_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_unsolicited_info.ui_events);
                   1502:     for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events)/sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events[0]); idx++) {
                   1503:        pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_unsolicited_events[idx];
                   1504:        pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
                   1505:
                   1506:        rxd->rxd_sop = 1;
                   1507:        rxd->rxd_seg_cnt = 0;
                   1508:        rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16;
                   1509:        rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event
                   1510:            - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events;
                   1511:        rxd->rxd_pa_hi = 0;
                   1512:     }
                   1513:     /*
                   1514:      * Initialize the receive information blocks (normal and SMT).
                   1515:      */
                   1516:     pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
                   1517:     pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8;
                   1518:
                   1519:     pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
                   1520:     pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3;
                   1521:
                   1522:     /*
                   1523:      * Initialize the transmit information block.
                   1524:      */
                   1525:     pdq->pdq_tx_hdr[0] = PDQ_FDDI_PH0;
                   1526:     pdq->pdq_tx_hdr[1] = PDQ_FDDI_PH1;
                   1527:     pdq->pdq_tx_hdr[2] = PDQ_FDDI_PH2;
                   1528:     pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
                   1529:     pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = sizeof(pdq->pdq_tx_hdr);
                   1530:     pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1;
                   1531:     pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_tx_hdr);
                   1532:
                   1533:     state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
                   1534:     PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
                   1535:
                   1536:     /*
                   1537:      * Stop the PDQ if it is running and put it into a known state.
                   1538:      */
                   1539:     state = pdq_stop(pdq);
                   1540:
                   1541:     PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
                   1542:     PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
                   1543:     /*
                   1544:      * If the adapter is not the state we expect, then the initialization
                   1545:      * failed.  Cleanup and exit.
                   1546:      */
                   1547: #if defined(PDQVERBOSE)
                   1548:     if (state == PDQS_HALTED) {
                   1549:        pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
                   1550:        printf("Halt code = %d (%s)\n", halt_code, pdq_halt_codes[halt_code]);
                   1551:        if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA)
                   1552:            PDQ_PRINTF(("PFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
                   1553:                       PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
                   1554:                       PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0) & PDQ_HOST_INT_FATAL_ERROR));
                   1555:     }
                   1556: #endif
                   1557:     if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE)
                   1558:        goto cleanup_and_return;
                   1559:
                   1560:     PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
                   1561:           pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1],
                   1562:           pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3],
                   1563:           pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5]));
                   1564:     PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n",
                   1565:           pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
                   1566:           pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3]));
                   1567:     PDQ_PRINTF(("PDQ Chip Revision = "));
                   1568:     switch (pdq->pdq_chip_rev) {
                   1569:        case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break;
                   1570:        case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break;
                   1571:        case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break;
                   1572:        default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev));
                   1573:     }
                   1574:     PDQ_PRINTF(("\n"));
                   1575:
                   1576:     return pdq;
                   1577: }

CVSweb