if_dc panics with 3Com OfficeConnect 10/100B PCI

Giorgos Keramidas keramida at ceid.upatras.gr
Mon Sep 12 19:55:38 PDT 2005


On 2005-08-22 00:56, Giorgos Keramidas <keramida at freebsd.org> wrote:
> On 2005-08-16 13:48, John Baldwin <jhb at FreeBSD.org> wrote:
> >
> > Compile in DDB and get a stack trace over the serial console using 't' in DDB
> > instead of worrying about getting a dump.
>
> [...]
> I have no way to debug the crash now, since I only have one machine at
> home.  When I get the chance I plan to test this again, and I'll report
> back then, if this is still a problem.

I think I've finally located the cause of this panic.  The panic happens
early in dc_attach(), and the last message I see is the one printed by
dc_attach() in src/sys/pci/if_dc.c:

% 	if (sc->dc_res == NULL) {
% 		device_printf(dev, "couldn't map ports/memory\n");
% 		error = ENXIO;
% 		goto fail;
% 	}
%
% 	[ various busdma setup calls ]
%
% fail:
% 	if (error)
% 		dc_detach(dev);
% 	return (error);

The bug of dc_detach() that causes the panic is that it doesn't check if
one of the busdma tags and some maps it destroys have been allocated.  In
this case, because dc_attach() fails too early, before any busdma calls,
they haven't been allocated and one of the busdma calls panics when it gets
a NULL pointer.

The following patch fixes the panic of loading if_dc.ko when the 3Com
NIC of the subject is installed:

%%%
Index: if_dc.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dc.c,v
retrieving revision 1.166
diff -u -r1.166 if_dc.c
--- if_dc.c	29 Aug 2005 18:45:21 -0000	1.166
+++ if_dc.c	13 Sep 2005 00:32:51 -0000
@@ -2364,11 +2364,17 @@
 		bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf, sc->dc_smap);
 	if (sc->dc_ldata != NULL)
 		bus_dmamem_free(sc->dc_ltag, sc->dc_ldata, sc->dc_lmap);
-	for (i = 0; i < DC_TX_LIST_CNT; i++)
-		bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_tx_map[i]);
-	for (i = 0; i < DC_RX_LIST_CNT; i++)
-		bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]);
-	bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap);
+	if (sc->dc_mtag) {
+		for (i = 0; i < DC_TX_LIST_CNT; i++)
+			if (sc->dc_cdata.dc_tx_map[i] != NULL)
+				bus_dmamap_destroy(sc->dc_mtag,
+				    sc->dc_cdata.dc_tx_map[i]);
+		for (i = 0; i < DC_RX_LIST_CNT; i++)
+			if (sc->dc_cdata.dc_rx_map[i] != NULL)
+				bus_dmamap_destroy(sc->dc_mtag,
+				    sc->dc_cdata.dc_rx_map[i]);
+		bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap);
+	}
 	if (sc->dc_stag)
 		bus_dma_tag_destroy(sc->dc_stag);
 	if (sc->dc_mtag)
%%%

With this patch, on CURRENT of Sep-12-2005, the attach of the NIC in
question still fails, but at least it doesn't panic the system while
doing so :)

P.S.: Is there any way to guard against similar bugs in other drivers
and/or bugs that may be introduced later on?  For instance, would adding
KASSERT() macros in busdma_machdep.c slow things down too much?


More information about the freebsd-current mailing list