From 13e539119b02e4af5daf6c55b31e6273c9a084a6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:11 -0500 Subject: [PATCH] Import 1.3.21 --- CREDITS | 14 +- Makefile | 2 +- Rules.make | 5 +- arch/i386/config.in | 5 +- arch/i386/kernel/entry.S | 3 +- arch/i386/kernel/setup.c | 24 ++- drivers/block/Makefile | 4 + drivers/block/README.ide | 43 ++-- drivers/block/README.optcd | 20 +- drivers/block/blk.h | 2 +- drivers/block/ide-cd.c | 2 - drivers/block/ide.c | 381 ++++++++++++++++++++++++++--------- drivers/block/ide.h | 78 +++++-- drivers/block/optcd.c | 276 ++++++++++++++++++++++++- drivers/block/triton.c | 352 ++++++++++++++++++++++++++++++++ drivers/char/lp.c | 45 +++-- drivers/char/serial.c | 1 - drivers/net/Makefile | 3 +- drivers/net/net_init.c | 12 +- drivers/net/ppp.c | 2 +- drivers/pci/pci.c | 4 +- drivers/scsi/Makefile | 2 +- drivers/scsi/scsi.c | 359 +++++++++++++++++---------------- drivers/scsi/sd_ioctl.c | 2 +- drivers/sound/ad1848.c | 2 +- drivers/sound/sound_switch.c | 2 +- fs/binfmt_elf.c | 27 ++- fs/buffer.c | 4 +- fs/msdos/namei.c | 5 +- fs/nfs/inode.c | 1 + fs/proc/net.c | 43 ---- fs/proc/root.c | 69 ++++++- fs/proc/scsi.c | 43 +--- fs/smbfs/README | 4 +- fs/smbfs/dir.c | 83 ++++---- fs/smbfs/file.c | 47 ++++- fs/smbfs/inode.c | 15 +- fs/smbfs/proc.c | 119 +++++++++-- fs/smbfs/sock.c | 274 +++++++++++++++++++------ include/asm-i386/string.h | 19 ++ include/asm-i386/unistd.h | 1 + include/linux/hdreg.h | 23 ++- include/linux/if_arp.h | 3 +- include/linux/if_ether.h | 1 + include/linux/in.h | 19 ++ include/linux/mm.h | 4 +- include/linux/skbuff.h | 1 + include/linux/smb_fs.h | 9 + include/linux/socket.h | 2 + include/net/netrom.h | 2 +- kernel/Makefile | 2 + mm/filemap.c | 241 +++++++++++++++++----- mm/swap.c | 15 +- net/Changes | 35 ++-- net/appletalk/ddp.c | 57 +++++- net/ax25/af_ax25.c | 62 ++++-- net/core/Makefile | 4 +- net/core/datagram.c | 15 ++ net/core/iovec.c | 7 +- net/ipv4/af_inet.c | 2 +- net/ipv4/arp.c | 2 +- net/ipv4/icmp.c | 2 +- net/ipv4/ip.c | 38 +++- net/ipv4/ip_fw.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv4/udp.c | 2 +- net/netrom/af_netrom.c | 6 +- net/netrom/nr_dev.c | 1 + net/unix/af_unix.c | 18 +- scripts/depend.awk | 5 +- versions.mk | 2 +- 71 files changed, 2259 insertions(+), 724 deletions(-) create mode 100644 drivers/block/triton.c diff --git a/CREDITS b/CREDITS index decee3859b9a..69bf9accae28 100644 --- a/CREDITS +++ b/CREDITS @@ -962,12 +962,14 @@ D: The Linux Support Team Erlangen N: Matt Welsh E: mdw@sunsite.unc.edu D: Linux Documentation Project coordinator -D: Author, Linux Installation and Getting Started -D: HOWTO coordinator and writer -D: Maintainer of sunsite.unc.edu Linux doc archives -D: Moderator, comp.os.linux.announce -S: 205 Gray Street NE -S: Wilson, North Carolina 27893 +D: Author, _Running_Linux_ and I&GS guide +D: Linuxdoc-SGML formatting system +D: Keithley DAS1200 device driver +D: Maintainer of sunsite WWW and FTP, moderator c.o.l.answers +S: Cornell University Computer Science Department +S: Robotics and Vision Laboratory +S: 4130 Upson Hall +S: Ithaca NY 14850 S: USA N: Marco van Wieringen diff --git a/Makefile b/Makefile index 0cc3d59cf60d..421cc33d3a7b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 20 +SUBLEVEL = 21 ARCH = i386 diff --git a/Rules.make b/Rules.make index d7686e5ad3fb..95dbbded2fc6 100644 --- a/Rules.make +++ b/Rules.make @@ -45,7 +45,8 @@ first_rule: sub_dirs $(O_TARGET) $(L_TARGET) # Rule to compile a set of .o files into one .o file # ifdef O_TARGET -$(O_TARGET): $(O_OBJS) +$(O_TARGET): $(O_OBJS) $(TOPDIR)/include/linux/config.h + rm -f $@ ifdef O_OBJS $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS) else @@ -57,7 +58,7 @@ endif # Rule to compile a set of .o files into one .a file # ifdef L_TARGET -$(L_TARGET): $(L_OBJS) +$(L_TARGET): $(L_OBJS) $(TOPDIR)/include/linux/config.h rm -f $@ $(AR) $(EXTRA_ARFLAGS) rcs $@ $(L_OBJS) endif diff --git a/arch/i386/config.in b/arch/i386/config.in index ca82d156d67a..9bae0d8e61b6 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -26,7 +26,10 @@ bool 'Networking support' CONFIG_NET y bool 'Limit memory to low 16MB' CONFIG_MAX_16M n bool 'PCI bios support' CONFIG_PCI y if [ "$CONFIG_PCI" = "y" ]; then - bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y + bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y + if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then + bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y + fi fi bool 'System V IPC' CONFIG_SYSVIPC y bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index bd64d74ba9b9..f09a507d288c 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -517,4 +517,5 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_getdents) .long SYMBOL_NAME(sys_select) .long SYMBOL_NAME(sys_flock) - .space (NR_syscalls-143)*4 + .long SYMBOL_NAME(sys_msync) + .space (NR_syscalls-144)*4 diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 45097c79ee00..f7cb717f70ac 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -103,14 +103,24 @@ void setup_arch(char **cmdline_p, init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; for (;;) { + /* + * "mem=nopentium" disables the 4MB page tables. + * "mem=XXX[kKmM]" overrides the BIOS-reported + * memory size + */ if (c == ' ' && *(const unsigned long *)from == *(const 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++; + if (!memcmp(from+4, "nopentium", 9)) { + from += 9+4; + x86_capability &= ~8; + } else { + 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++); diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 6fbd176283bf..d5984bddf6c1 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -106,6 +106,10 @@ ifdef CONFIG_BLK_DEV_IDE L_OBJS += ide.o endif +ifdef CONFIG_BLK_DEV_TRITON +L_OBJS += triton.o +endif + ifdef CONFIG_BLK_DEV_IDECD L_OBJS += ide-cd.o endif diff --git a/drivers/block/README.ide b/drivers/block/README.ide index ad92b88cf8b7..efbb1e4fe207 100644 --- a/drivers/block/README.ide +++ b/drivers/block/README.ide @@ -3,7 +3,12 @@ README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.x) Supported by: mlord@bnr.ca -- disks, interfaces, probing snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio -(see description later on below for handling BIG IDE drives with >1024 cyls). + +-----------------------------------------------------------------+ + | The hdparm utility for controlling various IDE features is | + | packaged separately. Look for it on popular linux FTP sites. | + +-----------------------------------------------------------------+ + +See description later on below for handling BIG IDE drives with >1024 cyls. Major features of ide.c & ide-cd.c: @@ -35,16 +40,29 @@ NEW! - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay" NEW! - should work for for EZ-Drive disks as well (not verified) - works with Linux fdisk, LILO, loadlin, bootln, etc.. NEW! - ide-cd.c now compiles separate from ide.c +NEW! - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces + - for details, see comments at top of triton.c -For a list of work underway, see the comments near the top of ide.c and ide-cd.c +For work in progress, see the comments in ide.c, ide-cd.c, and triton.c. *** - -IMPORTANT NOTICE: "CMD" EIDE Interfaces will not (by default) work *reliably* -when drives are attached to the second interface. To "fix" this, supply the -special kernel "command line" parameter to LILO: ide1=serialize -Failure to do so can cause severe data corruption! - +*** IMPORTANT NOTICES: +*** ================== +*** +*** "CMD" EIDE Interfaces will not (by default) work *reliably* when drives +*** are attached to the second interface. This is due to a flaw in the +*** hardware. To "fix" this, supply the special kernel "command line" +*** parameter to LILO or LOADLIN: ide1=serialize +*** +*** "CMD 640B" EIDE Interfaces will not work *reliably* when "hdparm -u1" +*** (interrupt unmasking) is used. This is due to a flaw in the hardware, +*** and is only a problem when "hdparm -u1" is used after booting. +*** +*** "RZ1000" EIDE Interfaces will also not work *reliably* when "hdparm -u1" +*** (interrupt unmasking) is used. This is due to a flaw in the hardware, +*** and is only a problem when "hdparm -u1" is used after booting. +*** +*** Failure to abide by these restrictions can cause severe data corruption! *** To access devices on the 2nd/3rd/4th interfaces, device entries must first be @@ -76,7 +94,7 @@ seldom occurs. Be careful, and if in doubt, don't do it! Drives are normally found by auto-probing and/or examining the CMOS/BIOS data. For really weird situations, the apparent (fdisk) geometry can also be specified -on the kernel "command line" using LILO. The format of such lines is: +on the kernel "command line" using LILO. The format of such lines is: hdx=cyls,heads,sects,wpcom,irq or hdx=cdrom @@ -139,9 +157,6 @@ and still allows newer hardware to run on the 2nd/3rd/4th IDE ports under control of ide.c. To have ide.c also "take over" the primary IDE port in this situation, use the "command line" parameter: ide0=0x1f0 -The hdparm.c program for controlling various IDE features is now packaged -separately. Look for it on popular linux FTP sites. - mlord@bnr.ca snyder@fnald0.fnal.gov ================================================================================ @@ -151,7 +166,7 @@ Summary of ide driver parameters for kernel "command line": "hdx=" is recognized for all "x" from "a" to "h", such as "hdc". "idex=" is recognized for all "x" from "0" to "3", such as "ide1". - + "hdx=noprobe" : drive may be present, but do not probe for it "hdx=nowerr" : ignore the WRERR_STAT bit on this drive "hdx=cdrom" : drive is present, and is a cdrom drive @@ -300,7 +315,7 @@ by doing the following after installing slackware (or whatever): 0. Boot from the "boot floppy" created during the installation 1. Mount your DOS partition as /dos (and stick it in /etc/fstab) 2. Move your kernel (/vmlinuz) to /dos/vmlinuz with: mv /vmlinuz /dos - 3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz + 3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz 4. Move /boot to /dos/boot with: cp -a /boot /dos ; rm -r /boot 5. Create a symlink for LILO to use with: ln -s /dos/boot /boot 6. Re-run LILO with: lilo diff --git a/drivers/block/README.optcd b/drivers/block/README.optcd index 63c8d29b09b9..514c9d9ccb12 100644 --- a/drivers/block/README.optcd +++ b/drivers/block/README.optcd @@ -1,9 +1,14 @@ This is the README file for the Optics Storage 8000 AT CDROM device driver. -The driver contains code to enable an ISP16 interface if it finds one, so if -you have that, you're lucky. - -My configuration code for the ISP-16 card can get found at +The driver contains code to enable an ISP16 interface if it finds one. It +didn't originally (although this README erroneously said so), because I think +this kind of code should go into its own module. But having to use a hack all +the time in order to use a part of the standard kernel started to annoy me, so +I copied the ISP16 code by Eric van der Maarel (maarel@marin.nl) from Vadim +Model's Sanyo sjcd driver. I'll remove it again from this driver when we have +some common way to talk to ISP16 interfaces. + +My original configuration code for the ISP-16 card can get found at dutette.et.tudelft.nl:/pub/linux/ and at Eberhard's mirror ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/ @@ -32,7 +37,10 @@ or with the matching address value of your interface card. I have tried the module with several 1.2.x kernel versions, and it seems to -work, as far as I tested. If you use it, I'd appreciate success/failure -reports. +work, as far as I tested. It also seems to work for several 1.3.x versions. +If you use it, I'd appreciate success/failure reports. If you find a bug, +try recompiling the driver with some strategically chosen #undef DEBUG_...'s +changed into #defines (you'll find them in .../include/linux/optcd.h) and +include the messages generated in your bug report. Good luck. Leo Spiekman (spiekman@dutette.et.tudelft.nl) diff --git a/drivers/block/blk.h b/drivers/block/blk.h index 0395968461fe..d8d936fe3670 100644 --- a/drivers/block/blk.h +++ b/drivers/block/blk.h @@ -336,7 +336,7 @@ static void (DEVICE_REQUEST)(void); #if ! SCSI_MAJOR(MAJOR_NR) -#ifdef _IDE_CD_C /* ide-cd.c uses copy from ide.c */ +#if defined(_IDE_CD_C) || defined(_TRITON_C) /* shares copy with ide.c */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); #else diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 69039bfb9552..722d0fa42a59 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -110,8 +110,6 @@ #define PACKET_COMMAND 4315 #define REQUEST_SENSE_COMMAND 4316 -#define WIN_PACKETCMD 0xa0 /* Send a packet command. */ - /* Some ATAPI command opcodes (just like SCSI). (Some other cdrom-specific codes are in cdrom.h.) */ #define TEST_UNIT_READY 0x00 diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 57214551a073..9ff7285cdf0d 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 5.03 Aug 13, 1995 + * linux/drivers/block/ide.c Version 5.10 Aug 26, 1995 * * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) */ @@ -115,12 +115,20 @@ * Version 5.03 tune-ups, comments, remove "busy wait" from drive resets * removed PROBE_FOR_IRQS option -- no longer needed * OOOPS! fixed "bad access" bug for 2nd drive on an i/f + * Version 5.04 changed "ira %d" to "irq %d" in DEBUG message + * added more comments, cleaned up unexpected_intr() + * OOOPS! fixed null pointer problem in ide reset code + * added autodetect for Triton chipset -- no effect yet + * Version 5.05 OOOPS! fixed bug in revalidate_disk() + * OOOPS! fixed bug in ide_do_request() + * added ATAPI reset sequence for cdroms + * Version 5.10 added Bus-Mastered DMA support for Triton Chipset + * some (mostly) cosmetic changes * * Driver compile-time options are in ide.h * * To do, in likely order of completion: * - add in several updates from my email collection (soon folks!) - * - add full support for Intel Triton chipset, including bus-mastered DMA * - improved CMD support: handing this off to someone else * - find someone to work on IDE *tape drive* support */ @@ -142,6 +150,10 @@ #include #include +#ifdef CONFIG_PCI +#include +#endif /* CONFIG_PCI */ + #include "ide.h" static ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */ @@ -196,50 +208,46 @@ void ide_set_recovery_timer (ide_hwif_t *hwif) * ide_drive_t structs as needed, rather than always consuming memory * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */ +#define MAGIC_COOKIE 0x12345678 static void init_ide_data (void) { + byte *p; unsigned int h, unit; - static unsigned long magic_cookie = 0x12345678; + static unsigned long magic_cookie = MAGIC_COOKIE; - if (magic_cookie != 0x12345678) + if (magic_cookie != MAGIC_COOKIE) return; /* already initialized */ magic_cookie = 0; for (h = 0; h < 16; ++h) irq_to_hwgroup[h] = NULL; + /* bulk initialize hwif & drive info with zeros */ + p = ((byte *) ide_hwifs) + sizeof(ide_hwifs); + do { + *--p = 0; + } while (p > (byte *) ide_hwifs); + for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; + /* fill in any non-zero initial values */ hwif->noprobe = (h > 1); - hwif->hwgroup = NULL; hwif->io_base = default_io_base[h]; hwif->ctl_port = hwif->io_base ? hwif->io_base + 0x206 : 0x000; #ifdef CONFIG_BLK_DEV_HD if (hwif->io_base == HD_DATA) hwif->noprobe = 1; /* may be overriden by ide_setup() */ #endif /* CONFIG_BLK_DEV_HD */ - hwif->gd = NULL; - hwif->irq = 0; /* default_irqs[h] used when probe fails */ hwif->major = ide_hwif_to_major[h]; hwif->name[0] = 'i'; hwif->name[1] = 'd'; hwif->name[2] = 'e'; hwif->name[3] = '0' + h; - hwif->name[4] = '\0'; - hwif->present = 0; - hwif->next = NULL; - hwif->reset_timeout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; - /* bulk initialize drive info with zeros */ - byte *p = ((byte *) drive) + sizeof(ide_drive_t); - do { - *--p = 0; - } while (p > (byte *) drive); - /* fill in any non-zero initial values */ drive->select.all = (unit<<4)|0xa0; drive->hwif = hwif; @@ -257,7 +265,13 @@ static void init_ide_data (void) #ifdef __i386__ #define VLB_SYNC 1 - +/* + * Some localbus EIDE interfaces require a special access sequence + * when using 32-bit I/O instructions to transfer data. We call this + * the "vlb_sync" sequence, which consists of three successive reads + * of the sector count register location, with interrupts disabled + * to ensure that the reads all happen together. + */ static inline void do_vlb_sync (unsigned short port) { unsigned int _v; __asm__ __volatile__ ( @@ -404,16 +418,30 @@ static void ide_geninit (struct gendisk *gd) } /* - * ide_alloc(): memory allocation for using during driver initialization. + * ide_alloc(): memory allocation for use *only* during driver initialization. + * If "within_area" is non-zero, the memory will be allocated such that + * it lies entirely within a "within_area" sized area (eg. 4096). This is + * needed for DMA stuff. "within_area" must be a power of two (not validated). + * All allocations are longword aligned. */ -static unsigned long init_mem_start = 0uL; /* used by init routines */ +static unsigned long ide_mem_start = 0uL; /* used by ide_alloc() */ -static inline void *ide_alloc (unsigned long bytecount) +void *ide_alloc (unsigned long bytecount, unsigned long within_area) { - unsigned long p = init_mem_start; - if (!p) panic("ide: ide_alloc() not valid now\n"); - init_mem_start += (bytecount + 3uL) & ~3uL; - return (void *) p; + const unsigned long longsize_m1 = (sizeof(long) - 1); + void *p; + + if (!ide_mem_start) + panic("ide: ide_alloc() not valid now\n"); + ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1; + if (within_area) { + unsigned long fraction = within_area - (ide_mem_start & (within_area - 1)); + if (fraction < bytecount) + ide_mem_start += fraction; /* realign to a new page */ + } + p = (void *) ide_mem_start; + ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1; + return p; } /* @@ -434,10 +462,10 @@ static void init_gendisk (ide_hwif_t *hwif) break; } minors = units * (1<sizes = ide_alloc(minors * sizeof(int)); - gd->part = ide_alloc(minors * sizeof(struct hd_struct)); - bs = ide_alloc(minors*sizeof(int)); + gd = ide_alloc (sizeof(struct gendisk), 0); + gd->sizes = ide_alloc (minors * sizeof(int), 0); + gd->part = ide_alloc (minors * sizeof(struct hd_struct), 0); + bs = ide_alloc (minors*sizeof(int), 0); /* cdroms and msdos f/s are examples of non-1024 blocksizes */ blksize_size[hwif->major] = bs; @@ -470,7 +498,12 @@ static void unexpected_intr (int, ide_hwgroup_t *); */ static void reset_ihandler (ide_drive_t *drive) { + unsigned long flags; + + save_flags(flags); + cli(); unexpected_intr (HWIF(drive)->irq, HWGROUP(drive)); + restore_flags(flags); } /* @@ -481,15 +514,49 @@ static void start_reset_timer (ide_hwif_t *hwif) { ide_hwgroup_t *hwgroup = hwif->hwgroup; - hwif->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */ + hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */ hwgroup->handler = &reset_ihandler; /* dummy irq handler */ hwgroup->timer.expires = jiffies + (HZ/20); /* polling interval */ add_timer(&(hwgroup->timer)); } +#ifdef CONFIG_BLK_DEV_IDECD +/* + * atapi_reset_handler() gets invoked to poll the interface for completion every 50ms + * during an atapi drive reset operation. If the drive has not yet responded, + * and we have not yet hit our maximum waiting time, then the timer is restarted + * for another 50ms. + * + * Returns 1 if waiting for another 50ms, returns 0 otherwise. + */ +static int atapi_reset_handler (ide_hwgroup_t *hwgroup) +{ + ide_hwif_t *hwif = hwgroup->hwif; + ide_drive_t *drive = hwgroup->drive; + byte stat; + + OUT_BYTE (drive->select.all, IDE_SELECT_REG); + udelay (10); + + if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) { + if (jiffies < hwgroup->reset_timeout) { + start_reset_timer (hwif); + return 1; + } + printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat); + return ide_do_reset (drive); /* do it the old fashioned way */ + } + hwgroup->doing_atapi_reset = 0; + hwgroup->handler = NULL; /* allow new requests to be processed */ + hwgroup->reset_timeout = 0; /* signal end of ide reset operation */ + printk("%s: ATAPI reset complete\n", drive->name); + return 0; +} +#endif /* CONFIG_BLK_DEV_IDECD */ + /* * reset_handler() gets invoked to poll the interface for completion every 50ms - * during an ide reset operation. If the drives have not not responded, + * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. * @@ -501,8 +568,13 @@ static int reset_handler (ide_hwgroup_t *hwgroup) ide_drive_t *drive = hwgroup->drive; byte tmp; +#ifdef CONFIG_BLK_DEV_IDECD + if (hwgroup->doing_atapi_reset) + return atapi_reset_handler(hwgroup); +#endif /* CONFIG_BLK_DEV_IDECD */ + if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { - if (jiffies < hwif->reset_timeout) { + if (jiffies < hwgroup->reset_timeout) { start_reset_timer (hwif); return 1; } @@ -532,7 +604,7 @@ static int reset_handler (ide_hwgroup_t *hwgroup) } } hwgroup->handler = NULL; /* allow new requests to be processed */ - hwif->reset_timeout = 0; /* signal end of ide reset operation */ + hwgroup->reset_timeout = 0; /* signal end of ide reset operation */ return 0; } @@ -542,9 +614,8 @@ static int reset_handler (ide_hwgroup_t *hwgroup) * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. * - * ATAPI devices have their own reset mechanism (not handled here), - * which allows them to be individually reset without clobbering other - * devices on the same interface. ide-cd.c will handle those separately. + * ATAPI devices have their own reset mechanism which allows them to be + * individually reset without clobbering other devices on the same interface. * * Unfortunately, the IDE interface does not generate an interrupt to let * us know when the reset operation has finished, so we must poll for this. @@ -552,15 +623,35 @@ static int reset_handler (ide_hwgroup_t *hwgroup) * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */ -static int ide_do_reset (ide_drive_t *drive) +int ide_do_reset (ide_drive_t *drive) { unsigned int unit; unsigned long flags; ide_hwif_t *hwif = HWIF(drive); + ide_hwgroup_t *hwgroup = HWGROUP(drive); save_flags(flags); cli(); /* Why ? */ +#ifdef CONFIG_BLK_DEV_IDECD + /* For an ATAPI device, first try an ATAPI SRST. */ + if (drive->media == cdrom) { + if (!hwgroup->doing_atapi_reset) { + hwgroup->doing_atapi_reset = 1; + if (!drive->keep_settings) + drive->unmask = 0; + OUT_BYTE (drive->select.all, IDE_SELECT_REG); + OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); + udelay (10); + hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; + start_reset_timer (hwif); /* begin periodic polling */ + restore_flags (flags); + return 1; + } + } + hwgroup->doing_atapi_reset = 0; +#endif /* CONFIG_BLK_DEV_IDECD */ + /* * First, reset any device state data we were maintaining * for any of the drives on this interface. @@ -589,10 +680,10 @@ static int ide_do_reset (ide_drive_t *drive) * This single interrupt gives us a "fast poll" for drives that * recover from reset very quickly, saving us the first 50ms wait time. */ - OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set nIEN and SRST */ + OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */ udelay(5); /* more than enough time */ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ - hwif->reset_timeout = jiffies + WAIT_WORSTCASE; + hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; start_reset_timer (hwif); /* begin periodic polling */ #endif /* OK_TO_RESET_CONTROLLER */ @@ -640,7 +731,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) printk("Busy "); else { if (stat & READY_STAT) printk("DriveReady "); - if (stat & WRERR_STAT) printk("WriteFault "); + if (stat & WRERR_STAT) printk("DeviceFault "); if (stat & SEEK_STAT) printk("SeekComplete "); if (stat & DRQ_STAT) printk("DataRequest "); if (stat & ECC_STAT) printk("CorrectedError "); @@ -746,6 +837,12 @@ int ide_error (ide_drive_t *drive, const char *msg, byte stat) if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) rq->errors |= ERROR_RESET; /* Mmmm.. timing problem */ + if (rq->errors > 3 && drive->using_dma) { /* DMA troubles? */ + drive->using_dma = 0; + printk("%s: DMA disabled\n", drive->name); + --rq->errors; + return 0; + } if (rq->errors >= ERROR_MAX) ide_end_request(0, HWGROUP(drive)); else { @@ -916,7 +1013,7 @@ static void multwrite_intr (ide_drive_t *drive) * Issue a simple drive command * The drive must be selected beforehand. */ -static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) +static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { ide_set_handler (drive, handler); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); @@ -924,6 +1021,9 @@ static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler OUT_BYTE(cmd,IDE_COMMAND_REG); } +/* + * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. + */ static void set_multmode_intr (ide_drive_t *drive) { byte stat = GET_STAT(); @@ -939,6 +1039,9 @@ static void set_multmode_intr (ide_drive_t *drive) IDE_DO_REQUEST; } +/* + * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. + */ static void set_geometry_intr (ide_drive_t *drive) { byte stat = GET_STAT(); @@ -950,6 +1053,9 @@ static void set_geometry_intr (ide_drive_t *drive) IDE_DO_REQUEST; } +/* + * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. + */ static void recal_intr (ide_drive_t *drive) { byte stat = GET_STAT(); @@ -961,6 +1067,10 @@ static void recal_intr (ide_drive_t *drive) IDE_DO_REQUEST; } +#ifdef IDE_DRIVE_CMD +/* + * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. + */ static void drive_cmd_intr (ide_drive_t *drive) { byte stat = GET_STAT(); @@ -972,8 +1082,14 @@ static void drive_cmd_intr (ide_drive_t *drive) return; IDE_DO_REQUEST; } +#endif /* IDE_DRIVE_CMD */ -static void do_special (ide_drive_t *drive) +/* + * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT + * commands to a drive. It used to do much more, but has been scaled back + * in recent updates, and could be completely eliminated with a bit more effort. + */ +static inline void do_special (ide_drive_t *drive) { special_t *s = &drive->special; #ifdef DEBUG @@ -1044,6 +1160,11 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou return 1; } +/* + * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk, + * using LBA if supported, or CHS otherwise, to address sectors. It also takes + * care of issuing special DRIVE_CMDs. + */ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { OUT_BYTE(drive->ctl,IDE_CONTROL_REG); @@ -1075,11 +1196,15 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned #endif } if (rq->cmd == READ) { + if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) + return; ide_set_handler(drive, &read_intr); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); return; } if (rq->cmd == WRITE) { + if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) + return; OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk("%s: no DRQ after issuing %s\n", drive->name, @@ -1108,6 +1233,10 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned ide_cmd(drive, args[0], args[1], &drive_cmd_intr); return; } else { + /* + * NULL is actually a valid way of waiting for + * all current requests to be flushed from the queue. + */ #ifdef DEBUG printk("%s: DRIVE_CMD (null)\n", drive->name); #endif @@ -1120,6 +1249,9 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned ide_end_request(0, HWGROUP(drive)); } +/* + * do_request() initiates handling of a new I/O request + */ static inline void do_request (ide_hwif_t *hwif, struct request *rq) { unsigned int minor, unit; @@ -1137,18 +1269,21 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq) goto kill_rq; } drive = &hwif->drives[unit]; +#ifdef DEBUG if (rq->bh && !rq->bh->b_lock) { printk("%s: block not locked\n", drive->name); goto kill_rq; } +#endif block = rq->sector; blockend = block + rq->nr_sectors; if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { - printk("%s: bad access: block=%ld, count=%ld\n", - drive->name, block, rq->nr_sectors); + printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, + (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); goto kill_rq; } block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; + ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive; #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); #endif @@ -1158,7 +1293,6 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq) return; } - ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive; if (!drive->special.all) { #ifdef CONFIG_BLK_DEV_IDECD switch (drive->media) { @@ -1202,7 +1336,6 @@ kill_rq: void ide_do_request (ide_hwgroup_t *hwgroup) { cli(); /* paranoia */ - if (hwgroup->handler != NULL) { printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); return; @@ -1218,14 +1351,25 @@ void ide_do_request (ide_hwgroup_t *hwgroup) goto got_rq; } while ((hwif = hwif->next) != hwgroup->hwif); return; /* no work left for this hwgroup */ + got_rq: + blk_dev[hwif->major].current_request = rq->next; } - got_rq: - blk_dev[hwif->major].current_request = rq->next; do_request(hwgroup->hwif = hwif, hwgroup->rq = rq); cli(); } while (hwgroup->handler == NULL); } +/* + * do_hwgroup_request() invokes ide_do_request() after first masking + * all possible interrupts for the current hwgroup. This prevents race + * conditions in the event that an unexpected interrupt occurs while + * we are in the driver. + * + * Note that when an interrupt is used to reenter the driver, the first level + * handler will already have masked the irq that triggered, but any other ones + * for the hwgroup will still be unmasked. The driver tries to be careful + * about such things. + */ static void do_hwgroup_request (ide_hwgroup_t *hwgroup) { if (hwgroup->handler == NULL) { @@ -1270,7 +1414,7 @@ static void timer_expiry (unsigned long data) save_flags(flags); cli(); - if (hwgroup->hwif->reset_timeout != 0) { /* ide reset in progress? */ + if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */ if (!reset_handler(hwgroup)) do_hwgroup_request (hwgroup); } else if (hwgroup->handler == NULL) { /* not waiting for anything? */ @@ -1278,6 +1422,8 @@ static void timer_expiry (unsigned long data) printk("%s: marginal timeout\n", drive->name); } else { /* drive not responding */ hwgroup->handler = NULL; + if (hwgroup->hwif->dmaproc) + (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); if (!ide_error(drive, "irq timeout", GET_STAT())) do_hwgroup_request (hwgroup); } @@ -1293,24 +1439,32 @@ static void timer_expiry (unsigned long data) * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. + * + * This routine assumes cli() is in effect when called. + * + * If an unexpected interrupt happens on irq15 while we are handling irq14 + * and if the two interfaces are "serialized" (CMD640B), then it looks like + * we could screw up by interfering with a new request being set up for irq15. + * + * In reality, this is a non-issue. The new command is not sent unless the + * drive is ready to accept one, in which case we know the drive is not + * trying to interrupt us. And ide_set_handler() is always invoked before + * completing the issuance of any new drive command, so we will not be + * accidently invoked as a result of any valid command completion interrupt. + * */ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) { byte stat; unsigned int unit; ide_hwif_t *hwif = hwgroup->hwif; - unsigned long flags; - - save_flags(flags); - cli(); /* * check for ide reset in progress */ - if (hwif->reset_timeout != 0) { + if (hwgroup->reset_timeout != 0) { if (!reset_handler(hwgroup)) do_hwgroup_request (hwgroup); - restore_flags(flags); return; } @@ -1330,7 +1484,6 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) } } } while ((hwif = hwif->next) != hwgroup->hwif); - restore_flags(flags); } /* @@ -1340,13 +1493,8 @@ static void ide_intr (int irq, struct pt_regs *regs) { ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq]; ide_handler_t *handler; - if (irq != hwgroup->hwif->irq) { -#ifdef DEBUG - printk("ide_intr: expected ira %d, got irq %d instead\n", - hwgroup->hwif->irq, irq); -#endif - unexpected_intr(irq, hwgroup); - } else if ((handler = hwgroup->handler) != NULL) { + + if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { ide_drive_t *drive = hwgroup->drive; hwgroup->handler = NULL; del_timer(&(hwgroup->timer)); @@ -1354,12 +1502,15 @@ static void ide_intr (int irq, struct pt_regs *regs) sti(); handler(drive); } else { - sti(); unexpected_intr(irq, hwgroup); } cli(); } +/* + * get_info_ptr() returns the (ide_drive_t *) for a given device number. + * It returns NULL if the given device number does not match any present drives. + */ static ide_drive_t *get_info_ptr (int i_rdev) { int major = MAJOR(i_rdev); @@ -1381,18 +1532,6 @@ static ide_drive_t *get_info_ptr (int i_rdev) } #ifdef IDE_DRIVE_CMD -static int write_fs_long (unsigned long useraddr, long value) -{ - int err; - - if (NULL == (long *)useraddr) - return -EINVAL; - if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long)))) - return err; - put_user((unsigned)value, (long *) useraddr); - return 0; -} - /* * This function issues a specific IDE drive command onto the * tail of the request queue, and waits for it to be completed. @@ -1513,7 +1652,7 @@ static int revalidate_disk(dev_t i_rdev) if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; - major = MAJOR(i_rdev); + major = MAJOR(i_rdev) << 8; minor = drive->select.b.unit << PARTN_BITS; save_flags(flags); cli(); @@ -1540,6 +1679,18 @@ static int revalidate_disk(dev_t i_rdev) return 0; } +static int write_fs_long (unsigned long useraddr, long value) +{ + int err; + + if (NULL == (long *)useraddr) + return -EINVAL; + if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long)))) + return err; + put_user((unsigned)value, (long *) useraddr); + return 0; +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1590,6 +1741,9 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_GET_UNMASKINTR: return write_fs_long(arg, drive->unmask); + case HDIO_GET_DMA: + return write_fs_long(arg, drive->using_dma); + case HDIO_GET_CHIPSET: return write_fs_long(arg, drive->chipset); @@ -1602,13 +1756,18 @@ static int ide_ioctl (struct inode *inode, struct file *file, if (drive->id == NULL) return -ENOMSG; err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id)); - if (err) return err; - memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id)); - return 0; + if (!err) + memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id)); + return err; case HDIO_GET_NOWERR: return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT); + case HDIO_SET_DMA: + if (drive->media != disk) + return -EPERM; + if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) + return -EPERM; case HDIO_SET_KEEPSETTINGS: case HDIO_SET_UNMASKINTR: case HDIO_SET_NOWERR: @@ -1622,6 +1781,9 @@ static int ide_ioctl (struct inode *inode, struct file *file, save_flags(flags); cli(); switch (cmd) { + case HDIO_SET_DMA: + drive->using_dma = arg; + break; case HDIO_SET_KEEPSETTINGS: drive->keep_settings = arg; break; @@ -1645,7 +1807,8 @@ static int ide_ioctl (struct inode *inode, struct file *file, return 0; case HDIO_SET_MULTCOUNT: - if (!suser()) return -EACCES; + if (!suser()) + return -EACCES; if (inode->i_rdev & PARTN_MASK) return -EINVAL; if ((drive->id != NULL) && (arg > drive->id->max_multsect)) @@ -1738,13 +1901,13 @@ static void fixstring (byte *s, const int bytecount, const int byteswap) *p++ = '\0'; } -static void do_identify (ide_drive_t *drive, byte cmd) +static inline void do_identify (ide_drive_t *drive, byte cmd) { int bswap; struct hd_driveid *id; unsigned long capacity, check; - id = drive->id = ide_alloc(SECTOR_WORDS*4); + id = drive->id = ide_alloc (SECTOR_WORDS*4, 0); ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ sti(); @@ -1764,11 +1927,11 @@ static void do_identify (ide_drive_t *drive, byte cmd) */ bswap = 1; if (cmd == WIN_PIDENTIFY) { - if ((id->model[0] == 'N' && id->model[1] == 'E') - || (id->model[0] == 'F' && id->model[1] == 'X') - || (id->model[0] == 'P' && id->model[1] == 'i')) - bswap = 0; /* NEC, Pioneer and *some* Mitsumi units */ - } /* Vertos drives may still be weird */ + if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */ + || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */ + || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */ + bswap = 0; /* Vertos drives may still be weird */ + } fixstring (id->model, sizeof(id->model), bswap); fixstring (id->fw_rev, sizeof(id->fw_rev), bswap); fixstring (id->serial_no, sizeof(id->serial_no), bswap); @@ -1862,7 +2025,10 @@ static void do_identify (ide_drive_t *drive, byte cmd) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) drive->special.b.set_multmode = 1; - printk(", MaxMult=%d", id->max_multsect); + } + if (HWIF(drive)->dmaproc != NULL) { /* hwif supports DMA? */ + if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) + printk(", DMA"); } printk("\n"); } @@ -1998,7 +2164,7 @@ static int do_probe (ide_drive_t *drive, byte cmd) * Returns: 0 no device was found * 1 device was found (note: drive->present might still be 0) */ -static byte probe_for_drive (ide_drive_t *drive) +static inline byte probe_for_drive (ide_drive_t *drive) { if (drive->noprobe) /* skip probing? */ return drive->present; @@ -2306,6 +2472,7 @@ int ide_xlate_1024 (dev_t i_rdev, int need_offset, const char *msg) * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value * means we have an AT controller hard disk for that drive. */ + static void probe_cmos_for_drives (ide_hwif_t *hwif) { #ifdef __i386__ @@ -2320,11 +2487,9 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif) ide_drive_t *drive = &hwif->drives[unit]; if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) { drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = * (BIOS+2); - drive->sect = drive->bios_sect = * (BIOS+14); - drive->wpcom = (*(unsigned short *)(BIOS+5))>>2; + drive->head = drive->bios_head = *(BIOS+2); + drive->sect = drive->bios_sect = *(BIOS+14); drive->ctl = *(BIOS+8); - drive->wpcom = 0; drive->media = disk; drive->present = 1; } @@ -2362,12 +2527,16 @@ static int init_irq (ide_hwif_t *hwif) * Got the irq, now set everything else up */ if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) { - hwgroup = ide_alloc(sizeof(ide_hwgroup_t)); + hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0); irq_to_hwgroup[hwif->irq] = hwgroup; hwgroup->hwif = hwif->next = hwif; hwgroup->rq = NULL; hwgroup->handler = NULL; hwgroup->drive = NULL; + hwgroup->reset_timeout = 0; +#ifdef CONFIG_BLK_DEV_IDECD + hwgroup->doing_atapi_reset = 0; +#endif /* CONFIG_BLK_DEV_IDECD */ init_timer(&hwgroup->timer); hwgroup->timer.function = &timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; @@ -2456,6 +2625,7 @@ static void try_to_init_dtc2278 (void) } #endif /* SUPPORT_DTC2278 */ + /* * This is gets invoked once during initialization, to set *everything* up */ @@ -2463,7 +2633,7 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end) { int h; - init_mem_start = (mem_start + 3uL) & ~3uL; /* for ide_alloc() */ + ide_mem_start = mem_start; /* for ide_alloc () */ init_ide_data (); /* * First, we determine what hardware is present @@ -2472,6 +2642,20 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end) if (probe_dtc2278) try_to_init_dtc2278(); #endif /* SUPPORT_DTC2278 */ +#ifdef CONFIG_PCI + /* + * Look for pci disk interfaces. + */ + if (pcibios_present()) { +#ifdef CONFIG_BLK_DEV_TRITON + ide_init_triton (ide_hwifs); +#endif /* CONFIG_BLK_DEV_TRITON */ + } +#endif /* CONFIG_PCI */ + + /* + * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports + */ for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; if (!hwif->noprobe) { @@ -2491,6 +2675,7 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end) if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) { printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name); hwif->present = 0; +B } #endif /* CONFIG_BLK_DEV_HD */ } @@ -2535,7 +2720,7 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end) hwif->present = 1; /* success */ } } - mem_start = init_mem_start; - init_mem_start = 0uL; /* prevent further use of ide_alloc() */ + mem_start = ide_mem_start; + ide_mem_start = 0uL; /* prevent further use of ide_alloc() */ return mem_start; } diff --git a/drivers/block/ide.h b/drivers/block/ide.h index bff63d62e52f..f22803bf62e0 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -21,7 +21,7 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ #include -#define REALLY_FAST_IO /* define if ide ports are perfect */ +#undef REALLY_FAST_IO /* define if ide ports are perfect */ #define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ #ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */ @@ -121,14 +121,6 @@ typedef unsigned char byte; /* used everywhere */ #ifdef CONFIG_BLK_DEV_IDECD -struct packet_command { - char *buffer; - int buflen; - int stat; - unsigned char c[12]; -}; - - struct atapi_request_sense { unsigned char error_code : 7; unsigned char valid : 1; @@ -146,6 +138,14 @@ struct atapi_request_sense { byte sense_key_specific[3]; }; +struct packet_command { + char *buffer; + int buflen; + int stat; + struct atapi_request_sense *sense_data; + unsigned char c[12]; +}; + /* Space to hold the disk TOC. */ #define MAX_TRACKS 99 @@ -165,6 +165,9 @@ struct atapi_toc_entry { }; struct atapi_toc { + int last_session_lba; + int xa_flag; + unsigned capacity; struct atapi_toc_header hdr; struct atapi_toc_entry ent[MAX_TRACKS+1]; /* One extra for the leadout. */ }; @@ -230,14 +233,13 @@ typedef struct ide_drive_s { unsigned vlb_32bit : 1; /* use 32bit in/out for data */ unsigned vlb_sync : 1; /* needed for some 32bit chip sets */ unsigned removeable : 1; /* 1 if need to do check_media_change */ - unsigned dma_capable : 1; /* for Intel Triton chipset, others.. */ + unsigned using_dma : 1; /* disk is using dma for read/write */ + unsigned unmask : 1; /* flag: okay to unmask other irqs */ + media_t media; /* disk, cdrom, tape */ select_t select; /* basic drive/head select reg value */ - byte unmask; /* flag: okay to unmask other irqs */ void *hwif; /* actually (ide_hwif_t *) */ byte ctl; /* "normal" value for IDE_CONTROL_REG */ byte ready_stat; /* min status value for drive ready */ - byte wpcom; /* ignored by all IDE drives */ - media_t media; /* disk, cdrom, tape */ byte mult_count; /* current multiple sector setting */ byte mult_req; /* requested multiple sector setting */ byte chipset; /* interface chipset access method */ @@ -259,22 +261,38 @@ typedef struct ide_drive_s { #endif /* CONFIG_BLK_DEV_IDECD */ } ide_drive_t; +/* + * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive. + * + * The caller is assumed to have selected the drive and programmed the drive's + * sector address using CHS or LBA. All that remains is to prepare for DMA + * and then issue the actual read/write DMA/PIO command to the drive. + * + * Returns 0 if all went well. + * Returns 1 if DMA read/write could not be started, in which case the caller + * should either try again later, or revert to PIO for the current request. + */ +typedef enum {ide_dma_read = 0, ide_dma_write = 1, ide_dma_abort = 2, ide_dma_check = 3} ide_dma_action_t; +typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); + typedef struct hwif_s { struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ void *hwgroup; /* actually (ide_hwgroup_t *) */ unsigned short io_base; /* base io port addr */ unsigned short ctl_port; /* usually io_base+0x206 */ - ide_drive_t drives[MAX_DRIVES]; /* drive info */ + ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ + ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ + unsigned long *dmatable; /* dma physical region descriptor table */ + unsigned short dma_base; /* base addr for dma ports (triton) */ byte irq; /* our irq number */ byte major; /* our major number */ byte drivecount; /* how many drives attached */ char name[5]; /* name of interface, eg. "ide0" */ unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ - unsigned long reset_timeout; /* timeout value during ide resets */ #if (DISK_RECOVERY_TIME > 0) - unsigned long last_timer; /* time when previous rq was done */ + unsigned long last_time; /* time when previous rq was done */ #endif #ifdef CONFIG_BLK_DEV_IDECD struct request request_sense_request; /* from ide-cd.c */ @@ -283,7 +301,7 @@ typedef struct hwif_s { } ide_hwif_t; /* - * our internal interrupt handler type + * internal ide interrupt handler type */ typedef void (ide_handler_t)(ide_drive_t *); @@ -294,6 +312,10 @@ typedef struct hwgroup_s { struct request *rq; /* current request */ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ + unsigned long reset_timeout; /* timeout value during ide resets */ +#ifdef CONFIG_BLK_DEV_IDECD + int doing_atapi_reset; +#endif /* CONFIG_BLK_DEV_IDECD */ } ide_hwgroup_t; /* @@ -363,6 +385,23 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou */ int ide_xlate_1024(dev_t, int, const char *); +/* + * Start a reset operation for an IDE interface. + * Returns 0 if the reset operation is still in progress, + * in which case the drive MUST return, to await completion. + * Returns 1 if the reset is complete (success or failure). + */ +int ide_do_reset (ide_drive_t *); + +/* + * ide_alloc(): memory allocation for use *only* during driver initialization. + * If "within_area" is non-zero, the memory will be allocated such that + * it lies entirely within a "within_area" sized area (eg. 4096). This is + * needed for DMA stuff. "within_area" must be a power of two (not validated). + * All allocations are longword aligned. + */ +void *ide_alloc (unsigned long bytecount, unsigned long within_area); + #ifdef CONFIG_BLK_DEV_IDECD /* * These are routines in ide-cd.c invoked from ide.c @@ -374,3 +413,8 @@ int ide_cdrom_open (struct inode *, struct file *, ide_drive_t *); void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *); void ide_cdrom_setup (ide_drive_t *); #endif /* CONFIG_BLK_DEV_IDECD */ + +#ifdef CONFIG_BLK_DEV_TRITON +void ide_init_triton (ide_hwif_t *); +#endif /* CONFIG_BLK_DEV_TRITON */ + diff --git a/drivers/block/optcd.c b/drivers/block/optcd.c index c22efad2b030..c844aed9daa7 100644 --- a/drivers/block/optcd.c +++ b/drivers/block/optcd.c @@ -1,10 +1,12 @@ -/* $Id: optcd.c,v 1.7 1995/06/28 20:20:13 root Exp $ +/* $Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $ linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks - by Eberhard Moenkeberg. + by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and + configuration by Eric van der Maarel (maarel@marin.nl), with some data + communicated by Vadim V. Model (vadim@rbrf.msk.su). 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 @@ -38,6 +40,12 @@ should go into its own driver. The driver now has its own major nr. Disk change detection now seems to work, too. + This version became part of the standard + kernel as of version 1.3.7 + 24-9-95 v0.4 Re-inserted ISP-16 interface code which I + copied from sjcd.c, with a few changes. + Updated README.optcd. Submitted for + inclusion in 1.3.21 */ #include @@ -69,6 +77,59 @@ #define optcd_port optcd /* Needed for the modutils. */ # include + +/* Some (Media)Magic */ +/* define types of drive the interface on an ISP16 card may be looking at */ +#define ISP16_DRIVE_X 0x00 +#define ISP16_SONY 0x02 +#define ISP16_PANASONIC0 0x02 +#define ISP16_SANYO0 0x02 +#define ISP16_MITSUMI 0x04 +#define ISP16_PANASONIC1 0x06 +#define ISP16_SANYO1 0x06 +#define ISP16_DRIVE_NOT_USED 0x08 /* not used */ +#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ +/* ...for port */ +#define ISP16_DRIVE_SET_PORT 0xF8D +/* set io parameters */ +#define ISP16_BASE_340 0x00 +#define ISP16_BASE_330 0x40 +#define ISP16_BASE_360 0x80 +#define ISP16_BASE_320 0xC0 +#define ISP16_IRQ_X 0x00 +#define ISP16_IRQ_5 0x04 /* shouldn't be used due to soundcard conflicts */ +#define ISP16_IRQ_7 0x08 /* shouldn't be used due to soundcard conflicts */ +#define ISP16_IRQ_3 0x0C +#define ISP16_IRQ_9 0x10 +#define ISP16_IRQ_10 0x14 +#define ISP16_IRQ_11 0x18 +#define ISP16_DMA_X 0x03 +#define ISP16_DMA_3 0x00 +#define ISP16_DMA_5 0x00 +#define ISP16_DMA_6 0x01 +#define ISP16_DMA_7 0x02 +#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ +/* ...for port */ +#define ISP16_IO_SET_PORT 0xF8E +/* enable the drive */ +#define ISP16_NO_IDE__ENABLE_CDROM_PORT 0xF90 /* ISP16 without IDE interface */ +#define ISP16_IDE__ENABLE_CDROM_PORT 0xF91 /* ISP16 with IDE interface */ +#define ISP16_ENABLE_CDROM 0x80 /* seven bit */ + +/* the magic stuff */ +#define ISP16_CTRL_PORT 0xF8F +#define ISP16_NO_IDE__CTRL 0xE2 /* ISP16 without IDE interface */ +#define ISP16_IDE__CTRL 0xE3 /* ISP16 with IDE interface */ + +static short isp16_detect(void); +static short isp16_no_ide__detect(void); +static short isp16_with_ide__detect(void); +static short isp16_config( int base, u_char drive_type, int irq, int dma ); +static short isp16_type; /* dependent on type of interface card */ +static u_char isp16_ctrl; +static u_short isp16_enable_cdrom_port; + + static short optcd_port = OPTCD_PORTBASE; /* Read current status/data availability flags */ @@ -1363,6 +1424,29 @@ int init_module(void) { optcd_port); RETURN_EIO; } + + if (!check_region(ISP16_DRIVE_SET_PORT, 5)) { + /* If someone else has'nt already reserved these ports, + probe for an ISP16 interface card, and enable SONY mode + with no interrupts and no DMA. (As far as I know, all optics + drives come with a SONY interface.) */ + if ( (isp16_type=isp16_detect()) < 0 ) + printk( "No ISP16 cdrom interface found.\n" ); + else { + u_char expected_drive; + + printk( "ISP16 cdrom interface (%s optional IDE) detected.\n", + (isp16_type==2)?"with":"without" ); + + expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0); + + if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) { + printk( "ISP16 cdrom interface has not been properly configured.\n" ); + return(mem_start); + } + } + } + if (!optResetDrive()) { printk("optcd: drive at 0x%x not ready\n", optcd_port); RETURN_EIO; @@ -1406,3 +1490,191 @@ void cleanup_module(void) { printk("optcd: module released.\n"); } #endif MODULE + + +/* + * -- ISP16 detection and configuration + * + * Copyright (c) 1995, Eric van der Maarel + * + * Version 0.5 + * + * Detect cdrom interface on ISP16 soundcard. + * Configure cdrom interface. + * + * Algorithm for the card with no IDE support option taken + * from the CDSETUP.SYS driver for MSDOS, + * by OPTi Computers, version 2.03. + * Algorithm for the IDE supporting ISP16 as communicated + * to me by Vadim Model and Leo Spiekman. + * + * Use, modifification or redistribution of this software is + * allowed under the terms of the GPL. + * + */ + + +#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) +#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) + +static short +isp16_detect(void) +{ + + if ( !( isp16_with_ide__detect() < 0 ) ) + return(2); + else + return( isp16_no_ide__detect() ); +} + +static short +isp16_no_ide__detect(void) +{ + u_char ctrl; + u_char enable_cdrom; + u_char io; + short i = -1; + + isp16_ctrl = ISP16_NO_IDE__CTRL; + isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT; + + /* read' and write' are a special read and write, respectively */ + + /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ + ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC; + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + /* read' 3,4 and 5-bit from the cdrom enable port */ + enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38; + + if ( !(enable_cdrom & 0x20) ) { /* 5-bit not set */ + /* read' last 2 bits of ISP16_IO_SET_PORT */ + io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03; + if ( ((io&0x01)<<1) == (io&0x02) ) { /* bits are the same */ + if ( io == 0 ) { /* ...the same and 0 */ + i = 0; + enable_cdrom |= 0x20; + } + else { /* ...the same and 1 */ /* my card, first time 'round */ + i = 1; + enable_cdrom |= 0x28; + } + ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom ); + } + else { /* bits are not the same */ + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + return(i); /* -> not detected: possibly incorrect conclusion */ + } + } + else if ( enable_cdrom == 0x20 ) + i = 0; + else if ( enable_cdrom == 0x28 ) /* my card, already initialised */ + i = 1; + + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + return(i); +} + +static short +isp16_with_ide__detect(void) +{ + u_char ctrl; + u_char tmp; + + isp16_ctrl = ISP16_IDE__CTRL; + isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT; + + /* read' and write' are a special read and write, respectively */ + + /* read' ISP16_CTRL_PORT and save */ + ctrl = ISP16_IN( ISP16_CTRL_PORT ); + + /* write' zero to the ctrl port and get response */ + ISP16_OUT( ISP16_CTRL_PORT, 0 ); + tmp = ISP16_IN( ISP16_CTRL_PORT ); + + if ( tmp != 2 ) /* isp16 with ide option not detected */ + return(-1); + + /* restore ctrl port value */ + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + return(2); +} + +static short +isp16_config( int base, u_char drive_type, int irq, int dma ) +{ + u_char base_code; + u_char irq_code; + u_char dma_code; + u_char i; + + if ( (drive_type == ISP16_MITSUMI) && (dma != 0) ) + printk( "Mitsumi cdrom drive has no dma support.\n" ); + + switch (base) { + case 0x340: base_code = ISP16_BASE_340; break; + case 0x330: base_code = ISP16_BASE_330; break; + case 0x360: base_code = ISP16_BASE_360; break; + case 0x320: base_code = ISP16_BASE_320; break; + default: + printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base ); + return(-1); + } + switch (irq) { + case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */ + case 5: irq_code = ISP16_IRQ_5; + printk( "Irq 5 shouldn't be used by cdrom interface on ISP16," + " due to possible conflicts with the soundcard.\n"); + break; + case 7: irq_code = ISP16_IRQ_7; + printk( "Irq 7 shouldn't be used by cdrom interface on ISP16," + " due to possible conflicts with the soundcard.\n"); + break; + case 3: irq_code = ISP16_IRQ_3; break; + case 9: irq_code = ISP16_IRQ_9; break; + case 10: irq_code = ISP16_IRQ_10; break; + case 11: irq_code = ISP16_IRQ_11; break; + default: + printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq ); + return(-1); + } + switch (dma) { + case 0: dma_code = ISP16_DMA_X; break; /* disable dma */ + case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16," + " due to conflict with the soundcard.\n"); + return(-1); break; + case 3: dma_code = ISP16_DMA_3; break; + case 5: dma_code = ISP16_DMA_5; break; + case 6: dma_code = ISP16_DMA_6; break; + case 7: dma_code = ISP16_DMA_7; break; + default: + printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma ); + return(-1); + } + + if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && + drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && + drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && + drive_type != ISP16_DRIVE_X ) { + printk( "Drive type (code 0x%02X) not supported by cdrom" + " interface on ISP16.\n", drive_type ); + return(-1); + } + + /* set type of interface */ + i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ + ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type ); + + /* enable cdrom on interface with ide support */ + if ( isp16_type > 1 ) + ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM ); + + /* set base address, irq and dma */ + i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ + ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code ); + + return(0); +} diff --git a/drivers/block/triton.c b/drivers/block/triton.c new file mode 100644 index 000000000000..75cbd214953a --- /dev/null +++ b/drivers/block/triton.c @@ -0,0 +1,352 @@ +/* + * linux/drivers/block/triton.c Version 1.00 Aug 26, 1995 + * + * Copyright (c) 1995 Mark Lord + * May be copied or modified under the terms of the GNU General Public License + */ + +/* + * This module provides support for the Bus Master IDE DMA function + * of the Intel PCI Triton chipset (82371FB). + * + * DMA is currently supported only for hard disk drives (not cdroms). + * + * Support for cdroms will likely be added at a later date, + * after broader experience has been obtained with hard disks. + * + * Up to four drives may be enabled for DMA, and the Triton chipset will + * (hopefully) arbitrate the PCI bus among them. Note that the 82371FB chip + * provides a single "line buffer" for the BM IDE function, so performance of + * multiple (two) drives doing DMA simultaneously will suffer somewhat, + * as they contest for that resource bottleneck. This is handled transparently + * inside the 82371FB chip. + * + * By default, DMA support is prepared for use, but is currently enabled only + * for drives which support multi-word DMA mode2 (mword2), or which are + * recognized as "good" (see table below). Drives with only mode0 or mode1 + * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A) + * but are not enabled by default. Use "hdparm -i" to view supported modes + * for a given drive. + * + * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling + * DMA support, but must be (re-)compiled against this kernel version or later. + * + * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting. + * If problems arise, ide.c will disable DMA operation after a few retries. + * This error recovery mechanism works and has been extremely well exercised. + * + * IDE drives, depending on their vintage, may support several different modes + * of DMA operation. The boot-time modes are indicated with a "*" in + * the "hdparm -i" listing, and can be changed with *knowledgeable* use of + * the "hdparm -X" feature. There is seldom a need to do this, as drives + * normally power-up with their "best" PIO/DMA modes enabled. + * + * Testing was done with an ASUS P55TP4XE/100 system and the following drives: + * + * Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4. + * - DMA mode2 works fine (7.4MB/sec), despite the tiny on-drive buffer. + * - This drive also does PIO mode4, slightly slower than DMA mode2. + * + * Micropolis MC2112A (1Gig w/512kB buffer), drive pre-dates EIDE, ATA2. + * - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer. + * - This older drive can also be tweaked for fastPIO (3,7MB/sec) by using + * maximum clock settings (5,4) and setting all flags except prefetch. + * + * Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3. + * - DMA does not work reliably. The drive appears to be somewhat tardy + * in deasserting DMARQ at the end of a sector. This is evident in + * the observation that WRITEs work most of the time, depending on + * cache-buffer occupancy, but multi-sector reads seldom work. + * + * Drives like the AC31000H could likely be made to work if all DMA were done + * one sector at a time, but that would likely negate any advantage over PIO. + * + * If you have any drive models add, email your results to: mlord@bnr.ca + * Keep an eye on your /var/adm/messages for "DMA disabled" messages. + */ +#define _TRITON_C +#include +#ifndef CONFIG_BLK_DEV_TRITON +#define CONFIG_BLK_DEV_TRITON y +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +/* + * good_dma_drives() lists the model names (from "hdparm -i") + * of drives which do not support mword2 DMA but which are + * known to work fine with this interface under Linux. + */ +const char *good_dma_drives[] = {"Micropolis 2112A"}; + +/* + * Our Physical Region Descriptor (PRD) table should be large enough + * to handle the biggest I/O request we are likely to see. Since requests + * can have no more than 256 sectors, and since the typical blocksize is + * two sectors, we can get by with a limit of 128 entries here for the + * usual worst case. Most requests seem to include some contiguous blocks, + * further reducing the number of table entries required. + * + * Note that the driver reverts to PIO mode for individual requests that exceed + * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling + * 100% of all crazy scenarios here is not necessary. + */ +#define PRD_ENTRIES 128 /* max memory area count per DMA */ + +/* + * dma_intr() is the handler for disk read/write DMA interrupts + */ +static void dma_intr (ide_drive_t *drive) +{ + byte stat, dma_stat; + int i; + struct request *rq = HWGROUP(drive)->rq; + unsigned short dma_base = HWIF(drive)->dma_base; + + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */ + stat = GET_STAT(); + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + if ((dma_stat & 7) == 4) { /* verify good DMA status */ + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } + IDE_DO_REQUEST; + return; + } + printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat); + } + sti(); + if (!ide_error(drive, "dma_intr", stat)) + IDE_DO_REQUEST; +} + +/* + * build_dmatable() prepares a dma request. + * Returns 0 if all went okay, returns 1 otherwise. + */ +static int build_dmatable (ide_drive_t *drive) +{ + struct request *rq = HWGROUP(drive)->rq; + struct buffer_head *bh = rq->bh; + unsigned long size, addr, *table = HWIF(drive)->dmatable; + unsigned int count = 0; + + do { + /* + * Determine addr and size of next buffer area. We assume that + * individual virtual buffers are always composed linearly in + * physical memory. For example, we assume that any 8kB buffer + * is always composed of two adjacent physical 4kB pages rather + * than two possibly non-adjacent physical 4kB pages. + */ + if (bh == NULL) { /* paging requests have (rq->bh == NULL) */ + addr = virt_to_bus (rq->buffer); + size = rq->nr_sectors << 9; + } else { + /* group sequential buffers into one large buffer */ + addr = virt_to_bus (bh->b_data); + size = bh->b_size; + while ((bh = bh->b_reqnext) != NULL) { + if ((addr + size) != virt_to_bus (bh->b_data)) + break; + size += bh->b_size; + } + } + + /* + * Fill in the dma table, without crossing any 64kB boundaries. + * We assume 16-bit alignment of all blocks. + */ + while (size) { + if (++count >= PRD_ENTRIES) { + printk("%s: DMA table too small\n", drive->name); + return 1; /* revert to PIO for this request */ + } else { + unsigned long bcount = 0x10000 - (addr & 0xffff); + if (bcount > size) + bcount = size; + *table++ = addr; + *table++ = bcount; + addr += bcount; + size -= bcount; + } + } + } while (bh != NULL); + if (count) { + *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */ + return 0; + } + printk("%s: empty DMA table?\n", drive->name); + return 1; /* let the PIO routines handle this weirdness */ +} + +/* + * triton_dmaproc() initiates/aborts DMA read/write operations on a drive. + * + * The caller is assumed to have selected the drive and programmed the drive's + * sector address using CHS or LBA. All that remains is to prepare for DMA + * and then issue the actual read/write DMA/PIO command to the drive. + * + * Returns 0 if all went well. + * Returns 1 if DMA read/write could not be started, in which case + * the caller should revert to PIO for the current request. + */ +static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + const char **list; + unsigned long dma_base = HWIF(drive)->dma_base; + + if (func == ide_dma_abort) { + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + return 0; + } + if (func == ide_dma_check) { + struct hd_driveid *id = drive->id; + if (id && (id->capability & 1)) { + /* Enable DMA on any drive that supports mword2 DMA */ + if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + /* Consult the list of known "good" drives */ + list = good_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + } + } + return 1; /* DMA not enabled */ + } + if (build_dmatable (drive)) + return 1; + outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ + outb((!func) << 3, dma_base); /* specify r/w */ + outb(0x26, dma_base+2); /* clear status bits */ + ide_set_handler (drive, &dma_intr); /* issue cmd to drive */ + OUT_BYTE(func ? WIN_WRITEDMA : WIN_READDMA, IDE_COMMAND_REG); + outb(inb(dma_base)|1, dma_base); /* begin DMA */ + return 0; +} + +/* + * print_triton_drive_flags() displays the currently programmed options + * in the Triton chipset for a given drive. + * + * If fastDMA is "no", then slow ISA timings are used for DMA data xfers. + * If fastPIO is "no", then slow ISA timings are used for PIO data xfers. + * If IORDY is "no", then IORDY is assumed to always be asserted. + * If PreFetch is "no", then data pre-fetch/post are not used. + * + * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and + * back-to-back 16-bit data transfers are enabled, using the sample_CLKs + * and recovery_CLKs (PCI clock cycles) timing parameters for that interface. + */ +static void print_triton_drive_flags (unsigned int unit, byte flags) +{ + printk(" %s ", unit ? "slave :" : "master:"); + printk( "fastDMA=%s", (flags&9) ? "on " : "off"); + printk(" PreFetch=%s", (flags&4) ? "on " : "off"); + printk(" IORDY=%s", (flags&2) ? "on " : "off"); + printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off"); +} + +/* + * ide_init_triton() uses the PCI BIOS to scan for a Triton i82371FB chip, + * and prepares the IDE driver for DMA operation if one is found. + * This routine is called from ide.c during driver initialization. + */ +void ide_init_triton (ide_hwif_t hwifs[]) +{ + int rc = 0, h; + unsigned short bmiba, pcicmd; + unsigned int timings; + unsigned char bus, fn; + + if (pcibios_find_device (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371, 0, &bus, &fn)) + goto quit; + ++fn; /* IDE is second function on this chip */ + + /* + * See if IDE and BM-DMA features are enabled: + */ + if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd))) + goto quit; + if ((pcicmd & 5) != 5) { + if ((pcicmd & 1) == 0) + printk("ide: Triton IDE ports are not enabled\n"); + else + printk("ide: Triton BM-DMA feature is not enabled\n"); + goto quit; + } +#if 0 + (void) pcibios_write_config_word(bus, fn, 0x42, 0x8037); /* for my MC2112A */ +#endif + /* + * See if ide port(s) are enabled + */ + if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings))) + goto quit; + if (!(timings & 0x80008000)) { + printk("ide: Triton IDE ports are not enabled\n"); + goto quit; + } + printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); + + /* + * Get the bmiba base address + */ + if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) + goto quit; + bmiba &= 0xfff0; /* extract port base address */ + + /* + * Save the dma_base port addr for each interface + */ + for (h = 0; h < MAX_HWIFS; ++h) { + ide_hwif_t *hwif = &hwifs[h]; + unsigned short base, time; + if (hwif->io_base == 0x1f0 && (timings & 0x8000)) { + time = timings & 0xffff; + base = bmiba; + } else if (hwif->io_base == 0x170 && (timings & 0x80000000)) { + time = timings >> 16; + base = bmiba + 8; + } else + continue; + printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+5); + if (check_region(base, 6)) { + printk(" -- ERROR, PORTS ALREADY IN USE"); + } else { + unsigned long *table; + request_region(base, 8, hwif->name); + hwif->dma_base = base; + table = ide_alloc(2 * PRD_ENTRIES * sizeof(long), 4096); + hwif->dmatable = table; + outl((unsigned long) table, base + 4); + hwif->dmaproc = &triton_dmaproc; + } + printk("\n %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n", + hwif->name, time, ((~time>>12)&3)+2, ((~time>>8)&3)+1); + print_triton_drive_flags (0, time & 0xf); + print_triton_drive_flags (1, (time >> 4) & 0xf); + } + +quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); +} + diff --git a/drivers/char/lp.c b/drivers/char/lp.c index d42bafab66ba..89047db2137a 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -33,7 +33,7 @@ /* the BIOS manuals say there can be up to 4 lpt devices * but I have not seen a board where the 4th address is listed - * if you have different hardware change the table below + * if you have different hardware change the table below * please let me know if you have different equipment * if you have more than 3 printers, remember to increase LP_NO */ @@ -41,7 +41,7 @@ struct lp_struct lp_table[] = { { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} }, { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} }, { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} }, -}; +}; #define LP_NO 3 /* Test if printer is ready (and optionally has no error conditions) */ @@ -51,9 +51,9 @@ struct lp_struct lp_table[] = { ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1) #define _LP_CAREFUL_READY(status) \ (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ - (LP_PBUSY|LP_PSELECD|LP_PERRORP) + (LP_PBUSY|LP_PSELECD|LP_PERRORP) -/* +/* * All my debugging code assumes that you debug with only one printer at * a time. RWWH * Debug info moved into stats area, so this is no longer true (Rob Janssen) @@ -72,7 +72,7 @@ static int lp_reset(int minor) static inline int lp_char_polled(char lpchar, int minor) { int status, wait = 0; - unsigned long count = 0; + unsigned long count = 0; struct lp_stats *stats; do { @@ -92,10 +92,10 @@ static inline int lp_char_polled(char lpchar, int minor) /* must wait before taking strobe high, and after taking strobe low, according spec. Some printers need it, others don't. */ while(wait != LP_WAIT(minor)) wait++; - /* control port takes strobe high */ + /* control port takes strobe high */ outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor ))); while(wait) wait--; - /* take strobe low */ + /* take strobe low */ outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor ))); /* update waittime statistics */ if (count > stats->maxwait) { @@ -116,7 +116,7 @@ static inline int lp_char_polled(char lpchar, int minor) static inline int lp_char_interrupt(char lpchar, int minor) { int wait; - unsigned long count = 0; + unsigned long count = 0; unsigned char status; struct lp_stats *stats; @@ -269,7 +269,7 @@ static inline int lp_write_polled(unsigned int minor, const char * buf, int coun current->timeout = jiffies + LP_TIMEOUT_POLLED; schedule(); } else - /* not offline or out of paper. on fire? */ + /* not offline or out of paper. on fire? */ if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor); if(LP_F(minor) & LP_ABORT) @@ -340,7 +340,7 @@ static int lp_open(struct inode * inode, struct file * file) have commandeered O_NONBLOCK, even though it is being used in a non-standard manner. This is strictly a Linux hack, and should most likely only ever be used by the tunelp application. */ - if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) { + if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) { int status = LP_S(minor); if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); @@ -545,7 +545,7 @@ long lp_init(long kmem_start) printk("lp: unable to get major %d\n", LP_MAJOR); #ifdef MODULE return -EIO; -#else +#else return kmem_start; #endif } @@ -577,7 +577,7 @@ long lp_init(long kmem_start) #ifdef MODULE return 0; -#else +#else return kmem_start; #endif } @@ -586,14 +586,19 @@ long lp_init(long kmem_start) #ifdef MODULE void cleanup_module(void) { - int offset; - if(MOD_IN_USE) - printk("lp: busy - remove delayed\n"); - else { - unregister_chrdev(LP_MAJOR,"lp"); - for (offset = 0; offset < LP_NO; offset++) - if (LP_F(offset) & LP_EXIST) - release_region(LP_B(offset),3); + int offset; + + if(MOD_IN_USE) { + printk("lp: busy - remove delayed\n"); + return; + } + unregister_chrdev(LP_MAJOR,"lp"); + for (offset = 0; offset < LP_NO; offset++) { + int base, size; + base = LP_B(offset); + size = (base == 0x3bc)? 3 : 8; + if (LP_F(offset) & LP_EXIST) + release_region(LP_B(offset),size); } } diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 21fc8c73cb83..c9f18a3ce71a 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a8fb24e701a3..0b04ee879db4 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -298,7 +298,8 @@ ewrk3.o: ewrk3.c CONFIG depca.o: depca.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $< -Space.o: ../../include/linux/autoconf.h +Space.o: Space.c ../../include/linux/autoconf.h CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) -c $< net_init.o: ../../include/linux/autoconf.h diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index 82fe4dbe8b6b..5e77af0d0c97 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -341,13 +341,13 @@ void unregister_netdev(struct device *dev) restore_flags(flags); return; } - for (i = 0; i < MAX_ETH_CARDS; ++i) + } + for (i = 0; i < MAX_ETH_CARDS; ++i) + { + if (ethdev_index[i] == dev) { - if (ethdev_index[i] == dev) - { - ethdev_index[i] = NULL; - break; - } + ethdev_index[i] = NULL; + break; } } restore_flags(flags); diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index c42d640bdeca..6f85d9a83d7d 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -1775,7 +1775,7 @@ ppp_xmit(struct sk_buff *skb, struct device *dev) /* If doing demand dial then divert the first frame to pppd. */ if (ppp->flags & SC_IP_DOWN) { - if (ppp->flags & SC_IP_FLUSH == 0) { + if ((ppp->flags & SC_IP_FLUSH) == 0) { if (ppp_us_queue (ppp, proto, p, len)) ppp->flags |= SC_IP_FLUSH; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b384941b41a6..56fa844217f1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -73,7 +73,7 @@ struct pci_dev_info dev_info[] = { BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00), DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), DEVICE( INTEL, INTEL_82437, "82437 Triton"), - DEVICE( INTEL, INTEL_82371, "82471 Triton"), + DEVICE( INTEL, INTEL_82371, "82371 Triton"), DEVICE( INTEL, INTEL_82438, "82438"), DEVICE( INTEL, INTEL_7116, "SAA7116"), DEVICE( INTEL, INTEL_82865, "82865"), @@ -261,7 +261,7 @@ const char *pci_strclass (unsigned int class) case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device"; case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller"; - case PCI_CLASS_STORAGE_IDE: return "IDE controller"; + case PCI_CLASS_STORAGE_IDE: return "IDE interface"; case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; case PCI_CLASS_STORAGE_RAID: return "RAID bus controller"; diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 9eb054afb86e..a503efdf4be5 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -191,7 +191,7 @@ aha152x.o: aha152x.c $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c aic7xxx_asm: aic7xxx_asm.c - $(CC) $(CFLAGS) -o $@ aic7xxx_asm.c + $(HOSTCC) -o $@ aic7xxx_asm.c aic7xxx.c: aic7xxx_seq.h aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 0a63c63c43f9..c735a41fb76d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -107,9 +107,9 @@ Scsi_Cmnd * last_cmnd = NULL; * It is only initialized to !=0 if the scsi code is present */ extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, - off_t offset, int length, int inout); + off_t offset, int length, int inout); extern int dispatch_scsi_info(int ino, char *buffer, char **start, - off_t offset, int length, int inout); + off_t offset, int length, int inout); /* @@ -202,19 +202,19 @@ static struct dev_info device_list[] = {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ {"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes - * SCSI code to reset bus.*/ + * for aha152x controller, which causes + * SCSI code to reset bus.*/ {"SEAGATE", "ST296","921", BLIST_NOLUN}, /* Responds to all lun */ {"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN}, {"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN}, {"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN}, {"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ + * for seagate controller, which causes + * SCSI code to reset bus.*/ {"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ + * for seagate controller, which causes + * SCSI code to reset bus.*/ {"QUANTUM","LPS525S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ {"QUANTUM","PD1225S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ {"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ @@ -407,12 +407,12 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, /* * We need the for so our continue, etc. work fine. - * We put this in a variable so that we can override - * it during the scan if we detect a device *KNOWN* - * to have multiple logical units. + * We put this in a variable so that we can override + * it during the scan if we detect a device *KNOWN* + * to have multiple logical units. */ - max_dev_lun = (max_scsi_luns < shpnt->max_lun ? - max_scsi_luns : shpnt->max_lun); + max_dev_lun = (max_scsi_luns < shpnt->max_lun ? + max_scsi_luns : shpnt->max_lun); for (lun = 0; lun < max_dev_lun; ++lun) { @@ -555,8 +555,8 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, SDpnt->manufacturer = SCSI_MAN_NEC; } else if (!strncmp(scsi_result+8,"TOSHIBA",7)) SDpnt->manufacturer = SCSI_MAN_TOSHIBA; - else if (!strncmp(scsi_result+8,"SONY",4)) - SDpnt->manufacturer = SCSI_MAN_SONY; + else if (!strncmp(scsi_result+8,"SONY",4)) + SDpnt->manufacturer = SCSI_MAN_SONY; else SDpnt->manufacturer = SCSI_MAN_UNKNOWN; @@ -569,7 +569,7 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, SDpnt->changed = 0; SDpnt->access_count = 0; SDpnt->busy = 0; - SDpnt->has_cmdblocks = 0; + SDpnt->has_cmdblocks = 0; /* * Currently, all sequential devices are assumed to be * tapes, all random devices disk, with the appropriate @@ -599,7 +599,7 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, #endif } - SDpnt->single_lun = 0; + SDpnt->single_lun = 0; SDpnt->soft_reset = (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2); SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; @@ -640,10 +640,10 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, SDpnt->disconnect = 0; - /* - * Get any flags for this device. - */ - bflags = get_device_flags(scsi_result); + /* + * Get any flags for this device. + */ + bflags = get_device_flags(scsi_result); /* @@ -654,16 +654,16 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, * change it here if it turns out that it isn't * a TEXEL drive. */ - if( (bflags & BLIST_BORKEN) == 0 ) - { + if( (bflags & BLIST_BORKEN) == 0 ) + { SDpnt->borken = 0; - } + } /* These devices need this "key" to unlock the * devices so we can use it */ - if( (bflags & BLIST_KEY) != 0 ) { + if( (bflags & BLIST_KEY) != 0 ) { printk("Unlocked floptical drive.\n"); SDpnt->lockable = 0; scsi_cmd[0] = MODE_SENSE; @@ -706,28 +706,28 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, */ if(bflags & BLIST_NOLUN) break; - /* - * If we want to only allow I/O to one of the luns - * attached to this device at a time, then we set this - * flag. - */ - if(bflags & BLIST_SINGLELUN) - { - SDpnt->single_lun = 1; - } - - /* - * If this device is known to support multiple units, override - * the other settings, and scan all of them. - */ - if(bflags & BLIST_FORCELUN) - { - /* - * We probably want to make this a variable, but this - * will do for now. - */ - max_dev_lun = 8; - } + /* + * If we want to only allow I/O to one of the luns + * attached to this device at a time, then we set this + * flag. + */ + if(bflags & BLIST_SINGLELUN) + { + SDpnt->single_lun = 1; + } + + /* + * If this device is known to support multiple units, override + * the other settings, and scan all of them. + */ + if(bflags & BLIST_FORCELUN) + { + /* + * We probably want to make this a variable, but this + * will do for now. + */ + max_dev_lun = 8; + } /* Old drives like the MAXTOR XT-3280 say vers=0 */ @@ -741,10 +741,10 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, } } /* if result == DID_OK ends */ - /* - * This might screw us up with multi-lun devices, but the user can - * scan for them too. - */ + /* + * This might screw us up with multi-lun devices, but the user can + * scan for them too. + */ if(hardcoded == 1) goto leave; } /* for lun ends */ @@ -850,35 +850,35 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) SCpnt = device->host->host_queue; if (!device->single_lun) { - while(SCpnt){ - if(SCpnt->target == device->id && - SCpnt->lun == device->lun) { - if(SCpnt->request.dev < 0) break; - } - SCpnt = SCpnt->next; - } + while(SCpnt){ + if(SCpnt->target == device->id && + SCpnt->lun == device->lun) { + if(SCpnt->request.dev < 0) break; + } + SCpnt = SCpnt->next; + } } else { - while(SCpnt){ - if(SCpnt->target == device->id) { - if (SCpnt->lun == device->lun) { - if(found == NULL - && SCpnt->request.dev < 0) - { - found=SCpnt; - } - } - if(SCpnt->request.dev >= 0) { - /* - * I think that we should really limit things to one - * outstanding command per device - this is what tends to trip - * up buggy firmware. - */ - return NULL; - } - } - SCpnt = SCpnt->next; - } - SCpnt = found; + while(SCpnt){ + if(SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + if(found == NULL + && SCpnt->request.dev < 0) + { + found=SCpnt; + } + } + if(SCpnt->request.dev >= 0) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends to trip + * up buggy firmware. + */ + return NULL; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; } if (!SCpnt) return NULL; @@ -975,41 +975,41 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, if (intr_count && SCSI_BLOCK(host)) return NULL; while (1==1){ - SCpnt = device->host->host_queue; - if (!device->single_lun) { - while(SCpnt){ - if(SCpnt->target == device->id && - SCpnt->lun == device->lun) { - SCwait = SCpnt; - if(SCpnt->request.dev < 0) break; - } - SCpnt = SCpnt->next; - } - } else { - while(SCpnt){ - if(SCpnt->target == device->id) { - if (SCpnt->lun == device->lun) { - SCwait = SCpnt; - if(found == NULL - && SCpnt->request.dev < 0) - { - found=SCpnt; - } - } - if(SCpnt->request.dev >= 0) { - /* - * I think that we should really limit things to one - * outstanding command per device - this is what tends to trip - * up buggy firmware. - */ - found = NULL; - break; - } - } - SCpnt = SCpnt->next; - } - SCpnt = found; - } + SCpnt = device->host->host_queue; + if (!device->single_lun) { + while(SCpnt){ + if(SCpnt->target == device->id && + SCpnt->lun == device->lun) { + SCwait = SCpnt; + if(SCpnt->request.dev < 0) break; + } + SCpnt = SCpnt->next; + } + } else { + while(SCpnt){ + if(SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + SCwait = SCpnt; + if(found == NULL + && SCpnt->request.dev < 0) + { + found=SCpnt; + } + } + if(SCpnt->request.dev >= 0) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends to trip + * up buggy firmware. + */ + found = NULL; + break; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; + } save_flags(flags); cli(); @@ -2198,7 +2198,8 @@ void * scsi_init_malloc(unsigned int size, int priority) scsi_init_memory_start += size; } } - memset((void *) retval, 0, size); + if (retval) + memset((void *) retval, 0, size); return (void *) retval; } @@ -2341,19 +2342,22 @@ unsigned long scsi_dev_init (unsigned long memory_start, unsigned long memory_en dma_sectors = (dma_sectors + 15) & 0xfff0; dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */ + + if (dma_sectors) + { + dma_malloc_freelist = (unsigned char *) + scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC); + memset(dma_malloc_freelist, 0, dma_sectors >> 3); + + dma_malloc_pages = (unsigned char **) + scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC); + memset(dma_malloc_pages, 0, dma_sectors >> 1); + + for(i=0; i< dma_sectors >> 3; i++) + dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); - dma_malloc_freelist = (unsigned char *) - scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC); - memset(dma_malloc_freelist, 0, dma_sectors >> 3); - - dma_malloc_pages = (unsigned char **) - scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC); - memset(dma_malloc_pages, 0, dma_sectors >> 1); - - for(i=0; i< dma_sectors >> 3; i++) - dma_malloc_pages[i] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); - + } /* OK, now we finish the initialization by doing spin-up, read * capacity, etc, etc */ @@ -2440,40 +2444,40 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, HBA_ptr = scsi_hostlist; if(inout == 0) { - size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none"); - len += size; - pos = begin + len; - while (HBA_ptr) { + size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none"); + len += size; + pos = begin + len; + while (HBA_ptr) { #if 0 - size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname); - len += size; - pos = begin + len; + size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname); + len += size; + pos = begin + len; #endif - scd = scsi_devices; - while (scd) { - if (scd->host == HBA_ptr) { - proc_print_scsidevice(scd, buffer, &size, len); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - scd = scd->next; - } + scd = scsi_devices; + while (scd) { + if (scd->host == HBA_ptr) { + proc_print_scsidevice(scd, buffer, &size, len); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + scd = scd->next; + } HBA_ptr = HBA_ptr->next; - } - + } + stop_output: - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len = length; /* Ending slop */ - return (len); + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Start slop */ + if(len>length) + len = length; /* Ending slop */ + return (len); } if(!buffer || length < 25 || strncmp("scsi", buffer, 4)) @@ -2623,15 +2627,18 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) */ if( new_dma_sectors < dma_sectors ) new_dma_sectors = dma_sectors; - - 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); - + + if (new_dma_sectors) + { + 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); + } + /* * If we need more buffers, expand the list. */ @@ -2646,13 +2653,19 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) */ save_flags(flags); cli(); - memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3); - scsi_init_free(dma_malloc_freelist, dma_sectors>>3); + if (dma_malloc_freelist) + { + 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); - + if (dma_malloc_pages) + { + 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; @@ -2739,7 +2752,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd)); sdpnt->host->host_queue = SCpnt; if (SCpnt) SCpnt->prev = NULL; - sdpnt->has_cmdblocks = 0; + sdpnt->has_cmdblocks = 0; } /* Next free up the Scsi_Device structures for this host */ @@ -2904,7 +2917,7 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); } } - SDpnt->has_cmdblocks = 0; + SDpnt->has_cmdblocks = 0; } } /* diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c index fcc61dcfb022..1f4c33bcd9e5 100644 --- a/drivers/scsi/sd_ioctl.c +++ b/drivers/scsi/sd_ioctl.c @@ -30,7 +30,7 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne struct hd_geometry *loc = (struct hd_geometry *) arg; switch (cmd) { - case HDIO_REQ: /* Return BIOS disk parameters */ + case HDIO_GETGEO: /* Return BIOS disk parameters */ if (!loc) return -EINVAL; error = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); if (error) diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 9a6a355e02d1..5e4b3ed27178 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -252,7 +252,7 @@ ad_leave_MCE (ad1848_info * devc) prev = INB (io_Index_Addr (devc)); OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */ - if (prev & 0x40 == 0) /* Not in MCE mode */ + if ((prev & 0x40) == 0) /* Not in MCE mode */ { RESTORE_INTR (flags); return; diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index 1d1b8599d797..aa85c2a2c8ff 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -479,7 +479,7 @@ sound_ioctl_sw (int dev, struct fileinfo *file, { DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */ + if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ if ((dev & 0x0f) != SND_DEV_CTL) { int dtype = dev & 0x0f; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b7326613a86b..01db8a604a30 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -172,7 +172,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex, struct inode * interpreter_inode, unsigned int *interp_load_addr) { - struct file * file; + struct file * file; struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; unsigned int len; @@ -258,7 +258,7 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex, SYS(close)(elf_exec_fileno); if(error < 0 && error > -1024) { - kfree(elf_phdata); + kfree(elf_phdata); return 0xffffffff; } @@ -386,7 +386,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum, 1); if (retval < 0) { - kfree (elf_phdata); + kfree (elf_phdata); MOD_DEC_USE_COUNT; return retval; } @@ -399,7 +399,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); if (elf_exec_fileno < 0) { - kfree (elf_phdata); + kfree (elf_phdata); MOD_DEC_USE_COUNT; return elf_exec_fileno; } @@ -458,7 +458,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* Some simple consistency checks for the interpreter */ if(elf_interpreter){ - interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; if(retval < 0) { kfree(elf_interpreter); kfree(elf_phdata); @@ -500,10 +500,10 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) } } if (!bprm->p) { - if(elf_interpreter) { + if(elf_interpreter) { kfree(elf_interpreter); } - kfree (elf_phdata); + kfree (elf_phdata); MOD_DEC_USE_COUNT; return -E2BIG; } @@ -662,6 +662,15 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) MAP_FIXED | MAP_PRIVATE, 0); } + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + regs->edx = 0; + start_thread(regs, elf_entry, bprm->p); if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); @@ -674,7 +683,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) static int load_elf_library(int fd){ - struct file * file; + struct file * file; struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; struct inode * inode; @@ -751,7 +760,7 @@ load_elf_library(int fd){ SYS(close)(fd); if (error != (elf_phdata->p_vaddr & 0xfffff000)) { - kfree(elf_phdata); + kfree(elf_phdata); MOD_DEC_USE_COUNT; return error; } diff --git a/fs/buffer.c b/fs/buffer.c index 10937274aa4e..a175baaabdeb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1171,6 +1171,7 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in return address; } +#if 0 /* * bwrite_page writes a page out to the buffer cache and/or the physical device. * It's used for mmap writes (the same way bread_page() is used for mmap reads). @@ -1192,9 +1193,10 @@ void bwrite_page(unsigned long address, dev_t dev, int b[], int size) mark_buffer_dirty(bh[i], 0); brelse(bh[i]); } else - memset((void *) address, 0, size); + memset((void *) address, 0, size); /* ???!?!! */ } } +#endif /* * Try to increase the number of buffers available: the size argument diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index aef8fcc2b4e3..bcad000df701 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -105,8 +105,9 @@ static int msdos_find(struct inode *dir,const char *name,int len, char msdos_name[MSDOS_NAME]; int res; - if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, - msdos_name,1)) < 0) return res; + res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, msdos_name,1); + if (res < 0) + return -ENOENT; return msdos_scan(dir,msdos_name,bh,de,ino); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2982179c0679..258637cf2a11 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -143,6 +143,7 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data, if (data->addr.sin_addr.s_addr == INADDR_ANY) { /* No address passed */ if (((struct sockaddr_in *)(&server->toaddr))->sin_addr.s_addr == INADDR_ANY) { printk("NFS: Error passed unconnected socket and no address\n") ; + MOD_DEC_USE_COUNT; return NULL ; } else { /* Need access to socket internals JSP */ diff --git a/fs/proc/net.c b/fs/proc/net.c index 0284098abeef..5e0eae3bc32f 100644 --- a/fs/proc/net.c +++ b/fs/proc/net.c @@ -36,49 +36,6 @@ #include #include -static struct file_operations proc_netdir_operations = { - NULL, /* lseek - default */ - NULL, /* read - bad */ - NULL, /* write - bad */ - proc_readdir, /* readdir */ - NULL, /* select - default */ - NULL, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* can't fsync */ -}; - -/* - * proc directories can do almost nothing.. - */ -static struct inode_operations proc_netdir_inode_operations = { - &proc_netdir_operations, /* default net directory file-ops */ - NULL, /* create */ - proc_lookup, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ -}; - -struct proc_dir_entry proc_net = { - PROC_NET, 3, "net", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_netdir_inode_operations, - NULL, NULL, - NULL, - NULL, NULL -}; - #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static int proc_readnet(struct inode * inode, struct file * file, diff --git a/fs/proc/root.c b/fs/proc/root.c index 7b457709b390..e51f222df45a 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -22,6 +22,53 @@ static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t); static int proc_root_lookup(struct inode *,const char *,int,struct inode **); +/* + * These are the generic /proc directory operations. They + * use the in-memory "struct proc_dir_entry" tree to parse + * the /proc directory. + * + * NOTE! The /proc/scsi directory currently does not correctly + * build up the proc_dir_entry tree, and will show up empty. + */ +static struct file_operations proc_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +static struct inode_operations proc_dir_inode_operations = { + &proc_dir_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* + * The root /proc directory is special, as it has the + * directories. Thus we don't use the generic + * directory handling functions for that.. + */ static struct file_operations proc_root_operations = { NULL, /* lseek - default */ NULL, /* read - bad */ @@ -36,7 +83,7 @@ static struct file_operations proc_root_operations = { }; /* - * proc directories can do almost nothing.. + * proc root can do almost nothing.. */ static struct inode_operations proc_root_inode_operations = { &proc_root_operations, /* default base directory file-ops */ @@ -61,13 +108,31 @@ static struct inode_operations proc_root_inode_operations = { */ struct proc_dir_entry proc_root = { PROC_ROOT_INO, 5, "/proc", - S_IFDIR | S_IRUGO | S_IXUGO, 3, 0, 0, + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, 0, &proc_root_inode_operations, NULL, NULL, NULL, &proc_root, NULL }; +struct proc_dir_entry proc_net = { + PROC_NET, 3, "net", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_dir_inode_operations, + NULL, NULL, + NULL, + NULL, NULL +}; + +struct proc_dir_entry proc_scsi = { + PROC_SCSI, 4, "scsi", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_dir_inode_operations, + NULL, NULL, + NULL, + &proc_root, NULL +}; + int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) { dp->next = dir->subdir; diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c index 608f7c06e99c..8f3d0f529f7d 100644 --- a/fs/proc/scsi.c +++ b/fs/proc/scsi.c @@ -34,8 +34,6 @@ static int proc_readscsi(struct inode * inode, struct file * file, char * buf, int count); static int proc_writescsi(struct inode * inode, struct file * file, const char * buf, int count); -static int proc_readscsidir(struct inode *, struct file *, - void *, filldir_t filldir); static int proc_lookupscsi(struct inode *,const char *,int,struct inode **); static int proc_scsilseek(struct inode *, struct file *, off_t, int); @@ -50,7 +48,7 @@ static struct file_operations proc_scsi_operations = { proc_scsilseek, /* lseek */ proc_readscsi, /* read */ proc_writescsi, /* write */ - proc_readscsidir, /* readdir */ + NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ @@ -80,15 +78,6 @@ struct inode_operations proc_scsi_inode_operations = { NULL /* permission */ }; -struct proc_dir_entry proc_scsi = { - PROC_SCSI, 4, "scsi", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_scsi_inode_operations, - NULL, NULL, - NULL, - &proc_root, NULL -}; - struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3]; struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4]; @@ -177,36 +166,6 @@ static int proc_lookupscsi(struct inode * dir, const char * name, int len, return(-ENOENT); } -static int proc_readscsidir(struct inode * inode, struct file * filp, - void * dirent, filldir_t filldir) -{ - struct proc_dir_entry * de; - uint index, num; - - num = 0; - - if (!inode || !S_ISDIR(inode->i_mode)) - return(-EBADF); - - index = count_dir_entries(inode->i_ino, &num); - - while (((unsigned) filp->f_pos + index) < index + num) { - if (dispatch_scsi_info_ptr) { - if (inode->i_ino <= PROC_SCSI_SCSI) - de = scsi_dir + filp->f_pos; - else - de = scsi_hba_dir + filp->f_pos + index; - } - else { - de = scsi_dir2 + filp->f_pos; - } - if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0) - break; - filp->f_pos++; - } - return(0); -} - int get_not_present_info(char *buffer, char **start, off_t offset, int length) { int len, pos, begin; diff --git a/fs/smbfs/README b/fs/smbfs/README index 00707f6f875b..937262dacfd4 100644 --- a/fs/smbfs/README +++ b/fs/smbfs/README @@ -1,7 +1,7 @@ smbfs is a filesystem which understands the SMB protocol. This is the protocol Windows for Workgroups, Windows NT or Lan Manager use to talk -to each other. It was inspired by samba, the program by Andrew -Tridgell that turns any unix site into a file server for DOS or +to each other. smbfs was inspired by samba, the program written by +Andrew Tridgell that turns any unix host into a file server for DOS or Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting program suite and lots of more information on SMB and NetBIOS over TCP/IP. There you also find explanation for conceps like diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 5be44babbd08..9802e3958aa4 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -159,10 +159,11 @@ static int c_last_returned_index; static struct smb_dirent* c_entry = NULL; static int -smb_readdir1(struct inode *inode, const struct file *filp, - struct smb_dirent *ret,ino_t *ino) +smb_readdir(struct inode *inode, struct file *filp, + void *dirent, filldir_t filldir) { int result, i = 0; + int index = 0; struct smb_dirent *entry = NULL; struct smb_server *server = SMB_SERVER(inode); @@ -198,6 +199,7 @@ smb_readdir1(struct inode *inode, const struct file *filp, if (filp->f_pos == c_entry[i].f_pos) { entry = &c_entry[i]; c_last_returned_index = i; + index = i; break; } } @@ -222,6 +224,7 @@ smb_readdir1(struct inode *inode, const struct file *filp, c_size = result; entry = c_entry; c_last_returned_index = 0; + index = 0; for (i = 0; i < c_size; i++) { switch (server->case_handling) @@ -236,22 +239,26 @@ smb_readdir1(struct inode *inode, const struct file *filp, } } } - - if (entry) { + + if (entry == NULL) { + /* Nothing found, even from a smb call */ + return 0; + } + + while (index < c_size) { /* We found it. For getwd(), we have to return the correct inode in d_ino if the inode is currently in use. Otherwise the inode number does not - matter. */ + matter. (You can argue a lot about this..) */ - int path_len; + int path_len; + int len; struct smb_inode_info *ino_info; char complete_path[SMB_MAXPATHLEN]; - - - i = strlen(entry->path); - if ((result = get_pname_static(inode, entry->path, i, + len = strlen(entry->path); + if ((result = get_pname_static(inode, entry->path, len, complete_path, &path_len)) < 0) return result; @@ -268,30 +275,20 @@ smb_readdir1(struct inode *inode, const struct file *filp, DDPRINTK("smb_readdir: entry->path = %s\n", entry->path); DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos); - *ino = (ino_t)ino_info; /* use the pointer as the - inode - dangerous if we have - 64 bit pointers! FIXME */ - - *ret = *entry; - return 1; - } - - return 0; -} - -static int -smb_readdir(struct inode *inode, struct file *filp, - void *dirent, filldir_t filldir) -{ - struct smb_dirent d; - ino_t ino; + if (filldir(dirent, entry->path, len, + entry->f_pos, (ino_t)ino_info) < 0) { + break; + } - while (smb_readdir1(inode,filp,&d,&ino) == 1) { - if (filldir(dirent,d.path,strlen(d.path)+1, - filp->f_pos,ino) < 0) { - return 0; - } - filp->f_pos++; + if ( (inode->i_ino != c_ino) + || (entry->f_pos != filp->f_pos)) { + /* Someone has destroyed the cache while we slept + in filldir */ + break; + } + filp->f_pos += 1; + index += 1; + entry += 1; } return 0; } @@ -716,13 +713,9 @@ smb_lookup(struct inode *dir, const char *__name, int len, found_in_cache = 0; if (dir->i_ino == c_ino) { - int first = c_last_returned_index - 1; + int first = c_last_returned_index; int i; - if (first < 0) { - first = c_size - 1; - } - i = first; do { DDPRINTK("smb_lookup: trying index: %d, name: %s\n", @@ -735,7 +728,8 @@ smb_lookup(struct inode *dir, const char *__name, int len, break; } i = (i + 1) % c_size; - + DDPRINTK("smb_lookup: index %d, name %s failed\n", + i, c_entry[i].path); } while (i != first); } @@ -920,10 +914,19 @@ smb_rename(struct inode *old_dir, const char *old_name, int old_len, res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len, new_path, new_len); + if (res == -EEXIST) { + int res1; + res1 = smb_proc_unlink(SMB_SERVER(old_dir), new_path, new_len); + if (res1 == 0) { + res = smb_proc_mv(SMB_SERVER(old_dir), old_path, + old_len, new_path, new_len); + } + } + if (res == 0) { smb_invalid_dir_cache(old_dir->i_ino); smb_invalid_dir_cache(new_dir->i_ino); - } + } finished: iput(old_dir); diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index c170965d6116..bcc543613ca2 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -102,10 +102,25 @@ smb_file_read(struct inode *inode, struct file *file, char *buf, int count) /* First read in as much as possible for each bufsize. */ while (already_read < count) { - to_read = min(bufsize, count - already_read); + result = 0; + to_read = 0; + + if ((SMB_SERVER(inode)->blkmode & 1) != 0) { + to_read = min(65535, count - already_read); + DPRINTK("smb_file_read: Raw %d bytes\n", to_read); + result = smb_proc_read_raw(SMB_SERVER(inode), + SMB_FINFO(inode), + pos, to_read, buf); + DPRINTK("smb_file_read: returned %d\n", result); + } + + if (result <= 0) { + to_read = min(bufsize, count - already_read); + result = smb_proc_read(SMB_SERVER(inode), + SMB_FINFO(inode), + pos, to_read, buf, 1); + } - result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode), - pos, to_read, buf, 1); if (result < 0) return result; pos += result; @@ -162,12 +177,30 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf, int coun already_written = 0; + DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n", + SMB_SERVER(inode)->blkmode, + SMB_SERVER(inode)->blkmode & 2); + while (already_written < count) { - to_write = min(bufsize, count - already_written); - - result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode), - pos, to_write, buf); + result = 0; + to_write = 0; + + if ((SMB_SERVER(inode)->blkmode & 2) != 0) { + to_write = min(65535, count - already_written); + DPRINTK("smb_file_write: Raw %d bytes\n", to_write); + result = smb_proc_write_raw(SMB_SERVER(inode), + SMB_FINFO(inode), + pos, to_write, buf); + DPRINTK("smb_file_write: returned %d\n", result); + } + + if (result <= 0) { + to_write = min(bufsize, count - already_written); + result = smb_proc_write(SMB_SERVER(inode), + SMB_FINFO(inode), + pos, to_write, buf); + } if (result < 0) return result; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 90e6f696863a..2352f677c7e1 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -345,13 +345,18 @@ smb_notify_change(struct inode *inode, struct iattr *attr) if ((error = inode_change_ok(inode, attr)) < 0) return error; - if (!S_ISREG(inode->i_mode)) - return -EPERM; + if (((attr->ia_valid & ATTR_UID) && + (attr->ia_uid != SMB_SERVER(inode)->m.uid))) + return -EPERM; - if ((attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) != 0) { + if (((attr->ia_valid & ATTR_GID) && + (attr->ia_uid != SMB_SERVER(inode)->m.gid))) return -EPERM; - } - + + if (((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) + return -EPERM; + if ((attr->ia_valid & ATTR_SIZE) != 0) { if ((error = smb_make_open(inode, O_WRONLY)) < 0) diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 708bd3784ce4..a45423009ea3 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -69,18 +69,7 @@ smb_decode_word(byte *p, word *data) return &p[2]; } -static byte * -smb_decode_dword(byte *p, dword *data) -{ -#if (ARCH == i386) - *data = *((dword *)p); -#else - *data = (dword)p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; -#endif - return &p[4]; -} - -static byte * +byte * smb_encode_smb_length(byte *p, dword len) { p[0] = p[1] = 0; @@ -320,6 +309,9 @@ smb_errno(int errcls, int error) case ERRlock: return EDEADLOCK; case ERRfilexists: return EEXIST; case 87: return 0; /* Unknown error!! */ + /* This next error seems to occur on an mv when + * the destination exists */ + case 183: return EEXIST; default: return EIO; } else if (errcls == ERRSRV) @@ -655,6 +647,33 @@ smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, return data_len; } +/* count must be <= 65535. No error number is returned. A result of 0 + indicates an error, which has to be investigated by a normal read + call. */ +int +smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, char *data) +{ + char *buf = server->packet; + int result; + + if ((count <= 0) || (count > 65535)) { + return -EINVAL; + } + + smb_setup_header_exclusive(server, SMBreadbraw, 8, 0); + + WSET(buf, smb_vwv0, finfo->fileid); + DSET(buf, smb_vwv1, offset); + WSET(buf, smb_vwv3, count); + WSET(buf, smb_vwv4, 0); + DSET(buf, smb_vwv5, 0); + + result = smb_request_read_raw(server, data, count); + smb_unlock_server(server); + return result; +} + int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, off_t offset, int count, const char *data) @@ -682,6 +701,61 @@ smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, return res; } +/* count must be <= 65535 */ +int +smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, const char *data) +{ + char *buf = server->packet; + int result; + + if ((count <= 0) || (count > 65535)) { + return -EINVAL; + } + + smb_setup_header_exclusive(server, SMBwritebraw, 11, 0); + + WSET(buf, smb_vwv0, finfo->fileid); + WSET(buf, smb_vwv1, count); + WSET(buf, smb_vwv2, 0); /* reserved */ + DSET(buf, smb_vwv3, offset); + DSET(buf, smb_vwv5, 0); /* timeout */ + WSET(buf, smb_vwv7, 1); /* send final result response */ + DSET(buf, smb_vwv8, 0); /* reserved */ + WSET(buf, smb_vwv10, 0); /* no data in this buf */ + WSET(buf, smb_vwv11, 0); /* no data in this buf */ + + result = smb_request_ok(server, SMBwritebraw, 1, 0); + + DPRINTK("smb_proc_write_raw: first request returned %d\n", result); + + if (result < 0) { + smb_unlock_server(server); + return result; + } + + result = smb_request_write_raw(server, data, count); + + DPRINTK("smb_proc_write_raw: raw request returned %d\n", result); + + if (result > 0) { + /* We have to do the checks of smb_request_ok here as well */ + if (smb_valid_packet(server->packet) != 0) { + DPRINTK("not a valid packet!\n"); + result = -EIO; + } else if (server->rcls != 0) { + result = -smb_errno(server->rcls, server->err); + } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) { + DPRINTK("smb_verify failed\n"); + result = -EIO; + } + } + + smb_unlock_server(server); + return result; +} + + /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */ static int @@ -1642,12 +1716,14 @@ smb_proc_reconnect(struct smb_server *server) server->m.password); DPRINTK("smb_proc_connect: usernam = %s\n", server->m.username); + DPRINTK("smb_proc_connect: blkmode = %d\n", + WVAL(server->packet, smb_vwv5)); - p = smb_decode_word(p, &(server->maxxmt)); - p = smb_decode_word(p, &(server->maxmux)); - p = smb_decode_word(p, &(server->maxvcs)); - p = smb_decode_word(p, &(server->blkmode)); - p = smb_decode_dword(p, &(server->sesskey)); + server->maxxmt = WVAL(server->packet, smb_vwv2); + server->maxmux = WVAL(server->packet, smb_vwv3); + server->maxvcs = WVAL(server->packet, smb_vwv4); + server->blkmode= WVAL(server->packet, smb_vwv5); + server->sesskey= DVAL(server->packet, smb_vwv6); smb_setup_header(server, SMBsesssetupX, 10, 2 + userlen + passlen); @@ -1674,6 +1750,15 @@ smb_proc_reconnect(struct smb_server *server) } smb_decode_word(server->packet+32, &(server->server_uid)); } + else + + { + server->maxxmt = 0; + server->maxmux = 0; + server->maxvcs = 0; + server->blkmode = 0; + server->sesskey = 0; + } /* Fine! We have a connection, send a tcon message. */ diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index fbea9cfb9f65..20a7b8105bc2 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -175,27 +175,36 @@ smb_dont_catch_keepalive(struct smb_server *server) } /* - * smb_receive - * fs points to the correct segment, server != NULL, sock!=NULL + * smb_receive_raw + * fs points to the correct segment, sock != NULL, target != NULL + * The smb header is only stored if want_header != 0. */ static int -smb_receive(struct smb_server *server, struct socket *sock) +smb_receive_raw(struct socket *sock, unsigned char *target, + int max_raw_length, int want_header) { int len, result; + int already_read; unsigned char peek_buf[4]; + unsigned short fs; /* We fool the kernel to believe + we call from user space. */ + re_recv: + fs = get_fs(); + set_fs(get_ds()); result = sock->ops->recvfrom(sock, (void *)peek_buf, 4, 0, - MSG_PEEK, NULL, NULL); + 0, NULL, NULL); + set_fs(fs); if (result < 0) { - DPRINTK("smb_receive: recv error = %d\n", -result); + DPRINTK("smb_receive_raw: recv error = %d\n", -result); return result; } - if (result == 0) { - DPRINTK("smb_receive: got 0 bytes\n"); + if (result < 4) { + DPRINTK("smb_receive_raw: got less than 4 bytes\n"); return -EIO; } @@ -206,51 +215,72 @@ smb_receive(struct smb_server *server, struct socket *sock) break; case 0x85: - DPRINTK("smb_receive: Got SESSION KEEP ALIVE\n"); - sock->ops->recvfrom(sock, (void *)peek_buf, 4, 1, - 0, NULL, NULL); + DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n"); goto re_recv; default: - printk("smb_receive: Invalid packet\n"); + printk("smb_receive_raw: Invalid packet\n"); return -EIO; } - /* Length not including first four bytes. */ - len = smb_len(peek_buf) + 4; - if (len > server->max_xmit) { - printk("smb_receive: Received length (%d) > max_xmit (%d)!\n", - len, server->max_xmit); + /* The length in the RFC NB header is the raw data length */ + len = smb_len(peek_buf); + if (len > max_raw_length) { + printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n", + len, max_raw_length); return -EIO; } - else - { - int already_read = 0; - while (already_read < len) { + if (want_header != 0) { + memcpy_tofs(target, peek_buf, 4); + target += 4; + } + + already_read = 0; + + while (already_read < len) { - result = sock->ops-> - recvfrom(sock, - (void *)(server->packet+already_read), - len - already_read, 0, 0, - NULL, NULL); + result = sock->ops-> + recvfrom(sock, + (void *)(target+already_read), + len - already_read, 0, 0, + NULL, NULL); - if (result < 0) { - printk("SMB: notice message: error = %d\n", - -result); - return result; - } - - already_read += result; + if (result < 0) { + printk("smb_receive_raw: recvfrom error = %d\n", + -result); + return result; } - result = already_read; + + already_read += result; + } + return already_read; +} + +/* + * smb_receive + * fs points to the correct segment, server != NULL, sock!=NULL + */ +static int +smb_receive(struct smb_server *server, struct socket *sock) +{ + int result; + + result = smb_receive_raw(sock, server->packet, + server->max_xmit - 4, /* max_xmit in server + includes NB header */ + 1); /* We want the header */ + + if (result < 0) { + printk("smb_receive: receive error: %d\n", result); + return result; } server->rcls = *((unsigned char *)(server->packet+9)); server->err = *((unsigned short *)(server->packet+11)); if (server->rcls != 0) { - DPRINTK("smb_response: rcls=%d, err=%d\n", + DPRINTK("smb_receive: rcls=%d, err=%d\n", server->rcls, server->err); } @@ -447,12 +477,6 @@ smb_request(struct smb_server *server) if (server->state != CONN_VALID) return -EIO; -#if 0 - while (server->lock) - sleep_on(&server->wait); - server->lock = 1; -#endif - if ((result = smb_dont_catch_keepalive(server)) != 0) { server->state = CONN_INVALID; smb_invalidate_all_inodes(server); @@ -486,11 +510,6 @@ smb_request(struct smb_server *server) result = result2; } -#if 0 - server->lock = 0; - wake_up(&server->wait); -#endif - if (result < 0) { server->state = CONN_INVALID; smb_invalidate_all_inodes(server); @@ -526,12 +545,6 @@ smb_trans2_request(struct smb_server *server, if (server->state != CONN_VALID) return -EIO; -#if 0 - while (server->lock) - sleep_on(&server->wait); - server->lock = 1; -#endif - if ((result = smb_dont_catch_keepalive(server)) != 0) { server->state = CONN_INVALID; smb_invalidate_all_inodes(server); @@ -540,13 +553,13 @@ smb_trans2_request(struct smb_server *server, len = smb_len(buffer) + 4; - DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); - old_mask = current->blocked; current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); fs = get_fs(); set_fs(get_ds()); + DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); + result = sock->ops->send(sock, (void *)buffer, len, 0, 0); if (result < 0) { printk("smb_trans2_request: send error = %d\n", result); @@ -567,11 +580,6 @@ smb_trans2_request(struct smb_server *server, result = result2; } -#if 0 - server->lock = 0; - wake_up(&server->wait); -#endif - if (result < 0) { server->state = CONN_INVALID; smb_invalidate_all_inodes(server); @@ -582,6 +590,156 @@ smb_trans2_request(struct smb_server *server, return result; } +/* target must be in user space */ +int +smb_request_read_raw(struct smb_server *server, + unsigned char *target, int max_len) +{ + unsigned long old_mask; + int len, result, result2; + unsigned short fs; /* We fool the kernel to believe + we call from user space. */ + + struct socket *sock = server_sock(server); + unsigned char *buffer = (server == NULL) ? NULL : server->packet; + + if ((sock == NULL) || (buffer == NULL)) { + printk("smb_request_read_raw: Bad server!\n"); + return -EBADF; + } + + if (server->state != CONN_VALID) + return -EIO; + + if ((result = smb_dont_catch_keepalive(server)) != 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + return result; + } + + len = smb_len(buffer) + 4; + + old_mask = current->blocked; + current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + fs = get_fs(); + set_fs(get_ds()); + + DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n", + len, buffer[8]); + DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n", + (unsigned int)target, max_len); + DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n", + (unsigned int)buffer, (unsigned int)sock); + + result = sock->ops->send(sock, (void *)buffer, len, 0, 0); + + DPRINTK("smb_request_read_raw: send returned %d\n", result); + + set_fs(fs); /* We recv into user space */ + + if (result < 0) { + printk("smb_request_read_raw: send error = %d\n", result); + } + else { + result = smb_receive_raw(sock, target, max_len, 0); + } + + /* read/write errors are handled by errno */ + current->signal &= ~_S(SIGPIPE); + current->blocked = old_mask; + + if ((result2 = smb_catch_keepalive(server)) < 0) { + result = result2; + } + + if (result < 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + } + + DPRINTK("smb_request_read_raw: result = %d\n", result); + + return result; +} + +/* Source must be in user space. smb_request_write_raw assumes that + * the request SMBwriteBraw has been completed successfully, so that + * we can send the raw data now. */ +int +smb_request_write_raw(struct smb_server *server, + unsigned const char *source, int length) +{ + unsigned long old_mask; + int result, result2; + unsigned short fs; /* We fool the kernel to believe + we call from user space. */ + byte nb_header[4]; + + struct socket *sock = server_sock(server); + unsigned char *buffer = (server == NULL) ? NULL : server->packet; + + if ((sock == NULL) || (buffer == NULL)) { + printk("smb_request_write_raw: Bad server!\n"); + return -EBADF; + } + + if (server->state != CONN_VALID) + return -EIO; + + if ((result = smb_dont_catch_keepalive(server)) != 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + return result; + } + + old_mask = current->blocked; + current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + fs = get_fs(); + set_fs(get_ds()); + + smb_encode_smb_length(nb_header, length); + + result = sock->ops->send(sock, (void *)nb_header, 4, 0, 0); + + if (result == 4) { + set_fs(fs); /* source is in user-land */ + result = sock->ops->send(sock, (void *)source, length, 0, 0); + set_fs(get_ds()); + } else { + result = -EIO; + } + + DPRINTK("smb_request_write_raw: send returned %d\n", result); + + if (result == length) { + result = smb_receive(server, sock); + } else { + result = -EIO; + } + + /* read/write errors are handled by errno */ + current->signal &= ~_S(SIGPIPE); + current->blocked = old_mask; + set_fs(fs); + + if ((result2 = smb_catch_keepalive(server)) < 0) { + result = result2; + } + + if (result < 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + } + + if (result > 0) { + result = length; + } + + DPRINTK("smb_request_write_raw: result = %d\n", result); + + return result; +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h index 8170facfea50..d93a2a773226 100644 --- a/include/asm-i386/string.h +++ b/include/asm-i386/string.h @@ -496,6 +496,25 @@ __asm__ __volatile__( return (s); } +/* Added by Gertjan van Wingerde to make minix and sysv module work */ +#define __HAVE_ARCH_STRNLEN +extern inline size_t strnlen(const char * s, size_t count) +{ +register int __res; +__asm__ __volatile__( + "movl %1,%0\n\t" + "jmp 2f\n" + "1:\tcmpb $0,(%0)\n\t" + "je 3f\n\t" + "incl %0\n" + "2:\tdecl %2\n\t" + "cmpl $-1,%2\n\t" + "jne 1b\n" + "3:\tsubl %1,%0" + :"=a" (__res):"c" (s),"d" (count)); +return __res; +} +/* end of additional stuff */ /* * This looks horribly ugly, but the compiler can optimize it totally, diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 6f293d9f37f1..06f83388196c 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -149,6 +149,7 @@ #define __NR_getdents 141 #define __NR__newselect 142 #define __NR_flock 143 +#define __NR_msync 144 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index 7abd7d14fc53..d6b0b5967cf5 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -56,12 +56,18 @@ #define WIN_DOORLOCK 0xde /* lock door on removeable drives */ #define WIN_DOORUNLOCK 0xdf /* unlock door on removeable drives */ -#define WIN_PIDENTIFY 0xA1 /* identify ATA-PI device */ -#define WIN_MULTREAD 0xC4 /* read multiple sectors */ -#define WIN_MULTWRITE 0xC5 /* write multiple sectors */ -#define WIN_SETMULT 0xC6 /* enable read multiple */ +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode */ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ #define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ -#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define WIN_READDMA 0xc8 /* read sectors using DMA transfers */ +#define WIN_WRITEDMA 0xca /* write sectors using DMA transfers */ + +/* Additional drive command codes used by ATAPI devices. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_PACKETCMD 0xa0 /* Send a packet command. */ /* Bits for HD_ERROR */ #define MARK_ERR 0x01 /* Bad address mark */ @@ -80,13 +86,13 @@ struct hd_geometry { /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x30n/0x31n */ #define HDIO_GETGEO 0x301 /* get device geometry */ -#define HDIO_REQ HDIO_GETGEO /* obsolete, use HDIO_GETGEO */ #define HDIO_GET_UNMASKINTR 0x302 /* get current unmask setting */ #define HDIO_GET_MULTCOUNT 0x304 /* get current IDE blockmode setting */ #define HDIO_GET_IDENTITY 0x307 /* get IDE identification info */ #define HDIO_GET_KEEPSETTINGS 0x308 /* get keep-settings-on-reset flag */ #define HDIO_GET_CHIPSET 0x309 /* get current interface type setting */ -#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */ +#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */ +#define HDIO_GET_DMA 0x30b /* get use-dma flag */ #define HDIO_DRIVE_CMD 0x31f /* execute a special drive command */ /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */ @@ -94,7 +100,8 @@ struct hd_geometry { #define HDIO_SET_UNMASKINTR 0x322 /* permit other irqs during I/O */ #define HDIO_SET_KEEPSETTINGS 0x323 /* keep ioctl settings on reset */ #define HDIO_SET_CHIPSET 0x324 /* optimise driver for interface type */ -#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */ +#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */ +#define HDIO_SET_DMA 0x326 /* set use-dma flag */ /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */ struct hd_driveid { diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 75f86b616300..0b7dd484214d 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -28,7 +28,7 @@ #define ARPHRD_AX25 3 /* AX.25 Level 2 */ #define ARPHRD_PRONET 4 /* PROnet token ring */ #define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet- huh? */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ #define ARPHRD_ARCNET 7 /* ARCnet */ #define ARPHRD_APPLETLK 8 /* APPLEtalk */ /* Dummy types for non ARP hardware */ @@ -40,6 +40,7 @@ #define ARPHRD_ADAPT 264 #define ARPHRD_PPP 512 #define ARPHRD_TUNNEL 768 /* IPIP tunnel */ +#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index f4511f2c1326..305556b0a96a 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -49,6 +49,7 @@ #define ETH_P_ATALK 0x809B /* Appletalk DDP */ #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ #define ETH_P_IPX 0x8137 /* IPX over DIX */ +#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ #define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ diff --git a/include/linux/in.h b/include/linux/in.h index 499a9c8046e1..c8e156e878cf 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -127,4 +127,23 @@ struct sockaddr_in { #endif +/* + * IPv6 definitions as we start to include them. This is just + * a beginning dont get excited 8) + */ + +struct in_addr6 +{ + unsigned char s6_addr[16]; +}; + +struct sockaddr_in6 +{ + unsigned short sin6_family; + unsigned short sin6_port; + unsigned long sin6_flowinfo; + struct in_addr6 sin6_addr; +}; + + #endif /* _LINUX_IN_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 24ae6f4ed974..3f7e00f95e84 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -95,13 +95,13 @@ struct vm_operations_struct { void (*close)(struct vm_area_struct * area); void (*unmap)(struct vm_area_struct *area, unsigned long, size_t); void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot); - void (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags); + int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags); void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise); unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, unsigned long page, int write_access); unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address, unsigned long page); - void (*swapout)(struct vm_area_struct *, unsigned long, pte_t *); + int (*swapout)(struct vm_area_struct *, unsigned long, pte_t *); pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long); }; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a36bf866bfd1..be1e6505f814 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -363,6 +363,7 @@ extern __inline__ void skb_trim(struct sk_buff *skb, int len) extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); +extern void skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size); extern void skb_free_datagram(struct sk_buff *skb); #endif /* __KERNEL__ */ diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 822dc674ce62..382ae83d3bd3 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -124,13 +124,18 @@ int smb_conn_is_valid(struct smb_server *server); /* linux/fs/smbfs/proc.c */ dword smb_len(unsigned char *packet); +byte *smb_encode_smb_length(byte *p, dword len); int smb_proc_open(struct smb_server *server, const char *pathname, int len, struct smb_dirent *entry); int smb_proc_close(struct smb_server *server, struct smb_dirent *finfo); int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data, int fs); +int smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, char *data); int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, off_t offset, int count, const char *data); +int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, const char *data); int smb_proc_create(struct smb_server *server, const char *path, int len, struct smb_dirent *entry); int smb_proc_mknew(struct smb_server *server, const char *path, int len, @@ -161,6 +166,10 @@ int smb_proc_trunc(struct smb_server *server, word fid, dword length); int smb_release(struct smb_server *server); int smb_connect(struct smb_server *server); int smb_request(struct smb_server *server); +int smb_request_read_raw(struct smb_server *server, + unsigned char *target, int max_len); +int smb_request_write_raw(struct smb_server *server, + unsigned const char *source, int length); int smb_catch_keepalive(struct smb_server *server); int smb_dont_catch_keepalive(struct smb_server *server); int smb_trans2_request(struct smb_server *server, diff --git a/include/linux/socket.h b/include/linux/socket.h index a0efebca6736..d98bf6981c01 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -48,6 +48,7 @@ struct msghdr #define AF_BRIDGE 7 /* Multiprotocol bridge */ #define AF_AAL5 8 /* Reserved for Werner's ATM */ #define AF_X25 9 /* Reserved for X.25 project */ +#define AF_INET6 10 /* IP version 6 */ #define AF_MAX 12 /* For now.. */ /* Protocol families, same as address families. */ @@ -61,6 +62,7 @@ struct msghdr #define PF_BRIDGE AF_BRIDGE #define PF_AAL5 AF_AAL5 #define PF_X25 AF_X25 +#define PF_INET6 AF_INET6 #define PF_MAX AF_MAX diff --git a/include/net/netrom.h b/include/net/netrom.h index 8f93519fcdf8..187001175427 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -90,7 +90,7 @@ struct nr_neigh { extern struct nr_parms_struct nr_default; extern int nr_rx_frame(struct sk_buff *, struct device *); extern void nr_destroy_socket(struct sock *); -extern int nr_get_info(char *, char **, off_t, int, int); +/*extern int nr_get_info(char *, char **, off_t, int, int);*/ /* nr_dev.c */ extern int nr_rx_ip(struct sk_buff *, struct device *); diff --git a/kernel/Makefile b/kernel/Makefile index 059b1ee5d9a3..3b08522090e7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -20,6 +20,8 @@ O_OBJS += $(SYMTAB_OBJS) ifdef CONFIG_MODVERSIONS $(O_TARGET): $(SYMTAB_OBJS:.o=.ver) +dep: $(SYMTAB_OBJS:.o=.ver) +fastdep: $(SYMTAB_OBJS:.o=.ver) endif include $(TOPDIR)/Rules.make diff --git a/mm/filemap.c b/mm/filemap.c index 9ec211cf74f8..04134503f654 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1,7 +1,7 @@ /* - * linux/mm/filemmap.c + * linux/mm/filemap.c * - * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 1994, 1995 Linus Torvalds */ /* @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -26,9 +28,15 @@ /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. + * + * Shared mappings now work. 15.8.1995 Bruno. */ -static inline void multi_bmap(struct inode * inode, unsigned int block, unsigned int * nr, int shift) +/* + * Simple routines for both non-shared and shared mappings. + */ + +static inline void multi_bmap(struct inode * inode, unsigned long block, unsigned int * nr, int shift) { int i = PAGE_SIZE >> shift; block >>= shift; @@ -51,23 +59,19 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share); } + /* - * NOTE! mmap sync doesn't really work yet. This is mainly a stub for it, - * which only works if the buffers and the page were already sharing the - * same physical page (that's actually pretty common, especially if the - * file has been mmap'ed before being read the normal way). - * - * Todo: - * - non-shared pages also need to be synced with the buffers. - * - the "swapout()" function needs to swap out the page to - * the shared file instead of using the swap device. + * Tries to write a shared mapped page to its backing store. May return -EIO + * if the disk is full. */ -static void filemap_sync_page(struct vm_area_struct * vma, +static int filemap_write_page(struct vm_area_struct * vma, unsigned long offset, unsigned long page) { + int old_fs; + unsigned long size, result; + struct file file; struct inode * inode; - int nr[PAGE_SIZE/512]; struct buffer_head * bh; bh = buffer_pages[MAP_NR(page)]; @@ -78,14 +82,39 @@ static void filemap_sync_page(struct vm_area_struct * vma, mark_buffer_dirty(tmp, 0); tmp = tmp->b_this_page; } while (tmp != bh); - return; + return 0; } + inode = vma->vm_inode; - offset += vma->vm_offset; - multi_bmap(inode, offset, nr, inode->i_sb->s_blocksize_bits); - bwrite_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize); + file.f_op = inode->i_op->default_file_ops; + if (!file.f_op->write) + return -EIO; + size = offset + PAGE_SIZE; + /* refuse to extend file size.. */ + if (S_ISREG(inode->i_mode)) { + if (size > inode->i_size) + size = inode->i_size; + /* Ho humm.. We should have tested for this earlier */ + if (size < offset) + return -EIO; + } + size -= offset; + file.f_mode = 3; + file.f_flags = 0; + file.f_count = 1; + file.f_inode = inode; + file.f_pos = offset; + file.f_reada = 0; + old_fs = get_fs(); + set_fs(KERNEL_DS); + result = file.f_op->write(inode, &file, (const char *) page, size); + set_fs(old_fs); + if (result != size) + return -EIO; + return 0; } + /* * Swapping to a shared file: while we're busy writing out the page * (and the page still exists in memory), we save the page information @@ -94,20 +123,22 @@ static void filemap_sync_page(struct vm_area_struct * vma, * * Once we've written it all out, we mark the page entry "empty", which * will result in a normal page-in (instead of a swap-in) from the now - * up-to-date shared file mapping. + * up-to-date disk file. */ -void filemap_swapout(struct vm_area_struct * vma, +int filemap_swapout(struct vm_area_struct * vma, unsigned long offset, pte_t *page_table) { + int error; unsigned long page = pte_page(*page_table); unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page)); pte_val(*page_table) = entry; invalidate(); - filemap_sync_page(vma, offset, page); + error = filemap_write_page(vma, offset, page); if (pte_val(*page_table) == entry) pte_clear(page_table); + return error; } /* @@ -124,41 +155,58 @@ static pte_t filemap_swapin(struct vm_area_struct * vma, mem_map[page]++; page = (page << PAGE_SHIFT) + PAGE_OFFSET; - return pte_mkdirty(mk_pte(page,vma->vm_page_prot)); + return mk_pte(page,vma->vm_page_prot); } -static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma, + +static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma, unsigned long address, unsigned int flags) { - pte_t page = *pte; - - if (!pte_present(page)) - return; - if (!pte_dirty(page)) - return; - if (flags & MS_INVALIDATE) { - pte_clear(pte); + pte_t pte = *ptep; + unsigned long page; + int error; + + if (!(flags & MS_INVALIDATE)) { + if (!pte_present(pte)) + return 0; + if (!pte_dirty(pte)) + return 0; + *ptep = pte_mkclean(pte); + page = pte_page(pte); + mem_map[MAP_NR(page)]++; } else { - mem_map[MAP_NR(pte_page(page))]++; - *pte = pte_mkclean(page); + if (pte_none(pte)) + return 0; + pte_clear(ptep); + if (!pte_present(pte)) { + swap_free(pte_val(pte)); + return 0; + } + page = pte_page(pte); + if (!pte_dirty(pte) || flags == MS_INVALIDATE) { + free_page(page); + return 0; + } } - filemap_sync_page(vma, address - vma->vm_start, pte_page(page)); - free_page(pte_page(page)); + error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page); + free_page(page); + return error; } -static inline void filemap_sync_pte_range(pmd_t * pmd, +static inline int filemap_sync_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, struct vm_area_struct *vma, unsigned long offset, unsigned int flags) { pte_t * pte; unsigned long end; + int error; if (pmd_none(*pmd)) - return; + return 0; if (pmd_bad(*pmd)) { printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd)); pmd_clear(pmd); - return; + return 0; } pte = pte_offset(pmd, address); offset += address & PMD_MASK; @@ -166,26 +214,29 @@ static inline void filemap_sync_pte_range(pmd_t * pmd, end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; + error = 0; do { - filemap_sync_pte(pte, vma, address + offset, flags); + error |= filemap_sync_pte(pte, vma, address + offset, flags); address += PAGE_SIZE; pte++; } while (address < end); + return error; } -static inline void filemap_sync_pmd_range(pgd_t * pgd, +static inline int filemap_sync_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, struct vm_area_struct *vma, unsigned int flags) { pmd_t * pmd; unsigned long offset, end; + int error; if (pgd_none(*pgd)) - return; + return 0; if (pgd_bad(*pgd)) { printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd)); pgd_clear(pgd); - return; + return 0; } pmd = pmd_offset(pgd, address); offset = address & PMD_MASK; @@ -193,31 +244,34 @@ static inline void filemap_sync_pmd_range(pgd_t * pgd, end = address + size; if (end > PGDIR_SIZE) end = PGDIR_SIZE; + error = 0; do { - filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags); + error |= filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); + return error; } -static void filemap_sync(struct vm_area_struct * vma, unsigned long address, +static int filemap_sync(struct vm_area_struct * vma, unsigned long address, size_t size, unsigned int flags) { pgd_t * dir; unsigned long end = address + size; + int error = 0; dir = pgd_offset(current, address); while (address < end) { - filemap_sync_pmd_range(dir, address, end - address, vma, flags); + error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags); address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } invalidate(); - return; + return error; } /* - * This handles area unmaps.. + * This handles partial area unmaps.. */ static void filemap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len) { @@ -251,9 +305,9 @@ static struct vm_operations_struct file_shared_mmap = { }; /* - * Private mappings just need to be able to load in the map + * Private mappings just need to be able to load in the map. * - * (this is actually used for shared mappings as well, if we + * (This is actually used for shared mappings as well, if we * know they can't ever get write permissions..) */ static struct vm_operations_struct file_private_mmap = { @@ -274,17 +328,21 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct { struct vm_operations_struct * ops; - if (vma->vm_offset & (inode->i_sb->s_blocksize - 1)) - return -EINVAL; + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) { + ops = &file_shared_mmap; + /* share_page() can only guarantee proper page sharing if + * the offsets are all page aligned. */ + if (vma->vm_offset & (PAGE_SIZE - 1)) + return -EINVAL; + } else { + ops = &file_private_mmap; + if (vma->vm_offset & (inode->i_sb->s_blocksize - 1)) + return -EINVAL; + } if (!inode->i_sb || !S_ISREG(inode->i_mode)) return -EACCES; if (!inode->i_op || !inode->i_op->bmap) return -ENOEXEC; - ops = &file_private_mmap; - if (vma->vm_flags & VM_SHARED) { - if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) - ops = &file_shared_mmap; - } if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; @@ -294,3 +352,74 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct vma->vm_ops = ops; return 0; } + + +/* + * The msync() system call. + */ + +static int msync_interval(struct vm_area_struct * vma, + unsigned long start, unsigned long end, int flags) +{ + if (!vma->vm_inode) + return 0; + if (vma->vm_ops->sync) { + int error; + error = vma->vm_ops->sync(vma, start, end-start, flags); + if (error) + return error; + if (flags & MS_SYNC) + return file_fsync(vma->vm_inode, NULL); + return 0; + } + return 0; +} + +asmlinkage int sys_msync(unsigned long start, size_t len, int flags) +{ + unsigned long end; + struct vm_area_struct * vma; + int unmapped_error, error; + + if (start & ~PAGE_MASK) + return -EINVAL; + len = (len + ~PAGE_MASK) & PAGE_MASK; + end = start + len; + if (end < start) + return -EINVAL; + if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) + return -EINVAL; + if (end == start) + return 0; + /* + * If the interval [start,end) covers some unmapped address ranges, + * just ignore them, but return -EFAULT at the end. + */ + vma = find_vma(current, start); + unmapped_error = 0; + for (;;) { + /* Still start < end. */ + if (!vma) + return -EFAULT; + /* Here start < vma->vm_end. */ + if (start < vma->vm_start) { + unmapped_error = -EFAULT; + start = vma->vm_start; + } + /* Here vma->vm_start <= start < vma->vm_end. */ + if (end <= vma->vm_end) { + if (start < end) { + error = msync_interval(vma, start, end, flags); + if (error) + return error; + } + return unmapped_error; + } + /* Here vma->vm_start <= start < vma->vm_end < end. */ + error = msync_interval(vma, start, vma->vm_end, flags); + if (error) + return error; + start = vma->vm_end; + vma = vma->vm_next; + } +} diff --git a/mm/swap.c b/mm/swap.c index 32f0b38cb483..0c6a82bc14d8 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -55,6 +55,13 @@ static struct swap_info_struct { extern int shm_swap (int, unsigned long); +/* + * To save us from swapping out pages which have just been swapped in and + * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT] + * the swap entry which was last used to fill the page, or zero if the + * page does not currently correspond to a page in swap. PAGE_DIRTY makes + * this info useless. + */ unsigned long *swap_cache; #ifdef SWAP_CACHE_INFO @@ -366,12 +373,14 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long addr return 0; } if (pte_dirty(pte)) { - if (mem_map[MAP_NR(page)] != 1) - return 0; if (vma->vm_ops && vma->vm_ops->swapout) { + pid_t pid = vma->vm_task->pid; vma->vm_task->mm->rss--; - vma->vm_ops->swapout(vma, address-vma->vm_start, page_table); + if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table)) + kill_proc(pid, SIGBUS, 1); } else { + if (mem_map[MAP_NR(page)] != 1) + return 0; if (!(entry = get_swap_page())) return 0; vma->vm_task->mm->rss--; diff --git a/net/Changes b/net/Changes index 61c42830b20e..adb4fc5edd02 100644 --- a/net/Changes +++ b/net/Changes @@ -140,9 +140,9 @@ o TCP does rerouting for most cases [TESTED] ------->>>>> 1.3.14 <<<<<---------- -o IPX works [IN] -o NetROM works [IN] -o AX.25 works [IN] +o IPX works [TESTED] +o NetROM works [TESTED] +o AX.25 works [TESTED] o Most modules need recompiling even though they load OK [BLAME LINUS] o Appletalk works nicely [CHECKED] @@ -150,14 +150,14 @@ o Fast IP forwarding part 1 works [CHECKED] ------->>>>> 1.3.15 <<<<<--------- o Mike Shaver has started RFC1122 verification [IN PROGRESS] -o Minor bug fixes [IN] +o Minor bug fixes [TESTED] ------->>>> 1.3.16 <<<-------- o Missing patches for device change in TCP [TESTED] o Device locking [TESTED] -o Infinite slip devices [IN] -o New AF_UNIX sockets [IN] +o Infinite slip devices [IN - BUG] +o New AF_UNIX sockets [TESTED] o Sendmsg/recvmsg (for some stuff only) [IN] o Device unload loopholes fixed [TESTED] o Extra firewall abilities [IN] @@ -165,11 +165,17 @@ o Appletalk node probe bug fix [TESTED] ------->>>> 1.3.18 <<<<--------- -o AF_UNIX debugging [IN] -o TCP explode on SWS bug fix [IN] -o John Naylor's ARP hwtype fix [IN] -o Datagram select matches BSD semantics [IN] +o AF_UNIX debugging [TESTED] +o TCP explode on SWS bug fix [TESTED] +o John Naylor's ARP hwtype fix [TESTED] +o Datagram select matches BSD semantics [TESTED] +-------->>>>> 1.3.21 <<<<<--------- + +o AF_UNIX fixes and 4K limiter [IN] +o Sendmsg/recvmsg for AX.25/Appletalk [IN] +o Datagram generic iovec support [IN] +o Misc minor bug fixes [IN] o Finish merging the bridge code o SIOCSLEEPRT patch @@ -177,7 +183,7 @@ o Options support in ip_build_xmit [PENDING] o Fast checksum/copy on outgoing TCP o Fast dev_grab_next() transmit reload function and dev_push_failed() ?? -o Faster ip_forward last hit cache [PENDING] +o Faster ip_forward last hit cache [PENDING(GuruA0)] o Forwarding queue control (+ fairness algorithms ??) o IP forward flow control. o Infinite PPP devices. @@ -186,6 +192,10 @@ o Clean up RAW AX.25 sockets. o Finish 802.2 Class I code to be compliant to the oddities of 802.2 o Full variable length AX.25 support [JSN doing] o Tidy BPQ support +o Strange eth0-eth3 bug +o Finish IPIP bug fixes +o Why doesnt the PROTO_UNREACH get sent ? + 0.2 --- @@ -282,9 +292,10 @@ their hands. [Provisionally taken] 17. PPP multilink. Another nasty job. 18. Implement swIPe under Linux. -[In progress] +[Reportedly in progress] 19. IPv4 IP-AH and IP-ESP. +[Taken] BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS - you make a mistake you have to reboot. You do at least get dumps and a diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 6449de7d49ac..5822d72d5ca1 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -13,6 +13,7 @@ * Michael Callahan : Made routing work * Wesley Craig : Fix probing to listen to a * passed node id. + * Alan Cox : Added send/recvmsg support * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1466,11 +1467,10 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) return(0); } -static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int noblock, - unsigned flags, struct sockaddr *sat, int addr_len) +static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags) { atalk_socket *sk=(atalk_socket *)sock->data; - struct sockaddr_at *usat=(struct sockaddr_at *)sat; + struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name; struct sockaddr_at local_satalk, gsat; struct sk_buff *skb; struct device *dev; @@ -1495,7 +1495,7 @@ static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int nobl return -EBUSY; } - if(addr_len msg_namelen sat_family != AF_APPLETALK) return -EINVAL; @@ -1581,7 +1581,7 @@ static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int nobl if(sk->debug) printk("SK %p: Copy user data (%d bytes).\n", sk, len); - memcpy_fromfs(skb_put(skb,len),ubuf,len); + memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); if(sk->no_check==1) ddp->deh_sum=0; @@ -1643,16 +1643,32 @@ static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int nobl return len; } + +static int atalk_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags, + struct sockaddr *sa, int addr_len) +{ + struct iovec iov; + struct msghdr msg; + iov.iov_base=(void *)ubuf; + iov.iov_len=size; + msg.msg_name=(void *)sa; + msg.msg_namelen=addr_len; + msg.msg_accrights=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + return atalk_sendmsg(sock,&msg,size,noblock,flags); +} + + static int atalk_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags) { return atalk_sendto(sock,ubuf,size,noblock,flags,NULL,0); } -static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sip, int *addr_len) +static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) { atalk_socket *sk=(atalk_socket *)sock->data; - struct sockaddr_at *sat=(struct sockaddr_at *)sip; + struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name; struct ddpehdr *ddp = NULL; int copied = 0; struct sk_buff *skb; @@ -1678,14 +1694,14 @@ static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock copied=ddp->deh_len; if(copied > size) copied=size; - skb_copy_datagram(skb,0,ubuf,copied); + skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); } else { copied=ddp->deh_len - sizeof(*ddp); if (copied > size) copied = size; - skb_copy_datagram(skb,sizeof(*ddp),ubuf,copied); + skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); } if(sat) { @@ -1705,6 +1721,23 @@ static int atalk_write(struct socket *sock, const char *ubuf, int size, int nobl } +static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags, + struct sockaddr *sa, int *addr_len) +{ + struct iovec iov; + struct msghdr msg; + iov.iov_base=ubuf; + iov.iov_len=size; + msg.msg_name=(void *)sa; + msg.msg_namelen=0; + if (addr_len) + msg.msg_namelen = *addr_len; + msg.msg_accrights=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + return atalk_recvmsg(sock,&msg,size,noblock,flags,addr_len); +} + static int atalk_recv(struct socket *sock, void *ubuf, int size , int noblock, unsigned flags) { @@ -1848,6 +1881,8 @@ static struct proto_ops atalk_proto_ops = { atalk_setsockopt, atalk_getsockopt, atalk_fcntl, + atalk_sendmsg, + atalk_recvmsg }; static struct notifier_block ddp_notifier={ @@ -1886,6 +1921,6 @@ void atalk_proto_init(struct net_proto *pro) atalk_if_get_info }); - printk("Appletalk BETA 0.11 for Linux NET3.030\n"); + printk("Appletalk BETA 0.12 for Linux NET3.030\n"); } #endif diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 11a1448ab9db..942bb62ccbd9 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1630,12 +1630,11 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type * return ax25_rcv(skb, dev, &port_call, ptype); } -static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblock, - unsigned flags, struct sockaddr *usip, int addr_len) +static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, int noblock, int flags) { struct sock *sk = (struct sock *)sock->data; - struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)usip; - unsigned char *uaddr = (unsigned char *)usip; + struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; + unsigned char *uaddr = (unsigned char *)msg->msg_name; int err; struct sockaddr_ax25 sax; struct sk_buff *skb; @@ -1644,14 +1643,17 @@ static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblo ax25_digi *dp; ax25_digi dtmp; int lv; + int addr_len=msg->msg_namelen; if (sk->err) { + cli(); err = sk->err; sk->err = 0; + sti(); return -err; } - if (flags) + if (flags|| msg->msg_accrights) return -EINVAL; if (sk->zapped) @@ -1731,7 +1733,7 @@ static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblo printk("AX.25: Appending user data\n"); /* User data follows immediately after the AX.25 data */ - memcpy_fromfs(skb_put(skb, len), ubuf, len); + memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); /* Add the PID, usually AX25_TEXT */ asmptr = skb_push(skb, 1); @@ -1780,6 +1782,22 @@ static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblo } +static int ax25_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags, + struct sockaddr *sa, int addr_len) +{ + struct iovec iov; + struct msghdr msg; + iov.iov_base=(void *)ubuf; + iov.iov_len=size; + msg.msg_name=(void *)sa; + msg.msg_namelen=addr_len; + msg.msg_accrights=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + return ax25_sendmsg(sock,&msg,size,noblock,flags); +} + + static int ax25_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags) { return ax25_sendto(sock, ubuf, size, noblock, flags, NULL, 0); @@ -1787,22 +1805,23 @@ static int ax25_send(struct socket *sock, const void *ubuf, int size, int nobloc static int ax25_write(struct socket *sock, const char *ubuf, int size, int noblock) { - return ax25_send(sock, ubuf, size, noblock, 0); + return ax25_sendto(sock, ubuf, size, noblock, 0, NULL, 0); } -static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sip, int *addr_len) +static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) { struct sock *sk = (struct sock *)sock->data; - struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)sip; - char *addrptr = (char *)sip; + struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; + char *addrptr = (char *)msg->msg_name; int copied, length; struct sk_buff *skb; int er; if (sk->err) { + cli(); er = -sk->err; sk->err = 0; + sti(); return er; } @@ -1830,7 +1849,7 @@ static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, } copied = (size < length) ? size : length; - skb_copy_datagram(skb, 0, ubuf, copied); + skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (sax) { struct sockaddr_ax25 addr; @@ -1859,6 +1878,23 @@ static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, return copied; } +static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags, + struct sockaddr *sa, int *addr_len) +{ + struct iovec iov; + struct msghdr msg; + iov.iov_base=ubuf; + iov.iov_len=size; + msg.msg_name=(void *)sa; + msg.msg_namelen=0; + if (addr_len) + msg.msg_namelen = *addr_len; + msg.msg_accrights=NULL; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + return ax25_recvmsg(sock,&msg,size,noblock,flags,addr_len); +} + static int ax25_recv(struct socket *sock, void *ubuf, int size , int noblock, unsigned flags) { @@ -2076,6 +2112,8 @@ static struct proto_ops ax25_proto_ops = { ax25_setsockopt, ax25_getsockopt, ax25_fcntl, + ax25_sendmsg, + ax25_recvmsg }; /* Called by socket.c on kernel start up */ diff --git a/net/core/Makefile b/net/core/Makefile index 3570be78edf8..7c98519f886a 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -9,10 +9,10 @@ O_TARGET := core.o -O_OBJS := +O_OBJS := sock.o skbuff.o iovec.o datagram.o ifdef CONFIG_NET -O_OBJS += sock.o dev.o dev_mcast.o iovec.o skbuff.o datagram.o +O_OBJS += dev.o dev_mcast.o endif include $(TOPDIR)/Rules.make diff --git a/net/core/datagram.c b/net/core/datagram.c index b61e0efd59a9..4dc47269eab9 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -17,6 +17,7 @@ * Florian La Roche: Changed for my new skbuff handling. * Darryl Miles : Fixed non-blocking SOCK_SEQPACKET. * Linus Torvalds : BSD semantic fixes. + * Alan Cox : Datagram iovec handling * * Note: * A lot of this will change when the protocol/socket separation @@ -164,11 +165,25 @@ void skb_free_datagram(struct sk_buff *skb) restore_flags(flags); } +/* + * Copy a datagram to a linear buffer. + */ + void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) { memcpy_tofs(to,skb->h.raw+offset,size); } + +/* + * Copy a datagram to an iovec. + */ + +void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size) +{ + memcpy_toiovec(to,skb->h.raw+offset,size); +} + /* * Datagram select: Again totally generic. Moved from udp.c * Now does seqpacket. diff --git a/net/core/iovec.c b/net/core/iovec.c index c5c3c3ade971..225e1f09f50f 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -64,9 +64,10 @@ void memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { while(len>0) { - memcpy_tofs(iov->iov_base, kdata,iov->iov_len); - kdata+=iov->iov_len; - len-=iov->iov_len; + int copy = min(iov->iov_len,len); + memcpy_tofs(iov->iov_base,kdata,copy); + kdata+=copy; + len-=copy; iov++; } } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 30a2bba551b3..4a9c16a1c5db 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -95,7 +95,7 @@ extern int afinet_get_info(char *, char **, off_t, int, int); extern int tcp_get_info(char *, char **, off_t, int, int); extern int udp_get_info(char *, char **, off_t, int, int); -int (*rarp_ioctl_hook)(int,void*) = NULL; +int (*rarp_ioctl_hook)(unsigned int,void*) = NULL; /* * See if a socket number is in use. diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 4b63a9009012..7ddbc46837e3 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -691,7 +691,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * Check for bad requests for 127.x.x.x and requests for multicast * addresses. If this is one such, delete it. */ - if (IN_LOOPBACK(tip) || IN_MULTICAST(tip)) + if (LOOPBACK(tip) || MULTICAST(tip)) { kfree_skb(skb, FREE_READ); return 0; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 11bc14f30bfb..d5364dde7373 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -102,7 +102,7 @@ (OK... we don't use it) MUST discard received REPLYs if not using this system (OK) MUST NOT send replies unless specifically made agent for this sort - of thing. (NOT YET) + of thing. (OK) */ #include diff --git a/net/ipv4/ip.c b/net/ipv4/ip.c index a2398e32e44f..6deb43646a7f 100644 --- a/net/ipv4/ip.c +++ b/net/ipv4/ip.c @@ -205,6 +205,26 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev return mac; } +static int ip_send_room(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr) +{ + int mac = 0; + + skb->dev = dev; + skb->arp = 1; + if (dev->hard_header) + { + skb_reserve(skb,MAX_HEADER); + mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len); + if (mac < 0) + { + mac = -mac; + skb->arp = 0; + skb->raddr = daddr; /* next routing address */ + } + } + return mac; +} + int ip_id_count = 0; /* @@ -287,7 +307,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd * Now build the MAC header. */ - tmp = ip_send(skb, raddr, len, *dev, saddr); + if(type==IPPROTO_TCP) + tmp = ip_send_room(skb, raddr, len, *dev, saddr); + else + tmp = ip_send(skb, raddr, len, *dev, saddr); /* * Book keeping @@ -1300,6 +1323,15 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) int err; #endif +#ifdef CONFIG_NET_IPV6 + /* + * Intercept IPv6 frames. We dump ST-II and invalid types just below.. + */ + + if(iph->version == 6) + return ipv6_rcv(skb,dev,pt); +#endif + ip_statistics.IpInReceives++; /* @@ -1571,13 +1603,13 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct sock *sknext=NULL; struct sk_buff *skb1; - raw_sk=get_sock_raw(raw_sk, hash, iph->saddr, iph->daddr); + raw_sk=get_sock_raw(raw_sk, iph->protocol, iph->saddr, iph->daddr); if(raw_sk) /* Any raw sockets */ { do { /* Find the next */ - sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr); + sknext=get_sock_raw(raw_sk->next, iph->protocol, iph->saddr, iph->daddr); if(sknext) skb1=skb_clone(skb, GFP_ATOMIC); else diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c index 5ec5daef8d1b..d960f2869bae 100644 --- a/net/ipv4/ip_fw.c +++ b/net/ipv4/ip_fw.c @@ -1502,7 +1502,7 @@ static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, #ifdef CONFIG_IP_MASQUERADE static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, - int length) + int length, int unused) { off_t pos=0, begin=0; struct ip_masq *ms; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 02ce3082715f..3a5aea847832 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -886,7 +886,7 @@ void tcp_err(int err, unsigned char *header, unsigned long daddr, * until we time out, or the user gives up. */ - if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT) + if (err < 13 && (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT)) { if (sk->state == TCP_SYN_SENT) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 826e44c7ffac..9dfb716a30e0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -189,7 +189,7 @@ void udp_err(int err, unsigned char *header, unsigned long daddr, /* 4.1.3.3. */ /* After the comment above, that should be no surprise. */ - if (icmp_err_convert[err & 0xff].fatal) + if (err < 13 && icmp_err_convert[err & 0xff].fatal) { sk->err = icmp_err_convert[err & 0xff].errno; sk->error_report(sk); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index fa7b098327aa..a8c57cdbccc0 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,7 @@ #include #include #include - +#include #include /************************************************************************\ @@ -1411,16 +1412,19 @@ void nr_proto_init(struct net_proto *pro) proc_net_register(&(struct proc_dir_entry) { PROC_NET_NR, 2, "nr", S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, nr_get_info }); proc_net_register(&(struct proc_dir_entry) { PROC_NET_NR_NEIGH, 8, "nr_neigh", S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, nr_neigh_get_info }); proc_net_register(&(struct proc_dir_entry) { PROC_NET_NR_NODES, 8, "nr_nodes", S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, nr_nodes_get_info }); } diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index f1854739d8dc..683c39d8264d 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -41,6 +41,7 @@ #include #include +#include #include #include diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 1a1865d5e0fa..37f3c4edce34 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -5,8 +5,8 @@ * * Currently this contains all but the file descriptor passing code. * Before that goes in the odd bugs in the iovec handlers need - * fixing, and this bit testing. BSD fd passing is a trivial part - * of the exercise. + * fixing, and this bit testing. BSD fd passing is not a trivial part + * of the exercise it turns out. Anyone like writing garbage collectors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,8 +15,9 @@ * * Fixes: * Linus Torvalds : Assorted bug cures. - * Niibe Yutaka : async I/O support + * Niibe Yutaka : async I/O support. * Carsten Paeth : PF_UNIX check, address fixes. + * Alan Cox : Limit size of allocated blocks. */ #include @@ -681,7 +682,7 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no if(sun==NULL) { if(sk->protinfo.af_unix.other==NULL) - return -EINVAL; + return -ENOTCONN; } /* @@ -694,6 +695,13 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no if(sock->type==SOCK_DGRAM) return -EMSGSIZE; len=(sk->sndbuf-sizeof(struct sk_buff))/2; + /* + * Keep to page sized kmalloc()'s as various people + * have suggested. Big mallocs stress the vm too + * much. + */ + if(len > 4000 && sock->type!=SOCK_DGRAM) + len = 4000; } size=/*protocol_size(&proto_unix)+*/len; @@ -1044,7 +1052,7 @@ static struct proto_ops unix_proto_ops = { void unix_proto_init(struct net_proto *pro) { - printk("NET3: Unix domain sockets 0.07 BETA for Linux NET3.030.\n"); + printk("NET3: Unix domain sockets 0.09 BETA for Linux NET3.030.\n"); sock_register(unix_proto_ops.family, &unix_proto_ops); proc_net_register(&(struct proc_dir_entry) { PROC_NET_UNIX, 4, "unix", diff --git a/scripts/depend.awk b/scripts/depend.awk index 630d90444c4c..a08dc29879b3 100644 --- a/scripts/depend.awk +++ b/scripts/depend.awk @@ -14,9 +14,8 @@ function fileExists(f, TMP, dummy, result) { return "Yes" } else {return ""} } - ERRNO="" - getline dummy < f - if(!length(ERRNO)) { + ERRNO = getline dummy < f + if(ERRNO >= 0) { close(f) return FILEHASH[f]="Yes" } else { diff --git a/versions.mk b/versions.mk index 3c71e9a377f0..41aadcd6bc1e 100644 --- a/versions.mk +++ b/versions.mk @@ -26,6 +26,6 @@ $(TOPINCL)/modversions.h: $(SYMTAB_OBJS:.o=.ver) do echo "#include "; done) \ > $(TOPINCL)/modversions.h -dep: $(TOPINCL)/modversions.h +fastdep: $(TOPINCL)/modversions.h endif -- 2.39.5