Subject: kern/3574: if_ie malfunctions on 3Com cards if more than one configured
To: None <gnats-bugs@gnats.netbsd.org>
From: None <rkboni@concentric.net>
List: netbsd-bugs
Date: 05/04/1997 23:10:29
>Number:         3574
>Category:       kern
>Synopsis:       with both ie0 and ie1 in kern config, 3C507 cards break
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun May  4 20:20:01 1997
>Last-Modified:
>Originator:     Rafal Boni
>Organization:
	Huh?  Whazzat?
>Release:        April 20'th, 1997, but is present in all newer verions
>Environment:

System: NetBSD doppelganger 1.2D NetBSD 1.2D (DOPPELGANGER) #0: Sun May 4 17:32:40 EDT 1997 rafal@doppelganger:/usr/NetBSD/src/sys/arch/i386/compile/DOPPELGANGER i386

	ISA i486 machine with one or more 3C507 cards.

>Description:
	The 3C507, like the 3c509, needs a Magick Sequence of bits to be sent
	to a Magick Port to enable all cards on a bus.  The driver is not 
	careful about only doing so once per bus, hence setting cards that 
	have already been initialized back into unconfigured states.

>How-To-Repeat:

	Build kernel with both ie0 and ie1, boot on a ISA-bus machine with
	a 3C507 on the bus.  Watch kernel freeze during/after autoconf.

>Fix:

	This code is stolen almost directly from the if_ep ISA frontend.

Index: if_ie.c
===================================================================
RCS file: /cvs/root/netbsd/src/sys/dev/isa/if_ie.c,v
retrieving revision 1.1.1.1
diff -c -2 -r1.1.1.1 if_ie.c
*** if_ie.c	1997/04/19 21:32:45	1.1.1.1
--- if_ie.c	1997/05/05 02:27:23
***************
*** 223,226 ****
--- 223,241 ----
  
  /*
+  * This keeps track of which ISAs have been through an ie probe sequence.
+  * A simple static variable isn't enough, since it's conceivable that
+  * a system might have more than one ISA bus.
+  *
+  * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0"
+  * for "isa0".
+  */
+ struct ie_isa_done_probe {
+ 	LIST_ENTRY(ie_isa_done_probe)	er_link;
+ 	int				er_bus;
+ };
+ static LIST_HEAD(, ie_isa_done_probe) ie_isa_all_probes;
+ static int ie_isa_probes_initialized;
+ 
+ /*
   * Ethernet status, per interface.
   */
***************
*** 314,318 ****
  void	ieattach __P((struct device *, struct device *, void *));
  int	sl_probe __P((struct ie_softc *, struct isa_attach_args *));
! int	el_probe __P((struct ie_softc *, struct isa_attach_args *));
  int	ee16_probe __P((struct ie_softc *, struct isa_attach_args *));
  int	check_ie_present __P((struct ie_softc *, caddr_t, u_int));
--- 329,333 ----
  void	ieattach __P((struct device *, struct device *, void *));
  int	sl_probe __P((struct ie_softc *, struct isa_attach_args *));
! int	el_probe __P((struct ie_softc *, struct isa_attach_args *, int));
  int	ee16_probe __P((struct ie_softc *, struct isa_attach_args *));
  int	check_ie_present __P((struct ie_softc *, caddr_t, u_int));
***************
*** 389,396 ****
  	struct ie_softc *sc = match;
  	struct isa_attach_args *ia = aux;
  
  	if (sl_probe(sc, ia))
  		return 1;
! 	if (el_probe(sc, ia))
  		return 1;
  	if (ee16_probe(sc, ia))
--- 404,439 ----
  	struct ie_softc *sc = match;
  	struct isa_attach_args *ia = aux;
