Generic LAN driver is new for the Solaris 8 10/00 release.
The Generic LAN driver (GLD) implements much of the STREAMS and Data Link Provider Interface (DLPI) functionality for a SolarisTM network driver.
Until Solaris 8 10/00, the GLD module was only available for Solaris Intel Platform Edition network drivers. Now GLD is available for Solaris SPARCTM Platform Edition network drivers, as well.
For more information, see gld(7D), dlpi(7P), gld(9E), gld(9F), gld_mac_info(9S), gld_stats(9S).
For the most current man pages, use the man command. The Solaris 8 Update release man pages include new feature information that is not in the Solaris 8 Reference Manual Collection.
GLD is a multi-threaded, clonable, loadable kernel module providing support for Solaris local area network device drivers. Local area network (LAN) device drivers in Solaris are STREAMS-based drivers that use DLPI to communicate with network protocol stacks. These protocol stacks use the network drivers to send and receive packets on a local area network. A network device driver must implement and conform to the requirements imposed by the DDI/DKI specification, STREAMS specification, DLPI specification, and programmatic interface of the device itself.
GLD implements most STREAMS and DLPI functionality required of a Solaris LAN driver. Several Solaris network drivers are implemented using GLD.
A Solaris network driver implemented using GLD is made up of two distinct parts: a generic component that deals with STREAMS and DLPI interfaces, and a device-specific component that deals with the particular hardware device. The device-specific module indicates its dependency on the GLD module (which is found at /kernel/misc/gld) and registers itself with GLD from within the driver's attach(9E) function. After it is successfully loaded, the driver is DLPI-compliant. The device-specific part of the driver calls gld(9F) functions when it receives data or needs some service from GLD. GLD makes calls into the gld(9E) entry points of the device-specific driver through pointers provided to GLD by the device-specific driver when it registered itself with GLD. The gld_mac_info(9S) structure is the main data interface between GLD and the device-specific driver.
The GLD facility currently supports devices of type DL_ETHER, DL_TPR, and DL_FDDI. GLD drivers are expected to process fully formed MAC-layer packets and should not perform logical link control (LLC) handling.
In some cases, you might need or want to implement a full DLPI-compliant driver without using the GLD facility. This is true for devices that are not ISO 8802-style (IEEE 802) LAN devices, or where you need a device type or DLPI service not supported by GLD.
For devices designated type DL_ETHER, GLD provides support for both Ethernet V2 and ISO 8802-3 (IEEE 802.3) packet processing. Ethernet V2 enables a data link service user to access and use any of a variety of conforming data link service providers without special knowledge of the provider's protocol. A service access point (SAP) is the point through which the user communicates with the service provider.
Streams bound to SAP values in the range [0-255] are treated as equivalent and denote that the user wants to use 8802-3 mode. If the value of the SAP field of the DL_BIND_REQ is within this range, GLD computes the length (not including the 14-byte media access control (MAC) header) of each subsequent DL_UNITDATA_REQ message on that Stream and transmits 8802-3 frames having those lengths in the MAC frame header type fields. Such lengths never exceed 1500.
All frames received from the media that have a type field in the range [0-1500] are assumed to be 8802-3 frames and are routed up all open Streams that are in 8802-3 mode (those Streams bound to a SAP value in the [0-255] range). If more than one Stream is in 8802-3 mode, the incoming frame is duplicated and routed up each such Stream.
Streams bound to SAP values greater than 1500 (Ethernet V2 mode) receive incoming packets whose Ethernet MAC header type value exactly matches the value of the SAP to which the Stream is bound.
For media types DL_TPR and DL_FDDI, GLD implements minimal SNAP (Sub-Net Access Protocol) processing for any Stream bound to a SAP value greater than 255. SAP values in the range [0-255] are LLC SAP values and are carried naturally by the media packet format. SAP values greater than 255 require a SNAP header, subordinate to the LLC header, to carry the 16-bit Ethernet V2-style SAP value.
SNAP headers are carried under LLC headers with destination SAP 0xAA. For outgoing packets with SAP values greater than 255, GLD creates an LLC+SNAP header that always looks like:
AA AA 03 00 00 00 XX XX
where ``XX XX'' represents the 16-bit SAP, corresponding to the Ethernet V2 style ``type.'' This is the only class of SNAP header supported—non-zero OUI fields and LLC control fields other than 03 are considered to be LLC packets with SAP 0xAA. Clients wanting to use SNAP formats other than this one must use LLC and bind to SAP 0xAA.
Incoming packets are examined to ascertain whether they conform to the format shown above. Packets that conform to this format are matched to any Streams bound to the packet's 16-bit SNAP type, as well as being considered to match the LLC SNAP SAP 0xAA.
Packets received for any LLC SAP are passed up all Streams that are bound to an LLC SAP, as described for media type DL_ETHER.
For type DL_TPR devices, GLD implements minimal support for source routing. Source routing enables a station that is sending a packet across a bridged medium to specify (in the packet MAC header) routing information that determines the route that the packet will take through the network.
Functionally, the source routing support provided by GLD learns routes, solicits and responds to requests for information about possible multiple routes, and selects among available routes. It adds Routing Information Fields to the MAC headers of outgoing packets and recognizes such fields in incoming packets.
GLD's source routing support does not implement the full Route Determination Entity (RDE) specified in Section 9 of ISO 8802-2 (IEEE 802.2). However, it is designed to interoperate with any such implementations that might exist in the same (or a bridged) network.
GLD implements both Style 1 and Style 2 DLPI providers. A physical point of attachment (PPA) is the point at which a system attaches itself to a physical communication medium. All communication on that physical medium funnels through the PPA. The Style 1 provider attaches the Stream to a particular PPA based on the major/minor device that has been opened. The Style 2 provider requires the DLS user to explicitly identify the desired PPA using DL_ATTACH_REQ. In this case, open(9E) creates a Stream between the user and GLD, and DL_ATTACH_REQ subsequently associates a particular PPA with that Stream. Style 2 is denoted by a minor number of zero. If a device node whose minor number is not zero is opened, Style 1 is indicated and the associated PPA is the minor number minus 1. In both Style 1 and Style 2 opens, the device is cloned.
GLD implements several DLPI primitives. The DL_INFO_REQ primitive requests information about the DLPI Stream. The message consists of one M_PROTO message block. GLD returns device-dependent values in the DL_INFO_ACK response to this request, based on information the GLD-based driver specified in the gldm_mac_info(9S) structure passed to gld_register(). However, GLD returns the following values on behalf of all GLD-based drivers:
Version is DL_VERSION_2.
Service mode is DL_CLDLS — GLD implements connectionless-mode service.
Provider style is DL_STYLE1 or DL_STYLE2, depending on how the Stream was opened.
No optional Quality Of Service (QOS) support is present and the QOS fields are zero.
Contrary to the DLPI specification, GLD returns the device's correct address length and broadcast address in DL_INFO_ACK even before the Stream has been attached to a PPA.
The DL_ATTACH_REQ primitive is used to associate a PPA with a Stream. This request is needed for Style 2 DLS providers to identify the physical medium over which the communication will transpire. Upon completion, the state changes from DL_UNATTACHED to DL_UNBOUND. The message consists of one M_PROTO message block. This request is not permitted when using the driver in Style 1 mode; Streams opened using Style 1 are already attached to a PPA by the time the open completes.
The DL_DETACH_REQ primitive requests to detach the PPA from the Stream. This is only allowed if the Stream was opened using Style 2.
The DL_BIND_REQ and DL_UNBIND_REQ primitives bind and unbind a DLSAP to the Stream. The PPA associated with a Stream will have completed initialization before completion of the processing of the DL_BIND_REQ on that Stream. Binding multiple Streams to the same SAP is allowed; each such Stream receives a copy of any packets received for that SAP.
The DL_ENABMULTI_REQ and DL_DISABMULTI_REQ primitives enable and disable reception of individual multicast group addresses. An application or other DLS user is permitted to create or modify a set of multicast addresses on a per-Stream basis by iterative use of these primitives. The Stream must be attached to a PPA for these primitives to be accepted.
The DL_PROMISCON_REQ and DL_PROMISCOFF_REQ primitives enable and disable promiscuous mode on a per-Stream basis, either at a physical level or at the SAP level. The DL Provider routes all received messages on the media to the DLS user until either a DL_DETACH_REQ or a DL_PROMISCOFF_REQ is received or the Stream is closed. It is possible to specify physical level promiscuous reception of all packets on the medium or of multicast packets only.
The Stream must be attached to a PPA for these promiscuous mode primitives to be accepted.
The DL_UNITDATA_REQ primitive is used to send data in a connectionless transfer. Because this is an unacknowledged service, there is no guarantee of delivery. The message consists of one M_PROTO message block followed by one or more M_DATA blocks containing at least one byte of data.
The DL_UNITDATA_IND type is used when a packet is received and is to be passed upstream. The packet is put into an M_PROTO message with the primitive set to DL_UNITDATA_IND.
The DL_PHYS_ADDR_REQ primitive requests the MAC address currently associated with the PPA attached to the Stream. The address is returned by the DL_PHYS_ADDR_ACK primitive. When using style 2, this primitive is only valid following a successful DL_ATTACH_REQ.
The DL_SET_PHYS_ADDR_REQ primitive changes the MAC address currently associated with the PPA attached to the Stream. This primitive affects all other current and future Streams attached to this device. Once changed, all Streams currently or subsequently opened and attached to this device will obtain this new physical address. The new physical address remains in effect until this primitive is used to change the physical address again or the driver is reloaded.
The superuser is allowed to change the physical address of a PPA while other Streams are bound to the same PPA.
The DL_GET_STATISTICS_REQ primitive requests a DL_GET_STATISTICS_ACK response containing statistics information associated with the PPA attached to the Stream. Style 2 Streams must be attached to a particular PPA using DL_ATTACH_REQ before this primitive can succeed.
GLD implements the ioctl ioc_cmd function described below. If GLD receives an ioctl command that it does not recognize, it passes it to the device-specific driver's gldm_ioctl() routine, as described in gld(9E).
The DLIOCRAW ioctl function is used by some DLPI applications, most notably the snoop(1M) command. The DLIOCRAW command puts the Stream into a raw mode, which causes the driver to pass full MAC-level incoming packets upstream in M_DATA messages instead of transforming them into the DL_UNITDATA_IND form that is normally used for reporting incoming packets. Packet SAP filtering is still performed on Streams that are in raw mode. If a Stream user wants to receive all incoming packets, it must also select the appropriate promiscuous mode or modes. After successfully selecting raw mode, the application is also allowed to send fully formatted packets to the driver as M_DATA messages for transmission. DLIOCRAW takes no arguments. Once enabled, the Stream remains in this mode until closed.
GLD-based drivers must include the header file <sys/gld.h>.
GLD-based drivers must also include the following declaration:
char _depends_on = "misc/gld";
GLD implements the open(9E) and close(9E) functions and the required STREAMS put(9E) and srv(9E) functions on behalf of the device-specific driver. GLD also implements the getinfo(9E) function for the driver.
The mi_idname element of the module_info(9S) structure is a string specifying the name of the driver. This must exactly match the name of the driver module as it exists in the file system.
The read-side qinit(9S) structure should specify the following elements:
The write-side qinit(9S) structure should specify these elements:
The devo_getinfo element of the dev_ops(9S) structure should specify gld_getinfo as the getinfo(9E) routine.
The driver's attach(9E) function does all the work of associating the hardware-specific device driver with the GLD facility and preparing the device and driver for use.
The attach(9E) function allocates a gld_mac_info(9S) (``macinfo'') structure using gld_mac_alloc(). The driver usually needs to save more information per device than is defined in the macinfo structure. It should allocate the additional required data structure and save a pointer to it in the gldm_private member of the gld_mac_info(9S) structure.
The attach(9E) routine must initialize the macinfo structure as described in gld_mac_info(9S) and then call gld_register() to link the driver with the GLD module. The driver should map registers if necessary and be fully initialized and prepared to accept interrupts before calling gld_register(). The attach(9E) function should add interrupts but not enable the device to generate them. The driver should reset the hardware before calling gld_register() to ensure it is quiescent. The device must not be started or put into a state where it might generate an interrupt before gld_register() is called. That will be done later when GLD calls the driver's gldm_start() entry point, described in gld(9E). After gld_register() succeeds, the gld(9E) entry points might be called by GLD at any time.
The attach(9E) routine should return DDI_SUCCESS if gld_register() succeeds. If gld_register() fails, it returns DDI_FAILURE, and the attach(9E) routine should deallocate any resources it allocated before calling gld_register() and then also return DDI_FAILURE. Under no circumstances should a failed macinfo structure be reused; it should be deallocated using gld_mac_free().
The detach(9E) function should attempt to unregister the driver from GLD. This is done by calling gld_unregister() described in gld(9F). The detach(9E) routine can get a pointer to the needed gld_mac_info(9S) structure from the device's private data using ddi_get_driver_private(9F). gld_unregister() checks certain conditions that could require that the driver not be detached. If the checks fail, gld_unregister() returns DDI_FAILURE, in which case the driver's detach(9E) routine must leave the device operational and return DDI_FAILURE.
If the checks succeed, gld_unregister() ensures that the device interrupts are stopped (calling the driver's gldm_stop() routine if necessary), unlinks the driver from the GLD framework, and returns DDI_SUCCESS. In this case, the detach(9E) routine should remove interrupts, deallocate any data structures allocated in the attach(9E) routine (using gld_mac_free() to deallocate the macinfo structure), and return DDI_SUCCESS. It is important to remove the interrupt before calling gld_mac_free().
Solaris network drivers must implement statistics variables. GLD itself tallies some network statistics, but other statistics must be counted by each GLD-based driver. GLD provides support for GLD-based drivers to report a standard set of network driver statistics. Statistics are reported by GLD using the kstat(7D) and kstat(9S) mechanisms. The DL_GET_STATISTICS_REQ DLPI command can also be used to retrieve the current statistics counters. All statistics are maintained as unsigned, and all are 32 bits unless otherwise noted.
GLD maintains and reports the following statistics.
Total bytes successfully received on the interface (64 bits).
Total bytes successfully received on the interface.
Total bytes requested to be transmitted on the interface (64 bits).
Total bytes requested to be transmitted on the interface.
Total packets successfully received on the interface (64 bits).
Total packets successfully received on the interface.
Total packets requested to be transmitted on the interface (64 bits).
Total packets requested to be transmitted on the interface.
packets successfully received, including group and functional addresses (
packets requested to be transmitted, including group and functional addresses
packets successfully received (
packets requested to be transmitted (
received packets not accepted by any Stream (
discarded on output because transmit buffer was busy, or no buffer could be
allocated for transmit (
of times a received packet could not be put up a Stream because the queue
was flow-controlled (
transmit was retried after having been delayed due to lack of resources (
Current ``promiscuous'' state of the interface (string).
The device-dependent driver counts the following statistics, keeping track of them in a private per-instance structure. When GLD is asked to report statistics, it calls the driver's gldm_get_stats() entry point, as described in gld(9E), to update the device-specific statistics in the gld_stats(9S) structure. GLD then reports the updated statistics using the named statistics variables shown below.
Current estimated bandwidth of the interface in bits per second (64 bits).
Current media type in use by the device (string).
handler was called and claimed the interrupt (
of times a valid incoming packet was known to have been discarded because
no buffer could be allocated for receive (
packets received that could not be processed because they contained errors
packets that were not successfully transmitted because of errors (
known to have been dropped by the hardware on receive (
underflowed on transmit (
overflowed during receive (
The following group of statistics applies to networks of type DL_ETHER. These statistics are maintained by device-specific drivers of that type, as shown previously.
Packets received with framing
errors (not an integral number of octets) (
Packets received with CRC errors (
Current duplex mode of the interface (string).
Number of times carrier was lost or never detected on a transmission attempt
Ethernet collisions during transmit (
Frames where excess collisions occurred on transmit, causing transmit failure
Number of times a transmit collision occurred late (after 512 bit times)
Packets without collisions where first transmit attempt was delayed because
the medium was busy (
Packets successfully transmitted with exactly one collision.
Packets successfully transmitted with multiple collisions.
Number of times SQE test error was reported.
Packets encountering transmit MAC failures, except carrier and collision failures.
Packets received with MAC errors, except align_errors, fcs_errors, and toolong_errors.
Packets received larger than the maximum permitted length.
Packets received smaller than the minimum permitted length (
The following group of statistics applies to networks of type DL_TPR; these are maintained by device-specific drivers of that type, as shown above.
Packets received with non-data bits or FCS errors.
Number of times an absence of transitions for five half-bit timers was detected.
Number of times loss of signal condition on the ring was detected.
Number of times an AMP or SMP frame, in which A is equal to C is equal to 0, was followed by another such SMP frame without an intervening AMP frame.
Number of times the station recognized an internal error.
Number of times the TRR timer expired during transmit.
Number of times a frame addressed to this station was received with the FS field `A' bit set to 1.
Number of times the station acting as the active monitor recognized an error condition that needed a token transmitted.
Number of times the frequency of the incoming signal differed from the expected frequency.
The following group of statistics applies to networks of type DL_FDDI; these are maintained by device-specific drivers of that type, as shown above.
Frames detected in error by this MAC that had not been detected in error by another MAC.
Frames received with format errors such that the frame was stripped.
Number of tokens received (total of non-restricted and restricted).
Number of times that TVX has expired.
Number of TRT expirations since this MAC was reset or a token was received.
Number of times the ring has entered the ``Ring Operational'' state from the ``Ring Not Operational'' state.
The GLD MAC information (gld_mac_info) structure is the main data interface between the device-specific driver and GLD. It contains data required by GLD and a pointer to an optional additional driver-specific information structure.
Allocate the gld_mac_info structure using gld_mac_alloc() and deallocate it using gld_mac_free(). Drivers must not make any assumptions about the length of this structure, which might vary in different releases of Solaris, GLD, or both. Structure members private to GLD, not documented here, should not be set or read by the device-specific driver.
The gld_mac_info(9S) structure contains the following fields.
caddr_t gldm_private; /* Driver private data */ int (*gldm_reset)(); /* Reset device */ int (*gldm_start)(); /* Start device */ int (*gldm_stop)(); /* Stop device */ int (*gldm_set_mac_addr)(); /* Set device phys addr */ int (*gldm_set_multicast)(); /* Set/delete multicast addr */ int (*gldm_set_promiscuous)(); /* Set/reset promiscuous mode */ int (*gldm_send)(); /* Transmit routine */ uint_t (*gldm_intr)(); /* Interrupt handler */ int (*gldm_get_stats)(); /* Get device statistics */ int (*gldm_ioctl)(); /* Driver-specific ioctls */ char *gldm_ident; /* Driver identity string */ uint32_t gldm_type; /* Device type */ uint32_t gldm_minpkt; /* Minimum packet size */ /* accepted by driver */ uint32_t gldm_maxpkt; /* Maximum packet size */ /* accepted by driver */ uint32_t gldm_addrlen; /* Physical address length */ int32_t gldm_saplen; /* SAP length for DL_INFO_ACK */ unsigned char *gldm_broadcast_addr; /* Physical broadcast addr */ unsigned char *gldm_vendor_addr; /* Factory MAC address */ t_uscalar_t gldm_ppa; /* Physical Point of */ /* Attachment (PPA) number */ dev_info_t *gldm_devinfo; /* Pointer to device's */ /* dev_info node */ ddi_iblock_cookie_t gldm_cookie; /* Device's interrupt */ /* block cookie */
These members of the gld_mac_info structure are visible to the device driver.
This structure member is private to the device-specific driver and is not used or modified by GLD. Conventionally this is used as a pointer to private data, pointing to a driver-defined and driver-allocated per-instance data structure.
The following group of structure members must be set by the driver before calling gld_register(), and should not thereafter be modified by the driver. Because gld_register() might use or cache the values of some of these structure members, changes made by the driver after calling gld_register() might cause unpredictable results.
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; see gld(9E).
Pointer to driver entry point; is allowed to be NULL; see gld(9E).
Pointer to a string containing a short description of the device. It is used to identify the device in system messages.
Type of device the driver handles. The values currently supported by GLD are DL_ETHER (ISO 8802-3 (IEEE 802.3) and Ethernet Bus), DL_TPR (IEEE 802.5 Token Passing Ring), and DL_FDDI (ISO 9314-2 Fibre Distributed Data Interface). This structure member must be correctly set for GLD to function properly.
Minimum Service Data Unit size—the minimum packet size, not including the MAC header, that the device will transmit. This size is allowed to be zero if the device-specific driver handles any required padding.
Maximum Service Data Unit size — the maximum size of packet, not including the MAC header, that can be transmitted by the device. For Ethernet, this number is 1500.
The length in bytes of physical addresses handled by the device. For Ethernet, Token Ring, and FDDI, the value of this structure member should be 6.
The length in bytes of the SAP address used by the driver. For GLD-based drivers, this should always be set to -2, to indicate that 2-byte SAP values are supported and that the SAP appears after the physical address in a DLSAP address. See ``Message DL_INFO_ACK'' in the DLPI specification for more details.
Pointer to an array of bytes of length gldm_addrlen containing the broadcast address to be used for transmit. The driver must provide space to hold the broadcast address, fill it in with the appropriate value, and set gldm_broadcast_addr to point to it. For Ethernet, Token Ring, and FDDI, the broadcast address is normally 0xFF-FF-FF-FF-FF-FF.
Pointer to an array of bytes of length gldm_addrlen containing the vendor-provided network physical address of the device. The driver must provide space to hold the address, fill it in with information read from the device, and set gldm_vendor_addr to point to it.
PPA number for this instance of the device. Normally this should be set to the instance number, returned from ddi_get_instance(9F).
Pointer to the dev_info node for this device.
Interrupt block cookie returned by ddi_get_iblock_cookie(9F), ddi_add_intr(9F), ddi_get_soft_iblock_cookie(9F), or ddi_add_softintr(9F). This must correspond to the device's receive-interrupt, from which gld_recv() is called.
The GLD statistics (gld_stats) structure is used to communicate statistics and state information from a GLD-based driver to GLD when returning from a driver's gldm_get_stats() routine, as discussed in gld(9E) and gld(7D). The members of this structure, filled in by the GLD-based driver, are used when GLD reports the statistics. In the tables below, the name of the statistics variable reported by GLD is noted in the comments. See gld(7D) for a more detailed description of the meaning of each statistic.
Drivers must not make any assumptions about the length of this structure, which might vary in different releases of Solaris, GLD, or both. Structure members private to GLD, not documented here, should not be set or read by the device-specific driver.
The following structure members are defined for all media types:
uint64_t glds_speed; /* ifspeed */ uint32_t glds_media; /* media */ uint32_t glds_intr; /* intr */ uint32_t glds_norcvbuf; /* norcvbuf */ uint32_t glds_errrcv; /* ierrors */ uint32_t glds_errxmt; /* oerrors */ uint32_t glds_missed; /* missed */ uint32_t glds_underflow; /* uflo */ uint32_t glds_overflow; /* oflo */
The following structure members are defined for media type DL_ETHER:
uint32_t glds_frame; /* align_errors */ uint32_t glds_crc; /* fcs_errors */ uint32_t glds_duplex; /* duplex */ uint32_t glds_nocarrier; /* carrier_errors */ uint32_t glds_collisions; /* collisions */ uint32_t glds_excoll; /* ex_collisions */ uint32_t glds_xmtlatecoll; /* tx_late_collisions */ uint32_t glds_defer; /* defer_xmts */ uint32_t glds_dot3_first_coll; /* first_collisions */ uint32_t glds_dot3_multi_coll; /* multi_collisions */ uint32_t glds_dot3_sqe_error; /* sqe_errors */ uint32_t glds_dot3_mac_xmt_error; /* macxmt_errors */ uint32_t glds_dot3_mac_rcv_error; /* macrcv_errors */ uint32_t glds_dot3_frame_too_long; /* toolong_errors */ uint32_t glds_short; /* runt_errors */
The following structure members are defined for media type DL_TPR:
uint32_t glds_dot5_line_error /* line_errors */ uint32_t glds_dot5_burst_error /* burst_errors */ uint32_t glds_dot5_signal_loss /* signal_losses */ uint32_t glds_dot5_ace_error /* ace_errors */ uint32_t glds_dot5_internal_error /* internal_errors */ uint32_t glds_dot5_lost_frame_error /* lost_frame_errors */ uint32_t glds_dot5_frame_copied_error /* frame_copied_errors */ uint32_t glds_dot5_token_error /* token_errors */ uint32_t glds_dot5_freq_error /* freq_errors */
The following structure members are defined for media type DL_FDDI:
uint32_t glds_fddi_mac_error; /* mac_errors */ uint32_t glds_fddi_mac_lost; /* mac_lost_errors */ uint32_t glds_fddi_mac_token; /* mac_tokens */ uint32_t glds_fddi_mac_tvx_expired; /* mac_tvx_expired */ uint32_t glds_fddi_mac_late; /* mac_late */ uint32_t glds_fddi_mac_ring_op; /* mac_ring_ops */
Most of the above statistics variables are counters denoting the number of times the particular event was observed. Exceptions are:
Estimate of the interface's current bandwidth in bits per second. For interfaces that do not vary in bandwidth or for those where no accurate estimation can be made, this object should contain the nominal bandwidth.
Type of media (wiring) or connector used by the hardware. Currently supported media names include GLDM_AUI, GLDM_BNC, GLDM_TP, GLDM_10BT, GLDM_100BT, GLDM_100BTX, GLDM_100BT4, GLDM_RING4, GLDM_RING16, GLDM_FIBER, and GLDM_PHYMII. GLDM_UNKNOWN is also permitted.
Current duplex state of the interface. Supported values are GLD_DUPLEX_HALF and GLD_DUPLEX_FULL. GLD_DUPLEX_UNKNOWN is also permitted.
Pointer to a gld_mac_info(9S) structure.
Pointer to the beginning of a character array containing a valid MAC address. The array will be of the length specified by the driver in the gldm_addrlen element of the gld_mac_info(9S) structure.
Pointer to the beginning of a character array containing a multicast, group, or functional address. The array will be of the length specified by the driver in the gldm_addrlen element of the gld_mac_info(9S) structure.
Flag indicating whether reception of the multicast address is to be enabled or disabled. This argument is specified as GLD_MULTI_ENABLE or GLD_MULTI_DISABLE.
Flag indicating what type of promiscuous mode, if any, is to be enabled. This argument is specified as GLD_MAC_PROMISC_PHYS, GLD_MAC_PROMISC_MULTI, or GLD_MAC_PROMISC_NONE.
gld_ioctl() uses mp as a pointer to a STREAMS message block containing the ioctl to be executed. gld_send() uses it as a pointer to a STREAMS message block containing the packet to be transmitted. gld_recv() uses it as a pointer to a message block containing a received packet.
Pointer to a gld_stats(9S) structure to be filled in with the current values of statistics counters.
Pointer to the queue(9S) structure to be used in the reply to the ioctl.
Pointer to the device's dev_info structure.
Device interface name.
These entry points must be implemented by a device-specific network driver designed to interface with GLD.
As described in gld(7D), the main data structure for communication between the device-specific driver and the GLD module is the gld_mac_info(9S) structure. Some of the elements in that structure are function pointers to the entry points described here. The device-specific driver must, in its attach(9E) routine, initialize these function pointers before calling gld_register().
gldm_reset() resets the hardware to its initial state.
gldm_start() enables the device to generate interrupts and prepares the driver to call gld_recv() for delivering received data packets to GLD.
gldm_stop() disables the device from generating any interrupts and stops the driver from calling gld_recv() for delivering data packets to GLD. GLD depends on the gldm_stop() routine to ensure that the device will no longer interrupt, and it must do so without fail. This function should always return GLD_SUCCESS.
unsigned char *macaddr);
gldm_set_mac_addr() sets the physical address that the hardware is to use for receiving data. This function should program the device to the passed MAC address macaddr. If sufficient resources are currently not available to carry out the request, return GLD_NORESOURCES. Return GLD_NOTSUPPORTED to indicate that the requested function is not supported.
unsigned char *multicastaddr,
gldm_set_multicast() enables and disables device-level reception of specific multicast addresses. If the third argument multiflag is set to GLD_MULTI_ENABLE, then the function sets the interface to receive packets with the multicast address pointed to by the second argument. If multiflag is set to GLD_MULTI_DISABLE, the driver is allowed to disable reception of the specified multicast address.
This function is called whenever GLD wants to enable or disable reception of a multicast, group, or functional address. GLD makes no assumptions about how the device does multicast support and calls this function to enable or disable a specific multicast address. Some devices might use a hash algorithm and a bitmask to enable collections of multicast addresses; this procedure is allowed, and GLD filters out any superfluous packets. If disabling an address could result in disabling more than one address at the device level, it is the responsibility of the device driver to keep whatever information it needs in order to avoid disabling an address that GLD has enabled but not disabled.
gldm_set_multicast() will not be called to enable a particular multicast address that is already enabled, nor will it be called to disable an address that is not currently enabled. GLD keeps track of multiple requests for the same multicast address and only calls the driver's entry point when the first request to enable, or the last request to disable, a particular multicast address is made. If sufficient resources are currently not available to carry out the request, return GLD_NORESOURCES. Return GLD_NOTSUPPORTED to indicate that the requested function is not supported.
gldm_set_promiscuous() enables and disables promiscuous mode. This function is called whenever GLD wants to enable or disable the reception of all packets on the medium, or of all multicast packets on the medium. If the second argument promiscflag is set to the value of GLD_MAC_PROMISC_PHYS, then the function enables physical-level promiscuous mode, resulting in the reception of all packets on the medium. If promiscflag is set to GLD_MAC_PROMISC_MULTI, then reception of all multicast packets will be enabled. If promiscflag is set to GLD_MAC_PROMISC_NONE, then promiscuous mode is disabled.
In the case of a request for promiscuous multicast mode, drivers for devices that have no multicast-only promiscuous mode must set the device to physical promiscuous mode to ensure that all multicast packets are received. In this case the routine should return GLD_SUCCESS. The GLD software filters out any superfluous packets. If sufficient resources are currently not available to carry out the request, return GLD_NORESOURCES. Return GLD_NOTSUPPORTED to indicate that the requested function is not supported.
For forward compatibility, gldm_set_promiscuous() routines should treat any unrecognized values for promiscflag as though they were GLD_MAC_PROMISC_PHYS.
gldm_send() queues a packet to the device for transmission. This routine is passed a STREAMS message containing the packet to be sent. The message might include multiple message blocks, and the send routine must traverse all the message blocks in the message to access the entire packet to be sent. The driver should be prepared to handle and skip over any zero-length message continuation blocks in the chain. The driver should check that the packet does not exceed the maximum allowable packet size, and it must pad the packet, if necessary, to the minimum allowable packet size. If the send routine successfully transmits or queues the packet, it should return GLD_SUCCESS.
The send routine should return GLD_NORESOURCES if it cannot immediately accept the packet for transmission; in this case GLD will retry it later. If gldm_send() ever returns GLD_NORESOURCES, the driver must, at a later time when resources have become available, call gld_sched(). This call to gld_sched() informs GLD that it should retry packets that the driver previously failed to queue for transmission. (If the driver's gldm_stop() routine is called, the driver is absolved from this obligation until it later again returns GLD_NORESOURCES from its gldm_send() routine. However, extra calls to gld_sched() will not cause incorrect operation.)
If the driver's send routine returns GLD_SUCCESS, then the driver is responsible for freeing the message when the driver and the hardware no longer need it. If the send routine copied the message into the device, or into a private buffer, then the send routine is permitted to free the message after the copy is made. If the hardware uses DMA to read the data directly out of the message data blocks, then the driver must not free the message until the hardware has completed reading the data. In this case the driver will probably free the message in the interrupt routine, or in a buffer reclaim operation at the beginning of a future send operation. If the send routine returns anything other than GLD_SUCCESS, then the driver must not free the message. Return GLD_NOLINK if gldm_send() is called when there is no physical connection to the network or link partner.
gldm_intr() is called when the device might have interrupted. Because it is possible to share interrupts with other devices, the driver must check the device status to determine whether it actually caused an interrupt. If the device that the driver controls did not cause the interrupt, then this routine must return DDI_INTR_UNCLAIMED. Otherwise, it must service the interrupt and should return DDI_INTR_CLAIMED. If the interrupt was caused by successful receipt of a packet, this routine should put the received packet into a STREAMS message of type M_DATA and pass that message to gld_recv().
gld_recv() will pass the inbound packet upstream to the appropriate next layer of the network protocol stack. It is important to correctly set the b_rptr and b_wptr members of the STREAMS message before calling gld_recv().
The driver should avoid holding mutex or other locks during the call to gld_recv(). In particular, locks that could be taken by a transmit thread must not be held during a call to gld_recv(): the interrupt thread that calls gld_recv() will in some cases carry out processing that includes sending an outgoing packet, resulting in a call to the driver's gldm_send() routine. If the gldm_send() routine were to try to acquire a mutex being held by the gldm_intr() routine at the time it calls gld_recv(), this would result in a panic due to recursive mutex entry. If other driver entry points attempt to acquire a mutex that the driver holds across a call to gld_recv(), deadlock can result.
The interrupt code should increment statistics counters for any errors. This includes failure to allocate a buffer needed for the received data and any hardware-specific errors, such as CRC errors or framing errors.
struct gld_stats *stats);
gldm_get_stats() gathers statistics from the hardware, driver private counters, or both, and updates the gld_stats(9S) structure pointed to by stats. This routine is called by GLD when it gets a request for statistics, and provides the mechanism by which GLD acquires device-dependent statistics from the driver before composing its reply to the statistics request. See gld_stats(9S) and gld(7D) for a description of the defined statistics counters.
gldm_ioctl() implements any device-specific ioctl commands. This element is allowed to be NULL if the driver does not implement any ioctl functions. The driver is responsible for converting the message block into an ioctl reply message and calling the qreply(9F) function before returning GLD_SUCCESS. This function should always return GLD_SUCCESS; any errors the driver might want to report should be returned by the message passed to qreply(9F). If the gldm_ioctl element is specified as NULL, GLD returns a message of type M_IOCNAK with an error of EINVAL.
In addition to the return values described above, and subject to the restrictions above, it is permitted for some of the GLD entry point functions to return these values:
If the function detected an unsuitable argument, for example, a bad multicast address, a bad MAC address, or a bad packet or packet length
On hardware failure
gld_mac_alloc() allocates a new gld_mac_info(9S) structure and returns a pointer to it. Some of the GLD-private elements of the structure might be initialized before gld_mac_alloc() returns; all other elements are initialized to zero. The device driver must initialize some structure members, as described in gld_mac_info(9S), before passing the pointer to the mac_info structure to gld_register().
gld_mac_free() frees a gld_mac_info(9S) structure previously allocated by gld_mac_alloc().
gld_register() is called from the device driver's attach(9E) routine and is used to link the GLD-based device driver with the GLD framework. Before calling gld_register(), the device driver's attach(9E) routine must first use gld_mac_alloc() to allocate a gld_mac_info(9S) structure, and initialize several of its structure elements. See gld_mac_info(9S) for more information. A successful call to gld_register() performs the following actions:
Links the device-specific driver with the GLD system
Sets the device-specific driver's private data pointer (using ddi_set_driver_private(9F)) to point to the macinfo structure
Creates the minor device node
The device interface name passed to gld_register() must exactly match the name of the driver module as it exists in the file system.
The driver's attach(9E) routine should return DDI_SUCCESS if gld_register() succeeds. If gld_register() does not return DDI_SUCCESS, the attach(9E) routine should deallocate any resources it allocated before calling gld_register(), and then return DDI_FAILURE.
gld_unregister() is called by the device driver's detach(9E) function, and if successful, performs the following tasks:
Ensures that the device's interrupts are stopped, calling the driver's gldm_stop() routine if necessary
Removes the minor device node
Unlinks the device-specific driver from the GLD system
If gld_unregister() returns DDI_SUCCESS, the detach(9E) routine should deallocate any data structures allocated in the attach(9E) routine, using gld_mac_free() to deallocate the macinfo structure, and return DDI_SUCCESS. If gld_unregister() does not return DDI_SUCCESS, the driver's detach(9E) routine must leave the device operational and return DDI_FAILURE.
gld_recv() is called by the driver's interrupt handler to pass a received packet upstream. The driver must construct and pass a STREAMS M_DATA message containing the raw packet. gld_recv() determines which STREAMS queues, if any, should receive a copy of the packet, duplicating it if necessary. It then formats a DL_UNITDATA_IND message, if required, and passes the data up all appropriate Streams.
The driver should avoid holding mutex or other locks during the call to gld_recv(). In particular, locks that could be taken by a transmit thread must not be held during a call to gld_recv(): the interrupt thread that calls gld_recv() will in some cases carry out processing that includes sending an outgoing packet, resulting in a call to the driver's gldm_send() routine. If the gldm_send() routine were to try to acquire a mutex being held by the gldm_intr() routine at the time it calls gld_recv(), this would result in a panic caused by a recursive mutex entry. If other driver entry points attempt to acquire a mutex that the driver holds across a call to gld_recv(), deadlock can result.
gld_sched() is called by the device driver to reschedule stalled outbound packets. Whenever the driver's gldm_send() routine has returned GLD_NORESOURCES, the driver must later call gld_sched() to inform the GLD framework that it should retry the packets that previously could not be sent. gld_sched() should be called as soon as possible after resources are again available, to ensure that GLD resumes passing outbound packets to the driver's gldm_send() routine in a timely way. (If the driver's gldm_stop() routine is called, the driver is absolved from this obligation until it later again returns GLD_NORESOURCES from its gldm_send() routine; however, extra calls to gld_sched() will not cause incorrect operation.)
gld_intr() is GLD's main interrupt handler. Normally, gld_intr() is specified as the interrupt routine in the device driver's call to ddi_add_intr(9F). The argument to the interrupt handler (specified as int_handler_arg in the call to ddi_add_intr(9F)) must be a pointer to the gld_mac_info(9S) structure. gld_intr() will, when appropriate, call the device driver's gldm_intr() function, passing that pointer to the gld_mac_info(9S) structure. However, if the driver uses a high-level interrupt, it must provide its own high-level interrupt handler and trigger a soft interrupt from within that. In this case, gld_intr() would normally be specified as the soft interrupt handler in the call to ddi_add_softintr(). gld_intr() will return a value appropriate for an interrupt handler.