aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2002-01-15 06:25:49 +0000
committerdavem <davem>2002-01-15 06:25:49 +0000
commit4d96e9d5b224da0d7fc611c0c8864799d23433b0 (patch)
tree2e5582dc74b1dc843db1dcc50225fcc1be24a693
parent2296b841d75e023d6cc902768f45d75b30034700 (diff)
downloadnetdev-vger-cvs-4d96e9d5b224da0d7fc611c0c8864799d23433b0.tar.gz
Merge mainline to 2.5.2-final.
-rw-r--r--Documentation/Configure.help19
-rw-r--r--Documentation/block/request.txt86
-rw-r--r--Documentation/cciss.txt2
-rw-r--r--Documentation/filesystems/devfs/ChangeLog6
-rw-r--r--Makefile6
-rw-r--r--arch/alpha/config.in2
-rw-r--r--arch/arm/config.in2
-rw-r--r--arch/cris/config.in2
-rw-r--r--arch/i386/config.in2
-rw-r--r--arch/i386/defconfig6
-rw-r--r--arch/i386/kernel/setup.c1
-rw-r--r--arch/ia64/config.in2
-rw-r--r--arch/m68k/config.in2
-rw-r--r--arch/mips/config.in2
-rw-r--r--arch/mips64/config.in2
-rw-r--r--arch/parisc/config.in1
-rw-r--r--arch/ppc/config.in2
-rw-r--r--arch/s390/config.in1
-rw-r--r--arch/s390x/config.in1
-rw-r--r--arch/sh/config.in2
-rw-r--r--arch/sparc/config.in4
-rw-r--r--arch/sparc/defconfig7
-rw-r--r--arch/sparc64/defconfig5
-rw-r--r--drivers/block/Config.in1
-rw-r--r--drivers/block/cciss.c82
-rw-r--r--drivers/block/cciss.h3
-rw-r--r--drivers/block/cciss_cmd.h8
-rw-r--r--drivers/block/cciss_scsi.c1631
-rw-r--r--drivers/block/cciss_scsi.h98
-rw-r--r--drivers/block/cpqarray.c13
-rw-r--r--drivers/block/elevator.c13
-rw-r--r--drivers/block/ll_rw_blk.c15
-rw-r--r--drivers/block/nbd.c6
-rw-r--r--drivers/md/md.c20
-rw-r--r--drivers/md/multipath.c1
-rw-r--r--drivers/md/raid5.c2
-rw-r--r--drivers/message/i2o/i2o_block.c4
-rw-r--r--drivers/net/7990.c19
-rw-r--r--drivers/net/7990.h3
-rw-r--r--drivers/net/8139cp.c17
-rw-r--r--drivers/net/8139too.c19
-rw-r--r--drivers/net/8390.c27
-rw-r--r--drivers/net/Makefile.lib69
-rw-r--r--drivers/net/a2065.c20
-rw-r--r--drivers/net/a2065.h3
-rw-r--r--drivers/net/am79c961a.c25
-rw-r--r--drivers/net/at1700.c22
-rw-r--r--drivers/net/atp.c21
-rw-r--r--drivers/net/au1000_eth.c17
-rw-r--r--drivers/net/bmac.c17
-rw-r--r--drivers/net/de2104x.c36
-rw-r--r--drivers/net/de4x5.c15
-rw-r--r--drivers/net/declance.c20
-rw-r--r--drivers/net/depca.c16
-rw-r--r--drivers/net/dl2k.c22
-rw-r--r--drivers/net/dl2k.h1
-rw-r--r--drivers/net/dmfe.c84
-rw-r--r--drivers/net/epic100.c22
-rw-r--r--drivers/net/ewrk3.c17
-rw-r--r--drivers/net/fealnx.c22
-rw-r--r--drivers/net/gmac.c18
-rw-r--r--drivers/net/ioc3-eth.c20
-rw-r--r--drivers/net/mace.c22
-rw-r--r--drivers/net/macmace.c22
-rw-r--r--drivers/net/myri_sbus.c3
-rw-r--r--drivers/net/natsemi.c46
-rw-r--r--drivers/net/pci-skeleton.c23
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c22
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c26
-rw-r--r--drivers/net/pcmcia/xircom_tulip_cb.c38
-rw-r--r--drivers/net/pcnet32.c21
-rw-r--r--drivers/net/sis900.c27
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h1
-rw-r--r--drivers/net/sk98lin/skaddr.c16
-rw-r--r--drivers/net/smc9194.c35
-rw-r--r--drivers/net/starfire.c26
-rw-r--r--drivers/net/sunbmac.c20
-rw-r--r--drivers/net/sundance.c27
-rw-r--r--drivers/net/sungem.c21
-rw-r--r--drivers/net/sunhme.c38
-rw-r--r--drivers/net/sunlance.c27
-rw-r--r--drivers/net/sunqe.c21
-rw-r--r--drivers/net/tulip/tulip_core.c36
-rw-r--r--drivers/net/via-rhine.c21
-rw-r--r--drivers/net/winbond-840.c17
-rw-r--r--drivers/net/yellowfin.c24
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/tapedefs.h2
-rw-r--r--drivers/scsi/advansys.c9
-rw-r--r--drivers/scsi/constants.c1
-rw-r--r--drivers/scsi/hosts.c16
-rw-r--r--drivers/scsi/hosts.h15
-rw-r--r--drivers/scsi/ide-scsi.c8
-rw-r--r--drivers/scsi/scsi.c88
-rw-r--r--drivers/scsi/scsi_error.c49
-rw-r--r--drivers/scsi/scsi_ioctl.c1
-rw-r--r--drivers/scsi/scsi_lib.c5
-rw-r--r--drivers/scsi/scsi_merge.c1
-rw-r--r--drivers/scsi/scsi_proc.c1
-rw-r--r--drivers/scsi/scsi_queue.c5
-rw-r--r--drivers/scsi/scsi_scan.c1
-rw-r--r--drivers/scsi/scsi_syms.c1
-rw-r--r--drivers/scsi/scsicam.c1
-rw-r--r--drivers/scsi/sym53c8xx.c4
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c6
-rw-r--r--drivers/sound/ymfpci.c366
-rw-r--r--drivers/sound/ymfpci.h22
-rw-r--r--drivers/telephony/phonedev.c2
-rw-r--r--drivers/usb/Makefile.lib1
-rw-r--r--drivers/usb/catc.c9
-rw-r--r--fs/Makefile.lib2
-rw-r--r--fs/affs/file.c1
-rw-r--r--fs/block_dev.c1
-rw-r--r--fs/buffer.c43
-rw-r--r--fs/dcache.c2
-rw-r--r--fs/devfs/base.c150
-rw-r--r--fs/driverfs/inode.c2
-rw-r--r--fs/fat/cache.c2
-rw-r--r--fs/fat/inode.c4
-rw-r--r--fs/jbd/journal.c1
-rw-r--r--fs/jbd/revoke.c10
-rw-r--r--fs/jbd/transaction.c1
-rw-r--r--fs/jffs2/Makefile2
-rw-r--r--fs/jffs2/crc32.c97
-rw-r--r--fs/jffs2/crc32.h21
-rw-r--r--fs/jffs2/dir.c2
-rw-r--r--fs/jffs2/erase.c2
-rw-r--r--fs/jffs2/file.c2
-rw-r--r--fs/jffs2/gc.c2
-rw-r--r--fs/jffs2/read.c2
-rw-r--r--fs/jffs2/readinode.c2
-rw-r--r--fs/jffs2/scan.c2
-rw-r--r--fs/jffs2/write.c2
-rw-r--r--fs/namei.c5
-rw-r--r--fs/partitions/msdos.c4
-rw-r--r--fs/reiserfs/bitmap.c2
-rw-r--r--fs/reiserfs/journal.c83
-rw-r--r--fs/reiserfs/tail_conversion.c1
-rw-r--r--include/linux/blkdev.h4
-rw-r--r--include/linux/crc32.h17
-rw-r--r--include/linux/fs.h21
-rw-r--r--include/linux/limits.h2
-rw-r--r--include/linux/reiserfs_fs.h5
-rw-r--r--include/linux/reiserfs_fs_sb.h2
-rw-r--r--include/linux/swap.h6
-rw-r--r--kernel/ksyms.c2
-rw-r--r--lib/Config.in8
-rw-r--r--lib/Makefile7
-rw-r--r--lib/crc32.c571
-rw-r--r--mm/page_io.c15
-rw-r--r--mm/swapfile.c98
152 files changed, 3391 insertions, 1649 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 2b8c1e15f..77b10d17e 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -6275,6 +6275,18 @@ CONFIG_BLK_CPQ_CISS_DA
boards supported by this driver, and for further information
on the use of this driver.
+SCSI tape drive support for Smart Array 5xxx
+CONFIG_CISS_SCSI_TAPE
+ When enabled (Y), this option allows SCSI tape drives and SCSI medium
+ changers (tape robots) to be accessed via a Compaq 5xxx array
+ controller. (See Documentation/cciss.txt for more details.)
+
+ "SCSI support" and "SCSI tape support" must also be enabled for this
+ option to work.
+
+ When this option is disabled (N), the SCSI portion of the driver
+ is not compiled.
+
QuickNet Internet LineJack/PhoneJack support
CONFIG_PHONE_IXJ
Say M if you have a telephony card manufactured by Quicknet
@@ -24003,6 +24015,13 @@ CONFIG_GDB_CONSOLE
would like kernel messages to be formatted into GDB $O packets so
that GDB prints them as program output, say 'Y'.
+CRC32 functions
+CONFIG_CRC32
+ This option is provided for the case where no in-kernel-tree
+ modules require CRC32 functions, but a module built outside the
+ kernel tree does. Such modules that use library CRC32 functions
+ require M here.
+
802.1Q VLAN Support
CONFIG_VLAN_8021Q
Select this and you will be able to create 802.1Q VLAN interfaces on your
diff --git a/Documentation/block/request.txt b/Documentation/block/request.txt
new file mode 100644
index 000000000..b8de23598
--- /dev/null
+++ b/Documentation/block/request.txt
@@ -0,0 +1,86 @@
+
+struct request documentation
+
+Jens Axboe <axboe@suse.de> 070102
+
+1.0
+Index
+
+2.0 Struct request members classification
+
+ 2.1 struct request members explanation
+
+3.0
+
+
+2.0
+Short explanation of request members
+
+Classification flags:
+
+ D driver member
+ B block layer member
+ I I/O scheduler member
+
+Unless an entry contains a D classification, a device driver must not access
+this member. Some members may contain D classifications, but should only be
+access through certain macros or functions (eg ->flags).
+
+<linux/blkdev.h>
+
+2.1
+Member Flag Comment
+------ ---- -------
+
+struct list_head queuelist BI Organization on various internal
+ queues
+
+void *elevator_private I I/O scheduler private data
+
+unsigned char cmd[16] D Driver can use this for setting up
+ a cdb before execution, see
+ blk_queue_prep_rq
+
+unsigned long flags DBI Contains info about data direction,
+ request type, etc.
+
+int rq_status D Request status bits
+
+kdev_t rq_dev DBI Target device
+
+int errors DB Error counts
+
+sector_t sector DBI Target location
+
+unsigned long hard_nr_sectors B Used to keep sector sane
+
+unsigned long nr_sectors DBI Total number of sectors in request
+
+unsigned long hard_nr_sectors B Used to keep nr_sectors sane
+
+unsigned short nr_phys_segments DB Number of physical scatter gather
+ segments in a request
+
+unsigned short nr_hw_segments DB Number of hardware scatter gather
+ segments in a request
+
+unsigned int current_nr_sectors DB Number of sectors in first segment
+ of request
+
+unsigned int hard_cur_sectors B Used to keep current_nr_sectors sane
+
+void *special D Free to be used by driver
+
+char *buffer D Map of first segment, also see
+ section on bouncing SECTION
+
+struct completion *waiting D Can be used by driver to get signalled
+ on request completion
+
+struct bio *bio DBI First bio in request
+
+struct bio *biotail DBI Last bio in request
+
+request_queue_t *q DB Request queue this request belongs to
+
+struct request_list *rl B Request list this request came from
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index d8c95d579..8548f913e 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -100,7 +100,7 @@ lun used to address the device. Once this is done, the SCSI mid layer
can be informed of changes to the virtual SCSI bus which the driver
presents to it in the usual way. For example:
- echo add-single-device 3 2 1 0 > /proc/scsi/scsi
+ echo scsi add-single-device 3 2 1 0 > /proc/scsi/scsi
to add a device on controller 3, bus 2, target 1, lun 0. Note that
the driver makes an effort to preserve the devices positions
diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
index 407a684e9..de386c4ea 100644
--- a/Documentation/filesystems/devfs/ChangeLog
+++ b/Documentation/filesystems/devfs/ChangeLog
@@ -1863,3 +1863,9 @@ Changes for patch v205
- Defined macros for error and debug messages
- Updated README from master HTML file
+===============================================================================
+Changes for patch v206
+
+- Added support for multiple Compaq cpqarray controllers
+
+- Fixed (rare, old) race in <devfs_lookup>
diff --git a/Makefile b/Makefile
index fffcc6e58..5c2a8e1c6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 2
-EXTRAVERSION =-pre11
+EXTRAVERSION =
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -122,7 +122,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
NETWORKS =net/network.o
LIBS =$(TOPDIR)/lib/lib.a
-SUBDIRS =kernel drivers mm fs net ipc lib
+SUBDIRS =kernel lib drivers mm fs net ipc
DRIVERS-n :=
DRIVERS-y :=
@@ -261,9 +261,9 @@ vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o ini
$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
--start-group \
$(CORE_FILES) \
+ $(LIBS) \
$(DRIVERS) \
$(NETWORKS) \
- $(LIBS) \
--end-group \
-o vmlinux
$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 91f072a80..14ca220f5 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -393,3 +393,5 @@ else
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/arm/config.in b/arch/arm/config.in
index 02bcbfa8b..f71bf7120 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -709,3 +709,5 @@ dep_bool ' Kernel low-level debugging messages via footbridge serial port' CO
dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
dep_bool ' Kernel low-level debugging messages via SA1100 Ser3 (otherwise Ser1)' CONFIG_DEBUG_LL_SER3 $CONFIG_DEBUG_LL $CONFIG_ARCH_SA1100
endmenu
+
+source lib/Config.in
diff --git a/arch/cris/config.in b/arch/cris/config.in
index 5a9ee03de..660133597 100644
--- a/arch/cris/config.in
+++ b/arch/cris/config.in
@@ -251,3 +251,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 68a6cc9ca..aa1284ad5 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -419,3 +419,5 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index b95477775..11ce0b503 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -130,6 +130,7 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
@@ -831,3 +832,8 @@ CONFIG_USB_STORAGE=y
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 35372e1de..ad737acde 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -748,6 +748,7 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_WARNING "Use a PAE enabled kernel.\n");
else
printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+ max_pfn = MAXMEM_PFN;
#else /* !CONFIG_HIGHMEM */
#ifndef CONFIG_X86_PAE
if (max_pfn > MAX_NONPAE_PFN) {
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index fb0931f7b..dff81a6f0 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -234,6 +234,8 @@ endmenu
source drivers/usb/Config.in
+source lib/Config.in
+
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
source net/bluetooth/Config.in
fi
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index a65b213cd..44bc86f06 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -546,3 +546,5 @@ comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+
+source lib/Config.in
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 3136bd056..25b7fd9e4 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -520,3 +520,5 @@ if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 4ebb9f27a..5ddba84ff 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -276,3 +276,5 @@ if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/parisc/config.in b/arch/parisc/config.in
index f68410f66..367242b77 100644
--- a/arch/parisc/config.in
+++ b/arch/parisc/config.in
@@ -208,3 +208,4 @@ comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 3545adc66..7dfaf4d33 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -393,3 +393,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
endmenu
+
+source lib/Config.in
diff --git a/arch/s390/config.in b/arch/s390/config.in
index c545c3614..f5932ba5c 100644
--- a/arch/s390/config.in
+++ b/arch/s390/config.in
@@ -73,3 +73,4 @@ fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
diff --git a/arch/s390x/config.in b/arch/s390x/config.in
index 5a9c5b689..1ab8e3c23 100644
--- a/arch/s390x/config.in
+++ b/arch/s390x/config.in
@@ -77,3 +77,4 @@ fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
diff --git a/arch/sh/config.in b/arch/sh/config.in
index 7b70ccccd..32fb2212b 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -386,3 +386,5 @@ if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
fi
endmenu
+
+source lib/Config.in
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index cb3336e0e..a25231961 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.111 2001-06-01 08:12:10 davem Exp $
+# $Id: config.in,v 1.112 2002-01-15 06:25:50 davem Exp $
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/config-language.txt.
#
@@ -266,3 +266,5 @@ comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+
+source lib/Config.in
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 1ebda5ea8..1ccb32ffe 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -289,7 +289,7 @@ CONFIG_EFS_FS=m
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
@@ -403,3 +403,8 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# Kernel hacking
#
# CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 3ff8f9448..2d80c59f8 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -869,3 +869,8 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_DCFLUSH is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 7902e3fc7..c78754672 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -35,6 +35,7 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
fi
dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI
+dep_mbool ' SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index e2792736f..35543c2fa 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -126,6 +126,8 @@ static struct block_device_operations cciss_fops = {
revalidate: frevalidate_logvol,
};
+#include "cciss_scsi.c" /* For SCSI tape support */
+
/*
* Report information about this controller.
*/
@@ -160,6 +162,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
pos += size; len += size;
+ cciss_proc_tape_report(ctlr, buffer, &pos, &len);
for(i=0; i<h->num_luns; i++) {
drv = &h->drv[i];
size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
@@ -179,20 +182,53 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
return len;
}
+static int
+cciss_proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ unsigned char cmd[80];
+ int len;
+#ifdef CONFIG_CISS_SCSI_TAPE
+ ctlr_info_t *h = (ctlr_info_t *) data;
+ int rc;
+#endif
+
+ if (count > sizeof(cmd)-1) return -EINVAL;
+ if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+ cmd[count] = '\0';
+ len = strlen(cmd); // above 3 lines ensure safety
+ if (cmd[len-1] == '\n')
+ cmd[--len] = '\0';
+# ifdef CONFIG_CISS_SCSI_TAPE
+ if (strcmp("engage scsi", cmd)==0) {
+ rc = cciss_engage_scsi(h->ctlr);
+ if (rc != 0) return -rc;
+ return count;
+ }
+ /* might be nice to have "disengage" too, but it's not
+ safely possible. (only 1 module use count, lock issues.) */
+# endif
+ return -EINVAL;
+}
+
/*
* Get us a file in /proc/cciss that says something about each controller.
* Create /proc/cciss if it doesn't exist yet.
*/
static void __init cciss_procinit(int i)
{
+ struct proc_dir_entry *pde;
+
if (proc_cciss == NULL) {
proc_cciss = proc_mkdir("cciss", proc_root_driver);
if (!proc_cciss)
return;
}
- create_proc_read_entry(hba[i]->devname, 0, proc_cciss,
- cciss_proc_get_info, hba[i]);
+ pde = create_proc_read_entry(hba[i]->devname,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+ proc_cciss, cciss_proc_get_info, hba[i]);
+ pde->write_proc = cciss_proc_write;
}
#endif /* CONFIG_PROC_FS */
@@ -824,9 +860,12 @@ static int sendcmd(
int ctlr,
void *buff,
size_t size,
- unsigned int use_unit_num,
+ unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
unsigned int log_unit,
- __u8 page_code )
+ __u8 page_code,
+ unsigned char *scsi3addr)
{
CommandList_struct *c;
int i;
@@ -860,15 +899,23 @@ static int sendcmd(
to controller so It's a physical command
mode = 0 target = 0.
So we have nothing to write.
- Otherwise
- mode = 1 target = LUNID
+ otherwise, if use_unit_num == 1,
+ mode = 1(volume set addressing) target = LUNID
+ otherwise, if use_unit_num == 2,
+ mode = 0(periph dev addr) target = scsi3addr
*/
- if(use_unit_num != 0)
+ if(use_unit_num == 1)
{
c->Header.LUN.LogDev.VolId=
hba[ctlr]->drv[log_unit].LunID;
c->Header.LUN.LogDev.Mode = 1;
}
+ else if (use_unit_num == 2)
+ {
+ memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+ c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+ }
+
/* are we trying to read a vital product page */
if(page_code != 0)
{
@@ -884,6 +931,7 @@ static int sendcmd(
c->Request.CDB[4] = size & 0xFF;
break;
case CISS_REPORT_LOG:
+ case CISS_REPORT_PHYS:
/* Talking to controller so It's a physical command
mode = 00 target = 0.
So we have nothing to write.
@@ -893,7 +941,7 @@ static int sendcmd(
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ; // Read
c->Request.Timeout = 0; // Don't time out
- c->Request.CDB[0] = CISS_REPORT_LOG;
+ c->Request.CDB[0] = cmd;
c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
@@ -971,6 +1019,7 @@ static int sendcmd(
ignore it
*/
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
+ (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
(c->Request.CDB[0] == CISS_INQUIRY)) &&
((c->err_info->CommandStatus ==
CMD_DATA_OVERRUN) ||
@@ -1356,6 +1405,10 @@ static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
} else if (c->cmd_type == CMD_IOCTL_PEND) {
c->cmd_type = CMD_IOCTL_DONE;
}
+# ifdef CONFIG_CISS_SCSI_TAPE
+ else if (c->cmd_type == CMD_SCSI)
+ complete_scsi_command(c, 0, a1);
+# endif
continue;
}
}
@@ -1592,7 +1645,7 @@ static void cciss_getgeometry(int cntl_num)
}
/* Get the firmware version */
return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 0, 0 ,0 );
+ sizeof(InquiryData_struct), 0, 0 ,0, NULL );
if (return_code == IO_OK)
{
hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
@@ -1606,7 +1659,7 @@ static void cciss_getgeometry(int cntl_num)
}
/* Get the number of logical volumes */
return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0 );
+ sizeof(ReportLunData_struct), 0, 0, 0, NULL );
if( return_code == IO_OK)
{
@@ -1652,7 +1705,7 @@ static void cciss_getgeometry(int cntl_num)
memset(size_buff, 0, sizeof(ReadCapdata_struct));
return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff,
- sizeof( ReadCapdata_struct), 1, i, 0 );
+ sizeof( ReadCapdata_struct), 1, i, 0, NULL );
if (return_code == IO_OK)
{
total_size = (0xff &
@@ -1684,7 +1737,7 @@ static void cciss_getgeometry(int cntl_num)
/* Execute the command to read the disk geometry */
memset(inq_buff, 0, sizeof(InquiryData_struct));
return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 1, i ,0xC1 );
+ sizeof(InquiryData_struct), 1, i ,0xC1, NULL );
if (return_code == IO_OK)
{
if(inq_buff->data_byte[8] == 0xFF)
@@ -1860,6 +1913,8 @@ static int __init cciss_init_one(struct pci_dev *pdev,
cciss_getgeometry(i);
+ cciss_find_non_disk_devices(i); /* find our tape drives, if any */
+
/* Turn the interrupts on so we can service requests */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
@@ -1901,6 +1956,8 @@ static int __init cciss_init_one(struct pci_dev *pdev,
MAX_PART, &cciss_fops,
hba[i]->drv[j].nr_blocks);
+ cciss_register_scsi(i, 1); /* hook ourself into SCSI subsystem */
+
return(1);
}
@@ -1927,6 +1984,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
free_irq(hba[i]->intr, hba[i]);
pci_set_drvdata(pdev, NULL);
iounmap((void*)hba[i]->vaddr);
+ cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
remove_proc_entry(hba[i]->devname, proc_cciss);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 1dafe1ec5..c6eb34da2 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -83,6 +83,9 @@ struct ctlr_info
struct hd_struct hd[256];
int sizes[256];
int blocksizes[256];
+#ifdef CONFIG_CISS_SCSI_TAPE
+ void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
+#endif
};
/* Defining the diffent access_menthods */
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index 7faf6f05c..6ba126d3d 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -89,6 +89,7 @@ typedef union _u64bit
//STRUCTURES
//###########################################################################
#define CISS_MAX_LUN 16
+#define CISS_MAX_PHYS_LUN 1024
// SCSI-3 Cmmands
#pragma pack(1)
@@ -101,6 +102,7 @@ typedef struct _InquiryData_struct
} InquiryData_struct;
#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */
+#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */
// Data returned
typedef struct _ReportLUNdata_struct
{
@@ -215,6 +217,9 @@ typedef struct _ErrorInfo_struct {
#define CMD_RWREQ 0x00
#define CMD_IOCTL_PEND 0x01
#define CMD_IOCTL_DONE 0x02
+#define CMD_SCSI 0x03
+#define CMD_MSG_DONE 0x04
+#define CMD_MSG_TIMEOUT 0x05
typedef struct _CommandList_struct {
CommandListHeader_struct Header;
@@ -229,6 +234,9 @@ typedef struct _CommandList_struct {
struct _CommandList_struct *prev;
struct _CommandList_struct *next;
struct request * rq;
+#ifdef CONFIG_CISS_SCSI_TAPE
+ void * scsi_cmd;
+#endif
} CommandList_struct;
//Configuration Table Structure
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
new file mode 100644
index 000000000..5951c9167
--- /dev/null
+++ b/drivers/block/cciss_scsi.c
@@ -0,0 +1,1631 @@
+/*
+ * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ * Copyright 2001 Compaq Computer Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ * Author: Stephen M. Cameron
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+
+/* Here we have code to present the driver as a scsi driver
+ as it is simultaneously presented as a block driver. The
+ reason for doing this is to allow access to SCSI tape drives
+ through the array controller. Note in particular, neither
+ physical nor logical disks are presented through the scsi layer. */
+
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include <asm/atomic.h>
+#include <linux/timer.h>
+
+#include "cciss_scsi.h"
+
+/* some prototypes... */
+static int sendcmd(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: address is in scsi3addr */
+ unsigned int log_unit,
+ __u8 page_code,
+ unsigned char *scsi3addr );
+
+
+int __init cciss_scsi_detect(Scsi_Host_Template *tpnt);
+int cciss_scsi_release(struct Scsi_Host *sh);
+const char *cciss_scsi_info(struct Scsi_Host *sa);
+
+int cciss_scsi_proc_info(
+ char *buffer, /* data buffer */
+ char **start, /* where data in buffer starts */
+ off_t offset, /* offset from start of imaginary file */
+ int length, /* length of data in buffer */
+ int hostnum, /* which host adapter (always zero for me) */
+ int func); /* 0 == read, 1 == write */
+
+int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *));
+#if 0
+int cciss_scsi_abort(Scsi_Cmnd *cmd);
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+int cciss_scsi_reset(Scsi_Cmnd *cmd, unsigned int reset_flags);
+#else
+int cciss_scsi_reset(Scsi_Cmnd *cmd);
+#endif
+#endif
+
+static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
+ { name: "cciss0", ndevices: 0 },
+ { name: "cciss1", ndevices: 0 },
+ { name: "cciss2", ndevices: 0 },
+ { name: "cciss3", ndevices: 0 },
+ { name: "cciss4", ndevices: 0 },
+ { name: "cciss5", ndevices: 0 },
+ { name: "cciss6", ndevices: 0 },
+ { name: "cciss7", ndevices: 0 },
+};
+
+/* We need one Scsi_Host_Template *per controller* instead of
+ the usual one Scsi_Host_Template per controller *type*. This
+ is so PCI hot plug could have a remote possibility of still
+ working even with the SCSI system. It's so
+ scsi_unregister_host will differentiate the controllers.
+ When register_scsi_module is called, each host template is
+ customized (name change) in cciss_register_scsi()
+ (that's called from cciss.c:cciss_init_one()) */
+
+static
+Scsi_Host_Template driver_template[MAX_CTLR] =
+{
+ CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+ CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+};
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_elem_t {
+ CommandList_struct cmd;
+ ErrorInfo_struct Err;
+ __u32 busaddr;
+};
+
+#pragma pack()
+
+#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
+ CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
+ // plus two for init time usage
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_t {
+ struct cciss_scsi_cmd_stack_elem_t *pool;
+ struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+ dma_addr_t cmd_pool_handle;
+ int top;
+};
+#pragma pack()
+
+struct cciss_scsi_adapter_data_t {
+ struct Scsi_Host *scsi_host;
+ struct cciss_scsi_cmd_stack_t cmd_stack;
+ int registered;
+ spinlock_t lock; // to protect ccissscsi[ctlr];
+};
+
+#define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
+ &(((struct cciss_scsi_adapter_data_t *) \
+ hba[ctlr]->scsi_ctlr)->lock), flags);
+#define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
+ &(((struct cciss_scsi_adapter_data_t *) \
+ hba[ctlr]->scsi_ctlr)->lock), flags);
+
+static CommandList_struct *
+scsi_cmd_alloc(ctlr_info_t *h)
+{
+ /* assume only one process in here at a time, locking done by caller. */
+ /* use CCISS_LOCK(ctlr) */
+ /* might be better to rewrite how we allocate scsi commands in a way that */
+ /* needs no locking at all. */
+
+ /* take the top memory chunk off the stack and return it, if any. */
+ struct cciss_scsi_cmd_stack_elem_t *c;
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ u64bit temp64;
+
+ sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ if (stk->top < 0)
+ return NULL;
+ c = stk->elem[stk->top];
+ /* memset(c, 0, sizeof(*c)); */
+ memset(&c->cmd, 0, sizeof(c->cmd));
+ memset(&c->Err, 0, sizeof(c->Err));
+ /* set physical addr of cmd and addr of scsi parameters */
+ c->cmd.busaddr = c->busaddr;
+ /* (__u32) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
+
+ temp64.val = (__u64) (c->busaddr + sizeof(CommandList_struct));
+ /* (__u64) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top) +
+ sizeof(CommandList_struct)); */
+ stk->top--;
+ c->cmd.ErrDesc.Addr.lower = temp64.val32.lower;
+ c->cmd.ErrDesc.Addr.upper = temp64.val32.upper;
+ c->cmd.ErrDesc.Len = sizeof(ErrorInfo_struct);
+
+ c->cmd.ctlr = h->ctlr;
+ c->cmd.err_info = &c->Err;
+
+ return (CommandList_struct *) c;
+}
+
+static void
+scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
+{
+ /* assume only one process in here at a time, locking done by caller. */
+ /* use CCISS_LOCK(ctlr) */
+ /* drop the free memory chunk on top of the stack. */
+
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+
+ sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ if (stk->top >= CMD_STACK_SIZE) {
+ printk("cciss: scsi_cmd_free called too many times.\n");
+ BUG();
+ }
+ stk->top++;
+ stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
+}
+
+static int
+scsi_cmd_stack_setup(int ctlr)
+{
+ int i;
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ size_t size;
+
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+ // pci_alloc_consistent guarentees 32-bit DMA address will
+ // be used
+
+ stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
+ pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
+
+ if (stk->pool == NULL) {
+ printk("stk->pool is null\n");
+ return -1;
+ }
+
+ for (i=0; i<CMD_STACK_SIZE; i++) {
+ stk->elem[i] = &stk->pool[i];
+ stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+ }
+ stk->top = CMD_STACK_SIZE-1;
+ return 0;
+}
+
+static void
+scsi_cmd_stack_free(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ size_t size;
+
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ if (stk->top != CMD_STACK_SIZE-1) {
+ printk( "cciss: %d scsi commands are still outstanding.\n",
+ CMD_STACK_SIZE - stk->top);
+ // BUG();
+ printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+ (unsigned int) stk);
+ }
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+ pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
+ stk->pool = NULL;
+}
+
+/* scsi_device_types comes from scsi.h */
+#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
+ "Unknown" : scsi_device_types[n]
+
+#if 0
+static int xmargin=8;
+static int amargin=60;
+
+static void
+print_bytes (unsigned char *c, int len, int hex, int ascii)
+{
+
+ int i;
+ unsigned char *x;
+
+ if (hex)
+ {
+ x = c;
+ for (i=0;i<len;i++)
+ {
+ if ((i % xmargin) == 0 && i>0) printk("\n");
+ if ((i % xmargin) == 0) printk("0x%04x:", i);
+ printk(" %02x", *x);
+ x++;
+ }
+ printk("\n");
+ }
+ if (ascii)
+ {
+ x = c;
+ for (i=0;i<len;i++)
+ {
+ if ((i % amargin) == 0 && i>0) printk("\n");
+ if ((i % amargin) == 0) printk("0x%04x:", i);
+ if (*x > 26 && *x < 128) printk("%c", *x);
+ else printk(".");
+ x++;
+ }
+ printk("\n");
+ }
+}
+
+static void
+print_cmd(CommandList_struct *cp)
+{
+ printk("queue:%d\n", cp->Header.ReplyQueue);
+ printk("sglist:%d\n", cp->Header.SGList);
+ printk("sgtot:%d\n", cp->Header.SGTotal);
+ printk("Tag:0x%08x/0x%08x\n", cp->Header.Tag.upper,
+ cp->Header.Tag.lower);
+ printk("LUN:0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ cp->Header.LUN.LunAddrBytes[0],
+ cp->Header.LUN.LunAddrBytes[1],
+ cp->Header.LUN.LunAddrBytes[2],
+ cp->Header.LUN.LunAddrBytes[3],
+ cp->Header.LUN.LunAddrBytes[4],
+ cp->Header.LUN.LunAddrBytes[5],
+ cp->Header.LUN.LunAddrBytes[6],
+ cp->Header.LUN.LunAddrBytes[7]);
+ printk("CDBLen:%d\n", cp->Request.CDBLen);
+ printk("Type:%d\n",cp->Request.Type.Type);
+ printk("Attr:%d\n",cp->Request.Type.Attribute);
+ printk(" Dir:%d\n",cp->Request.Type.Direction);
+ printk("Timeout:%d\n",cp->Request.Timeout);
+ printk( "CDB: %02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ cp->Request.CDB[0], cp->Request.CDB[1],
+ cp->Request.CDB[2], cp->Request.CDB[3],
+ cp->Request.CDB[4], cp->Request.CDB[5],
+ cp->Request.CDB[6], cp->Request.CDB[7],
+ cp->Request.CDB[8], cp->Request.CDB[9],
+ cp->Request.CDB[10], cp->Request.CDB[11],
+ cp->Request.CDB[12], cp->Request.CDB[13],
+ cp->Request.CDB[14], cp->Request.CDB[15]),
+ printk("edesc.Addr: 0x%08x/0%08x, Len = %d\n",
+ cp->ErrDesc.Addr.upper, cp->ErrDesc.Addr.lower,
+ cp->ErrDesc.Len);
+ printk("sgs..........Errorinfo:\n");
+ printk("scsistatus:%d\n", cp->err_info->ScsiStatus);
+ printk("senselen:%d\n", cp->err_info->SenseLen);
+ printk("cmd status:%d\n", cp->err_info->CommandStatus);
+ printk("resid cnt:%d\n", cp->err_info->ResidualCnt);
+ printk("offense size:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_size);
+ printk("offense byte:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_num);
+ printk("offense value:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+
+}
+
+#endif
+
+static int
+find_bus_target_lun(int ctlr, int *bus, int *target, int *lun)
+{
+ /* finds an unused bus, target, lun for a new device */
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int i, found=0;
+ unsigned char target_taken[CCISS_MAX_SCSI_DEVS_PER_HBA];
+
+ memset(&target_taken[0], 0, CCISS_MAX_SCSI_DEVS_PER_HBA);
+
+ target_taken[SELF_SCSI_ID] = 1;
+ for (i=0;i<ccissscsi[ctlr].ndevices;i++)
+ target_taken[ccissscsi[ctlr].dev[i].target] = 1;
+
+ for (i=0;i<CCISS_MAX_SCSI_DEVS_PER_HBA;i++) {
+ if (!target_taken[i]) {
+ *bus = 0; *target=i; *lun = 0; found=1;
+ break;
+ }
+ }
+ return (!found);
+}
+
+static int
+cciss_scsi_add_entry(int ctlr, int hostno,
+ unsigned char *scsi3addr, int devtype)
+{
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int n = ccissscsi[ctlr].ndevices;
+ struct cciss_scsi_dev_t *sd;
+
+ if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
+ printk("cciss%d: Too many devices, "
+ "some will be inaccessible.\n", ctlr);
+ return -1;
+ }
+ sd = &ccissscsi[ctlr].dev[n];
+ if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0)
+ return -1;
+ memcpy(&sd->scsi3addr[0], scsi3addr, 8);
+ sd->devtype = devtype;
+ ccissscsi[ctlr].ndevices++;
+
+ /* initially, (before registering with scsi layer) we don't
+ know our hostno and we don't want to print anything first
+ time anyway (the scsi layer's inquiries will show that info) */
+ if (hostno != -1)
+ printk("cciss%d: %s device c%db%dt%dl%d added.\n",
+ ctlr, DEVICETYPE(sd->devtype), hostno,
+ sd->bus, sd->target, sd->lun);
+ return 0;
+}
+
+static void
+cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
+{
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int i;
+ struct cciss_scsi_dev_t sd;
+
+ if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
+ sd = ccissscsi[ctlr].dev[entry];
+ for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
+ ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
+ ccissscsi[ctlr].ndevices--;
+ printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+ ctlr, DEVICETYPE(sd.devtype), hostno,
+ sd.bus, sd.target, sd.lun);
+}
+
+
+#define SCSI3ADDR_EQ(a,b) ( \
+ (a)[7] == (b)[7] && \
+ (a)[6] == (b)[6] && \
+ (a)[5] == (b)[5] && \
+ (a)[4] == (b)[4] && \
+ (a)[3] == (b)[3] && \
+ (a)[2] == (b)[2] && \
+ (a)[1] == (b)[1] && \
+ (a)[0] == (b)[0])
+
+static int
+adjust_cciss_scsi_table(int ctlr, int hostno,
+ struct cciss_scsi_dev_t sd[], int nsds)
+{
+ /* sd contains scsi3 addresses and devtypes, but
+ bus target and lun are not filled in. This funciton
+ takes what's in sd to be the current and adjusts
+ ccissscsi[] to be in line with what's in sd. */
+
+ int i,j, found, changes=0;
+ struct cciss_scsi_dev_t *csd;
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+
+ /* find any devices in ccissscsi[] that are not in
+ sd[] and remove them from ccissscsi[] */
+
+ i = 0;
+ while(i<ccissscsi[ctlr].ndevices) {
+ csd = &ccissscsi[ctlr].dev[i];
+ found=0;
+ for (j=0;j<nsds;j++) {
+ if (SCSI3ADDR_EQ(sd[j].scsi3addr,
+ csd->scsi3addr)) {
+ if (sd[j].devtype == csd->devtype)
+ found=2;
+ else
+ found=1;
+ break;
+ }
+ }
+
+ if (found == 0) { /* device no longer present. */
+ changes++;
+ /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+ ctlr, DEVICETYPE(csd->devtype), hostno,
+ csd->bus, csd->target, csd->lun); */
+ cciss_scsi_remove_entry(ctlr, hostno, i);
+ /* note, i not incremented */
+ }
+ else if (found == 1) { /* device is different kind */
+ changes++;
+ printk("cciss%d: device c%db%dt%dl%d type changed "
+ "(device type now %s).\n",
+ ctlr, hostno, csd->bus, csd->target, csd->lun,
+ DEVICETYPE(csd->devtype));
+ csd->devtype = sd[j].devtype;
+ i++; /* so just move along. */
+ } else /* device is same as it ever was, */
+ i++; /* so just move along. */
+ }
+
+ /* Now, make sure every device listed in sd[] is also
+ listed in ccissscsi[], adding them if they aren't found */
+
+ for (i=0;i<nsds;i++) {
+ found=0;
+ for (j=0;j<ccissscsi[ctlr].ndevices;j++) {
+ csd = &ccissscsi[ctlr].dev[j];
+ if (SCSI3ADDR_EQ(sd[i].scsi3addr,
+ csd->scsi3addr)) {
+ if (sd[i].devtype == csd->devtype)
+ found=2; /* found device */
+ else
+ found=1; /* found a bug. */
+ break;
+ }
+ }
+ if (!found) {
+ changes++;
+ if (cciss_scsi_add_entry(ctlr, hostno,
+ &sd[i].scsi3addr[0], sd[i].devtype) != 0)
+ break;
+ } else if (found == 1) {
+ /* should never happen... */
+ changes++;
+ printk("cciss%d: device unexpectedly changed type\n",
+ ctlr);
+ /* but if it does happen, we just ignore that device */
+ }
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+
+ if (!changes)
+ printk("cciss%d: No device changes detected.\n", ctlr);
+
+ return 0;
+}
+
+static int
+lookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr)
+{
+ int i;
+ struct cciss_scsi_dev_t *sd;
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ for (i=0;i<ccissscsi[ctlr].ndevices;i++) {
+ sd = &ccissscsi[ctlr].dev[i];
+ if (sd->bus == bus &&
+ sd->target == target &&
+ sd->lun == lun) {
+ memcpy(scsi3addr, &sd->scsi3addr[0], 8);
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return 0;
+ }
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return -1;
+}
+
+
+static void
+cciss_find_non_disk_devices(int cntl_num)
+{
+ ReportLunData_struct *ld_buff;
+ InquiryData_struct *inq_buff;
+ int return_code;
+ int i;
+ int listlength = 0;
+ int num_luns;
+ unsigned char scsi3addr[8];
+ unsigned long flags;
+ int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+
+ hba[cntl_num]->scsi_ctlr = (void *)
+ kmalloc(sizeof(struct cciss_scsi_adapter_data_t),
+ GFP_KERNEL);
+ if (hba[cntl_num]->scsi_ctlr == NULL)
+ return;
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->scsi_host = NULL;
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->lock = SPIN_LOCK_UNLOCKED;
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->registered = 0;
+
+ if (scsi_cmd_stack_setup(cntl_num) != 0) {
+ printk("Trouble, returned non-zero!\n");
+ return;
+ }
+
+ ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+ memset(ld_buff, 0, sizeof(ReportLunData_struct));
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return;
+ }
+
+ /* Get the physical luns */
+ return_code = sendcmd(CISS_REPORT_PHYS, cntl_num, ld_buff,
+ reportlunsize, 0, 0, 0, NULL );
+
+ if( return_code == IO_OK) {
+ unsigned char *c = &ld_buff->LUNListLength[0];
+ listlength = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+ }
+ else { /* getting report of physical luns failed */
+ printk(KERN_WARNING "cciss: report physical luns"
+ " command failed\n");
+ listlength = 0;
+ }
+
+ CPQ_TAPE_LOCK(cntl_num, flags);
+ ccissscsi[cntl_num].ndevices = 0;
+ num_luns = listlength / 8; // 8 bytes pre entry
+ /* printk("Found %d LUNs\n", num_luns); */
+
+ if (num_luns > CISS_MAX_PHYS_LUN)
+ {
+ printk(KERN_WARNING
+ "cciss: Maximum physical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN,
+ num_luns - CISS_MAX_PHYS_LUN);
+ num_luns = CISS_MAX_PHYS_LUN;
+ }
+
+ for(i=0; i<num_luns; i++) {
+ /* Execute an inquiry to figure the device type */
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ memcpy(scsi3addr, ld_buff->LUN[i], 8); /* ugly... */
+ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+ sizeof(InquiryData_struct), 2, 0 ,0, scsi3addr );
+ if (return_code == IO_OK) {
+ if(inq_buff->data_byte[8] == 0xFF)
+ {
+ printk(KERN_WARNING "cciss: inquiry failed\n");
+ } else {
+ int devtype;
+
+ /* printk("Inquiry...\n");
+ print_bytes((unsigned char *) inq_buff, 36, 1, 1); */
+ devtype = (inq_buff->data_byte[0] & 0x1f);
+
+ switch (devtype)
+ {
+ case 0x01: /* sequential access, (tape) */
+ case 0x08: /* medium changer */
+ /* this is the only kind of dev */
+ /* we want to expose here. */
+ if (cciss_scsi_add_entry(cntl_num, -1,
+ (unsigned char *) ld_buff->LUN[i],
+ devtype) != 0)
+ i=num_luns; // leave loop
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+ else printk("cciss: inquiry failed.\n");
+ }
+#if 0
+ for (i=0;i<ccissscsi[cntl_num].ndevices;i++)
+ printk("Tape device presented at c%db%dt%dl%d\n",
+ cntl_num, // <-- this is wrong
+ ccissscsi[cntl_num].dev[i].bus,
+ ccissscsi[cntl_num].dev[i].target,
+ ccissscsi[cntl_num].dev[i].lun);
+#endif
+ CPQ_TAPE_UNLOCK(cntl_num, flags);
+ kfree(ld_buff);
+ kfree(inq_buff);
+ return;
+}
+
+static void
+complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
+{
+ Scsi_Cmnd *cmd;
+ ctlr_info_t *ctlr;
+ u64bit addr64;
+ ErrorInfo_struct *ei;
+
+ ei = cp->err_info;
+
+ /* First, see if it was a message rather than a command */
+ if (cp->Request.Type.Type == TYPE_MSG) {
+ cp->cmd_type = CMD_MSG_DONE;
+ return;
+ }
+
+ cmd = (Scsi_Cmnd *) cp->scsi_cmd;
+ ctlr = hba[cp->ctlr];
+
+ /* undo the DMA mappings */
+
+ if (cmd->use_sg) {
+ pci_unmap_sg(ctlr->pdev,
+ cmd->buffer, cmd->use_sg,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+ else if (cmd->request_bufflen) {
+ addr64.val32.lower = cp->SG[0].Addr.lower;
+ addr64.val32.upper = cp->SG[0].Addr.upper;
+ pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+
+ cmd->result = (DID_OK << 16); /* host byte */
+ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ /* cmd->result |= (GOOD < 1); */ /* status byte */
+
+ cmd->result |= (ei->ScsiStatus);
+ /* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus); */
+
+ /* copy the sense data whether we need to or not. */
+
+ memcpy(cmd->sense_buffer, ei->SenseInfo,
+ ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
+ SCSI_SENSE_BUFFERSIZE :
+ ei->SenseLen);
+ cmd->resid = ei->ResidualCnt;
+
+ if(ei->CommandStatus != 0)
+ { /* an error has occurred */
+ switch(ei->CommandStatus)
+ {
+ case CMD_TARGET_STATUS:
+ /* Pass it up to the upper layers... */
+ if( ei->ScsiStatus)
+ {
+#if 0
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ cp,
+ ei->ScsiStatus);
+#endif
+ cmd->result |= (ei->ScsiStatus < 1);
+ }
+ else { /* scsi status is zero??? How??? */
+
+ /* Ordinarily, this case should never happen, but there is a bug
+ in some released firmware revisions that allows it to happen
+ if, for example, a 4100 backplane loses power and the tape
+ drive is in it. We assume that it's a fatal error of some
+ kind because we can't show that it wasn't. We will make it
+ look like selection timeout since that is the most common
+ reason for this to occur, and it's severe enough. */
+
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ break;
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cp %p has"
+ " completed with data overrun "
+ "reported\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* print_bytes(cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ /* We get CMD_INVALID if you address a non-existent tape drive instead
+ of a selection timeout (no response). You will see this if you yank
+ out a tape drive, then try to access it. This is kind of a shame
+ because it means that any other CMD_INVALID (e.g. driver bug) will
+ get interpreted as a missing target. */
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cp %p has "
+ "protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p had "
+ " hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p had "
+ "connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ cmd->result = DID_ABORT << 16;
+ printk(KERN_WARNING "cciss: cp %p was "
+ "aborted\n", cp);
+ break;
+ case CMD_ABORT_FAILED:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p reports "
+ "abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ cmd->result = DID_ABORT << 16;
+ printk(KERN_WARNING "cciss: cp %p aborted "
+ "do to an unsolicited abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ cmd->result = DID_TIME_OUT << 16;
+ printk(KERN_WARNING "cciss: cp %p timedout\n",
+ cp);
+ break;
+ default:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p returned "
+ "unknown status %x\n", cp,
+ ei->CommandStatus);
+ }
+ }
+ // printk("c:%p:c%db%dt%dl%d ", cmd, ctlr->ctlr, cmd->channel,
+ // cmd->target, cmd->lun);
+ cmd->scsi_done(cmd);
+ scsi_cmd_free(ctlr, cp);
+}
+
+/* cciss_scsi_detect is called from the scsi mid layer.
+ The scsi mid layer (scsi_register_host) is
+ called from cciss.c:cciss_init_one(). */
+
+int __init
+cciss_scsi_detect(Scsi_Host_Template *tpnt)
+{
+ int i;
+ struct Scsi_Host *sh;
+
+ /* Tell the kernel we want to be a SCSI driver... */
+ sh = scsi_register(tpnt, sizeof(struct ctlr_info *));
+ if (sh == NULL) return 0;
+
+ sh->io_port = 0; // good enough? FIXME,
+ sh->n_io_port = 0; // I don't think we use these two...
+
+ sh->this_id = SELF_SCSI_ID;
+
+ /* This is a bit kludgey, using the adapter name to figure out */
+ /* which scsi host template we've got, won't scale beyond 9 ctlrs. */
+ i = tpnt->name[5] - '0';
+
+# if MAX_CTLR > 9
+# error "cciss_scsi.c: MAX_CTLR > 9, code maintenance needed."
+# endif
+
+ if (i<0 || i>=MAX_CTLR || hba[i] == NULL) {
+ /* we didn't find ourself... we shouldn't get here. */
+ printk("cciss_scsi_detect: could not find ourself in hba[]\n");
+ return 0;
+ }
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[i]->scsi_ctlr)->scsi_host = (void *) sh;
+ sh->hostdata[0] = (unsigned long) hba[i];
+ sh->irq = hba[i]->intr;
+ sh->unique_id = sh->irq;
+ scsi_set_pci_device(sh, hba[i]->pdev);
+
+ return 1; /* Say we have 1 scsi adapter, this will be */
+ /* called multiple times, once for each adapter */
+ /* from cciss.c:cciss_init_one(). We do it this */
+ /* way for PCI-hot plug reasons. (we don't know how */
+ /* many adapters we have total, so we say we have */
+ /* 1, each of a unique type.) */
+}
+
+static void __exit cleanup_cciss_module(void);
+int
+cciss_scsi_release(struct Scsi_Host *sh)
+{
+ return 0;
+}
+
+static void
+cciss_unmap_one(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ size_t buflen,
+ int data_direction)
+{
+ u64bit addr64;
+
+ addr64.val32.lower = cp->SG[0].Addr.lower;
+ addr64.val32.upper = cp->SG[0].Addr.upper;
+ pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction);
+}
+
+static void
+cciss_map_one(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ unsigned char *buf,
+ size_t buflen,
+ int data_direction)
+{
+ __u64 addr64;
+
+ addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
+ cp->SG[0].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Len = buflen;
+ cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
+}
+
+static int
+cciss_scsi_do_simple_cmd(ctlr_info_t *c,
+ CommandList_struct *cp,
+ unsigned char *scsi3addr,
+ unsigned char *cdb,
+ unsigned char cdblen,
+ unsigned char *buf, int bufsize,
+ int direction)
+{
+ unsigned long flags;
+
+ cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
+ cp->scsi_cmd = NULL;
+ cp->Header.ReplyQueue = 0; // unused in simple mode
+ memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN));
+ cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
+ // Fill in the request block...
+
+ /* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n",
+ scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
+ scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */
+
+ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+ memcpy(cp->Request.CDB, cdb, cdblen);
+ cp->Request.Timeout = 1000; // guarantee completion.
+ cp->Request.CDBLen = cdblen;
+ cp->Request.Type.Type = TYPE_CMD;
+ cp->Request.Type.Attribute = ATTR_SIMPLE;
+ cp->Request.Type.Direction = direction;
+
+ /* Fill in the SG list and do dma mapping */
+ cciss_map_one(c->pdev, cp,
+ (unsigned char *) buf, bufsize,
+ scsi_to_pci_dma_dir(SCSI_DATA_READ));
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ addQ(&c->reqQ, cp);
+ c->Qdepth++;
+ start_io(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+
+ /* Wait for the request to complete */
+ while(cp->cmd_type != CMD_IOCTL_DONE)
+ schedule_timeout(1);
+
+ /* undo the dma mapping */
+ cciss_unmap_one(c->pdev, cp, bufsize,
+ scsi_to_pci_dma_dir(SCSI_DATA_READ));
+
+ return(0);
+}
+
+static void
+cciss_scsi_interpret_error(CommandList_struct *cp)
+{
+ ErrorInfo_struct *ei;
+
+ ei = cp->err_info;
+ switch(ei->CommandStatus)
+ {
+ case CMD_TARGET_STATUS:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "completed with errors\n", cp);
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ cp,
+ ei->ScsiStatus);
+ if (ei->ScsiStatus == 0)
+ printk(KERN_WARNING
+ "cciss:SCSI status is abnormally zero. "
+ "(probably indicates selection timeout "
+ "reported incorrectly due to a known "
+ "firmware bug, circa July, 2001.)\n");
+ break;
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ printk("UNDERRUN\n");
+ break;
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cp %p has"
+ " completed with data overrun "
+ "reported\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* controller unfortunately reports SCSI passthru's */
+ /* to non-existent targets as invalid commands. */
+ printk(KERN_WARNING "cciss: cp %p is "
+ "reported invalid (probably means "
+ "target device no longer present)\n",
+ cp);
+ /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cp %p has "
+ "protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ /* cmd->result = DID_ERROR << 16; */
+ printk(KERN_WARNING "cciss: cp %p had "
+ " hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cp %p had "
+ "connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cp %p was "
+ "aborted\n", cp);
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cp %p reports "
+ "abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss: cp %p aborted "
+ "do to an unsolicited abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ printk(KERN_WARNING "cciss: cp %p timedout\n",
+ cp);
+ break;
+ default:
+ printk(KERN_WARNING "cciss: cp %p returned "
+ "unknown status %x\n", cp,
+ ei->CommandStatus);
+ }
+}
+
+static int
+cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
+ InquiryData_struct *buf)
+{
+ int rc;
+ CommandList_struct *cp;
+ char cdb[6];
+ ErrorInfo_struct *ei;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ cp = scsi_cmd_alloc(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ ei = cp->err_info;
+
+ if (cp == NULL) { /* trouble... */
+ printk("cmd_alloc returned NULL!\n");
+ return -1;
+ }
+
+ cdb[0] = CISS_INQUIRY;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = sizeof(*buf) & 0xff;
+ cdb[5] = 0;
+ rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb,
+ 6, (unsigned char *) buf,
+ sizeof(*buf), XFER_READ);
+
+ if (rc != 0) return rc; /* something went wrong */
+
+ if (ei->CommandStatus != 0 &&
+ ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ cciss_scsi_interpret_error(cp);
+ rc = -1;
+ }
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ scsi_cmd_free(c, cp);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ return rc;
+}
+
+static int
+cciss_scsi_do_report_phys_luns(ctlr_info_t *c,
+ ReportLunData_struct *buf, int bufsize)
+{
+ int rc;
+ CommandList_struct *cp;
+ unsigned char cdb[12];
+ unsigned char scsi3addr[8];
+ ErrorInfo_struct *ei;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ cp = scsi_cmd_alloc(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ if (cp == NULL) { /* trouble... */
+ printk("cmd_alloc returned NULL!\n");
+ return -1;
+ }
+
+ memset(&scsi3addr[0], 0, 8); /* address the controller */
+ cdb[0] = CISS_REPORT_PHYS;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = 0;
+ cdb[5] = 0;
+ cdb[6] = (sizeof(*buf) >> 24) & 0xFF; //MSB
+ cdb[7] = (sizeof(*buf) >> 16) & 0xFF;
+ cdb[8] = (sizeof(*buf) >> 8) & 0xFF;
+ cdb[9] = sizeof(*buf) & 0xFF;
+ cdb[10] = 0;
+ cdb[11] = 0;
+
+ rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr,
+ cdb, 12,
+ (unsigned char *) buf,
+ bufsize, XFER_READ);
+
+ if (rc != 0) return rc; /* something went wrong */
+
+ ei = cp->err_info;
+ if (ei->CommandStatus != 0 &&
+ ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ cciss_scsi_interpret_error(cp);
+ rc = -1;
+ }
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ scsi_cmd_free(c, cp);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ return rc;
+}
+
+static void
+cciss_update_non_disk_devices(int cntl_num, int hostno)
+{
+ /* the idea here is we could get notified from /proc
+ that some devices have changed, so we do a report
+ physical luns cmd, and adjust our list of devices
+ accordingly. (We can't rely on the scsi-mid layer just
+ doing inquiries, because the "busses" that the scsi
+ mid-layer probes are totally fabricated by this driver,
+ so new devices wouldn't show up.
+
+ the scsi3addr's of devices won't change so long as the
+ adapter is not reset. That means we can rescan and
+ tell which devices we already know about, vs. new
+ devices, vs. disappearing devices.
+
+ Also, if you yank out a tape drive, then put in a disk
+ in it's place, (say, a configured volume from another
+ array controller for instance) _don't_ poke this driver
+ (so it thinks it's still a tape, but _do_ poke the scsi
+ mid layer, so it does an inquiry... the scsi mid layer
+ will see the physical disk. This would be bad. Need to
+ think about how to prevent that. One idea would be to
+ snoop all scsi responses and if an inquiry repsonse comes
+ back that reports a disk, chuck it an return selection
+ timeout instead and adjust our table... Not sure i like
+ that though.
+
+ */
+
+ ReportLunData_struct *ld_buff;
+ InquiryData_struct *inq_buff;
+ unsigned char scsi3addr[8];
+ ctlr_info_t *c;
+ __u32 num_luns=0;
+ unsigned char *ch;
+ /* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */
+ struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
+ int ncurrent=0;
+ int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+ int i;
+
+ c = (ctlr_info_t *) hba[cntl_num];
+ ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+ memset(ld_buff, 0, reportlunsize);
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return;
+ }
+
+ if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
+ ch = &ld_buff->LUNListLength[0];
+ num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
+ if (num_luns > CISS_MAX_PHYS_LUN) {
+ printk(KERN_WARNING
+ "cciss: Maximum physical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN,
+ num_luns - CISS_MAX_PHYS_LUN);
+ num_luns = CISS_MAX_PHYS_LUN;
+ }
+ }
+ else {
+ printk(KERN_ERR "cciss: Report physical LUNs failed.\n");
+ return;
+ }
+
+
+ /* adjust our table of devices */
+ for(i=0; i<num_luns; i++)
+ {
+ int devtype;
+
+ /* for each physical lun, do an inquiry */
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
+
+ if (cciss_scsi_do_inquiry(hba[cntl_num],
+ scsi3addr, inq_buff) != 0)
+ {
+ /* Inquiry failed (msg printed already) */
+ devtype = 0; /* so we will skip this device. */
+ } else /* what kind of device is this? */
+ devtype = (inq_buff->data_byte[0] & 0x1f);
+
+ switch (devtype)
+ {
+ case 0x01: /* sequential access, (tape) */
+ case 0x08: /* medium changer */
+ memcpy(&currentsd[ncurrent].scsi3addr[0],
+ &scsi3addr[0], 8);
+ currentsd[ncurrent].devtype = devtype;
+ currentsd[ncurrent].bus = -1;
+ currentsd[ncurrent].target = -1;
+ currentsd[ncurrent].lun = -1;
+ ncurrent++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);
+
+ kfree(inq_buff);
+ kfree(ld_buff);
+ return;
+}
+
+static int
+is_keyword(char *ptr, int len, char *verb) // Thanks to ncr53c8xx.c
+{
+ int verb_len = strlen(verb);
+ if (len >= verb_len && !memcmp(verb,ptr,verb_len))
+ return verb_len;
+ else
+ return 0;
+}
+
+static int
+cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length)
+{
+ int arg_len;
+
+ if ((arg_len = is_keyword(buffer, length, "rescan")) != 0)
+ cciss_update_non_disk_devices(ctlr, hostno);
+ else
+ return -EINVAL;
+ return length;
+}
+
+/* It's a pity that we need this, but, we do... */
+extern struct Scsi_Host *scsi_hostlist; /* from ../scsi/hosts.c */
+
+int
+cciss_scsi_proc_info(char *buffer, /* data buffer */
+ char **start, /* where data in buffer starts */
+ off_t offset, /* offset from start of imaginary file */
+ int length, /* length of data in buffer */
+ int hostnum, /* which host adapter (always zero for me) */
+ int func) /* 0 == read, 1 == write */
+{
+
+ int buflen, datalen;
+ struct Scsi_Host *sh;
+ int found;
+ ctlr_info_t *ci;
+ int cntl_num;
+
+ /* Lets see if we can find our Scsi_Host...
+ this might be kind of "bad", searching scis_hostlist this way
+ but how else can we find the scsi host? I think I've seen
+ this coded both ways, (circular list and null terminated list)
+ I coded it to work either way, since I wasn't sure. */
+
+ sh = scsi_hostlist;
+ found=0;
+ do {
+ if (sh == NULL) break;
+ if (sh->host_no == hostnum) {
+ found++;
+ break;
+ }
+ sh = sh->next;
+ } while (sh != scsi_hostlist && sh != NULL);
+
+ if (sh == NULL || found == 0) /* This really shouldn't ever happen. */
+ return -EINVAL;
+
+ ci = (ctlr_info_t *) sh->hostdata[0];
+ if (ci == NULL) /* This really shouldn't ever happen. */
+ return -EINVAL;
+
+ cntl_num = ci->ctlr; /* Get our index into the hba[] array */
+
+ if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */
+ buflen = sprintf(buffer, "hostnum=%d\n", hostnum);
+
+ datalen = buflen - offset;
+ if (datalen < 0) { /* they're reading past EOF. */
+ datalen = 0;
+ *start = buffer+buflen;
+ } else
+ *start = buffer + offset;
+ return(datalen);
+ } else /* User is writing to /proc/scsi/cciss*?/?* ... */
+ return cciss_scsi_user_command(cntl_num, hostnum,
+ buffer, length);
+}
+
+/* this is via the generic proc support */
+const char *
+cciss_scsi_info(struct Scsi_Host *sa)
+{
+ static char buf[300];
+ ctlr_info_t *ci;
+
+ /* probably need to work on putting a bit more info in here... */
+ /* this is output via the /proc filesystem. */
+
+ ci = (ctlr_info_t *) sa->hostdata[0];
+
+ sprintf(buf, "%s %c%c%c%c\n",
+ ci->product_name,
+ ci->firm_ver[0],
+ ci->firm_ver[1],
+ ci->firm_ver[2],
+ ci->firm_ver[3]);
+
+ return buf;
+}
+
+
+/* cciss_scatter_gather takes a Scsi_Cmnd, (cmd), and does the pci
+ dma mapping and fills in the scatter gather entries of the
+ cciss command, cp. */
+
+static void
+cciss_scatter_gather(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ Scsi_Cmnd *cmd)
+{
+ unsigned int use_sg, nsegs=0, len;
+ struct scatterlist *scatter = (struct scatterlist *) cmd->buffer;
+ __u64 addr64;
+
+ /* is it just one virtual address? */
+ if (!cmd->use_sg) {
+ if (cmd->request_bufflen) { /* anything to xfer? */
+
+ addr64 = (__u64) pci_map_single(pdev,
+ cmd->request_buffer,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+ cp->SG[0].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Len = cmd->request_bufflen;
+ nsegs=1;
+ }
+ } /* else, must be a list of virtual addresses.... */
+ else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */
+
+ use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+ for (nsegs=0; nsegs < use_sg; nsegs++) {
+ addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
+ len = sg_dma_len(&scatter[nsegs]);
+ cp->SG[nsegs].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[nsegs].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[nsegs].Len = len;
+ cp->SG[nsegs].Ext = 0; // we are not chaining
+ }
+ } else BUG();
+
+ cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+ return;
+}
+
+
+int
+cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+ ctlr_info_t **c;
+ int ctlr, rc;
+ unsigned char scsi3addr[8];
+ CommandList_struct *cp;
+ unsigned long flags;
+
+ // Get the ptr to our adapter structure (hba[i]) out of cmd->host.
+ // We violate cmd->host privacy here. (Is there another way?)
+ c = (ctlr_info_t **) &cmd->host->hostdata[0];
+ ctlr = (*c)->ctlr;
+
+ rc = lookup_scsi3addr(ctlr, cmd->channel, cmd->target, cmd->lun,
+ scsi3addr);
+ if (rc != 0) {
+ /* the scsi nexus does not match any that we presented... */
+ /* pretend to mid layer that we got selection timeout */
+ cmd->result = DID_NO_CONNECT << 16;
+ done(cmd);
+ /* we might want to think about registering controller itself
+ as a processor device on the bus so sg binds to it. */
+ return 0;
+ }
+
+ /* printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n",
+ cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun);*/
+ // printk("q:%p:c%db%dt%dl%d ", cmd, ctlr, cmd->channel,
+ // cmd->target, cmd->lun);
+
+ /* Ok, we have a reasonable scsi nexus, so send the cmd down, and
+ see what the device thinks of it. */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ cp = scsi_cmd_alloc(*c);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (cp == NULL) { /* trouble... */
+ printk("scsi_cmd_alloc returned NULL!\n");
+ /* FIXME: next 3 lines are -> BAD! <- */
+ cmd->result = DID_NO_CONNECT << 16;
+ done(cmd);
+ return 0;
+ }
+
+ // Fill in the command list header
+
+ cmd->scsi_done = done; // save this for use by completion code
+
+ // save cp in case we have to abort it
+ cmd->host_scribble = (unsigned char *) cp;
+
+ cp->cmd_type = CMD_SCSI;
+ cp->scsi_cmd = cmd;
+ cp->Header.ReplyQueue = 0; // unused in simple mode
+ memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+ cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
+
+ // Fill in the request block...
+
+ cp->Request.Timeout = 1000; // guarantee completion
+ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+ if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
+ cp->Request.CDBLen = cmd->cmd_len;
+ memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);
+ cp->Request.Type.Type = TYPE_CMD;
+ cp->Request.Type.Attribute = ATTR_SIMPLE;
+ switch(cmd->sc_data_direction)
+ {
+ case SCSI_DATA_WRITE: cp->Request.Type.Direction = XFER_WRITE; break;
+ case SCSI_DATA_READ: cp->Request.Type.Direction = XFER_READ; break;
+ case SCSI_DATA_NONE: cp->Request.Type.Direction = XFER_NONE; break;
+
+ case SCSI_DATA_UNKNOWN:
+ // This can happen if a buggy application does a scsi passthru
+ // and sets both inlen and outlen to non-zero. ( see
+ // ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
+
+ cp->Request.Type.Direction = XFER_RSVD;
+ // This is technically wrong, and cciss controllers should
+ // reject it with CMD_INVALID, which is the most correct
+ // response, but non-fibre backends appear to let it
+ // slide by, and give the same results as if this field
+ // were set correctly. Either way is acceptable for
+ // our purposes here.
+
+ break;
+
+ default:
+ printk("cciss: unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+
+ cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
+
+ /* Put the request on the tail of the request queue */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&(*c)->reqQ, cp);
+ (*c)->Qdepth++;
+ start_io(*c);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ /* the cmd'll come back via intr handler in complete_scsi_command() */
+ return 0;
+}
+
+static void
+init_driver_template(int ctlr)
+{
+ memset(&driver_template[ctlr], 0, sizeof(driver_template[ctlr]));
+ driver_template[ctlr].name = ccissscsi[ctlr].name;
+ driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+ driver_template[ctlr].detect = cciss_scsi_detect;
+ driver_template[ctlr].release = cciss_scsi_release;
+ driver_template[ctlr].proc_info = cciss_scsi_proc_info;
+ driver_template[ctlr].queuecommand = cciss_scsi_queue_command;
+ driver_template[ctlr].eh_abort_handler = NULL;
+ driver_template[ctlr].eh_device_reset_handler = NULL;
+ driver_template[ctlr].bios_param = scsicam_bios_param;
+ driver_template[ctlr].can_queue = SCSI_CCISS_CAN_QUEUE;
+ driver_template[ctlr].this_id = 7;
+ driver_template[ctlr].sg_tablesize = MAXSGENTRIES;
+ driver_template[ctlr].cmd_per_lun = 1;
+ driver_template[ctlr].use_clustering = DISABLE_CLUSTERING;
+ driver_template[ctlr].module = THIS_MODULE;
+
+ /* set scsi_host to NULL so our detect routine will
+ find us on register */
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->scsi_host = NULL;
+
+}
+
+static void
+cciss_unregister_scsi(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ unsigned long flags;
+
+ /* we are being forcibly unloaded, and may not refuse. */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ /* if we weren't ever actually registered, don't unregister */
+ if (((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered) {
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ scsi_unregister_host(&driver_template[ctlr]);
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ }
+ init_driver_template(ctlr);
+ scsi_cmd_stack_free(ctlr);
+ kfree(hba[ctlr]->scsi_ctlr);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+}
+
+static int
+cciss_register_scsi(int ctlr, int this_is_init_time)
+{
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ driver_template[ctlr].name = ccissscsi[ctlr].name;
+ driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+ driver_template[ctlr].module = THIS_MODULE;;
+
+ /* Since this is really a block driver, the SCSI core may not be
+ initialized yet, in which case, calling scsi_register_host
+ would hang. instead, we will do it later, via /proc filesystem
+ and rc scripts, when we know SCSI core is good to go. */
+
+ if (this_is_init_time) {
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return 0;
+ }
+
+ /* Only register if SCSI devices are detected. */
+ if (ccissscsi[ctlr].ndevices != 0) {
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered = 1;
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return scsi_register_host(&driver_template[ctlr]);
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ printk(KERN_INFO
+ "cciss%d: No appropriate SCSI device detected, "
+ "SCSI subsystem not engaged.\n", ctlr);
+ return 0;
+}
+
+static int
+cciss_engage_scsi(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ if (((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered) {
+ printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ return ENXIO;
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ cciss_update_non_disk_devices(ctlr, -1);
+ cciss_register_scsi(ctlr, 0);
+ return 0;
+}
+
+static void
+cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
+{
+ int size;
+ unsigned int flags;
+
+ *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ size = sprintf(buffer + *len,
+ " Sequential access devices: %d\n\n",
+ ccissscsi[ctlr].ndevices);
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ *pos += size; *len += size;
+}
+
+#else /* no CONFIG_CISS_SCSI_TAPE */
+
+/* If no tape support, then these become defined out of existence */
+
+#define cciss_find_non_disk_devices(cntl_num)
+#define cciss_unregister_scsi(ctlr)
+#define cciss_register_scsi(ctlr, this_is_init_time)
+#define cciss_proc_tape_report(ctlr, buffer, pos, len)
+
+#endif /* CONFIG_CISS_SCSI_TAPE */
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
new file mode 100644
index 000000000..1e580f109
--- /dev/null
+++ b/drivers/block/cciss_scsi.h
@@ -0,0 +1,98 @@
+/*
+ * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ * Copyright 2001 Compaq Computer Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+#ifndef _CCISS_SCSI_H_
+#define _CCISS_SCSI_H_
+
+#include <scsi/scsicam.h> /* possibly irrelevant, since we don't show disks */
+
+ // the scsi id of the adapter...
+#define SELF_SCSI_ID 15
+ // 15 is somewhat arbitrary, since the scsi-2 bus
+ // that's presented by the driver to the OS is
+ // fabricated. The "real" scsi-3 bus the
+ // hardware presents is fabricated too.
+ // The actual, honest-to-goodness physical
+ // bus that the devices are attached to is not
+ // addressible natively, and may in fact turn
+ // out to be not scsi at all.
+
+#define SCSI_CCISS_CAN_QUEUE 2
+
+/* this notation works fine for static initializations (as is the usual
+ case for linux scsi drivers), but not so well for dynamic settings,
+ so, if you change this, you also have to change cciss_unregister_scsi()
+ in cciss_scsi.c */
+#define CCISS_SCSI { \
+ name: "", \
+ detect: cciss_scsi_detect, \
+ release: cciss_scsi_release, \
+ proc_info: cciss_scsi_proc_info, \
+ queuecommand: cciss_scsi_queue_command, \
+ bios_param: scsicam_bios_param, \
+ can_queue: SCSI_CCISS_CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: MAXSGENTRIES, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING,\
+}
+
+/*
+ info: cciss_scsi_info, \
+
+Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
+Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
+
+If the upper scsi layer tries to track how many commands we have
+outstanding, it will be operating under the misapprehension that it is
+the only one sending us requests. We also have the block interface,
+which is where most requests must surely come from, so the upper layer's
+notion of how many requests we have outstanding will be wrong most or
+all of the time.
+
+Note, the normal SCSI mid-layer error handling doesn't work well
+for this driver because 1) it takes the io_request_lock before
+calling error handlers and uses a local variable to store flags,
+so the io_request_lock cannot be released and interrupts enabled
+inside the error handlers, and, the error handlers cannot poll
+for command completion because they might get commands from the
+block half of the driver completing, and not know what to do
+with them. That's what we get for making a hybrid scsi/block
+driver, I suppose.
+
+*/
+
+struct cciss_scsi_dev_t {
+ int devtype;
+ int bus, target, lun; /* as presented to the OS */
+ unsigned char scsi3addr[8]; /* as presented to the HW */
+};
+
+struct cciss_scsi_hba_t {
+ char *name;
+ int ndevices;
+#define CCISS_MAX_SCSI_DEVS_PER_HBA 16
+ struct cciss_scsi_dev_t dev[CCISS_MAX_SCSI_DEVS_PER_HBA];
+};
+
+#endif /* _CCISS_SCSI_H_ */
+#endif /* CONFIG_CISS_SCSI_TAPE */
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 6a92fa4f5..b67eeec19 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -32,6 +32,7 @@
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
@@ -70,6 +71,7 @@ MODULE_LICENSE("GPL");
static int nr_ctlr;
static ctlr_info_t *hba[MAX_CTLR];
+static devfs_handle_t de_arr[MAX_CTLR][NWD];
static int eisa[8];
@@ -336,6 +338,7 @@ void cleanup_module(void)
del_gendisk(&ida_gendisk[i]);
}
+ devfs_unregister(devfs_find_handle(NULL, "ida", 0, 0, 0, 0));
remove_proc_entry("cpqarray", proc_root_driver);
kfree(ida);
kfree(ida_sizes);
@@ -486,6 +489,8 @@ int __init cpqarray_init(void)
ida_gendisk[i].part = ida + (i*256);
ida_gendisk[i].sizes = ida_sizes + (i*256);
ida_gendisk[i].nr_real = 0;
+ ida_gendisk[i].de_arr = de_arr[i];
+ ida_gendisk[i].fops = &ida_fops;
/* Get on the disk list */
add_gendisk(&ida_gendisk[i]);
@@ -1795,6 +1800,14 @@ static void getgeometry(int ctlr)
return;
}
+ if (!de_arr[ctlr][log_unit]) {
+ char txt[16];
+
+ sprintf(txt, "ida/c%dd%d", ctlr,
+ log_unit);
+ de_arr[ctlr][log_unit] =
+ devfs_mk_dir(NULL, txt, NULL);
+ }
info_p->phys_drives =
sense_config_buf->ctlr_phys_drv;
info_p->drv_assign_map
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 8fcdc77fa..8b5536023 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -58,8 +58,6 @@ inline int bio_rq_in_between(struct bio *bio, struct request *rq,
next_rq = list_entry(next, struct request, queuelist);
- BUG_ON(next_rq->flags & REQ_STARTED);
-
/*
* not a sector based request
*/
@@ -147,9 +145,10 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
*/
if (q->last_merge) {
struct request *__rq = list_entry_rq(q->last_merge);
- BUG_ON(__rq->flags & REQ_STARTED);
- if ((ret = elv_try_merge(__rq, bio)))
+ if (!rq_mergeable(__rq))
+ q->last_merge = NULL;
+ else if ((ret = elv_try_merge(__rq, bio)))
*req = __rq;
}
@@ -231,6 +230,12 @@ void elevator_linus_add_request(request_queue_t *q, struct request *rq,
elevator_t *e = &q->elevator;
int lat = 0, *latency = e->elevator_data;
+ /*
+ * it's a bug to let this rq preempt an already started request
+ */
+ if (insert_here->next != &q->queue_head)
+ BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
+
if (!(rq->flags & REQ_BARRIER))
lat = latency[rq_data_dir(rq)];
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index f98c41e49..142b4a8e8 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -818,7 +818,6 @@ int blk_init_queue(request_queue_t *q, request_fn_proc *rfn, spinlock_t *lock)
q->plug_tq.data = q;
q->queue_flags = (1 << QUEUE_FLAG_CLUSTER);
q->queue_lock = lock;
- q->last_merge = NULL;
blk_queue_segment_boundary(q, 0xffffffff);
@@ -964,12 +963,6 @@ static inline void add_request(request_queue_t * q, struct request * req,
drive_stat_acct(req, req->nr_sectors, 1);
/*
- * it's a bug to let this rq preempt an already started request
- */
- if (insert_here->next != &q->queue_head)
- BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
-
- /*
* elevator indicated where it wants this request to be
* inserted at elevator_merge time
*/
@@ -1121,8 +1114,10 @@ again:
switch (el_ret) {
case ELEVATOR_BACK_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->back_merge_fn(q, req, bio))
+ if (!q->back_merge_fn(q, req, bio)) {
+ insert_here = &req->queuelist;
break;
+ }
elv_merge_cleanup(q, req, nr_sectors);
@@ -1135,8 +1130,10 @@ again:
case ELEVATOR_FRONT_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->front_merge_fn(q, req, bio))
+ if (!q->front_merge_fn(q, req, bio)) {
+ insert_here = req->queuelist.prev;
break;
+ }
elv_merge_cleanup(q, req, nr_sectors);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 49b2e7dc1..740e5c8b8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -206,7 +206,7 @@ struct request *nbd_read_stat(struct nbd_device *lo)
if (result <= 0)
HARDFAIL("Recv control failed.");
memcpy(&xreq, reply.handle, sizeof(xreq));
- req = blkdev_entry_prev_request(&lo->queue_head);
+ req = blkdev_entry_to_request(lo->queue_head.prev);
if (xreq != req)
FAIL("Unexpected handle received.\n");
@@ -250,7 +250,7 @@ void nbd_do_it(struct nbd_device *lo)
goto out;
}
#ifdef PARANOIA
- if (req != blkdev_entry_prev_request(&lo->queue_head)) {
+ if (req != blkdev_entry_to_request(lo->queue_head.prev)) {
printk(KERN_ALERT "NBD: I have problem...\n");
}
if (lo != &nbd_dev[minor(req->rq_dev)]) {
@@ -285,7 +285,7 @@ void nbd_clear_que(struct nbd_device *lo)
#endif
while (!list_empty(&lo->queue_head)) {
- req = blkdev_entry_prev_request(&lo->queue_head);
+ req = blkdev_entry_to_request(lo->queue_head.prev);
#ifdef PARANOIA
if (!req) {
printk( KERN_ALERT "NBD: panic, panic, panic\n" );
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8266fdc87..3fb9ad117 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3697,7 +3697,7 @@ struct {
* Searches all registered partitions for autorun RAID arrays
* at boot time.
*/
-static int detected_devices[128];
+static kdev_t detected_devices[128];
static int dev_cnt;
void md_autodetect_dev(kdev_t dev)
@@ -3738,7 +3738,7 @@ static void autostart_arrays(void)
}
dev_cnt = 0;
- autorun_devices(-1);
+ autorun_devices(to_kdev_t(-1));
}
static struct {
@@ -3855,14 +3855,14 @@ void __init md_setup_drive(void)
*p++ = 0;
dev = name_to_kdev_t(devname);
- handle = devfs_find_handle(NULL, devname, MAJOR (dev), MINOR (dev),
+ handle = devfs_find_handle(NULL, devname, major(dev), minor(dev),
DEVFS_SPECIAL_BLK, 1);
if (handle != 0) {
unsigned major, minor;
devfs_get_maj_min(handle, &major, &minor);
dev = mk_kdev(major, minor);
}
- if (!dev) {
+ if (kdev_none(dev)) {
printk(KERN_WARNING "md: Unknown device name: %s\n", devname);
break;
}
@@ -3872,7 +3872,7 @@ void __init md_setup_drive(void)
devname = p;
}
- devices[i] = 0;
+ devices[i] = to_kdev_t(0);
if (!md_setup_args.device_set[minor])
continue;
@@ -3908,7 +3908,10 @@ void __init md_setup_drive(void)
ainfo.layout = 0;
ainfo.chunk_size = md_setup_args.chunk[minor];
err = set_array_info(mddev, &ainfo);
- for (i = 0; !err && (dev = devices[i]); i++) {
+ for (i = 0; !err && i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (kdev_none(dev))
+ break;
dinfo.number = i;
dinfo.raid_disk = i;
dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC);
@@ -3922,7 +3925,10 @@ void __init md_setup_drive(void)
}
} else {
/* persistent */
- for (i = 0; (dev = devices[i]); i++) {
+ for (i = 0; i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (kdev_none(dev))
+ break;
dinfo.major = major(dev);
dinfo.minor = minor(dev);
add_new_disk (mddev, &dinfo);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 94d3cbb7c..792e787fc 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -274,6 +274,7 @@ static int multipath_make_request (mddev_t *mddev, int rw,
memcpy(bh_req, bh, sizeof(*bh));
bh_req->b_blocknr = bh->b_rsector;
bh_req->b_dev = multipath->dev;
+ /* FIXME - later we will need bdev here */
bh_req->b_rdev = multipath->dev;
/* bh_req->b_rsector = bh->n_rsector; */
bh_req->b_end_io = multipath_end_request;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 6773bf201..385f26395 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -469,6 +469,7 @@ static struct buffer_head *raid5_build_block (struct stripe_head *sh, int i)
init_buffer(bh, raid5_end_read_request, sh);
bh->b_dev = conf->disks[i].dev;
+ /* FIXME - later we will need bdev here */
bh->b_blocknr = block;
bh->b_state = (1 << BH_Req) | (1 << BH_Mapped);
@@ -1137,6 +1138,7 @@ static void handle_stripe(struct stripe_head *sh)
else if (spare && action[i] == WRITE+1)
bh->b_dev = spare->dev;
else skip=1;
+ /* FIXME - later we will need bdev here */
if (!skip) {
PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, action[i]-1, i);
atomic_inc(&sh->count);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 1ca4133e9..ddf546d5d 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -894,13 +894,13 @@ static void i2ob_request(request_queue_t *q)
u32 m;
- while (!list_empty(&q->queue_head)) {
+ while (!blk_queue_empty(q)) {
/*
* On an IRQ completion if there is an inactive
* request on the queue head it means it isnt yet
* ready to dispatch.
*/
- req = blkdev_entry_next_request(&q->queue_head);
+ req = elv_next_request(q);
if(req->rq_status == RQ_INACTIVE)
return;
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 765d9bd6b..7c99d9e3a 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -569,7 +570,7 @@ static void lance_load_multicast (struct net_device *dev)
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
@@ -590,21 +591,7 @@ static void lance_load_multicast (struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
- {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
index 0fb2a48fa..6875780ae 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/7990.h
@@ -132,9 +132,6 @@ struct lance_private
char tx_full;
};
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
* Am7990 Control and Status Registers
*/
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index ff5f5792f..e9f2252cf 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -55,6 +55,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -723,22 +724,6 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- return crc;
-}
-
static void __cp_set_rx_mode (struct net_device *dev)
{
struct cp_private *cp = dev->priv;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 2d219b466..c96bce2ac 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -109,6 +109,7 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/completion.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -587,7 +588,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
static int rtl8139_close (struct net_device *dev);
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
static void rtl8139_set_rx_mode (struct net_device *dev);
static void __set_rx_mode (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
@@ -2371,23 +2371,6 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- return crc;
-}
-
-
static void __set_rx_mode (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 67064058e..06e0746a9 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -68,6 +68,7 @@ static const char version[] =
#include <linux/in.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -885,27 +886,6 @@ static struct net_device_stats *get_stats(struct net_device *dev)
}
/*
- * Update the given Autodin II CRC value with another data byte.
- */
-
-static inline u32 update_crc(u8 byte, u32 current_crc)
-{
- int bit;
- u8 ah = 0;
- for (bit=0; bit<8; bit++)
- {
- u8 carry = (current_crc>>31);
- current_crc <<= 1;
- ah = ((ah<<1) | carry) ^ byte;
- if (ah&1)
- current_crc ^= 0x04C11DB7; /* CRC polynomial */
- ah >>= 1;
- byte >>= 1;
- }
- return current_crc;
-}
-
-/*
* Form the 64 bit 8390 multicast table from the linked list of addresses
* associated with this dev structure.
*/
@@ -916,16 +896,13 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
for (dmi=dev->mc_list; dmi; dmi=dmi->next)
{
- int i;
u32 crc;
if (dmi->dmi_addrlen != ETH_ALEN)
{
printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
continue;
}
- crc = 0xffffffff; /* initial CRC value */
- for (i=0; i<ETH_ALEN; i++)
- crc = update_crc(dmi->dmi_addr[i], crc);
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
/*
* The 8390 uses the 6 most significant bits of the
* CRC to index the multicast table.
diff --git a/drivers/net/Makefile.lib b/drivers/net/Makefile.lib
new file mode 100644
index 000000000..af22a0e02
--- /dev/null
+++ b/drivers/net/Makefile.lib
@@ -0,0 +1,69 @@
+# These drivers all require crc32.o
+obj-$(CONFIG_8139CP) += crc32.o
+obj-$(CONFIG_8139TOO) += crc32.o
+obj-$(CONFIG_A2065) += crc32.o
+obj-$(CONFIG_ARM_AM79C961A) += crc32.o
+obj-$(CONFIG_AT1700) += crc32.o
+obj-$(CONFIG_ATP) += crc32.o
+obj-$(CONFIG_DE2104X) += crc32.o
+obj-$(CONFIG_DE4X5) += crc32.o
+obj-$(CONFIG_DECLANCE) += crc32.o
+obj-$(CONFIG_DEPCA) += crc32.o
+obj-$(CONFIG_DL2K) += crc32.o
+obj-$(CONFIG_DM9102) += crc32.o
+obj-$(CONFIG_EPIC100) += crc32.o
+obj-$(CONFIG_EWRK3) += crc32.o
+obj-$(CONFIG_FEALNX) += crc32.o
+obj-$(CONFIG_HAPPYMEAL) += crc32.o
+obj-$(CONFIG_MACE) += crc32.o
+obj-$(CONFIG_MACMACE) += crc32.o
+obj-$(CONFIG_MIPS_AU1000_ENET) += crc32.o
+obj-$(CONFIG_NATSEMI) += crc32.o
+obj-$(CONFIG_PCMCIA_FMVJ18X) += crc32.o
+obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o
+obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o
+obj-$(CONFIG_PCNET32) += crc32.o
+obj-$(CONFIG_SIS900) += crc32.o
+obj-$(CONFIG_SMC9194) += crc32.o
+obj-$(CONFIG_STARFIRE) += crc32.o
+obj-$(CONFIG_SUNBMAC) += crc32.o
+obj-$(CONFIG_SUNDANCE) += crc32.o
+obj-$(CONFIG_SUNGEM) += crc32.o
+obj-$(CONFIG_SUNGEM) += crc32.o
+obj-$(CONFIG_SUNLANCE) += crc32.o
+obj-$(CONFIG_SUNQE) += crc32.o
+obj-$(CONFIG_TULIP) += crc32.o
+obj-$(CONFIG_VIA_RHINE) += crc32.o
+obj-$(CONFIG_YELLOWFIN) += crc32.o
+obj-$(CONFIG_WINBOND_840) += crc32.o
+
+
+# These rely on drivers/net/7990.o which requires crc32.o
+obj-$(CONFIG_HPLANCE) += crc32.o
+obj-$(CONFIG_MVME147_NET) += crc32.o
+
+
+# These rely on drivers/net/8390.o which requires crc32.o
+obj-$(CONFIG_OAKNET) += crc32.o
+obj-$(CONFIG_NE2K_PCI) += crc32.o
+obj-$(CONFIG_STNIC) += crc32.o
+obj-$(CONFIG_MAC8390) += crc32.o
+obj-$(CONFIG_APNE) += crc32.o
+obj-$(CONFIG_PCMCIA_PCNET) += crc32.o
+obj-$(CONFIG_ARM_ETHERH) += crc32.o
+obj-$(CONFIG_WD80x3) += crc32.o
+obj-$(CONFIG_EL2) += crc32.o
+obj-$(CONFIG_NE2000) += crc32.o
+obj-$(CONFIG_NE2_MCA) += crc32.o
+obj-$(CONFIG_HPLAN) += crc32.o
+obj-$(CONFIG_HPLAN_PLUS) += crc32.o
+obj-$(CONFIG_ULTRA) += crc32.o
+obj-$(CONFIG_ULTRAMCA) += crc32.o
+obj-$(CONFIG_ULTRA32) += crc32.o
+obj-$(CONFIG_E2100) += crc32.o
+obj-$(CONFIG_ES3210) += crc32.o
+obj-$(CONFIG_LNE390) += crc32.o
+obj-$(CONFIG_NE3210) += crc32.o
+obj-$(CONFIG_AC3200) += crc32.o
+obj-$(CONFIG_ARIADNE2) += crc32.o
+obj-$(CONFIG_HYDRA) += crc32.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index e00dee5c4..63ed2cbd6 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -6,6 +6,7 @@
* Fixes and tips by:
* - Janos Farkas (CHEXUM@sparta.banki.hu)
* - Jes Degn Soerensen (jds@kom.auc.dk)
+ * - Matt Domsch (Matt_Domsch@dell.com)
*
* ----------------------------------------------------------------------------
*
@@ -47,6 +48,7 @@
#include <linux/string.h>
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -639,7 +641,7 @@ static void lance_load_multicast (struct net_device *dev)
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
@@ -660,21 +662,7 @@ static void lance_load_multicast (struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
- {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/a2065.h b/drivers/net/a2065.h
index f6e4d255f..184ad573d 100644
--- a/drivers/net/a2065.h
+++ b/drivers/net/a2065.h
@@ -43,9 +43,6 @@ struct lance_regs {
};
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
* Am7990 Control and Status Registers
*/
diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
index 30840e5d5..b7bb8f4ca 100644
--- a/drivers/net/am79c961a.c
+++ b/drivers/net/am79c961a.c
@@ -29,6 +29,7 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -308,33 +309,13 @@ static struct net_device_stats *am79c961_getstats (struct net_device *dev)
return &priv->stats;
}
-static inline u32 update_crc(u32 crc, u8 byte)
-{
- int i;
-
- for (i = 8; i != 0; i--) {
- byte ^= crc & 1;
- crc >>= 1;
-
- if (byte & 1)
- crc ^= 0xedb88320;
-
- byte >>= 1;
- }
-
- return crc;
-}
-
static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
{
if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
- int i, idx, bit;
+ int idx, bit;
u32 crc;
- crc = 0xffffffff;
-
- for (i = 0; i < ETH_ALEN; i++)
- crc = update_crc(crc, dmi->dmi_addr[i]);
+ crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
idx = crc >> 30;
bit = (crc >> 26) & 15;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 5a9ad62ad..badecbc40 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -49,6 +49,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -804,27 +805,6 @@ net_get_stats(struct net_device *dev)
Set the multicast/promiscuous mode for this adaptor.
*/
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void
set_rx_mode(struct net_device *dev)
{
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 62d7ceaea..5a31cfe28 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -140,6 +140,7 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */
#include <asm/dma.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -857,26 +858,6 @@ net_get_stats(struct net_device *dev)
* Set or clear the multicast filter for this adapter.
*/
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode_8002(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 168b9dd15..a9a4ac162 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -47,6 +47,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -1094,22 +1095,6 @@ static void au1000_tx_timeout(struct net_device *dev)
au1000_init(dev);
}
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index cf0d30df6..e94ccb93c 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1053,16 +1053,13 @@ static void bmac_set_multicast(struct net_device *dev)
/* The version of set_multicast below was lifted from sunhme.c */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void bmac_set_multicast(struct net_device *dev)
{
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
unsigned short rx_cfg;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
bmwrite(dev, BHASH0, 0xffff);
@@ -1089,17 +1086,7 @@ static void bmac_set_multicast(struct net_device *dev)
if(!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for(byte = 0; byte < 6; byte++) {
- for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if(test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/de2104x.c b/drivers/net/de2104x.c
index 5c43129ab..80dcf3384 100644
--- a/drivers/net/de2104x.c
+++ b/drivers/net/de2104x.c
@@ -43,6 +43,7 @@
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -657,41 +658,6 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
new frame, not around filling de->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
#undef set_bit_le
#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 2b5cff2b9..3af726812 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -436,6 +436,7 @@
'pb' is now only initialized if a de4x5 chip is
present.
<france@handhelds.org>
+ 0.547 08-Nov-01 Use library crc32 functions by <Matt_Domsch@dell.com>
=========================================================================
*/
@@ -457,6 +458,7 @@ static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.c
#include <linux/init.h>
#include <linux/version.h>
#include <linux/spinlock.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -622,9 +624,6 @@ struct parameters {
#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
** EISA bus defines
*/
@@ -2050,7 +2049,7 @@ SetMulticastFilter(struct net_device *dev)
u_long iobase = dev->base_addr;
int i, j, bit, byte;
u16 hashcode;
- u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
+ u32 omr, crc;
char *pa;
unsigned char *addrs;
@@ -2065,13 +2064,7 @@ SetMulticastFilter(struct net_device *dev)
addrs=dmi->dmi_addr;
dmi=dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
- /* process each address bit */
- for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
- crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 173e42b4a..f5c828869 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -79,6 +79,7 @@ static char *lancestr = "LANCE";
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <linux/etherdevice.h>
@@ -88,9 +89,6 @@ unsigned long dmaptr;
#endif
static int type;
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
@@ -920,7 +918,7 @@ static void lance_load_multicast(struct net_device *dev)
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_BE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
@@ -945,19 +943,7 @@ static void lance_load_multicast(struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test) {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc(6, addrs);
crc = crc >> 26;
mcast_table[crc >> 3] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index e6f061bed..9095f2fc6 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -228,6 +228,8 @@
by <peterd@pnd-pc.demon.co.uk>
0.53 12-Jan-01 Release resources on failure, bss tidbits
by acme@conectiva.com.br
+ 0.54 08-Nov-01 use library crc32 functions
+ by Matt_Domsch@dell.com
=========================================================================
*/
@@ -245,6 +247,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -296,9 +299,6 @@ static int depca_debug = 1;
#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
** EISA bus defines
*/
@@ -1225,7 +1225,7 @@ static void SetMulticastFilter(struct net_device *dev)
char *addrs;
int i, j, bit, byte;
u16 hashcode;
- s32 crc, poly = CRC_POLYNOMIAL_BE;
+ u32 crc;
if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */
for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
@@ -1240,13 +1240,7 @@ static void SetMulticastFilter(struct net_device *dev)
addrs=dmi->dmi_addr;
dmi=dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
- /* process each address bit */
- for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
- crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc(ETH_ALEN, addrs);
hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
for (j=0;j<5;j++) { /* ... in reverse order. */
hashcode = (hashcode << 1) | ((crc>>=1) & 1);
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 161075784..1c232734f 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -75,7 +75,6 @@ static int rio_close (struct net_device *dev);
static int find_miiphy (struct net_device *dev);
static int parse_eeprom (struct net_device *dev);
static int read_eeprom (long ioaddr, int eep_addr);
-static unsigned get_crc (unsigned char *p, int len);
static int mii_wait_link (struct net_device *dev, int wait);
static int mii_set_media (struct net_device *dev);
static int mii_get_media (struct net_device *dev);
@@ -327,7 +326,7 @@ parse_eeprom (struct net_device *dev)
}
/* Check CRC */
- crc = ~get_crc (sromdata, 256 - 4);
+ crc = ~ether_crc_le(256-4, sromdata);
if (psrom->crc != crc) {
printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
return -1;
@@ -972,23 +971,6 @@ change_mtu (struct net_device *dev, int new_mtu)
return 0;
}
-#define CRC_POLY 0xedb88320
-static unsigned
-get_crc (unsigned char *p, int len)
-{
- int bit;
- unsigned char byte;
- unsigned crc = 0xffffffff;
-
- while (--len >= 0) {
- byte = *p++;
- for (bit = 0; bit < 8; bit++, byte >>= 1) {
- crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
- }
- }
- return crc;
-}
-
static void
set_multicast (struct net_device *dev)
{
@@ -1023,7 +1005,7 @@ set_multicast (struct net_device *dev)
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+ set_bit (ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
hash_table);
}
writel (hash_table[0], ioaddr + HashTable0);
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 985468c60..62559339f 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -26,6 +26,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c
index c94409b25..4cca074aa 100644
--- a/drivers/net/dmfe.c
+++ b/drivers/net/dmfe.c
@@ -84,6 +84,7 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/crc32.h>
#include <asm/processor.h>
#include <asm/bitops.h>
@@ -288,72 +289,6 @@ static u8 HPNA_NoiseFloor; /* Default: HPNA NoiseFloor */
static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control
4: TX pause packet */
-unsigned long CrcTable[256] = {
- 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
- 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
- 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
- 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
- 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
- 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
- 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
- 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
- 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
- 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
- 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
- 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
- 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
- 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
- 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
- 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
- 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
- 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
- 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
- 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
- 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
- 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
- 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
- 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
- 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
- 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
- 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
- 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
- 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
- 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
- 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
- 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
- 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
- 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
- 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
- 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
- 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
- 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
- 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
- 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
- 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
- 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
- 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
- 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
- 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
- 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
- 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
- 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
- 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
- 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
- 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
- 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
- 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
- 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
- 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
- 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
- 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
- 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
- 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
- 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
- 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
- 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
- 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
- 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
-};
/* function declaration ------------------------------------- */
static int dmfe_open(struct DEVICE *);
@@ -382,7 +317,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
static void dmfe_dynamic_reset(struct DEVICE *);
static void dmfe_free_rxbuffer(struct dmfe_board_info *);
static void dmfe_init_dm910x(struct DEVICE *);
-static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
static void dmfe_parse_srom(struct dmfe_board_info *);
static void dmfe_program_DM9801(struct dmfe_board_info *, int);
static void dmfe_program_DM9802(struct dmfe_board_info *);
@@ -1851,18 +1786,11 @@ static u16 phy_read_1bit(unsigned long ioaddr)
* 0 : return the normal CRC (for Hash Table index)
*/
-unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
- unsigned long Crc = 0xffffffff;
-
- while (Len--) {
- Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
- }
-
- if (flag)
- return ~Crc;
- else
- return Crc;
+ u32 crc = crc32(~0, Data, Len);
+ if (flag) crc = ~crc;
+ return crc;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 468c675b4..7c30e7750 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -124,6 +124,7 @@ static int rx_copybreak;
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -1302,27 +1303,6 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev)
new frame, not around filling ep->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
long ioaddr = dev->base_addr;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 4b9319011..dadc8c8d3 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -132,6 +132,7 @@
<kenneth@bbs.sas.ntu.ac.sg>.
0.42 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
+ 0.44 08-Nov-01 use library crc32 functions <Matt_Domsch@dell.com>
=========================================================================
*/
@@ -148,6 +149,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -207,9 +209,6 @@ static int ewrk3_debug = 1;
#define EISA_SLOT_INC 0x1000
#endif
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */
/*
@@ -1174,10 +1173,10 @@ static void SetMulticastFilter(struct net_device *dev)
struct dev_mc_list *dmi = dev->mc_list;
u_long iobase = dev->base_addr;
int i;
- char *addrs, j, bit, byte;
+ char *addrs, bit, byte;
short *p = (short *) lp->mctbl;
u16 hashcode;
- s32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
spin_lock_irq(&lp->hw_lock);
@@ -1219,13 +1218,7 @@ static void SetMulticastFilter(struct net_device *dev)
addrs = dmi->dmi_addr;
dmi = dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */
- /* process each address bit */
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index e63a3c542..e35d85f47 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -72,6 +72,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -426,7 +427,6 @@ static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -1711,26 +1711,6 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
-
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
-
- return crc;
-}
-
-
static void set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c
index 8d3e0b2d4..1406a5edb 100644
--- a/drivers/net/gmac.c
+++ b/drivers/net/gmac.c
@@ -16,6 +16,8 @@
* - PHY updates
* BenH <benh@kernel.crashing.org> - 08/08/2001
* - Add more PHYs, fixes to sleep code
+ * Matt Domsch <Matt_Domsch@dell.com> - 11/12/2001
+ * - use library crc32 functions
*/
#include <linux/module.h>
@@ -33,6 +35,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -997,14 +1000,13 @@ gmac_stop_dma(struct gmac *gm)
* Configure promisc mode and setup multicast hash table
* filter
*/
-#define CRC_POLY 0xedb88320
static void
gmac_set_multicast(struct net_device *dev)
{
struct gmac *gm = (struct gmac *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
int i,j,k,b;
- unsigned long crc;
+ u32 crc;
int multicast_hash = 0;
int multicast_all = 0;
int promisc = 0;
@@ -1027,17 +1029,7 @@ gmac_set_multicast(struct net_device *dev)
hash_table[i] = 0;
for (i = 0; i < dev->mc_count; i++) {
- crc = ~0;
- for (j = 0; j < 6; ++j) {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k) {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 24; /* bit number in multicast_filter */
hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
dmi = dmi->next;
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index dc1667b24..1a3e62efe 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -33,6 +33,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#ifdef CONFIG_SERIAL
#include <linux/serial.h>
@@ -1611,27 +1612,16 @@ static void ioc3_timeout(struct net_device *dev)
* Given a multicast ethernet address, this routine calculates the
* address's bit index in the logical address filter mask
*/
-#define CRC_MASK 0xedb88320
static inline unsigned int
ioc3_hash(const unsigned char *addr)
{
unsigned int temp = 0;
unsigned char byte;
- unsigned int crc;
- int bits, len;
-
- len = ETH_ALEN;
- for (crc = ~0; --len >= 0; addr++) {
- byte = *addr;
- for (bits = 8; --bits >= 0; ) {
- if ((byte ^ crc) & 1)
- crc = (crc >> 1) ^ CRC_MASK;
- else
- crc >>= 1;
- byte >>= 1;
- }
- }
+ u32 crc;
+ int bits;
+
+ crc = ether_crc_le(ETH_ALEN, addr);
crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */
for (bits = 6; --bits >= 0; ) {
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 04ca3c75a..770492474 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -15,6 +15,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -508,17 +509,12 @@ static struct net_device_stats *mace_stats(struct net_device *dev)
return &p->stats;
}
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY 0xedb88320
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
volatile struct mace *mb = mp->mace;
- int i, j, k, b;
- unsigned long crc;
+ int i, j;
+ u32 crc;
mp->maccc &= ~PROM;
if (dev->flags & IFF_PROMISC) {
@@ -534,17 +530,7 @@ static void mace_set_multicast(struct net_device *dev)
for (i = 0; i < 8; i++)
multicast_filter[i] = 0;
for (i = 0; i < dev->mc_count; i++) {
- crc = ~0;
- for (j = 0; j < 6; ++j) {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k) {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 26; /* bit number in multicast_filter */
multicast_filter[j >> 3] |= 1 << (j & 7);
dmi = dmi->next;
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 099b1fc93..9f792a43f 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/timer.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -539,17 +540,12 @@ static struct net_device_stats *mace68k_stats(struct net_device *dev)
return &p->stats;
}
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY 0xedb88320
-
static void mace68k_set_multicast(struct net_device *dev)
{
struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
volatile struct mace *mb = mp->mace;
int i, j, k, b;
- unsigned long crc;
+ u32 crc;
mp->maccc &= ~PROM;
if (dev->flags & IFF_PROMISC)
@@ -570,19 +566,7 @@ static void mace68k_set_multicast(struct net_device *dev)
multicast_filter[i] = 0;
for (i = 0; i < dev->mc_count; i++)
{
- crc = ~0;
- for (j = 0; j < 6; ++j)
- {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k)
- {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 26; /* bit number in multicast_filter */
multicast_filter[j >> 3] |= 1 << (j & 7);
dmi = dmi->next;
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 4ea8280d6..09b2d0450 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -800,9 +800,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu)
static struct net_device_stats *myri_get_stats(struct net_device *dev)
{ return &(((struct myri_eth *)dev->priv)->enet_stats); }
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void myri_set_multicast(struct net_device *dev)
{
/* Do nothing, all MyriCOM nodes transmit multicast frames
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 7d01a2c6e..a94d69453 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -102,6 +102,9 @@
version 1.0.13:
* ETHTOOL_[GS]EEPROM support (Tim Hockin)
+ version 1.0.13:
+ * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
+
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
* support for an external PHY
@@ -110,7 +113,7 @@
#define DRV_NAME "natsemi"
#define DRV_VERSION "1.07+LK1.0.13"
-#define DRV_RELDATE "Oct 19, 2001"
+#define DRV_RELDATE "Nov 12, 2001"
/* Updated to recommendations in pci-skeleton v2.03. */
@@ -1706,36 +1709,15 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
-#if 0
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-#else
+/**
+ * dp83815_crc - computer CRC for hash table entries
+ *
+ * Note - this is, for some reason, *not* the same function
+ * as ether_crc_le() or ether_crc(), though it uses the
+ * same big-endian polynomial.
+ */
#define DP_POLYNOMIAL 0x04C11DB7
-/* dp83815_crc - computer CRC for hash table entries */
-static unsigned ether_crc_le(int length, unsigned char *data)
+static unsigned dp83815_crc(int length, unsigned char *data)
{
u32 crc;
u8 cur_byte;
@@ -1759,7 +1741,7 @@ static unsigned ether_crc_le(int length, unsigned char *data)
return (crc);
}
-#endif
+
void set_bit_le(int offset, unsigned char * data)
{
@@ -1788,7 +1770,7 @@ static void __set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
mc_filter);
}
rx_mode = RxFilterEnable | AcceptBroadcast
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index e94d6c3cb..6743227a3 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -96,6 +96,7 @@ IVc. Errata
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#define NETDRV_VERSION "1.0.0"
@@ -509,7 +510,6 @@ static void netdrv_interrupt (int irq, void *dev_instance,
static int netdrv_close (struct net_device *dev);
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
static void netdrv_set_rx_mode (struct net_device *dev);
static void netdrv_hw_start (struct net_device *dev);
@@ -1853,27 +1853,6 @@ static struct net_device_stats *netdrv_get_stats (struct net_device *dev)
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- DPRINTK ("ENTER\n");
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- DPRINTK ("EXIT\n");
- return crc;
-}
-
-
static void netdrv_set_rx_mode (struct net_device *dev)
{
struct netdrv_private *tp = dev->priv;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 381693494..6c47c37a0 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -47,6 +47,7 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
+#include <linux/crc32.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
@@ -1181,27 +1182,6 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev)
Set the multicast/promiscuous mode for this adaptor.
*/
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index f1c322bb2..44c218c3f 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -34,6 +34,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -1740,31 +1741,6 @@ static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
return &smc->stats;
}
-/*======================================================================
-
- Compute the AUTODIN polynomial "CRC32" for ethernet packets.
-
-======================================================================*/
-
-static const u_int ethernet_polynomial = 0x04c11db7U;
-
-static u_int ether_crc(int length, u_char *data)
-{
- int crc = 0xffffffff; /* Initial value. */
-
- while (--length >= 0) {
- u_char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- /* The hash index is the either the upper or lower bits of the CRC, so
- * we return the entire CRC.
- */
- return crc;
-}
/*======================================================================
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
index e7fe6ae79..578af8d57 100644
--- a/drivers/net/pcmcia/xircom_tulip_cb.c
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -101,6 +101,7 @@ static int csr0 = 0x00A00000 | 0x4800;
#include <linux/init.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
@@ -1518,43 +1519,6 @@ static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP;
}
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
Note that we only use exclusion around actually queueing the
new frame, not around filling tp->setup_frame. This is non-deterministic
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 4ad12acf7..25b86ec89 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -36,6 +36,7 @@ static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -215,8 +216,6 @@ static int full_duplex[MAX_UNITS];
#define PCNET32_TOTAL_SIZE 0x20
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
@@ -1425,8 +1424,8 @@ static void pcnet32_load_multicast (struct net_device *dev)
volatile u16 *mcast_table = (u16 *)&ib->filter;
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
@@ -1447,19 +1446,7 @@ static void pcnet32_load_multicast (struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test) {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index e6140c6cf..6724c7406 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1,6 +1,6 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.08.01 Aug. 25 2001
+ Revision: 1.08.02 Jan. 4 2002
Modified from the driver which is originally written by Donald Becker.
@@ -18,6 +18,7 @@
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
+ Rev 1.08.02 Jan. 4 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
@@ -62,11 +63,12 @@
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include "sis900.h"
static char version[] __devinitdata =
-KERN_INFO "sis900.c: v1.08.01 9/25/2001\n";
+KERN_INFO "sis900.c: v1.08.02 1/4/2002\n";
static int max_interrupt_work = 40;
static int multicast_filter_limit = 128;
@@ -1928,26 +1930,7 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision)
{
-/* what is the correct value of the POLYNOMIAL ??
- Donald Becker use 0x04C11DB7U
- Joseph Zbiciak im14u2c@primenet.com gives me the
- correct answer, thank you Joe !! */
-#define POLYNOMIAL 0x04C11DB7L
- u32 crc = 0xffffffff, msb;
- int i, j;
- u32 byte;
-
- for (i = 0; i < 6; i++) {
- byte = *addr++;
- for (j = 0; j < 8; j++) {
- msb = crc >> 31;
- crc <<= 1;
- if (msb ^ (byte & 1)) {
- crc ^= POLYNOMIAL;
- }
- byte >>= 1;
- }
- }
+ u32 crc = ether_crc(6, addr);
/* leave 8 or 7 most siginifant bits */
if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
index 7a7c953b7..4f8e30868 100644
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -116,6 +116,7 @@ typedef struct s_AC SK_AC;
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#include <asm/byteorder.h>
#include <asm/bitops.h>
#include <asm/io.h>
diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c
index b7381fe67..ca223be37 100644
--- a/drivers/net/sk98lin/skaddr.c
+++ b/drivers/net/sk98lin/skaddr.c
@@ -199,7 +199,6 @@ extern "C" {
/* defines ********************************************************************/
-#define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */
#define HASH_BITS 6 /* #bits in hash */
#define SK_MC_BIT 0x01
@@ -534,18 +533,9 @@ int Flags) /* permanent/non-perm, sw-only */
unsigned SkCrc32McHash(
unsigned char *pMc) /* Multicast address */
{
- unsigned Idx;
- unsigned Bit;
- unsigned Data;
- unsigned Crc;
-
- Crc = 0xFFFFFFFFUL;
- for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
- Data = *pMc++;
- for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
- Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
- }
- }
+ u32 Crc;
+
+ Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
return (Crc & ((1 << HASH_BITS) - 1));
} /* SkCrc32McHash */
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index c40f7dc8b..07337b7b9 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -51,6 +51,7 @@
. allocation
. 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet
. 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ"
+ . 11/08/01 Matt Domsch Use common crc32 function
----------------------------------------------------------------------------*/
static const char version[] =
@@ -69,6 +70,7 @@ static const char version[] =
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/errno.h>
@@ -223,10 +225,6 @@ static struct net_device_stats * smc_query_statistics( struct net_device *dev);
*/
static void smc_set_multicast_list(struct net_device *dev);
-/*
- . CRC compute
- */
-static int crc32( char * s, int length );
/*---------------------------------------------------------------
.
@@ -436,7 +434,7 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs
continue;
/* only use the low order bits */
- position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+ position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
/* do some messy swapping to put the bit in the right spot */
multicast_table[invert3[position&7]] |=
@@ -452,33 +450,6 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs
}
/*
- Finds the CRC32 of a set of bytes.
- Again, from Peter Cammaert's code.
-*/
-static int crc32( char * s, int length ) {
- /* indices */
- int perByte;
- int perBit;
- /* crc polynomial for Ethernet */
- const unsigned long poly = 0xedb88320;
- /* crc value - preinitialized to all 1's */
- unsigned long crc_value = 0xffffffff;
-
- for ( perByte = 0; perByte < length; perByte ++ ) {
- unsigned char c;
-
- c = *(s++);
- for ( perBit = 0; perBit < 8; perBit++ ) {
- crc_value = (crc_value>>1)^
- (((crc_value^c)&0x01)?poly:0);
- c >>= 1;
- }
- }
- return crc_value;
-}
-
-
-/*
. Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
. Purpose:
. Attempt to allocate memory for a packet, if chip-memory is not
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 0fec2bcce..3d17fd6c2 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -109,6 +109,7 @@ TODO:
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1612,32 +1613,9 @@ static struct net_device_stats *get_stats(struct net_device *dev)
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
+/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
them. Select the endian-ness that results in minimal calculations.
*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index f5fda2e07..ec420faea 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.28 2001-10-21 06:35:29 davem Exp $
+/* $Id: sunbmac.c,v 1.29 2002-01-15 06:25:51 davem Exp $
* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -979,9 +980,6 @@ static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
return &bp->enet_stats;
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void bigmac_set_multicast(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
@@ -989,7 +987,7 @@ static void bigmac_set_multicast(struct net_device *dev)
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 tmp, crc, poly = CRC_POLYNOMIAL_LE;
+ u32 tmp, crc;
/* Disable the receiver. The bit self-clears when
* the operation is complete.
@@ -1022,17 +1020,7 @@ static void bigmac_set_multicast(struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index ab376ffed..c55a85e82 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -98,6 +98,7 @@ static char *media[MAX_UNITS];
#include <linux/init.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
@@ -1262,32 +1263,6 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
long ioaddr = dev->base_addr;
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index cd118255d..6563a1ea9 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.46 2002-01-15 05:35:33 davem Exp $
+/* $Id: sungem.c,v 1.47 2002-01-15 06:25:51 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -31,6 +31,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
@@ -1700,8 +1701,6 @@ static void gem_init_dma(struct gem *gp)
gp->regs + RXDMA_BLANK);
}
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static u32
gem_setup_multicast(struct gem *gp)
{
@@ -1717,9 +1716,9 @@ gem_setup_multicast(struct gem *gp)
rxcfg |= MAC_RXCFG_PROM;
} else {
u16 hash_table[16];
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
struct dev_mc_list *dmi = gp->dev->mc_list;
- int i, j, bit, byte;
+ int i;
for (i = 0; i < 16; i++)
hash_table[i] = 0;
@@ -1732,17 +1731,7 @@ gem_setup_multicast(struct gem *gp)
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 24;
hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
}
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 4bff4dd7d..0ef854539 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.123 2001-10-02 02:22:30 davem Exp $
+/* $Id: sunhme.c,v 1.124 2002-01-15 06:25:51 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -33,6 +33,7 @@ static char version[] =
#include <linux/init.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -1469,9 +1470,6 @@ force_link:
add_timer(&hp->happy_timer);
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static int happy_meal_init(struct happy_meal *hp, int from_irq)
{
unsigned long gregs = hp->gregs;
@@ -1583,8 +1581,8 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
u16 hash_table[4];
struct dev_mc_list *dmi = hp->dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
for (i = 0; i < 4; i++)
hash_table[i] = 0;
@@ -1596,17 +1594,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
@@ -2385,8 +2373,8 @@ static void happy_meal_set_multicast(struct net_device *dev)
unsigned long bregs = hp->bigmacregs;
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
/* Lock out others. */
netif_stop_queue(dev);
@@ -2412,17 +2400,7 @@ static void happy_meal_set_multicast(struct net_device *dev)
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 9a69bf36c..8e210656b 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.110 2002-01-14 10:08:07 davem Exp $
+/* $Id: sunlance.c,v 1.111 2002-01-15 06:25:51 davem Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -62,12 +62,15 @@
* Anton Blanchard (anton@progsoc.uts.edu.au)
* 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces.
* David S. Miller (davem@redhat.com)
+ * 2.01:
+ * 11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
+ *
*/
#undef DEBUG_DRIVER
static char version[] =
- "sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+ "sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
static char lancestr[] = "LANCE";
@@ -86,6 +89,7 @@ static char lancestr[] = "LANCE";
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -115,9 +119,6 @@ static char lancestr[] = "LANCE";
#define LANCE_LOG_RX_BUFFERS 4
#endif
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
@@ -1181,7 +1182,7 @@ static void lance_load_multicast(struct net_device *dev)
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
@@ -1211,19 +1212,7 @@ static void lance_load_multicast(struct net_device *dev)
/* multicast address? */
if (!(*addrs & 1))
continue;
-
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
if (lp->pio_buffer) {
u16 tmp = sbus_readw(&mcast_table[crc>>4]);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c1c38f145..9ab2c1764 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.53 2001-12-21 00:54:31 davem Exp $
+/* $Id: sunqe.c,v 1.54 2002-01-15 06:25:51 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
@@ -24,6 +24,7 @@ static char version[] =
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -622,9 +623,6 @@ static struct net_device_stats *qe_get_stats(struct net_device *dev)
return &qep->net_stats;
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void qe_set_multicast(struct net_device *dev)
{
struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -632,7 +630,7 @@ static void qe_set_multicast(struct net_device *dev)
u8 new_mconfig = qep->mconfig;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* Lock out others. */
netif_stop_queue(dev);
@@ -660,18 +658,7 @@ static void qe_set_multicast(struct net_device *dev)
if (!(*addrs & 1))
continue;
-
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 917f1a9be..b396f5ba8 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
@@ -968,41 +969,6 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
new frame, not around filling tp->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
#undef set_bit_le
#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 2e753ad17..0aed62e90 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -151,6 +151,7 @@ static const int multicast_filter_limit = 32;
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -1519,26 +1520,6 @@ static inline void clear_tally_counters(const long ioaddr)
readw(ioaddr + RxMissed);
}
-
-/* The big-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- return crc;
-}
-
static void via_rhine_set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c
index f81fc206f..92e188068 100644
--- a/drivers/net/winbond-840.c
+++ b/drivers/net/winbond-840.c
@@ -136,6 +136,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
@@ -389,7 +390,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev);
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static void netdev_error(struct net_device *dev, int intr_status);
static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
static u32 __set_rx_mode(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
@@ -1407,21 +1407,6 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- return crc;
-}
static u32 __set_rx_mode(struct net_device *dev)
{
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index e169ad56f..e56ab051d 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -125,6 +125,7 @@ static int gx_fix;
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/unaligned.h>
@@ -1339,29 +1340,6 @@ static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
/* Set or clear the multicast filter for this adaptor. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
-
static void set_rx_mode(struct net_device *dev)
{
struct yellowfin_private *yp = dev->priv;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index f1deb2a35..bb14996da 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -115,7 +115,7 @@ do { \
static inline struct request *
dasd_next_request( request_queue_t *queue )
{
- return blkdev_entry_next_request(&queue->queue_head);
+ return elv_next_request(queue);
}
static inline void
dasd_dequeue_request( request_queue_t * q, struct request *req )
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index d6715d169..064a5cc00 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -771,7 +771,7 @@ void xpram_request(request_queue_t * queue)
fault=0;
#if ( XPRAM_VERSION == 24 )
- current_req = blkdev_entry_next_request (&queue->queue_head);
+ current_req = CURRENT;
#endif /* V24 */
dev_no = DEVICE_NR(current_req->rq_dev);
/* Check if the minor number is in range */
diff --git a/drivers/s390/char/tapedefs.h b/drivers/s390/char/tapedefs.h
index fa714c2c4..8506921d5 100644
--- a/drivers/s390/char/tapedefs.h
+++ b/drivers/s390/char/tapedefs.h
@@ -41,7 +41,7 @@ do { \
static inline struct request *
tape_next_request( request_queue_t *queue )
{
- return blkdev_entry_next_request(&queue->queue_head);
+ return elv_next_request(queue);
}
static inline void
tape_dequeue_request( request_queue_t * q, struct request *req )
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index b5882e5ba..3d366c790 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -8393,8 +8393,8 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
- shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+" unchecked_isa_dma %d, use_clustering %d\n",
+ shp->unchecked_isa_dma, shp->use_clustering);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
@@ -9412,9 +9412,8 @@ asc_prt_scsi_host(struct Scsi_Host *s)
s->dma_channel, s->this_id, s->can_queue);
printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
- s->loaded_as_module);
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
if (ASC_NARROW_BOARD(boardp)) {
asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 23113ae7c..ebbd33c54 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -5,7 +5,6 @@
*
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/config.h>
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index aa0fd64cb..e27637677 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -24,7 +24,6 @@
* hosts currently present in the system.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/blk.h>
#include <linux/kernel.h>
@@ -55,13 +54,6 @@ static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v
* number it is during detection.
*/
-/* This is a placeholder for controllers that are not configured into
- * the system - we do this to ensure that the controller numbering is
- * always consistent, no matter how the kernel is configured. */
-
-#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, 0, 0, 0, 0, 0, 0}
-
/*
* When figure is run, we don't want to link to any object code. Since
* the macro for each host will contain function pointers, we cannot
@@ -157,17 +149,14 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
flag_new = 0;
retval->host_no = shn->host_no;
shn->host_registered = 1;
- shn->loaded_as_module = 1;
break;
}
}
- spin_lock_init(&retval->host_lock);
+ spin_lock_init(&retval->default_lock);
+ scsi_assign_lock(retval, &retval->default_lock);
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
- if(j > 0xffff) panic("Too many extra bytes requested\n");
- retval->extra_bytes = j;
- retval->loaded_as_module = 1;
if (flag_new) {
shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
if (!shn) {
@@ -181,7 +170,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
shn->name[hname_len] = 0;
shn->host_no = max_scsi_hosts++;
shn->host_registered = 1;
- shn->loaded_as_module = 1;
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 3246ba64f..8604eb351 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -312,7 +312,8 @@ struct Scsi_Host
struct Scsi_Host * next;
Scsi_Device * host_queue;
- spinlock_t host_lock;
+ spinlock_t default_lock;
+ spinlock_t *host_lock;
struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on
@@ -329,7 +330,6 @@ struct Scsi_Host
volatile unsigned short host_failed; /* commands that failed. */
/* public: */
- unsigned short extra_bytes;
unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int resetting; /* if set, it means that last_reset is a valid value */
unsigned long last_reset;
@@ -386,10 +386,6 @@ struct Scsi_Host
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned highmem_io:1;
- /*
- * True if this host was loaded as a loadable module
- */
- unsigned loaded_as_module:1;
/*
* Host has rejected a command because it was busy.
@@ -451,7 +447,6 @@ typedef struct SHN
char * name;
unsigned short host_no;
unsigned short host_registered;
- unsigned loaded_as_module;
} Scsi_Host_Name;
extern Scsi_Host_Name * scsi_host_no_list;
@@ -471,10 +466,14 @@ extern int next_scsi_host;
unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
extern void scsi_unregister(struct Scsi_Host * i);
-
extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt);
extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt);
+static inline void scsi_assign_lock(struct Scsi_Host *host, spinlock_t *lock)
+{
+ host->host_lock = lock;
+}
+
static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
struct pci_dev *pdev)
{
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 3bb3bef50..1c47f9cc0 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -292,9 +292,9 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
}
}
host = pc->scsi_cmd->host;
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
pc->done(pc->scsi_cmd);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
idescsi_free_bio (rq->bio);
kfree(pc); kfree(rq);
scsi->pc = NULL;
@@ -805,9 +805,9 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
rq->special = (char *) pc;
rq->bio = idescsi_dma_bio (drive, pc);
rq->flags = REQ_SPECIAL;
- spin_unlock(&cmd->host->host_lock);
+ spin_unlock_irq(cmd->host->host_lock);
(void) ide_do_drive_cmd (drive, rq, ide_end);
- spin_lock_irq(&cmd->host->host_lock);
+ spin_lock_irq(cmd->host->host_lock);
return 0;
abort:
if (pc) kfree (pc);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b3257fc46..554dc6b44 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -75,8 +75,6 @@
#include <linux/kmod.h>
#endif
-#undef USE_STATIC_SCSI_MEMORY
-
struct proc_dir_entry *proc_scsi;
#ifdef CONFIG_PROC_FS
@@ -195,16 +193,23 @@ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt)
{
request_queue_t *q = &SDpnt->request_queue;
- blk_init_queue(q, scsi_request_fn, &SHpnt->host_lock);
+ /*
+ * tell block layer about assigned host_lock for this host
+ */
+ blk_init_queue(q, scsi_request_fn, SHpnt->host_lock);
+
q->queuedata = (void *) SDpnt;
/* Hardware imposed limit. */
blk_queue_max_hw_segments(q, SHpnt->sg_tablesize);
- blk_queue_max_sectors(q, SHpnt->max_sectors);
- /* scsi_alloc_sgtable max */
+ /*
+ * scsi_alloc_sgtable max
+ */
blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ blk_queue_max_sectors(q, SHpnt->max_sectors);
+
if (!SHpnt->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
}
@@ -647,7 +652,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/* Assign a unique nonzero serial_number. */
if (++serial_number == 0)
@@ -698,9 +703,9 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
* length exceeds what the host adapter can handle.
*/
if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) {
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
rtn = host->hostt->queuecommand(SCpnt, scsi_done);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
if (rtn != 0) {
scsi_delete_timer(SCpnt);
scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
@@ -711,20 +716,20 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
SCSI_LOG_MLQUEUE(3,
printk("queuecommand : command too long.\n"));
SCpnt->result = (DID_ABORT << 16);
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
scsi_done(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
rtn = 1;
}
} else {
int temp;
SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", host->hostt->command));
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
temp = host->hostt->command(SCpnt);
SCpnt->result = temp;
#ifdef DEBUG_DELAY
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
clock = jiffies + 4 * HZ;
while (time_before(jiffies, clock)) {
barrier();
@@ -732,10 +737,10 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
}
printk("done(host = %d, result = %04x) : routine at %p\n",
host->host_no, temp, host->hostt->command);
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
#endif
scsi_done(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
}
SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
return rtn;
@@ -805,7 +810,7 @@ void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd,
Scsi_Device * SDpnt = SRpnt->sr_device;
struct Scsi_Host *host = SDpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCSI_LOG_MLQUEUE(4,
{
@@ -902,7 +907,7 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt)
{
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
SRpnt->sr_command = SCpnt;
@@ -992,7 +997,7 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
{
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCpnt->pid = scsi_pid++;
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
@@ -1346,7 +1351,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
host = SCpnt->host;
device = SCpnt->device;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/*
* We need to protect the decrement, as otherwise a race condition
@@ -1355,10 +1360,10 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* one execution context, but the device and host structures are
* shared.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
host->host_busy--; /* Indicate that we are free */
device->device_busy--; /* Decrement device usage counter. */
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
/*
* Clear the flags which say that the device/host is no longer
@@ -1512,7 +1517,6 @@ void __init scsi_host_no_insert(char *str, int n)
shn->name[len] = 0;
shn->host_no = n;
shn->host_registered = 0;
- shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
@@ -1968,12 +1972,6 @@ int scsi_register_host(Scsi_Host_Template * tpnt)
}
}
}
-#if defined(USE_STATIC_SCSI_MEMORY)
- printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
if (out_of_space) {
scsi_unregister_host(tpnt); /* easiest way to clean up?? */
@@ -2163,13 +2161,6 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt)
printk(KERN_INFO "scsi : %d host%s left.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
-#if defined(USE_STATIC_SCSI_MEMORY)
- printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
-
/*
* Remove it from the linked list and /proc if all
* hosts were successfully removed (ie preset == 0)
@@ -2406,35 +2397,6 @@ static void scsi_dump_status(int level)
}
}
}
-
- for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
- for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
- /* Now dump the request lists for each block device */
- printk(KERN_INFO "Dump of pending block device requests\n");
- for (i = 0; i < MAX_BLKDEV; i++) {
- struct list_head * queue_head;
-
- queue_head = &blk_dev[i].request_queue.queue_head;
- if (!list_empty(queue_head)) {
- struct request *req;
- struct list_head * entry;
-
- printk(KERN_INFO "%d: ", i);
- entry = queue_head->next;
- do {
- req = blkdev_entry_to_request(entry);
- printk("(%s %d %ld %ld %ld) ",
- kdevname(req->rq_dev),
- req->cmd,
- req->sector,
- req->nr_sectors,
- req->current_nr_sectors);
- } while ((entry = entry->next) != queue_head);
- printk("\n");
- }
- }
- }
- }
#endif /* CONFIG_SCSI_LOGGING */ /* } */
}
#endif /* CONFIG_PROC_FS */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index b6894649e..57596d9eb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -8,7 +8,6 @@
*
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
@@ -583,7 +582,7 @@ STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout)
unsigned long flags;
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
retry:
/*
@@ -605,9 +604,9 @@ retry:
SCpnt->host->eh_action = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
host->hostt->queuecommand(SCpnt, scsi_eh_done);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
down(&sem);
@@ -630,10 +629,10 @@ retry:
* abort a timed out command or not. Not sure how
* we should treat them differently anyways.
*/
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
if (SCpnt->host->hostt->eh_abort_handler)
SCpnt->host->hostt->eh_abort_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
SCpnt->request.rq_status = RQ_SCSI_DONE;
SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
@@ -650,9 +649,9 @@ retry:
* timeout protection here, since we would end up waiting in
* the actual low level driver, we don't know how to wake it up.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
temp = host->hostt->command(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
SCpnt->result = temp;
/* Fall through to code below to examine status. */
@@ -772,9 +771,9 @@ STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
SCpnt->owner = SCSI_OWNER_LOWLEVEL;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
return rtn;
}
@@ -804,9 +803,9 @@ STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
}
SCpnt->owner = SCSI_OWNER_LOWLEVEL;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
@@ -837,9 +836,9 @@ STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
return FAILED;
}
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
@@ -883,9 +882,9 @@ STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt)
if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
return FAILED;
}
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
@@ -1226,7 +1225,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
Scsi_Device *SDpnt;
unsigned long flags;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/*
* Next free up anything directly waiting upon the host. This will be
@@ -1243,7 +1242,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
* now that error recovery is done, we will need to ensure that these
* requests are started.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q = &SDpnt->request_queue;
@@ -1256,7 +1255,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
q->request_fn(q);
}
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
}
/*
@@ -1303,7 +1302,7 @@ STATIC int scsi_unjam_host(struct Scsi_Host *host)
Scsi_Cmnd *SCdone;
int timed_out;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCdone = NULL;
@@ -1844,11 +1843,7 @@ void scsi_error_handler(void *data)
* If the HA was compiled into the kernel, then we don't listen
* to any signals.
*/
- if( host->loaded_as_module ) {
siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
- } else {
- siginitsetinv(&current->blocked, 0);
- }
lock_kernel();
@@ -1894,10 +1889,8 @@ void scsi_error_handler(void *data)
* semaphores isn't unreasonable.
*/
down_interruptible(&sem);
- if( host->loaded_as_module ) {
- if (signal_pending(current))
- break;
- }
+ if (signal_pending(current))
+ break;
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index f64d20090..b99553c5e 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -4,7 +4,6 @@
* - get rid of some verify_areas and use __copy*user and __get/put_user
* for the ones that remain
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <asm/io.h>
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 0188aaa2f..66f21a372 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -17,7 +17,6 @@
* go through and retrofit queueing functions into all 30 some-odd drivers.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
@@ -365,7 +364,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
* If there are blocks left over at the end, set up the command
* to queue the remainder of them.
*/
- if (end_that_request_first(req, 1, sectors)) {
+ if (end_that_request_first(req, uptodate, sectors)) {
if (!requeue)
return SCpnt;
@@ -444,7 +443,7 @@ static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
{
struct request *req = &SCpnt->request;
- ASSERT_LOCK(&SCpnt->host->host_lock, 0);
+ ASSERT_LOCK(SCpnt->host->host_lock, 0);
/*
* Free up any indirection buffers we allocated for DMA purposes.
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index 3368906c2..807ecbc58 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -15,7 +15,6 @@
* be handled all at once by a host adapter.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 01d667925..2f7e4adcc 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -17,7 +17,6 @@
*/
#include <linux/config.h> /* for CONFIG_PROC_FS */
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/string.h>
diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
index 1d9a90bbd..40d2ad5a2 100644
--- a/drivers/scsi/scsi_queue.c
+++ b/drivers/scsi/scsi_queue.c
@@ -10,7 +10,6 @@
* we attempt to remove commands from the queue and retry them.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
@@ -137,10 +136,10 @@ int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
* Decrement the counters, since these commands are no longer
* active on the host/device.
*/
- spin_lock_irqsave(&cmd->host->host_lock, flags);
+ spin_lock_irqsave(cmd->host->host_lock, flags);
cmd->host->host_busy--;
cmd->device->device_busy--;
- spin_unlock_irqrestore(&cmd->host->host_lock, flags);
+ spin_unlock_irqrestore(cmd->host->host_lock, flags);
/*
* Insert this command at the head of the queue for it's device.
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index aede1a6a9..8f4d70c1e 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -8,7 +8,6 @@
* clearer.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index 8f511d1a5..e363fac3d 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -2,7 +2,6 @@
* We should not even be trying to compile this if we are not doing
* a module.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index e8f8c90bf..3582d44e0 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -10,7 +10,6 @@
* For more information, please consult the SCSI-CAM draft.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/fs.h>
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index bc030dcb4..f22d1414d 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -643,9 +643,9 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;
#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
#define NCR_LOCK_SCSI_DONE(host, flags) \
- spin_lock_irqsave(&((host)->host_lock), flags)
+ spin_lock_irqsave(((host)->host_lock), flags)
#define NCR_UNLOCK_SCSI_DONE(host, flags) \
- spin_unlock_irqrestore(&((host)->host_lock), flags)
+ spin_unlock_irqrestore(((host)->host_lock), flags)
#else
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index d8c43a9d5..10e68e096 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -138,11 +138,11 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;
#define SYM_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags)
#define SYM_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags)
-#define SYM_INIT_LOCK_HCB(np) spin_lock_init(&np->s.host->host_lock);
+#define SYM_INIT_LOCK_HCB(np) spin_lock_init((np)->s.host->host_lock);
#define SYM_LOCK_HCB(np, flags) \
- spin_lock_irqsave(&np->s.host->host_lock, flags)
+ spin_lock_irqsave((np)->s.host->host_lock, flags)
#define SYM_UNLOCK_HCB(np, flags) \
- spin_unlock_irqrestore(&np->s.host->host_lock, flags)
+ spin_unlock_irqrestore((np)->s.host->host_lock, flags)
/*
* These simple macros limit expression involving
diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c
index d90a28c85..209c40f61 100644
--- a/drivers/sound/ymfpci.c
+++ b/drivers/sound/ymfpci.c
@@ -1,6 +1,8 @@
/*
* Copyright 1999 Jaroslav Kysela <perex@suse.cz>
* Copyright 2000 Alan Cox <alan@redhat.com>
+ * Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
+ * Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
*
* Yamaha YMF7xx driver.
*
@@ -37,8 +39,16 @@
* - Remove prog_dmabuf from read/write, leave it in open.
* - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
* native synthesizer through a playback slot.
- * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
- * - Make the thing big endian compatible. ALSA has it done.
+ * - 2001/11/29 ac97_save_state
+ * Talk to Kai to remove ac97_save_state before it's too late!
+ * - Second AC97
+ * - Restore S/PDIF - Toshibas have it.
+ *
+ * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
+ * unconventional. However, given how small our fragments can be,
+ * a little uncached access is perhaps better than endless flushing.
+ * On i386 and other I/O-coherent architectures pci_alloc_consistent
+ * is entirely harmless.
*/
#include <linux/config.h>
@@ -155,7 +165,7 @@ static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched)
schedule_timeout(1);
}
} while (end_time - (signed long)jiffies >= 0);
- printk("ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
+ printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
secondary, ymfpci_readw(codec, reg));
return -EBUSY;
}
@@ -173,19 +183,19 @@ static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
{
- ymfpci_t *codec = dev->private_data;
+ ymfpci_t *unit = dev->private_data;
+ int i;
- if (ymfpci_codec_ready(codec, 0, 0))
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
- if (ymfpci_codec_ready(codec, 0, 0))
+ ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) {
- int i;
+ if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
for (i = 0; i < 600; i++)
- ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
- return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
/*
@@ -279,18 +289,22 @@ static void ymf_pcm_update_shift(struct ymf_pcm_format *f)
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1
-/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Allocate DMA buffer
+ */
+static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
{
void *rawbuf = NULL;
+ dma_addr_t dma_addr;
int order;
- struct page * map, * mapend;
+ struct page *map, *mapend;
/* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+ rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
+ if (rawbuf)
break;
-
+ }
if (!rawbuf)
return -ENOMEM;
@@ -301,6 +315,7 @@ static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
dmabuf->ready = dmabuf->mapped = 0;
dmabuf->rawbuf = rawbuf;
+ dmabuf->dma_addr = dma_addr;
dmabuf->buforder = order;
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
@@ -311,8 +326,10 @@ static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
return 0;
}
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Free DMA buffer
+ */
+static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
{
struct page *map, *mapend;
@@ -321,7 +338,9 @@ static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf)
mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
clear_bit(PG_reserved, &map->flags);
- free_pages((unsigned long)dmabuf->rawbuf,dmabuf->buforder);
+
+ pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
+ dmabuf->rawbuf, dmabuf->dma_addr);
}
dmabuf->rawbuf = NULL;
dmabuf->mapped = dmabuf->ready = 0;
@@ -347,7 +366,7 @@ static int prog_dmabuf(struct ymf_state *state, int rec)
/* allocate DMA buffer if not allocated yet */
if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(dmabuf)))
+ if ((ret = alloc_dmabuf(state->unit, dmabuf)))
return ret;
/*
@@ -404,7 +423,7 @@ static int prog_dmabuf(struct ymf_state *state, int rec)
dmabuf->ready = 1;
#if 0
- printk("prog_dmabuf: rate %d format 0x%x,"
+ printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
" numfrag %d fragsize %d dmasize %d\n",
state->format.rate, state->format.format, dmabuf->numfrag,
dmabuf->fragsize, dmabuf->dmasize);
@@ -587,7 +606,8 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
if (ypcm->running) {
YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
voice->number, codec->active_bank, dmabuf->count,
- voice->bank[0].start, voice->bank[1].start);
+ le32_to_cpu(voice->bank[0].start),
+ le32_to_cpu(voice->bank[1].start));
silence = (ymf_pcm_format_width(state->format.format) == 16) ?
0 : 0x80;
/* We need actual left-hand-side redzone size here. */
@@ -595,7 +615,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
redzone <<= (state->format.shift + 1);
swptr = dmabuf->swptr;
- pos = voice->bank[codec->active_bank].start;
+ pos = le32_to_cpu(voice->bank[codec->active_bank].start);
pos <<= state->format.shift;
if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
@@ -615,7 +635,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
dmabuf->hwptr = pos;
if (dmabuf->count == 0) {
- printk("ymfpci%d: %d: strain: hwptr %d\n",
+ printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
codec->dev_audio, voice->number, dmabuf->hwptr);
ymf_playback_trigger(codec, ypcm, 0);
}
@@ -633,7 +653,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
/*
* Lost interrupt or other screwage.
*/
- printk("ymfpci%d: %d: lost: delta %d"
+ printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
" hwptr %d swptr %d distance %d count %d\n",
codec->dev_audio, voice->number, delta,
dmabuf->hwptr, swptr, distance, dmabuf->count);
@@ -641,10 +661,10 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
/*
* Normal end of DMA.
*/
-// printk("ymfpci%d: %d: done: delta %d"
-// " hwptr %d swptr %d distance %d count %d\n",
-// codec->dev_audio, voice->number, delta,
-// dmabuf->hwptr, swptr, distance, dmabuf->count);
+ YMFDBGI("ymfpci%d: %d: done: delta %d"
+ " hwptr %d swptr %d distance %d count %d\n",
+ codec->dev_audio, voice->number, delta,
+ dmabuf->hwptr, swptr, distance, dmabuf->count);
}
played = dmabuf->count;
if (ypcm->running) {
@@ -698,7 +718,7 @@ static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
redzone = ymf_calc_lend(state->format.rate);
redzone <<= (state->format.shift + 1);
- pos = cap->bank[unit->active_bank].start;
+ pos = le32_to_cpu(cap->bank[unit->active_bank].start);
// pos <<= state->format.shift;
if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
@@ -742,9 +762,11 @@ static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
return -EINVAL;
}
if (cmd != 0) {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] = virt_to_bus(ypcm->voices[0]->bank);
+ codec->ctrl_playback[ypcm->voices[0]->number + 1] =
+ cpu_to_le32(ypcm->voices[0]->bank_ba);
if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] = virt_to_bus(ypcm->voices[1]->bank);
+ codec->ctrl_playback[ypcm->voices[1]->number + 1] =
+ cpu_to_le32(ypcm->voices[1]->bank_ba);
ypcm->running = 1;
} else {
codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
@@ -810,6 +832,7 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
u32 lpfK = ymfpci_calc_lpfK(rate);
ymfpci_playback_bank_t *bank;
int nbank;
+ unsigned le_0x40000000 = cpu_to_le32(0x40000000);
format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
if (stereo)
@@ -818,24 +841,24 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
end >>= 1;
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
- bank->format = format;
+ bank->format = cpu_to_le32(format);
bank->loop_default = 0; /* 0-loops forever, otherwise count */
- bank->base = addr;
+ bank->base = cpu_to_le32(addr);
bank->loop_start = 0;
- bank->loop_end = end;
+ bank->loop_end = cpu_to_le32(end);
bank->loop_frac = 0;
- bank->eg_gain_end = 0x40000000;
- bank->lpfQ = lpfQ;
+ bank->eg_gain_end = le_0x40000000;
+ bank->lpfQ = cpu_to_le32(lpfQ);
bank->status = 0;
bank->num_of_frames = 0;
bank->loop_count = 0;
bank->start = 0;
bank->start_frac = 0;
bank->delta =
- bank->delta_end = delta;
+ bank->delta_end = cpu_to_le32(delta);
bank->lpfK =
- bank->lpfK_end = lpfK;
- bank->eg_gain = 0x40000000;
+ bank->lpfK_end = cpu_to_le32(lpfK);
+ bank->eg_gain = le_0x40000000;
bank->lpfD1 =
bank->lpfD2 = 0;
@@ -855,31 +878,31 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
bank->left_gain =
bank->right_gain =
bank->left_gain_end =
- bank->right_gain_end = 0x40000000;
+ bank->right_gain_end = le_0x40000000;
} else {
bank->eff2_gain =
bank->eff2_gain_end =
bank->eff3_gain =
- bank->eff3_gain_end = 0x40000000;
+ bank->eff3_gain_end = le_0x40000000;
}
} else {
if (!spdif) {
if ((voice->number & 1) == 0) {
bank->left_gain =
- bank->left_gain_end = 0x40000000;
+ bank->left_gain_end = le_0x40000000;
} else {
- bank->format |= 1;
+ bank->format |= cpu_to_le32(1);
bank->right_gain =
- bank->right_gain_end = 0x40000000;
+ bank->right_gain_end = le_0x40000000;
}
} else {
if ((voice->number & 1) == 0) {
bank->eff2_gain =
- bank->eff2_gain_end = 0x40000000;
+ bank->eff2_gain_end = le_0x40000000;
} else {
- bank->format |= 1;
+ bank->format |= cpu_to_le32(1);
bank->eff3_gain =
- bank->eff3_gain_end = 0x40000000;
+ bank->eff3_gain_end = le_0x40000000;
}
}
}
@@ -920,7 +943,7 @@ static int ymf_playback_prepare(struct ymf_state *state)
ymf_pcm_init_voice(ypcm->voices[nvoice],
state->format.voices == 2, state->format.rate,
ymf_pcm_format_width(state->format.format) == 16,
- virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize,
+ ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
ypcm->spdif);
}
return 0;
@@ -969,9 +992,9 @@ static int ymf_capture_prepare(struct ymf_state *state)
}
for (nbank = 0; nbank < 2; nbank++) {
bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
- bank->base = virt_to_bus(ypcm->dmabuf.rawbuf);
+ bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
// bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
- bank->loop_end = ypcm->dmabuf.dmasize;
+ bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
bank->start = 0;
bank->num_of_loops = 0;
}
@@ -1442,13 +1465,14 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
struct ymf_dmabuf *dmabuf;
+ int redzone;
unsigned long flags;
unsigned int mask = 0;
if (file->f_mode & FMODE_WRITE)
poll_wait(file, &state->wpcm.dmabuf.wait, wait);
- // if (file->f_mode & FMODE_READ)
- // poll_wait(file, &dmabuf->wait, wait);
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &state->rpcm.dmabuf.wait, wait);
spin_lock_irqsave(&state->unit->reg_lock, flags);
if (file->f_mode & FMODE_READ) {
@@ -1457,12 +1481,21 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
mask |= POLLIN | POLLRDNORM;
}
if (file->f_mode & FMODE_WRITE) {
+ redzone = ymf_calc_lend(state->format.rate);
+ redzone <<= state->format.shift;
+ redzone *= 3;
+
dmabuf = &state->wpcm.dmabuf;
if (dmabuf->mapped) {
if (dmabuf->count >= (signed)dmabuf->fragsize)
mask |= POLLOUT | POLLWRNORM;
} else {
- if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+ /*
+ * Don't select unless a full fragment is available.
+ * Otherwise artsd does GETOSPACE, sees 0, and loops.
+ */
+ if (dmabuf->count + redzone + dmabuf->fragsize
+ <= dmabuf->dmasize)
mask |= POLLOUT | POLLWRNORM;
}
}
@@ -1509,13 +1542,16 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int redzone;
int val;
switch (cmd) {
case OSS_GETVERSION:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_RESET:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
@@ -1537,6 +1573,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_SYNC:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
dmabuf = &state->wpcm.dmabuf;
if (file->f_flags & O_NONBLOCK) {
@@ -1555,6 +1592,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_SPEED: /* set smaple rate */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
if (val >= 8000 && val <= 48000) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1586,6 +1624,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
@@ -1607,24 +1646,31 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_GETBLKSIZE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(state, 0)))
return val;
- return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
+ val = state->wpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+ return put_user(val, (int *)arg);
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf(state, 1)))
return val;
- return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
+ val = state->rpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+ return put_user(val, (int *)arg);
}
return -EINVAL;
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
if (val == AFMT_S16_LE || val == AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1650,6 +1696,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1677,6 +1724,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return put_user(state->format.voices, (int *)arg);
case SNDCTL_DSP_POST:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
/*
* Quoting OSS PG:
* The ioctl SNDCTL_DSP_POST is a lightweight version of
@@ -1698,6 +1746,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+ cmd,
+ (val >> 16) & 0xFFFF, val & 0xFFFF,
+ (val >> 16) & 0xFFFF, val & 0xFFFF);
dmabuf = &state->wpcm.dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
@@ -1708,20 +1760,25 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_GETOSPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
+ redzone = ymf_calc_lend(state->format.rate);
+ redzone <<= state->format.shift;
+ redzone *= 3;
spin_lock_irqsave(&state->unit->reg_lock, flags);
abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+ abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
@@ -1736,15 +1793,18 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETCAPS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
(int *)arg); */
return put_user(0, (int *)arg);
case SNDCTL_DSP_GETIPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
@@ -1752,13 +1812,13 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
- /* XXX fishy - breaks invariant count=hwptr-swptr */
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
@@ -1766,22 +1826,25 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
- /* XXX fishy - breaks invariant count=swptr-hwptr */
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */
- return -EINVAL;
+ case SNDCTL_DSP_SETDUPLEX:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
+ return 0; /* Always duplex */
case SOUND_PCM_READ_RATE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
return put_user(state->format.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
return put_user(state->format.voices, (int *)arg);
case SOUND_PCM_READ_BITS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
return put_user(AFMT_S16_LE, (int *)arg);
case SNDCTL_DSP_MAPINBUF:
@@ -1797,6 +1860,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
* Some programs mix up audio devices and ioctls
* or perhaps they expect "universal" ioctls,
* for instance we get SNDCTL_TMR_CONTINUE here.
+ * (mpg123 -g 100 ends here too - to be fixed.)
*/
YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
break;
@@ -1867,8 +1931,8 @@ static int ymf_open(struct inode *inode, struct file *file)
}
#if 0 /* test if interrupts work */
- ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
+ ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
(YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
#endif
up(&unit->open_sem);
@@ -1881,8 +1945,8 @@ out_nodma:
* a nestable exception, but here it is not nestable due to semaphore.
* XXX Doubtful technique of self-describing objects....
*/
- dealloc_dmabuf(&state->wpcm.dmabuf);
- dealloc_dmabuf(&state->rpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->rpcm.dmabuf);
ymf_pcm_free_substream(&state->wpcm);
ymf_pcm_free_substream(&state->rpcm);
@@ -1896,13 +1960,13 @@ out_nodma:
static int ymf_release(struct inode *inode, struct file *file)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- ymfpci_t *codec = state->unit;
+ ymfpci_t *unit = state->unit;
#if 0 /* test if interrupts work */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
#endif
- down(&codec->open_sem);
+ down(&unit->open_sem);
/*
* XXX Solve the case of O_NONBLOCK close - don't deallocate here.
@@ -1910,8 +1974,8 @@ static int ymf_release(struct inode *inode, struct file *file)
*/
ymf_wait_dac(state);
ymf_stop_adc(state); /* fortunately, it's immediate */
- dealloc_dmabuf(&state->wpcm.dmabuf);
- dealloc_dmabuf(&state->rpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->rpcm.dmabuf);
ymf_pcm_free_substream(&state->wpcm);
ymf_pcm_free_substream(&state->rpcm);
@@ -1919,7 +1983,7 @@ static int ymf_release(struct inode *inode, struct file *file)
file->private_data = NULL; /* Can you tell I programmed Solaris */
kfree(state);
- up(&codec->open_sem);
+ up(&unit->open_sem);
return 0;
}
@@ -1929,10 +1993,10 @@ static int ymf_release(struct inode *inode, struct file *file)
*/
static int ymf_open_mixdev(struct inode *inode, struct file *file)
{
- int i;
int minor = minor(inode->i_rdev);
struct list_head *list;
ymfpci_t *unit;
+ int i;
list_for_each(list, &ymf_devs) {
unit = list_entry(list, ymfpci_t, ymf_devs);
@@ -1989,23 +2053,21 @@ static /*const*/ struct file_operations ymf_mixer_fops = {
static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct ymf_dmabuf *dmabuf;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
spin_lock_irqsave(&unit->reg_lock, flags);
unit->suspended = 1;
for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_save_state(codec);
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_save_state(codec);
}
list_for_each(p, &unit->states) {
@@ -2032,12 +2094,12 @@ static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
static int ymf_resume(struct pci_dev *pcidev)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
ymfpci_aclink_reset(unit->pci);
ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
@@ -2058,10 +2120,8 @@ static int ymf_resume(struct pci_dev *pcidev)
}
for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_restore_state(codec);
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_restore_state(codec);
}
unit->suspended = 0;
@@ -2161,12 +2221,15 @@ static void ymfpci_aclink_reset(struct pci_dev * pci)
{
u8 cmd;
+ /*
+ * In the 744, 754 only 0x01 exists, 0x02 is undefined.
+ * It does not seem to hurt to trip both regardless of revision.
+ */
pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
- if (cmd & 0x03) {
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- }
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+
pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
}
@@ -2242,29 +2305,39 @@ static void ymfpci_download_image(ymfpci_t *codec)
static int ymfpci_memalloc(ymfpci_t *codec)
{
- long size, playback_ctrl_size;
+ unsigned int playback_ctrl_size;
+ unsigned int bank_size_playback;
+ unsigned int bank_size_capture;
+ unsigned int bank_size_effect;
+ unsigned int size;
+ unsigned int off;
+ char *ptr;
+ dma_addr_t pba;
int voice, bank;
- u8 *ptr;
playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
- codec->bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
- codec->bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
- codec->bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
+ bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
+ bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
+ bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
- ((codec->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
- ((codec->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
- ((codec->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
+ ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
+ ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
+ ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
codec->work_size;
- ptr = (u8 *)kmalloc(size + 0x00ff, GFP_KERNEL);
+ ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
if (ptr == NULL)
return -ENOMEM;
+ codec->dma_area_va = ptr;
+ codec->dma_area_ba = pba;
+ codec->dma_area_size = size + 0xff;
- codec->work_ptr = ptr;
- ptr += 0x00ff;
- (long)ptr &= ~0x00ff;
+ if ((off = ((uint) ptr) & 0xff) != 0) {
+ ptr += 0x100 - off;
+ pba += 0x100 - off;
+ }
/*
* Hardware requires only ptr[playback_ctrl_size] zeroed,
@@ -2272,34 +2345,49 @@ static int ymfpci_memalloc(ymfpci_t *codec)
*/
memset(ptr, 0, size);
- codec->bank_base_playback = ptr;
codec->ctrl_playback = (u32 *)ptr;
- codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;
+ codec->ctrl_playback_ba = pba;
+ codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+ pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+
+ off = 0;
for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
- for (bank = 0; bank < 2; bank++) {
- codec->bank_playback[voice][bank] = (ymfpci_playback_bank_t *)ptr;
- ptr += codec->bank_size_playback;
- }
codec->voices[voice].number = voice;
- codec->voices[voice].bank = codec->bank_playback[voice][0];
+ codec->voices[voice].bank =
+ (ymfpci_playback_bank_t *) (ptr + off);
+ codec->voices[voice].bank_ba = pba + off;
+ off += 2 * bank_size_playback; /* 2 banks */
}
- ptr += (codec->bank_size_playback + 0x00ff) & ~0x00ff;
- codec->bank_base_capture = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ off = 0;
+ codec->bank_base_capture = pba;
for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
for (bank = 0; bank < 2; bank++) {
- codec->bank_capture[voice][bank] = (ymfpci_capture_bank_t *)ptr;
- ptr += codec->bank_size_capture;
+ codec->bank_capture[voice][bank] =
+ (ymfpci_capture_bank_t *) (ptr + off);
+ off += bank_size_capture;
}
- ptr += (codec->bank_size_capture + 0x00ff) & ~0x00ff;
- codec->bank_base_effect = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ off = 0;
+ codec->bank_base_effect = pba;
for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
for (bank = 0; bank < 2; bank++) {
- codec->bank_effect[voice][bank] = (ymfpci_effect_bank_t *)ptr;
- ptr += codec->bank_size_effect;
+ codec->bank_effect[voice][bank] =
+ (ymfpci_effect_bank_t *) (ptr + off);
+ off += bank_size_effect;
}
- ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff;
- codec->work_base = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ codec->work_base = pba;
return 0;
}
@@ -2311,16 +2399,17 @@ static void ymfpci_memfree(ymfpci_t *codec)
ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
- kfree(codec->work_ptr);
+ pci_free_consistent(codec->pci,
+ codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
}
static void ymf_memload(ymfpci_t *unit)
{
- ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback));
- ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture));
- ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect));
- ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base));
+ ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
+ ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
+ ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
+ ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
/* S/PDIF output initialization */
@@ -2358,7 +2447,7 @@ static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
codec->codec_write = ymfpci_codec_write;
if (ac97_probe_codec(codec) == 0) {
- printk("ymfpci: ac97_probe_codec failed\n");
+ printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
goto out_kfree;
}
@@ -2399,6 +2488,7 @@ static int assigned;
static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
u16 ctrl;
+ unsigned long base;
ymfpci_t *codec;
int err;
@@ -2407,6 +2497,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
return err;
}
+ base = pci_resource_start(pcidev, 0);
if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "ymfpci: no core\n");
@@ -2421,16 +2512,21 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
codec->pci = pcidev;
pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
- codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
- if (codec->reg_area_virt == NULL) {
- printk(KERN_ERR "ymfpci: unable to map registers\n");
+
+ if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
+ printk(KERN_ERR "ymfpci: unable to request mem region\n");
goto out_free;
}
+ if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
+ printk(KERN_ERR "ymfpci: unable to map registers\n");
+ goto out_release_region;
+ }
+
pci_set_master(pcidev);
printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
- (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
+ (char *)ent->driver_data, base, pcidev->irq);
ymfpci_aclink_reset(pcidev);
if (ymfpci_codec_ready(codec, 0, 1) < 0)
@@ -2460,8 +2556,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
/* register /dev/dsp */
if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci%d: unable to register dsp\n",
- codec->dev_audio);
+ printk(KERN_ERR "ymfpci: unable to register dsp\n");
goto out_free_irq;
}
@@ -2479,7 +2574,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
codec->opl3_data.irq = -1;
codec->mpu_data.io_base = codec->iomidi;
- codec->mpu_data.irq = -1; /* XXX Make it ours. */
+ codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */
if (codec->iomidi) {
if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
@@ -2507,6 +2602,8 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
ymfpci_writel(codec, YDSXGR_STATUS, ~0);
out_unmap:
iounmap(codec->reg_area_virt);
+ out_release_region:
+ release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
out_free:
kfree(codec);
return -ENODEV;
@@ -2530,6 +2627,7 @@ static void __devexit ymf_remove_one(struct pci_dev *pcidev)
ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
iounmap(codec->reg_area_virt);
+ release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
#ifdef CONFIG_SOUND_YMFPCI_LEGACY
if (codec->iomidi) {
unload_uart401(&codec->mpu_data);
diff --git a/drivers/sound/ymfpci.h b/drivers/sound/ymfpci.h
index 1686f204d..9ecf6b2ca 100644
--- a/drivers/sound/ymfpci.h
+++ b/drivers/sound/ymfpci.h
@@ -227,6 +227,7 @@ struct ymf_voice {
char use, pcm, synth, midi; // bool
ymfpci_playback_bank_t *bank;
struct ymf_pcm *ypcm;
+ dma_addr_t bank_ba;
};
struct ymf_capture {
@@ -239,19 +240,17 @@ struct ymf_capture {
struct ymf_unit {
u8 rev; /* PCI revision */
void *reg_area_virt;
- void *work_ptr;
+ void *dma_area_va;
+ dma_addr_t dma_area_ba;
+ unsigned int dma_area_size;
- unsigned int bank_size_playback;
- unsigned int bank_size_capture;
- unsigned int bank_size_effect;
+ dma_addr_t bank_base_capture;
+ dma_addr_t bank_base_effect;
+ dma_addr_t work_base;
unsigned int work_size;
- void *bank_base_playback;
- void *bank_base_capture;
- void *bank_base_effect;
- void *work_base;
-
u32 *ctrl_playback;
+ dma_addr_t ctrl_playback_ba;
ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
@@ -286,10 +285,11 @@ struct ymf_unit {
};
struct ymf_dmabuf {
-
- /* OSS buffer management stuff */
+ dma_addr_t dma_addr;
void *rawbuf;
unsigned buforder;
+
+ /* OSS buffer management stuff */
unsigned numfrag;
unsigned fragshift;
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index 0380ee2df..c8eb8d1e4 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -46,7 +46,7 @@ static DECLARE_MUTEX(phone_lock);
static int phone_open(struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int err = 0;
struct phone_device *p;
struct file_operations *old_fops, *new_fops = NULL;
diff --git a/drivers/usb/Makefile.lib b/drivers/usb/Makefile.lib
new file mode 100644
index 000000000..891c91821
--- /dev/null
+++ b/drivers/usb/Makefile.lib
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_CATC) += crc32.o
diff --git a/drivers/usb/catc.c b/drivers/usb/catc.c
index 856fb1c8f..cc1486170 100644
--- a/drivers/usb/catc.c
+++ b/drivers/usb/catc.c
@@ -39,6 +39,7 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
@@ -531,13 +532,9 @@ static struct net_device_stats *catc_get_stats(struct net_device *netdev)
static void catc_multicast(unsigned char *addr, u8 *multicast)
{
- unsigned int crc = 0xffffffff;
- u8 byte, idx, bit;
-
- for (idx = 0; idx < 6; idx++)
- for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)
- crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);
+ u32 crc;
+ crc = ether_crc_le(6, addr);
multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
}
diff --git a/fs/Makefile.lib b/fs/Makefile.lib
new file mode 100644
index 000000000..0ca1cff14
--- /dev/null
+++ b/fs/Makefile.lib
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FS_JFFS2) += crc32.o
+obj-$(CONFIG_EFI_PARTITION) += crc32.o
diff --git a/fs/affs/file.c b/fs/affs/file.c
index a09a4502e..6a3602298 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -401,6 +401,7 @@ err_ext:
err_alloc:
brelse(ext_bh);
bh_result->b_state &= ~(1UL << BH_Mapped);
+ bh_result->b_bdev = NULL;
// unlock cache
affs_unlock_ext(inode);
return -ENOSPC;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 672bd95c7..4f34a8c0d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -128,6 +128,7 @@ static int blkdev_get_block(struct inode * inode, sector_t iblock, struct buffer
return -EIO;
bh->b_dev = inode->i_rdev;
+ bh->b_bdev = inode->i_bdev;
bh->b_blocknr = iblock;
bh->b_state |= 1UL << BH_Mapped;
return 0;
diff --git a/fs/buffer.c b/fs/buffer.c
index b55ac6aba..8a9233a44 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -83,7 +83,7 @@ static int nr_unused_buffer_heads;
static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
-static int grow_buffers(kdev_t dev, unsigned long block, int size);
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size);
static void __refile_buffer(struct buffer_head *);
/* This is used by some architectures to estimate available memory. */
@@ -557,9 +557,9 @@ static void remove_from_queues(struct buffer_head *bh)
spin_unlock(&lru_list_lock);
}
-struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block, int size)
{
- struct buffer_head *bh, **p = &hash(dev, block);
+ struct buffer_head *bh, **p = &hash(to_kdev_t(bdev->bd_dev), block);
read_lock(&hash_table_lock);
@@ -572,7 +572,7 @@ struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
continue;
if (bh->b_size != size)
continue;
- if (!kdev_same(bh->b_dev, dev))
+ if (bh->b_bdev != bdev)
continue;
get_bh(bh);
break;
@@ -1024,15 +1024,14 @@ void invalidate_inode_buffers(struct inode *inode)
*/
struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size)
{
- kdev_t dev = to_kdev_t(bdev->bd_dev);
for (;;) {
struct buffer_head * bh;
- bh = get_hash_table(dev, block, size);
+ bh = __get_hash_table(bdev, block, size);
if (bh)
return bh;
- if (!grow_buffers(dev, block, size))
+ if (!grow_buffers(bdev, block, size))
free_more_memory();
}
}
@@ -1202,6 +1201,7 @@ static void __put_unused_buffer_head(struct buffer_head * bh)
kmem_cache_free(bh_cachep, bh);
} else {
bh->b_dev = B_FREE;
+ bh->b_bdev = NULL;
bh->b_blocknr = -1;
bh->b_this_page = NULL;
@@ -1305,6 +1305,7 @@ try_again:
goto no_grow;
bh->b_dev = NODEV;
+ bh->b_bdev = NULL;
bh->b_this_page = head;
head = bh;
@@ -1366,6 +1367,7 @@ static void discard_buffer(struct buffer_head * bh)
if (buffer_mapped(bh)) {
mark_buffer_clean(bh);
lock_buffer(bh);
+ bh->b_bdev = NULL;
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
@@ -1487,7 +1489,7 @@ static void unmap_underlying_metadata(struct buffer_head * bh)
{
struct buffer_head *old_bh;
- old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
if (old_bh) {
mark_buffer_clean(old_bh);
wait_on_buffer(old_bh);
@@ -2119,7 +2121,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, sector_t b[],
* FIXME: we need a swapper_inode->get_block function to remove
* some of the bmap kludges and interface ugliness here.
*/
-int brw_page(int rw, struct page *page, kdev_t dev, sector_t b[], int size)
+int brw_page(int rw, struct page *page, struct block_device *bdev, sector_t b[], int size)
{
struct buffer_head *head, *bh;
@@ -2134,7 +2136,8 @@ int brw_page(int rw, struct page *page, kdev_t dev, sector_t b[], int size)
do {
lock_buffer(bh);
bh->b_blocknr = *(b++);
- bh->b_dev = dev;
+ bh->b_bdev = bdev;
+ bh->b_dev = to_kdev_t(bdev->bd_dev);
set_bit(BH_Mapped, &bh->b_state);
set_buffer_async_io(bh);
bh = bh->b_this_page;
@@ -2234,7 +2237,7 @@ failed:
return NULL;
}
-static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size)
+static void hash_page_buffers(struct page *page, struct block_device *bdev, int block, int size)
{
struct buffer_head *head = page->buffers;
struct buffer_head *bh = head;
@@ -2248,7 +2251,8 @@ static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size
do {
if (!(bh->b_state & (1 << BH_Mapped))) {
init_buffer(bh, NULL, NULL);
- bh->b_dev = dev;
+ bh->b_bdev = bdev;
+ bh->b_dev = to_kdev_t(bdev->bd_dev);
bh->b_blocknr = block;
bh->b_state = uptodate;
}
@@ -2267,15 +2271,14 @@ static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size
* Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want.
*/
-static int grow_buffers(kdev_t dev, unsigned long block, int size)
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size)
{
struct page * page;
- struct block_device *bdev;
unsigned long index;
int sizebits;
/* Size must be multiple of hard sectorsize */
- if (size & (get_hardsect_size(dev)-1))
+ if (size & (get_hardsect_size(to_kdev_t(bdev->bd_dev))-1))
BUG();
/* Size must be within 512 bytes and PAGE_SIZE */
if (size < 512 || size > PAGE_SIZE)
@@ -2289,22 +2292,14 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size)
index = block >> sizebits;
block = index << sizebits;
- bdev = bdget(kdev_t_to_nr(dev));
- if (!bdev) {
- printk("No block device for %s\n", kdevname(dev));
- BUG();
- }
-
/* Create a page with the proper size buffers.. */
page = grow_dev_page(bdev, index, size);
- /* This is "wrong" - talk to Al Viro */
- atomic_dec(&bdev->bd_count);
if (!page)
return 0;
/* Hash in the buffers on the hash list */
- hash_page_buffers(page, dev, block, size);
+ hash_page_buffers(page, bdev, block, size);
UnlockPage(page);
page_cache_release(page);
diff --git a/fs/dcache.c b/fs/dcache.c
index d4379a0ee..7246506ff 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1262,7 +1262,7 @@ void __init vfs_caches_init(unsigned long mempages)
panic("Cannot create buffer head SLAB cache");
names_cachep = kmem_cache_create("names_cache",
- PATH_MAX + 1, 0,
+ PATH_MAX, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!names_cachep)
panic("Cannot create names SLAB cache");
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 639ae7464..19c406600 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -601,6 +601,9 @@
Only return old entry in <devfs_mk_dir> if a directory.
Defined macros for error and debug messages.
v1.8
+ 20020113 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed (rare, old) race in <devfs_lookup>.
+ v1.9
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -633,7 +636,7 @@
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "1.8 (20011226)"
+#define DEVFS_VERSION "1.9 (20020113)"
#define DEVFS_NAME "devfs"
@@ -894,8 +897,8 @@ void devfs_put (devfs_handle_t de)
{
devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
DEVFS_SPECIAL_BLK,
- mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor) );
+ mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor) );
}
WRITE_ENTRY_MAGIC (de, 0);
#ifdef CONFIG_DEVFS_DEBUG
@@ -1552,7 +1555,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
(flags & DEVFS_FL_AUTO_DEVNUM) )
{
- if ( kdev_none( devnum = devfs_alloc_devnum (devtype) ) )
+ if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
{
PRINTK ("(%s): exhausted %s device numbers\n",
name, S_ISCHR (mode) ? "char" : "block");
@@ -1564,14 +1567,14 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
{
PRINTK ("(%s): could not prepare leaf\n", name);
- if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+ if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
return NULL;
}
if ( S_ISCHR (mode) || S_ISBLK (mode) )
{
de->u.fcb.u.device.major = major;
de->u.fcb.u.device.minor = minor;
- de->u.fcb.autogen = kdev_none(devnum) ? FALSE : TRUE;
+ de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
}
else if ( !S_ISREG (mode) )
{
@@ -1601,7 +1604,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
{
PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
devfs_put (dir);
- if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+ if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
return NULL;
}
DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n",
@@ -2378,7 +2381,7 @@ EXPORT_SYMBOL(devfs_unregister_blkdev);
* @buf: A working area that will be used. This must not go out of scope
* until devfsd is idle again.
*
- * Returns 0 on success, else a negative error code.
+ * Returns 0 on success (event was queued), else a negative error code.
*/
static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
@@ -2397,7 +2400,7 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
current->euid, current->egid, fs_info, 0) )
return -ENOENT;
- /* Possible success */
+ /* Possible success: event has been queued */
return 0;
} /* End Function try_modload */
@@ -2413,7 +2416,7 @@ static int check_disc_changed (struct devfs_entry *de)
{
int tmp;
int retval = 0;
- kdev_t dev = mk_kdev(de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
+ kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
struct block_device_operations *bdops;
extern int warn_no_part;
@@ -2599,15 +2602,15 @@ static struct inode *_devfs_get_vfs_inode (struct super_block *sb,
inode->i_rdev = NODEV;
if ( S_ISCHR (de->mode) )
{
- inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
+ inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
is_fcb = TRUE;
}
else if ( S_ISBLK (de->mode) )
{
- inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
+ inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
if (bd_acquire (inode) == 0)
{
if (!inode->i_bdev->bd_op && de->u.fcb.ops)
@@ -2861,34 +2864,55 @@ static int devfs_d_delete (struct dentry *dentry)
return 0;
} /* End Function devfs_d_delete */
+struct devfs_lookup_struct
+{
+ devfs_handle_t de;
+ wait_queue_head_t wait_queue;
+};
+
static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
{
struct inode *dir = dentry->d_parent->d_inode;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+ devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+ struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
+ DECLARE_WAITQUEUE (wait, current);
if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
{
- devfs_handle_t de;
- devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+ devfs_handle_t de = lookup_info->de;
struct inode *inode;
- DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n",
- dentry->d_name.name, dentry, current->comm);
- read_lock (&parent->u.dir.lock);
- de = _devfs_search_dir (parent, dentry->d_name.name,
- dentry->d_name.len);
- read_unlock (&parent->u.dir.lock);
- if (de == NULL) return 1;
+ DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p de: %p by: \"%s\"\n",
+ dentry->d_name.name, dentry, de, current->comm);
+ if (de == NULL)
+ {
+ read_lock (&parent->u.dir.lock);
+ de = _devfs_search_dir (parent, dentry->d_name.name,
+ dentry->d_name.len);
+ read_unlock (&parent->u.dir.lock);
+ if (de == NULL) return 1;
+ lookup_info->de = de;
+ }
/* Create an inode, now that the driver information is available */
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
- devfs_put (de);
if (!inode) return 1;
- DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n",
- de->name, de->inode.ino, inode, de);
+ DPRINTK (DEBUG_I_LOOKUP,
+ "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+ de->name, de->inode.ino, inode, de, current->comm);
d_instantiate (dentry, inode);
return 1;
}
- if ( wait_for_devfsd_finished (fs_info) ) dentry->d_op = &devfs_dops;
+ if (lookup_info == NULL) return 1; /* Early termination */
+ read_lock (&parent->u.dir.lock);
+ if (dentry->d_fsdata)
+ {
+ add_wait_queue (&lookup_info->wait_queue, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ read_unlock (&parent->u.dir.lock);
+ schedule ();
+ }
+ else read_unlock (&parent->u.dir.lock);
return 1;
} /* End Function devfs_d_revalidate_wait */
@@ -2897,9 +2921,12 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
{
+ struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */
+ struct devfs_lookup_struct lookup_info;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
struct devfs_entry *parent, *de;
struct inode *inode;
+ struct dentry *retval = NULL;
/* Set up the dentry operations before anything else, to ensure cleaning
up on any error */
@@ -2921,60 +2948,61 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
}
+ lookup_info.de = de;
+ init_waitqueue_head (&lookup_info.wait_queue);
+ dentry->d_fsdata = &lookup_info;
if (de == NULL)
{ /* Try with devfsd. For any kind of failure, leave a negative dentry
so someone else can deal with it (in the case where the sysadmin
does a mknod()). It's important to do this before hashing the
dentry, so that the devfsd queue is filled before revalidates
can start */
- struct devfs_entry tmp;
-
if (try_modload (parent, fs_info,
dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
- {
+ { /* Lookup event was not queued to devfsd */
d_add (dentry, NULL);
return NULL;
}
- /* devfsd claimed success */
- dentry->d_op = &devfs_wait_dops;
- d_add (dentry, NULL); /* Open the floodgates */
- /* Unlock directory semaphore, which will release any waiters. They
- will get the hashed dentry, and may be forced to wait for
- revalidation */
- up (&dir->i_sem);
- devfs_d_revalidate_wait (dentry, 0); /* I might have to wait too */
- down (&dir->i_sem); /* Grab it again because them's the rules */
- /* If someone else has been so kind as to make the inode, we go home
- early */
- if (dentry->d_inode) return NULL;
+ }
+ dentry->d_op = &devfs_wait_dops;
+ d_add (dentry, NULL); /* Open the floodgates */
+ /* Unlock directory semaphore, which will release any waiters. They
+ will get the hashed dentry, and may be forced to wait for
+ revalidation */
+ up (&dir->i_sem);
+ wait_for_devfsd_finished (fs_info); /* If I'm not devfsd, must wait */
+ down (&dir->i_sem); /* Grab it again because them's the rules */
+ de = lookup_info.de;
+ /* If someone else has been so kind as to make the inode, we go home
+ early */
+ if (dentry->d_inode) goto out;
+ if (de == NULL)
+ {
read_lock (&parent->u.dir.lock);
de = _devfs_search_dir (parent, dentry->d_name.name,
dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
- if (de == NULL) return NULL;
+ if (de == NULL) goto out;
/* OK, there's an entry now, but no VFS inode yet */
}
- else
- {
- dentry->d_op = &devfs_wait_dops;
- d_add (dentry, NULL); /* Open the floodgates */
- }
/* Create an inode, now that the driver information is available */
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
- devfs_put (de);
- if (!inode) return ERR_PTR (-ENOMEM);
- DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n",
- de->name, de->inode.ino, inode, de);
- d_instantiate (dentry, inode);
- if (dentry->d_op == &devfs_wait_dops)
- { /* Unlock directory semaphore, which will release any waiters. They
- will get the hashed dentry, and may be forced to wait for
- revalidation */
- up (&dir->i_sem);
- devfs_d_revalidate_wait (dentry, 0); /* I might have to wait too */
- down (&dir->i_sem); /* Grab it again because them's the rules */
+ if (!inode)
+ {
+ retval = ERR_PTR (-ENOMEM);
+ goto out;
}
- return NULL;
+ DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+ de->name, de->inode.ino, inode, de, current->comm);
+ d_instantiate (dentry, inode);
+out:
+ dentry->d_op = &devfs_dops;
+ dentry->d_fsdata = NULL;
+ write_lock (&parent->u.dir.lock);
+ wake_up (&lookup_info.wait_queue);
+ write_unlock (&parent->u.dir.lock);
+ devfs_put (de);
+ return retval;
} /* End Function devfs_lookup */
static int devfs_unlink (struct inode *dir, struct dentry *dentry)
diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c
index 1a37b2286..c8d9f4143 100644
--- a/fs/driverfs/inode.c
+++ b/fs/driverfs/inode.c
@@ -374,7 +374,7 @@ static int driverfs_d_delete_file (struct dentry * dentry)
entry = (struct driver_file_entry *)dentry->d_fsdata;
if (entry)
- kfree(dentry);
+ kfree(entry);
return 0;
}
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 540d9df2b..a37623906 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -189,7 +189,7 @@ static void list_cache(void)
for (walk = fat_cache; walk; walk = walk->next) {
if (walk->sb)
- printk("<%s,%d>(%d,%d) ", walk->sb->s_dev->s_id,
+ printk("<%s,%d>(%d,%d) ", walk->sb->s_id,
walk->start_cluster, walk->file_cluster,
walk->disk_cluster);
else printk("-- ");
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index e6daf9dc5..904a5b277 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -407,7 +407,7 @@ static void fat_read_root(struct inode *inode)
}
inode->i_blksize = 1 << sbi->cluster_bits;
inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
- & ~(inode->i_blksize - 1)) / 512;
+ & ~(inode->i_blksize - 1)) >> 9;
MSDOS_I(inode)->i_logstart = 0;
MSDOS_I(inode)->mmu_private = inode->i_size;
@@ -949,7 +949,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
/* this is as close to the truth as we can get ... */
inode->i_blksize = 1 << sbi->cluster_bits;
inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
- & ~(inode->i_blksize - 1)) / 512;
+ & ~(inode->i_blksize - 1)) >> 9;
inode->i_mtime = inode->i_atime =
date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
inode->i_ctime =
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index a483de6c2..92388ce7e 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -475,6 +475,7 @@ int journal_write_metadata_buffer(transaction_t *transaction,
new_jh->b_transaction = NULL;
new_bh->b_size = jh2bh(jh_in)->b_size;
+ new_bh->b_bdev = transaction->t_journal->j_dev;
new_bh->b_dev = to_kdev_t(transaction->t_journal->j_dev->bd_dev);
new_bh->b_blocknr = blocknr;
new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty);
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index faf2b412b..43987b60f 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -278,7 +278,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr,
{
struct buffer_head *bh = NULL;
journal_t *journal;
- kdev_t dev;
+ struct block_device *bdev;
int err;
if (bh_in)
@@ -290,11 +290,11 @@ int journal_revoke(handle_t *handle, unsigned long blocknr,
return -EINVAL;
}
- dev = to_kdev_t(journal->j_fs_dev->bd_dev);
+ bdev = journal->j_fs_dev;
bh = bh_in;
if (!bh) {
- bh = get_hash_table(dev, blocknr, journal->j_blocksize);
+ bh = __get_hash_table(bdev, blocknr, journal->j_blocksize);
if (bh)
BUFFER_TRACE(bh, "found on hash");
}
@@ -304,7 +304,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr,
/* If there is a different buffer_head lying around in
* memory anywhere... */
- bh2 = get_hash_table(dev, blocknr, journal->j_blocksize);
+ bh2 = __get_hash_table(bdev, blocknr, journal->j_blocksize);
if (bh2) {
/* ... and it has RevokeValid status... */
if ((bh2 != bh) &&
@@ -408,7 +408,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
* state machine will get very upset later on. */
if (need_cancel && !bh->b_pprev) {
struct buffer_head *bh2;
- bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ bh2 = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
if (bh2) {
clear_bit(BH_Revoked, &bh2->b_state);
__brelse(bh2);
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 16d8e3ed2..1b113947c 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1864,6 +1864,7 @@ zap_buffer:
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
clear_bit(BH_New, &bh->b_state);
+ bh->b_bdev = NULL;
return may_free;
}
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index 9c9e76fc1..7cc0da6a7 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -12,7 +12,7 @@
COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
compr_zlib.o zlib.o
-JFFS2_OBJS := crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
+JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
symlink.o build.o erase.o background.o
diff --git a/fs/jffs2/crc32.c b/fs/jffs2/crc32.c
deleted file mode 100644
index b3b6a811a..000000000
--- a/fs/jffs2/crc32.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
- * code or tables extracted from it, as desired without restriction.
- *
- * First, the polynomial itself and its table of feedback terms. The
- * polynomial is
- * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
- *
- * Note that we take it "backwards" and put the highest-order term in
- * the lowest-order bit. The X^32 term is "implied"; the LSB is the
- * X^31 term, etc. The X^0 term (usually shown as "+1") results in
- * the MSB being 1
- *
- * Note that the usual hardware shift register implementation, which
- * is what we're using (we're merely optimizing it by doing eight-bit
- * chunks at a time) shifts bits into the lowest-order term. In our
- * implementation, that means shifting towards the right. Why do we
- * do it this way? Because the calculated CRC must be transmitted in
- * order from highest-order term to lowest-order term. UARTs transmit
- * characters in order from LSB to MSB. By storing the CRC this way
- * we hand it to the UART in the order low-byte to high-byte; the UART
- * sends each low-bit to hight-bit; and the result is transmission bit
- * by bit from highest- to lowest-order term without requiring any bit
- * shuffling on our part. Reception works similarly
- *
- * The feedback terms table consists of 256, 32-bit entries. Notes
- *
- * The table can be generated at runtime if desired; code to do so
- * is shown later. It might not be obvious, but the feedback
- * terms simply represent the results of eight shift/xor opera
- * tions for all combinations of data and CRC register values
- *
- * The values must be right-shifted by eight bits by the "updcrc
- * logic; the shift must be unsigned (bring in zeroes). On some
- * hardware you could probably optimize the shift in assembler by
- * using byte-swap instructions
- * polynomial $edb88320
- */
-
-/* $Id: crc32.c,v 1.3 2001/02/07 16:45:32 dwmw2 Exp $ */
-
-#include "crc32.h"
-
-const __u32 crc32_table[256] = {
- 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
- 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
- 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
- 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
- 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
- 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
- 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
- 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
- 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
- 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
- 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
- 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
- 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
- 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
- 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
- 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
- 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
- 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
- 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
- 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
- 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
- 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
- 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
- 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
- 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
- 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
- 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
- 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
- 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
- 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
- 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
- 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
- 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
- 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
- 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
- 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
- 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
- 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
- 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
- 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
- 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
- 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
- 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
- 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
- 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
- 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
- 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
- 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
- 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
- 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
- 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
- 0x2d02ef8dL
-};
diff --git a/fs/jffs2/crc32.h b/fs/jffs2/crc32.h
deleted file mode 100644
index cd8979f73..000000000
--- a/fs/jffs2/crc32.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef CRC32_H
-#define CRC32_H
-
-/* $Id: crc32.h,v 1.3 2001/02/26 14:44:37 dwmw2 Exp $ */
-
-#include <linux/types.h>
-
-extern const __u32 crc32_table[256];
-
-/* Return a 32-bit CRC of the contents of the buffer. */
-
-static inline __u32
-crc32(__u32 val, const void *ss, int len)
-{
- const unsigned char *s = ss;
- while (--len >= 0)
- val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
- return val;
-}
-
-#endif
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c40a8fb0a..c1e9143f6 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -38,11 +38,11 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/jffs2_fs_i.h>
#include <linux/jffs2_fs_sb.h>
#include "nodelist.h"
-#include "crc32.h"
static int jffs2_readdir (struct file *, void *, filldir_t);
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 633875a6d..115c7a20f 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -39,8 +39,8 @@
#include <linux/mtd/mtd.h>
#include <linux/jffs2.h>
#include <linux/interrupt.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
struct erase_priv_struct {
struct jffs2_eraseblock *jeb;
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 4771c02ee..f0446acb9 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -40,9 +40,9 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include "nodelist.h"
-#include "crc32.h"
extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 4cdb28557..9294e584c 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -42,8 +42,8 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct inode *inode, struct jffs2_full_dnode *fd);
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index cce42560d..fd46ae954 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-#include "crc32.h"
int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
{
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 2e1d93de3..f72affe1a 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -41,10 +41,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/mtd/mtd.h>
#include <linux/jffs2.h>
#include "nodelist.h"
-#include "crc32.h"
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index c8708da6a..d1b870bd5 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -39,8 +39,8 @@
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index e8af1895c..32c11f954 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-#include "crc32.h"
/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
fill in the raw_inode while you're at it. */
diff --git a/fs/namei.c b/fs/namei.c
index 20d3add2c..3d9b2dbec 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -99,16 +99,17 @@
* kernel data space before using them..
*
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ * PATH_MAX includes the nul terminator --RR.
*/
static inline int do_getname(const char *filename, char *page)
{
int retval;
- unsigned long len = PATH_MAX + 1;
+ unsigned long len = PATH_MAX;
if ((unsigned long) filename >= TASK_SIZE) {
if (!segment_eq(get_fs(), KERNEL_DS))
return -EFAULT;
- } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
+ } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
len = TASK_SIZE - (unsigned long) filename;
retval = strncpy_from_user((char *)page, filename, len);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 68a58ff9d..870f9c112 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -166,7 +166,7 @@ static void extended_partition(struct gendisk *hd, struct block_device *bdev,
add_gd_partition(hd, *current_minor, next, size);
#if CONFIG_BLK_DEV_MD
if (SYS_IND(p) == LINUX_RAID_PARTITION) {
- md_autodetect_dev(MKDEV(hd->major,*current_minor));
+ md_autodetect_dev(mk_kdev(hd->major,*current_minor));
}
#endif
@@ -580,7 +580,7 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev,
NR_SECTS(p)*sector_size);
#if CONFIG_BLK_DEV_MD
if (SYS_IND(p) == LINUX_RAID_PARTITION) {
- md_autodetect_dev(MKDEV(hd->major,minor));
+ md_autodetect_dev(mk_kdev(hd->major,minor));
}
#endif
if (is_extended_partition(p)) {
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 9caf73298..a426e4f84 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -168,7 +168,7 @@ retry:
block_to_try = (i * (s->s_blocksize << 3)) + j;
/* the block is not in the journal, we can proceed */
- if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
+ if (!(reiserfs_in_journal(s, block_to_try, for_unformatted, &next_block_to_try))) {
*bmap_nr = i;
*offset = j;
return 1;
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 634747f31..98d6b2dc3 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -414,12 +414,15 @@ void reiserfs_check_lock_depth(char *caller) {
}
/* return a cnode with same dev, block number and size in table, or null if not found */
-static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserfs_journal_cnode **table,
- kdev_t dev,long bl,int size) {
+static inline struct reiserfs_journal_cnode *
+get_journal_hash_dev(struct super_block *sb,
+ struct reiserfs_journal_cnode **table,
+ long bl)
+{
struct reiserfs_journal_cnode *cn ;
- cn = journal_hash(table, dev, bl) ;
+ cn = journal_hash(table, sb, bl) ;
while(cn) {
- if ((cn->blocknr == bl) && (kdev_same(cn->dev, dev)))
+ if (cn->blocknr == bl && cn->sb == sb)
return cn ;
cn = cn->hnext ;
}
@@ -430,7 +433,7 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserf
static inline struct reiserfs_journal_cnode *get_journal_hash(struct super_block *p_s_sb, struct buffer_head *bh) {
struct reiserfs_journal_cnode *cn ;
if (bh) {
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_dev, bh->b_blocknr, bh->b_size) ;
+ cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_blocknr);
}
else {
return (struct reiserfs_journal_cnode *)0 ;
@@ -502,8 +505,8 @@ int dump_journal_writers(void) {
** reject it on the next call to reiserfs_in_journal
**
*/
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev,
- unsigned long bl, int size, int search_all,
+int reiserfs_in_journal(struct super_block *p_s_sb,
+ unsigned long bl, int search_all,
unsigned long *next_zero_bit) {
struct reiserfs_journal_cnode *cn ;
struct reiserfs_list_bitmap *jb ;
@@ -540,12 +543,12 @@ int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev,
}
/* is it in any old transactions? */
- if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {
+ if (search_all && (cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bl))) {
return 1;
}
/* is it in the current transaction. This should never happen */
- if ((cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, dev,bl,size))) {
+ if ((cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bl))) {
return 1;
}
@@ -559,13 +562,13 @@ int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev,
inline void insert_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_cnode *cn) {
struct reiserfs_journal_cnode *cn_orig ;
- cn_orig = journal_hash(table, cn->dev, cn->blocknr) ;
+ cn_orig = journal_hash(table, cn->sb, cn->blocknr) ;
cn->hnext = cn_orig ;
cn->hprev = NULL ;
if (cn_orig) {
cn_orig->hprev = cn ;
}
- journal_hash(table, cn->dev, cn->blocknr) = cn ;
+ journal_hash(table, cn->sb, cn->blocknr) = cn ;
}
/* lock the current transaction */
@@ -760,12 +763,12 @@ reiserfs_panic(s, "journal-539: flush_commit_list: BAD count(%d) > orig_commit_l
** returns NULL if it can't find anything
*/
static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journal_cnode *cn) {
- kdev_t dev = cn->dev;
+ struct super_block *sb = cn->sb;
unsigned long blocknr = cn->blocknr ;
cn = cn->hprev ;
while(cn) {
- if (kdev_same(cn->dev, dev) && cn->blocknr == blocknr && cn->jlist) {
+ if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist) {
return cn->jlist ;
}
cn = cn->hprev ;
@@ -773,6 +776,8 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journa
return NULL ;
}
+void remove_journal_hash(struct super_block *, struct reiserfs_journal_cnode **,
+struct reiserfs_journal_list *, unsigned long, int);
/*
** once all the real blocks have been flushed, it is safe to remove them from the
@@ -780,12 +785,11 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journa
** block to be reallocated for data blocks if it had been deleted.
*/
static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl, int debug) {
- struct buffer_head fake_bh ;
struct reiserfs_journal_cnode *cn, *last ;
cn = jl->j_realblock ;
/* which is better, to lock once around the whole loop, or
- ** to lock for each call to remove_from_journal_list?
+ ** to lock for each call to remove_journal_hash?
*/
while(cn) {
if (cn->blocknr != 0) {
@@ -793,10 +797,8 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reis
printk("block %lu, bh is %d, state %d\n", cn->blocknr, cn->bh ? 1: 0,
cn->state) ;
}
- fake_bh.b_blocknr = cn->blocknr ;
- fake_bh.b_dev = cn->dev ;
cn->state = 0 ;
- remove_from_journal_list(p_s_sb, jl, &fake_bh, 1) ;
+ remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, jl, cn->blocknr, 1) ;
}
last = cn ;
cn = cn->next ;
@@ -1178,7 +1180,7 @@ loop_start:
mark_buffer_notjournal_dirty(cn->bh) ;
while(walk_cn) {
if (walk_cn->bh && walk_cn->blocknr == blocknr &&
- kdev_same(walk_cn->dev, cn->dev)) {
+ walk_cn->sb == cn->sb) {
if (walk_cn->jlist) {
atomic_dec(&(walk_cn->jlist->j_nonzerolen)) ;
}
@@ -1267,21 +1269,21 @@ static unsigned long reiserfs_journal_kupdate(struct super_block *s) {
** removes any nodes in table with name block and dev as bh.
** only touchs the hnext and hprev pointers.
*/
-void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_list *jl,struct buffer_head *bh,
- int remove_freed){
+void remove_journal_hash(struct super_block *sb,
+ struct reiserfs_journal_cnode **table,
+ struct reiserfs_journal_list *jl,
+ unsigned long block, int remove_freed)
+{
struct reiserfs_journal_cnode *cur ;
struct reiserfs_journal_cnode **head ;
- if (!bh)
- return ;
-
- head= &(journal_hash(table, bh->b_dev, bh->b_blocknr)) ;
+ head= &(journal_hash(table, sb, block)) ;
if (!head) {
return ;
}
cur = *head ;
while(cur) {
- if (cur->blocknr == bh->b_blocknr && kdev_same(cur->dev, bh->b_dev) && (jl == NULL || jl == cur->jlist) &&
+ if (cur->blocknr == block && cur->sb == sb && (jl == NULL || jl == cur->jlist) &&
(!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) {
if (cur->hnext) {
cur->hnext->hprev = cur->hprev ;
@@ -1292,7 +1294,7 @@ void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_
*head = cur->hnext ;
}
cur->blocknr = 0 ;
- cur->dev = NODEV ;
+ cur->sb = NULL ;
cur->state = 0 ;
if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */
atomic_dec(&(cur->jlist->j_nonzerolen)) ;
@@ -2184,7 +2186,7 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, struct super_bloc
cn->bh = bh ;
cn->blocknr = bh->b_blocknr ;
- cn->dev = bh->b_dev ;
+ cn->sb = p_s_sb;
cn->jlist = NULL ;
insert_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, cn) ;
if (!count_already_incd) {
@@ -2215,7 +2217,7 @@ int journal_mark_dirty_nolog(struct reiserfs_transaction_handle *th, struct supe
buffer_journal_dirty(bh)) {
return journal_mark_dirty(th, p_s_sb, bh) ;
}
- if (get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_dev,bh->b_blocknr,bh->b_size)) {
+ if (get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_blocknr)) {
return journal_mark_dirty(th, p_s_sb, bh) ;
}
mark_buffer_dirty(bh) ;
@@ -2238,7 +2240,7 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i
struct reiserfs_journal_cnode *cn ;
int ret = 0;
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+ cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, blocknr) ;
if (!cn || !cn->bh) {
return ret ;
}
@@ -2255,7 +2257,8 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i
if (cn == SB_JOURNAL(p_s_sb)->j_last) {
SB_JOURNAL(p_s_sb)->j_last = cn->prev ;
}
- remove_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh, 0) ;
+ if (bh)
+ remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh->b_blocknr, 0) ;
mark_buffer_not_journaled(bh) ; /* don't log this one */
if (!already_cleaned) {
@@ -2273,12 +2276,6 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i
return ret ;
}
-/* removes from a specific journal list hash */
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
- remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ;
- return 0 ;
-}
-
/*
** for any cnode in a journal list, it can only be dirtied of all the
** transactions that include it are commited to disk.
@@ -2290,7 +2287,7 @@ int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list
**
*/
static int can_dirty(struct reiserfs_journal_cnode *cn) {
- kdev_t dev = cn->dev ;
+ struct super_block *sb = cn->sb;
unsigned long blocknr = cn->blocknr ;
struct reiserfs_journal_cnode *cur = cn->hprev ;
int can_dirty = 1 ;
@@ -2300,7 +2297,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) {
** to disk right now.
*/
while(cur && can_dirty) {
- if (cur->jlist && cur->bh && cur->blocknr && kdev_same(cur->dev, dev) &&
+ if (cur->jlist && cur->bh && cur->blocknr && cur->sb == sb &&
cur->blocknr == blocknr) {
can_dirty = 0 ;
}
@@ -2313,7 +2310,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) {
while(cur && can_dirty) {
if (cur->jlist && cur->jlist->j_len > 0 &&
atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh &&
- cur->blocknr && kdev_same(cur->dev, dev) && cur->blocknr == blocknr) {
+ cur->blocknr && cur->sb == sb && cur->blocknr == blocknr) {
can_dirty = 0 ;
}
cur = cur->hnext ;
@@ -2578,9 +2575,9 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, struct super_bloc
cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
/* find all older transactions with this block, make sure they don't try to write it out */
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+ cn = get_journal_hash_dev(p_s_sb,SB_JOURNAL(p_s_sb)->j_list_hash_table, blocknr) ;
while (cn) {
- if (kdev_same(p_s_sb->s_dev, cn->dev) && blocknr == cn->blocknr) {
+ if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
set_bit(BLOCK_FREED, &cn->state) ;
if (cn->bh) {
if (!cleaned) {
@@ -2821,7 +2818,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
}
jl_cn->blocknr = cn->bh->b_blocknr ;
jl_cn->state = 0 ;
- jl_cn->dev = cn->bh->b_dev ;
+ jl_cn->sb = p_s_sb ;
jl_cn->bh = cn->bh ;
jl_cn->jlist = SB_JOURNAL_LIST(p_s_sb) + SB_JOURNAL_LIST_INDEX(p_s_sb) ;
insert_journal_hash(SB_JOURNAL(p_s_sb)->j_list_hash_table, jl_cn) ;
diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
index 775f81cbc..5648d0985 100644
--- a/fs/reiserfs/tail_conversion.c
+++ b/fs/reiserfs/tail_conversion.c
@@ -142,6 +142,7 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) {
clear_bit(BH_Mapped, &bh->b_state) ;
clear_bit(BH_Req, &bh->b_state) ;
clear_bit(BH_New, &bh->b_state) ;
+ bh->b_bdev = NULL;
unlock_buffer(bh) ;
}
}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 3f11ceb30..0cbe78286 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -326,10 +326,6 @@ extern int * max_readahead[MAX_BLKDEV];
#define MIN_READAHEAD 3
#define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-#define blkdev_entry_next_request(entry) blkdev_entry_to_request((entry)->next)
-#define blkdev_entry_prev_request(entry) blkdev_entry_to_request((entry)->prev)
-#define blkdev_next_request(req) blkdev_entry_to_request((req)->queuelist.next)
-#define blkdev_prev_request(req) blkdev_entry_to_request((req)->queuelist.prev)
extern void drive_stat_acct(struct request *, int, int);
diff --git a/include/linux/crc32.h b/include/linux/crc32.h
new file mode 100644
index 000000000..a0033ffee
--- /dev/null
+++ b/include/linux/crc32.h
@@ -0,0 +1,17 @@
+/*
+ * crc32.h
+ * See linux/lib/crc32.c for license and changes
+ */
+#ifndef _LINUX_CRC32_H
+#define _LINUX_CRC32_H
+
+#include <linux/types.h>
+
+extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
+extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len);
+
+#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
+#define ether_crc_le(length, data) crc32_le(~0, data, length)
+#define ether_crc(length, data) crc32_be(~0, data, length)
+
+#endif /* _LINUX_CRC32_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b102c2d51..a01f0c3b4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -245,6 +245,7 @@ struct buffer_head {
unsigned short b_size; /* block size */
unsigned short b_list; /* List that this buffer appears */
kdev_t b_dev; /* device (B_FREE = free) */
+ struct block_device *b_bdev;
atomic_t b_count; /* users using this block */
unsigned long b_state; /* buffer state bitmap (see above) */
@@ -1357,7 +1358,20 @@ extern void insert_inode_hash(struct inode *);
extern void remove_inode_hash(struct inode *);
extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list);
-extern struct buffer_head * get_hash_table(kdev_t, sector_t, int);
+extern struct buffer_head * __get_hash_table(struct block_device *, sector_t, int);
+static inline struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+{
+ struct block_device *bdev;
+ struct buffer_head *bh;
+ bdev = bdget(kdev_t_to_nr(dev));
+ if (!bdev) {
+ printk("No block device for %s\n", bdevname(dev));
+ BUG();
+ }
+ bh = __get_hash_table(bdev, block, size);
+ atomic_dec(&bdev->bd_count);
+ return bh;
+}
extern struct buffer_head * __getblk(struct block_device *, sector_t, int);
static inline struct buffer_head * getblk(kdev_t dev, sector_t block, int size)
{
@@ -1416,11 +1430,12 @@ static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
}
static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
{
- return get_hash_table(sb->s_dev, block, sb->s_blocksize);
+ return __get_hash_table(sb->s_bdev, block, sb->s_blocksize);
}
static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
{
bh->b_state |= 1 << BH_Mapped;
+ bh->b_bdev = sb->s_bdev;
bh->b_dev = sb->s_dev;
bh->b_blocknr = block;
}
@@ -1428,7 +1443,7 @@ extern void wakeup_bdflush(void);
extern void put_unused_buffer_head(struct buffer_head * bh);
extern struct buffer_head * get_unused_buffer_head(int async);
-extern int brw_page(int, struct page *, kdev_t, sector_t [], int);
+extern int brw_page(int, struct page *, struct block_device *, sector_t [], int);
typedef int (get_block_t)(struct inode*,sector_t,struct buffer_head*,int);
diff --git a/include/linux/limits.h b/include/linux/limits.h
index 51c49ec4e..45faa81d9 100644
--- a/include/linux/limits.h
+++ b/include/linux/limits.h
@@ -11,7 +11,7 @@
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
#define NAME_MAX 255 /* # chars in a file name */
-#define PATH_MAX 4095 /* # chars in a path name */
+#define PATH_MAX 4096 /* # chars in a path name including nul */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define RTSIG_MAX 32
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index b50d60989..1c4cec479 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -1651,7 +1651,7 @@ extern wait_queue_head_t reiserfs_commit_thread_wait ;
#define _jhashfn(dev,block) \
((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \
(((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
-#define journal_hash(t,dev,block) ((t)[_jhashfn((kdev_t_to_nr(dev)),(block)) & JBH_HASH_MASK])
+#define journal_hash(t,sb,block) ((t)[_jhashfn((kdev_t_to_nr(sb->s_dev)),(block)) & JBH_HASH_MASK])
/* finds n'th buffer with 0 being the start of this commit. Needs to go away, j_ap_blocks has changed
** since I created this. One chunk of code in journal.c needs changing before deleting it
@@ -1678,14 +1678,13 @@ int pop_journal_writer(int windex) ;
int journal_lock_dobalance(struct super_block *p_s_sb) ;
int journal_unlock_dobalance(struct super_block *p_s_sb) ;
int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
+int reiserfs_in_journal(struct super_block *p_s_sb, unsigned long bl, int searchall, unsigned long *next) ;
int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
struct super_block *reiserfs_get_super(kdev_t dev) ;
void flush_async_commits(struct super_block *p_s_sb) ;
int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ;
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ;
int buffer_journaled(const struct buffer_head *bh) ;
int mark_buffer_journal_new(struct buffer_head *bh) ;
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 1eee601a1..a78f78986 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -199,7 +199,7 @@ struct reiserfs_super_block_v1
*/
struct reiserfs_journal_cnode {
struct buffer_head *bh ; /* real buffer head */
- kdev_t dev ; /* dev of real buffer head */
+ struct super_block *sb ; /* dev of real buffer head */
unsigned long blocknr ; /* block number of real buffer head, == 0 when buffer on disk */
int state ;
struct reiserfs_journal_list *jlist ; /* journal list this cnode lives in */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 7ea6e7334..b0ac23988 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -65,8 +65,7 @@ struct swap_info_struct {
unsigned int flags;
kdev_t swap_device;
spinlock_t sdev_lock;
- struct dentry * swap_file;
- struct vfsmount *swap_vfsmnt;
+ struct file *swap_file;
unsigned short * swap_map;
unsigned int lowest_bit;
unsigned int highest_bit;
@@ -141,8 +140,7 @@ extern struct swap_info_struct swap_info[];
extern int is_swap_partition(kdev_t);
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void);
-extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *,
- struct inode **);
+extern void get_swaphandle_info(swp_entry_t, unsigned long *, struct inode **);
extern int swap_duplicate(swp_entry_t);
extern int swap_count(struct page *);
extern int valid_swaphandles(swp_entry_t, unsigned long *);
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index eded2d7fb..f3f8775d8 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -511,7 +511,7 @@ EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(read_ahead);
-EXPORT_SYMBOL(get_hash_table);
+EXPORT_SYMBOL(__get_hash_table);
EXPORT_SYMBOL(get_empty_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(remove_inode_hash);
diff --git a/lib/Config.in b/lib/Config.in
new file mode 100644
index 000000000..6072b4572
--- /dev/null
+++ b/lib/Config.in
@@ -0,0 +1,8 @@
+#
+# Library configuration
+#
+mainmenu_option next_comment
+comment 'Library routines'
+
+tristate 'CRC32 functions' CONFIG_CRC32
+endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 38a91fa0c..9e2d80f5f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@
L_TARGET := lib.a
-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o
obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
@@ -19,4 +19,9 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
obj-y += dec_and_lock.o
endif
+obj-$(CONFIG_CRC32) += crc32.o
+include $(TOPDIR)/drivers/net/Makefile.lib
+include $(TOPDIR)/drivers/usb/Makefile.lib
+include $(TOPDIR)/fs/Makefile.lib
+
include $(TOPDIR)/Rules.make
diff --git a/lib/crc32.c b/lib/crc32.c
new file mode 100644
index 000000000..8bf7b8d8d
--- /dev/null
+++ b/lib/crc32.c
@@ -0,0 +1,571 @@
+/*
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32(). Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0. The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end. Then individual
+ * users can do whatever they need.
+ * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ * fs/jffs2 uses seed 0, doesn't xor with ~0.
+ * fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ *
+ */
+
+#include <linux/crc32.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+#if __GNUC__ >= 3 /* 2.x has "attribute", but only 3.0 has "pure */
+#define attribute(x) __attribute__(x)
+#else
+#define attribute(x)
+#endif
+
+/*
+ * This code is in the public domain; copyright abandoned.
+ * Liability for non-performance of this code is limited to the amount
+ * you paid for it. Since it is distributed for free, your refund will
+ * be very very small. If it breaks, you get to keep both pieces.
+ */
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
+MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_LICENSE("GPL and additional rights");
+
+
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/* How many bits at a time to use. Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#define CRC_LE_BITS 8
+#define CRC_BE_BITS 8
+
+/*
+ * Little-endian CRC computation. Used with serial bit streams sent
+ * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
+# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_LE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_le()
+#define crc32cleanup_le()
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+ return crc;
+}
+#else /* Table-based approach */
+
+static u32 *crc32table_le;
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static int __init crc32init_le(void)
+{
+ unsigned i, j;
+ u32 crc = 1;
+
+ crc32table_le =
+ kmalloc((1 << CRC_LE_BITS) * sizeof(u32), GFP_KERNEL);
+ if (!crc32table_le)
+ return 1;
+ crc32table_le[0] = 0;
+
+ for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
+ crc32table_le[i + j] = crc ^ crc32table_le[j];
+ }
+ return 0;
+}
+
+/**
+ * crc32cleanup_le(): free LE table data
+ */
+static void __exit crc32cleanup_le(void)
+{
+ if (crc32table_le) kfree(crc32table_le);
+ crc32table_le = NULL;
+}
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ while (len--) {
+# if CRC_LE_BITS == 8
+ crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
+# elif CRC_LE_BITS == 4
+ crc ^= *p++;
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+# elif CRC_LE_BITS == 2
+ crc ^= *p++;
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+# endif
+ }
+ return crc;
+}
+#endif
+
+/*
+ * Big-endian CRC computation. Used with serial bit streams sent
+ * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
+# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_BE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_be()
+#define crc32cleanup_be()
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++ << 24;
+ for (i = 0; i < 8; i++)
+ crc =
+ (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+ 0);
+ }
+ return crc;
+}
+
+#else /* Table-based approach */
+static u32 *crc32table_be;
+
+/**
+ * crc32init_be() - allocate and initialize BE table data
+ */
+static int __init crc32init_be(void)
+{
+ unsigned i, j;
+ u32 crc = 0x80000000;
+
+ crc32table_be =
+ kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
+ if (!crc32table_be)
+ return 1;
+ crc32table_be[0] = 0;
+
+ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
+ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+ for (j = 0; j < i; j++)
+ crc32table_be[i + j] = crc ^ crc32table_be[j];
+ }
+ return 0;
+}
+
+/**
+ * crc32cleanup_be(): free BE table data
+ */
+static void __exit crc32cleanup_be(void)
+{
+ if (crc32table_be) kfree(crc32table_be);
+ crc32table_be = NULL;
+}
+
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+ while (len--) {
+# if CRC_BE_BITS == 8
+ crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++];
+# elif CRC_BE_BITS == 4
+ crc ^= *p++ << 24;
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+# elif CRC_BE_BITS == 2
+ crc ^= *p++ << 24;
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+# endif
+ }
+ return crc;
+}
+#endif
+
+/*
+ * A brief CRC tutorial.
+ *
+ * A CRC is a long-division remainder. You add the CRC to the message,
+ * and the whole thing (message+CRC) is a multiple of the given
+ * CRC polynomial. To check the CRC, you can either check that the
+ * CRC matches the recomputed value, *or* you can check that the
+ * remainder computed on the message+CRC is 0. This latter approach
+ * is used by a lot of hardware implementations, and is why so many
+ * protocols put the end-of-frame flag after the CRC.
+ *
+ * It's actually the same long division you learned in school, except that
+ * - We're working in binary, so the digits are only 0 and 1, and
+ * - When dividing polynomials, there are no carries. Rather than add and
+ * subtract, we just xor. Thus, we tend to get a bit sloppy about
+ * the difference between adding and subtracting.
+ *
+ * A 32-bit CRC polynomial is actually 33 bits long. But since it's
+ * 33 bits long, bit 32 is always going to be set, so usually the CRC
+ * is written in hex with the most significant bit omitted. (If you're
+ * familiar with the IEEE 754 floating-point format, it's the same idea.)
+ *
+ * Note that a CRC is computed over a string of *bits*, so you have
+ * to decide on the endianness of the bits within each byte. To get
+ * the best error-detecting properties, this should correspond to the
+ * order they're actually sent. For example, standard RS-232 serial is
+ * little-endian; the most significant bit (sometimes used for parity)
+ * is sent last. And when appending a CRC word to a message, you should
+ * do it in the right order, matching the endianness.
+ *
+ * Just like with ordinary division, the remainder is always smaller than
+ * the divisor (the CRC polynomial) you're dividing by. Each step of the
+ * division, you take one more digit (bit) of the dividend and append it
+ * to the current remainder. Then you figure out the appropriate multiple
+ * of the divisor to subtract to being the remainder back into range.
+ * In binary, it's easy - it has to be either 0 or 1, and to make the
+ * XOR cancel, it's just a copy of bit 32 of the remainder.
+ *
+ * When computing a CRC, we don't care about the quotient, so we can
+ * throw the quotient bit away, but subtract the appropriate multiple of
+ * the polynomial from the remainder and we're back to where we started,
+ * ready to process the next bit.
+ *
+ * A big-endian CRC written this way would be coded like:
+ * for (i = 0; i < input_bits; i++) {
+ * multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * }
+ * Notice how, to get at bit 32 of the shifted remainder, we look
+ * at bit 31 of the remainder *before* shifting it.
+ *
+ * But also notice how the next_input_bit() bits we're shifting into
+ * the remainder don't actually affect any decision-making until
+ * 32 bits later. Thus, the first 32 cycles of this are pretty boring.
+ * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+ * the end, so we have to add 32 extra cycles shifting in zeros at the
+ * end of every message,
+ *
+ * So the standard trick is to rearrage merging in the next_input_bit()
+ * until the moment it's needed. Then the first 32 cycles can be precomputed,
+ * and merging in the final 32 zero bits to make room for the CRC can be
+ * skipped entirely.
+ * This changes the code to:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit() << 31;
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * With this optimization, the little-endian code is simpler:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit();
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder >> 1) ^ multiple;
+ * }
+ *
+ * Note that the other details of endianness have been hidden in CRCPOLY
+ * (which must be bit-reversed) and next_input_bit().
+ *
+ * However, as long as next_input_bit is returning the bits in a sensible
+ * order, we can actually do the merging 8 or more bits at a time rather
+ * than one bit at a time:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte() << 24;
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * Or in little-endian:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte();
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+ * word at a time and increase the inner loop count to 32.
+ *
+ * You can also mix and match the two loop styles, for example doing the
+ * bulk of a message byte-at-a-time and adding bit-at-a-time processing
+ * for any fractional bytes at the end.
+ *
+ * The only remaining optimization is to the byte-at-a-time table method.
+ * Here, rather than just shifting one bit of the remainder to decide
+ * in the correct multiple to subtract, we can shift a byte at a time.
+ * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+ * but again the multiple of the polynomial to subtract depends only on
+ * the high bits, the high 8 bits in this case.
+ *
+ * The multile we need in that case is the low 32 bits of a 40-bit
+ * value whose high 8 bits are given, and which is a multiple of the
+ * generator polynomial. This is simply the CRC-32 of the given
+ * one-byte message.
+ *
+ * Two more details: normally, appending zero bits to a message which
+ * is already a multiple of a polynomial produces a larger multiple of that
+ * polynomial. To enable a CRC to detect this condition, it's common to
+ * invert the CRC before appending it. This makes the remainder of the
+ * message+crc come out not as zero, but some fixed non-zero value.
+ *
+ * The same problem applies to zero bits prepended to the message, and
+ * a similar solution is used. Instead of starting with a remainder of
+ * 0, an initial remainder of all ones is used. As long as you start
+ * the same way on decoding, it doesn't make a difference.
+ */
+
+#if UNITTEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if 0 /*Not used at present */
+static void
+buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+{
+ fputs(prefix, stdout);
+ while (len--)
+ printf(" %02x", *buf++);
+ putchar('\n');
+
+}
+#endif
+
+static u32 attribute((const)) bitreverse(u32 x)
+{
+ x = (x >> 16) | (x << 16);
+ x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
+ x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
+ x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
+ x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
+ return x;
+}
+
+static void bytereverse(unsigned char *buf, size_t len)
+{
+ while (len--) {
+ unsigned char x = *buf;
+ x = (x >> 4) | (x << 4);
+ x = (x >> 2 & 0x33) | (x << 2 & 0xcc);
+ x = (x >> 1 & 0x55) | (x << 1 & 0xaa);
+ *buf++ = x;
+ }
+}
+
+static void random_garbage(unsigned char *buf, size_t len)
+{
+ while (len--)
+ *buf++ = (unsigned char) random();
+}
+
+#if 0 /* Not used at present */
+static void store_le(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) x;
+ buf[1] = (unsigned char) (x >> 8);
+ buf[2] = (unsigned char) (x >> 16);
+ buf[3] = (unsigned char) (x >> 24);
+}
+#endif
+
+static void store_be(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) (x >> 24);
+ buf[1] = (unsigned char) (x >> 16);
+ buf[2] = (unsigned char) (x >> 8);
+ buf[3] = (unsigned char) x;
+}
+
+/*
+ * This checks that CRC(buf + CRC(buf)) = 0, and that
+ * CRC commutes with bit-reversal. This has the side effect
+ * of bytewise bit-reversing the input buffer, and returns
+ * the CRC of the reversed buffer.
+ */
+static u32 test_step(u32 init, unsigned char *buf, size_t len)
+{
+ u32 crc1, crc2;
+ size_t i;
+
+ crc1 = crc32_be(init, buf, len);
+ store_be(crc1, buf + len);
+ crc2 = crc32_be(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_be(init, buf, i);
+ crc2 = crc32_be(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ /* Now swap it around for the other test */
+
+ bytereverse(buf, len + 4);
+ init = bitreverse(init);
+ crc2 = bitreverse(crc1);
+ if (crc1 != bitreverse(crc2))
+ printf("\nBit reversal fail: 0x%08x -> %0x08x -> 0x%08x\n",
+ crc1, crc2, bitreverse(crc2));
+ crc1 = crc32_le(init, buf, len);
+ if (crc1 != crc2)
+ printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
+ crc2);
+ crc2 = crc32_le(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_le(init, buf, i);
+ crc2 = crc32_le(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ return crc1;
+}
+
+#define SIZE 64
+#define INIT1 0
+#define INIT2 0
+
+int main(void)
+{
+ unsigned char buf1[SIZE + 4];
+ unsigned char buf2[SIZE + 4];
+ unsigned char buf3[SIZE + 4];
+ int i, j;
+ u32 crc1, crc2, crc3;
+
+ crc32init_le();
+ crc32init_be();
+
+ for (i = 0; i <= SIZE; i++) {
+ printf("\rTesting length %d...", i);
+ fflush(stdout);
+ random_garbage(buf1, i);
+ random_garbage(buf2, i);
+ for (j = 0; j < i; j++)
+ buf3[j] = buf1[j] ^ buf2[j];
+
+ crc1 = test_step(INIT1, buf1, i);
+ crc2 = test_step(INIT2, buf2, i);
+ /* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
+ crc3 = test_step(INIT1 ^ INIT2, buf3, i);
+ if (crc3 != (crc1 ^ crc2))
+ printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
+ crc3, crc1, crc2);
+ }
+ printf("\nAll test complete. No failures expected.\n");
+ return 0;
+}
+
+#endif /* UNITTEST */
+
+/**
+ * init_crc32(): generates CRC32 tables
+ *
+ * On successful initialization, use count is increased.
+ * This guarantees that the library functions will stay resident
+ * in memory, and prevents someone from 'rmmod crc32' while
+ * a driver that needs it is still loaded.
+ * This also greatly simplifies drivers, as there's no need
+ * to call an initialization/cleanup function from each driver.
+ * Since crc32.o is a library module, there's no requirement
+ * that the user can unload it.
+ */
+static int __init init_crc32(void)
+{
+ int rc1, rc2, rc;
+ rc1 = crc32init_le();
+ rc2 = crc32init_be();
+ rc = rc1 || rc2;
+ if (!rc) MOD_INC_USE_COUNT;
+ return rc;
+}
+
+/**
+ * cleanup_crc32(): frees crc32 data when no longer needed
+ */
+static void cleanup_crc32(void)
+{
+ crc32cleanup_le();
+ crc32cleanup_be();
+}
+
+module_init(init_crc32);
+module_exit(cleanup_crc32);
+
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(crc32_be);
diff --git a/mm/page_io.c b/mm/page_io.c
index 79700f304..cacb39521 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -38,9 +38,9 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
unsigned long offset;
sector_t zones[PAGE_SIZE/512];
int zones_used;
- kdev_t dev = NODEV;
int block_size;
struct inode *swapf = 0;
+ struct block_device *bdev;
if (rw == READ) {
ClearPageUptodate(page);
@@ -48,12 +48,13 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
} else
kstat.pswpout++;
- get_swaphandle_info(entry, &offset, &dev, &swapf);
- if (!kdev_none(dev)) {
+ get_swaphandle_info(entry, &offset, &swapf);
+ bdev = swapf->i_bdev;
+ if (bdev) {
zones[0] = offset;
zones_used = 1;
block_size = PAGE_SIZE;
- } else if (swapf) {
+ } else {
int i, j;
unsigned int block = offset
<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
@@ -65,13 +66,11 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
return 0;
}
zones_used = i;
- dev = swapf->i_dev;
- } else {
- return 0;
+ bdev = swapf->i_sb->s_bdev;
}
/* block_size == PAGE_SIZE/zones_used */
- brw_page(rw, page, dev, zones, block_size);
+ brw_page(rw, page, bdev, zones, block_size);
/* Note! For consistency we do all of the logic,
* decrementing the page count, and unlocking the page in the
diff --git a/mm/swapfile.c b/mm/swapfile.c
index ff9a8e1f0..2149e6eda 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -11,7 +11,6 @@
#include <linux/kernel_stat.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
-#include <linux/blkdev.h> /* for blk_size */
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/shm.h>
@@ -713,6 +712,7 @@ asmlinkage long sys_swapoff(const char * specialfile)
{
struct swap_info_struct * p = NULL;
unsigned short *swap_map;
+ struct file *swap_file;
struct nameidata nd;
int i, type, prev;
int err;
@@ -730,8 +730,8 @@ asmlinkage long sys_swapoff(const char * specialfile)
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
p = swap_info + type;
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- if (p->swap_file == nd.dentry)
- break;
+ if (p->swap_file->f_dentry == nd.dentry)
+ break;
}
prev = type;
}
@@ -774,15 +774,9 @@ asmlinkage long sys_swapoff(const char * specialfile)
swap_list_unlock();
goto out_dput;
}
- if (!kdev_none(p->swap_device))
- blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
- path_release(&nd);
-
swap_list_lock();
swap_device_lock(p);
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
- p->swap_vfsmnt = NULL;
+ swap_file = p->swap_file;
p->swap_file = NULL;
p->swap_device = NODEV;
p->max = 0;
@@ -792,6 +786,7 @@ asmlinkage long sys_swapoff(const char * specialfile)
swap_device_unlock(p);
swap_list_unlock();
vfree(swap_map);
+ filp_close(swap_file, NULL);
err = 0;
out_dput:
@@ -813,7 +808,8 @@ int get_swaparea_info(char *buf)
len = sprintf(buf, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
if ((ptr->flags & SWP_USED) && ptr->swap_map) {
- char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
+ char * path = d_path(ptr->swap_file->f_dentry,
+ ptr->swap_file->f_vfsmnt,
page, PAGE_SIZE);
int j, usedswap = 0;
for (j = 0; j < ptr->max; ++j)
@@ -826,7 +822,7 @@ int get_swaparea_info(char *buf)
}
len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
path,
- kdev_none(ptr->swap_device) ? "file\t" : "partition",
+ !kdev_none(ptr->swap_device) ? "partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),
usedswap << (PAGE_SHIFT - 10),
ptr->prio);
@@ -856,8 +852,9 @@ int is_swap_partition(kdev_t dev) {
asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
{
struct swap_info_struct * p;
- struct nameidata nd;
- struct inode * swap_inode;
+ char *name;
+ struct file *swap_file = NULL;
+ struct address_space *mapping;
unsigned int type;
int i, j, prev;
int error;
@@ -867,7 +864,6 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
int nr_good_pages = 0;
unsigned long maxpages = 1;
int swapfilesize;
- struct block_device *bdev = NULL;
unsigned short *swap_map;
if (!capable(CAP_SYS_ADMIN))
@@ -887,7 +883,6 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
nr_swapfiles = type+1;
p->flags = SWP_USED;
p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
p->swap_device = NODEV;
p->swap_map = NULL;
p->lowest_bit = 0;
@@ -902,53 +897,33 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
p->prio = --least_priority;
}
swap_list_unlock();
- error = user_path_walk(specialfile, &nd);
+ name = getname(specialfile);
+ error = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto bad_swap_2;
+ swap_file = filp_open(name, O_RDWR, 0);
+ putname(name);
+ error = PTR_ERR(swap_file);
if (error)
goto bad_swap_2;
- p->swap_file = nd.dentry;
- p->swap_vfsmnt = nd.mnt;
- swap_inode = nd.dentry->d_inode;
- error = -EINVAL;
-
- if (S_ISBLK(swap_inode->i_mode)) {
- kdev_t dev = swap_inode->i_rdev;
- struct block_device_operations *bdops;
- devfs_handle_t de;
+ p->swap_file = swap_file;
- p->swap_device = dev;
- set_blocksize(dev, PAGE_SIZE);
-
- bd_acquire(swap_inode);
- bdev = swap_inode->i_bdev;
- de = devfs_get_handle_from_inode(swap_inode);
- bdops = devfs_get_ops(de); /* Increments module use count */
- if (bdops) bdev->bd_op = bdops;
-
- error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
- devfs_put_ops(de);/*Decrement module use count now we're safe*/
- if (error)
- goto bad_swap_2;
- set_blocksize(dev, PAGE_SIZE);
- error = -ENODEV;
- if (kdev_none(dev) || (blk_size[major(dev)] &&
- !blk_size[major(dev)][minor(dev)]))
- goto bad_swap;
- swapfilesize = 0;
- if (blk_size[major(dev)])
- swapfilesize = blk_size[major(dev)][minor(dev)]
- >> (PAGE_SHIFT - 10);
- } else if (S_ISREG(swap_inode->i_mode))
- swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
- else
+ if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+ p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
+ set_blocksize(p->swap_device, PAGE_SIZE);
+ } else if (!S_ISREG(swap_file->f_dentry->d_inode->i_mode))
goto bad_swap;
+ mapping = swap_file->f_dentry->d_inode->i_mapping;
+ swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
+
error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
struct swap_info_struct *q = &swap_info[i];
if (i == type || !q->swap_file)
continue;
- if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping)
+ if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
goto bad_swap;
}
@@ -1085,16 +1060,11 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
error = 0;
goto out;
bad_swap:
- if (bdev)
- blkdev_put(bdev, BDEV_SWAP);
bad_swap_2:
swap_list_lock();
swap_map = p->swap_map;
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
p->swap_device = NODEV;
p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
p->swap_map = NULL;
p->flags = 0;
if (!(swap_flags & SWAP_FLAG_PREFER))
@@ -1102,7 +1072,8 @@ bad_swap_2:
swap_list_unlock();
if (swap_map)
vfree(swap_map);
- path_release(&nd);
+ if (swap_file)
+ filp_close(swap_file, NULL);
out:
if (swap_header)
free_page((long) swap_header);
@@ -1219,7 +1190,7 @@ bad_unused:
* Prior swap_duplicate protects against swap device deletion.
*/
void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
- kdev_t *dev, struct inode **swapf)
+ struct inode **swapf)
{
unsigned long type;
struct swap_info_struct *p;
@@ -1245,14 +1216,7 @@ void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
return;
}
- if (!kdev_none(p->swap_device)) {
- *dev = p->swap_device;
- } else if (p->swap_file) {
- *swapf = p->swap_file->d_inode;
- } else {
- printk(KERN_ERR "rw_swap_page: no swap file or device\n");
- }
- return;
+ *swapf = p->swap_file->f_dentry->d_inode;
}
/*