The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386ps2/if_en.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 
   27 /*
   28  * HISTORY
   29  * $Log:        if_en.c,v $
   30  * Revision 2.2  93/11/17  16:53:33  dbg
   31  *      Changed start() to return void.
   32  *      [93/09/13            dbg]
   33  * 
   34  *      Created, used if_pc586 as a reference.
   35  *      [93/09/09            zon]
   36  * 
   37  */
   38 
   39 /* default: no debug messages */
   40 #undef EN_DEBUG
   41 
   42 /* default: thick ethernet */
   43 #define EN_THIN_ETHERNET 0
   44 
   45 /* default: no loopback */
   46 #define EN_LOOPBACK 0
   47 
   48 #include <mach_ttd.h>
   49 #include <kern/time_out.h>
   50 #include <device/device_types.h>
   51 #include <device/errno.h>
   52 #include <device/io_req.h>
   53 #include <device/if_hdr.h>
   54 #include <device/if_ether.h>
   55 #include <device/net_status.h>
   56 #include <device/net_io.h>
   57 
   58 #include <i386/ipl.h>
   59 #include <mach/vm_param.h>
   60 #include <vm/vm_kern.h>
   61 
   62 #if MACH_TTD
   63 #include <ttd/ttd_stub.h>
   64 #endif
   65 
   66 #include <i386ps2/bus.h>
   67 
   68 #include <en.h>
   69 
   70 #ifdef EN_DEBUG
   71 /* if non-zero, print debugging information */
   72 /* if > 1, print more information */
   73 /* if > 2, print even more information */
   74 int en_debug = EN_DEBUG;
   75 #endif
   76 
   77 /* if non-zero, configure for THIN ethernet, otherwise for THICK ethernet */
   78 int en_thin_ethernet = EN_THIN_ETHERNET;
   79 
   80 /* if non-zero, enable hardware loopback */
   81 int en_loopback = EN_LOOPBACK;
   82 
   83 /*****************************************************************************/
   84 
   85 /*
   86  * LOCAL MEMORY MAP
   87  *
   88  * SCP  FFF6 -- FFFF, 10 BYTES
   89  * ISCP FFEE -- FFF5, 8 BYTES
   90  * SCB  FFDE -- FFED, 16 BYTES
   91  * CU   FFCC -- FFDD, 18 BYTES
   92  * TBD  FFC4 -- FFCB, 8 BYTES
   93  * TBUF F80E -- FFC3, 1974 BYTES
   94  * RBUF C320 -- F80D, 13550 BYTES (25 X 542)
   95  * RBD  C226 -- C31F, 250 BYTES (25 X 10)
   96  * FD   C000 -- C225, 550 BYTES (25 X 22)
   97  */
   98 
   99 #define RBUF_SIZE 542 /* size of a receive buffer */
  100 
  101 #define TBUF_SIZE 1974 /* size of transmit buffer */
  102 
  103 #define MAX_FD  25 /* FD chain has 25 units */
  104 #define MAX_RBD 25 /* RBD chain has 25 units */
  105 
  106 #define ETHER_SIZE 6 /* size of ethernet address */
  107 
  108 #define SCP   0xFFF6 /* local address of SCP  */
  109 #define ISCP  0xFFEE /* local address of ISCP */
  110 #define SCB   0xFFDE /* local address of SCB  */
  111 #define CU    0xFFCC /* local address of CU   */
  112 #define TBD   0xFFC4 /* local address of TBD  */
  113 #define TBUF  0xF80E /* local address of TBUF */
  114 
  115 /* local address of RBUF[i] */
  116 #define RBUF(i) (0xC320 + ((i) * RBUF_SIZE))
  117 
  118 /* local address of RBD[i] */
  119 #define RBD(i) (0xC226 + ((i) * sizeof(struct rbd)))
  120 
  121 /* local address of FD[i] */
  122 #define FD(i) (0xC000 + ((i) * sizeof(struct fd)))
  123 #define FD_INDEX(f) (((f) - FD(0)) / sizeof(struct fd))
  124 
  125 typedef struct scp {
  126         unsigned short sysbus;
  127         unsigned short unused[2];
  128         unsigned short iscp;
  129         unsigned short iscp_base;
  130 } *scp_t;
  131 
  132 typedef struct iscp {
  133         unsigned short busy;
  134         unsigned short scb_offset;
  135         unsigned short scb;
  136         unsigned short scb_base;
  137 } *iscp_t;
  138 
  139 typedef struct scb {
  140         unsigned short status;
  141         unsigned short command;
  142         unsigned short cbl_offset;
  143         unsigned short rfa_offset;
  144         unsigned short crcerrs;
  145         unsigned short alnerrs;
  146         unsigned short rscerrs;
  147         unsigned short ovrnerrs;
  148 } *scb_t;
  149 
  150 typedef struct transmit {
  151         unsigned short tbd_offset;
  152         unsigned char dest_addr[ETHER_SIZE];
  153         unsigned short length;
  154 } *transmit_t;
  155 
  156 typedef struct configure {
  157         unsigned short fifolim_bytecnt;
  158         unsigned short addrlen_mode;
  159         unsigned short linprio_interframe;
  160         unsigned short slot_time;
  161         unsigned short hardware;
  162         unsigned short min_frame_len;
  163 } *configure_t;
  164 
  165 /* standard configuration parameters */
  166 #define FIFOLIM_BYTECNT    0x080C
  167 #define ADDRLEN_MODE       0x2600
  168 #define LINPRIO_INTERFRAME 0x6000
  169 #define SLOT_TIME          0xF200
  170 #define HARDWARE           0x0000
  171 #define MIN_FRAME_LEN      0x0040
  172 
  173 typedef struct ac {
  174         unsigned short status;
  175         unsigned short command;
  176         unsigned short link_offset;
  177         union {
  178                 struct transmit transmit;
  179                 struct configure configure;
  180                 unsigned char iasetup[ETHER_SIZE];
  181         } cmd;
  182 } *ac_t;
  183 
  184 typedef struct tbd {
  185         unsigned short act_count;
  186         unsigned short next_tbd_offset;
  187         unsigned short buffer_addr;
  188         unsigned short buffer_base;
  189 } *tbd_t;
  190 
  191 typedef struct fd {
  192         unsigned short status;
  193         unsigned short command;
  194         unsigned short link_offset;
  195         unsigned short rbd_offset;
  196         unsigned char destination[ETHER_SIZE];
  197         unsigned char source[ETHER_SIZE];
  198         unsigned short length;
  199 } *fd_t;
  200 
  201 typedef struct rbd {
  202         unsigned short status;
  203         unsigned short next_rbd_offset;
  204         unsigned short buffer_addr;
  205         unsigned short buffer_base;
  206         unsigned short size;
  207 } *rbd_t;
  208 
  209 #define SCB_SW_INT      0xF000
  210 #define SCB_SW_CX       0x8000
  211 #define SCB_SW_FR       0x4000
  212 #define SCB_SW_CNA      0x2000
  213 #define SCB_SW_RNR      0x1000
  214 
  215 #define SCB_IDLE        0x0700
  216 #define SCB_CUS_IDLE    0x0000
  217 #define SCB_CUS_SUSPND  0x0100
  218 #define SCB_CUS_ACTV    0x0200
  219 
  220 #define SCB_RUS_IDLE    0x0000
  221 #define SCB_RUS_SUSPND  0x0010
  222 #define SCB_RUS_NORESRC 0x0020
  223 #define SCB_RUS_READY   0x0040
  224 
  225 #define SCB_ACK_CX      0x8000
  226 #define SCB_ACK_FR      0x4000
  227 #define SCB_ACK_CNA     0x2000
  228 #define SCB_ACK_RNR     0x1000
  229 
  230 #define SCB_CU_STRT     0x0100
  231 #define SCB_CU_RSUM     0x0200
  232 #define SCB_CU_SUSPND   0x0300
  233 #define SCB_CU_ABRT     0x0400
  234 
  235 #define SCB_RESET       0x0080
  236 
  237 #define SCB_RU_STRT     0x0010
  238 #define SCB_RU_RSUM     0x0020
  239 #define SCB_RU_SUSPND   0x0030
  240 #define SCB_RU_ABRT     0x0040
  241 
  242 #define AC_NOP          0x00
  243 #define AC_IASETUP      0x01
  244 #define AC_CONFIGURE    0x02
  245 #define AC_MCSETUP      0x03
  246 #define AC_TRANSMIT     0x04
  247 #define AC_TDR          0x05
  248 #define AC_DUMP         0x06
  249 #define AC_DIAGNOSE     0x07
  250 
  251 #define AC_SW_C         0x8000
  252 #define AC_SW_B         0x4000
  253 #define AC_SW_OK        0x2000
  254 #define AC_SW_A         0x1000
  255 #define AC_SW_FAIL      0x0800
  256 
  257 #define AC_CW_EL        0x8000
  258 #define AC_CW_S         0x4000
  259 #define AC_CW_I         0x2000
  260 
  261 #define TC_CARRIER      0x0400
  262 #define TC_CLS          0x0200
  263 #define TC_DMA          0x0100
  264 #define TC_DEFER        0x0080
  265 #define TC_SQE          0x0040
  266 #define TC_COLLISION    0x0020
  267 
  268 #define TBD_SW_EOF      0x8000
  269 #define TBD_SW_COUNT    0x3FFF
  270 
  271 #define RBD_SW_EOF      0x8000
  272 #define RBD_SW_COUNT    0x3FFF
  273 #define RBD_EL          0x8000
  274 #define RFD_DONE        0x8000
  275 #define RFD_BUSY        0x4000
  276 #define RFD_OK          0x2000
  277 #define RFD_CRC         0x0800
  278 #define RFD_ALN         0x0400
  279 #define RFD_RSC         0x0200
  280 #define RFD_DMA         0x0100
  281 #define RFD_SHORT       0x0080
  282 #define RFD_EOF         0x0040
  283 #define RFD_EL          0x8000
  284 #define RFD_SUSP        0x4000
  285 
  286 /*****************************************************************************/
  287 
  288 static int probe();
  289 static int attach();
  290 static int interrupt();
  291 
  292 #if MACH_TTD
  293 int en_get_packet();
  294 int en_send_packet();
  295 #endif
  296 
  297 static struct i386_dev *info[NEN];
  298 
  299 struct i386_driver endriver = { probe, 0, attach, "en", info, 0, 0 };
  300 
  301 int (*enintrs[])() = { interrupt, 0 };
  302 
  303 /* spl for network interrupts */
  304 #define SPLNET spl6
  305 
  306 /* POS identification for ethernet board */
  307 #define EN_POS_ID 0x6042
  308 
  309 /* do automatic reset if no interrupts for 10 seconds */
  310 #define AUTOMATIC_RESET 10000
  311 
  312 /* maximum local address (local address is 16 bits) */
  313 #define MAX_ADDRESS 0x00010000
  314 
  315 /* window to local memory is 16K bytes */
  316 #define WINDOW_SIZE round_page(16 * 1024)
  317 
  318 /* information from ethernet POS registers */
  319 typedef struct pos {
  320         int card_enabled;          /* if non-zero, the card is enabled      */
  321         int thin_ethernet_enabled; /* if non-zero, thin ethernet is enabled */
  322         unsigned short io_base;    /* ethernet I/O register base            */
  323         unsigned long ram_base;    /* local memory window base              */
  324         int interrupt_level;       /* ethernet interrupt level (IRQ)        */
  325         int revision_level;        /* ethernet adapter revision level       */
  326         unsigned short register6;  /* address of "register 6"               */
  327 } *pos_t;
  328 
  329 /* ethernet device per-unit state information */
  330 typedef struct en {
  331         int unit;                         /* unit number, index to en[]    */
  332         struct pos pos;                   /* POS information               */
  333         unsigned char bank;               /* current local memory bank     */
  334         unsigned short minimum_address;   /* minimum local memory address  */
  335         unsigned char *window;            /* window to local memory        */
  336         char network_address[ETHER_SIZE]; /* ethernet address              */
  337         int attached;                     /* if non-zero, unit is attached */
  338 #if MACH_TTD
  339         int ttd_enabled;                  /* if non-zero, TTD polled mode  */
  340 #endif
  341         int busy;                         /* if non-zero, output is busy   */
  342         int interrupt_count;              /* automatic_reset() counter     */
  343         unsigned short fd;                /* (local) address of current fd */
  344         unsigned short end_fd;            /* (local) address of end fd     */
  345         unsigned short end_rbd;           /* (local) address of end rbd    */
  346         volatile scp_t scp;               /* pointer to SCP in bank #3     */
  347         volatile iscp_t iscp;             /* pointer to ISCP in bank #3    */
  348         volatile scb_t scb;               /* pointer to SCB in bank #3     */
  349         volatile ac_t cb;                 /* pointer to CB in bank #3      */
  350         volatile tbd_t tbd;               /* pointer to TBD in bank #3     */
  351         struct ifnet ifnet;               /* IFNET structure               */
  352 } *en_t;
  353 
  354 /* ethernet device per-unit state information */
  355 static struct en en[NEN];
  356 
  357 /*****************************************************************************/
  358 
  359 /* print an ethernet address */
  360 static print_ethernet_address(unsigned char *address)
  361 {
  362         printf("%02X:%02X:%02X:%02X:%02X:%02X",
  363                address[0],
  364                address[1],
  365                address[2],
  366                address[3],
  367                address[4],
  368                address[5]);
  369 }
  370 
  371 /*****************************************************************************/
  372 
  373 #define MAX_POS_SLOT      0x0008
  374 #define POS_SELECT_PORT   0x0096
  375 #define POS_SELECT_BASE   0x0008
  376 #define POS_REGISTER_BASE 0x0100
  377 
  378 /* read a POS register */
  379 static unsigned char POS_read(int slot, int n)
  380 {
  381         unsigned char value;
  382 
  383         outb(POS_SELECT_PORT, POS_SELECT_BASE + slot);
  384         value = inb(POS_REGISTER_BASE + n);
  385         outb(POS_SELECT_PORT, 0);
  386 
  387         return value;
  388 
  389 }
  390 
  391 /* write a POS register */
  392 static void POS_write(int slot, int n, unsigned char value)
  393 {
  394 
  395         outb(POS_SELECT_PORT, POS_SELECT_BASE + slot);
  396         outb(POS_REGISTER_BASE + n, value);
  397         outb(POS_SELECT_PORT, 0);
  398 
  399 }
  400 
  401 /* read POS identification in the adapter at the specified slot */
  402 static unsigned short POS_read_slot_id(int slot)
  403 {
  404         union {
  405                 unsigned short word;
  406                 unsigned char byte[2];
  407         } x;
  408 
  409         x.byte[0] = POS_read(slot, 0);
  410         x.byte[1] = POS_read(slot, 1);
  411 
  412         return x.word;
  413 
  414 }
  415 
  416 /* read POS register 'n' in the adapter at the specified slot */
  417 static unsigned char POS_read_slot_data(int slot, int n)
  418 {
  419 
  420         return POS_read(slot, n + 2);
  421 
  422 }
  423 
  424 /* write POS register 'n' in the adaptor at the specified slot */
  425 static void POS_write_slot_data(int slot, int n, unsigned char value)
  426 {
  427 
  428         POS_write(slot, n + 2, value);
  429 
  430 }
  431 
  432 /*****************************************************************************/
  433 
  434 /* reset the ethernet adaptor, disable interrupt generation */
  435 static void
  436         channel_reset(register en_t x)
  437 {
  438         register volatile unsigned char *w = x->window;
  439         register volatile unsigned char ww;
  440 
  441 #ifdef EN_DEBUG
  442         if (en_debug > 2)
  443                 printf("EN%d CHANNEL RESET\n", x->unit);
  444 #endif
  445 
  446         outb(x->pos.register6, 0x03);
  447         ww = *w;
  448         ww = *w;
  449         ww = *w;
  450         ww = *w;
  451         outb(x->pos.register6, 0x83);
  452 
  453         x->bank = 3;
  454 
  455 }
  456 
  457 /* enable the ethernet adaptor to generate interrupts */
  458 /* interrupt generation is disabled after a channel_reset() */
  459 static void
  460         enable_interrupts(register en_t x)
  461 {
  462 
  463         outb(x->pos.register6, inb(x->pos.register6) | 0x04);
  464 
  465 }
  466 
  467 /* strobe the ethernet adaptor's channel attention */
  468 static void
  469         channel_attention(register en_t x)
  470 {
  471         register unsigned char register6 = inb(x->pos.register6);
  472         register volatile unsigned char *w = x->window;
  473         register volatile unsigned char ww;
  474 
  475 #ifdef EN_DEBUG
  476         if (en_debug > 2)
  477                 printf("EN%d CHANNEL ATTENTION\n", x->unit);
  478 #endif
  479 
  480         outb(x->pos.register6, register6 | 0x40);
  481         ww = *w;
  482         ww = *w;
  483         outb(x->pos.register6, register6);
  484 
  485 }
  486 
  487 /* return an access pointer to local memory */
  488 /*** this may move the window to a different bank ***/
  489 /* NOTE: all interesting structures are in bank #3 (0xC000 - 0xFFFF) */
  490 static unsigned char *
  491         window(register en_t x, register unsigned short address)
  492 {
  493         register unsigned char bank = ((address) >> 14) & 3;
  494 
  495         if (address < x->minimum_address)
  496                 panic("EN%d WINDOW ADDRESS 0x%04X < 0x%04X\n",
  497                        x->unit,
  498                        address,
  499                        x->minimum_address);
  500 
  501         if (bank != x->bank) {
  502                 outb(x->pos.register6,
  503                      (inb(x->pos.register6) & 0xFC) | bank);
  504                 x->bank = bank;
  505         }
  506 
  507         return &x->window[address & 0x3FFF];
  508 
  509 }
  510 
  511 /* check a bank of local memory, return zero if OK */
  512 /* return address+1 if local memory error */
  513 static int bank_check(register en_t x, unsigned short base)
  514 {
  515         int i;
  516         int bank = (base >> 14) & 3;
  517         unsigned char *w = window(x, base);
  518 
  519         for (i = 0; i < 0x4000; i++)
  520                 *window(x, base + i) = (i + bank) & 0xFF;
  521 
  522         for (i = 0; i < 0x4000; i++)
  523                 if (*window(x, base + i) != ((i + bank) & 0xFF))
  524                         return base + i + 1;
  525 
  526         return 0;
  527 
  528 }
  529 
  530 /*****************************************************************************/
  531 
  532 /* probe for an ethernet device, return non-zero if one is found */
  533 /* this routine reads all POS register information for the adaptor */
  534 static int probe(addr, iod)
  535 register caddr_t addr;
  536 register struct i386_dev *iod;
  537 {
  538         register en_t x = &en[iod->dev_unit];
  539         unsigned char register0;
  540         unsigned char register1;
  541         int slot;
  542         int unit;
  543 
  544         /* search for an adaptor for the specified device unit */
  545         unit = 0;
  546         for (slot = 0; slot < MAX_POS_SLOT; slot++) {
  547                 if ((POS_read_slot_id(slot) == EN_POS_ID) &&
  548                     (unit++ == iod->dev_unit))
  549                         break;
  550         }
  551         if (slot == MAX_POS_SLOT)
  552                 return 0;
  553 
  554         /* set device unit (index to en[]) */
  555         x->unit = iod->dev_unit;
  556 
  557         /* read POS register #0 */
  558         register0 = POS_read_slot_data(slot, 0);
  559 
  560         /* read CARD_ENABLED bit */
  561         x->pos.card_enabled = register0 & 0x01;
  562 
  563         /* read/set THIN_ETHERNET_ENABLED bit */
  564         if (x->pos.thin_ethernet_enabled = !(register0 & 0x20)) {
  565                 if (!en_thin_ethernet) {
  566                         register0 |= 0x20;
  567                         POS_write_slot_data(slot, 0, register0);
  568                 }
  569         }
  570         else {
  571                 if (en_thin_ethernet) {
  572                         register0 &= ~0x20;
  573                         POS_write_slot_data(slot, 0, register0);
  574                 }
  575         }
  576 
  577         /* read IO_BASE */
  578         switch (register0 & 0x06) {
  579         case 0x00:
  580                 x->pos.io_base = 0x0300;
  581                 break;
  582         case 0x02:
  583                 x->pos.io_base = 0x1300;
  584                 break;
  585         case 0x04:
  586                 x->pos.io_base = 0x2300;
  587                 break;
  588         case 0x06:
  589                 x->pos.io_base = 0x3300;
  590                 break;
  591         }
  592 
  593         /* read RAM_BASE */
  594         switch (register0 & 0x18) {
  595         case 0x00:
  596                 x->pos.ram_base = 0x000C0000;
  597                 break;
  598         case 0x08:
  599                 x->pos.ram_base = 0x000C8000;
  600                 break;
  601         case 0x10:
  602                 x->pos.ram_base = 0x000D0000;
  603                 break;
  604         case 0x18:
  605                 x->pos.ram_base = 0x000D8000;
  606                 break;
  607         }
  608 
  609         /* read INTERRUPT_LEVEL */
  610         switch (register0 & 0xC0) {
  611         case 0x00:
  612                 x->pos.interrupt_level = 12;
  613                 break;
  614         case 0x40:
  615                 x->pos.interrupt_level = 7;
  616                 break;
  617         case 0x80:
  618                 x->pos.interrupt_level = 3;
  619                 break;
  620         case 0xC0:
  621                 x->pos.interrupt_level = 9;
  622                 break;
  623         }
  624 
  625         /* write INTERRUPT_LEVEL to cover POST routine bug */
  626         register1 = POS_read_slot_data(slot, 1);
  627         register1 &= 0xF0;
  628         switch (x->pos.interrupt_level) {
  629         case 12:
  630                 register1 |= 0x01;
  631                 break;
  632         case 7:
  633                 register1 |= 0x02;
  634                 break;
  635         case 3:
  636                 register1 |= 0x04;
  637                 break;
  638         case 9:
  639                 register1 |= 0x08;
  640                 break;
  641         }
  642         POS_write_slot_data(slot, 1, register1);
  643 
  644 #ifdef EN_DEBUG
  645         if (en_debug > 2) {
  646                 printf("ENPROBE: EN%d\n", x->unit);
  647                 printf("         BOARD IS %s\n",
  648                        x->pos.card_enabled ? "ENABLED" : "DISABLED");
  649                 printf("         THIN ETHERNET IS %s\n",
  650                        x->pos.thin_ethernet_enabled ? "ENABLED" : "DISABLED");
  651                 printf("         IO BASE IS 0x%04X\n",
  652                        x->pos.io_base);
  653                 printf("         RAM BASE IS 0x%08X\n",
  654                        x->pos.ram_base);
  655                 printf("         INTERRUPT LEVEL IS %d\n",
  656                        x->pos.interrupt_level);
  657         }
  658 #endif
  659 
  660         /* complain if the adaptor is not enabled */
  661         if (!x->pos.card_enabled)
  662                 printf("EN%d: ETHERNET ADAPTOR IS NOT ENABLED.\n", x->unit);
  663 
  664         /* return non-zero if enabled ethernet adaptor has been found */
  665         return x->pos.card_enabled;
  666 
  667 }
  668 
  669 /* attach an ethernet device, return non-zero if success */
  670 /* this routine sets up the device per-unit state information */
  671 static int attach(iod)
  672 register struct i386_dev *iod;
  673 {
  674         register en_t x = &en[iod->dev_unit];
  675         register int i;
  676         int memory_size;
  677 
  678         /* cache the I/O address of adaptor register #6 */
  679         x->pos.register6 = x->pos.io_base + 6;
  680 
  681         /* get a pointer to the local memory window */
  682         x->window = (void *)phystokv(x->pos.ram_base);
  683 
  684         /* reset the ethernet adaptor */
  685         channel_reset(x);
  686 
  687         /* read the ethernet address */
  688         for (i = 0; i < ETHER_SIZE; i++)
  689                 x->network_address[i] = inb(x->pos.io_base + i);
  690 
  691         /* display the ethernet address */
  692 #ifdef EN_DEBUG
  693         if (en_debug > 2)
  694                 printf("ENATTACH: EN%d\n"
  695                        "          ETHERNET ADDRESS ",
  696                        x->unit);
  697         else
  698 #endif
  699         printf("EN%d: ", x->unit);
  700         print_ethernet_address(x->network_address);
  701         printf("\n");
  702 
  703         /* read the revision level from adaptor register #7 */
  704         x->pos.revision_level = inb(x->pos.io_base + 7) & 0x0F;
  705 
  706 #ifdef EN_DEBUG
  707         if (en_debug > 2)
  708                 printf("          REVISION LEVEL IS '%X'\n",
  709                        x->pos.revision_level);
  710 #endif
  711 
  712         /* error if incorrect revision level */
  713         switch (x->pos.revision_level) {
  714         case 0x0F:
  715         case 0x0E:
  716                 break;
  717         default:
  718                 printf("EN%d: INCORRECT REVISION LEVEL '%X'\n",
  719                        x->unit,
  720                        x->pos.revision_level);
  721                 return 0;
  722         }
  723 
  724         /* check local memory, determine size of local memory */
  725         /* error if can not access at least 16K of local memory */
  726         x->minimum_address = 0x0000;
  727         if (i = bank_check(x, 0xC000)) {
  728                 printf("EN%d: CAN NOT ACCESS LOCAL MEMORY AT 0x%04x\n",
  729                        x->unit,
  730                        i - 1);
  731                 return 0;
  732         }
  733         else if (bank_check(x, 0x8000)) {
  734                 memory_size = 16;
  735                 x->minimum_address = 0xC000;
  736         }
  737         else if (bank_check(x, 0x4000)) {
  738                 memory_size = 32;
  739                 x->minimum_address = 0x8000;
  740         }
  741         else if (bank_check(x, 0x0000)) {
  742                 memory_size = 48;
  743                 x->minimum_address = 0x4000;
  744         }
  745         else {
  746                 memory_size = 64;
  747                 x->minimum_address = 0x0000;
  748         }
  749 
  750 #ifdef EN_DEBUG
  751         if (en_debug > 2)
  752                 printf("          THERE ARE %dK BYTES OF LOCAL MEMORY\n",
  753                        memory_size);
  754 #endif
  755 
  756         /* set up IFNET structure for this device unit */
  757         x->ifnet.if_unit = x->unit;
  758         x->ifnet.if_mtu = ETHERMTU;
  759         x->ifnet.if_flags = IFF_BROADCAST;
  760         x->ifnet.if_header_size = sizeof(struct ether_header);
  761         x->ifnet.if_header_format = HDR_ETHERNET;
  762         x->ifnet.if_address_size = 6;
  763         x->ifnet.if_address = x->network_address;
  764         if_init_queues(&x->ifnet);
  765 
  766         /* connect interrupt handler to the adaptor's IRQ */
  767         iod->dev_pic = x->pos.interrupt_level;
  768         iod->dev_spl = SPL4;
  769         take_dev_irq(iod);
  770 
  771         /* this ethernet device unit has been attached OK */
  772         x->attached = 1;
  773 
  774 #if MACH_TTD
  775         if (!ttd_get_packet) {
  776                 ttd_device_unit = x->unit;
  777                 ttd_get_packet = en_get_packet;
  778                 ttd_send_packet = en_send_packet;
  779                 memcpy(ttd_host_ether_id.array,
  780                        x->network_address,
  781                        ETHER_SIZE);
  782         }
  783 #endif
  784 
  785 #ifdef EN_DEBUG
  786         if (en_debug > 2)
  787                 printf("EN%d ATTACH: OK\n", x->unit);
  788 #endif
  789 
  790         /* return non-zero if attached OK */
  791         return !x->attached;
  792 
  793 }
  794 
  795 /*****************************************************************************/
  796 
  797 #ifdef EN_DEBUG
  798 
  799 static void print_scp(en_t x, unsigned short scp_offset)
  800 {
  801         scp_t scp = (scp_t)window(x, scp_offset);
  802 
  803         printf("SCP 0x%04X: SYSBUS=0x%04X ISCP=0x%04X ISCP_BASE=0x%04X\n",
  804                scp_offset,
  805                scp->sysbus,
  806                scp->iscp,
  807                scp->iscp_base);
  808 
  809 }
  810 
  811 static void print_iscp(en_t x, unsigned short iscp_offset)
  812 {
  813         iscp_t iscp = (iscp_t)window(x, iscp_offset);
  814 
  815         printf("ISCP 0x%04X: BUSY=0x%04X SCB_OFFSET=0x%04X "
  816                "SCB=0x%04X SCB_BASE=0x%04X\n",
  817                iscp_offset,
  818                iscp->busy,
  819                iscp->scb_offset,
  820                iscp->scb,
  821                iscp->scb_base);
  822 
  823 }
  824 
  825 static void print_scb(en_t x, unsigned short scb_offset)
  826 {
  827         scb_t scb = (scb_t)window(x, scb_offset);
  828 
  829         printf("SCB 0x%04X: STATUS=0x%04X COMMAND=0x%04X\n",
  830                scb_offset,
  831                scb->status,
  832                scb->command);
  833         printf("            CBL_OFFSET=0x%04X RFA_OFFSET=0x%04X\n",
  834                scb->cbl_offset,
  835                scb->rfa_offset);
  836         printf("            ERRS 0x%04X 0x%04X 0x%04X 0x%04X\n",
  837                scb->crcerrs,
  838                scb->alnerrs,
  839                scb->rscerrs,
  840                scb->ovrnerrs);
  841 
  842 }
  843 
  844 static void print_ac(en_t x, unsigned short cb_offset)
  845 {
  846         ac_t cb = (ac_t)window(x, cb_offset);
  847 
  848         printf("CB 0x%04X: STATUS=0x%04X COMMAND=0x%04X LINK_OFFSET=0x%04X\n",
  849                cb_offset,
  850                cb->status,
  851                cb->command,
  852                cb->link_offset);
  853         switch (cb->command & 0x0007) {
  854         case AC_NOP:
  855                 printf("NOP\n");
  856                 break;
  857         case AC_IASETUP:
  858                 printf("IASETUP: ");
  859                 print_ethernet_address(cb->cmd.iasetup);
  860                 printf("\n");
  861                 break;
  862         case AC_CONFIGURE:
  863                 printf("CONFIGURE: %d %d %d %d %d %d\n",
  864                        cb->cmd.configure.fifolim_bytecnt,
  865                        cb->cmd.configure.addrlen_mode,
  866                        cb->cmd.configure.linprio_interframe,
  867                        cb->cmd.configure.slot_time,
  868                        cb->cmd.configure.hardware,
  869                        cb->cmd.configure.min_frame_len);
  870                 break;
  871         case AC_MCSETUP:
  872                 printf("MCSETUP\n");
  873                 break;
  874         case AC_TRANSMIT:
  875                 printf("TRANSMIT: 0x%04X ",
  876                        cb->cmd.transmit.tbd_offset);
  877                 print_ethernet_address(cb->cmd.transmit.dest_addr);
  878                 printf(" %d\n", cb->cmd.transmit.length);
  879                 break;
  880         case AC_TDR:
  881                 printf("TDR\n");
  882                 break;
  883         case AC_DUMP:
  884                 printf("DUMP\n");
  885                 break;
  886         case AC_DIAGNOSE:
  887                 printf("DIAGNOSE\n");
  888                 break;
  889         }
  890 }
  891 
  892 static void print_fd(en_t x, unsigned short fd_offset)
  893 {
  894         fd_t fd = (fd_t)window(x, fd_offset);
  895 
  896         printf("FD 0x%04X: STATUS=0x%04X COMMAND=0x%04X\n",
  897                fd_offset,
  898                fd->status,
  899                fd->command);
  900         printf("           LINK=0x%04X RBD=0x%04X\n",
  901                fd->link_offset,
  902                fd->rbd_offset);
  903         printf("           DEST=");
  904         print_ethernet_address(fd->destination);
  905         printf("\n");
  906         printf("           SOURCE=");
  907         print_ethernet_address(fd->source);
  908         printf("\n");
  909         printf("           LENGTH=%d\n", fd->length);
  910 
  911 }
  912 
  913 #endif
  914 
  915 /*****************************************************************************/
  916 
  917 /* acknowledge any completed commands, return non-zero if error */
  918 static int acknowledge(register en_t x, char *where)
  919 {
  920         register int i;
  921 
  922         if (x->scb->command = (x->scb->status & SCB_SW_INT)) {
  923 
  924 #ifdef EN_DEBUG
  925                 if (en_debug > 2)
  926                         printf("EN%d %s: ACKNOWLEDGE 0x%04X\n",
  927                                x->unit,
  928                                where,
  929                                x->scb->status & SCB_SW_INT);
  930 #endif
  931 
  932                 channel_attention(x);
  933                 for (i = 0; i < 1000000; i++)
  934                         if (!x->scb->command)
  935                                 break;
  936                 if (x->scb->command) {
  937                         printf("EN%d %s: 0x%04X NOT ACKNOWLEDGED\n",
  938                                x->unit,
  939                                where,
  940                                x->scb->command);
  941                         return -1;
  942                 }
  943 
  944         }
  945 
  946         return 0;
  947 
  948 }
  949 
  950 /* run a command, return non-zero if error */
  951 static int
  952         run_command(register en_t x,
  953                     char *where,
  954                     char *what,
  955                     register int interrupt)
  956 {
  957         int i;
  958 
  959         x->cb->status = 0;
  960         x->cb->command |= AC_CW_EL;
  961         x->cb->link_offset = CU;
  962 
  963         if (interrupt)
  964                 x->cb->command |= AC_CW_I;
  965 
  966 #ifdef EN_DEBUG
  967         if (en_debug > 2)
  968                 print_ac(x, CU);
  969 #endif
  970 
  971         if (interrupt)
  972                 while (x->scb->command);
  973 
  974         x->scb->command = SCB_CU_STRT;
  975 
  976         channel_attention(x);
  977 
  978         if (interrupt)
  979                 return 0;
  980 
  981         for(i = 0; i < 10000000; i++)
  982                 if (x->cb->status & AC_SW_C)
  983                         break;
  984 
  985         x->cb->command = AC_CW_EL;
  986 
  987         if (x->cb->status & AC_SW_B) {
  988                 printf("EN%d %s: %s TIMEOUT\n", x->unit, where, what);
  989                 return -1;
  990         }
  991 
  992         if (!(x->cb->status & AC_SW_C) ||
  993             !(x->cb->status & AC_SW_OK)) {
  994                 printf("EN%d %s: %s FAILED (0x%04X)\n",
  995                        x->unit,
  996                        where,
  997                        what,
  998                        x->cb->status);
  999                 return -1;
 1000         }
 1001 
 1002         if (acknowledge(x, where))
 1003                 return -1;
 1004 
 1005         return 0;
 1006 
 1007 }
 1008 
 1009 /* do a NOP command, return non-zero if error */
 1010 static int ac_nop(register en_t x, char *where)
 1011 {
 1012 
 1013         x->cb->command = AC_NOP;
 1014 
 1015         return run_command(x, where, "NOP", 0);
 1016 
 1017 }
 1018 
 1019 /* do a DIAGNOSE command, return non-zero if error */
 1020 static int ac_diagnose(register en_t x, char *where)
 1021 {
 1022 
 1023         x->cb->command = AC_DIAGNOSE;
 1024 
 1025         return run_command(x, where, "DIAGNOSE", 0);
 1026 
 1027 }
 1028 
 1029 /* do a CONFIGURE command, return non-zero if error */
 1030 static int
 1031         ac_configure(register en_t x,
 1032                      char *where,
 1033                      unsigned short fifolim_bytecnt,
 1034                      unsigned short addrlen_mode,
 1035                      unsigned short linprio_interframe,
 1036                      unsigned short slot_time,
 1037                      unsigned short hardware,
 1038                      unsigned short min_frame_len)
 1039 {
 1040 
 1041         x->cb->command = AC_CONFIGURE;
 1042         x->cb->cmd.configure.fifolim_bytecnt = fifolim_bytecnt;
 1043         x->cb->cmd.configure.addrlen_mode = addrlen_mode;
 1044         x->cb->cmd.configure.linprio_interframe = linprio_interframe;
 1045         x->cb->cmd.configure.slot_time = slot_time;
 1046         x->cb->cmd.configure.hardware = hardware;
 1047         x->cb->cmd.configure.min_frame_len = min_frame_len;
 1048 
 1049         return run_command(x, where, "CONFIGURE", 0);
 1050 
 1051 }
 1052 
 1053 /* do an IASETUP command, return non-zero if error */
 1054 static int
 1055         ac_iasetup(register en_t x,
 1056                    char *where,
 1057                    unsigned char *network_address)
 1058 {
 1059 
 1060         x->cb->command = AC_IASETUP;
 1061 
 1062         memcpy(x->cb->cmd.iasetup, x->network_address, ETHER_SIZE);
 1063 
 1064         return run_command(x, where, "IASETUP", 0);
 1065 
 1066 }
 1067 
 1068 /*****************************************************************************/
 1069 
 1070 /* build the FD chain */
 1071 static void build_fd_chain(register en_t x)
 1072 {
 1073         register int i;
 1074 
 1075         for (i = 0; i < MAX_FD; i++) {
 1076                 register fd_t fd = (fd_t)window(x, FD(i));
 1077                 fd->status = 0;
 1078                 fd->command = 0;
 1079                 fd->rbd_offset = i ? 0xFFFF : RBD(0);
 1080                 if ((i + 1) < MAX_FD) {
 1081                         fd->link_offset = FD(i + 1);
 1082                 }
 1083                 else {
 1084                         fd->command |= AC_CW_EL;
 1085                         fd->link_offset = 0xFFFF;
 1086                 }
 1087         }
 1088 
 1089         /* the first FD in the chain is the "current" one */
 1090         x->fd = FD(0);
 1091 
 1092         /* the last FD in the chain is for recycle() */
 1093         x->end_fd = FD(MAX_FD - 1);
 1094 
 1095 }
 1096 
 1097 /* build the RBD chain */
 1098 static void build_rbd_chain(register en_t x)
 1099 {
 1100         register int i;
 1101 
 1102         for (i = 0; i < MAX_RBD; i++) {
 1103                 register rbd_t rbd = (rbd_t)window(x, RBD(i));
 1104                 rbd->status = 0;
 1105                 rbd->buffer_addr = RBUF(i);
 1106                 rbd->buffer_base = 0;
 1107                 rbd->size = RBUF_SIZE;
 1108                 if ((i + 1) < MAX_RBD)
 1109                         rbd->next_rbd_offset = RBD(i + 1);
 1110                 else {
 1111                         rbd->size |= AC_CW_EL;
 1112                         rbd->next_rbd_offset = 0xFFFF;
 1113                 }
 1114         }
 1115 
 1116         /* the last RBD in the chain is for recycle() */
 1117         x->end_rbd = RBD(MAX_RBD - 1);
 1118 
 1119 }
 1120 
 1121 /* start up the RECEIVE UNIT */
 1122 static void start_receive_unit(register en_t x)
 1123 {
 1124 
 1125         if ((x->scb->status & SCB_RUS_READY) == SCB_RUS_READY) {
 1126 #ifdef EN_DEBUG
 1127                 if (en_debug)
 1128                         printf("EN%d START_RECEIVE_UNIT: READY FD 0x%04X\n",
 1129                                x->unit,
 1130                                x->fd);
 1131 #endif
 1132                 return;
 1133         }
 1134 
 1135         build_fd_chain(x);
 1136 
 1137         build_rbd_chain(x);
 1138 
 1139 #ifdef EN_DEBUG
 1140         if (en_debug)
 1141                 printf("EN%d START_RECEIVE_UNIT: FD 0x%04X\n",
 1142                        x->unit,
 1143                        x->fd);
 1144 #endif
 1145 
 1146         x->scb->rfa_offset = x->fd;
 1147         x->scb->command = SCB_RU_STRT;
 1148 
 1149         channel_attention(x);
 1150 
 1151 }
 1152 
 1153 /* transmit a packet frame */
 1154 static void transmit(register en_t x, char *data, int count)
 1155 {
 1156         unsigned char *tbuf;
 1157         struct ether_header *eh = (struct ether_header *)data;
 1158 
 1159         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1160             (IFF_UP | IFF_RUNNING))
 1161                 panic("EN%d TRANSMIT: NOT UP AND RUNNING", x->unit);
 1162 
 1163 #ifdef EN_DEBUG
 1164         if (en_debug) {
 1165                 printf("EN%d TRANSMIT: DHOST ", x->unit);
 1166                 print_ethernet_address(eh->ether_dhost);
 1167                 printf("\n");
 1168         }
 1169 #endif
 1170 
 1171         count -= sizeof(struct ether_header);
 1172 
 1173         tbuf = window(x, TBUF);
 1174         memcpy(tbuf, data + sizeof(struct ether_header), count);
 1175         if (count < ETHERMIN)
 1176                 bzero(&tbuf[count], ETHERMIN - count);
 1177 
 1178         /* move window back to bank #3 */
 1179         (void)window(x, 0xFFFF);
 1180 
 1181         /* set up TBD */
 1182         x->tbd->act_count = (count < ETHERMIN) ? ETHERMIN : count;
 1183         x->tbd->next_tbd_offset = 0xFFFF;
 1184         x->tbd->buffer_addr = TBUF;
 1185         x->tbd->buffer_base = 0;
 1186         x->tbd->act_count |= TBD_SW_EOF;
 1187 
 1188         /* set up CB with TRANSMIT command */
 1189         x->cb->command = AC_TRANSMIT;
 1190         x->cb->cmd.transmit.tbd_offset = TBD;
 1191         x->cb->cmd.transmit.length = (unsigned short)eh->ether_type;
 1192         memcpy(x->cb->cmd.transmit.dest_addr,
 1193                eh->ether_dhost,
 1194                ETHER_SIZE);
 1195 
 1196         /* run TRANSMIT command, interrupt when complete */
 1197         run_command(x, "TRANSMIT", "TRANSMIT", 1);
 1198 
 1199 }
 1200 
 1201 /* start output */
 1202 static void start(int unit)
 1203 {
 1204         register en_t x = &en[unit];
 1205         io_req_t m;
 1206 
 1207         /* error if ethernet device is not UP and RUNNING */
 1208         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1209             (IFF_UP | IFF_RUNNING)) {
 1210                 printf("EN%d START: NOT UP AND RUNNING\n", unit);
 1211 
 1212                 IF_DEQUEUE(&x->ifnet.if_snd, m);
 1213 
 1214                 if (m)
 1215                         iodone(m);
 1216 
 1217                 return;
 1218         }
 1219 
 1220         /* if currently busy with output, do nothing */
 1221         if (x->busy && (x->scb->status & SCB_IDLE)) {
 1222 #ifdef EN_DEBUG
 1223                 if (en_debug)
 1224                         printf("EN%d START: BUSY\n", x->unit);
 1225 #endif
 1226                 return;
 1227         }
 1228         x->busy = 0;
 1229 
 1230         /* take the I/O request out of the queue */
 1231         IF_DEQUEUE(&x->ifnet.if_snd, m);
 1232 
 1233         /* if there is an I/O request, transmit the packet */
 1234         if (m) {
 1235 #ifdef EN_DEBUG
 1236                 if (en_debug)
 1237                         printf("EN%d START: OK\n", unit);
 1238 #endif
 1239                 x->busy++;
 1240                 transmit(x, m->io_data, m->io_count);
 1241                 iodone(m);
 1242         }
 1243 #ifdef EN_DEBUG
 1244         else if (en_debug)
 1245                 printf("EN%d START: EMPTY\n", x->unit);
 1246 #endif
 1247         
 1248         return;
 1249 }
 1250 
 1251 /* forward declaration of reset() */
 1252 static void reset(register en_t x, char *where);
 1253 
 1254 /* automatic reset if there is no interrupt activity */
 1255 static automatic_reset(x)
 1256 en_t x;
 1257 {
 1258         spl_t s;
 1259 
 1260         /* if ethernet device is no UP and RUNNING, do nothing */
 1261         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1262             (IFF_UP | IFF_RUNNING))
 1263                 return;
 1264 
 1265         /* if there has been no interrupt activity, reset() */
 1266         if (!x->interrupt_count) {
 1267                 s = SPLNET();
 1268                 reset(x, "AUTOMATIC_RESET");
 1269                 splx(s);
 1270         }
 1271         /* otherwise, clear the counter and set up the timeout() */
 1272         else {
 1273                 x->interrupt_count = 0;
 1274                 (void)untimeout(automatic_reset, x);
 1275                 timeout(automatic_reset, x, AUTOMATIC_RESET);
 1276         }
 1277 
 1278 }
 1279 
 1280 /* reset the ethernet device, set UP and RUNNING if success */
 1281 static void reset(register en_t x, char *where)
 1282 {
 1283         int i;
 1284 
 1285 #ifdef EN_DEBUG
 1286         if (en_debug)
 1287                 printf("EN%d RESET (%s)\n", x->unit, where);
 1288 #endif
 1289 
 1290         /* do hardware reset */
 1291         channel_reset(x);
 1292 
 1293         /* enable hardware loopback if required */
 1294         if (en_loopback)
 1295                 outb(x->pos.register6, inb(x->pos.register6) | 0x20);
 1296 
 1297         /* clear all local memory */
 1298         for (i = x->minimum_address; i < MAX_ADDRESS; i += 0x4000)
 1299                 bzero(window(x, i), 0x4000);
 1300 
 1301         /* set up SCP */
 1302         x->scp = (scp_t)window(x, SCP);
 1303         x->scp->sysbus = 0;
 1304         x->scp->iscp = ISCP;
 1305         x->scp->iscp_base = 0;
 1306 #ifdef EN_DEBUG
 1307         if (en_debug > 2)
 1308                 print_scp(x, SCP);
 1309 #endif
 1310 
 1311         /* set up ISCP */
 1312         x->iscp = (iscp_t)window(x, ISCP);
 1313         x->iscp->busy = 1;
 1314         x->iscp->scb_offset = SCB;
 1315         x->iscp->scb = 0;
 1316         x->iscp->scb_base = 0;
 1317 #ifdef EN_DEBUG
 1318         if (en_debug > 2)
 1319                 print_iscp(x, ISCP);
 1320 #endif
 1321 
 1322         /* set up SCB */
 1323         x->scb = (scb_t)window(x, SCB);
 1324         x->scb->status = 0;
 1325         x->scb->command = 0;
 1326         x->scb->cbl_offset = CU;
 1327         x->scb->rfa_offset = FD(0);
 1328         x->scb->crcerrs = 0;
 1329         x->scb->alnerrs = 0;
 1330         x->scb->rscerrs = 0;
 1331         x->scb->ovrnerrs = 0;
 1332 #ifdef EN_DEBUG
 1333         if (en_debug > 2)
 1334                 print_scb(x, SCB);
 1335 #endif
 1336 
 1337         /* set up CB pointer */
 1338         x->cb = (ac_t)window(x, CU);
 1339 
 1340         /* set up TBD pointer */
 1341         x->tbd = (tbd_t)window(x, TBD);
 1342 
 1343         /* issue SCB_RESET */
 1344         x->scb->command = SCB_RESET;
 1345         channel_attention(x);
 1346 
 1347         /* error if SCB_RESET timeout */
 1348         for (i = 0; i < 1000000; i++)
 1349                 if (!x->iscp->busy)
 1350                         break;
 1351         if (x->iscp->busy) {
 1352                 printf("EN%d RESET: SCB_RESET TIMEOUT\n", x->unit);
 1353                 goto error;
 1354         }
 1355 
 1356         /* error if not ready after SCB_RESET */
 1357         for (i = 0; i < 1000000; i++)
 1358                 if (x->scb->status == (SCB_SW_CX | SCB_SW_CNA))
 1359                         break;
 1360         if (x->scb->status != (SCB_SW_CX | SCB_SW_CNA)) {
 1361                 printf("EN%d RESET: SCB_RESET NOT READY\n", x->unit);
 1362                 goto error;
 1363         }
 1364 
 1365         /* acknowledge the SCB_RESET */
 1366         (void)acknowledge(x, "RESET");
 1367 
 1368         /* do a NOP, error if error */
 1369         if (ac_nop(x, "RESET"))
 1370                 goto error;
 1371 
 1372         /* do a DIAGNOSE, error if error */
 1373         if (ac_diagnose(x, "RESET"))
 1374                 goto error;
 1375 
 1376         /* do a CONFIGURE, error if error */
 1377         if (ac_configure(x,
 1378                          "RESET",
 1379                          FIFOLIM_BYTECNT,
 1380                          ADDRLEN_MODE,
 1381                          LINPRIO_INTERFRAME,
 1382                          SLOT_TIME,
 1383                          HARDWARE,
 1384                          MIN_FRAME_LEN))
 1385                 goto error;
 1386 
 1387         /* do an IASETUP, error if error */
 1388         if (ac_iasetup(x, "RESET", x->network_address))
 1389                 goto error;
 1390 
 1391         /* ethernet device is UP and RUNNING */
 1392         x->ifnet.if_flags |= IFF_UP | IFF_RUNNING;
 1393 
 1394         /* clear start() busy flag */
 1395         x->busy = 0;
 1396 
 1397         /* set automatic reset timer */
 1398         x->interrupt_count = 1;
 1399         automatic_reset(x);
 1400 
 1401         /* allow the adaptor to generate interrupts */
 1402 #if EN_TTD
 1403         if (!kttd_active)
 1404 #endif
 1405         enable_interrupts(x);
 1406 
 1407         /* start up the RECEIVE UNIT */
 1408         start_receive_unit(x);
 1409 
 1410         /* start up the transmitter */
 1411         start(x->unit);
 1412 
 1413         /* all done */
 1414         return;
 1415 
 1416         /* reset has failed */
 1417 error:
 1418 
 1419         /* do a channel_reset() to turn off the adaptor */
 1420         channel_reset(x);
 1421 
 1422         /* ethernet device is not UP and RUNNING */
 1423         x->ifnet.if_flags &= ~IFF_RUNNING;
 1424         x->ifnet.if_flags &= ~IFF_UP;
 1425 
 1426         /* complain that the reset failed */
 1427         printf("EN%d %s: RESET FAILED\n", x->unit, where);
 1428 
 1429 }
 1430 
 1431 /* recycle the current receive frame descriptor and its receive buffers */
 1432 /* return a pointer to the current FD, return zero if error */
 1433 static fd_t recycle(register en_t x, unsigned short end_rbd)
 1434 {
 1435         fd_t fd;
 1436         unsigned short next_fd;
 1437         volatile rbd_t rbd;
 1438 
 1439 #ifdef EN_DEBUG
 1440         if (en_debug > 1)
 1441                 printf("EN%d RECYCLE: FD[%d]\n", x->unit, FD_INDEX(x->fd));
 1442 #endif
 1443 
 1444         /* get a pointer to the current frame descriptor */
 1445         fd = (fd_t)window(x, x->fd);
 1446 
 1447         /* if there are receive buffers to recycle... */
 1448         if (fd->rbd_offset != 0xFFFF) {
 1449 
 1450                 /* get a pointer to the new end of the free list */
 1451                 if (end_rbd == 0xFFFF)
 1452                         end_rbd = fd->rbd_offset;
 1453                 for (;;) {
 1454                         rbd = (rbd_t)window(x, end_rbd);
 1455                         if (rbd->status & RBD_SW_EOF)
 1456                                 break;
 1457                         if ((end_rbd = rbd->next_rbd_offset) == 0xFFFF) {
 1458                                 printf("EN%d RECYCLE: FD[%d] BAD RBD CHAIN\n",
 1459                                        x->unit,
 1460                                        FD_INDEX(x->fd));
 1461                                 return 0;
 1462                         }
 1463                 }
 1464 
 1465                 /* terminate the new end of the free list */
 1466                 rbd->status = 0;
 1467                 rbd->next_rbd_offset = 0xFFFF;
 1468                 rbd->size |= RBD_EL;
 1469 
 1470                 /* connect to the end of the free list */
 1471                 rbd = (rbd_t)window(x, x->end_rbd);
 1472                 rbd->next_rbd_offset = fd->rbd_offset;
 1473                 rbd->size &= ~RBD_EL;
 1474 
 1475                 /* note the new end of the free list */
 1476                 x->end_rbd = end_rbd;
 1477 
 1478         }
 1479 
 1480         /* get a pointer to the current frame descriptor */
 1481         fd = (fd_t)window(x, x->fd);
 1482 
 1483         /* error if FD chain is broken */
 1484         if ((next_fd = fd->link_offset) == 0xFFFF) {
 1485                 printf("EN%d RECYCLE: FD[%d] BAD FD CHAIN\n",
 1486                        x->unit,
 1487                        FD_INDEX(x->fd));
 1488                 return 0;
 1489         }
 1490 
 1491         /* clear the fields for this FD structure */
 1492         fd->status = 0;
 1493         fd->command = AC_CW_EL;
 1494         fd->link_offset = 0xFFFF;
 1495         fd->rbd_offset = 0xFFFF;
 1496 
 1497         /* attach to the end of the free list */
 1498         fd = (fd_t)window(x, x->end_fd);
 1499         fd->link_offset = x->fd;
 1500         fd->command = 0;
 1501         x->end_fd = x->fd;
 1502 
 1503         /* make the next FD the current FD */
 1504         return (fd_t)window(x, x->fd = next_fd);
 1505 
 1506 }
 1507 
 1508 /* receive a packet, return zero if no packet received */
 1509 static ipc_kmsg_t receive(register en_t x, ipc_kmsg_t m)
 1510 {
 1511         volatile fd_t fd;
 1512         volatile rbd_t rbd;
 1513         ipc_kmsg_t allocated;
 1514         struct ether_header *e;
 1515         struct packet_header *p;
 1516         char *d;
 1517         unsigned short n;
 1518         unsigned short rbd_address;
 1519 
 1520         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1521             (IFF_UP | IFF_RUNNING))
 1522                 panic("EN%d RECEIVE: NOT UP AND RUNNING", x->unit);
 1523 
 1524         /* get a pointer to the current frame descriptor */
 1525         fd = (fd_t)window(x, x->fd);
 1526 
 1527         /* while there is a completed frame to process... */
 1528         while (fd->status & RFD_DONE) {
 1529 
 1530                 /* if the frame is not OK, complain and drop the packet */
 1531                 if (!(fd->status & RFD_OK)) {
 1532                         printf("EN%d RECEIVE: FD[%d] STATUS 0x%04X\n",
 1533                                x->unit,
 1534                                FD_INDEX(x->fd),
 1535                                fd->status & 0x0FFF);
 1536                         x->ifnet.if_ierrors++;
 1537                         if (!(fd = recycle(x, 0xFFFF)))
 1538                                 goto error;
 1539                         continue;
 1540                 }
 1541 
 1542                 /* if can't get a message buffer, complain and drop packet */
 1543                 allocated = 0;
 1544                 if (!m && ((allocated = m = net_kmsg_get()) == IKM_NULL)) {
 1545 #ifdef EN_DEBUG
 1546                         if (en_debug)
 1547                                 printf("EN%d RECEIVE: "
 1548                                        "FD[%d] NET_KMSG_GET FAILED\n",
 1549                                        x->unit,
 1550                                        FD_INDEX(x->fd));
 1551 #endif
 1552                         x->ifnet.if_rcvdrops++;
 1553                         if (!(fd = recycle(x, 0xFFFF)))
 1554                                 goto error;
 1555                         continue;
 1556                 }
 1557 
 1558 #ifdef EN_DEBUG
 1559                 if (en_debug) {
 1560                         printf("EN%d RECEIVE: FD[%d] ",
 1561                                x->unit,
 1562                                FD_INDEX(x->fd));
 1563                         print_ethernet_address(fd->source);
 1564                         printf(" => ", x->unit);
 1565                         print_ethernet_address(fd->destination);
 1566                         printf("\n");
 1567                 }
 1568 #endif
 1569 
 1570                 /* get pointers to the ethernet header and packet data */
 1571                 e = (struct ether_header *)(&net_kmsg(m)->header[0]);
 1572                 p = (struct packet_header *)(&net_kmsg(m)->packet[0]);
 1573                 d = (char *)(p + 1);
 1574                 p->type = e->ether_type = fd->length;
 1575                 p->length = sizeof(struct packet_header);
 1576 
 1577                 /* set ether_type, ether_shost and ether_dhost */
 1578                 memcpy(e->ether_shost, fd->source, ETHER_SIZE);
 1579                 memcpy(e->ether_dhost, fd->destination, ETHER_SIZE);
 1580 
 1581                 /* error if there is no receive buffer */
 1582                 if ((rbd_address = fd->rbd_offset) == 0xFFFF) {
 1583                         printf("EN%d RECEIVE: FD[%d] MISSING RBD\n",
 1584                                x->unit,
 1585                                FD_INDEX(x->fd));
 1586                         x->ifnet.if_rcvdrops++;
 1587                         goto error;
 1588                 }
 1589 
 1590                 /* copy each receive buffer into the message buffer... */
 1591                 for (;;) {
 1592 
 1593                         /* get pointer to receive buffer descriptor */
 1594                         rbd = (rbd_t)window(x, rbd_address);
 1595 
 1596                         /* copy receive buffer to message buffer */
 1597                         n = rbd->status & RBD_SW_COUNT;
 1598                         memcpy(d, window(x, rbd->buffer_addr), n);
 1599                         d += n;
 1600 
 1601                         /* accumulate packet length */
 1602                         p->length += n;
 1603 
 1604                         /* get pointer to receive buffer descriptor */
 1605                         rbd = (rbd_t)window(x, rbd_address);
 1606 
 1607                         /* all done if end of receive buffer chain */
 1608                         if (rbd->status & RBD_SW_EOF)
 1609                                 break;
 1610 
 1611                         /* go to the next buffer, error if chain is broken */
 1612                         if ((rbd_address = rbd->next_rbd_offset) == 0xFFFF) {
 1613                                 printf("EN%d RECEIVE: FD[%d] BAD RBD CHAIN\n",
 1614                                        x->unit,
 1615                                        FD_INDEX(x->fd));
 1616                                 x->ifnet.if_rcvdrops++;
 1617                                 goto error;
 1618                         }
 1619 
 1620                 }
 1621 
 1622                 /* all done, recycle this frame descriptor and its buffers */
 1623                 if (!(fd = recycle(x, rbd_address)))
 1624                         goto error;
 1625 
 1626                 /* all done, no error, return message */
 1627                 return m;
 1628 
 1629         }
 1630 
 1631         /* all done, there is no message to return */
 1632         return 0;
 1633 
 1634 error:
 1635 
 1636         /* if a message buffer was allocated, put it back */
 1637         if (allocated)
 1638                 net_kmsg_put(allocated);
 1639 
 1640         /* reset */
 1641         reset(x, "RECEIVE");
 1642 
 1643         /* failed, return zero */
 1644         return 0;
 1645 
 1646 }
 1647 
 1648 /*****************************************************************************/
 1649 
 1650 /* handle an ethernet adaptor interrupt */
 1651 static int interrupt(unit)
 1652 int unit;
 1653 {
 1654         register volatile en_t x = &en[unit];
 1655         unsigned short type;
 1656         ipc_kmsg_t m;
 1657         struct packet_header *p;
 1658 
 1659 #ifdef EN_DEBUG
 1660         if (en_debug)
 1661                 printf("EN%d INTERRUPT 0x%04X\n",
 1662                        x->unit,
 1663                        x->scb->status & SCB_SW_INT);
 1664 #endif
 1665 
 1666         /* if not UP and RUNNING, complain then do nothing */
 1667         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1668             (IFF_UP | IFF_RUNNING)) {
 1669                 printf("EN%d INTERRUPT: NOT UP AND RUNNING\n", unit);
 1670                 return -1;
 1671         }
 1672 
 1673         /* count this interrupt for automatic_reset() */
 1674         x->interrupt_count++;
 1675 
 1676         /* while there are interrupts to process... */
 1677         while (type = (x->scb->status & SCB_SW_INT)) {
 1678 
 1679                 /* acknowledge the interrupting command(s) */
 1680                 acknowledge(x, "INTERRUPT");
 1681 
 1682                 /* if a frame has been received, process it (them) */
 1683                 if (type & SCB_SW_FR)
 1684                         while (m = receive(x, 0)) {
 1685                                 p = (struct packet_header *)
 1686                                         (&net_kmsg(m)->packet[0]);
 1687                                 net_packet(&x->ifnet,
 1688                                            m,
 1689                                            p->length,
 1690                                            ethernet_priority(m));
 1691                         }
 1692 
 1693                 /* if the RECEIVE UNIT went off-line, restart it */
 1694                 if (type & SCB_SW_RNR)
 1695                         start_receive_unit(x);
 1696 
 1697                 /* if a packet has been transmitted, try for another */
 1698                 if (type & SCB_SW_CX) {
 1699                         x->busy = 0;
 1700                         start(unit);
 1701                 }
 1702 
 1703         }
 1704 
 1705         /* return zero, nothing looks at this return value anyway... */
 1706         return 0;
 1707 
 1708 }
 1709 
 1710 /*****************************************************************************/
 1711 
 1712 #if MACH_TTD
 1713 
 1714 int en_get_packet(unit)
 1715 int unit;
 1716 {
 1717         en_t x = &en[unit];
 1718         spl_t s;
 1719 
 1720         /* crash if TTD not active */
 1721         if (!kttd_active)
 1722                 panic("EN%d EN_GET_PACKET: KTTD NOT ACTIVE\n");
 1723 
 1724         s = SPLNET();
 1725 
 1726         /* if not UP and RUNNING, do a reset() */
 1727         if ((x->ifnet.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1728             (IFF_UP | IFF_RUNNING))
 1729                 reset(x, "EN_GET_PACKET");
 1730 
 1731         /* loop until a packet is received */
 1732         while (!receive(x, (ipc_kmsg_t)ttd_request_msg));
 1733 
 1734         /* acknowledge any completed commands */
 1735         (void)acknowledge(x, "EN_GET_PACKET");
 1736 
 1737         splx(s);
 1738 
 1739         return 0;
 1740 
 1741 }
 1742 
 1743 int en_send_packet(unit, packet, len)
 1744 int unit;
 1745 char *packet;
 1746 int len;
 1747 {
 1748         en_t x = &en[unit];
 1749         spl_t s;
 1750 
 1751         /* crash if TTD not active */
 1752         if (!kttd_active)
 1753                 panic("EN%d EN_SEND_PACKET: KTTD NOT ACTIVE\n");
 1754 
 1755         s = SPLNET();
 1756 
 1757         /* transmit the packet */
 1758         transmit(x, packet, len);
 1759 
 1760         /* acknowledge any completed commands */
 1761         (void)acknowledge(x, "EN_SEND_PACKET");
 1762 
 1763         splx(s);
 1764 
 1765         return 0;
 1766 
 1767 }
 1768 
 1769 #endif
 1770 
 1771 /*****************************************************************************/
 1772 
 1773 /* return en structure pointer for specified ethernet device */
 1774 /* return zero if bad unit number or device not UP */
 1775 static en_t dev_to_en(register dev_t dev, char *name)
 1776 {
 1777         register unsigned int unit = minor(dev);
 1778         register en_t x;
 1779 
 1780 #ifdef EN_DEBUG
 1781         if (en_debug)
 1782                 printf("EN%d %s\n", unit, name);
 1783 #endif
 1784 
 1785         if ((unit < NEN) && ((x = &en[unit])->ifnet.if_flags & IFF_UP))
 1786                 return x;
 1787 
 1788         return 0;
 1789 
 1790 }
 1791 
 1792 /* open an ethernet device */
 1793 io_return_t
 1794         enopen(dev_t dev, dev_mode_t mode, io_req_t ior)
 1795 {
 1796         unsigned int unit = minor(dev);
 1797         register en_t x;
 1798         spl_t s;
 1799 
 1800 #ifdef EN_DEBUG
 1801         if (en_debug)
 1802                 printf("EN%d OPEN\n", unit);
 1803 #endif
 1804 
 1805         /* error if bad unit number or device not attached */
 1806         if ((unit >NEN) || !(x = &en[unit])->attached)
 1807                 return D_NO_SUCH_DEVICE;
 1808 
 1809 #ifdef EN_DEBUG
 1810         if (en_debug > 2) {
 1811                 int i, base;
 1812                 unsigned char c;
 1813                 printf("    BOARD IS %s\n",
 1814                        x->pos.card_enabled ? "ENABLED" : "DISABLED");
 1815                 printf("    THIN ETHERNET IS %s\n",
 1816                        x->pos.thin_ethernet_enabled ? "ENABLED" : "DISABLED");
 1817                 printf("    IO BASE IS 0x%04X\n",
 1818                        x->pos.io_base);
 1819                 printf("    RAM BASE IS 0x%08X\n",
 1820                        x->pos.ram_base);
 1821                 printf("    INTERRUPT LEVEL IS %d\n",
 1822                        x->pos.interrupt_level);
 1823                 printf("    ETHERNET ADDRESS ");
 1824                 print_ethernet_address(x->network_address);
 1825                 printf("\n");
 1826                 printf("    ETHERNET BOARD REVISION LEVEL IS '%X'\n",
 1827                        x->pos.revision_level);
 1828                 printf("    THE MINIMUM ADDRESS IS 0x%04X\n",
 1829                        x->minimum_address);
 1830                 for (base = x->minimum_address;
 1831                      base < MAX_ADDRESS;
 1832                      base += 0x4000)
 1833                         if (i = bank_check(x, base))
 1834                                 break;
 1835                 if (i)
 1836                         printf("    CAN NOT ACCESS BYTE AT 0x%04X\n", i - 1);
 1837                 else
 1838                         printf("    RAM ACCESS OK\n");
 1839         }
 1840 #endif
 1841 
 1842         /* reset the ethernet device */
 1843         s = SPLNET();
 1844         reset(x, "ENOPEN");
 1845         splx(s);
 1846 
 1847         /* success if the device is UP and RUNNING */
 1848         if (x->ifnet.if_flags & IFF_RUNNING)
 1849                 return D_SUCCESS;
 1850 
 1851         /* error if the reset() failed */
 1852         return D_IO_ERROR;
 1853 
 1854 }
 1855 
 1856 /* output to an ethernet device */
 1857 io_return_t
 1858         enoutput(dev_t dev, io_req_t ior)
 1859 {
 1860         register en_t x = dev_to_en(dev, "ENOUTPUT");
 1861 
 1862         /* error if no such device */
 1863         if (!x)
 1864                 return D_NO_SUCH_DEVICE;
 1865 
 1866         /* use the generic net_write() */
 1867         return net_write(&x->ifnet, start, ior);
 1868 
 1869 }
 1870 
 1871 /* set the input filter for an ethernet device */
 1872 io_return_t
 1873         ensetinput(dev_t dev,
 1874                    mach_port_t receive_port,
 1875                    int priority,
 1876                    filter_t *filter,
 1877                    unsigned int filter_count)
 1878 {
 1879         register en_t x = dev_to_en(dev, "ENSETINPUT");
 1880 
 1881         /* error if no such device */
 1882         if (!x)
 1883                 return D_NO_SUCH_DEVICE;
 1884 
 1885         /* use the generic net_set_filter() */
 1886         return net_set_filter(&x->ifnet,
 1887                               receive_port,
 1888                               priority,
 1889                               filter,
 1890                               filter_count);
 1891 
 1892 }
 1893 
 1894 /* get status for an ethernet device */
 1895 io_return_t
 1896         engetstat(dev_t dev,
 1897                   int flavor,
 1898                   dev_status_t status,
 1899                   unsigned int *count)
 1900 {
 1901         register en_t x = dev_to_en(dev, "ENGETSTAT");
 1902 
 1903         /* error if no such device */
 1904         if (!x)
 1905                 return D_NO_SUCH_DEVICE;
 1906 
 1907         /* use the generic net_getstat() */
 1908         return net_getstat(&x->ifnet, flavor, status, count);
 1909 
 1910 }
 1911 
 1912 /* set status for an ethernet device */
 1913 io_return_t
 1914         ensetstat(dev_t dev,
 1915                   int flavor,
 1916                   dev_status_t status,
 1917                   unsigned int count)
 1918 {
 1919         register en_t x = dev_to_en(dev, "ENSETSTAT");
 1920         register struct net_status *ns = (struct net_status *)status;
 1921         spl_t s;
 1922 
 1923         /* error if no such device */
 1924         if (!x)
 1925                 return D_NO_SUCH_DEVICE;
 1926 
 1927         /* do the right thing... */
 1928         switch (flavor) {
 1929         case NET_STATUS:
 1930                 if (count != NET_STATUS_COUNT)
 1931                         return D_INVALID_OPERATION;
 1932 #ifdef EN_DEBUG
 1933                 if (en_debug)
 1934                         printf("EN%d SETSTAT: NET_STATUS 0x%08X\n",
 1935                                x->unit,
 1936                                ns->flags);
 1937 #endif
 1938                 s = SPLNET();
 1939                 reset(x, "ENSETSTAT");
 1940                 splx(s);
 1941                 break;
 1942         default:
 1943                 return D_INVALID_OPERATION;
 1944         }
 1945 
 1946         return D_SUCCESS;
 1947 
 1948 }

Cache object: b3f8f5cd64c28a2b27ac445542f1ca01


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.