+ 	int bus = parent->dv_unit;
+ 	struct ie_isa_done_probe *er;
+         int bus_probed = 0;
+ 
+ 	if (ie_isa_probes_initialized == 0) {
+ 		LIST_INIT(&ie_isa_all_probes);
+ 		ie_isa_probes_initialized = 1;
+ 	}
+ 
+ 	/*
+ 	 * Check if we're already probed this bus, for the benefit of the
+          * 3Com cards.
+ 	 */
+ 	for (er = ie_isa_all_probes.lh_first; er != NULL;
+ 	    er = er->er_link.le_next)
+ 		if (er->er_bus == parent->dv_unit)
+ 			bus_probed = 1;
+ 
+ 	/*
+ 	 * Mark this bus so we know if we've probed it next time through
+ 	 */
+ 	er = (struct ie_isa_done_probe *)
+ 	    malloc(sizeof(struct ie_isa_done_probe), M_DEVBUF, M_NOWAIT);
+ 	if (er == NULL)
+ 		panic("ie_probe: can't allocate state storage");
+ 
+ 	er->er_bus = bus;
+ 	LIST_INSERT_HEAD(&ie_isa_all_probes, er, er_link);
  
  	if (sl_probe(sc, ia))
  		return 1;
! 	if (el_probe(sc, ia, bus_probed))
  		return 1;
  	if (ee16_probe(sc, ia))
***************
*** 467,473 ****
  
  int
! el_probe(sc, ia)
  	struct ie_softc *sc;
  	struct isa_attach_args *ia;
  {
  	bus_space_tag_t iot = ia->ia_iot;
--- 510,517 ----
  
  int
! el_probe(sc, ia, bus_probed)
  	struct ie_softc *sc;
  	struct isa_attach_args *ia;
+ 	int bus_probed;
  {
  	bus_space_tag_t iot = ia->ia_iot;
***************
*** 483,502 ****
  	sc->chan_attn = el_chan_attn;
  
! 	/*
! 	 * Map the Etherlink ID port for the probe sequence.
! 	 */
! 	if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
! 		printf("3c507 probe: can't map Etherlink ID port\n");
! 		return 0;
! 	}
  
! 	/*
! 	 * Reset and put card in CONFIG state without changing address.
! 	 * XXX Indirect brokenness here!
! 	 */
! 	elink_reset(iot, ioh, sc->sc_dev.dv_parent->dv_unit);
! 	elink_idseq(iot, ioh, ELINK_507_POLY);
! 	elink_idseq(iot, ioh, ELINK_507_POLY);
! 	outb(ELINK_ID_PORT, 0xff);
  
  	/* Check for 3COM signature before proceeding. */
--- 527,548 ----
  	sc->chan_attn = el_chan_attn;
  
!         if (!bus_probed) {
! 		/*
! 		 * Map the Etherlink ID port for the probe sequence.
! 		 */
! 		if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
! 			printf("3c507 probe: can't map Etherlink ID port\n");
! 			return 0;
! 		}
  
! 		/*
! 		 * Reset and put card in CONFIG state without changing address.
! 		 * XXX Indirect brokenness here!
! 		 */
! 		elink_reset(iot, ioh, sc->sc_dev.dv_parent->dv_unit);
! 		elink_idseq(iot, ioh, ELINK_507_POLY);
! 		elink_idseq(iot, ioh, ELINK_507_POLY);
! 		outb(ELINK_ID_PORT, 0xff);
! 	}
  
  	/* Check for 3COM signature before proceeding. */
***************
*** 514,520 ****
  
  	/* Go to RUN state. */
! 	outb(ELINK_ID_PORT, 0x00);
! 	elink_idseq(iot, ioh, ELINK_507_POLY);
! 	outb(ELINK_ID_PORT, 0x00);
  
  	/* Set bank 2 for version info and read BCD version byte. */
--- 560,568 ----
  
  	/* Go to RUN state. */
! 	if (!bus_probed) {
! 		outb(ELINK_ID_PORT, 0x00);
! 		elink_idseq(iot, ioh, ELINK_507_POLY);
! 		outb(ELINK_ID_PORT, 0x00);
! 	}
  
  	/* Set bank 2 for version info and read BCD version byte. */
***************
*** 579,583 ****
  
   out:
! 	bus_space_unmap(iot, ioh, 1);
  	return rval;
  }
--- 627,632 ----
  
   out:
! 	if (!bus_probed)
! 	    bus_space_unmap(iot, ioh, 1);
  	return rval;
  }
>Audit-Trail:
>Unformatted: