kern/100425: sbni drivers does not work under 5.x

Rashid N. Achilov shelton at granch.ru
Mon Jul 17 08:00:46 UTC 2006


>Number:         100425
>Category:       kern
>Synopsis:       sbni drivers does not work under 5.x
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jul 17 08:00:34 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Rashid N. Achilov
>Release:        FreeBSD 5.5-PRERELEASE i386
>Organization:
>Environment:
System: FreeBSD www.granch.ru 5.5-PRERELEASE FreeBSD 5.5-PRERELEASE #2: Thu May 18 19:26:36 NOVST 2006 shelton at www.granch.ru:/usr/obj/usr/src/sys/Proxy i386
>Description:
Driver for device sbni does not work correctly under 5.4 and high. When connect between
two devices established (with any OS - FreeBSD, linux, Windows), all incoming packets
qualified as 'bad' and drop down. So, data exchange is impossible. A trouble source is
a calc_crc32 procedure, which was sometime written by ASM insertions. GCC 3.x produced
code, which calcs CRC incorrectly, so calc_crc32 decline ALL incoming packets. A sbni
driver has also (still unusable) C-sourced calc_crc32 procedure. When I have switched
to use it, driver start to work.
>How-To-Repeat:
Install a couple sbni devices at a couple boxes, one side with FreeBSD 5.x, two with
any other supported system. Install sbni device into a kernel or load kernel module.
Install sbniconfig utility. Connect devices. You can see in a sbniconfig output, that
"rx" will increased, and "bad rx" will increased too and all received packets will
'bad'.
>Fix:
Go to /usr/src/sys and appy this patch
--- modules/sbni/Makefile	Thu Nov 22 04:29:35 2001
+++ Makefile.new	Mon Jul 17 14:10:21 2006
@@ -7,4 +7,7 @@

 SRCS+=	bus_if.h device_if.h isa_if.h pci_if.h

+# To build with lost of debug messages, uncomment here
+#CFLAGS += -DDEBUG
+
 .include <bsd.kmod.mk>
--- dev/sbni/if_sbni.c	Sun Jan 30 07:00:01 2005
+++ if_sbni.c.new	Fri Jul 14 12:35:47 2006
@@ -57,6 +57,9 @@
  * Revision 4.1 2001/01/21
  * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
  *
+ * Revision 4.2 2006/07/12 by Rashid N. "CityCat" Achilov
+ * Incorrect checksum calculation under 5.x eliminated
+ *
  * Written with reference to NE2000 driver developed by David Greenman.
  */

@@ -84,7 +87,12 @@
 #include <dev/sbni/if_sbnireg.h>
 #include <dev/sbni/if_sbnivar.h>

+/* In 5.x ASM source for CRC caclulations produced incorrect CRC check */
+#if __FreeBSD_version < 500000
 #define ASM_CRC 1
+#else
+#undef ASM_CRC
+#endif

 static void	sbni_init(void *);
 static void	sbni_start(struct ifnet *);
@@ -374,7 +382,7 @@
 		 */
 		csr0 = sbni_inb(sc, CSR0);
 		if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
