Date: Mon, 17 Jul 2006 14:48:32 +0700 (NOVST) From: "Rashid N. Achilov" <shelton@granch.ru> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/100425: sbni drivers does not work under 5.x Message-ID: <200607170748.k6H7mWRf025476@www.granch.ru> Resent-Message-ID: <200607170800.k6H80YqS053266@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607170748.k6H7mWRf025476>