diff -u --recursive --new-file v1.1.72/linux/Makefile linux/Makefile --- v1.1.72/linux/Makefile Tue Dec 6 17:37:05 1994 +++ linux/Makefile Wed Dec 14 14:46:30 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 72 +SUBLEVEL = 73 ARCH = i386 diff -u --recursive --new-file v1.1.72/linux/arch/i386/boot/head.S linux/arch/i386/boot/head.S --- v1.1.72/linux/arch/i386/boot/head.S Mon Dec 5 18:47:54 1994 +++ linux/arch/i386/boot/head.S Mon Dec 12 21:33:00 1994 @@ -122,9 +122,15 @@ /* get processor type */ movl $1, %eax # Use the CPUID instruction to .byte 0x0f, 0xa2 # check the processor type - andl $0xf00, %eax # Set _x86 with the family - shrl $8, %eax # returned. - movl %eax, _x86 + movb %al, %cl # save reg for future use + andb $0x0f,%ah # mask processor family + movb %ah, _x86 + andb $0xf0, %eax # mask model + shrb $4, %al + movb %al, _x86_model + andb $0x0f, %cl # mask mask revision + movb %cl, _x86_mask + movl %edx, _x86_capability /* get vendor info */ xorl %eax, %eax # call CPUID with 0 -> return vendor ID .byte 0x0f, 0xa2 # CPUID @@ -174,7 +180,7 @@ * We depend on ET to be correct. This checks for 287/387. */ check_x87: - movl $0,_hard_math + movb $0,_hard_math clts fninit fstsw %ax @@ -185,7 +191,7 @@ movl %eax,%cr0 ret .align 2 -1: movl $1,_hard_math +1: movb $1,_hard_math .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ ret diff -u --recursive --new-file v1.1.72/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.1.72/linux/arch/i386/config.in Mon Dec 5 18:47:54 1994 +++ linux/arch/i386/config.in Mon Dec 12 21:18:59 1994 @@ -19,13 +19,6 @@ bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y #fi -comment 'Screen saver mode' - -bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n -if [ "$CONFIG_VESA_PSPM" = "y" ]; then -bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n -fi - if [ "$CONFIG_NET" = "y" ]; then comment 'Networking options' bool 'TCP/IP networking' CONFIG_INET y @@ -212,6 +205,11 @@ bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n +bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n +if [ "$CONFIG_VESA_PSPM" = "y" ]; then +bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n +fi + bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n if [ "$CONFIG_QIC02_TAPE" = "y" ]; then @@ -241,6 +239,9 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n bool 'Kernel profiling support' CONFIG_PROFILE n +if [ "$CONFIG_PROFILE" = "y" ]; then + int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 +fi if [ "$CONFIG_SCSI" = "y" ]; then bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y fi diff -u --recursive --new-file v1.1.72/linux/arch/sparc/boot/boot.S linux/arch/sparc/boot/boot.S --- v1.1.72/linux/arch/sparc/boot/boot.S Tue Dec 6 17:37:05 1994 +++ linux/arch/sparc/boot/boot.S Mon Dec 12 20:41:32 1994 @@ -13,7 +13,7 @@ document those I have come across thus far. Upon bootup the boot prom loads your a.out image into memory. This memory the prom has already mapped for you, however as far as I can tell the virtual - adress cache is not turned on although the MMU is translating + address cache is not turned on although the MMU is translating things. You get loaded at 0xf8004000 exactly. So, when you link a boot-loadable object you want to do something like: @@ -27,7 +27,7 @@ the 'rom vector' in register %o0 right before it jumps to your starting address. This is a pointer to a struct that is full of pointer to functions (ie. printf, halt, reboot), pointers to - linked lists (ie. memory mappings), and pointer to imperical + linked lists (ie. memory mappings), and pointer to empirical constants (ie. stdin and stdout magic cookies + rom version). Starting with this piece of information you can figure out just about anything you want about the machine you are on. @@ -62,6 +62,10 @@ .asciz "sun4c" .ascii " " +/* + * Sun people can't spell worth damn. "compatability" indeed. + * At least we *know* we can't spell, and use a spell-checker. + */ _cputypvar: .asciz "compatability" @@ -109,7 +113,7 @@ prom_bootstr: .skip 4 ! what we are invoked with prom_putchar: .skip 4 ! void putchar(int ch) BLOCKING. prom_getchar: .skip 4 ! int getchar(void) BLOCKING. -prom_nputchar: .skip 4 ! int purchar(int ch) non-block +prom_nputchar: .skip 4 ! int putchar(int ch) non-block prom_ngetchar: .skip 4 ! int getchar(void) non-block prom_halt: .skip 4 ! void halt(void) solaris friend prom_eval: .skip 4 ! void eval(int len, char* string) @@ -137,7 +141,7 @@ */ prom_sync: .skip 4 ! hook in prom for "sync" func -prom_v0bootarg: .skip 4 ! v0 prom boot arguements +prom_v0bootarg: .skip 4 ! v0 prom boot arguments prom_v2bootarg: .skip 4 ! same as above for v2 proms prom_ethaddr_func: .skip 4 ! extract ethernet device address prom_v2devfunc: .skip 4 ! ptr to v2 style device ops. @@ -244,7 +248,7 @@ or unimplemented) and 128 software traps (ditto). One of the instructions must be a branch. More often than not this - will be to a trap handler entry point becuase it is completely + will be to a trap handler entry point because it is completely impossible to handle any trap in 4 insns. I welcome anyone to challenge this theory. :-) @@ -285,7 +289,7 @@ */ .data - .skip 32 ! alignment byte & negative indicies + .skip 32 ! alignment byte & negative indices lnx_uw: .skip 32 ! u_char uwtab[-31..31]; lnx_winmask: .skip 32 ! u_char wmask[0..31]; @@ -347,7 +351,7 @@ set _cputypvar, %o1 ! first node has cpu-arch set _cputypval, %o2 ! information, the string - ld [%g7 + 0x1c], %o4 ! 'compatability' tells + ld [%g7 + 0x1c], %o4 ! 'compatibility' tells ld [%o4 + 0x0c], %o4 ! that we want 'sun4x' where call %o4 ! x is one of '', 'c', 'm', nop ! 'd' or 'e'. %o2 holds pointer @@ -476,7 +480,7 @@ */ /* Another Note: - The prom printf() function can take up to 5 arguements in registers + The prom printf() function can take up to 5 arguments in registers %o1 -- %o5 , the format string goes in %o0. It is your usual libc printf() believe it or not. */ @@ -503,7 +507,7 @@ be mv_to_vmprom ! is there more? nop - ld [%l4 + 0x8], %l6 ! aparently so... + ld [%l4 + 0x8], %l6 ! apparently so... add %o1, %l6, %o1 b memloop ld [%l4], %l4 @@ -524,7 +528,7 @@ cmp %l4, 0 be mv_to_vmprom2 ! is there more? nop - ld [%l4 + 0x8], %l6 ! aparently so... + ld [%l4 + 0x8], %l6 ! apparently so... add %o2, %l6, %o2 b memloop2 ld [%l4], %l4 @@ -545,7 +549,7 @@ cmp %l4, 0 be mv_to_vmprom3 ! is there more? nop - ld [%l4 + 0x8], %l6 ! aparently so... + ld [%l4 + 0x8], %l6 ! apparently so... add %o3, %l6, %o3 b memloop3 ld [%l4], %l4 @@ -668,7 +672,7 @@ halt_me: ld [%g7 + 0x74], %o0 call %o0 ! get us out of here... - nop ! aparently solaris is better + nop ! apparently solaris is better _strlen: mov %o0, %l1 diff -u --recursive --new-file v1.1.72/linux/arch/sparc/string.S linux/arch/sparc/string.S --- v1.1.72/linux/arch/sparc/string.S Tue Dec 6 17:37:05 1994 +++ linux/arch/sparc/string.S Wed Dec 7 07:21:24 1994 @@ -16,7 +16,7 @@ .align 4 .globl _strlen _strlen: - mov %o0, %g3 ! leaf-proceedure optimization, here + mov %o0, %g3 ! leaf-procedure optimization, here ldsb [%g3], %g2 ! I only use the register sent to me cmp %g2, 0 ! and the globals. Now, this routine be 1f ! is callable from boot code. @@ -24,16 +24,16 @@ add %o0, 1, %o0 0: ldsb [%o0], %g2 cmp %g2, 0 - bne,a 0b ! annuling branch, yuck + bne,a 0b ! annulling branch, yuck add %o0, 1, %o0 1: retl - sub %o0, %g3, %o0 ! since %g3 holds the origional pointer + sub %o0, %g3, %o0 ! since %g3 holds the original pointer ! and %o0 is at the end byte, we can ! subtract and the result is strlen. /* String concatenate function. I am too lazy to honor the third count - arguement at this time. Once again, this could be optimized so much + argument at this time. Once again, this could be optimized so much more to use word accesses instead of slooow byte loads. */ .align 4 diff -u --recursive --new-file v1.1.72/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.1.72/linux/drivers/block/floppy.c Tue Dec 6 17:37:06 1994 +++ linux/drivers/block/floppy.c Wed Dec 7 07:21:24 1994 @@ -3208,7 +3208,7 @@ return; } } - printk("unknown floppy paramter %s\n", str); + printk("unknown floppy parameter %s\n", str); } #endif diff -u --recursive --new-file v1.1.72/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v1.1.72/linux/drivers/char/ChangeLog Thu Dec 1 19:15:03 1994 +++ linux/drivers/char/ChangeLog Mon Dec 12 21:54:28 1994 @@ -1,3 +1,26 @@ +Thu Dec 8 14:52:11 1994 + + * serial.c (rs_ioctl): Don't allow most ioctl's if the serial port + isn't initialized. + + * serial.c (rs_close): Don't clear the IER if the serial port + isn't initialized. + + * serial.c (block_til_ready): Don't try to block on the dialin + port if the serial port isn't initialized. + +Wed Dec 7 10:48:30 1994 Si Park (si@wimpol.demon.co.uk) + * tty_io.c (tty_register_driver): Fix bug when linking onto + the tty_drivers list. We now test that there are elements + already on the list before setting the back link from the + first element to the new driver. + + * tty_io.c (tty_unregister_driver): Fix bug in unlinking the + specified driver from the tty_drivers list. We were not + setting the back link correctly. This used to result in + a dangling back link pointer and cause panics on the next + call to get_tty_driver(). + Tue Nov 29 10:21:09 1994 Theodore Y. Ts'o (tytso@rt-11) * tty_io.c (tty_unregister_driver): Fix bug in diff -u --recursive --new-file v1.1.72/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.1.72/linux/drivers/char/console.c Sat Dec 3 13:05:42 1994 +++ linux/drivers/char/console.c Wed Dec 14 09:10:37 1994 @@ -22,8 +22,8 @@ * 'void console_print(const char * b)' * 'void update_screen(int new_console)' * - * 'void blank_screen(void)' - * 'void unblank_screen(void)' + * 'void do_blank_screen(int)' + * 'void do_unblank_screen(void)' * 'void poke_blanked_console(void)' * 'void scrollback(int lines)' * 'void scrollfront(int lines)' @@ -117,11 +117,11 @@ static void highlight_pointer(const int currcons, const int where); /* Variables for selection control. */ -#define SEL_BUFFER_SIZE 4096 +/* Use a dynamic buffer, instead of static (Dec 1994) */ static int sel_cons = 0; static int sel_start = -1; static int sel_end; -static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' }; +static char *sel_buffer = NULL; #endif /* CONFIG_SELECTION */ #define NPAR 16 @@ -132,6 +132,8 @@ static void get_scrmem(int currcons); static void set_scrmem(int currcons, long offset); static void set_origin(int currcons); +static void blank_screen(void); +static void unblank_screen(void); static void gotoxy(int currcons, int new_x, int new_y); static void save_cur(int currcons); static inline void set_cursor(int currcons); @@ -160,9 +162,7 @@ static int console_blanked = 0; static int blankinterval = 10*60*HZ; -#ifndef CONFIG_VESA_PSPM static long blank_origin, blank__origin, unblank_origin; -#endif struct vc_data { unsigned long vc_screenbuf_size; @@ -307,16 +307,16 @@ * Huang shi chao, delivered together with many new monitor models * * capable of the VESA Power Saving Protocol. * * Adapted to Linux by Christoph Rimek (chrimek@toppoint.de) 15-may-94 * - * Re-Adapted by Nicholas Leon (nicholas@neko.binary9.com) 10/94 * - * (with minor reorganization/changes) * + * Re-Adapted by Nicholas Leon (nicholas@neko.binary9.com) 10/94 * + * (with minor reorganization/changes) * */ static void vesa_blank(void); static void vesa_unblank(void); -#define seq_port_reg (0x3c4) /* Sequencer register select port */ -#define seq_port_val (0x3c5) /* Sequencer register value port */ +#define seq_port_reg (0x3c4) /* Sequencer register select port */ +#define seq_port_val (0x3c5) /* Sequencer register value port */ #define video_misc_rd (0x3cc) /* Video misc. read port */ #define video_misc_wr (0x3c2) /* Video misc. write port */ @@ -338,6 +338,8 @@ unsigned char ClockingMode; /* Seq-Controller:01h */ } vga; +static int vesa_blanked = 0; + /* routine to blank a vesa screen */ static void vesa_blank(void) { @@ -405,11 +407,15 @@ outb_p(vga.CrtCtrlIndex,video_port_reg); sti(); + vesa_blanked = 1; } /* routine to unblank a vesa screen */ static void vesa_unblank(void) { + if (!vesa_blanked) + return; + /* restore original values of VGA controller registers */ cli(); outb_p(vga.CrtMiscIO,video_misc_wr); @@ -438,6 +444,8 @@ outb_p(vga.SeqCtrlIndex,seq_port_reg); outb_p(vga.CrtCtrlIndex,video_port_reg); sti(); + + vesa_blanked = 0; } #endif /* CONFIG_VESA_PSPM */ @@ -1426,7 +1434,7 @@ utf = 0; utf_count = 0; - disp_ctrl = 0; + disp_ctrl = 1; toggle_meta = 0; decscnm = 0; @@ -1925,9 +1933,11 @@ { int currcons = fg_console; unsigned char c; + static int printing = 0; - if (!printable) + if (!printable || printing) return; /* console not yet initialized */ + printing = 1; if (!vc_cons_allocated(currcons)) { /* impossible */ @@ -1952,16 +1962,8 @@ pos+=2; } set_cursor(currcons); - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; - timer_active &= ~(1< p2) - { - p = p1; - p1 = p2; - p2 = p; - } + for (p = p1; p <= p2; p += 2) *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07); } @@ -2415,6 +2419,7 @@ /* * This function uses a 128-bit look up table + * WARNING: This depends on both endianness and the ascii code */ static unsigned long inwordLut[4]={ 0x00000000, /* control chars */ @@ -2439,10 +2444,10 @@ return (!(p % video_size_row) || !((p + 2) % video_size_row)); } -/* constrain v such that l <= v <= u */ -static inline short limit(const int v, const int l, const int u) +/* constrain v such that v <= u */ +static inline short limit(const unsigned short v, const unsigned short u) { - return (v < l) ? l : ((v > u) ? u : v); + return ((v > u) ? u : v); } /* invoked via ioctl(TIOCLINUX) */ @@ -2471,10 +2476,10 @@ ye = get_fs_word(args++) - 1; sel_mode = get_fs_word(args); - xs = limit(xs, 0, video_num_columns - 1); - ys = limit(ys, 0, video_num_lines - 1); - xe = limit(xe, 0, video_num_columns - 1); - ye = limit(ye, 0, video_num_lines - 1); + xs = limit(xs, video_num_columns - 1); + ys = limit(ys, video_num_lines - 1); + xe = limit(xe, video_num_columns - 1); + ye = limit(ye, video_num_lines - 1); ps = ys * video_size_row + (xs << 1); pe = ye * video_size_row + (xe << 1); @@ -2578,6 +2583,16 @@ } sel_start = new_sel_start; sel_end = new_sel_end; + + /* realloc the buffer (it seems to be efficient, anyway) */ + if (sel_buffer) kfree(sel_buffer); + sel_buffer = kmalloc((sel_end-sel_start)/2+2, GFP_KERNEL); + if (!sel_buffer) + { + printk("selection: kmalloc() failed\n"); + clear_selection(); + return (0); /* is it right? */ + } obp = bp = sel_buffer; for (i = sel_start; i <= sel_end; i += 2) { @@ -2596,10 +2611,6 @@ } obp = bp; } - /* check for space, leaving room for next character, possible - newline, and null at end. */ - if (bp - sel_buffer > SEL_BUFFER_SIZE - 3) - break; } *bp = '\0'; return 0; @@ -2614,7 +2625,7 @@ int c, l; struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - if (!sel_buffer[0]) + if (!bp || !bp[0]) return 0; unblank_screen(); c = strlen(sel_buffer); diff -u --recursive --new-file v1.1.72/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v1.1.72/linux/drivers/char/serial.c Thu Dec 1 19:15:03 1994 +++ linux/drivers/char/serial.c Mon Dec 12 21:05:28 1994 @@ -1666,6 +1666,13 @@ if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ @@ -1852,9 +1859,9 @@ * line status register. */ info->IER &= ~UART_IER_RLSI; - serial_out(info, UART_IER, info->IER); info->read_status_mask &= ~UART_LSR_DR; if (info->flags & ASYNC_INITIALIZED) { + serial_out(info, UART_IER, info->IER); wait_until_sent(tty, 3000); /* 30 seconds timeout */ /* * Before we drop DTR, make sure the UART transmitter @@ -1965,10 +1972,11 @@ } /* - * If non-blocking mode is set, then make the check up front - * and then exit. + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. */ - if (filp->f_flags & O_NONBLOCK) { + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & ASYNC_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; diff -u --recursive --new-file v1.1.72/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v1.1.72/linux/drivers/char/tty_io.c Thu Dec 1 19:15:03 1994 +++ linux/drivers/char/tty_io.c Mon Dec 12 21:54:28 1994 @@ -73,6 +73,8 @@ extern int shift_state; #endif /* CONFIG_SELECTION */ extern int do_screendump(int arg, int mode); +extern void do_blank_screen(int nopowersave); +extern void do_unblank_screen(void); struct termios tty_std_termios; /* for the benefit of tty drivers */ struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */ @@ -513,11 +515,9 @@ if (old_vc_mode != vt_cons[new_console]->vc_mode) { if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else { - timer_active &= ~(1<prev = 0; driver->next = tty_drivers; - tty_drivers->prev = driver; + if (tty_drivers) tty_drivers->prev = driver; tty_drivers = driver; return error; } @@ -1633,7 +1633,7 @@ tty_drivers = driver->next; if (driver->next) - driver->next = driver->next->prev; + driver->next->prev = driver->prev; return 0; } diff -u --recursive --new-file v1.1.72/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v1.1.72/linux/drivers/char/vt.c Tue Nov 15 15:35:39 1994 +++ linux/drivers/char/vt.c Mon Dec 12 21:18:59 1994 @@ -52,6 +52,8 @@ extern void change_console(unsigned int new_console); extern void complete_change_console(unsigned int new_console); extern int vt_waitactive(void); +extern void do_blank_screen(int nopowersave); +extern void do_unblank_screen(void); extern unsigned int keymap_count; @@ -208,11 +210,9 @@ * explicitly blank/unblank the screen if switching modes */ if (arg == KD_TEXT) - unblank_screen(); - else { - timer_active &= ~(1<scb.status, lp->scb.command) if (--boguscnt == 0) { - printk("%s: recieve unit start timed out with status %4.4x, cmd %4.4x.\n", + printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } @@ -1016,7 +1016,7 @@ #ifdef MODULE char kernel_version[] = UTS_RELEASE; static struct device dev_apricot = { - " ", /* device name inservted by /linux/drivers/net/net_init.c */ + " ", /* device name inserted by /linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x300, 10, 0, 0, 0, NULL, apricot_probe }; diff -u --recursive --new-file v1.1.72/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.1.72/linux/drivers/net/depca.c Tue Dec 6 17:37:06 1994 +++ linux/drivers/net/depca.c Mon Dec 12 20:06:54 1994 @@ -17,6 +17,7 @@ DEPCA (the original) DE100 + DE101 DE200 Turbo DE201 Turbo DE202 Turbo (TP BNC) @@ -147,26 +148,28 @@ Version Date Description - 0.1 25-jan-94 Initial writing. - 0.2 27-jan-94 Added LANCE TX hardware buffer chaining. - 0.3 1-feb-94 Added multiple DEPCA support. - 0.31 4-feb-94 Added DE202 recognition. - 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support. - 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable. + 0.1 25-jan-94 Initial writing. + 0.2 27-jan-94 Added LANCE TX hardware buffer chaining. + 0.3 1-feb-94 Added multiple DEPCA support. + 0.31 4-feb-94 Added DE202 recognition. + 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support. + 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable. Add jabber packet fix from murf@perftech.com and becker@super.org - 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access. - 0.35 8-mar-94 Added DE201 recognition. Tidied up. - 0.351 30-apr-94 Added EISA support. Added DE422 recognition. - 0.36 16-may-94 DE422 fix released. - 0.37 22-jul-94 Added MODULE support - 0.38 15-aug-94 Added DBR ROM switch in depca_close(). + 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access. + 0.35 8-mar-94 Added DE201 recognition. Tidied up. + 0.351 30-apr-94 Added EISA support. Added DE422 recognition. + 0.36 16-may-94 DE422 fix released. + 0.37 22-jul-94 Added MODULE support + 0.38 15-aug-94 Added DBR ROM switch in depca_close(). Multi DEPCA bug fix. + 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0 + 0.381 12-dec-94 Added DE101 recognition, fix multicast bug ========================================================================= */ -static char *version = "depca.c:v0.38 8/15/94 davies@wanton.lkg.dec.com\n"; +static char *version = "depca.c:v0.381 12/12/94 davies@wanton.lkg.dec.com\n"; #include #include @@ -208,8 +211,10 @@ #endif #ifndef DEPCA_SIGNATURE -#define DEPCA_SIGNATURE {"DEPCA","DE100",\ - "DE200","DE201","DE202","DE210",\ +#define DEPCA_SIGNATURE {"DEPCA",\ + "DE100","DE101",\ + "DE200","DE201","DE202",\ + "DE210",\ "DE422",\ ""} #define DEPCA_NAME_LENGTH 8 @@ -1237,35 +1242,28 @@ ** num_addrs > 0 Multicast mode, receive normal and MC packets, and do ** best-effort filtering. */ +#define hash_filter lp->init_block.filter + static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { short ioaddr = dev->base_addr; struct depca_private *lp = (struct depca_private *)dev->priv; - /* We take the simple way out and always enable promiscuous mode. */ - STOP_DEPCA; /* Temporarily stop the depca. */ - - lp->init_block.mode = PROM; /* Set promiscuous mode */ - if (num_addrs >= 0) { - short multicast_table[4]; - int i; - - SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table); - - /* We don't use the multicast table, but rely on upper-layer filtering. */ - memset(multicast_table, (num_addrs==0) ? 0 : -1, sizeof(multicast_table)); - - for (i = 0; i < 4; i++) { - lp->init_block.filter[i] = multicast_table[i]; + if (irq2dev_map[dev->irq] != NULL) { + STOP_DEPCA; /* Temporarily stop the depca. */ + depca_init_ring(dev); /* Initialize the descriptor rings */ + + if (num_addrs >= 0) { + SetMulticastFilter(num_addrs, (char *)addrs, (char *)hash_filter); + lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ + } else { + lp->init_block.mode |= PROM; /* Set promiscuous mode */ } - lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ - } else { - lp->init_block.mode |= PROM; /* Set promiscuous mode */ - } - outw(CSR0, DEPCA_ADDR); - outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */ + LoadCSRs(dev); /* Reload CSR3 */ + InitRestartDepca(dev); /* Resume normal operation. */ + } } /* diff -u --recursive --new-file v1.1.72/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v1.1.72/linux/drivers/net/ewrk3.c Tue Dec 6 17:37:06 1994 +++ linux/drivers/net/ewrk3.c Mon Dec 12 22:09:05 1994 @@ -118,11 +118,12 @@ 0.23 21-sep-94 Added transmit cut through 0.24 31-oct-94 Added uid checks in some ioctls 0.30 1-nov-94 BETA code release + 0.31 5-dec-94 Added check/snarf_region code. ========================================================================= */ -static char *version = "ewrk3.c:v0.30 11/1/94 davies@wanton.lkg.dec.com\n"; +static char *version = "ewrk3.c:v0.31 12/5/94 davies@wanton.lkg.dec.com\n"; #include #include @@ -314,7 +315,7 @@ static struct device *eisa_probe(struct device *dev); static struct device *alloc_device(struct device *dev, int iobase); -static int num_ewrk3s = 0, num_eth = 0, autoprobed = 0; +static int num_ewrk3s = 0, num_eth = 0; static unsigned char irq[] = {5,0,10,3,11,9,15,12}; #else @@ -323,6 +324,8 @@ #endif /* MODULE */ +static int autoprobed = 0; + /* ** Miscellaneous defines... */ @@ -344,14 +347,23 @@ #endif if (base_addr > 0x0ff) { /* Check a single specified location. */ - if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==0) { - if (DevicePresent(base_addr) == 0) { /* Is EWRK3 really here? */ - status = ewrk3_hw_init(dev, base_addr); + if (!autoprobed) { /* Module or fixed location */ + if (!check_region(base_addr, EWRK3_IOP_INC)) { + if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==1) { + if (DevicePresent(base_addr) == 0) { /* Is EWRK3 really here? */ + snarf_region(base_addr, EWRK3_IOP_INC); /* Register I/O region */ + status = ewrk3_hw_init(dev, base_addr); + } else { + printk("ewrk3_probe(): No device found\n"); + mem_chkd &= ~(0x01 << ((base_addr - EWRK3_IO_BASE)/EWRK3_IOP_INC)); + } + } } else { - printk("ewrk3_probe(): No device found\n"); + printk("%s: ewrk3_probe(): Detected a device already registered at 0x%02x\n", dev->name, base_addr); + mem_chkd &= ~(0x01 << ((base_addr - EWRK3_IO_BASE)/EWRK3_IOP_INC)); } - } else { - status = ewrk3_hw_init(dev, base_addr); /* Yes there is h/w */ + } else { /* already know what ewrk3 h/w is here */ + status = ewrk3_hw_init(dev, base_addr); } } else if (base_addr > 0) { /* Don't probe at all. */ status = -ENXIO; @@ -1282,12 +1294,13 @@ } } } - hashcode = (crc & 0x01); /* hashcode is 9 LSb of CRC ... */ + hashcode = ((crc >>= 23) & 0x01); /* hashcode is 9 MSb of CRC ... */ for (j=0;j<8;j++) { /* ... in reverse order. */ hashcode <<= 1; crc >>= 1; hashcode |= (crc & 0x01); } + octet = hashcode >> 3; /* bit[3-8] -> octet in filter */ /* bit[0-2] -> bit in octet */ if (lp->shmem_length == IO_ONLY) { @@ -1323,20 +1336,27 @@ i < 24; iobase += EWRK3_IOP_INC, i++) { if (tmp & 0x01) { - if (DevicePresent(iobase) == 0) { + /* Anything else registered here? */ + if (!check_region(iobase, EWRK3_IOP_INC)) { + if (DevicePresent(iobase) == 0) { /* ** Device found. Mark its (I/O) location for future reference. Only 24 ** EtherWORKS devices can exist between 0x100 and 0x3e0. */ - if (num_ewrk3s > 0) { /* only gets here in autoprobe */ - dev = alloc_device(dev, iobase); - } else { - if ((status = ewrk3_hw_init(dev, iobase)) == 0) { - num_ewrk3s++; + snarf_region(iobase, EWRK3_IOP_INC); + if (num_ewrk3s > 0) { /* only gets here in autoprobe */ + dev = alloc_device(dev, iobase); + } else { + if ((status = ewrk3_hw_init(dev, iobase)) == 0) { + num_ewrk3s++; + } } + num_eth++; + } else { + mem_chkd &= ~(0x01 << ((iobase - EWRK3_IO_BASE)/EWRK3_IOP_INC)); } - num_eth++; } else { + printk("%s: ewrk3_probe(): Detected a device already registered at 0x%02x\n", dev->name, iobase); mem_chkd &= ~(0x01 << ((iobase - EWRK3_IO_BASE)/EWRK3_IOP_INC)); } } @@ -1358,20 +1378,24 @@ iobase+=EISA_SLOT_INC; /* get the first slot address */ for (status = -ENODEV, i=1; i 0) { /* only gets here in autoprobe */ - dev = alloc_device(dev, iobase); - } else { - if ((status = ewrk3_hw_init(dev, iobase)) == 0) { - num_ewrk3s++; + mem_chkd |= (0x01 << (i + 24)); + snarf_region(iobase, EWRK3_IOP_INC); + if (num_ewrk3s > 0) { /* only gets here in autoprobe */ + dev = alloc_device(dev, iobase); + } else { + if ((status = ewrk3_hw_init(dev, iobase)) == 0) { + num_ewrk3s++; + } } + num_eth++; } - num_eth++; } } return dev; diff -u --recursive --new-file v1.1.72/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.1.72/linux/drivers/net/slhc.c Wed Aug 10 19:26:18 1994 +++ linux/drivers/net/slhc.c Mon Dec 12 22:24:45 1994 @@ -38,6 +38,8 @@ * status display * - Jul 1994 Dmitry Gorodchanin * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. * * * This module is a difficult issue. Its clearly inet code but its also clearly @@ -71,6 +73,11 @@ #include #include "slhc.h" +#ifdef MODULE +#include +#include +#endif + int last_retran; static unsigned char *encode(unsigned char *cp, unsigned short n); @@ -91,7 +98,7 @@ register struct cstate *ts; struct slcompress *comp; - comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) return NULL; @@ -112,7 +119,7 @@ } if ( tslots > 0 && tslots < 256 ) { - comp->tstate = + comp->tstate = (struct cstate *)kmalloc(tslots * sizeof(struct cstate), GFP_KERNEL); if (! comp->tstate) @@ -145,6 +152,9 @@ ts[0].next = &(ts[comp->tslot_limit]); ts[0].cs_this = 0; } +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return comp; } @@ -162,6 +172,9 @@ if ( comp->tstate != NULLSLSTATE ) kfree( comp->tstate ); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif kfree( comp ); } @@ -216,7 +229,7 @@ } } -/* +/* * icp and isize are the original packet. * ocp is a place to put a copy if necessary. * cpp is initially a pointer to icp. If the copy is used, @@ -241,7 +254,7 @@ ip = (struct iphdr *) icp; /* Bail if this packet isn't TCP, or is an IP fragment */ - if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || + if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || (ip->frag_off & 32)){ /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) @@ -310,7 +323,7 @@ * Found it -- move to the front on the connection list. */ if(lcs == ocs) { - /* found at most recently used */ + /* found at most recently used */ } else if (cs == ocs) { /* found at least recently used */ comp->xmit_oldest = lcs->cs_this; @@ -345,7 +358,7 @@ || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4 != 0))){ goto uncompressed; } - + /* * Figure out which of the changing fields changed. The * receiver expects changes in the order: urgent, window, @@ -379,7 +392,7 @@ cp = encode(cp,deltaS); changes |= NEW_S; } - + switch(changes){ case 0: /* Nothing changed. If this packet contains data and the * last one didn't, this is probably a data packet following @@ -388,7 +401,7 @@ * retransmitted ack or window probe. Send it uncompressed * in case the other side missed the compressed version. */ - if(ip->tot_len != cs->cs_ip.tot_len && + if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; goto uncompressed; @@ -522,7 +535,7 @@ thp->check = htons(x); thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; -/* +/* * we can use the same number for the length of the saved header and * the current one, because the packet wouldn't have been sent * as compressed unless the options were the same as the previous one @@ -557,7 +570,7 @@ if(changes & NEW_W){ if((x = decode(&cp)) == -1) { goto bad; - } + } thp->window = htons( ntohs(thp->window) + x); } if(changes & NEW_A){ @@ -715,4 +728,21 @@ } } +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; + +int init_module(void) +{ + printk("CSLIP: code copyright 1989 Regents of the University of California\n"); + return 0; +} + +void cleanup_module(void) +{ + if (MOD_IN_USE) { + printk("CSLIP: module in use, remove delayed"); + } + return; +} +#endif /* MODULE */ #endif /* CONFIG_INET */ diff -u --recursive --new-file v1.1.72/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.1.72/linux/drivers/net/slip.c Sat Nov 26 18:36:05 1994 +++ linux/drivers/net/slip.c Mon Dec 12 22:24:06 1994 @@ -3,7 +3,7 @@ * devices like TTY. It interfaces between a raw TTY, and the * kernel's INET protocol layers (via DDI). * - * Version: @(#)slip.c 0.7.6 05/25/93 + * Version: @(#)slip.c 0.8.2 11/29/94 * * Authors: Laurence Culhane, * Fred N. van Kempen, @@ -25,117 +25,106 @@ * Alan Cox : Default to 192.168.0.0 (RFC 1597) * A.N.Kuznetsov : dev_tint() recursion fix. * Dmitry Gorodchanin : SLIP memory leaks - * Alan Cox : Oops - fix AX.25 buffer lengths + * Dmitry Gorodchanin : Code cleanup. Reduce tty driver + * buffering from 4096 to 256 bytes. + * Improving SLIP responce time. + * CONFIG_SLIP_MODE_SLIP6. + * ifconfig sl? up & down now works correctly. + * Modularization. + * Alan Cox : Oops - fix AX.25 buffer lengths + * * * * FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without * CONFIG_INET defined. + * I hope now it is fixed ;) */ - -#include -#include +#define SL_CHECK_TRANSMIT #include -#include -#include -#include + +#ifdef SL_COMPRESSED +/* I think following lines must be in the + * 14 Oct 1994 Dmitry Gorodchanin + */ +#define CONFIG_SLIP_COMPRESSED +#endif +#define CONFIG_SLIP_MODE_SLIP6 + +#include +#include +#include #include #include -#include -#include #include +#include #include #include -#include -#include -#include #include #ifdef CONFIG_AX25 #include "ax25.h" #endif #include -#ifdef CONFIG_INET -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#endif #include #include -#include "sock.h" #include "slip.h" #ifdef CONFIG_INET +#include "ip.h" +#include "tcp.h" #include "slhc.h" #endif +#ifdef MODULE +#include +#include +#endif -#define SLIP_VERSION "0.7.5-NET3.014-NEWTTY" + +#ifdef MODULE +#define SLIP_VERSION "0.8.1-NET3.014-NEWTTY-MODULAR" +#else +#define SLIP_VERSION "0.8.1-NET3.014-NEWTTY" +#endif static struct slip sl_ctrl[SL_NRUNIT]; static struct tty_ldisc sl_ldisc; static int already = 0; +static int slip_esc(unsigned char *p, unsigned char *d, int len); +static void slip_unesc(struct slip *sl, unsigned char c); +#ifdef CONFIG_SLIP_MODE_SLIP6 +static int slip_esc6(unsigned char *p, unsigned char *d, int len); +static void slip_unesc6(struct slip *sl, unsigned char c); +#endif + /* Initialize a SLIP control block for use. */ static void sl_initialize(struct slip *sl, struct device *dev) { - sl->magic = SLIP_MAGIC; - sl->inuse = 0; - sl->sending = 0; - sl->escape = 0; - sl->flags = 0; -#ifdef SL_ADAPTIVE - sl->mode = SL_MODE_ADAPTIVE; /* automatic CSLIP recognition */ -#else -#ifdef SL_COMPRESSED - sl->mode = SL_MODE_CSLIP | SL_MODE_ADAPTIVE; /* Default */ -#else - sl->mode = SL_MODE_SLIP; /* Default for non compressors */ -#endif -#endif - - sl->line = dev->base_addr; - sl->tty = NULL; - sl->dev = dev; - sl->slcomp = NULL; - - /* Clear all pointers. */ - sl->rbuff = NULL; - sl->xbuff = NULL; - sl->cbuff = NULL; - - sl->rhead = NULL; - sl->rend = NULL; - dev->rmem_end = (unsigned long) NULL; - dev->rmem_start = (unsigned long) NULL; - dev->mem_end = (unsigned long) NULL; - dev->mem_start = (unsigned long) NULL; - dev->type = ARPHRD_SLIP + sl->mode; - if(dev->type == 260) /* KISS */ - dev->type=ARPHRD_AX25; + memset(sl, 0, sizeof (struct slip)); + sl->magic = SLIP_MAGIC; + sl->dev = dev; + sl->mode = SL_MODE_DEFAULT; + dev->type = ARPHRD_SLIP + sl->mode; + if (dev->type == 260) { /* KISS */ + dev->type = ARPHRD_AX25; + } } /* Find a free SLIP channel, and link in this `tty' line. */ static inline struct slip * sl_alloc(void) { - unsigned long flags; - struct slip *sl; - int i; - - save_flags (flags); - cli(); - for (i = 0; i < SL_NRUNIT; i++) { - sl = &sl_ctrl[i]; - if (sl->inuse == 0) { - sl->inuse = 1; - sl->tty = NULL; - restore_flags(flags); - return(sl); - } - } - restore_flags(flags); - return(NULL); + struct slip *sl; + int i; + + for (i = 0; i < SL_NRUNIT; i++) { + sl = &sl_ctrl[i]; + if (!set_bit(SLF_INUSE, &sl->flags)) { + return sl; + } + } + return NULL; } @@ -143,121 +132,112 @@ static inline void sl_free(struct slip *sl) { - unsigned long flags; - - if (sl->inuse) { - save_flags(flags); - cli(); - sl->inuse = 0; - sl->tty = NULL; - restore_flags(flags); - } + if (!clear_bit(SLF_INUSE, &sl->flags)) { + printk("%s: sl_free for already free unit.\n", sl->dev->name); + } } /* MTU has been changed by the IP layer. Unfortunately we are not told about this, but we spot it ourselves and fix things up. We could be in an upcall from the tty driver, or in an ip packet queue. */ - + static void sl_changedmtu(struct slip *sl) { - struct device *dev=sl->dev; - unsigned char *tb,*rb,*cb,*tf,*rf,*cf; - int l; - int omtu=sl->mtu; + struct device *dev = sl->dev; + unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; +#ifdef CONFIG_INET + unsigned char *cbuff, *ocbuff; +#endif + int len; + unsigned long flags; -#ifdef CONFIG_AX25 - sl->mtu=dev->mtu+73; -#else - sl->mtu=dev->mtu; -#endif - l=(dev->mtu *2); + len = dev->mtu * 2; /* * allow for arrival of larger UDP packets, even if we say not to * also fixes a bug in which SunOS sends 512-byte packets even with * an MSS of 128 */ - if (l < (576 * 2)) - l = 576 * 2; - - tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); - rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); - cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); - - if(tb==NULL || rb==NULL || cb==NULL) - { - printk("Unable to grow slip buffers. MTU change cancelled.\n"); - sl->mtu=omtu; - dev->mtu=omtu; - if(tb!=NULL) - kfree(tb); - if(rb!=NULL) - kfree(rb); - if(cb!=NULL) - kfree(cb); + if (len < 576 * 2) { + len = 576 * 2; + } + + xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); + rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); +#ifdef CONFIG_INET + cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); +#endif + +#ifdef CONFIG_INET + if (xbuff == NULL || rbuff == NULL || cbuff == NULL) { +#else + if (xbuff == NULL || rbuff == NULL) { +#endif + printk("%s: unable to grow slip buffers, MTU change cancelled.\n", + sl->dev->name); + dev->mtu = sl->mtu; + if (xbuff != NULL) { + kfree(xbuff); + } + if (rbuff != NULL) { + kfree(rbuff); + } +#ifdef CONFIG_INET + if (cbuff != NULL) { + kfree(cbuff); + } +#endif return; } - - cli(); - - tf=(unsigned char *)sl->dev->mem_start; - sl->dev->mem_start=(unsigned long)tb; - sl->dev->mem_end=(unsigned long) (sl->dev->mem_start + l); - rf=(unsigned char *)sl->dev->rmem_start; - sl->dev->rmem_start=(unsigned long)rb; - sl->dev->rmem_end=(unsigned long) (sl->dev->rmem_start + l); - - sl->xbuff = (unsigned char *) sl->dev->mem_start; - sl->rbuff = (unsigned char *) sl->dev->rmem_start; - sl->rend = (unsigned char *) sl->dev->rmem_end; - sl->rhead = sl->rbuff; - - cf=sl->cbuff; - sl->cbuff=cb; - - sl->escape=0; - sl->sending=0; - sl->rcount=0; - - sti(); - - if(rf!=NULL) - kfree(rf); - if(tf!=NULL) - kfree(tf); - if(cf!=NULL) - kfree(cf); -} + save_flags(flags); cli(); -/* Stuff one byte into a SLIP receiver buffer. */ -static inline void -sl_enqueue(struct slip *sl, unsigned char c) -{ - unsigned long flags; + oxbuff = sl->xbuff; + sl->xbuff = xbuff; + orbuff = sl->rbuff; + sl->rbuff = rbuff; +#ifdef CONFIG_INET + ocbuff = sl->cbuff; + sl->cbuff = cbuff; +#endif + if (sl->xleft) { + if (sl->xleft <= len) { + memcpy(sl->xbuff, sl->xhead, sl->xleft); + } else { + sl->xleft = 0; + sl->tx_dropped++; + } + } + sl->xhead = sl->xbuff; - save_flags(flags); - cli(); - if (sl->rhead < sl->rend) { - *sl->rhead = c; - sl->rhead++; - sl->rcount++; - } else sl->roverrun++; - restore_flags(flags); -} + if (sl->rcount) { + if (sl->rcount <= len) { + memcpy(sl->rbuff, orbuff, sl->rcount); + } else { + sl->rcount = 0; + sl->rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } + } +#ifdef CONFIG_AX25 + sl->mtu = dev->mtu + 73; +#else + sl->mtu = dev->mtu; +#endif + sl->buffsize = len; -/* Release 'i' bytes from a SLIP receiver buffer. */ -static inline void -sl_dequeue(struct slip *sl, int i) -{ - unsigned long flags; + restore_flags(flags); - save_flags(flags); - cli(); - if (sl->rhead > sl->rbuff) { - sl->rhead -= i; - sl->rcount -= i; - } - restore_flags(flags); + if (oxbuff != NULL) { + kfree(oxbuff); + } + if (orbuff != NULL) { + kfree(orbuff); + } +#ifdef CONFIG_INET + if (ocbuff != NULL) { + kfree(ocbuff); + } +#endif } @@ -265,13 +245,9 @@ static inline void sl_lock(struct slip *sl) { - unsigned long flags; - - save_flags(flags); - cli(); - sl->sending = 1; - sl->dev->tbusy = 1; - restore_flags(flags); + if (set_bit(0, (void *) &sl->dev->tbusy)) { + printk("%s: trying to lock already locked device!\n", sl->dev->name); + } } @@ -279,123 +255,116 @@ static inline void sl_unlock(struct slip *sl) { - unsigned long flags; - - save_flags(flags); - cli(); - sl->sending = 0; - sl->dev->tbusy = 0; - restore_flags(flags); + if (!clear_bit(0, (void *)&sl->dev->tbusy)) { + printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); + } } - /* Send one completely decapsulated IP datagram to the IP layer. */ static void sl_bump(struct slip *sl) { - int done; - unsigned char c; - unsigned long flags; - int count; - - count = sl->rcount; -#ifdef CONFIG_INET - if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { - if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { -#if 1 - /* ignore compressed packets when CSLIP is off */ - if (!(sl->mode & SL_MODE_CSLIP)) { - printk("SLIP: compressed packet ignored\n"); - return; - } -#endif - /* make sure we've reserved enough space for uncompress to use */ - save_flags(flags); - cli(); - if ((sl->rhead + 80) < sl->rend) { - sl->rhead += 80; - sl->rcount += 80; - done = 1; - } else { - sl->roverrun++; - done = 0; - } - restore_flags(flags); - if (! done) /* not enough space available */ - return; - - count = slhc_uncompress(sl->slcomp, sl->rbuff, count); - if (count <= 0) { - sl->errors++; - return; - } - } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { - if (!(sl->mode & SL_MODE_CSLIP)) { - /* turn on header compression */ - sl->mode |= SL_MODE_CSLIP; - printk("SLIP: header compression turned on\n"); - } - sl->rbuff[0] &= 0x4f; - if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) { - sl->errors++; - return; - } - } - } - -#endif - /* Bump the datagram to the upper layers... */ - do { - /* clh_dump(sl->rbuff, count); */ - done = dev_rint(sl->rbuff, count, 0, sl->dev); - if (done == 0 || done == 1) break; - } while(1); + struct sk_buff *skb; + int count; + + count = sl->rcount; +#ifdef CONFIG_INET + if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { + unsigned char c; + if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { + /* ignore compressed packets when CSLIP is off */ + if (!(sl->mode & SL_MODE_CSLIP)) { + printk("%s: compressed packet ignored\n", sl->dev->name); + return; + } + /* make sure we've reserved enough space for uncompress to use */ + if (count + 80 > sl->buffsize) { + sl->rx_over_errors++; + return; + } + count = slhc_uncompress(sl->slcomp, sl->rbuff, count); + if (count <= 0) { + return; + } + } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { + if (!(sl->mode & SL_MODE_CSLIP)) { + /* turn on header compression */ + sl->mode |= SL_MODE_CSLIP; + printk("%s: header compression turned on\n", sl->dev->name); + } + sl->rbuff[0] &= 0x4f; + if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) { + return; + } + } + } +#endif /* CONFIG INET */ - sl->rpacket++; + skb = alloc_skb(count, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); + sl->rx_dropped++; + return; + } + skb->len = count; + skb->dev = sl->dev; + memcpy(skb->data, sl->rbuff, count); + netif_rx(skb); + sl->rx_packets++; } /* Encapsulate one IP datagram and stuff into a TTY queue. */ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) { - unsigned char *p; - int actual, count; + unsigned char *p; + int actual, count; + - #ifdef CONFIG_AX25 - if(sl->mtu != sl->dev->mtu+73)/* Someone has been ifconfigging */ + if (sl->mtu != sl->dev->mtu + 73) { /* Someone has been ifconfigging */ #else - if(sl->mtu != sl->dev->mtu) /* Someone has been ifconfigging */ + if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */ #endif - sl_changedmtu(sl); - - if(len>sl->mtu) /* Sigh, shouldn't occur BUT ... */ - { - len=sl->mtu; - printk("slip: truncating oversized transmit packet!\n"); - } - - p = icp; -#ifdef CONFIG_INET - if(sl->mode & SL_MODE_CSLIP) - len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); -#endif - if(sl->mode & SL_MODE_SLIP6) - count=slip_esc6(p, (unsigned char *)sl->xbuff,len); - else - count=slip_esc(p, (unsigned char *)sl->xbuff,len); - sl->spacket++; - - /* Tell TTY to send it on its way. */ - actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); - if (actual == count) { - sl_unlock(sl); - mark_bh(NET_BH); - } else { - sl->xhead = sl->xbuff + count; - sl->xtail = sl->xbuff + actual; - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - } + sl_changedmtu(sl); + } + + if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */ + len = sl->mtu; + printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); + sl->tx_dropped++; + sl_unlock(sl); + return; + } + + p = icp; +#ifdef CONFIG_INET + if (sl->mode & SL_MODE_CSLIP) { + len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); + } +#endif +#ifdef CONFIG_SLIP_MODE_SLIP6 + if(sl->mode & SL_MODE_SLIP6) + count = slip_esc6(p, (unsigned char *) sl->xbuff, len); + else +#endif + count = slip_esc(p, (unsigned char *) sl->xbuff, len); + + /* Order of next two lines is *very* important. + * When we are sending a little amount of data, + * the transfer may be completed inside driver.write() + * routine, because it's running with interrupts enabled. + * In this case we *never* got WRITE_WAKEUP event, + * if we did not request it before write operation. + * 14 Oct 1994 Dmitry Gorodchanin. + */ + sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); +#ifdef SL_CHECK_TRANSMIT + sl->dev->trans_start = jiffies; +#endif + sl->xleft = count - actual; + sl->xhead = sl->xbuff + actual; } /* @@ -404,87 +373,76 @@ */ static void slip_write_wakeup(struct tty_struct *tty) { - register int count, answer; + int actual; struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) { - return; - } - - if (!sl->xtail) - return; - - cli(); - if (sl->flags & SLF_XMIT_BUSY) { - sti(); + if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) { return; } - sl->flags |= SLF_XMIT_BUSY; - sti(); - - count = sl->xhead - sl->xtail; - - answer = tty->driver.write(tty, 0, sl->xtail, count); - if (answer == count) { - sl->xtail = 0; - tty->flags &= ~TTY_DO_WRITE_WAKEUP; + if (sl->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet */ + sl->tx_packets++; + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl_unlock(sl); mark_bh(NET_BH); - } else { - sl->xtail += answer; + return; } - sl->flags &= ~SLF_XMIT_BUSY; -} -/*static void sl_hex_dump(unsigned char *x,int l) -{ - int n=0; - printk("sl_xmit: (%d bytes)\n",l); - while(l) - { - printk("%2X ",(int)*x++); - l--; - n++; - if(n%32==0) - printk("\n"); - } - if(n%32) - printk("\n"); -}*/ + actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft); + sl->xleft -= actual; + sl->xhead += actual; +} /* Encapsulate an IP datagram and kick it into a TTY queue. */ static int sl_xmit(struct sk_buff *skb, struct device *dev) { - struct tty_struct *tty; - struct slip *sl; - int size; - - /* Find the correct SLIP channel to use. */ - sl = &sl_ctrl[dev->base_addr]; - tty = sl->tty; - - /* - * If we are busy already- too bad. We ought to be able - * to queue things at this point, to allow for a little - * frame buffer. Oh well... - */ - if (sl->sending) { - sl->sbusy++; - return(1); - } - - /* We were not, so we are now... :-) */ - if (skb != NULL) { - sl_lock(sl); - - size=skb->len; - sl_encaps(sl, skb->data, size); - dev_kfree_skb(skb, FREE_WRITE); - } - return(0); + struct slip *sl = &sl_ctrl[dev->base_addr]; + + if (!dev->start) { + printk("%s: xmit call when iface is down\n", dev->name); + return 1; + } + /* + * If we are busy already- too bad. We ought to be able + * to queue things at this point, to allow for a little + * frame buffer. Oh well... + * ----------------------------------------------------- + * I hate queues in SLIP driver. May be it's efficient, + * but for me latency is more important. ;) + * So, no queues ! + * 14 Oct 1994 Dmitry Gorodchanin. + */ + if (dev->tbusy) { + /* May be we must check transmitter timeout here ? + * 14 Oct 1994 Dmitry Gorodchanin. + */ +#ifdef SL_CHECK_TRANSMIT + if (jiffies - dev->trans_start < 20 * HZ) { + /* 20 sec timeout not reached */ + return 1; + } + printk("%s: transmit timed out, %s?\n", dev->name, + (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? + "bad line quality" : "driver error"); + sl->xleft = 0; + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + sl_unlock(sl); +#else + return 1; +#endif + } + + /* We were not busy, so we are now... :-) */ + if (skb != NULL) { + sl_lock(sl); + sl_encaps(sl, skb->data, skb->len); + dev_kfree_skb(skb, FREE_WRITE); + } + return 0; } @@ -493,11 +451,13 @@ sl_type_trans (struct sk_buff *skb, struct device *dev) { #ifdef CONFIG_AX25 - struct slip *sl=&sl_ctrl[dev->base_addr]; - if(sl->mode&SL_MODE_AX25) + struct slip *sl = &sl_ctrl[dev->base_addr]; + + if (sl->mode & SL_MODE_AX25) { return htons(ETH_P_AX25); + } #endif - return htons(ETH_P_IP); + return htons(ETH_P_IP); } @@ -508,30 +468,32 @@ { #ifdef CONFIG_AX25 #ifdef CONFIG_INET - struct slip *sl=&sl_ctrl[dev->base_addr]; - if((sl->mode&SL_MODE_AX25) && type!=htons(ETH_P_AX25)) - return ax25_encapsulate(buff,dev,type,daddr,saddr,len,skb); -#endif -#endif + struct slip *sl = &sl_ctrl[dev->base_addr]; - return(0); + if ((sl->mode & SL_MODE_AX25) && type != htons(ETH_P_AX25)) { + return ax25_encapsulate(buff, dev, type, daddr, saddr, len, skb); + } +#endif +#endif + return 0; } /* Rebuild the MAC-level header. Not used by SLIP. */ static int sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr, - struct sk_buff *skb) + struct sk_buff *skb) { #ifdef CONFIG_AX25 #ifdef CONFIG_INET - struct slip *sl=&sl_ctrl[dev->base_addr]; - - if(sl->mode&SL_MODE_AX25) - return ax25_rebuild_header(buff,dev,raddr, skb); -#endif -#endif - return(0); + struct slip *sl = &sl_ctrl[dev->base_addr]; + + if (sl->mode & SL_MODE_AX25) { + return ax25_rebuild_header(buff, dev, raddr, skb); + } +#endif +#endif + return 0; } @@ -539,84 +501,84 @@ static int sl_open(struct device *dev) { - struct slip *sl; - unsigned char *p; - unsigned long l; - - sl = &sl_ctrl[dev->base_addr]; - if (sl->tty == NULL) { - return(-ENXIO); - } - sl->dev = dev; - - /* - * Allocate the SLIP frame buffers: - * - * mem_end Top of frame buffers - * mem_start Start of frame buffers - * rmem_end Top of RECV frame buffer - * rmem_start Start of RECV frame buffer - */ - l = (dev->mtu * 2); -/* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (l < (576 * 2)) - l = 576 * 2; + struct slip *sl = &sl_ctrl[dev->base_addr]; + unsigned long len; - p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); - if (p == NULL) { - return(-ENOMEM); - } + if (sl->tty == NULL) { + return -ENXIO; + } + + /* + * Allocate the SLIP frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + len = dev->mtu * 2; + /* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) { + len = 576 * 2; + } + sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sl->rbuff == NULL) { + goto norbuff; + } + sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sl->xbuff == NULL) { + goto noxbuff; + } +#ifdef CONFIG_INET + sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sl->cbuff == NULL) { + goto nocbuff; + } + sl->slcomp = slhc_init(16, 16); + if (sl->slcomp == NULL) { + goto noslcomp; + } +#endif #ifdef CONFIG_AX25 - sl->mtu = dev->mtu+73; -#else - sl->mtu = dev->mtu; -#endif - sl->dev->mem_start = (unsigned long) p; - sl->dev->mem_end = (unsigned long) (sl->dev->mem_start + l); - - p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); - if (p == NULL) { - kfree((unsigned char *)sl->dev->mem_start); - return(-ENOMEM); - } - sl->dev->rmem_start = (unsigned long) p; - sl->dev->rmem_end = (unsigned long) (sl->dev->rmem_start + l); - - sl->xbuff = (unsigned char *) sl->dev->mem_start; - sl->rbuff = (unsigned char *) sl->dev->rmem_start; - sl->rend = (unsigned char *) sl->dev->rmem_end; - sl->rhead = sl->rbuff; - - sl->escape = 0; - sl->sending = 0; - sl->rcount = 0; - - p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); - if (p == NULL) { - kfree((unsigned char *)sl->dev->mem_start); - kfree((unsigned char *)sl->dev->rmem_start); - return(-ENOMEM); - } - sl->cbuff = p; + sl->mtu = dev->mtu + 73; +#else + sl->mtu = dev->mtu; +#endif + sl->buffsize = len; + sl->rcount = 0; + sl->xleft = 0; +#ifdef CONFIG_SLIP_MODE_SLIP6 + sl->xdata = 0; + sl->xbits = 0; +#endif + sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ + sl->mode = SL_MODE_DEFAULT; + + /* Needed because address '0' is special */ + if (dev->pa_addr == 0) { + dev->pa_addr=ntohl(0xC0A80001); + } + dev->tbusy = 0; + dev->flags |= IFF_UP; + dev->start = 1; + + return 0; + + /* Cleanup */ #ifdef CONFIG_INET - sl->slcomp = slhc_init(16, 16); - if (sl->slcomp == NULL) { - kfree((unsigned char *)sl->dev->mem_start); - kfree((unsigned char *)sl->dev->rmem_start); - kfree((unsigned char *)sl->cbuff); - return(-ENOMEM); - } -#endif - dev->flags|=IFF_UP; - /* Needed because address '0' is special */ - if(dev->pa_addr==0) - dev->pa_addr=ntohl(0xC0A80001); - return(0); +noslcomp: + kfree(sl->cbuff); +nocbuff: +#endif + kfree(sl->xbuff); +noxbuff: + kfree(sl->rbuff); +norbuff: + return -ENOMEM; } @@ -624,28 +586,32 @@ static int sl_close(struct device *dev) { - struct slip *sl; - - sl = &sl_ctrl[dev->base_addr]; - if (sl->tty == NULL) { - return(-EBUSY); - } - sl->tty->disc_data = 0; - sl_free(sl); + struct slip *sl = &sl_ctrl[dev->base_addr]; - /* Free all SLIP frame buffers. */ - kfree(sl->rbuff); - kfree(sl->xbuff); - kfree(sl->cbuff); -#ifdef CONFIG_INET - slhc_free(sl->slcomp); + if (sl->tty == NULL) { + return -EBUSY; + } + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + dev->tbusy = 1; + dev->flags &= ~IFF_UP; + + /* Free all SLIP frame buffers. */ + kfree(sl->rbuff); + sl->rbuff = NULL; + kfree(sl->xbuff); + sl->xbuff = NULL; +#ifdef CONFIG_INET + kfree(sl->cbuff); + sl->cbuff = NULL; + slhc_free(sl->slcomp); + sl->slcomp = NULL; #endif - sl_initialize(sl, dev); - - return(0); + dev->start = 0; + return 0; } -static int slip_receive_room(struct tty_struct *tty) +static int +slip_receive_room(struct tty_struct *tty) { return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -656,41 +622,46 @@ * a block of SLIP data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ -static void slip_receive_buf(struct tty_struct *tty, unsigned char *cp, - char *fp, int count) +static void +slip_receive_buf(struct tty_struct *tty, unsigned char *cp, char *fp, int count) { struct slip *sl = (struct slip *) tty->disc_data; - - if (!sl || sl->magic != SLIP_MAGIC) + + if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) return; - + /* * Argh! mtu change time! - costs us the packet part received * at the change */ #ifdef CONFIG_AX25 - if(sl->mtu!=sl->dev->mtu+73) -#else - if(sl->mtu!=sl->dev->mtu) -#endif + if (sl->mtu != sl->dev->mtu + 73) { +#else + if (sl->mtu != sl->dev->mtu) { +#endif sl_changedmtu(sl); - + } + /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - sl->flags |= SLF_ERROR; + if (!set_bit(SLF_ERROR, &sl->flags)) { + sl->rx_errors++; + } cp++; continue; } +#ifdef CONFIG_SLIP_MODE_SLIP6 if (sl->mode & SL_MODE_SLIP6) - slip_unesc6(sl,*cp++); + slip_unesc6(sl, *cp++); else - slip_unesc(sl,*cp++); +#endif + slip_unesc(sl, *cp++); } } /* - * Open the high-level part of the SLIP channel. + * Open the high-level part of the SLIP channel. * This function is called by the TTY module when the * SLIP line discipline is called for. Because we are * sure the tty line exists, we only have to link it to @@ -699,63 +670,39 @@ static int slip_open(struct tty_struct *tty) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = (struct slip *) tty->disc_data; - /* First make sure we're not already connected. */ - if (sl && sl->magic == SLIP_MAGIC) { - return(-EEXIST); - } - - /* OK. Find a free SLIP channel to use. */ - if ((sl = sl_alloc()) == NULL) { - return(-ENFILE); - } - sl->tty = tty; - tty->disc_data = sl; - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + /* First make sure we're not already connected. */ + if (sl && sl->magic == SLIP_MAGIC) { + return -EEXIST; + } - /* Perform the low-level SLIP initialization. */ - (void) sl_open(sl->dev); + /* OK. Find a free SLIP channel to use. */ + if ((sl = sl_alloc()) == NULL) { + return -ENFILE; + } - /* Done. We have linked the TTY line to a channel. */ - return(sl->line); -} + sl->tty = tty; + tty->disc_data = sl; + if (tty->driver.flush_buffer) { + tty->driver.flush_buffer(tty); + } + if (tty->ldisc.flush_buffer) { + tty->ldisc.flush_buffer(tty); + } - -static struct enet_statistics * -sl_get_stats(struct device *dev) -{ - static struct enet_statistics stats; - struct slip *sl; - struct slcompress *comp; - - /* Find the correct SLIP channel to use. */ - sl = &sl_ctrl[dev->base_addr]; - if (! sl) - return NULL; - - memset(&stats, 0, sizeof(struct enet_statistics)); - - stats.rx_packets = sl->rpacket; - stats.rx_over_errors = sl->roverrun; - stats.tx_packets = sl->spacket; - stats.tx_dropped = sl->sbusy; - stats.rx_errors = sl->errors; -#ifdef CONFIG_INET - comp = sl->slcomp; - if (comp) { - stats.rx_fifo_errors = comp->sls_i_compressed; - stats.rx_dropped = comp->sls_i_tossed; - stats.tx_fifo_errors = comp->sls_o_compressed; - stats.collisions = comp->sls_o_misses; - } + /* Perform the low-level SLIP initialization. */ + (void) sl_open(sl->dev); + +#ifdef MODULE + MOD_INC_USE_COUNT; #endif - return (&stats); + + /* Done. We have linked the TTY line to a channel. */ + return sl->dev->base_addr; } + /* * Close down a SLIP channel. * This means flushing out any pending queues, and then restoring the @@ -765,249 +712,324 @@ static void slip_close(struct tty_struct *tty) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = (struct slip *) tty->disc_data; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) { - return; - } + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC) { + return; + } + + (void) dev_close(sl->dev); - (void) dev_close(sl->dev); + tty->disc_data = 0; + sl->tty = NULL; + sl_free(sl); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif } - /************************************************************************ - * STANDARD SLIP ENCAPSULATION * - ************************************************************************ - * - */ - - int - slip_esc(unsigned char *s, unsigned char *d, int len) - { - int count = 0; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - d[count++] = END; - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the SLIP protocol. - */ - - while(len-- > 0) { - switch(*s) { - case END: - d[count++] = ESC; - d[count++] = ESC_END; - break; - case ESC: - d[count++] = ESC; - d[count++] = ESC_ESC; - break; - default: - d[count++] = *s; - } - ++s; - } - d[count++] = END; - return(count); - } - - void - slip_unesc(struct slip *sl, unsigned char s) - { - switch(s) { - case ESC: - sl->flags |= SLF_ESCAPE; - break; - case ESC_ESC: - if (sl->flags & SLF_ESCAPE) - sl_enqueue(sl, ESC); - else - sl_enqueue(sl, s); - sl->flags &= ~SLF_ESCAPE; - break; - case ESC_END: - if (sl->flags & SLF_ESCAPE) - sl_enqueue(sl, END); - else - sl_enqueue(sl, s); - sl->flags &= ~SLF_ESCAPE; - break; - case END: - if (sl->rcount > 2) - sl_bump(sl); - sl_dequeue(sl, sl->rcount); - sl->rcount = 0; - sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); - break; - default: - sl_enqueue(sl, s); - sl->flags &= ~SLF_ESCAPE; - } - } +static struct enet_statistics * +sl_get_stats(struct device *dev) +{ + static struct enet_statistics stats; + struct slip *sl = &sl_ctrl[dev->base_addr]; +#ifdef CONFIG_INET + struct slcompress *comp; +#endif + + if (! sl) { + return NULL; + } + + memset(&stats, 0, sizeof(struct enet_statistics)); + + stats.rx_packets = sl->rx_packets; + stats.tx_packets = sl->tx_packets; + stats.rx_dropped = sl->rx_dropped; + stats.tx_dropped = sl->tx_dropped; + stats.tx_errors = sl->tx_errors; + stats.rx_errors = sl->rx_errors; + stats.rx_over_errors = sl->rx_over_errors; + +#ifdef CONFIG_INET + comp = sl->slcomp; + if (comp) { + stats.rx_fifo_errors = comp->sls_i_compressed; + stats.rx_dropped += comp->sls_i_tossed; + stats.tx_fifo_errors = comp->sls_o_compressed; + stats.collisions = comp->sls_o_misses; + } +#endif /* CONFIG_INET */ + return (&stats); +} + - /************************************************************************ - * 6 BIT SLIP ENCAPSULATION * - ************************************************************************ - * - */ - - int - slip_esc6(unsigned char *s, unsigned char *d, int len) - { - int count = 0; - int i; - unsigned short v = 0; - short bits = 0; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - d[count++] = 0x70; - - /* - * Encode the packet into printable ascii characters - */ - - for (i = 0; i < len; ++i) { - v = (v << 8) | s[i]; - bits += 8; - while (bits >= 6) { - unsigned char c; - - bits -= 6; - c = 0x30 + ((v >> bits) & 0x3F); - d[count++] = c; - } - } - if (bits) { - unsigned char c; - - c = 0x30 + ((v << (6 - bits)) & 0x3F); - d[count++] = c; - } - d[count++] = 0x70; - return(count); - } - - void - slip_unesc6(struct slip *sl, unsigned char s) - { - unsigned char c; - - if (s == 0x70) { - if (sl->rcount > 8) { /* XXX must be 2 for compressed slip */ - #ifdef NOTDEF - printk("rbuff %02x %02x %02x %02x\n", - sl->rbuff[0], - sl->rbuff[1], - sl->rbuff[2], - sl->rbuff[3] - ); - #endif - sl_bump(sl); - } - sl_dequeue(sl, sl->rcount); - sl->rcount = 0; - sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); /* SLF_ESCAPE not used */ - sl->xbits = 0; + * STANDARD SLIP ENCAPSULATION * + ************************************************************************/ + +int +slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = END; + return (ptr - d); +} + +static void +slip_unesc(struct slip *sl, unsigned char s) +{ + + switch(s) { + case END: + if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + sl_bump(sl); + } + clear_bit(SLF_ESCAPE, &sl->flags); + sl->rcount = 0; + return; + + case ESC: + set_bit(SLF_ESCAPE, &sl->flags); + return; + case ESC_ESC: + if (clear_bit(SLF_ESCAPE, &sl->flags)) { + s = ESC; + } + break; + case ESC_END: + if (clear_bit(SLF_ESCAPE, &sl->flags)) { + s = END; + } + break; + } + if (!test_bit(SLF_ERROR, &sl->flags)) { + if (sl->rcount < sl->buffsize) { + sl->rbuff[sl->rcount++] = s; + return; + } + sl->rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } +} + + +#ifdef CONFIG_SLIP_MODE_SLIP6 +/************************************************************************ + * 6 BIT SLIP ENCAPSULATION * + ************************************************************************/ + +int +slip_esc6(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + int i; + unsigned short v = 0; + short bits = 0; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = 0x70; + + /* + * Encode the packet into printable ascii characters + */ + + for (i = 0; i < len; ++i) { + v = (v << 8) | s[i]; + bits += 8; + while (bits >= 6) { + bits -= 6; + c = 0x30 + ((v >> bits) & 0x3F); + *ptr++ = c; + } + } + if (bits) { + c = 0x30 + ((v << (6 - bits)) & 0x3F); + *ptr++ = c; + } + *ptr++ = 0x70; + return ptr - d; +} + +void +slip_unesc6(struct slip *sl, unsigned char s) +{ + unsigned char c; + + if (s == 0x70) { + if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + sl_bump(sl); + } + sl->rcount = 0; + sl->xbits = 0; + sl->xdata = 0; } else if (s >= 0x30 && s < 0x70) { sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); sl->xbits += 6; if (sl->xbits >= 8) { sl->xbits -= 8; c = (unsigned char)(sl->xdata >> sl->xbits); - sl_enqueue(sl, c); + if (!test_bit(SLF_ERROR, &sl->flags)) { + if (sl->rcount < sl->buffsize) { + sl->rbuff[sl->rcount++] = c; + return; + } + sl->rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } } } - } +} +#endif /* CONFIG_SLIP_MODE_SLIP6 */ #ifdef CONFIG_AX25 -int sl_set_mac_address(struct device *dev, void *addr) +int +sl_set_mac_address(struct device *dev, void *addr) { - int err=verify_area(VERIFY_READ,addr,7); - if(err) + int err; + + err = verify_area(VERIFY_READ, addr, 7); + if (err) { return err; - memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */ + } + + memcpy_fromfs(dev->dev_addr, addr, 7); /* addr is an AX.25 shifted ASCII mac address */ + return 0; } -static int sl_set_dev_mac_address(struct device *dev, void *addr) +static int +sl_set_dev_mac_address(struct device *dev, void *addr) { - memcpy(dev->dev_addr,addr,7); + memcpy(dev->dev_addr, addr, 7); return 0; } -#endif + +#endif /* CONFIG_AX25 */ /* Perform I/O control on an active SLIP channel. */ static int slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { - struct slip *sl = (struct slip *) tty->disc_data; - int err; + struct slip *sl = (struct slip *) tty->disc_data; + int err; + unsigned int tmp; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) { - return(-EINVAL); - } - - switch(cmd) { - case SIOCGIFNAME: - err=verify_area(VERIFY_WRITE, arg, 16); - if(err) + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC) { + return -EINVAL; + } + + switch(cmd) { + case SIOCGIFNAME: + err = verify_area(VERIFY_WRITE, arg, 16); + if (err) { return -err; + } memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1); - return(0); + return 0; + case SIOCGIFENCAP: - err=verify_area(VERIFY_WRITE,arg,sizeof(long)); - put_fs_long(sl->mode,(long *)arg); - return(0); + err = verify_area(VERIFY_WRITE, arg, sizeof(long)); + if (err) { + return -err; + } + put_fs_long(sl->mode, (long *)arg); + return 0; + case SIOCSIFENCAP: - err=verify_area(VERIFY_READ,arg,sizeof(long)); - sl->mode=get_fs_long((long *)arg); -#ifdef CONFIG_AX25 - if(sl->mode & SL_MODE_AX25) - { + err = verify_area(VERIFY_READ, arg, sizeof(long)); + if (err) { + return -err; + } + tmp = get_fs_long((long *)arg); +#ifndef CONFIG_INET + if (tmp & SL_MODE_CSLIP) { + return -EINVAL; + } +#endif +#ifndef CONFIG_SLIP_MODE_SLIP6 + if (tmp & SL_MODE_SLIP6) { + return -EINVAL; + } +#endif +#ifndef CONFIG_AX25 + if (tmp & SL_MODE_AX25) { + return -EINVAL; + } +#else + if (tmp & SL_MODE_AX25) { sl->dev->addr_len=7; /* sizeof an AX.25 addr */ sl->dev->hard_header_len=17; /* We don't do digipeaters */ - } - else - { + } else { sl->dev->addr_len=0; /* No mac addr in slip mode */ sl->dev->hard_header_len=0; } -#endif - sl->dev->type=ARPHRD_SLIP+sl->mode; - if(sl->dev->type==260) - sl->dev->type=ARPHRD_AX25; - return(0); - case SIOCSIFHWADDR: -#ifdef CONFIG_AX25 - return sl_set_mac_address(sl->dev,arg); #endif + sl->mode = tmp; + sl->dev->type = ARPHRD_SLIP+sl->mode; + if (sl->dev->type == 260) { + sl->dev->type = ARPHRD_AX25; + } + return 0; + + case SIOCSIFHWADDR: +#ifdef CONFIG_AX25 + return sl_set_mac_address(sl->dev, arg); +#else + return -EINVAL; +#endif + /* Allow stty to read, but not set, the serial port */ case TCGETS: case TCGETA: return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); - + default: return -ENOIOCTLCMD; - } + } } @@ -1015,84 +1037,149 @@ int slip_init(struct device *dev) { - struct slip *sl; - int i; -#ifdef CONFIG_AX25 - static char ax25_bcast[7]={'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[7]={'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + struct slip *sl = &sl_ctrl[dev->base_addr]; + int i; +#ifdef CONFIG_AX25 + static char ax25_bcast[7] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[7] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; #endif - sl = &sl_ctrl[dev->base_addr]; - - if (already++ == 0) { - printk("SLIP: version %s (%d channels)\n", - SLIP_VERSION, SL_NRUNIT); -#ifdef SL_COMPRESSED - printk("CSLIP: code copyright 1989 Regents of the University of California\n"); + if (already++ == 0) { + printk("SLIP: version %s (%d channels) %s\n", + SLIP_VERSION, SL_NRUNIT, +#ifdef CONFIG_SLIP_MODE_SLIP6 + "(6 bit encapsulation enabled)" +#else + "" +#endif + ); +#if defined(CONFIG_INET) && !defined(MODULE) + printk("CSLIP: code copyright 1989 Regents of the University of California\n"); #endif #ifdef CONFIG_AX25 - printk("AX25: KISS encapsulation enabled\n"); + printk("AX25: KISS encapsulation enabled\n"); #endif - /* Fill in our LDISC request block. */ - memset(&sl_ldisc, 0, sizeof(sl_ldisc)); - sl_ldisc.magic = TTY_LDISC_MAGIC; - sl_ldisc.flags = 0; - sl_ldisc.open = slip_open; - sl_ldisc.close = slip_close; - sl_ldisc.read = NULL; - sl_ldisc.write = NULL; - sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long)) slip_ioctl; - sl_ldisc.select = NULL; - sl_ldisc.receive_buf = slip_receive_buf; - sl_ldisc.receive_room = slip_receive_room; - sl_ldisc.write_wakeup = slip_write_wakeup; - if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) - printk("ERROR: %d\n", i); - } - - /* Set up the "SLIP Control Block". */ - sl_initialize(sl, dev); - - /* Clear all statistics. */ - sl->rcount = 0; /* SLIP receiver count */ - sl->rpacket = 0; /* #frames received */ - sl->roverrun = 0; /* "overrun" counter */ - sl->spacket = 0; /* #frames sent out */ - sl->sbusy = 0; /* "xmit busy" counter */ - sl->errors = 0; /* not used at present */ - - /* Finish setting up the DEVICE info. */ - dev->mtu = SL_MTU; - dev->hard_start_xmit = sl_xmit; - dev->open = sl_open; - dev->stop = sl_close; - dev->hard_header = sl_header; - dev->type_trans = sl_type_trans; - dev->get_stats = sl_get_stats; + /* Fill in our LDISC request block. */ + memset(&sl_ldisc, 0, sizeof(sl_ldisc)); + sl_ldisc.magic = TTY_LDISC_MAGIC; + sl_ldisc.flags = 0; + sl_ldisc.open = slip_open; + sl_ldisc.close = slip_close; + sl_ldisc.read = NULL; + sl_ldisc.write = NULL; + sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) slip_ioctl; + sl_ldisc.select = NULL; + sl_ldisc.receive_buf = slip_receive_buf; + sl_ldisc.receive_room = slip_receive_room; + sl_ldisc.write_wakeup = slip_write_wakeup; + if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { + printk("SLIP: can't register line discipline (err = %d)\n", i); + } + } + + /* Set up the "SLIP Control Block". (And clear statistics) */ + sl_initialize(sl, dev); + + /* Finish setting up the DEVICE info. */ + dev->mtu = SL_MTU; + dev->hard_start_xmit = sl_xmit; + dev->open = sl_open; + dev->stop = sl_close; + dev->hard_header = sl_header; + dev->type_trans = sl_type_trans; + dev->get_stats = sl_get_stats; #ifdef HAVE_SET_MAC_ADDR #ifdef CONFIG_AX25 - dev->set_mac_address = sl_set_dev_mac_address; + dev->set_mac_address = sl_set_dev_mac_address; +#endif #endif + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = 0; +#ifdef CONFIG_AX25 + memcpy(dev->broadcast, ax25_bcast, 7); /* Only activated in AX.25 mode */ + memcpy(dev->dev_addr, ax25_test, 7); /* "" "" "" "" */ #endif - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = 0; -#ifdef CONFIG_AX25 - memcpy(dev->broadcast,ax25_bcast,7); /* Only activated in AX.25 mode */ - memcpy(dev->dev_addr,ax25_test,7); /* "" "" "" "" */ -#endif - dev->rebuild_header = sl_rebuild_header; - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&dev->buffs[i]); - - /* New-style flags. */ - dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); + dev->rebuild_header = sl_rebuild_header; + + for (i = 0; i < DEV_NUMBUFFS; i++) { + skb_queue_head_init(&dev->buffs[i]); + } - return(0); + /* New-style flags. */ + dev->flags = 0; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); + + return 0; +} +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; + +static struct device dev_slip[SL_NRUNIT] = { + { + "sl0", /* slip */ + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, slip_init, + }, + { "sl1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, slip_init }, + { "sl2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, slip_init }, + { "sl3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, slip_init }, +#ifdef SL_SLIP_LOTS + { "sl4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, slip_init }, + { "sl5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, slip_init }, + { "sl6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, slip_init }, + { "sl7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, slip_init }, + { "sl8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, slip_init }, + { "sl9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, slip_init }, + { "sl10", 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, slip_init }, + { "sl11", 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, slip_init }, + { "sl12", 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, slip_init }, + { "sl13", 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, slip_init }, + { "sl14", 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, slip_init }, + { "sl15", 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, slip_init }, +#endif /* SL_SLIP_LOTS */ +}; + +int +init_module(void) +{ + int err; + int i; + + for (i = 0; i < SL_NRUNIT; i++) { + if ((err = register_netdev(&dev_slip[i]))) { + if (err == -EEXIST) { + printk("SLIP: devices already present. Module not loaded.\n"); + } + return err; + } + } + return 0; +} + +void +cleanup_module(void) +{ + int i; + + if (MOD_IN_USE) { + printk("SLIP: device busy, remove delayed\n"); + return; + } + for (i = 0; i < SL_NRUNIT; i++) { + unregister_netdev(&dev_slip[i]); + } + if ((i = tty_register_ldisc(N_SLIP, NULL))) { + printk("SLIP: can't unregister line discipline (err = %d)\n", i); + } + already = 0; } +#endif /* MODULE */ diff -u --recursive --new-file v1.1.72/linux/drivers/net/slip.h linux/drivers/net/slip.h --- v1.1.72/linux/drivers/net/slip.h Fri Aug 19 08:53:24 1994 +++ linux/drivers/net/slip.h Mon Dec 12 21:01:09 1994 @@ -10,6 +10,7 @@ * Alan Cox : Added slip mtu field. * Matt Dillon : Printable slip (borrowed from net2e) * Alan Cox : Added SL_SLIP_LOTS + * Dmitry Gorodchanin : A lot of changes in the 'struct slip' * * Author: Fred N. van Kempen, */ @@ -33,44 +34,44 @@ struct slip { int magic; - /* Bitmapped flag fields. */ - char inuse; /* are we allocated? */ - char sending; /* "channel busy" indicator */ - char escape; /* SLIP state machine */ - char unused; /* fillers */ /* Various fields. */ - int line; /* SLIP channel number */ struct tty_struct *tty; /* ptr to TTY structure */ struct device *dev; /* easy for intr handling */ +#if defined(CONFIG_INET) struct slcompress *slcomp; /* for header compression */ + unsigned char *cbuff; /* compression buffer */ +#endif /* These are pointers to the malloc()ed frame buffers. */ unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ unsigned char *xbuff; /* transmitter buffer */ - unsigned char *cbuff; /* compression buffer */ - - /* These are the various pointers into the buffers. */ - unsigned char *rhead; /* RECV buffer pointer (head) */ - unsigned char *rend; /* RECV buffer pointer (end) */ - int rcount; /* SLIP receive counter */ - unsigned char *xhead; /* XMIT buffer pointer (head) */ - unsigned char *xtail; /* XMIT buffer pointer (tail) */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ /* SLIP interface statistics. */ - unsigned long rpacket; /* inbound frame counter */ - unsigned long roverrun; /* "buffer overrun" counter */ - unsigned long spacket; /* outbound frames counter */ - unsigned long sbusy; /* "transmitter busy" counter */ - unsigned long errors; /* error count */ - + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Palnned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ + /* Detailed SLIP statistics. */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + +#ifdef CONFIG_SLIP_MODE_SLIP6 + int xdata, xbits; /* 6 bit slip controls */ +#endif + unsigned char flags; /* Flag values/ mode etc */ -#define SLF_ESCAPE 2 -#define SLF_ERROR 4 -#define SLF_COMP 16 -#define SLF_EXPN 32 -#define SLF_XMIT_BUSY 64 +#define SLF_INUSE 0 /* Channel in use */ +#define SLF_ESCAPE 1 /* ESC received */ +#define SLF_ERROR 2 /* Parity, etc. error */ + unsigned char mode; /* SLIP mode */ #define SL_MODE_SLIP 0 #define SL_MODE_CSLIP 1 @@ -78,15 +79,25 @@ #define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP) #define SL_MODE_AX25 4 #define SL_MODE_ADAPTIVE 8 - int xdata,xbits; /* 6 bit slip controls */ }; +#ifdef CONFIG_INET +#ifdef CONFIG_SLIP_ADAPTIVE +#define SL_MODE_DEFAULT SL_MODE_ADAPTIVE +#else /* !CONFIG_SLIP_ADAPTIVE */ +#ifdef CONFIG_SLIP_COMPRESSED +#define SL_MODE_DEFAULT (SL_MODE_CSLIP | SL_MODE_ADAPTIVE) +#else /* !CONFIG_SLIP_COMPRESSED */ +#define SL_MODE_DEFAULT SL_MODE_SLIP +#endif /* CONFIG_SLIP_COMPRESSED */ +#endif /* CONFIG_SLIP_ADAPTIVE */ +#else /* !CONFIG_INET */ +#define SL_MODE_DEFAULT SL_MODE_SLIP +#endif /* CONFIG_INET */ + + #define SLIP_MAGIC 0x5302 -extern int slip_init(struct device *dev); -extern int slip_esc(unsigned char *s, unsigned char *d, int len); -extern int slip_esc6(unsigned char *s, unsigned char *d, int len); -extern void slip_unesc(struct slip *sl, unsigned char s); -extern void slip_unesc6(struct slip *sl, unsigned char s); +extern int slip_init(struct device *dev); #endif /* _LINUX_SLIP.H */ diff -u --recursive --new-file v1.1.72/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v1.1.72/linux/drivers/net/smc-ultra.c Sun Oct 9 19:28:49 1994 +++ linux/drivers/net/smc-ultra.c Wed Dec 7 09:15:34 1994 @@ -17,7 +17,7 @@ */ static char *version = - "smc-ultra.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + "smc-ultra.c:v1.11 11/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; #include #include @@ -226,16 +226,21 @@ void *xfer_start = (void *)(dev->mem_start + ring_offset - (START_PG<<8)); + /* Enable shared memory. */ + outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); + if (xfer_start + count > (void*) dev->rmem_end) { /* We must wrap the input move. */ int semi_count = (void*)dev->rmem_end - xfer_start; memcpy(buf, xfer_start, semi_count); count -= semi_count; memcpy(buf + semi_count, (char *)dev->rmem_start, count); + outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ return dev->rmem_start + count; } memcpy(buf, xfer_start, count); + outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ return ring_offset + count; } @@ -246,8 +251,12 @@ unsigned char *shmem = (unsigned char *)dev->mem_start + ((start_page - START_PG)<<8); + /* Enable shared memory. */ + outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); + memcpy(shmem, buf, count); + outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ } static int diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog --- v1.1.72/linux/drivers/scsi/ChangeLog Sat Dec 3 13:05:42 1994 +++ linux/drivers/scsi/ChangeLog Mon Dec 12 20:35:51 1994 @@ -1,3 +1,92 @@ +Tue Dec 6 12:34:20 1994 Eric Youngdale (eric@andante) + + * Linux 1.1.72 released. + + * sg.c: Bugfix - always use sg_free, since we might have big buff. + +Fri Dec 2 11:24:53 1994 Eric Youngdale (eric@andante) + + * Linux 1.1.71 released. + + * sg.c: Clear buff field when not in use. Only call scsi_free if + non-null. + + * scsi.h: Call wake_up(&wait_for_request) when done with a + command. + + * scsi.c (scsi_times_out): Pass pid down so that we can protect + against race conditions. + + * scsi.c (scsi_abort): Zero timeout field if we get the + NOT_RUNNING message back from low-level driver. + + + * scsi.c (scsi_done): Restore cmd_len, use_sg here. + + * scsi.c (request_sense): Not here. + + * hosts.h: Add new forbidden_addr, forbidden_size fields. Who + added these and why???? + + * hosts.c (scsi_mem_init): Mark pages as reserved if they fall in + the forbidden regions. I am not sure - I think this is so that + we can deal with boards that do incomplete decoding of their + address lines for the bios chips, but I am not entirely sure. + + * buslogic.c: Set forbidden_addr stuff if using a buggy board. + + * aha1740.c: Test for NULL pointer in SCtmp. This should not + occur, but a nice message is better than a kernel segfault. + + * 53c7,8xx.c: Add new PCI chip ID for 815. + +Fri Dec 2 11:24:53 1994 Eric Youngdale (eric@andante) + + * Linux 1.1.70 released. + + * ChangeLog, st.c: Spelling. + +Tue Nov 29 18:48:42 1994 Eric Youngdale (eric@andante) + + * Linux 1.1.69 released. + + * u14-34f.h: Non-functional change. [Dario]. + + * u14-34f.c: Use block field in Scsi_Host to prevent commands from + being queued to more than one host at the same time (used when + motherboard does not deal with multiple bus-masters very well). + Only when SINGLE_HOST_OPERATIONS is defined. + Use new cmd_per_lun field. [Dario] + + * eata.c: Likewise. + + * st.c: More changes from Kai. Add ready flag to indicate drive + status. + + * README.st: Document this. + + * sr.c: Bugfix (do not subtract CD_BLOCK_OFFSET) for photo-cd + code. + + * sg.c: Bugfix - fix problem where opcode is not correctly set up. + + * seagate.[c,h]: Use #defines to set driver name. + + * scsi_ioctl.c: Zero buffer before executing command. + + * scsi.c: Use new cmd_per_lun field in Scsi_Hosts as appropriate. + Add Sony CDU55S to blacklist. + + * hosts.h: Add new cmd_per_lun field to Scsi_Hosts. + + * hosts.c: Initialize cmd_per_lun in Scsi_Hosts from template. + + * buslogic.c: Use cmd_per_lun field - initialize to different + values depending upon bus type (i.e. use 1 if ISA, so we do not + hog memory). Use other patches which got lost from 1.1.68. + + * aha1542.c: Spelling. + Tue Nov 29 15:43:50 1994 Eric Youngdale (eric@andante.aib.com) * Linux 1.1.68 released. diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c --- v1.1.72/linux/drivers/scsi/buslogic.c Mon Dec 5 18:47:55 1994 +++ linux/drivers/scsi/buslogic.c Wed Dec 14 12:03:13 1994 @@ -1,13 +1,17 @@ /* - * buslogic.c (C) 1993, 1994 David B. Gentzel + * buslogic.c Copyright (C) 1993, 1994 David B. Gentzel * Low-level scsi driver for BusLogic adapters * by David B. Gentzel, Whitfield Software Services, Carnegie, PA * (gentzel@nova.enet.dec.com) * Thanks to BusLogic for providing the necessary documentation * - * The original version of this driver was derived from aha1542.[ch] which - * is Copyright (C) 1992 Tommy Thorn. Much has been reworked, but most of - * basic structure and substantial chunks of code still remain. + * The original version of this driver was derived from aha1542.[ch], + * which is Copyright (C) 1992 Tommy Thorn. Much has been reworked, but + * most of basic structure and substantial chunks of code still remain. + * + * Furthermore, many subsequent fixes and improvements to the aha1542 + * driver have been folded back into this driver. These changes to + * aha1542.[ch] are Copyright (C) 1993, 1994 Eric Youngdale. * * Thanks to the following individuals who have made contributions (of * (code, information, support, or testing) to this driver: @@ -94,6 +98,9 @@ # define BUSLOGIC_DEBUG 0 #endif +/* ??? Until kmalloc actually implements GFP_DMA, we can't depend on it... */ +#undef GFP_DMA + /* If different port addresses are needed (e.g. to install more than two cards), you must define BUSLOGIC_PORT_OVERRIDE to be a comma-separated list of the addresses which will be checked. This can also be used to resolve a @@ -106,7 +113,7 @@ The test is believed to fail on at least some AMI BusLogic clones. */ /* #define BIOS_TRANSLATION_OVERRIDE BIOS_TRANSLATION_BIG */ -#define BUSLOGIC_VERSION "1.13" +#define BUSLOGIC_VERSION "1.14" /* Not a random value - if this is too large, the system hangs for a long time waiting for something to happen if a board is not installed. */ @@ -134,13 +141,17 @@ /* BusLogic boards can be configured for quite a number of port addresses (six to be exact), but I generally do not want the driver poking around at random. We allow two port addresses - this allows people to use a BusLogic - with a MIDI card, which frequently also uses 0x330. */ -static const unsigned int bases[] = { + with a MIDI card, which frequently also uses 0x330. + + This can also be overridden on the command line to the kernel, via LILO or + LODLIN. */ +static unsigned short bases[7] = { #ifdef BUSLOGIC_PORT_OVERRIDE - BUSLOGIC_PORT_OVERRIDE + BUSLOGIC_PORT_OVERRIDE, #else - 0x330, 0x334, /* 0x130, 0x134, 0x230, 0x234 */ + 0x330, 0x334, /* 0x130, 0x134, 0x230, 0x234, */ #endif + 0 }; #define BIOS_TRANSLATION_DEFAULT 0 /* Default case */ @@ -168,7 +179,14 @@ #define INTR_RESET(base) outb(RINT, CONTROL(base)) -#define buslogic_printk buslogic_prefix(),printk +#define buslogic_printk buslogic_prefix(__PRETTY_FUNCTION__),printk + +#if defined(MODULE) && !defined(GFP_DMA) +# define CHECK_DMA_ADDR(isa, addr, badstmt) \ + do { if ((isa) && (addr) > (void *)ISA_DMA_THRESHOLD) badstmt; } while (0) +#else +# define CHECK_DMA_ADDR(isa, addr, badstmt) +#endif #define CHECK(cond) if (cond) ; else goto fail @@ -203,9 +221,9 @@ } } -static void buslogic_prefix(void) +static void buslogic_prefix(const char *func) { - printk("BusLogic SCSI: "); + printk("BusLogic SCSI: %s: ", func); } static void buslogic_stat(unsigned int base) @@ -244,7 +262,7 @@ return FALSE; fail: sti(); - buslogic_printk("buslogic_out failed(%u): ", len + 1); + buslogic_printk("failed(%u): ", len + 1); buslogic_stat(base); return TRUE; } @@ -264,7 +282,7 @@ fail: sti(); #if (BUSLOGIC_DEBUG & BD_IO) - buslogic_printk("buslogic_in failed(%u): ", len + 1); + buslogic_printk("failed(%u): ", len + 1); buslogic_stat(base); #endif return TRUE; @@ -385,7 +403,7 @@ # endif #endif if (errstr != NULL) - buslogic_printk("makecode: %s (%02X)\n", errstr, haerr); + buslogic_printk("%s (%02X)\n", errstr, haerr); return (hosterr << 16) | scsierr; } @@ -413,7 +431,7 @@ shpnt = host[irqno - 9]; if (!shpnt) - panic("buslogic.c: NULL SCSI host entry"); + panic("buslogic_interrupt: NULL SCSI host entry"); mb = HOSTDATA(shpnt)->mb; ccb = HOSTDATA(shpnt)->ccbs; @@ -422,7 +440,7 @@ #if (BUSLOGIC_DEBUG & BD_INTERRUPT) flag = inb(INTERRUPT(base)); - buslogic_printk("buslogic_interrupt: "); + buslogic_printk(""); if (!(flag & INTV)) printk("no interrupt? "); if (flag & IMBL) @@ -447,7 +465,7 @@ is sufficient. A SCSI reset detected is something that we really need to deal with in some way. */ if (flag & (MBOR | CMDC | RSTS)) { - buslogic_printk("Unusual flag:"); + buslogic_printk("unusual flag:"); if (flag & MBOR) printk(" MBOR"); if (flag & CMDC) @@ -503,7 +521,7 @@ #if (BUSLOGIC_DEBUG & BD_INTERRUPT) if (ccb[mbo].tarstat || ccb[mbo].hastat) - buslogic_printk("buslogic_interrupt: returning %08X (status %d)\n", + buslogic_printk("returning %08X (status %d).\n", ((int)ccb[mbo].hastat << 16) | ccb[mbo].tarstat, mb[mbi].status); #endif @@ -518,7 +536,7 @@ sctmp = HOSTDATA(shpnt)->sc[mbo]; if (!sctmp || !sctmp->scsi_done) { - buslogic_printk("buslogic_interrupt: Unexpected interrupt\n"); + buslogic_printk("unexpected interrupt.\n"); buslogic_printk("tarstat=%02X, hastat=%02X id=%d lun=%d ccb#=%u\n", ccb[mbo].tarstat, ccb[mbo].hastat, ccb[mbo].id, ccb[mbo].lun, mbo); @@ -544,14 +562,14 @@ if (status_byte(ccb[mbo].tarstat) == CHECK_CONDITION) { size_t i; - buslogic_printk("buslogic_interrupt: sense:"); + buslogic_printk("sense:"); for (i = 0; i < sizeof sctmp->sense_buffer; i++) printk(" %02X", sctmp->sense_buffer[i]); printk("\n"); } if (errstatus) - buslogic_printk("buslogic_interrupt: returning %08X\n", errstatus); + buslogic_printk("returning %08X.\n", errstatus); #endif sctmp->result = errstatus; @@ -577,6 +595,7 @@ int mbo; struct mailbox *mb; struct ccb *ccb; + struct Scsi_Host *shpnt = scpnt->host; #if (BUSLOGIC_DEBUG & BD_COMMAND) if (target > 1) { @@ -589,8 +608,8 @@ if (*cmd == REQUEST_SENSE) { #if (BUSLOGIC_DEBUG & (BD_COMMAND | BD_ERRORS)) if (bufflen != sizeof scpnt->sense_buffer) { - buslogic_printk("Wrong buffer length supplied for request sense" - " (%d)\n", + buslogic_printk("wrong buffer length supplied for request sense" + " (%d).\n", bufflen); } #endif @@ -608,11 +627,10 @@ i = *(int *)(cmd + 2); else i = -1; - buslogic_printk("buslogic_queuecommand:" - " dev %d cmd %02X pos %d len %d ", + buslogic_printk("dev %d cmd %02X pos %d len %d ", target, *cmd, i, bufflen); - buslogic_stat(scpnt->host->io_port); - buslogic_printk("buslogic_queuecommand: dumping scsi cmd:"); + buslogic_stat(shpnt->io_port); + buslogic_printk("dumping scsi cmd:"); for (i = 0; i < scpnt->cmd_len; i++) printk(" %02X", cmd[i]); printk("\n"); @@ -621,38 +639,40 @@ } #endif - mb = HOSTDATA(scpnt->host)->mb; - ccb = HOSTDATA(scpnt->host)->ccbs; + mb = HOSTDATA(shpnt)->mb; + ccb = HOSTDATA(shpnt)->ccbs; /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them. */ cli(); - mbo = HOSTDATA(scpnt->host)->last_mbo_used + 1; + mbo = HOSTDATA(shpnt)->last_mbo_used + 1; if (mbo >= BUSLOGIC_MAILBOXES) mbo = 0; do { if (mb[mbo].status == MBX_NOT_IN_USE - && HOSTDATA(scpnt->host)->sc[mbo] == NULL) + && HOSTDATA(shpnt)->sc[mbo] == NULL) break; mbo++; if (mbo >= BUSLOGIC_MAILBOXES) mbo = 0; - } while (mbo != HOSTDATA(scpnt->host)->last_mbo_used); + } while (mbo != HOSTDATA(shpnt)->last_mbo_used); - if (mb[mbo].status != MBX_NOT_IN_USE || HOSTDATA(scpnt->host)->sc[mbo]) { - /* ??? Instead of panicing, should we enable OMBR interrupts and - sleep until we get one? */ - panic("buslogic.c: unable to find empty mailbox"); + if (mb[mbo].status != MBX_NOT_IN_USE || HOSTDATA(shpnt)->sc[mbo]) { + /* ??? Instead of failing, should we enable OMBR interrupts and sleep + until we get one? */ + sti(); + buslogic_printk("unable to find empty mailbox.\n"); + goto fail; } - HOSTDATA(scpnt->host)->sc[mbo] = scpnt; /* This will effectively + HOSTDATA(shpnt)->sc[mbo] = scpnt; /* This will effectively prevent someone else from screwing with this cdb. */ - HOSTDATA(scpnt->host)->last_mbo_used = mbo; + HOSTDATA(shpnt)->last_mbo_used = mbo; sti(); @@ -685,17 +705,20 @@ w/scatter-gather */ scpnt->host_scribble = (unsigned char *)scsi_malloc(BUSLOGIC_SG_MALLOC); - if (scpnt->host_scribble == NULL) - panic("buslogic.c: unable to allocate DMA memory"); + if (scpnt->host_scribble == NULL) { + buslogic_printk("unable to allocate DMA memory.\n"); + goto fail; + } sgpnt = (struct scatterlist *)scpnt->request_buffer; cptr = (struct chain *)scpnt->host_scribble; - if (scpnt->use_sg > scpnt->host->sg_tablesize) { - buslogic_printk("buslogic_queuecommand: bad segment list," - " %d > %d\n", - scpnt->use_sg, scpnt->host->sg_tablesize); - panic("buslogic.c: bad segment list"); + if (scpnt->use_sg > shpnt->sg_tablesize) { + buslogic_printk("bad segment list, %d > %d.\n", + scpnt->use_sg, shpnt->sg_tablesize); + goto fail; } for (i = 0; i < scpnt->use_sg; i++) { + CHECK_DMA_ADDR(shpnt->unchecked_isa_dma, sgpnt[i].address, + goto baddma); cptr[i].dataptr = sgpnt[i].address; cptr[i].datalen = sgpnt[i].length; } @@ -715,6 +738,7 @@ } else { ccb[mbo].op = CCB_OP_INIT; /* SCSI Initiator Command */ scpnt->host_scribble = NULL; + CHECK_DMA_ADDR(shpnt->unchecked_isa_dma, buff, goto baddma); ccb[mbo].datalen = bufflen; ccb[mbo].dataptr = buff; } @@ -730,7 +754,7 @@ { size_t i; - buslogic_printk("buslogic_queuecommand: sending..."); + buslogic_printk("sending..."); for (i = 0; i < sizeof ccb[mbo] - 10; i++) printk(" %02X", ((unsigned char *)&ccb[mbo])[i]); printk("\n"); @@ -739,18 +763,28 @@ if (done) { #if (BUSLOGIC_DEBUG & BD_COMMAND) - buslogic_printk("buslogic_queuecommand: now waiting for interrupt: "); - buslogic_stat(scpnt->host->io_port); + buslogic_printk("now waiting for interrupt: "); + buslogic_stat(shpnt->io_port); #endif scpnt->scsi_done = done; mb[mbo].status = MBX_ACTION_START; /* start scsi command */ - buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd); + buslogic_out(shpnt->io_port, buscmd, sizeof buscmd); #if (BUSLOGIC_DEBUG & BD_COMMAND) - buslogic_stat(scpnt->host->io_port); + buslogic_stat(shpnt->io_port); #endif } else - buslogic_printk("buslogic_queuecommand: done can't be NULL\n"); + buslogic_printk("done can't be NULL.\n"); + + while (0) { +#if defined(MODULE) && !defined(GFP_DMA) + baddma: + buslogic_printk("address > 16MB used for ISA HA.\n"); +#endif + fail: + scpnt->result = DID_ERROR << 16; + done(scpnt); + } return 0; } @@ -764,7 +798,7 @@ int buslogic_command(Scsi_Cmnd *scpnt) { #if (BUSLOGIC_DEBUG & BD_COMMAND) - buslogic_printk("buslogic_command: calling buslogic_queuecommand\n"); + buslogic_printk("calling buslogic_queuecommand.\n"); #endif buslogic_queuecommand(scpnt, internal_done); @@ -802,7 +836,7 @@ while (0) { fail: - buslogic_printk("buslogic_detect: failed setting up mailboxes\n"); + buslogic_printk("failed setting up mailboxes.\n"); } INTR_RESET(base); @@ -820,7 +854,7 @@ int i; #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("getconfig: called\n"); + buslogic_printk("called\n"); #endif i = inb(STATUS(base)); @@ -854,8 +888,8 @@ *irq = 15; break; default: - buslogic_printk("Unable to determine BusLogic IRQ level." - " Disabling board.\n"); + buslogic_printk("unable to determine BusLogic IRQ level, " + " disabling board.\n"); goto fail; } *id = inquiry_result[2] & 0x7; @@ -898,8 +932,8 @@ *dma = 7; break; default: - buslogic_printk("Unable to determine BusLogic DMA channel." - " Disabling board.\n"); + buslogic_printk("unable to determine BusLogic DMA channel," + " disabling board.\n"); goto fail; } else @@ -908,7 +942,7 @@ while (0) { fail: #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("buslogic_detect: query board settings\n"); + buslogic_printk("query board settings\n"); #endif return TRUE; } @@ -930,7 +964,7 @@ unsigned int i; #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("buslogic_query: called\n"); + buslogic_printk("called\n"); #endif /* Quick and dirty test for presence of the card. */ @@ -983,7 +1017,7 @@ firmware_rev[2] = inquiry_result[3]; firmware_rev[3] = '\0'; #if 0 - buslogic_printk("Inquiry Bytes: %02X(%c) %02X(%c)\n", + buslogic_printk("inquiry bytes: %02X(%c) %02X(%c)\n", inquiry_result[0], inquiry_result[0], inquiry_result[1], inquiry_result[1]); #endif @@ -1050,13 +1084,15 @@ /* bus_type from getconfig doesn't differentiate between EISA/VESA. We override using the model number here. */ - /* ??? What bus_type gets returned for PCI? */ switch (*bus_type) { case 'E': switch (model[0]) { case '4': *bus_type = 'V'; break; + case '9': + *bus_type = 'P'; + break; case '7': break; default: @@ -1071,7 +1107,7 @@ while (0) { fail: #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("buslogic_query: query board settings\n"); + buslogic_printk("query board settings\n"); #endif return TRUE; } @@ -1094,14 +1130,15 @@ char *firmware_rev; struct Scsi_Host *shpnt; size_t indx; + int unchecked_isa_dma; int count = 0; #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("buslogic_detect:\n"); + buslogic_printk("called\n"); #endif tpnt->can_queue = BUSLOGIC_MAILBOXES; - for (indx = 0; indx < ARRAY_SIZE(bases); indx++) + for (indx = 0; bases[indx] != 0; indx++) if (!check_region(bases[indx], 4)) { shpnt = scsi_register(tpnt, sizeof (struct hostdata)); @@ -1117,13 +1154,45 @@ buslogic_stat(base); #endif + /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */ + unchecked_isa_dma = (bus_type == 'A'); +#ifndef CONFIG_NO_BUGGY_BUSLOGIC + /* There is a hardware bug in the BT-445S prior to revision D. + When the BIOS is enabled and you have more than 16MB of memory, + the card mishandles memory transfers over 16MB which (if viewed + as a 24-bit address) overlap with the BIOS address space. For + example if you have the BIOS located at physical address + 0xDC000 and a DMA transfer from the card to RAM starts at + physical address 0x10DC000 then the transfer is messed up. To + be more precise every fourth byte of the transfer is messed up. + (This analysis courtesy of Tomas Hurka, author of the NeXTSTEP + BusLogic driver.) */ + + if (bus_type == 'V' /* 445 */ + && firmware_rev[0] <= '3' /* S */ + && bios != NULL) { /* BIOS enabled */ +#if 1 + /* Now that LNZ's forbidden_addr stuff is in the higher level + scsi code, we can use this instead. */ + /* Avoid addresses which "mirror" the BIOS for DMA. */ + shpnt->forbidden_addr = (unsigned long)bios; + shpnt->forbidden_size = 16 * 1024; +#else + /* Use double-buffering. */ + unchecked_isa_dma = TRUE; +#endif + } +#endif + + CHECK_DMA_ADDR(unchecked_isa_dma, shpnt, goto unregister); + if (setup_mailboxes(base, shpnt)) goto unregister; /* Set the Bus on/off-times as not to ruin floppy performance. CMD_BUSOFF_TIME is a noop for EISA boards (and possibly others???). */ - if (bus_type != 'E') { + if (bus_type != 'E' && bus_type != 'P') { /* The default ON/OFF times for BusLogic adapters is 7/4. */ static const unsigned char oncmd[] = { CMD_BUSON_TIME, 7 }; static const unsigned char offcmd[] = { CMD_BUSOFF_TIME, 5 }; @@ -1136,19 +1205,18 @@ WAIT_UNTIL(INTERRUPT(base), CMDC); while (0) { fail: - buslogic_printk("buslogic_detect:" - " setting bus on/off-time failed\n"); + buslogic_printk("setting bus on/off-time failed.\n"); } INTR_RESET(base); } - buslogic_printk("Configuring %s HA at port 0x%03X, IRQ %u", + buslogic_printk("configuring %s HA at port 0x%03X, IRQ %u", (bus_type == 'A' ? "ISA" : (bus_type == 'E' ? "EISA" : (bus_type == 'M' ? "MCA" : (bus_type == 'P' ? "PCI" : (bus_type == 'V' ? "VESA" - : (bus_type == 'X' ? "EISA/VESA" + : (bus_type == 'X' ? "EISA/VESA/PCI" : "Unknown")))))), base, irq); if (bios != NULL) @@ -1161,20 +1229,19 @@ if (model[0]) printk(" (revision %d)", model[6]); printk("\n"); - buslogic_printk("Firmware revision: %s\n", firmware_rev); + buslogic_printk("firmware revision: %s\n", firmware_rev); #if (BUSLOGIC_DEBUG & BD_DETECT) buslogic_stat(base); #endif #if (BUSLOGIC_DEBUG & BD_DETECT) - buslogic_printk("buslogic_detect: enable interrupt channel %d\n", - irq); + buslogic_printk("enable interrupt channel %d.\n", irq); #endif cli(); if (request_irq(irq, buslogic_interrupt, 0, "buslogic")) { - buslogic_printk("Unable to allocate IRQ for " + buslogic_printk("unable to allocate IRQ for " "BusLogic controller.\n"); sti(); goto unregister; @@ -1182,7 +1249,7 @@ if (dma) { if (request_dma(dma, "buslogic")) { - buslogic_printk("Unable to allocate DMA channel for " + buslogic_printk("unable to allocate DMA channel for " "BusLogic controller.\n"); free_irq(irq); sti(); @@ -1198,50 +1265,22 @@ host[irq - 9] = shpnt; shpnt->this_id = id; - /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */ - shpnt->unchecked_isa_dma = (bus_type == 'A'); -#ifndef CONFIG_NO_BUGGY_BUSLOGIC - /* There is a hardware bug in the BT-445S prior to revision D. - When the BIOS is enabled and you have more than 16MB of memory, - the card mishandles memory transfers over 16MB which (if viewed - as a 24-bit address) overlap with the BIOS address space. For - example if you have the BIOS located at physical address - 0xDC000 and a DMA transfer from the card to RAM starts at - physical address 0x10DC000 then the transfer is messed up. To - be more precise every fourth byte of the transfer is messed up. - (This analysis courtesy of Tomas Hurka, author of the NeXTSTEP - BusLogic driver.) */ - - if (bus_type == 'V' /* 445 */ - && firmware_rev[0] <= '3' /* S */ - && bios != NULL) { /* BIOS enabled */ -#if 1 - /* Now that LNZ's forbidden_addr stuff makes it into the higher - level scsi code, we can use this instead. */ - /* Avoid addresses which "mirror" the BIOS for DMA. */ - shpnt->forbidden_addr = bios; - shpnt->forbidden_size = 16 * 1024; -#else - /* Use double-buffering. */ - shpnt->unchecked_isa_dma = TRUE; -#endif - } -#endif + shpnt->unchecked_isa_dma = unchecked_isa_dma; /* Have to keep cmd_per_lun at 1 for ISA machines otherwise lots of memory gets sucked up for bounce buffers. */ - shpnt->cmd_per_lun - = (shpnt->unchecked_isa_dma ? 1 : BUSLOGIC_CMDLUN); + shpnt->cmd_per_lun = (unchecked_isa_dma ? 1 : BUSLOGIC_CMDLUN); shpnt->sg_tablesize = max_sg; if (shpnt->sg_tablesize > BUSLOGIC_MAX_SG) shpnt->sg_tablesize = BUSLOGIC_MAX_SG; /* ??? shpnt->base should really be "const unsigned char *"... */ shpnt->base = (unsigned char *)bios; shpnt->io_port = base; + shpnt->n_io_port = 4; /* Number of bytes of I/O space used */ shpnt->dma_channel = dma; shpnt->irq = irq; HOSTDATA(shpnt)->bios_translation = bios_translation; if (bios_translation == BIOS_TRANSLATION_BIG) - buslogic_printk("Using extended bios translation.\n"); + buslogic_printk("using extended bios translation.\n"); HOSTDATA(shpnt)->last_mbi_used = 2 * BUSLOGIC_MAILBOXES - 1; HOSTDATA(shpnt)->last_mbo_used = BUSLOGIC_MAILBOXES - 1; memset(HOSTDATA(shpnt)->sc, 0, sizeof HOSTDATA(shpnt)->sc); @@ -1261,8 +1300,7 @@ buf[i] = 0x87; for (i = 0; i < 2; i++) if (!buslogic_command(i, cmd, buf, sizeof buf)) { - buslogic_printk("buslogic_detect: LU %u " - "sector_size %d device_size %d\n", + buslogic_printk("LU %u sector_size %d device_size %d\n", i, *(int *)(buf + 4), *(int *)buf); } @@ -1312,7 +1350,7 @@ count++; } - buslogic_printk("Potential to restart %d stalled commands...\n", count); + buslogic_printk("potential to restart %d stalled commands...\n", count); #if 0 /* start scsi command */ if (count) @@ -1333,7 +1371,7 @@ size_t mbi, mbo; unsigned int i; - buslogic_printk("buslogic_abort: %X %X\n", + buslogic_printk("%X %X\n", inb(STATUS(scpnt->host->io_port)), inb(INTERRUPT(scpnt->host->io_port))); @@ -1353,8 +1391,8 @@ sti(); if (mb[mbi].status != MBX_NOT_IN_USE) { - buslogic_printk("Lost interrupt discovered on irq %d" - " - attempting to recover\n", + buslogic_printk("lost interrupt discovered on irq %d" + " - attempting to recover...\n", scpnt->host->irq); { int intval[3]; @@ -1370,20 +1408,20 @@ for (i = 0; i < BUSLOGIC_MAILBOXES; i++) if (HOSTDATA(scpnt->host)->sc[i]) { if (HOSTDATA(scpnt->host)->sc[i] == scpnt) { - buslogic_printk("Timed out command pending for %4.4X\n", + buslogic_printk("timed out command pending for %4.4X.\n", scpnt->request.dev); if (HOSTDATA(scpnt->host)->mb[i].status != MBX_NOT_IN_USE) { - buslogic_printk("OGMB still full - restarting\n"); + buslogic_printk("OGMB still full - restarting...\n"); buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd); } } else - buslogic_printk("Other pending command %4.4X\n", + buslogic_printk("other pending command: %4.4X\n", scpnt->request.dev); } #endif #if (BUSLOGIC_DEBUG & BD_ABORT) - buslogic_printk("buslogic_abort\n"); + buslogic_printk("called\n"); #endif #if 1 @@ -1413,7 +1451,7 @@ unsigned int i; #if (BUSLOGIC_DEBUG & BD_RESET) - buslogic_printk("buslogic_reset\n"); + buslogic_printk("called\n"); #endif #if 0 /* This does a scsi reset for all devices on the bus. */ @@ -1433,7 +1471,7 @@ interrupt for the commands that we aborted with the specified target, or do we generate this on our own? Try it without first and see what happens. */ - buslogic_printk("Sent BUS DEVICE RESET to target %d\n", + buslogic_printk("sent BUS DEVICE RESET to target %d.\n", scpnt->target); /* If the first does not work, then try the second. I think the @@ -1448,7 +1486,7 @@ sctmp->result = DID_RESET << 16; if (sctmp->host_scribble) scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC); - buslogic_printk("Sending DID_RESET for target %d\n", + buslogic_printk("sending DID_RESET for target %d.\n", scpnt->target); sctmp->scsi_done(scpnt); @@ -1505,3 +1543,36 @@ ip[2] = 1024; */ return 0; } + +/* called from init/main.c */ +void buslogic_setup(char *str, int *ints) +{ + static const unsigned short valid_bases[] + = { 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 }; + static size_t setup_idx = 0; + size_t i; + + if (setup_idx >= ARRAY_SIZE(bases) - 1) { + buslogic_printk("called too many times. Bad LILO params?\n"); + return; + } + if (ints[0] != 1) { + buslogic_printk("malformed command line.\n"); + buslogic_printk("usage: buslogic=\n"); + return; + } + for (i = 0; i < ARRAY_SIZE(valid_bases); i++) + if (valid_bases[i] == ints[1]) { + bases[setup_idx++] = ints[1]; + bases[setup_idx] = 0; + return; + } + buslogic_printk("invalid base 0x%X specified.\n", ints[i]); +} + +#ifdef MODULE +/* Eventually this will go into an include file, but that's later... */ +Scsi_Host_Template driver_template = BUSLOGIC; + +# include "scsi_module.c" +#endif diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/buslogic.h linux/drivers/scsi/buslogic.h --- v1.1.72/linux/drivers/scsi/buslogic.h Thu Dec 1 19:15:04 1994 +++ linux/drivers/scsi/buslogic.h Wed Dec 14 12:03:13 1994 @@ -1,13 +1,6 @@ /* - * buslogic.h (C) 1993 David B. Gentzel - * Low-level scsi driver for BusLogic adapters - * by David B. Gentzel, Whitfield Software Services, Carnegie, PA - * (gentzel@nova.enet.dec.com) - * Thanks to BusLogic for providing the necessary documentation - * - * The original version of this driver was derived from aha1542.[ch] which - * is Copyright (C) 1992 Tommy Thorn. Much has been reworked, but most of - * basic structure and substantial chunks of code still remain. + * buslogic.h Copyright (C) 1993, 1994 David B. Gentzel + * See buslogic.c for more information. */ #ifndef _BUSLOGIC_H diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.1.72/linux/drivers/scsi/fdomain.c Tue Nov 29 18:51:26 1994 +++ linux/drivers/scsi/fdomain.c Mon Dec 12 21:47:12 1994 @@ -1,10 +1,10 @@ /* fdomain.c -- Future Domain TMC-16x0 SCSI driver * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Wed Nov 2 16:37:58 1994 by faith@cs.unc.edu + * Revised: Wed Dec 7 09:36:57 1994 by faith@cs.unc.edu * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992, 1993, 1994 Rickard E. Faith * - * $Id: fdomain.c,v 5.20 1994/11/02 21:38:33 root Exp $ + * $Id: fdomain.c,v 5.22 1994/12/07 15:15:46 root Exp $ * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -40,7 +40,8 @@ The following BIOS versions are supported: 2.0, 3.0, 3.2, 3.4, and 3.5. The following chips are supported: TMC-1800, TMC-18C50, TMC-18C30. - Reports suggest that the driver will also work with the 36C70 chip. + Reports suggest that the driver will also work with the 36C70 chip and + with the Quantum ISA-200S SCSI adapter. Please note that the drive ordering that Future Domain implemented in BIOS versions 3.4 and 3.5 is the opposite of the order (currently) used by the @@ -133,6 +134,9 @@ Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the patch for the version 3.5 BIOS. + Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the + patch for the Quantum ISA-200S SCSI adapter. + All of the alpha testers deserve much thanks. @@ -182,7 +186,7 @@ #include #include -#define VERSION "$Revision: 5.20 $" +#define VERSION "$Revision: 5.22 $" /* START OF USER DEFINABLE OPTIONS */ @@ -273,6 +277,7 @@ static int bios_major = 0; static int bios_minor = 0; static int PCI_bus = 0; +static int ISA_200S = 0; /* Quantum ISA-200S */ static int interrupt_level = 0; static volatile int in_command = 0; static Scsi_Cmnd *current_SC = NULL; @@ -347,12 +352,13 @@ int sig_length; int major_bios_version; int minor_bios_version; - int PCI_bus; + int flag; /* 1 == PCI_bus, 2 == ISA_200S */ } signatures[] = { /* 1 2 3 4 5 6 */ /* 123456789012345678901234567890123456789012345678901234567890 */ { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, @@ -532,7 +538,8 @@ signatures[j].signature, signatures[j].sig_length )) { bios_major = signatures[j].major_bios_version; bios_minor = signatures[j].minor_bios_version; - PCI_bus = signatures[j].PCI_bus; + PCI_bus = (signatures[j].flag == 1); + ISA_200S = (signatures[j].flag == 2); bios_base = addresses[i]; } } @@ -554,8 +561,13 @@ DOS (this geometry has nothing to do with physical geometry). */ - port_base = *((char *)bios_base + 0x1fcc) - + (*((char *)bios_base + 0x1fcd) << 8); + if (ISA_200S) { /* The Quantum board is slightly different. */ + port_base = *((char *)bios_base + 0x1fa2) + + (*((char *)bios_base + 0x1fa3) << 8); + } else { + port_base = *((char *)bios_base + 0x1fcc) + + (*((char *)bios_base + 0x1fcd) << 8); + } #if DEBUG_DETECT printk( " %x,", port_base ); @@ -1540,6 +1552,17 @@ The table at 0x1fcc are I/O ports addresses for the various operations. I calculate these by hand in this driver code. + + + For the ISA-200S version of BIOS Version 2.0: + + The drive parameter table starts at 0x1f33. + + WARNING: Assume that the table entry is 25 bytes long. Someone needs + to check this for the Quantum ISA-200S card. + + + For BIOS Version 3.2: The drive parameter table starts at 0x1f70. Each entry is @@ -1549,7 +1572,11 @@ drive = MINOR(dev) / 16; if (bios_major == 2) { - i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 ); + if (ISA_200S) { + i = (struct drive_info *)( (char *)bios_base + 0x1f33 + drive * 25 ); + } else { + i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 ); + } info_array[0] = i->heads; info_array[1] = i->sectors; info_array[2] = i->cylinders; diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v1.1.72/linux/drivers/scsi/hosts.c Mon Dec 5 18:47:55 1994 +++ linux/drivers/scsi/hosts.c Wed Dec 14 12:03:12 1994 @@ -1,7 +1,7 @@ /* - * hosts.c Copyright (C) 1992 Drew Eckhardt + * hosts.c Copyright (C) 1992 Drew Eckhardt * mid to lowlevel SCSI driver interface by - * Drew Eckhardt + * Drew Eckhardt * * */ @@ -10,7 +10,7 @@ /* * This file contains the medium level SCSI * host interface initialization, as well as the scsi_hosts array of SCSI - * hosts currently present in the system. + * hosts currently present in the system. */ #include @@ -19,7 +19,7 @@ #include #include "scsi.h" -#ifndef NULL +#ifndef NULL #define NULL 0L #endif @@ -50,7 +50,7 @@ #ifdef CONFIG_SCSI_U14_34F #include "u14-34f.h" #endif - + #ifdef CONFIG_SCSI_FUTURE_DOMAIN #include "fdomain.h" #endif @@ -94,7 +94,7 @@ #ifdef CONFIG_SCSI_EATA #include "eata.h" #endif - + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif @@ -104,9 +104,9 @@ */ /* - * The scsi host entries should be in the order you wish the + * The scsi host entries should be in the order you wish the * cards to be detected. A driver may appear more than once IFF - * it can deal with being detected (and therefore initialized) + * it can deal with being detected (and therefore initialized) * with more than one simultaneous host number, can handle being * reentrant, etc. * @@ -122,9 +122,9 @@ NULL, NULL, 0, 0, 0, 0, 0, 0} /* - * When figure is run, we don't want to link to any object code. Since - * the macro for each host will contain function pointers, we cannot - * use it and instead must use a "blank" that does no such + * When figure is run, we don't want to link to any object code. Since + * the macro for each host will contain function pointers, we cannot + * use it and instead must use a "blank" that does no such * idiocy. */ @@ -161,7 +161,7 @@ IN2000, #endif #ifdef CONFIG_SCSI_GENERIC_NCR5380 - GENERIC_NCR5380, + GENERIC_NCR5380, #endif #ifdef CONFIG_SCSI_QLOGIC QLOGIC, @@ -173,7 +173,7 @@ SEAGATE_ST0X, #endif #ifdef CONFIG_SCSI_T128 - TRANTOR_T128, + TRANTOR_T128, #endif #ifdef CONFIG_SCSI_NCR53C7xx NCR53c7xx, @@ -192,7 +192,7 @@ #define MAX_SCSI_HOSTS (sizeof(builtin_scsi_hosts) / sizeof(Scsi_Host_Template)) /* - * Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here. + * Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here. */ struct Scsi_Host * scsi_hostlist = NULL; @@ -232,13 +232,13 @@ retval->extra_bytes = j; retval->loaded_as_module = scsi_loadable_module_flag; retval->host_no = next_host++; - retval->host_queue = NULL; - retval->host_wait = NULL; - retval->last_reset = 0; + retval->host_queue = NULL; + retval->host_wait = NULL; + retval->last_reset = 0; retval->irq = 0; retval->forbidden_addr = 0; retval->forbidden_size = 0; - retval->hostt = tpnt; + retval->hostt = tpnt; retval->next = NULL; #ifdef DEBUG printk("Register %x %x: %d\n", retval, retval->hostt, j); @@ -282,19 +282,19 @@ if(called) return 0; - called = 1; + called = 1; for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++) { /* - * Initialize our semaphores. -1 is interpreted to mean + * Initialize our semaphores. -1 is interpreted to mean * "inactive" - where as 0 will indicate a time out condition. - */ - + */ + pcount = next_host; - if ((tpnt->detect) && - (tpnt->present = + if ((tpnt->detect) && + (tpnt->present = tpnt->detect(tpnt))) - { + { /* The only time this should come up is when people use some kind of patched driver of some kind or another. */ if(pcount == next_host) { @@ -312,7 +312,7 @@ } } printk ("scsi : %d hosts.\n", count); - + /* Now attach the high level drivers */ #ifdef CONFIG_BLK_DEV_SD scsi_register_device(&sd_template); @@ -334,17 +334,21 @@ void scsi_mem_init(unsigned long memory_end) { - struct Scsi_Host *Host; - long High8, Low24; - for (Host = scsi_hostlist; Host != NULL; Host = Host->next) - if (Host->forbidden_addr > 0 && Host->forbidden_size > 0) - for (High8 = 1<<24; High8 < memory_end; High8 += 1<<24) - for (Low24 = Host->forbidden_addr; - Low24 < Host->forbidden_addr + Host->forbidden_size; - Low24 += PAGE_SIZE) - { - unsigned long ForbiddenAddress = High8 + Low24; - if (ForbiddenAddress >= memory_end) break; - mem_map[MAP_NR(ForbiddenAddress)] = MAP_PAGE_RESERVED; - } + struct Scsi_Host *Host; + long High8, Low24; + for (Host = scsi_hostlist; Host != NULL; Host = Host->next) { + if (Host->forbidden_addr > 0 && Host->forbidden_size > 0) { + for (High8 = 1<<24; High8 < memory_end; High8 += 1<<24) { + for (Low24 = Host->forbidden_addr; + Low24 < Host->forbidden_addr + Host->forbidden_size; + Low24 += PAGE_SIZE) { + unsigned long ForbiddenAddress = High8 + Low24; + if (ForbiddenAddress >= memory_end) goto next_host; + mem_map[MAP_NR(ForbiddenAddress)] = MAP_PAGE_RESERVED; + } + } + } + next_host: + continue; + } } diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c --- v1.1.72/linux/drivers/scsi/qlogic.c Tue Nov 29 18:51:27 1994 +++ linux/drivers/scsi/qlogic.c Tue Dec 13 10:12:54 1994 @@ -14,19 +14,30 @@ Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 (you can reference it, but it is incomplete and inaccurate in places) - Version 0.37 + Version 0.38a + + This also works with loadable SCSI as a module. Check configuration + options QL_INT_ACTIVE_HIGH and QL_TURBO_PDMA for PCMCIA usage (which + also requires an enabler). + Redistributable under terms of the GNU Public License */ /*----------------------------------------------------------------*/ /* Configuration */ +/* Set the following to 2 to use normal interrupt (active high/totempole- + tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + drain */ +#define QL_INT_ACTIVE_HIGH 2 + /* Set the following to 1 to enable the use of interrupts. Note that 0 tends to be more stable, but slower (or ties up the system more) */ #define QL_USE_IRQ 1 /* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable */ + again, 0 tends to be slower, but more stable. THIS SHOULD BE ZERO FOR + PCMCIA */ #define QL_TURBO_PDMA 1 /* This will reset all devices when the driver is initialized (during bootup). @@ -64,6 +75,8 @@ #include "../block/blk.h" /* to get disk capacity */ #include #include +#include +#include #include #include #include @@ -83,9 +96,9 @@ /*----------------------------------------------------------------*/ #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb6 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) -/* following is watchdog timeout - 0 is longest possible */ +/* following is watchdog timeout */ #define WATCHDOG 5000000 /*----------------------------------------------------------------*/ @@ -196,9 +209,9 @@ static int ql_wai(void) { int i,k; - i = WATCHDOG; - while (--i && !qabort && !((k = inb(qbase + 4)) & 0xe0)); - if (!i) + i = jiffies + WATCHDOG; + while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)); + if (i <= jiffies) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -291,7 +304,9 @@ j &= 7; /* j = inb( qbase + 7 ) >> 5; */ /* correct status is supposed to be step 4 */ /* it sometimes returns step 3 but with 0 bytes left to send */ - if (j != 4 && (j != 3 || inb(qbase + 7) & 0x1f)) { +/* We can try stuffing the FIFO with the max each time, but we will get a + sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ + if(j != 3 && j != 4) { printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f ); ql_zap(); return (DID_ERROR << 16); @@ -333,10 +348,10 @@ k = inb(qbase + 5); /* should be 0x10, bus service */ } /*** Enter Status (and Message In) Phase ***/ - k = WATCHDOG; + k = jiffies + WATCHDOG; rtrc(4) - while (--k && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if (!k) { + while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( k <= jiffies ) { ql_zap(); return (DID_TIME_OUT << 16); } @@ -465,6 +480,8 @@ */ for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { + if( check_region( qbase , 0x10 ) ) + continue; REG1; if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) ) @@ -498,25 +515,30 @@ outb(10, 0x20); /* access pending interrupt map */ outb(10, 0xa0); while (j--) { - outb(0xb2, qbase + 0xd); /* int pin off */ + outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin off */ i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */ - outb(0xb6, qbase + 0xd); /* int pin on */ + outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin on */ i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */ } REG0; while (inb(qbase + 5)); /* purge int */ while (i) /* find on bit */ i >>= 1, qlirq++; /* should check for exactly 1 on */ - if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic")) + if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, SA_INTERRUPT, "qlogic")) host->can_queue = 1; sti(); #endif + snarf_region( qbase , 0x10 ); + hreg = scsi_register( host , 0 ); /* no host data */ hreg->io_port = qbase; - hreg->irq = qlirq; + hreg->n_io_port = 16; + if( qlirq != -1 ) + hreg->irq = qlirq; - sprintf(qinfo, "Qlogic Driver version 0.36, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq); + sprintf(qinfo, "Qlogic Driver version 0.38a, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq); host->name = qinfo; + return 1; } @@ -562,3 +584,10 @@ { return qinfo; } + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = QLOGIC; + +#include "scsi_module.c" +#endif diff -u --recursive --new-file v1.1.72/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.1.72/linux/drivers/scsi/scsi.c Mon Dec 5 18:47:55 1994 +++ linux/drivers/scsi/scsi.c Mon Dec 12 20:35:51 1994 @@ -45,6 +45,7 @@ static int time_start; static int time_elapsed; +static int scsi_maybe_deadlocked = 0; #define MAX_SCSI_DEVICE_CODE 10 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = @@ -369,7 +370,7 @@ * flags set for ROM / WORM treated as RO. */ - switch (type = scsi_result[0]) + switch (type = (scsi_result[0] & 0x1f)) { case TYPE_TAPE : case TYPE_DISK : @@ -393,7 +394,7 @@ SDpnt->soft_reset = (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2); SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; - SDpnt->type = type; + SDpnt->type = (type & 0x1f); if (type != -1) { @@ -664,6 +665,12 @@ host = device->host; + if (intr_count && device->host->can_queue + && device->host->host_busy >= device->host->can_queue) { + scsi_maybe_deadlocked = 1; + return NULL; + } + while (1==1){ SCpnt = host->host_queue; while(SCpnt){ @@ -1374,6 +1381,17 @@ */ for(block = host->block; block != host; block = block->block) wake_up(&block->host_wait); + /* + * If we might have deadlocked, get things started again. Only + * for block devices - character devices should never deadlock. + */ + if (scsi_maybe_deadlocked) { + struct Scsi_Device_Template * sdtpnt; + scsi_maybe_deadlocked = 0; + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->blk && blk_dev[sdtpnt->major].request_fn) + (*blk_dev[sdtpnt->major].request_fn)(); + } } wake_up(&host->host_wait); SCpnt->result = result | ((exit & 0xff) << 24); @@ -1615,7 +1633,7 @@ SCpnt->timeout = 0; pid = SCpnt->pid; sti(); - scsi_times_out(SCpnt, SCpnt); + scsi_times_out(SCpnt, pid); ++timed_out; cli(); } @@ -1701,10 +1719,12 @@ void *scsi_malloc(unsigned int len) { unsigned int nbits, mask; + unsigned long flags; int i, j; if((len & 0x1ff) || len > 8192) return NULL; + save_flags(flags); cli(); nbits = len >> 9; mask = (1 << nbits) - 1; @@ -1713,7 +1733,7 @@ for(j=0; j<17-nbits; j++){ if ((dma_malloc_freelist[i] & (mask << j)) == 0){ dma_malloc_freelist[i] |= (mask << j); - sti(); + restore_flags(flags); dma_free_sectors -= nbits; #ifdef DEBUG printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9)); @@ -1721,7 +1741,7 @@ return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9)); }; }; - sti(); + restore_flags(flags); return NULL; /* Nope. No more */ } @@ -1729,6 +1749,7 @@ { int offset; int page, sector, nbits, mask; + unsigned long flags; #ifdef DEBUG printk("Sfree %x %d\n",obj, len); @@ -1747,13 +1768,14 @@ if ((mask << sector) > 0xffff) panic ("Bad memory alignment"); + save_flags(flags); cli(); if(dma_malloc_freelist[page] & (mask << sector) != (mask<next || !tpnt->detect) return 1; /* Must be already loaded, or + no detect routine available */ + pcount = next_scsi_host; + if ((tpnt->present = tpnt->detect(tpnt))) + { + if(pcount == next_scsi_host) { + if(tpnt->present > 1) { + printk("Failure to register low-level scsi driver"); + scsi_unregister_host(tpnt); + return 1; + } + /* The low-level driver failed to register a driver. We + can do this now. */ + scsi_register(tpnt,0); + } + tpnt->next = scsi_hosts; /* Add to the linked list */ + scsi_hosts = tpnt; + + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) + if(shpnt->hostt == tpnt) + { + if(tpnt->info) + name = tpnt->info(shpnt); + else + name = tpnt->name; + printk ("scsi%d : %s\n", /* And print a little message */ + shpnt->host_no, name); + } + /* The next step is to call scan_scsis here. This generates the + Scsi_Devices entries */ + + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) + if(shpnt->hostt == tpnt) scan_scsis(shpnt); + + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + + /* Next we create the Scsi_Cmnd structures for this host */ + + for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) + if(SDpnt->host->hostt == tpnt) + { + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); + if(SDpnt->attached){ + for(j=0;jhost->cmd_per_lun;j++){ + SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); + SCpnt->host = SDpnt->host; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->lun = SDpnt->lun; + SCpnt->request.dev = -1; /* Mark not busy */ + SCpnt->request.sem = NULL; + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->underflow = 0; + SCpnt->timeout = 0; + SCpnt->transfersize = 0; + SCpnt->host_scribble = NULL; + host = SDpnt->host; + SCpnt->next = host->host_queue; + SCpnt->prev = NULL; + host->host_queue = SCpnt; + if(host->host_queue) + host->host_queue->prev = SCpnt; + }; + }; + } + /* Next, check to see if we need to extend the DMA buffer pool */ + { + unsigned char * new_dma_malloc_freelist = NULL; + unsigned int new_dma_sectors = 0; + unsigned int new_need_isa_buffer = 0; + unsigned char ** new_dma_malloc_pages = NULL; + + if (scsi_devicelist) + new_dma_sectors = 16; /* Base value we use */ + + for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) { + host = SDpnt->host; + + if(SDpnt->type != TYPE_TAPE) + new_dma_sectors += ((host->sg_tablesize * + sizeof(struct scatterlist) + 511) >> 9) * + host->cmd_per_lun; + + if(host->unchecked_isa_dma && + scsi_need_isa_bounce_buffers && + SDpnt->type != TYPE_TAPE) { + new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * + host->cmd_per_lun; + new_need_isa_buffer++; + }; + }; + + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + + new_dma_malloc_freelist = (unsigned char *) + scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC); + memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3); + + new_dma_malloc_pages = (unsigned char **) + scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC); + memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1); + + for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++) + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + + + /* When we dick with the actual DMA list, we need to protect things */ + cli(); + memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3); + scsi_init_free(dma_malloc_freelist, dma_sectors>>3); + dma_malloc_freelist = new_dma_malloc_freelist; + + memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1); + scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1); + + dma_free_sectors += new_dma_sectors - dma_sectors; + dma_malloc_pages = new_dma_malloc_pages; + dma_sectors = new_dma_sectors; + need_isa_buffer = new_need_isa_buffer; + sti(); + + + } + /* This does any final handling that is required. */ + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->finish) (*sdtpnt->finish)(); + } + return 0; +} + +/* + * Similarily, this entry point should be called by a loadable module if it + * is trying to remove a low level scsi driver from the system. + */ +static void scsi_unregister_host(Scsi_Host_Template * tpnt) +{ + Scsi_Host_Template * SHT, *SHTp; + Scsi_Device *sdpnt, * sdppnt, * sdpnt1; + Scsi_Cmnd * SCpnt; + struct Scsi_Device_Template * sdtpnt; + struct Scsi_Host * shpnt, *sh1; + int pcount; + + /* First verify that this host adapter is completely free with no pending + commands */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt && *sdpnt->host->hostt->usage_count) return; + + for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) + { + if (shpnt->hostt != tpnt) continue; + for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) + { + cli(); + if(SCpnt->request.dev != -1) { + sti(); + for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) + if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1; + printk("Device busy???\n"); + return; + } + SCpnt->request.dev = 0xffe0; /* Mark as busy */ + } + } + /* Next we detach the high level drivers from the Scsi_Device structures */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt) + { + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt); + /* If something still attached, punt */ + if (sdpnt->attached) { + printk("Attached usage count = %d\n", sdpnt->attached); + return; + } + } + + /* Next we free up the Scsi_Cmnd structures for this host */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt) + while (sdpnt->host->host_queue) { + SCpnt = sdpnt->host->host_queue->next; + scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd)); + sdpnt->host->host_queue = SCpnt; + if (SCpnt) SCpnt->prev = NULL; + } + + /* Next free up the Scsi_Device structures for this host */ + + sdppnt = NULL; + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1) + { + sdpnt1 = sdpnt->next; + if (sdpnt->host->hostt == tpnt) { + if (sdppnt) + sdppnt->next = sdpnt->next; + else + scsi_devices = sdpnt->next; + scsi_init_free((char *) sdpnt, sizeof (Scsi_Device)); + } else + sdppnt = sdpnt; + } + + /* Next we go through and remove the instances of the individual hosts + that were detected */ + + shpnt = scsi_hostlist; + while(shpnt) { + sh1 = shpnt->next; + if(shpnt->hostt == tpnt) { + if(shpnt->loaded_as_module) { + pcount = next_scsi_host; + if(tpnt->release) + (*tpnt->release)(shpnt); + else { + /* This is the default case for the release function. It should do the right + thing for most correctly written host adapters. */ + if (shpnt->irq) free_irq(shpnt->irq); + if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel); + if (shpnt->io_port && shpnt->n_io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + } + if(pcount == next_scsi_host) scsi_unregister(shpnt); + tpnt->present--; + } + } + shpnt = sh1; + } + + /* There were some hosts that were loaded at boot time, so we cannot + do any more than this */ + if (tpnt->present) return; + + /* OK, this is the very last step. Remove this host adapter from the + linked list. */ + for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next) + if(SHT == tpnt) { + if(SHTp) + SHTp->next = SHT->next; + else + scsi_hosts = SHT->next; + SHT->next = NULL; + break; + } +} + +int scsi_register_module(int module_type, void * ptr) +{ + switch(module_type){ + case MODULE_SCSI_HA: + return scsi_register_host((Scsi_Host_Template *) ptr); + /* The rest of these are not yet implemented */ + + /* Load constants.o */ + case MODULE_SCSI_CONST: + + /* Load specialized ioctl handler for some device. Intended for cdroms that + have non-SCSI2 audio command sets. */ + case MODULE_SCSI_IOCTL: + + /* Load upper level device handler of some kind */ + case MODULE_SCSI_DEV: + default: + return 1; + } +} + +void scsi_unregister_module(int module_type, void * ptr) +{ + switch(module_type) { + case MODULE_SCSI_HA: + scsi_unregister_host((Scsi_Host_Template *) ptr); + break; + /* The rest of these are not yet implemented. */ + case MODULE_SCSI_CONST: + case MODULE_SCSI_IOCTL: + case MODULE_SCSI_DEV: + default: + } + return; +} +#endif + #ifdef DEBUG_TIMEOUT static void scsi_dump_status(void) { - int i, i1; - Scsi_Host * shpnt; + int i; + struct Scsi_Host * shpnt; Scsi_Cmnd * SCpnt; printk("Dump of scsi parameters:\n"); - for(shpnt = scsi_hosts; shpnt; shpnt = shpnt->next) + i = 0; + for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) { /* (0) 0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x */ printk("(%d) %d:%d:%d (%4.4x %d %d %d %d) (%d %d %x) (%d %d %d) %x %x %x\n", - i, SCpnt->host->host_no, + i++, SCpnt->host->host_no, SCpnt->target, SCpnt->lun, SCpnt->request.dev, diff -u --recursive --new-file v1.1.72/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v1.1.72/linux/drivers/sound/gus_wave.c Fri Aug 19 08:54:08 1994 +++ linux/drivers/sound/gus_wave.c Mon Dec 12 21:19:00 1994 @@ -3052,7 +3052,6 @@ pcm_active = 0; /* Signal to the play_next_pcm_block routine */ case LMODE_PCM: { - int orig_qlen = pcm_qlen; int flag; /* 0 or 2 */ pcm_qlen--; @@ -3068,7 +3067,7 @@ pcm_active = 0; } - /* +/* * If the queue was full before this interrupt, the DMA transfer was * suspended. Let it continue now. */ diff -u --recursive --new-file v1.1.72/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v1.1.72/linux/fs/binfmt_elf.c Tue Dec 6 17:37:06 1994 +++ linux/fs/binfmt_elf.c Mon Dec 12 21:49:38 1994 @@ -549,7 +549,7 @@ elf_ppnt->p_vaddr & 0xfffff000, elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff), PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, + MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, elf_ppnt->p_offset & 0xfffff000); #ifdef LOW_ELF_STACK diff -u --recursive --new-file v1.1.72/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.72/linux/fs/buffer.c Thu Dec 1 19:15:04 1994 +++ linux/fs/buffer.c Mon Dec 12 20:22:34 1994 @@ -777,7 +777,12 @@ { if (!buf) return; +/* + * Hmm.. Leaving this in for now, as I'm a bit nervous about it.. + */ +#if 0 wait_on_buffer(buf); +#endif /* If dirty, mark the time this buffer should be written back */ set_writetime(buf, 0); diff -u --recursive --new-file v1.1.72/linux/fs/open.c linux/fs/open.c --- v1.1.72/linux/fs/open.c Tue Nov 15 15:35:40 1994 +++ linux/fs/open.c Mon Dec 12 21:23:00 1994 @@ -418,8 +418,11 @@ if (flag & (O_TRUNC | O_CREAT)) flag |= 2; error = open_namei(filename,flag,mode,&inode,NULL); - if (!error && (f->f_mode & 2)) + if (!error && (f->f_mode & 2)) { error = get_write_access(inode); + if (error) + iput(inode); + } if (error) { current->files->fd[fd]=NULL; f->f_count--; diff -u --recursive --new-file v1.1.72/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.1.72/linux/fs/proc/array.c Tue Dec 6 17:37:06 1994 +++ linux/fs/proc/array.c Mon Dec 12 21:33:00 1994 @@ -16,6 +16,9 @@ * * Danny ter Haar : Some minor additions for cpuinfo * + * + * Alessandro Rubini : profile extension. + * */ #include @@ -95,6 +98,64 @@ &proc_kcore_operations, }; +#ifdef CONFIG_PROFILE + +extern unsigned long prof_len; +extern unsigned long * prof_buffer; +/* + * This function accesses profiling information. The returned data is + * binary: the sampling step and the actual contents of the profile + * buffer. Use of the program readprofile is recommended in order to + * get meaningful info out of these data. + */ +static int read_profile(struct inode *inode, struct file *file, char *buf, int count) +{ + unsigned long p = file->f_pos; + int read; + char * pnt; + unsigned long sample_step = 1 << CONFIG_PROFILE_SHIFT; + + if (count < 0) + return -EINVAL; + if (p >= (prof_len+1)*sizeof(unsigned long)) + return 0; + if (count > (prof_len+1)*sizeof(unsigned long) - p) + count = (prof_len+1)*sizeof(unsigned long) - p; + read = 0; + + while (p < sizeof(unsigned long) && count > 0) { + put_fs_byte(*((char *)(&sample_step)+p),buf); + buf++; p++; count--; read++; + } + pnt = (char *)prof_buffer + p - sizeof(unsigned long); + memcpy_tofs(buf,(void *)pnt,count); + read += count; + file->f_pos += read; + return read; +} + +/* Writing to /proc/profile resets the counters */ +static int write_profile(struct inode * inode, struct file * file, char * buf, int count) +{ + int i=prof_len; + + while (i--) + prof_buffer[i]=0UL; + return count; +} + +static struct file_operations proc_profile_operations = { + NULL, /* lseek */ + read_profile, + write_profile, +}; + +struct inode_operations proc_profile_inode_operations = { + &proc_profile_operations, +}; + +#endif /* CONFIG_PROFILE */ + static int get_loadavg(char * buffer) { int a, b, c; @@ -182,18 +243,47 @@ static int get_cpuinfo(char * buffer) { - return sprintf(buffer,"cpu : %d86\n" - "vid : %s\n" - "fdiv_bug : %s\n" - "math : %s\n" - "hlt : %s\n" - "wp : %s\n", - x86, + /* to conserve memory, we define the strins yes and no in + advance */ + char *yes="yes"; + char *no="no"; + char *model[2][9]={{"DX","SX","DX/2","4","5","6", + "7","DX/4"}, + {"Pentium 60/66","Pentium 90","3", + "4","5","6","7","8"}}; + return sprintf(buffer,"cpu\t\t: %c86\n" + "model\t\t: %s\n" + "mask\t\t: %c\n" + "vid\t\t: %s\n" + "fdiv_bug\t: %s\n" + "math\t\t: %s\n" + "hlt\t\t: %s\n" + "wp\t\t: %s\n" + "Integrated NPU\t: %s\n" + "Enhanced VM86\t: %s\n" + "IO Breakpoints\t: %s\n" + "4MB Pages\t: %s\n" + "TS Counters\t: %s\n" + "Pentium MSR\t: %s\n" + "Mach. Ch. Exep.\t: %s\n" + "CMPXCHGB8B\t: %s\n", + x86+'0', + x86_model ? model[x86-4][x86_model-1] : "Unknown", + x86_mask+'@', x86_vendor_id, - fdiv_bug ? "yes" : "no", - hard_math ? "yes" : "no", - hlt_works_ok ? "yes" : "no", - wp_works_ok ? "yes" : "no"); + fdiv_bug ? yes : no, + hard_math ? yes : no, + hlt_works_ok ? yes : no, + wp_works_ok ? yes : no, + x86_capability & 1 ? yes : no, + x86_capability & 2 ? yes : no, + x86_capability & 4 ? yes : no, + x86_capability & 8 ? yes : no, + x86_capability & 16 ? yes : no, + x86_capability & 32 ? yes : no, + x86_capability & 128 ? yes : no, + x86_capability & 256 ? yes : no + ); } static struct task_struct ** get_task(pid_t pid) diff -u --recursive --new-file v1.1.72/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v1.1.72/linux/fs/proc/inode.c Tue Oct 11 09:17:04 1994 +++ linux/fs/proc/inode.c Mon Dec 12 22:38:19 1994 @@ -16,6 +16,8 @@ #include #include +extern unsigned long prof_len; + void proc_put_inode(struct inode *inode) { if (inode->i_nlink) @@ -127,6 +129,13 @@ inode->i_op = &proc_kcore_inode_operations; inode->i_size = high_memory + PAGE_SIZE; break; +#ifdef CONFIG_PROFILE + case PROC_PROFILE: + inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR; + inode->i_op = &proc_profile_inode_operations; + inode->i_size = (1+prof_len) * sizeof(unsigned long); + break; +#endif default: inode->i_mode = S_IFREG | S_IRUGO; inode->i_op = &proc_array_inode_operations; diff -u --recursive --new-file v1.1.72/linux/fs/proc/root.c linux/fs/proc/root.c --- v1.1.72/linux/fs/proc/root.c Tue Dec 6 17:37:06 1994 +++ linux/fs/proc/root.c Mon Dec 12 20:13:07 1994 @@ -74,6 +74,7 @@ { PROC_KSYMS, 5, "ksyms" }, { PROC_DMA, 3, "dma" }, { PROC_IOPORTS, 7, "ioports"}, + { PROC_PROFILE, 7, "profile"}, }; #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0]))) diff -u --recursive --new-file v1.1.72/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v1.1.72/linux/fs/umsdos/dir.c Wed Nov 2 12:03:47 1994 +++ linux/fs/umsdos/dir.c Mon Dec 12 21:15:19 1994 @@ -32,10 +32,14 @@ { return -EISDIR; } +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+3) & ~3) + /* Read count directory entries from directory filp Return a negative value from linux/errno.h. - Return > 0 if success (the length of the file name). + Return > 0 if success (The amount of byte written in + dirent round_up to a word size (32 bits). This function is used by the normal readdir VFS entry point and by some function who try to find out info on a file from a pure MSDOS @@ -72,7 +76,7 @@ put_fs_byte(0,dirent->d_name+3); put_fs_word (3,&dirent->d_reclen); if (u_entry != NULL) u_entry->flags = 0; - ret = 3; + ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1); filp->f_pos++; }else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){ @@ -191,7 +195,7 @@ dirent->d_reclen = entry.name_len; if (u_entry != NULL) *u_entry = entry; } - ret = entry.name_len; + ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1); iput (inode); break; } @@ -219,7 +223,7 @@ /* Read count directory entries from directory filp Return a negative value from linux/errno.h. - Return > 0 if success (the length of the file name). + Return > 0 if success (the amount of byte written to dirent) */ static int UMSDOS_readdir( struct inode *dir, /* Point to a description of the super block */ diff -u --recursive --new-file v1.1.72/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v1.1.72/linux/fs/umsdos/rdir.c Sun Jul 24 17:39:46 1994 +++ linux/fs/umsdos/rdir.c Mon Dec 12 21:15:19 1994 @@ -32,8 +32,10 @@ { int ret = 0; while (1){ + int len = -1; ret = msdos_readdir(dir,filp,dirent,count); - if (ret == 5 + if (ret > 0) len = get_fs_word(&dirent->d_reclen); + if (len == 5 && pseudo_root != NULL && dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){ /* @@ -45,7 +47,7 @@ if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break; }else{ if (pseudo_root != NULL - && ret == 2 + && len == 2 && dir == dir->i_sb->s_mounted && dir == pseudo_root->i_sb->s_mounted){ char name[2]; diff -u --recursive --new-file v1.1.72/linux/include/asm-alpha/delay.h linux/include/asm-alpha/delay.h --- v1.1.72/linux/include/asm-alpha/delay.h Sat Nov 26 18:36:07 1994 +++ linux/include/asm-alpha/delay.h Wed Dec 14 14:47:44 1994 @@ -35,4 +35,13 @@ __delay(usecs); } +/* + * 64-bit integers means we don't have to worry about overflow as + * on some other architectures.. + */ +extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) +{ + return (a*b)/c; +} + #endif /* defined(__ALPHA_DELAY_H) */ diff -u --recursive --new-file v1.1.72/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v1.1.72/linux/include/asm-alpha/io.h Tue Nov 22 15:41:13 1994 +++ linux/include/asm-alpha/io.h Wed Dec 14 14:45:57 1994 @@ -176,4 +176,7 @@ *(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x60) = b; } +#define inb_p inb +#define outb_p outb + #endif diff -u --recursive --new-file v1.1.72/linux/include/asm-alpha/types.h linux/include/asm-alpha/types.h --- v1.1.72/linux/include/asm-alpha/types.h Mon Dec 5 18:47:56 1994 +++ linux/include/asm-alpha/types.h Wed Dec 14 14:45:57 1994 @@ -1,6 +1,21 @@ #ifndef _ALPHA_TYPES_H #define _ALPHA_TYPES_H +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned long size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef long ssize_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef long ptrdiff_t; +#endif + /* * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the * header files exported to user space diff -u --recursive --new-file v1.1.72/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v1.1.72/linux/include/asm-alpha/unistd.h Mon Nov 28 14:21:46 1994 +++ linux/include/asm-alpha/unistd.h Wed Dec 14 14:45:57 1994 @@ -12,83 +12,32 @@ #define _syscall0(type,name) \ type name(void) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name)); \ -if (__res >= 0) \ - return (type) __res; \ -errno = -__res; \ -return -1; \ } #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1))); \ -if (__res >= 0) \ - return (type) __res; \ -errno = -__res; \ -return -1; \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ type name(type1 arg1,type2 arg2) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ -if (__res >= 0) \ - return (type) __res; \ -errno = -__res; \ -return -1; \ } #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3))); \ -if (__res>=0) \ - return (type) __res; \ -errno=-__res; \ -return -1; \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4))); \ -if (__res>=0) \ - return (type) __res; \ -errno=-__res; \ -return -1; \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ -long __res; \ -__asm__ __volatile__ (".long 131" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ -if (__res>=0) \ - return (type) __res; \ -errno=-__res; \ -return -1; \ } #endif /* _ALPHA_UNISTD_H */ diff -u --recursive --new-file v1.1.72/linux/include/asm-i386/delay.h linux/include/asm-i386/delay.h --- v1.1.72/linux/include/asm-i386/delay.h Mon Aug 15 12:24:39 1994 +++ linux/include/asm-i386/delay.h Wed Dec 14 14:18:14 1994 @@ -32,4 +32,15 @@ __delay(usecs); } +extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) +{ + __asm__("mull %1 ; divl %2" + :"=a" (a) + :"d" (b), + "r" (c), + "0" (a) + :"dx"); + return a; +} + #endif /* defined(_I386_DELAY_H) */ diff -u --recursive --new-file v1.1.72/linux/include/asm-i386/string.h linux/include/asm-i386/string.h --- v1.1.72/linux/include/asm-i386/string.h Sun Sep 18 05:37:03 1994 +++ linux/include/asm-i386/string.h Mon Dec 12 21:41:30 1994 @@ -427,7 +427,7 @@ } /* we might want to write optimized versions of these later */ -#define __constant_c_memset(s,c,count) __memset_generic((s),(c),(count)) +#define __constant_c_memset(s,c,count) __memset_generic((s),(unsigned char)(c),(count)) #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count)) /* diff -u --recursive --new-file v1.1.72/linux/include/asm-i386/types.h linux/include/asm-i386/types.h --- v1.1.72/linux/include/asm-i386/types.h Mon Dec 5 18:47:56 1994 +++ linux/include/asm-i386/types.h Wed Dec 14 14:45:57 1994 @@ -1,6 +1,21 @@ #ifndef _I386_TYPES_H #define _I386_TYPES_H +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef int ssize_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef int ptrdiff_t; +#endif + /* * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the * header files exported to user space diff -u --recursive --new-file v1.1.72/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v1.1.72/linux/include/asm-sparc/bitops.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/bitops.h Thu Dec 15 09:22:01 1994 @@ -0,0 +1,75 @@ +#ifndef _SPARC_BITOPS_H +#define _SPARC_BITOPS_H + +/* + * Copyright 1994, David S. Miller (davem@caip.rutgers.edu). + */ + + +/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' + * is in the highest of the four bytes and bit '31' is the high bit + * within the first byte. Sparc is BIG-Endian. Unless noted otherwise + * all bit-ops return 0 is bit previously clear and != 0 otherwise. + */ + +extern __inline__ unsigned int set_bit(unsigned int nr, void *addr) +{ + + __asm__ __volatile__( + "or %g0, %g0, %o2\n\t" + "or %g0, %g0, %o3\n\t" + "or %g0, %o0, %o4\n\t" + "srl %o4, 0x5, %o4\n\t" + "add %o1, %o4, %o1\n\t" + "or %g0, 0x1, %o5" + "or %g0, 0x1f, %o6" + "and %o6, %o5, %o6" + "sll %o5, %o6, %o2" + "ld [%o1], %o5\n\t" + "and %o5, %o2, %o0" + "or %o5, %o2, %o5" + "st %o5, [%o1]"); + + return nr; /* confuse gcc :-) */ + +} + +extern __inline__ unsigned int clear_bit(unsigned int nr, void *addr) +{ + __asm__ __volatile__( + "or %g0, %g0, %o2\n\t" + "or %g0, %g0, %o3\n\t" + "or %g0, %o0, %o4\n\t" + "srl %o4, 0x5, %o4\n\t" + "add %o1, %o4, %o1\n\t" + "or %g0, 0x1, %o5" + "or %g0, 0x1f, %o6" + "and %o6, %o5, %o6" + "sll %o5, %o6, %o2" + "ld [%o1], %o5\n\t" + "and %o5, %o2, %o0\n\t" + "xnor %g0, %o2, %o2\n\t" + "and %o5, %o2, %o5\n\t" + "st %o5, [%o1]\n\t"); + + return nr; /* confuse gcc ;-) */ + +} + +extern __inline__ unsigned int test_bit(int nr, int *addr) +{ + __asm__ __volatile__( + "or %g0, %o0, %o3\n\t" + "srl %o3, 0x5, %o3\n\t" + "add %o1, %o3, %o1\n\t" + "and %o0, 0x1f, %o0\n\t" + "or %g0, 0x1, %o2\n\t" + "sll %o2, %o0, %o0" + "ld [%o1], %o2\n\t" + "and %o0, %o2, %o0\n\t"); + + return nr; /* confuse gcc :> */ + +} + +#endif /* defined(_SPARC_BITOPS_H) */ diff -u --recursive --new-file v1.1.72/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h --- v1.1.72/linux/include/asm-sparc/delay.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/delay.h Thu Dec 15 09:22:01 1994 @@ -0,0 +1,32 @@ +#ifndef __SPARC_DELAY_H +#define __SPARC_DELAY_H + +extern unsigned long loops_per_sec; + +/* + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu). + * + * Delay quick inlined code using 'loops_per_second' which is + * calculated in calibrate_delay() in main.c (ie. BogoMIPS :-) + */ + +extern __inline__ void __delay(unsigned int loops) +{ + __asm__ __volatile__("\n1:\tcmp %0, 0\n\t" + "bne,a 1b\n\t" + "sub %0, 1, %0\n": "=r" (loops) : "0" (loops)); +} + +/* udelay(usecs) is used for very short delays up to 1 millisecond. */ + +extern __inline__ void udelay(unsigned int usecs) +{ + usecs *= 0x000010c6; /* Sparc is 32-bit just like ix86 */ + + __asm__("sethi %hi(_loops_per_sec), %o1\n\t" + "ld [%o1 + %lo(_loops_per_sec)], %o1\n\t" + "call ___delay\n\t" + "umul %o1, %o0, %o0\n\t"); +} + +#endif /* defined(__SPARC_DELAY_H) */ diff -u --recursive --new-file v1.1.72/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h --- v1.1.72/linux/include/asm-sparc/openprom.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/openprom.h Mon Dec 12 20:39:19 1994 @@ -0,0 +1,262 @@ +/* openprom.h: Prom structures and defines for access to the OPENBOOT + prom routines and data areas. + + Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) +*/ + +/* In the v0 interface of the openboot prom we could traverse a nice + little list structure to figure out where in vm-space the prom had + mapped itself and how much space it was taking up. In the v2 prom + interface we have to rely on 'magic' values. :-( Most of the machines + I have checked on have the prom mapped here all the time though. +*/ +#define LINUX_OPPROM_BEGVM 0xffd00000 +#define LINUX_OPPROM_ENDVM 0xfff00000 + +#define LINUX_OPPROM_MAGIC 0x10010407 + +/* The device functions structure for the v0 prom. Nice and neat, open, + close, read & write divied up between net + block + char devices. We + also have a seek routine only usable for block devices. The divide + and conquer strategy of this struct becomes unnecessary for v2. + + V0 device names are limited to two characters, 'sd' for scsi-disk, + 'le' for local-ethernet, etc. Note that it is technically possible + to boot a kernel off of a tape drive and use the tape as the root + partition! In order to do this you have to have 'magic' formatted + tapes from Sun supposedly :-) +*/ + +struct linux_dev_v0_funcs { + int (*v0_devopen)(char *device_str); + int (*v0_devclose)(int dev_desc); + int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, caddr_t buf); + int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, caddr_t buf); + int (*v0_wrnetdev)(int dev_desc, int num_bytes, caddr_t buf); + int (*v0_rdnetdev)(int dev_desc, int num_bytes, caddr_t buf); + int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, caddr_t buf); + int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, caddr_t buf); + int (*v0_seekdev)(int dev_desc, long logical_offst, int from); +}; + +/* The OpenBoot Prom device operations for version-2 interfaces are both + good and bad. They now allow you to address ANY device whatsoever + that is in the machine via these funny "device paths". They look like + this: + + "/sbus/esp@0,0xf004002c/sd@3,1" + + You can basically reference any device on the machine this way, and + you pass this string to the v2 dev_ops. Producing these strings all + the time can be a pain in the rear after a while. Why v2 has memory + allocations in here are beyond me. Perhaps they figure that if you + are going to use only the prom's device drivers then your memory + management is either non-existant or pretty sad. :-) +*/ + +struct linux_dev_v2_funcs { + int (*v2_aieee)(int d); /* figure this out later... */ + + /* "dumb" prom memory management routines, probably + only safe to use for mapping device address spaces... + */ + + caddr_t (*v2_dumb_mem_alloc)(caddr_t va, unsigned sz); + void (*v2_dumb_mem_free)(caddr_t va, unsigned sz); + + /* "dumb" mmap() munmap(), copy on write? whats that? */ + caddr_t (*v2_dumb_mmap)(caddr_t virta, int asi, unsigned prot, unsigned sz); + void (*v2_dumb_munmap)(caddr_t virta, unsigned size); + + /* Basic Operations, self-explanatory */ + int (*v2_dev_open)(char *devpath); + void (*v2_dev_close)(int d); + int (*v2_dev_read)(int d, caddr_t buf, int nbytes); + int (*v2_dev_write)(int d, caddr_t buf, int nbytes); + void (*v2_dev_seek)(int d, int hi, int lo); + + /* huh? */ + void (*v2_wheee2)(); + void (*v2_wheee3)(); +}; + +/* Just like the device ops, they slightly screwed up the mem-list + from v0 to v2. Probably easier on the prom-writer dude, sucks for + us though. See above comment about prom-vm mapped address space + magic numbers. :-( +*/ + +struct linux_mlist_v0 { + struct linux_mlist_v0 *theres_more; + caddr_t start_adr; + unsigned num_bytes; +}; + +/* The linux_mlist_v0's are pointer by this structure. One list + per description. This means one list for total physical memory, + one for prom's address mapping, and one for physical mem left after + the kernel is loaded. + */ +struct linux_mem_v0 { + struct linux_mlist_v0 **v0_totphys; /* all of physical */ + struct linux_mlist_v0 **v0_prommap; /* addresses map'd by prom */ + struct linux_mlist_v0 **v0_available; /* what phys. is left over */ +}; + +/* Arguements sent to the kernel from the boot prompt. */ + +struct linux_arguments_v0 { + char *argv[8]; /* argv format for boot string */ + char args[100]; /* string space */ + char boot_dev[2]; /* e.g., "sd" for `b sd(...' */ + int boot_dev_ctrl; /* controller # */ + int boot_dev_unit; /* unit # */ + int dev_partition; /* partition # */ + char *kernel_file_name; /* kernel to boot, e.g., "vmunix" */ + void *aieee1; /* give me some time :> */ +}; + +/* Prom version-2 gives us the raw strings for boot arguments and + boot device path. We also get the stdin and stdout file pseudo + descriptors for use with the mungy v2 device functions. +*/ +struct linux_bootargs_v2 { + char **bootpath; /* V2: Path to boot device */ + char **bootargs; /* V2: Boot args */ + int *fd_stdin; /* V2: Stdin descriptor */ + int *fd_stdout; /* V2: Stdout descriptor */ +}; + +/* This is the actual Prom Vector from which everything else is accessed + via struct and function pointers, etc. The prom when it loads us into + memory plops a pointer to this master structure in register %o0 before + it jumps to the kernel start address. I will update this soon to cover + the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-) +*/ +struct promvec { + /* Version numbers. */ + u_int pv_magic; /* Magic number */ + u_int pv_romvec_vers; /* interface version (0, 2) */ + u_int pv_plugin_vers; /* ??? */ + u_int pv_printrev; /* PROM rev # (* 10, e.g 1.9 = 19) */ + + /* Version 0 memory descriptors (see below). */ + struct v0mem pv_v0mem; /* V0: Memory description lists. */ + + /* Node operations (see below). */ + struct nodeops *pv_nodeops; /* node functions */ + + char **pv_bootstr; /* Boot command, eg sd(0,0,0)vmunix */ + + struct v0devops pv_v0devops; /* V0: device ops */ + + /* + * PROMDEV_* cookies. I fear these may vanish in lieu of fd0/fd1 + * (see below) in future PROMs, but for now they work fine. + */ + char *pv_stdin; /* stdin cookie */ + char *pv_stdout; /* stdout cookie */ +#define PROMDEV_KBD 0 /* input from keyboard */ +#define PROMDEV_SCREEN 0 /* output to screen */ +#define PROMDEV_TTYA 1 /* in/out to ttya */ +#define PROMDEV_TTYB 2 /* in/out to ttyb */ + + /* Blocking getchar/putchar. NOT REENTRANT! (grr) */ + int (*pv_getchar)(void); + void (*pv_putchar)(int ch); + + /* Non-blocking variants that return -1 on error. */ + int (*pv_nbgetchar)(void); + int (*pv_nbputchar)(int ch); + + /* Put counted string (can be very slow). */ + void (*pv_putstr)(char *str, int len); + + /* Miscellany. */ + void (*pv_reboot)(char *bootstr); + void (*pv_printf)(const char *fmt, ...); + void (*pv_abort)(void); /* L1-A abort */ + int *pv_ticks; /* Ticks since last reset */ + __dead void (*pv_halt)(void); /* Halt! */ + void (**pv_synchook)(void); /* "sync" command hook */ + + /* + * This eval's a FORTH string. Unfortunately, its interface + * changed between V0 and V2, which gave us much pain. + */ + union { + void (*v0_eval)(int len, char *str); + void (*v2_eval)(char *str); + } pv_fortheval; + + struct v0bootargs **pv_v0bootargs; /* V0: Boot args */ + + /* Extract Ethernet address from network device. */ + u_int (*pv_enaddr)(int d, char *enaddr); + + struct v2bootargs pv_v2bootargs; /* V2: Boot args + std in/out */ + struct v2devops pv_v2devops; /* V2: device operations */ + + int pv_spare[15]; + + /* + * The following is machine-dependent. + * + * The sun4c needs a PROM function to set a PMEG for another + * context, so that the kernel can map itself in all contexts. + * It is not possible simply to set the context register, because + * contexts 1 through N may have invalid translations for the + * current program counter. The hardware has a mode in which + * all memory references go to the PROM, so the PROM can do it + * easily. + */ + void (*pv_setctxt)(int ctxt, caddr_t va, int pmeg); +}; + +/* + * In addition to the global stuff defined in the PROM vectors above, + * the PROM has quite a collection of `nodes'. A node is described by + * an integer---these seem to be internal pointers, actually---and the + * nodes are arranged into an N-ary tree. Each node implements a fixed + * set of functions, as described below. The first two deal with the tree + * structure, allowing traversals in either breadth- or depth-first fashion. + * The rest deal with `properties'. + * + * A node property is simply a name/value pair. The names are C strings + * (NUL-terminated); the values are arbitrary byte strings (counted strings). + * Many values are really just C strings. Sometimes these are NUL-terminated, + * sometimes not, depending on the the interface version; v0 seems to + * terminate and v2 not. Many others are simply integers stored as four + * bytes in machine order: you just get them and go. The third popular + * format is an `address', which is made up of one or more sets of three + * integers as defined below. + * + * N.B.: for the `next' functions, next(0) = first, and next(last) = 0. + * Whoever designed this part had good taste. On the other hand, these + * operation vectors are global, rather than per-node, yet the pointers + * are not in the openprom vectors but rather found by indirection from + * there. So the taste balances out. + */ +struct openprom_addr { + int oa_space; /* address space (may be relative) */ + u_int oa_base; /* address within space */ + u_int oa_size; /* extent (number of bytes) */ +}; + +struct nodeops { + /* + * Tree traversal. + */ + int (*no_nextnode)(int node); /* next(node) */ + int (*no_child)(int node); /* first child */ + + /* + * Property functions. Proper use of getprop requires calling + * proplen first to make sure it fits. Kind of a pain, but no + * doubt more convenient for the PROM coder. + */ + int (*no_proplen)(int node, caddr_t name); + int (*no_getprop)(int node, caddr_t name, caddr_t val); + int (*no_setprop)(int node, caddr_t name, caddr_t val, int len); + caddr_t (*no_nextprop)(int node, caddr_t name); +}; diff -u --recursive --new-file v1.1.72/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h --- v1.1.72/linux/include/asm-sparc/string.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/string.h Thu Dec 15 09:22:01 1994 @@ -0,0 +1,11 @@ +/* string.h: External definitions for optimized assembly string + routines for the Linux Kernel. + + Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) +*/ + +extern int strlen(char* str); +extern int strcmp(char* str1, char* str2); +extern int strncmp(char* str1, char* str2, int strlen); +extern int strcpy(char* dest, char* source); +extern int strncpy(char* dest, char* source, int cpylen); diff -u --recursive --new-file v1.1.72/linux/include/asm-sparc/types.h linux/include/asm-sparc/types.h --- v1.1.72/linux/include/asm-sparc/types.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/types.h Thu Dec 15 09:22:01 1994 @@ -0,0 +1,45 @@ +#ifndef _SPARC_TYPES_H +#define _SPARC_TYPES_H + +/* + * _xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space <-- Linus sez this + */ + +/* NOTE: I will have to change these when the V9 sparcs come into play, + * however this won't be for a while. + */ + +typedef signed char __s8; +typedef unsigned char __u8; + +typedef signed short __s16; +typedef unsigned short __u16; + +typedef signed int __s32; +typedef unsigned int __u32; + +/* Only 32-bit sparcs for now so.... */ + +typedef signed long long __s64; +typedef unsigned long long __s64; + +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +/* Again, only have to worry about 32-bits */ + +typedef signed long long s64; +typedef unsigned long long u64; + +#endif /* __KERNEL__ */ + +#endif /* defined(_SPARC_TYPES_H) */ diff -u --recursive --new-file v1.1.72/linux/include/linux/in.h linux/include/linux/in.h --- v1.1.72/linux/include/linux/in.h Thu Dec 1 19:15:05 1994 +++ linux/include/linux/in.h Thu Dec 15 08:28:07 1994 @@ -87,6 +87,7 @@ #define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) #define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_MULTICAST_NET 0xF0000000 #define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) @@ -104,19 +105,13 @@ #define IN_LOOPBACKNET 127 /* Address to loopback in software to local host. */ -#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ - - -/* - * Options for use with `getsockopt' and `setsockopt' at - * the IP level. LINUX does not yet have the IP_OPTIONS - * option (grin), so we undefine it for now.- HJ && FvK - */ -#if 0 -# define IP_OPTIONS 1 /* IP per-packet options */ -#endif -#define IP_HDRINCL 2 /* raw packet header option */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ +/* Defines for Multicast INADDR */ +#define INADDR_UNSPEC_GROUP 0xe0000000 /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001 /* 224.0.0.1 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ff /* 224.0.0.255 */ + /* Linux Internet number representation function declarations. */ #undef ntohl diff -u --recursive --new-file v1.1.72/linux/include/linux/ip.h linux/include/linux/ip.h --- v1.1.72/linux/include/linux/ip.h Sat Dec 3 13:05:43 1994 +++ linux/include/linux/ip.h Thu Dec 15 08:28:07 1994 @@ -28,6 +28,8 @@ #define IPOPT_TIMESTAMP 68 +#define MAXTTL 255 + struct timestamp { __u8 len; __u8 ptr; diff -u --recursive --new-file v1.1.72/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v1.1.72/linux/include/linux/proc_fs.h Tue Dec 6 17:37:06 1994 +++ linux/include/linux/proc_fs.h Mon Dec 12 20:13:07 1994 @@ -26,7 +26,8 @@ PROC_FILESYSTEMS, PROC_KSYMS, PROC_DMA, - PROC_IOPORTS + PROC_IOPORTS, + PROC_PROFILE /* wether enabled or not */ }; enum pid_directory_inos { @@ -109,6 +110,7 @@ extern struct inode_operations proc_mem_inode_operations; extern struct inode_operations proc_array_inode_operations; extern struct inode_operations proc_kcore_inode_operations; +extern struct inode_operations proc_profile_inode_operations; extern struct inode_operations proc_kmsg_inode_operations; extern struct inode_operations proc_link_inode_operations; extern struct inode_operations proc_fd_inode_operations; diff -u --recursive --new-file v1.1.72/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.72/linux/include/linux/sched.h Mon Dec 5 18:47:56 1994 +++ linux/include/linux/sched.h Mon Dec 12 21:33:00 1994 @@ -14,13 +14,16 @@ /* * System setup and hardware bug flags.. */ -extern int hard_math; -extern int x86; +extern char hard_math; +extern char x86; /* lower 4 bits */ extern char x86_vendor_id[13]; -extern fdiv_bug; -extern int ignore_irq13; -extern int wp_works_ok; /* doesn't work on a 386 */ -extern int hlt_works_ok; /* problems on some 486Dx4's and old 386's */ +extern char x86_model; /* lower 4 bits */ +extern char x86_mask; /* lower 4 bits */ +extern int x86_capability; /* field of flags */ +extern int fdiv_bug; +extern char ignore_irq13; +extern char wp_works_ok; /* doesn't work on a 386 */ +extern char hlt_works_ok; /* problems on some 486Dx4's and old 386's */ extern unsigned long intr_count; extern unsigned long event; diff -u --recursive --new-file v1.1.72/linux/include/linux/socket.h linux/include/linux/socket.h --- v1.1.72/linux/include/linux/socket.h Thu Dec 1 19:15:05 1994 +++ linux/include/linux/socket.h Mon Dec 12 21:01:09 1994 @@ -81,8 +81,10 @@ #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IP_TTL 2 +#ifdef 1_3_WILL_DO_THIS_FUNKY_STUFF #define IP_HRDINCL 3 #define IP_OPTIONS 4 +#endif #define IP_MULTICAST_IF 32 #define IP_MULTICAST_TTL 33 diff -u --recursive --new-file v1.1.72/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.1.72/linux/include/linux/tty.h Tue Oct 18 10:07:59 1994 +++ linux/include/linux/tty.h Mon Dec 12 21:19:00 1994 @@ -322,8 +322,6 @@ extern int con_open(struct tty_struct * tty, struct file * filp); extern void update_screen(int new_console); -extern void blank_screen(void); -extern void unblank_screen(void); /* vt.c */ diff -u --recursive --new-file v1.1.72/linux/include/linux/types.h linux/include/linux/types.h --- v1.1.72/linux/include/linux/types.h Mon Nov 28 14:21:46 1994 +++ linux/include/linux/types.h Wed Dec 14 14:45:57 1994 @@ -3,16 +3,6 @@ #include -#ifndef _SIZE_T -#define _SIZE_T -typedef unsigned int size_t; -#endif - -#ifndef _SSIZE_T -#define _SSIZE_T -typedef int ssize_t; -#endif - #ifndef _TIME_T #define _TIME_T typedef long time_t; @@ -21,11 +11,6 @@ #ifndef _CLOCK_T #define _CLOCK_T typedef long clock_t; -#endif - -#ifndef _PTRDIFF_T -#define _PTRDIFF_T -typedef int ptrdiff_t; #endif #ifndef NULL diff -u --recursive --new-file v1.1.72/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h --- v1.1.72/linux/include/linux/umsdos_fs.h Mon Nov 28 14:21:47 1994 +++ linux/include/linux/umsdos_fs.h Mon Dec 12 21:15:19 1994 @@ -79,12 +79,38 @@ #define UMSDOS_INIT_EMD 1242 /* Create the EMD file if not there */ #define UMSDOS_DOS_SETUP 1243 /* Set the defaults of the MsDOS driver */ -#include - struct umsdos_ioctl{ struct dirent dos_dirent; struct umsdos_dirent umsdos_dirent; - struct new_stat stat; + /* The following structure is used to exchange some data */ + /* with utilities (umsdos_progs/util/umsdosio.c). The first */ + /* releases were using struct stat from "sys/stat.h". This was */ + /* causing some problem for cross compilation of the kernel */ + /* Since I am not really using the structure stat, but only some field */ + /* of it, I have decided to replicate the structure here */ + /* for compatibility with the binaries out there */ + struct { + dev_t st_dev; + unsigned short __pad1; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned short __pad2; + off_t st_size; + unsigned long st_blksize; + unsigned long st_blocks; + time_t st_atime; + unsigned long __unused1; + time_t st_mtime; + unsigned long __unused2; + time_t st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; + }stat; char version,release; }; diff -u --recursive --new-file v1.1.72/linux/init/main.c linux/init/main.c --- v1.1.72/linux/init/main.c Tue Dec 6 17:37:06 1994 +++ linux/init/main.c Wed Dec 14 14:18:14 1994 @@ -26,7 +26,7 @@ extern unsigned long * prof_buffer; extern unsigned long prof_len; -extern char edata, end; +extern char etext, end; extern char *linux_banner; asmlinkage void lcall7(void); struct desc_struct default_ldt; @@ -95,6 +95,7 @@ extern void aha152x_setup(char *str, int *ints); extern void aha1542_setup(char *str, int *ints); extern void aha274x_setup(char *str, int *ints); +extern void buslogic_setup(char *str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); #ifdef CONFIG_SBPCD @@ -219,6 +220,9 @@ #ifdef CONFIG_SCSI_AHA274X { "aha274x=", aha274x_setup}, #endif +#ifdef CONFIG_SCSI_BUSLOGIC + { "buslogic=", buslogic_setup}, +#endif #ifdef CONFIG_BLK_DEV_XD { "xd=", xd_setup }, #endif @@ -279,12 +283,7 @@ __delay(loops_per_sec); ticks = jiffies - ticks; if (ticks >= HZ) { - __asm__("mull %1 ; divl %2" - :"=a" (loops_per_sec) - :"d" (HZ), - "r" (ticks), - "0" (loops_per_sec) - :"dx"); + loops_per_sec = muldiv(loops_per_sec, HZ, ticks); printk("ok - %lu.%02lu BogoMips\n", loops_per_sec/500000, (loops_per_sec/5000) % 100); @@ -390,8 +389,16 @@ int len = 0; for (;;) { - if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") + if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") { memory_end = simple_strtoul(from+4, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + memory_end = memory_end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + memory_end = memory_end << 20; + from++; + } + } c = *(from++); if (!c) break; @@ -418,7 +425,6 @@ static double x = 4195835.0; static double y = 3145727.0; unsigned short control_word; - extern int fdiv_bug; if (!hard_math) { #ifndef CONFIG_MATH_EMULATION @@ -528,8 +534,9 @@ init_modules(); #ifdef CONFIG_PROFILE prof_buffer = (unsigned long *) memory_start; - prof_len = (unsigned long) &end; - prof_len >>= 2; + /* only text is profiled */ + prof_len = (unsigned long) &etext; + prof_len >>= CONFIG_PROFILE_SHIFT; memory_start += prof_len * sizeof(unsigned long); #endif memory_start = console_init(memory_start,memory_end); diff -u --recursive --new-file v1.1.72/linux/ipc/sem.c linux/ipc/sem.c --- v1.1.72/linux/ipc/sem.c Thu Nov 3 17:53:30 1994 +++ linux/ipc/sem.c Mon Dec 12 21:41:30 1994 @@ -155,7 +155,7 @@ int i, id, val = 0; struct semid_ds *sma; struct ipc_perm *ipcp; - struct sem *curr; + struct sem *curr = NULL; struct sem_undo *un; unsigned int nsems; ushort *array = NULL; @@ -219,9 +219,18 @@ nsems = sma->sem_nsems; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) return -EIDRM; - if (semnum >= nsems) - return -EINVAL; - curr = &sma->sem_base[semnum]; + + switch (cmd) { + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case SETVAL: + if (semnum >= nsems) + return -EINVAL; + curr = &sma->sem_base[semnum]; + break; + } switch (cmd) { case GETVAL: diff -u --recursive --new-file v1.1.72/linux/kernel/sched.c linux/kernel/sched.c --- v1.1.72/linux/kernel/sched.c Mon Dec 5 18:47:56 1994 +++ linux/kernel/sched.c Mon Dec 12 21:33:00 1994 @@ -68,15 +68,18 @@ /* * Tell us the machine setup.. */ -int hard_math = 0; /* set by boot/head.S */ -int x86 = 0; /* set by boot/head.S to 3 or 4 */ +char hard_math = 0; /* set by boot/head.S */ +char x86 = 0; /* set by boot/head.S to 3 or 4 */ +char x86_model = 0; /* set by boot/head.S */ +char x86_mask = 0; /* set by boot/head.S */ +int x86_capability = 0; /* set by boot/head.S */ int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */ char x86_vendor_id[13] = "Unknown"; -int ignore_irq13 = 0; /* set if exception 16 works */ -int wp_works_ok = 0; /* set if paging hardware honours WP */ -int hlt_works_ok = 1; /* set if the "hlt" instruction works */ +char ignore_irq13 = 0; /* set if exception 16 works */ +char wp_works_ok = 0; /* set if paging hardware honours WP */ +char hlt_works_ok = 1; /* set if the "hlt" instruction works */ /* * Bus types .. @@ -679,7 +682,7 @@ #ifdef CONFIG_PROFILE if (prof_buffer && current != task[0]) { unsigned long eip = regs->eip; - eip >>= 2; + eip >>= CONFIG_PROFILE_SHIFT; if (eip < prof_len) prof_buffer[eip]++; } diff -u --recursive --new-file v1.1.72/linux/mm/swap.c linux/mm/swap.c --- v1.1.72/linux/mm/swap.c Tue Dec 6 17:37:07 1994 +++ linux/mm/swap.c Wed Dec 14 08:36:40 1994 @@ -769,6 +769,8 @@ if (!page) continue; if (page & PAGE_PRESENT) { + if (page >= high_memory) + continue; if (!(page = in_swap_cache(page))) continue; if (SWP_TYPE(page) != type) diff -u --recursive --new-file v1.1.72/linux/modules/NET_MODULES linux/modules/NET_MODULES --- v1.1.72/linux/modules/NET_MODULES Tue Dec 6 17:37:07 1994 +++ linux/modules/NET_MODULES Thu Dec 15 08:40:19 1994 @@ -1 +1 @@ -3c509.o de600.o de620.o 3c501.o apricot.o eexpress.o plip.o 8390.o +3c509.o de600.o de620.o 3c501.o apricot.o eexpress.o plip.o 8390.o slip.o slhc.o diff -u --recursive --new-file v1.1.72/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.72/linux/net/inet/af_inet.c Sat Dec 3 13:05:43 1994 +++ linux/net/inet/af_inet.c Wed Dec 14 09:02:26 1994 @@ -21,6 +21,10 @@ * Alan Cox : Asynchronous I/O support * Alan Cox : Keep correct socket pointer on sock structures * when accept() ed + * Alan Cox : Semantics of SO_LINGER aren't state moved + * to close when you look carefully. With + * this fixed and the accept bug fixed + * some RPC stuff seems happier. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -660,7 +664,7 @@ sk->ip_tos=0; sk->ip_ttl=64; #ifdef CONFIG_IP_MULTICAST - sk->ip_mc_loop=0; + sk->ip_mc_loop=1; sk->ip_mc_ttl=1; *sk->ip_mc_name=0; sk->ip_mc_list=NULL; @@ -739,7 +743,8 @@ cli(); if (sk->lingertime) current->timeout = jiffies + HZ*sk->lingertime; - while(sk->state != TCP_CLOSE && current->timeout>0) + while(sk->state < TCP_LAST_ACK && sk->state!= TCP_FIN_WAIT2 && + sk->state != TCP_TIME_WAIT && current->timeout>0) { interruptible_sleep_on(sk->sleep); if (current->signal & ~current->blocked) @@ -803,7 +808,7 @@ return(-EACCES); chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr); - if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR) + if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST) return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ if (chk_addr_ret || addr->sin_addr.s_addr == 0) diff -u --recursive --new-file v1.1.72/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.72/linux/net/inet/dev.c Sat Dec 3 13:05:43 1994 +++ linux/net/inet/dev.c Wed Dec 14 09:02:26 1994 @@ -25,6 +25,8 @@ * ???????? : Support the full private ioctl range * Alan Cox : Moved ioctl permission check into drivers * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI + * Alan Cox : 100 backlog just doesn't cut it when + * you start doing multicast video 8) * * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have * the rest as well commented in the end. @@ -267,14 +269,19 @@ */ if (ret == 0) + { dev->flags |= (IFF_UP | IFF_RUNNING); - - /* - * Initialise multicasting status - */ - - dev_mc_upload(dev); - + /* + * Initialise multicasting status + */ +#ifdef CONFIG_IP_MULTICAST + /* + * Join the all host group + */ + ip_mc_allhost(dev); +#endif + dev_mc_upload(dev); + } return(ret); } @@ -496,7 +503,7 @@ if (!backlog_size) dropping = 0; - else if (backlog_size > 100) + else if (backlog_size > 300) dropping = 1; if (dropping) diff -u --recursive --new-file v1.1.72/linux/net/inet/dev_mcast.c linux/net/inet/dev_mcast.c --- v1.1.72/linux/net/inet/dev_mcast.c Thu Dec 1 19:15:06 1994 +++ linux/net/inet/dev_mcast.c Wed Dec 14 09:02:26 1994 @@ -57,16 +57,26 @@ void dev_mc_upload(struct device *dev) { struct dev_mc_list *dmi; - char *data; - - /* Promiscuous is promiscuous - so no filter needed */ - - if(dev->flags&IFF_PROMISC) + char *data, *tmp; + + /* Don't do anything till we up the interface + [dev_open will call this function so the list will + stay sane] */ + + if(!(dev->flags&IFF_UP)) return; + /* Devices with no set multicast don't get set */ if(dev->set_multicast_list==NULL) return; + /* Promiscuous is promiscuous - so no filter needed */ + if(dev->flags&IFF_PROMISC) + { + dev->set_multicast_list(dev, -1, NULL); + return; + } + if(dev->mc_count==0) { dev->set_multicast_list(dev,0,NULL); @@ -79,13 +89,13 @@ printk("Unable to get memory to set multicast list on %s\n",dev->name); return; } - for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) + for(tmp = data, dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) { - memcpy(data,dmi->dmi_addr, dmi->dmi_addrlen); - data+=dev->addr_len; + memcpy(tmp,dmi->dmi_addr, dmi->dmi_addrlen); + tmp+=dev->addr_len; } dev->set_multicast_list(dev,dev->mc_count,data); - kfree_s(data,dev->mc_count*dev->addr_len); + kfree(data); } /* diff -u --recursive --new-file v1.1.72/linux/net/inet/icmp.c linux/net/inet/icmp.c --- v1.1.72/linux/net/inet/icmp.c Tue Nov 22 15:41:14 1994 +++ linux/net/inet/icmp.c Mon Dec 12 21:01:10 1994 @@ -27,6 +27,7 @@ * A.N.Kuznetsov : Multihoming fixes. * Laco Rusnak : Multihoming fixes. * Alan Cox : Tightened up icmp_send(). + * Alan Cox : Multicasts. * * * @@ -656,7 +657,7 @@ * Parse the ICMP message */ - if (ip_chk_addr(daddr) == IS_BROADCAST) + if (ip_chk_addr(daddr) != IS_MYADDR) { if (icmph->type != ICMP_ECHO) { diff -u --recursive --new-file v1.1.72/linux/net/inet/igmp.c linux/net/inet/igmp.c --- v1.1.72/linux/net/inet/igmp.c Tue Dec 6 17:37:07 1994 +++ linux/net/inet/igmp.c Thu Dec 15 08:28:07 1994 @@ -245,11 +245,11 @@ static void ip_mc_dec_group(struct device *dev, unsigned long addr) { struct ip_mc_list **i; - for(i=&dev->ip_mc_list;i!=NULL;i=&(*i)->next) + for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next) { if((*i)->multiaddr==addr) { - if(--(*i)->users) + if(--((*i)->users)) return; else { @@ -278,6 +278,28 @@ dev->ip_mc_list=NULL; } +/* + * Device going up. Make sure it is in all hosts + */ + +void ip_mc_allhost(struct device *dev) +{ + struct ip_mc_list *i; + for(i=dev->ip_mc_list;i!=NULL;i=i->next) + if(i->multiaddr==IGMP_ALL_HOSTS) + return; + i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL); + if(!i) + return; + i->users=1; + i->interface=dev; + i->multiaddr=IGMP_ALL_HOSTS; + i->next=dev->ip_mc_list; + dev->ip_mc_list=i; + ip_mc_filter_add(i->interface, i->multiaddr); + +} + /* * Join a socket to a group */ diff -u --recursive --new-file v1.1.72/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.72/linux/net/inet/ip.c Tue Dec 6 17:37:07 1994 +++ linux/net/inet/ip.c Wed Dec 14 09:34:15 1994 @@ -58,10 +58,19 @@ * Richard Underwood : IP multicasting. * Alan Cox : Cleaned up multicast handlers. * Alan Cox : RAW sockets demultiplex in the BSD style. + * Gunther Mayer : Fix the SNMP reporting typo + * Alan Cox : Always in group 224.0.0.1 * * To Fix: * IP option processing is mostly not needed. ip_forward needs to know about routing rules * and time stamp but that's about all. Use the route mtu field here too + * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient + * and could be made very efficient with the addition of some virtual memory hacks to permit + * the allocation of a buffer that can then be 'grown' by twiddling page tables. + * Output fragmentation wants updating along with the buffer management to use a single + * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet + * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause + * fragmentation anyway. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -107,10 +116,10 @@ * SNMP management statistics */ -#ifdef CONFIG_IP_FORWARDING +#ifdef CONFIG_IP_FORWARD struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */ #else -struct ip_mib ip_statistics={1,64,}; /* Forwarding=No, Default TTL=64 */ +struct ip_mib ip_statistics={0,64,}; /* Forwarding=No, Default TTL=64 */ #endif #ifdef CONFIG_IP_MULTICAST @@ -326,6 +335,10 @@ #ifdef Not_Yet_Avail build_options(iph, opt); #endif +#ifdef CONFIG_IP_FIREWALL + if(!ip_fw_chk(iph,ip_fw_blk_chain)) + return -EPERM; +#endif return(20 + tmp); /* IP header plus MAC header size */ } @@ -569,13 +582,13 @@ * Generate a checksum for an outgoing IP datagram. */ -static void ip_send_check(struct iphdr *iph) +void ip_send_check(struct iphdr *iph) { iph->check = 0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } -/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/ +/************************ Fragment Handlers From NET2E **********************************/ /* @@ -1598,7 +1611,8 @@ } #ifdef CONFIG_IP_MULTICAST - if(brd==IS_MULTICAST) + + if(brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK)) { /* * Check it is for one of our groups @@ -1746,6 +1760,7 @@ static void ip_loopback(struct device *old_dev, struct sk_buff *skb) { + extern struct device loopback_dev; struct device *dev=&loopback_dev; int len=skb->len-old_dev->hard_header_len; struct sk_buff *newskb=alloc_skb(len+dev->hard_header_len, GFP_ATOMIC); @@ -1931,22 +1946,26 @@ * Multicasts are looped back for other local users */ - if (MULTICAST(skb->daddr) && !(dev->flags&IFF_LOOPBACK)) + if (MULTICAST(iph->daddr) && !(dev->flags&IFF_LOOPBACK)) { if(sk==NULL || sk->ip_mc_loop) { - struct ip_mc_list *imc=dev->ip_mc_list; - while(imc!=NULL) + if(skb->daddr==IGMP_ALL_HOSTS) + ip_loopback(dev,skb); + else { - if(imc->multiaddr==skb->daddr) + struct ip_mc_list *imc=dev->ip_mc_list; + while(imc!=NULL) { - ip_loopback(dev,skb); - break; + if(imc->multiaddr==iph->daddr) + { + ip_loopback(dev,skb); + break; + } + imc=imc->next; } - imc=imc->next; } } - /* Multicasts with ttl 0 must not go beyond the host */ if(skb->ip_hdr->ttl==0) @@ -1984,127 +2003,6 @@ } -/* - * A socket has timed out on its send queue and wants to do a - * little retransmitting. Currently this means TCP. - */ - -void ip_do_retransmit(struct sock *sk, int all) -{ - struct sk_buff * skb; - struct proto *prot; - struct device *dev; - - prot = sk->prot; - skb = sk->send_head; - - while (skb != NULL) - { - dev = skb->dev; - IS_SKB(skb); - skb->when = jiffies; - - /* - * In general it's OK just to use the old packet. However we - * need to use the current ack and window fields. Urg and - * urg_ptr could possibly stand to be updated as well, but we - * don't keep the necessary data. That shouldn't be a problem, - * if the other end is doing the right thing. Since we're - * changing the packet, we have to issue a new IP identifier. - */ - - /* this check may be unnecessary - retransmit only for TCP */ - if (sk->protocol == IPPROTO_TCP) { - struct tcphdr *th; - struct iphdr *iph; - int size; - - iph = (struct iphdr *)(skb->data + dev->hard_header_len); - th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2)); - size = skb->len - (((unsigned char *) th) - skb->data); - - iph->id = htons(ip_id_count++); - ip_send_check(iph); - - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); - tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - } - - /* - * If the interface is (still) up and running, kick it. - */ - - if (dev->flags & IFF_UP) - { - /* - * If the packet is still being sent by the device/protocol - * below then don't retransmit. This is both needed, and good - - * especially with connected mode AX.25 where it stops resends - * occurring of an as yet unsent anyway frame! - * We still add up the counts as the round trip time wants - * adjusting. - */ - if (sk && !skb_device_locked(skb)) - { - /* Remove it from any existing driver queue first! */ - skb_unlink(skb); - /* Now queue it */ - ip_statistics.IpOutRequests++; - dev_queue_xmit(skb, dev, sk->priority); - } - } - - /* - * Count retransmissions - */ - sk->retransmits++; - sk->prot->retransmits ++; - - /* - * Only one retransmit requested. - */ - if (!all) - break; - - /* - * This should cut it off before we send too many packets. - */ - if (sk->retransmits >= sk->cong_window) - break; - skb = skb->link3; - } -} - -/* - * This is the normal code called for timeouts. It does the retransmission - * and then does backoff. ip_do_retransmit is separated out because - * tcp_ack needs to send stuff from the retransmit queue without - * initiating a backoff. - */ - -void ip_retransmit(struct sock *sk, int all) -{ - ip_do_retransmit(sk, all); - - /* - * Increase the timeout each time we retransmit. Note that - * we do not increase the rtt estimate. rto is initialized - * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests - * that doubling rto each time is the least we can get away with. - * In KA9Q, Karn uses this for the first few times, and then - * goes to quadratic. netBSD doubles, but only goes up to *64, - * and clamps at 1 to 64 sec afterwards. Note that 120 sec is - * defined in the protocol as the maximum possible RTT. I guess - * we'll have to use something other than TCP to talk to the - * University of Mars. - */ - - sk->retransmits++; - sk->backoff++; - sk->rto = min(sk->rto << 1, 120*HZ); - reset_timer(sk, TIME_WRITE, sk->rto); -} #ifdef CONFIG_IP_MULTICAST @@ -2177,6 +2075,19 @@ if(level!=SOL_IP) return -EOPNOTSUPP; +#ifdef CONFIG_IP_MULTICAST + if(optname==IP_MULTICAST_TTL) + { + unsigned char ucval; + ucval=get_fs_byte((unsigned char *)optval); + printk("MC TTL %d\n", ucval); + if(ucval<1||ucval>255) + return -EINVAL; + sk->ip_mc_ttl=(int)ucval; + return 0; + } +#endif + switch(optname) { case IP_TOS: @@ -2194,6 +2105,7 @@ sk->ip_ttl=val; return 0; #ifdef CONFIG_IP_MULTICAST +#ifdef GCC_WORKS case IP_MULTICAST_TTL: { unsigned char ucval; @@ -2205,7 +2117,7 @@ sk->ip_mc_ttl=(int)ucval; return 0; } - +#endif case IP_MULTICAST_IF: { /* Not fully tested */ @@ -2267,9 +2179,7 @@ static struct options optmem; unsigned long route_src; struct rtable *rt; - struct ip_mc_list *l=NULL; struct device *dev=NULL; - int ct=0; /* * Check the arguments. diff -u --recursive --new-file v1.1.72/linux/net/inet/ip.h linux/net/inet/ip.h --- v1.1.72/linux/net/inet/ip.h Thu Dec 1 19:15:06 1994 +++ linux/net/inet/ip.h Mon Dec 12 21:01:10 1994 @@ -85,11 +85,11 @@ extern unsigned short ip_compute_csum(unsigned char * buff, int len); extern int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); +extern void ip_send_check(struct iphdr *ip); +extern int ip_id_count; extern void ip_queue_xmit(struct sock *sk, struct device *dev, struct sk_buff *skb, int free); -extern void ip_retransmit(struct sock *sk, int all); -extern void ip_do_retransmit(struct sock *sk, int all); extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen); extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen); extern void ip_init(void); diff -u --recursive --new-file v1.1.72/linux/net/inet/ip_fw.c linux/net/inet/ip_fw.c --- v1.1.72/linux/net/inet/ip_fw.c Tue Dec 6 17:37:07 1994 +++ linux/net/inet/ip_fw.c Mon Dec 12 21:54:05 1994 @@ -435,7 +435,7 @@ #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) -static void free_fw_chain(struct ip_fw **chainptr) +static void free_fw_chain(struct ip_fw *volatile* chainptr) { unsigned long flags; save_flags(flags); @@ -450,11 +450,13 @@ restore_flags(flags); } -static int add_to_chain(struct ip_fw **chainptr, struct ip_fw *frwl) +/* Volatiles to keep some of the compiler versions amused */ + +static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl) { struct ip_fw *ftmp; struct ip_fw *chtmp=NULL; - struct ip_fw *chtmp_prev=NULL; + struct ip_fw *volatile chtmp_prev=NULL; unsigned long flags; unsigned long m_src_mask,m_dst_mask; unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm; @@ -475,6 +477,7 @@ } memcpy(ftmp, frwl, sizeof( struct ip_fw ) ); + ftmp->p_cnt=0L; ftmp->b_cnt=0L; @@ -629,7 +632,7 @@ return(0); } -static int del_from_chain(struct ip_fw **chainptr, struct ip_fw *frwl) +static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl) { struct ip_fw *ftmp,*ltmp; unsigned short tport1,tport2,tmpnum; diff -u --recursive --new-file v1.1.72/linux/net/inet/packet.c linux/net/inet/packet.c --- v1.1.72/linux/net/inet/packet.c Sat Nov 26 18:36:07 1994 +++ linux/net/inet/packet.c Mon Dec 12 21:01:10 1994 @@ -374,7 +374,7 @@ NULL, NULL, ip_queue_xmit, /* These two are not actually used */ - ip_retransmit, + NULL, NULL, NULL, NULL, diff -u --recursive --new-file v1.1.72/linux/net/inet/raw.c linux/net/inet/raw.c --- v1.1.72/linux/net/inet/raw.c Thu Dec 1 19:15:06 1994 +++ linux/net/inet/raw.c Mon Dec 12 21:01:10 1994 @@ -301,7 +301,7 @@ udp_connect, NULL, ip_queue_xmit, - ip_retransmit, + NULL, NULL, NULL, NULL, diff -u --recursive --new-file v1.1.72/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.72/linux/net/inet/tcp.c Tue Dec 6 17:37:07 1994 +++ linux/net/inet/tcp.c Thu Dec 15 08:28:07 1994 @@ -105,13 +105,37 @@ * socket close. * Alan Cox : Reset tracing code. * Alan Cox : Spurious resets on shutdown. + * Alan Cox : Giant 15 minute/60 second timer error + * Alan Cox : Small whoops in selecting before an accept. + * Alan Cox : Kept the state trace facility since its + * handy for debugging. + * Alan Cox : More reset handler fixes. + * Alan Cox : Started rewriting the code based on the RFC's + * for other useful protocol references see: + * Comer, KA9Q NOS, and for a reference on the + * difference between specifications and how BSD + * works see the 4.4lite source. + * A.N.Kuznetsov : Don't time wait on completion of tidy + * close. * * * To Fix: - * Fast path the code. Two things here - fix the window calculation + * Fast path the code. Two things here - fix the window calculation * so it doesn't iterate over the queue, also spot packets with no funny * options arriving in order and process directly. * + * Implement RFC 1191 [Path MTU discovery] + * Look at the effect of implementing RFC 1337 suggestions and their impact. + * Rewrite output state machine to use a single queue and do low window + * situations as per the spec (RFC 1122) + * Speed up input assembly algorithm. + * RFC1323 - PAWS and window scaling. PAWS is required for IPv6 so we + * could do with it working on IPv4 + * User settable/learned rtt/max window/mtu + * Cope with MTU/device switches when retransmitting in tcp. + * + * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -188,6 +212,9 @@ unsigned long tcp_rx_miss=0, tcp_rx_hit1=0, tcp_rx_hit2=0; #endif +/* The less said about this the better, but it works and will do for 1.2 */ + +static struct wait_queue *master_select_wakeup; static __inline__ int min(unsigned int a, unsigned int b) { @@ -198,14 +225,29 @@ #undef STATE_TRACE +#ifdef STATE_TRACE +static char *statename[]={ + "Unused","Established","Syn Sent","Syn Recv", + "Fin Wait 1","Fin Wait 2","Time Wait", "Close", + "Close Wait","Last ACK","Listen","Closing" +}; +#endif + static __inline__ void tcp_set_state(struct sock *sk, int state) { if(sk->state==TCP_ESTABLISHED) tcp_statistics.TcpCurrEstab--; #ifdef STATE_TRACE if(sk->debug) - printk("TCP sk=%s, State %d -> %d\n",sk, sk->state,state); + printk("TCP sk=%p, State %s -> %s\n",sk, statename[sk->state],statename[state]); #endif + /* This is a hack but it doesnt occur often and its going to + be a real to fix nicely */ + + if(state==TCP_ESTABLISHED && sk->state==TCP_SYN_RECV) + { + wake_up_interruptible(&master_select_wakeup); + } sk->state=state; if(state==TCP_ESTABLISHED) tcp_statistics.TcpCurrEstab++; @@ -312,6 +354,138 @@ } /* + * A socket has timed out on its send queue and wants to do a + * little retransmitting. Currently this means TCP. + */ + +void tcp_do_retransmit(struct sock *sk, int all) +{ + struct sk_buff * skb; + struct proto *prot; + struct device *dev; + + prot = sk->prot; + skb = sk->send_head; + + while (skb != NULL) + { + struct tcphdr *th; + struct iphdr *iph; + int size; + + dev = skb->dev; + IS_SKB(skb); + skb->when = jiffies; + + /* + * In general it's OK just to use the old packet. However we + * need to use the current ack and window fields. Urg and + * urg_ptr could possibly stand to be updated as well, but we + * don't keep the necessary data. That shouldn't be a problem, + * if the other end is doing the right thing. Since we're + * changing the packet, we have to issue a new IP identifier. + */ + + + iph = (struct iphdr *)(skb->data + dev->hard_header_len); + th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2)); + size = skb->len - (((unsigned char *) th) - skb->data); + + iph->id = htons(ip_id_count++); + ip_send_check(iph); + + /* + * This is not the right way to handle this. We have to + * issue an up to date window and ack report with this + * retransmit to keep the odd buggy tcp that relies on + * the fact BSD does this happy. + * We don't however need to recalculate the entire + * checksum, so someone wanting a small problem to play + * with might like to implement RFC1141/RFC1624 and speed + * this up by avoiding a full checksum. + */ + + th->ack_seq = ntohl(sk->acked_seq); + th->window = ntohs(tcp_select_window(sk)); + tcp_send_check(th, sk->saddr, sk->daddr, size, sk); + + /* + * If the interface is (still) up and running, kick it. + */ + + if (dev->flags & IFF_UP) + { + /* + * If the packet is still being sent by the device/protocol + * below then don't retransmit. This is both needed, and good - + * especially with connected mode AX.25 where it stops resends + * occurring of an as yet unsent anyway frame! + * We still add up the counts as the round trip time wants + * adjusting. + */ + if (sk && !skb_device_locked(skb)) + { + /* Remove it from any existing driver queue first! */ + skb_unlink(skb); + /* Now queue it */ + ip_statistics.IpOutRequests++; + dev_queue_xmit(skb, dev, sk->priority); + } + } + + /* + * Count retransmissions + */ + sk->retransmits++; + sk->prot->retransmits ++; + + /* + * Only one retransmit requested. + */ + if (!all) + break; + + /* + * This should cut it off before we send too many packets. + */ + if (sk->retransmits >= sk->cong_window) + break; + skb = skb->link3; + } +} + +/* + * This is the normal code called for timeouts. It does the retransmission + * and then does backoff. tcp_do_retransmit is separated out because + * tcp_ack needs to send stuff from the retransmit queue without + * initiating a backoff. + */ + +void tcp_retransmit_time(struct sock *sk, int all) +{ + tcp_do_retransmit(sk, all); + + /* + * Increase the timeout each time we retransmit. Note that + * we do not increase the rtt estimate. rto is initialized + * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests + * that doubling rto each time is the least we can get away with. + * In KA9Q, Karn uses this for the first few times, and then + * goes to quadratic. netBSD doubles, but only goes up to *64, + * and clamps at 1 to 64 sec afterwards. Note that 120 sec is + * defined in the protocol as the maximum possible RTT. I guess + * we'll have to use something other than TCP to talk to the + * University of Mars. + */ + + sk->retransmits++; + sk->backoff++; + sk->rto = min(sk->rto << 1, 120*HZ); + reset_timer(sk, TIME_WRITE, sk->rto); +} + + +/* * A timer event has trigger a tcp retransmit timeout. The * socket xmit queue is ready and set up to send. Because * the ack receive code keeps the queue straight we do @@ -322,7 +496,7 @@ { if (all) { - ip_retransmit(sk, all); + tcp_retransmit_time(sk, all); return; } @@ -333,7 +507,7 @@ sk->cong_window = 1; /* Do the actual retransmit. */ - ip_retransmit(sk, all); + tcp_retransmit_time(sk, all); } @@ -489,6 +663,8 @@ { case SEL_IN: select_wait(sk->sleep, wait); + if(sk->state==TCP_LISTEN) + select_wait(&master_select_wakeup,wait); if (skb_peek(&sk->receive_queue) != NULL) { if ((sk->state == TCP_LISTEN && tcp_find_established(sk)) || tcp_readable(sk)) @@ -907,7 +1083,7 @@ * This routine builds a generic TCP header. */ -int tcp_build_header(struct tcphdr *th, struct sock *sk, int push) +extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push) { /* FIXME: want to get rid of this. */ @@ -1694,7 +1870,7 @@ prot =(struct proto *)sk->prot; th =(struct tcphdr *)&sk->dummy_th; - release_sock(sk); /* incase the malloc sleeps. */ + release_sock(sk); /* in case the malloc sleeps. */ buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL); if (buff == NULL) return; @@ -1826,11 +2002,18 @@ struct tcphdr *t1; int tmp; struct device *ndev=NULL; + + /* + * Cannot reset a reset (Think about it). + */ + + if(th->rst) + return; -/* - * We need to grab some memory, and put together an RST, - * and then put it into the queue to be sent. - */ + /* + * We need to grab some memory, and put together an RST, + * and then put it into the queue to be sent. + */ buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC); if (buff == NULL) @@ -1902,6 +2085,9 @@ * However it may also be called with the ack to the SYN. So you * can't assume this is always the SYN. It's always called after * we have set up sk->mtu to our own MTU. + * + * We need at minimum to add PAWS support here. Possibly large windows + * as Linux gets deployed on 100Mb/sec networks. */ static void tcp_options(struct sock *sk, struct tcphdr *th) @@ -2079,6 +2265,7 @@ newsk->rcv_ack_seq = newsk->write_seq; newsk->urg_data = 0; newsk->retransmits = 0; + newsk->linger=0; newsk->destroy = 0; init_timer(&newsk->timer); newsk->timer.data = (unsigned long)newsk; @@ -2520,7 +2707,7 @@ * This routine deals with incoming acks, but not outgoing ones. */ -static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len) +extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len) { unsigned long ack; int flag = 0; @@ -2558,7 +2745,7 @@ * Keepalive processing. */ - if (after(ack, sk->sent_seq) || (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) + if (after(ack, sk->sent_seq)) { return(0); } @@ -2592,6 +2779,11 @@ sk->send_head = NULL; sk->send_tail = NULL; + /* + * This is an artefact of a flawed concept. We want one + * queue and a smarter send routine when we send all. + */ + flag |= 4; sk->window_seq = ack + ntohs(th->window); @@ -2635,6 +2827,10 @@ sti(); } + /* + * Pipe has emptied + */ + if (sk->send_tail == NULL || sk->send_head == NULL) { sk->send_head = NULL; @@ -2648,26 +2844,26 @@ if (sk->timeout == TIME_WRITE && sk->cong_window < 2048 && after(ack, sk->rcv_ack_seq)) { -/* - * This is Jacobson's slow start and congestion avoidance. - * SIGCOMM '88, p. 328. Because we keep cong_window in integral - * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a - * counter and increment it once every cwnd times. It's possible - * that this should be done only if sk->retransmits == 0. I'm - * interpreting "new data is acked" as including data that has - * been retransmitted but is just now being acked. - */ + /* + * This is Jacobson's slow start and congestion avoidance. + * SIGCOMM '88, p. 328. Because we keep cong_window in integral + * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a + * counter and increment it once every cwnd times. It's possible + * that this should be done only if sk->retransmits == 0. I'm + * interpreting "new data is acked" as including data that has + * been retransmitted but is just now being acked. + */ if (sk->cong_window < sk->ssthresh) - /* - * In "safe" area, increase - */ + /* + * In "safe" area, increase + */ sk->cong_window++; else { - /* - * In dangerous area, increase slowly. In theory this is - * sk->cong_window += 1 / sk->cong_window - */ + /* + * In dangerous area, increase slowly. In theory this is + * sk->cong_window += 1 / sk->cong_window + */ if (sk->cong_count >= sk->cong_window) { sk->cong_window++; @@ -2681,9 +2877,9 @@ sk->rcv_ack_seq = ack; /* - * if this ack opens up a zero window, clear backoff. It was - * being used to time the probes, and is probably far higher than - * it needs to be for normal retransmission. + * If this ack opens up a zero window, clear backoff. It was + * being used to time the probes, and is probably far higher than + * it needs to be for normal retransmission. */ if (sk->timeout == TIME_PROBE0) @@ -2693,9 +2889,10 @@ { sk->retransmits = 0; sk->backoff = 0; - /* - * Recompute rto from rtt. this eliminates any backoff. - */ + + /* + * Recompute rto from rtt. this eliminates any backoff. + */ sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; if (sk->rto > 120*HZ) @@ -2703,13 +2900,13 @@ if (sk->rto < 20) /* Was 1*HZ, then 1 - turns out we must allow about .2 of a second because of BSD delayed acks - on a 100Mb/sec link .2 of a second is going to need huge windows (SIGH) */ - sk->rto = 20; + sk->rto = 20; } } - /* - * See if we can take anything off of the retransmit queue. - */ + /* + * See if we can take anything off of the retransmit queue. + */ while(sk->send_head != NULL) { @@ -2899,30 +3096,6 @@ } break; } -#ifdef NOTDEF - if (sk->send_head == NULL && sk->ack_backlog == 0 && - sk->state != TCP_TIME_WAIT && !sk->keepopen) - { - if (!sk->dead) - sk->write_space(sk); - if (sk->keepopen) { - reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - } else { - delete_timer(sk); - } - } - else - { - if (sk->state != (unsigned char) sk->keepopen) - { - reset_timer(sk, TIME_WRITE, sk->rto); - } - if (sk->state == TCP_TIME_WAIT) - { - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - } - } -#endif } if (sk->packets_out == 0 && sk->partial != NULL && @@ -2944,19 +3117,22 @@ { if (!sk->dead) sk->state_change(sk); + if(sk->debug) + printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n", + sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq); if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) { flag |= 1; - tcp_time_wait(sk); + tcp_set_state(sk,TCP_CLOSE); sk->shutdown = SHUTDOWN_MASK; } } /* - * Incoming ACK to a FIN we sent in the case of our initiating the close. + * Incoming ACK to a FIN we sent in the case of our initiating the close. * - * Move to FIN_WAIT2 to await a FIN from the other end. Set - * SEND_SHUTDOWN but not RCV_SHUTDOWN as data can still be coming in. + * Move to FIN_WAIT2 to await a FIN from the other end. Set + * SEND_SHUTDOWN but not RCV_SHUTDOWN as data can still be coming in. */ if (sk->state == TCP_FIN_WAIT1) @@ -2989,7 +3165,26 @@ tcp_time_wait(sk); } } - + + /* + * Final ack of a three way shake + */ + + if(sk->state==TCP_SYN_RECV) + { + tcp_set_state(sk, TCP_ESTABLISHED); + tcp_options(sk,th); + sk->dummy_th.dest=th->source; + sk->copied_seq=sk->acked_seq-1; + if(!sk->dead) + sk->state_change(sk); + if(sk->max_window==0) + { + sk->max_window=32; + sk->mss=min(sk->max_window,sk->mtu); + } + } + /* * I make no guarantees about the first clause in the following * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under @@ -3014,7 +3209,7 @@ * It's possible that there should also be a test for TIME_WRITE, but * I think as long as "send_head != NULL" and "retransmit" is on, we've * got to be in real retransmission mode. - * Note that ip_do_retransmit is called with all==1. Setting cong_window + * Note that tcp_do_retransmit is called with all==1. Setting cong_window * back to 1 at the timeout will cause us to send 1, then 2, etc. packets. * As long as no further losses occur, this seems reasonable. */ @@ -3027,7 +3222,7 @@ tcp_retransmit(sk,0); else { - ip_do_retransmit(sk, 1); + tcp_do_retransmit(sk, 1); reset_timer(sk, TIME_WRITE, sk->rto); } } @@ -3037,26 +3232,119 @@ /* + * Process the FIN bit. This now behaves as it is supposed to work + * and the FIN takes effect when it is validly part of sequence + * space. Not before when we get holes. + * + * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT + * (and thence onto LAST-ACK and finally, CLOSE, we never enter + * TIME-WAIT) + * + * If we are in FINWAIT-1, a received FIN indicates simultaneous + * close and we go into CLOSING (and later onto TIME-WAIT) + * + * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. + * + */ + +static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) +{ + sk->fin_seq = th->seq + skb->len + th->syn + th->fin; + + if (!sk->dead) + { + sk->state_change(sk); + } + + switch(sk->state) + { + case TCP_SYN_RECV: + case TCP_SYN_SENT: + case TCP_ESTABLISHED: + /* + * move to CLOSE_WAIT, tcp_data() already handled + * sending the ack. + */ /* Check me --------------vvvvvvv */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + tcp_set_state(sk,TCP_CLOSE_WAIT); + if (th->rst) + sk->shutdown = SHUTDOWN_MASK; + break; + + case TCP_CLOSE_WAIT: + case TCP_CLOSING: + /* + * received a retransmission of the FIN, do + * nothing. + */ + break; + case TCP_TIME_WAIT: + /* + * received a retransmission of the FIN, + * restart the TIME_WAIT timer. + */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + return(0); + case TCP_FIN_WAIT1: + /* + * This case occurs when a simultaneous close + * happens, we must ack the received FIN and + * enter the CLOSING state. + * + * XXX timeout not set properly + */ + + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + tcp_set_state(sk,TCP_CLOSING); + break; + case TCP_FIN_WAIT2: + /* + * received a FIN -- send ACK and enter TIME_WAIT + */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + sk->shutdown|=SHUTDOWN_MASK; + tcp_set_state(sk,TCP_TIME_WAIT); + break; + case TCP_CLOSE: + /* + * already in CLOSE + */ + break; + default: + tcp_set_state(sk,TCP_LAST_ACK); + + /* Start the timers. */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + return(0); + } + + return(0); +} + + + +/* * This routine handles the data. If there is room in the buffer, * it will be have already been moved into it. If there is no * room, then we will just have to discard the packet. */ -static int tcp_data(struct sk_buff *skb, struct sock *sk, +extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned long saddr, unsigned short len) { struct sk_buff *skb1, *skb2; struct tcphdr *th; int dup_dumped=0; unsigned long new_seq; - struct sk_buff *tail; unsigned long shut_seq; th = skb->h.th; skb->len = len -(th->doff*4); - /* The bytes in the receive read/assembly queue has increased. Needed for the - low memory discard algorithm */ + /* + * The bytes in the receive read/assembly queue has increased. Needed for the + * low memory discard algorithm + */ sk->bytes_rcv += skb->len; @@ -3078,57 +3366,62 @@ if(sk->shutdown & RCV_SHUTDOWN) { - new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ - /* - * This is subtle and not nice. When we shut down we can - * have data in the queue and acked_seq therefore not - * pointing to the last byte that will be read. Thus - * the naive implementation: - * after(new_seq,sk->acked_seq+1) - * will cause bogus resets IFF a resend of a frame that has - * been queued but not yet read after a shutdown has been done. - * What we do now is a bit more complex but works as - * follows. If the queue is empty copied_seq+1 is right (+1 for FIN) - * if the queue has data the shutdown occurs at the right edge of - * the last packet queued +1 - * - * We can't simply ack data beyond this point as it has - * and will never be received by an application. + * FIXME: BSD has some magic to avoid sending resets to + * broken 4.2 BSD keepalives. Much to my suprise a few none + * BSD stacks still have broken keepalives so we want to + * cope with it. */ - tail=skb_peek(&sk->receive_queue); - if(tail!=NULL) - { - tail=sk->receive_queue.prev; - shut_seq=tail->h.th->seq+tail->len+1; - } - else - shut_seq=sk->copied_seq+1; - - if(after(new_seq,shut_seq)) + + if(skb->len) /* We don't care if its just an ack or + a keepalive/window probe */ { - sk->acked_seq = new_seq + th->fin; - if(sk->debug) - printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n", - sk, new_seq, shut_seq, sk->blog); - tcp_reset(sk->saddr, sk->daddr, skb->h.th, - sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); - tcp_statistics.TcpEstabResets++; - tcp_set_state(sk,TCP_CLOSE); - sk->err = EPIPE; - sk->shutdown = SHUTDOWN_MASK; - kfree_skb(skb, FREE_READ); - if (!sk->dead) - sk->state_change(sk); - return(0); + new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ + + /* Do this the way 4.4BSD treats it. Not what I'd + regard as the meaning of the spec but its what BSD + does and clearly they know everything 8) */ + + /* + * This is valid because of two things + * + * a) The way tcp_data behaves at the bottom. + * b) A fin takes effect when read not when received. + */ + + shut_seq=sk->acked_seq+1; /* Last byte */ + + if(after(new_seq,shut_seq)) + { + if(sk->debug) + printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n", + sk, new_seq, shut_seq, sk->blog); + if(sk->dead) + { + sk->acked_seq = new_seq + th->fin; + tcp_reset(sk->saddr, sk->daddr, skb->h.th, + sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); + tcp_statistics.TcpEstabResets++; + tcp_set_state(sk,TCP_CLOSE); + sk->err = EPIPE; + sk->shutdown = SHUTDOWN_MASK; + kfree_skb(skb, FREE_READ); + return 0; + } + } } } + /* * Now we have to walk the chain, and figure out where this one * goes into it. This is set up so that the last packet we received * will be the first one we look at, that way if everything comes * in order, there will be no performance loss, and if they come * out of order we will be able to fit things in nicely. + * + * [AC: This is wrong. We should assume in order first and then walk + * forwards from the first hole based upon real traffic patterns.] + * */ /* @@ -3209,7 +3502,9 @@ } /* - * Now figure out if we can ack anything. + * Now figure out if we can ack anything. This is very messy because we really want two + * receive queues, a completed and an assembly queue. We also want only one transmit + * queue. */ if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) @@ -3228,8 +3523,9 @@ } skb->acked = 1; - /* - * When we ack the fin, we turn on the RCV_SHUTDOWN flag. + /* + * When we ack the fin, we turn on the RCV_SHUTDOWN flag. Also do the FIN + * processing. */ if (skb->h.th->fin) @@ -3237,6 +3533,7 @@ if (!sk->dead) sk->state_change(sk); sk->shutdown |= RCV_SHUTDOWN; + tcp_fin(skb,sk,skb->h.th); } for(skb2 = skb->next; @@ -3264,6 +3561,7 @@ sk->shutdown |= RCV_SHUTDOWN; if (!sk->dead) sk->state_change(sk); + tcp_fin(skb,sk,skb->h.th); } /* @@ -3356,6 +3654,14 @@ } +/* + * This routine is only called when we have urgent data + * signalled. Its the 'slow' part of tcp_urg. It could be + * moved inline now as tcp_urg is only called from one + * place. We handle URGent data wrong. We have to - as + * BSD still doesn't use the correction from RFC961. + */ + static void tcp_check_urg(struct sock * sk, struct tcphdr * th) { unsigned long ptr = ntohs(th->urg_ptr); @@ -3384,125 +3690,52 @@ sk->urg_seq = ptr; } -static inline int tcp_urg(struct sock *sk, struct tcphdr *th, +/* + * This is the 'fast' part of urgent handling. + */ + +extern __inline__ int tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr, unsigned long len) { unsigned long ptr; - /* check if we get a new urgent pointer */ + /* + * Check if we get a new urgent pointer - normally not + */ + if (th->urg) tcp_check_urg(sk,th); - /* do we wait for any urgent data? */ + /* + * Do we wait for any urgent data? - normally not + */ + if (sk->urg_data != URG_NOTYET) return 0; - /* is the urgent pointer pointing into this packet? */ - ptr = sk->urg_seq - th->seq + th->doff*4; - if (ptr >= len) + /* + * Is the urgent pointer pointing into this packet? + */ + + ptr = sk->urg_seq - th->seq + th->doff*4; + if (ptr >= len) return 0; - /* ok, got the correct packet, update info */ + /* + * Ok, got the correct packet, update info + */ + sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th); if (!sk->dead) sk->data_ready(sk,0); return 0; } - /* - * This deals with incoming fins. 'Linus at 9 O'clock' 8-) - * - * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT - * (and thence onto LAST-ACK and finally, CLOSE, we never enter - * TIME-WAIT) - * - * If we are in FINWAIT-1, a received FIN indicates simultaneous - * close and we go into CLOSING (and later onto TIME-WAIT) - * - * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. - * + * This will accept the next outstanding connection. */ -static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th, - unsigned long saddr, struct device *dev) -{ - sk->fin_seq = th->seq + skb->len + th->syn + th->fin; - - if (!sk->dead) - { - sk->state_change(sk); - } - - switch(sk->state) - { - case TCP_SYN_RECV: - case TCP_SYN_SENT: - case TCP_ESTABLISHED: - /* - * move to CLOSE_WAIT, tcp_data() already handled - * sending the ack. - */ - reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN); - tcp_set_state(sk,TCP_CLOSE_WAIT); - if (th->rst) - sk->shutdown = SHUTDOWN_MASK; - break; - - case TCP_CLOSE_WAIT: - case TCP_CLOSING: - /* - * received a retransmission of the FIN, do - * nothing. - */ - break; - case TCP_TIME_WAIT: - /* - * received a retransmission of the FIN, - * restart the TIME_WAIT timer. - */ - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return(0); - case TCP_FIN_WAIT1: - /* - * This case occurs when a simultaneous close - * happens, we must ack the received FIN and - * enter the CLOSING state. - * - * XXX timeout not set properly - */ - - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - tcp_set_state(sk,TCP_CLOSING); - break; - case TCP_FIN_WAIT2: - /* - * received a FIN -- send ACK and enter TIME_WAIT - */ - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - sk->shutdown|=SHUTDOWN_MASK; - tcp_set_state(sk,TCP_TIME_WAIT); - break; - case TCP_CLOSE: - /* - * already in CLOSE - */ - break; - default: - tcp_set_state(sk,TCP_LAST_ACK); - - /* Start the timers. */ - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return(0); - } -/* sk->ack_backlog++; tcp_data has already dealt with ACK's */ - - return(0); -} - - -/* This will accept the next outstanding connection. */ -static struct sock * -tcp_accept(struct sock *sk, int flags) + +static struct sock *tcp_accept(struct sock *sk, int flags) { struct sock *newsk; struct sk_buff *skb; @@ -3572,8 +3805,10 @@ struct rtable *rt; if (sk->state != TCP_CLOSE) + { return(-EISCONN); - + } + if (addr_len < 8) return(-EINVAL); @@ -3715,8 +3950,7 @@ /* This functions checks to see if the tcp header is actually acceptable. */ -static int -tcp_sequence(struct sock *sk, struct tcphdr *th, short len, +extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len, struct options *opt, unsigned long saddr, struct device *dev) { unsigned long next_seq; @@ -3757,7 +3991,8 @@ * connect again and it will work (with luck). */ - if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) { + if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) + { tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl); return 1; } @@ -3767,39 +4002,57 @@ return 0; } - -#ifdef TCP_FASTPATH /* - * Is the end of the queue clear of fragments as yet unmerged into the data stream - * Yes if - * a) The queue is empty - * b) The last frame on the queue has the acked flag set + * When we get a reset we do this. */ -static inline int tcp_clean_end(struct sock *sk) +static int tcp_std_reset(struct sock *sk, struct sk_buff *skb) { - struct sk_buff *skb=skb_peek(&sk->receive_queue); - if(skb==NULL || sk->receive_queue.prev->acked) - return 1; + sk->zapped=1; + sk->err = ECONNRESET; + if(sk->state==TCP_CLOSE_WAIT) + sk->err = EPIPE; +#ifdef TCP_DO_RFC1337 + /* + * Time wait assassination protection [RFC1337] + */ + if(sk->state!=TCP_TIME_WAIT) + { + tcp_set_state(sk,TCP_CLOSE); + sk->shutdown = SHUTDOWN_MASK; + } +#else + tcp_set_state(sk,TCP_CLOSE); + sk->shutdown = SHUTDOWN_MASK; +#endif + if (!sk->dead) + sk->state_change(sk); + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); } -#endif - -int -tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, +/* + * A TCP packet has arrived. + */ + +int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct inet_protocol * protocol) { struct tcphdr *th; struct sock *sk; - + int syn_ok=0; + if (!skb) { + printk("IMPOSSIBLE 1\n"); return(0); } if (!dev) { + printk("IMPOSSIBLE 2\n"); return(0); } @@ -3821,10 +4074,14 @@ /* * If this socket has got a reset its to all intents and purposes - * really dead + * really dead. Count closed sockets as dead. + * + * Note: BSD appears to have a bug here. A 'closed' TCP in BSD + * simply drops data. This seems incorrect as a 'closed' TCP doesn't + * exist so should cause resets as if the port was unreachable. */ - if (sk!=NULL && sk->zapped) + if (sk!=NULL && (sk->zapped || sk->state==TCP_CLOSE)) sk=NULL; if (!redo) @@ -3844,9 +4101,14 @@ /* See if we know about the socket. */ if (sk == NULL) { - if (!th->rst) - tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); + /* + * No such TCB. If th->rst is 0 send a reset (checked in tcp_reset) + */ + tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); skb->sk = NULL; + /* + * Discard frame + */ kfree_skb(skb, FREE_READ); return(0); } @@ -3871,8 +4133,11 @@ } else { - if (!sk) + if (sk==NULL) { + tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); + skb->sk = NULL; + kfree_skb(skb, FREE_READ); return(0); } } @@ -3880,6 +4145,7 @@ if (!sk->prot) { + printk("IMPOSSIBLE 3\n"); return(0); } @@ -3898,322 +4164,114 @@ skb->sk=sk; sk->rmem_alloc += skb->mem_len; -#ifdef TCP_FASTPATH -/* - * Incoming data stream fastpath. - * - * We try to optimise two things. - * 1) Spot general data arriving without funny options and skip extra checks and the switch. - * 2) Spot the common case in raw data receive streams of a packet that has no funny options, - * fits exactly on the end of the current queue and may or may not have the ack bit set. - * - * Case two especially is done inline in this routine so there are no long jumps causing heavy - * cache thrashing, no function call overhead (except for the ack sending if needed) and for - * speed although further optimizing here is possible. - */ - - /* I'm trusting gcc to optimise this sensibly... might need judicious application of a software mallet */ - if(!(sk->shutdown & RCV_SHUTDOWN) && sk->state==TCP_ESTABLISHED && !th->urg && !th->syn && !th->fin && !th->rst) - { - /* Packets in order. Fits window */ - if(th->seq == sk->acked_seq+1 && sk->window && tcp_clean_end(sk)) + /* + * This basically follows the flow suggested by RFC793, with the corrections in RFC1122. We + * don't implement precedence and we process URG incorrectly (deliberately so) for BSD bug + * compatibility. We also set up variables more throughroughly [Karn notes in the + * KA9Q code the RFC793 incoming segment rules don't initialise the variables for all paths]. + */ + + if(sk->state!=TCP_ESTABLISHED) /* Skip this lot for normal flow */ + { + + /* + * Now deal with unusual cases. + */ + + if(sk->state==TCP_LISTEN) { - /* Ack is harder */ - if(th->ack && !tcp_ack(sk, th, saddr, len)) + if(th->ack) /* These use the socket TOS.. might want to be the received TOS */ + tcp_reset(daddr,saddr,th,sk->prot,opt,dev,sk->ip_tos, sk->ip_ttl); + + /* + * We don't care for RST, and non SYN are absorbed (old segments) + * Broadcast/multicast SYN isn't allowed. Note - bug if you change the + * netmask on a running connection it can go broadcast. Even Sun's have + * this problem so I'm ignoring it + */ + + if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR) { kfree_skb(skb, FREE_READ); release_sock(sk); return 0; } + + /* + * Guess we need to make a new socket up + */ + + tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq()); + /* - * Set up variables + * Now we have several options: In theory there is nothing else + * in the frame. KA9Q has an option to send data with the syn, + * BSD accepts data with the syn up to the [to be] advertised window + * and Solaris 2.1 gives you a protocol error. For now we just ignore + * it, that fits the spec precisely and avoids incompatibilities. It + * would be nice in future to drop through and process the data. */ - skb->len -= (th->doff *4); - sk->bytes_rcv += skb->len; - tcp_rx_hit2++; - if(skb->len) - { - skb_queue_tail(&sk->receive_queue,skb); /* We already know where to put it */ - if(sk->window >= skb->len) - sk->window-=skb->len; /* We know its effect on the window */ - else - sk->window=0; - sk->acked_seq = th->seq+skb->len; /* Easy */ - skb->acked=1; /* Guaranteed true */ - if(!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog || - sk->bytes_rcv > sk->max_unacked) - { - tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th , saddr); - } - else - { - sk->ack_backlog++; - reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); - } - if(!sk->dead) - sk->data_ready(sk,0); - release_sock(sk); - return 0; - } - } - /* - * More generic case of arriving data stream in ESTABLISHED - */ - tcp_rx_hit1++; - if(!tcp_sequence(sk, th, len, opt, saddr, dev)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - if(th->ack && !tcp_ack(sk, th, saddr, len)) - { - kfree_skb(skb, FREE_READ); + release_sock(sk); return 0; } - if(tcp_data(skb, sk, saddr, len)) - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - tcp_rx_miss++; -#endif - - /* - * Now deal with all cases. - */ - - switch(sk->state) - { /* - * This should close the system down if it's waiting - * for an ack that is never going to be sent. + * SYN sent means we have to look for a suitable ack and either reset + * for bad matches or go to connected */ - case TCP_LAST_ACK: - if (th->rst) - { - sk->zapped=1; - sk->err = ECONNRESET; - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - { - sk->state_change(sk); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - case TCP_ESTABLISHED: - case TCP_CLOSE_WAIT: - case TCP_CLOSING: - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - case TCP_TIME_WAIT: - - /* - * is it a good packet? - */ - - if (!tcp_sequence(sk, th, len, opt, saddr,dev)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - if (th->rst) + + else if(sk->state==TCP_SYN_SENT) + { + /* Crossed SYN or previous junk segment */ + if(th->ack) { - tcp_statistics.TcpEstabResets++; - sk->zapped=1; - /* This means the thing should really be closed. */ - sk->err = ECONNRESET; - if (sk->state == TCP_CLOSE_WAIT) + /* We got an ack, but its not a good ack */ + if(!tcp_ack(sk,th,saddr,len)) { - sk->err = EPIPE; - } - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - { - sk->state_change(sk); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - if (th->syn) - { - long seq=sk->write_seq; - int st=sk->state; - tcp_statistics.TcpEstabResets++; - sk->err = ECONNRESET; - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if(sk->debug) - printk("Socket %p reset by SYN while established.\n", sk); - if (!sk->dead) { - sk->state_change(sk); - } - /* - * The BSD port reuse protocol violation. - * I do sometimes wonder how the *bsd people - * have the nerve to talk about 'standards'. - * - * If seq > last used on connection then - * open a new connection and use 128000+seq of - * old connection. - * - */ - - if(st==TCP_TIME_WAIT && th->seq > sk->acked_seq && sk->dead) - { - struct sock *psk=sk; - /* - * Find the listening socket. - */ - sk=get_sock(&tcp_prot, th->source, daddr, th->dest, saddr); - if(sk && sk->state==TCP_LISTEN) - { - sk->inuse=1; - tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000); - release_sock(psk); - /* Fall through in case people are - also using the piggy backed SYN + data - protocol violation */ - } - else - { - tcp_reset(daddr, saddr, th, psk->prot, opt,dev, psk->ip_tos,psk->ip_ttl); - release_sock(psk); - kfree_skb(skb, FREE_READ); - return 0; - } - } - else - { - tcp_reset(daddr, saddr, th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl); + /* Reset the ack - its an ack from a + different connection [ th->rst is checked in tcp_reset()] */ + tcp_statistics.TcpAttemptFails++; + tcp_reset(daddr, saddr, th, + sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } - } - if (th->ack && !tcp_ack(sk, th, saddr, len)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - if (tcp_urg(sk, th, saddr, len)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - - if (tcp_data(skb, sk, saddr, len)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - release_sock(sk); - return(0); - - - case TCP_CLOSE: - if (sk->dead || sk->daddr) { - kfree_skb(skb, FREE_READ); + if(th->rst) + return tcp_std_reset(sk,skb); + if(!th->syn) + { + /* A valid ack from a different connection + start. Shouldn't happen but cover it */ + kfree_skb(skb, FREE_READ); release_sock(sk); - return(0); - } - - if (!th->rst) { - if (!th->ack) - th->ack_seq = 0; - if(sk->debug) printk("Reset on closed socket %d.\n",sk->blog); - tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - - case TCP_LISTEN: - if (th->rst) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - if (th->ack) { - if(sk->debug) printk("Reset on listening socket %d.\n",sk->blog); - tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - if (th->syn) - { + return 0; + } /* - * Now we just put the whole thing including - * the header and saddr, and protocol pointer - * into the buffer. We can't respond until the - * user tells us to accept the connection. + * Ok.. its good. Set up sequence numbers and + * move to established. */ - tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq()); - release_sock(sk); - return(0); - } - - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - - case TCP_SYN_RECV: - if (th->syn) { - /* Probably a retransmitted syn */ - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - - default: - if (!tcp_sequence(sk, th, len, opt, saddr,dev)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - case TCP_SYN_SENT: - if (th->rst) - { - tcp_statistics.TcpAttemptFails++; - sk->err = ECONNREFUSED; - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - sk->zapped = 1; - if (!sk->dead) - { + syn_ok=1; /* Don't reset this connection for the syn */ + sk->acked_seq=th->seq+1; + sk->fin_seq=th->seq; + tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr); + tcp_set_state(sk, TCP_ESTABLISHED); + tcp_options(sk,th); + sk->dummy_th.dest=th->source; + sk->copied_seq=sk->acked_seq-1; + if(!sk->dead) sk->state_change(sk); + if(sk->max_window==0) + { + sk->max_window = 32; + sk->mss = min(sk->max_window, sk->mtu); } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); } - if (!th->ack) + else { - if (th->syn) + /* See if SYN's cross. Drop if boring */ + if(th->syn && !th->rst) { /* Crossed SYN's are fine - but talking to yourself is right out... */ @@ -4222,150 +4280,138 @@ sk->dummy_th.dest==th->dest) { tcp_statistics.TcpAttemptFails++; - sk->err = ECONNREFUSED; - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - sk->zapped = 1; - if (!sk->dead) - { - sk->state_change(sk); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); + return tcp_std_reset(sk,skb); } tcp_set_state(sk,TCP_SYN_RECV); - } + + /* + * FIXME: + * Must send SYN|ACK here + */ + } + /* Discard junk segment */ kfree_skb(skb, FREE_READ); release_sock(sk); - return(0); + return 0; } - - switch(sk->state) - { - case TCP_SYN_SENT: - if (!tcp_ack(sk, th, saddr, len)) - { - tcp_statistics.TcpAttemptFails++; - tcp_reset(daddr, saddr, th, - sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - /* - * If the syn bit is also set, switch to - * tcp_syn_recv, and then to established. - */ - if (!th->syn) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - /* Ack the syn and fall through. */ - sk->acked_seq = th->seq+1; - sk->fin_seq = th->seq; - tcp_send_ack(sk->sent_seq, th->seq+1, - sk, th, sk->daddr); + /* + * SYN_RECV with data maybe.. drop through + */ + goto rfc_step6; + } - case TCP_SYN_RECV: - if (!tcp_ack(sk, th, saddr, len)) - { - tcp_statistics.TcpAttemptFails++; - tcp_reset(daddr, saddr, th, - sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl); - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - tcp_set_state(sk,TCP_ESTABLISHED); + } + + /* BSD has a funny hack with TIME_WAIT and fast reuse of a port. We + don't use it, we don't need it and its not in the spec. There is + a more complex suggestion for fixing these reuse issues in RFC1644 + but not yet ready for general use. Also see RFC1379.*/ + + /* We are now in normal data flow (see the step list in the RFC) */ + /* Note most of these are inline now. I'll inline the lot when + I have time to test it hard and look at what gcc outputs */ + +#define BSD_TIME_WAIT +#ifdef BSD_TIME_WAIT + if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead && + after(th->seq, sk->acked_seq) && !th->rst) + { + long seq=sk->write_seq; + if(sk->debug) + printk("Doing a BSD time wait\n"); + tcp_statistics.TcpEstabResets++; + sk->err=ECONNRESET; + tcp_set_state(sk, TCP_CLOSE); + sk->shutdown = SHUTDOWN_MASK; + release_sock(sk); + sk=get_sock(&tcp_prot, th->source, daddr, th->dest, saddr); + if(sk && sk->state==TCP_LISTEN) + { + sk->inuse=1; + tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000); + release_sock(sk); + return 0; + } + kfree_skb(skb, FREE_READ); + return 0; + } +#endif - /* - * Now we need to finish filling out - * some of the tcp header. - * - * We need to check for mtu info. - */ - tcp_options(sk, th); - sk->dummy_th.dest = th->source; - sk->copied_seq = sk->acked_seq-1; - if (!sk->dead) - { - sk->state_change(sk); - } + if(/*sk->state!=TCP_SYN_RECV &&*/ !tcp_sequence(sk,th,len,opt,saddr,dev)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + + if(th->rst) + return tcp_std_reset(sk,skb); - /* - * We've already processed his first - * ack. In just about all cases that - * will have set max_window. This is - * to protect us against the possibility - * that the initial window he sent was 0. - * This must occur after tcp_options, which - * sets sk->mtu. - */ - if (sk->max_window == 0) - { - sk->max_window = 32; - sk->mss = min(sk->max_window, sk->mtu); - } + /* + * !syn_ok is effectively the state test in RFC793. + */ + + if(th->syn && !syn_ok) + { + tcp_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255); + return tcp_std_reset(sk,skb); + } - /* - * Now process the rest like we were - * already in the established state. - */ - if (th->urg) - { - if (tcp_urg(sk, th, saddr, len)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - } - if (tcp_data(skb, sk, saddr, len)) - kfree_skb(skb, FREE_READ); + /* + * Process the ACK + */ + - if (th->fin) - tcp_fin(skb, sk, th, saddr, dev); - release_sock(sk); - return(0); - } + if(th->ack && !tcp_ack(sk,th,saddr,len)) + { + /* + * Our three way handshake failed. + */ + + if(sk->state==TCP_SYN_RECV) + { + tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return 0; + } - if (th->urg) - { - if (tcp_urg(sk, th, saddr, len)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - } - if (tcp_data(skb, sk, saddr, len)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } +rfc_step6: /* I'll clean this up later */ + + /* + * Process urgent data + */ + + if(tcp_urg(sk, th, saddr, len)) + { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return 0; + } - if (!th->fin) - { - release_sock(sk); - return(0); - } - tcp_fin(skb, sk, th, saddr, dev); - release_sock(sk); - return(0); + + /* + * Process the encapsulated data + */ + + if(tcp_data(skb,sk, saddr, len)) + { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return 0; } -} + /* + * And done + */ + + release_sock(sk); + return 0; +} /* - * This routine sends a packet with an out of date sequence - * number. It assumes the other end will try to ack it. + * This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. */ static void tcp_write_wakeup(struct sock *sk) @@ -4379,8 +4425,8 @@ return; /* After a valid reset we can send no more */ /* - * Write data can still be transmitted/retransmitted in the - * following states. If any other state is encountered, return. + * Write data can still be transmitted/retransmitted in the + * following states. If any other state is encountered, return. */ if (sk->state != TCP_ESTABLISHED && @@ -4388,7 +4434,8 @@ sk->state != TCP_FIN_WAIT1 && sk->state != TCP_LAST_ACK && sk->state != TCP_CLOSING - ) { + ) + { return; } @@ -4428,7 +4475,7 @@ t1->rst = 0; t1->urg = 0; t1->psh = 0; - t1->fin = 0; + t1->fin = 0; /* We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */ t1->syn = 0; t1->ack_seq = ntohl(sk->acked_seq); t1->window = ntohs(tcp_select_window(sk)); @@ -4442,8 +4489,11 @@ tcp_statistics.TcpOutSegs++; } -void -tcp_send_probe0(struct sock *sk) +/* + * A window probe timeout has occured. + */ + +void tcp_send_probe0(struct sock *sk) { if (sk->zapped) return; /* After a valid reset we can send no more */ diff -u --recursive --new-file v1.1.72/linux/net/inet/udp.c linux/net/inet/udp.c --- v1.1.72/linux/net/inet/udp.c Sat Dec 3 13:05:43 1994 +++ linux/net/inet/udp.c Mon Dec 12 22:45:44 1994 @@ -70,6 +70,7 @@ #include "sock.h" #include "udp.h" #include "icmp.h" +#include "route.h" /* * SNMP MIB for the UDP layer @@ -523,6 +524,8 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) { + struct rtable *rt; + unsigned long sa; if (addr_len < sizeof(*usin)) return(-EINVAL); @@ -534,6 +537,10 @@ if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ + rt=ip_rt_route(usin->sin_addr.s_addr, NULL, &sa); + if(rt==NULL) + return -ENETUNREACH; + sk->saddr = sa; /* Update source address */ sk->daddr = usin->sin_addr.s_addr; sk->dummy_th.dest = usin->sin_port; sk->state = TCP_ESTABLISHED; @@ -703,7 +710,7 @@ udp_connect, NULL, ip_queue_xmit, - ip_retransmit, + NULL, NULL, NULL, udp_rcv, diff -u --recursive --new-file v1.1.72/linux/net/socket.c linux/net/socket.c --- v1.1.72/linux/net/socket.c Fri Nov 18 15:22:10 1994 +++ linux/net/socket.c Mon Dec 12 21:35:37 1994 @@ -266,8 +266,8 @@ return(NULL); } SOCK_INODE(sock)->i_mode = S_IFSOCK; - SOCK_INODE(sock)->i_uid = current->euid; - SOCK_INODE(sock)->i_gid = current->egid; + SOCK_INODE(sock)->i_uid = current->uid; + SOCK_INODE(sock)->i_gid = current->gid; SOCK_INODE(sock)->i_socket = sock; sock->wait = &SOCK_INODE(sock)->i_wait;