-			printf("sbni: internal error!\n");
+		  printf("sbni: incorrect state, TR not ready, but RC ready\n");

 		/* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
 		if (req_ans || sc->tx_frameno != 0)
@@ -406,21 +414,41 @@
 		frame_ok = framelen > 4 ?
 		    upload_data(sc, framelen, frameno, is_first, crc) :
 		    skip_tail(sc, framelen, crc);
+#ifdef DEBUG
+		printf("[RF]header OK, frame_ok=%d, framelen=%d\n",frame_ok,framelen);
+#endif
 		if (frame_ok)
 			interpret_ack(sc, ack);
 	} else
+            {
+#ifdef DEBUG
+              printf("[RF]Header BAD!\n");
+#endif
 		frame_ok = 0;
+            }

 	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
 	if (frame_ok) {
+#ifdef DEBUG
+                printf("[RF]Good: frame_ok=%d,framelen=%d\n",frame_ok,framelen);
+#endif
 		sc->state |= FL_PREV_OK;
 		if (framelen > 4)
+                  {
 			sc->in_stats.all_rx_number++;
+#ifdef DEBUG
+                    printf("[RF]Good: received: %d\n",sc->in_stats.all_rx_number);
+#endif
+                  }
 	} else {
 		sc->state &= ~FL_PREV_OK;
 		change_level(sc);
 		sc->in_stats.all_rx_number++;
 		sc->in_stats.bad_rx_number++;
+#ifdef DEBUG
+                printf("[RF]Bad: received all: %d\n",sc->in_stats.all_rx_number);
+                printf("[RF]Bad: received bad: %d\n",sc->in_stats.bad_rx_number);
+#endif
 	}

 	return (!frame_ok || framelen > 4);
@@ -548,29 +576,46 @@

 		if (sc->inppos + framelen  <=  ETHER_MAX_LEN) {
 			frame_ok = append_frame_to_pkt(sc, framelen, crc);
+#ifdef DEBUG
+                        printf("[UD]Append frame,frame_ok=%d\n",frame_ok);
+#endif

 		/*
 		 * if CRC is right but framelen incorrect then transmitter
 		 * error was occured... drop entire packet
 		 */
 		} else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
+#ifdef DEBUG
+                        printf("[UD]CRC OK, but framelen incorrect\n");
+#endif
 			sc->wait_frameno = 0;
 			sc->inppos = 0;
 			sc->arpcom.ac_if.if_ierrors++;
 			/* now skip all frames until is_first != 0 */
 		}
 	} else
+            {
 		frame_ok = skip_tail(sc, framelen, crc);
+#ifdef DEBUG
+              printf("[UD]sc->wait_frameno=%d != frameno=%d\n",sc->wait_frameno,frameno);
+#endif
+            }

 	if (is_first && !frame_ok) {
 		/*
 		 * Frame has been violated, but we have stored
 		 * is_first already... Drop entire packet.
 		 */
+#ifdef DEBUG
+                printf("[UD]is_first (%ud) && !frame_ok (%d)\n",is_first,frame_ok);
+#endif
 		sc->wait_frameno = 0;
 		sc->arpcom.ac_if.if_ierrors++;
 	}

+#ifdef DEBUG
+        printf("[UD]returning frame_ok=%d\n",frame_ok);
+#endif
 	return (frame_ok);
 }

@@ -620,15 +665,30 @@
 	caddr_t p;

 	if (sc->inppos + framelen > ETHER_MAX_LEN)
+          {
+#ifdef DEBUG
+            printf("[AF]sc->inppos + framelen (%d) > ETHER_MAX\n",sc->inppos + framelen);
+#endif
 		return (0);
+          }

 	if (!sc->rx_buf_p && !get_rx_buf(sc))
+          {
+#ifdef DEBUG
+            printf("[AF]Cannot get RX buffer\n");
+#endif
 		return (0);
+          }

 	p = sc->rx_buf_p->m_data + sc->inppos;
 	sbni_insb(sc, p, framelen);
 	if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
+          {
+#ifdef DEBUG
+            printf("[AF]calc_crc32 != CRC32_REMAINDER\n");
+#endif
 		return (0);
+          }

 	sc->inppos += framelen - 4;
 	if (--sc->wait_frameno == 0) {		/* last frame received */
@@ -636,6 +696,9 @@
 		sc->arpcom.ac_if.if_ipackets++;
 	}

+#ifdef DEBUG
+        printf("[AF]Append OK, sc->inppos = %d\n",sc->inppos);
+#endif
 	return (1);
 }

@@ -1144,8 +1207,10 @@

 /* -------------------------------------------------------------------------- */

+/* Beware! Under 5.x ASM code produced incorrect CRC!, so you MUST	*
+ * use C procedure for CRC calculations. So, this code will in play	*
+ * only under 4.x							*/
 #ifdef ASM_CRC
-
 static u_int32_t
 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
 {
@@ -1223,7 +1288,6 @@

 	return (_crc);
 }
-
 #else	/* ASM_CRC */

 static u_int32_t

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list