diff options
249 files changed, 8267 insertions, 6838 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index daf40bc291ca..2e3a7333354e 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -13,14 +13,6 @@ DOCBOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \ kernel-api.sgml journal-api.sgml lsm.sgml -JBDSOURCES := $(TOPDIR)/include/linux/jbd.h \ - $(TOPDIR)/fs/jbd/journal.c \ - $(TOPDIR)/fs/jbd/recovery.c \ - $(TOPDIR)/fs/jbd/transaction.c - -journal-api.sgml: journal-api.tmpl $(JBDSOURCES) - $(TOPDIR)/scripts/docgen $(JBDSOURCES) \ - <journal-api.tmpl >journal-api.sgml ### # The build process is as follows (targets): # (sgmldocs) @@ -32,7 +24,7 @@ journal-api.sgml: journal-api.tmpl $(JBDSOURCES) # The targets that may be used. .PHONY: sgmldocs psdocs pdfdocs htmldocs clean mrproper -BOOKS := $(addprefix Documentation/DocBook/,$(DOCBOOKS)) +BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) sgmldocs: $(BOOKS) PS := $(patsubst %.sgml, %.ps, $(BOOKS)) @@ -86,19 +78,19 @@ $(BOOKS): $(KERNELDOC) ### # procfs guide uses a .c file as example code. # This requires an explicit dependency -C-procfs-example = Documentation/DocBook/procfs_example.sgml -Documentation/DocBook/procfs-guide.sgml: $(C-procfs-example) +C-procfs-example = procfs_example.sgml +C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example)) +$(obj)/procfs-guide.sgml: $(C-procfs-example2) ### # The parportbook includes a few images. # Force them to be build before the books IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig -IMG-parportbook2 := $(addprefix Documentation/DocBook/,$(IMG-parportbook)) +IMG-parportbook2 := $(addprefix $(obj)/,$(IMG-parportbook)) EPS-parportbook := $(patsubst %.fig,%.eps, $(IMG-parportbook2)) PNG-parportbook := $(patsubst %.fig,%.png, $(IMG-parportbook2)) -Documentation/DocBook/parportbook.html: $(PNG-parportbook) -Documentation/DocBook/parportbook.ps Documentation/DocBook/parportbook.pdf:\ - $(EPS-parportbook) +$(obj)/parportbook.html: $(PNG-parportbook) +$(obj)/parportbook.ps $(obj)/parportbook.pdf: $(EPS-parportbook) ### # Rules to generate postscript, PDF and HTML @@ -155,21 +147,20 @@ dochelp: ### # clean and mrproper as used by the top-level makefile # Temporary files left by various tools -DVI := $(patsubst %.sgml, %.dvi, $(BOOKS)) -AUX := $(patsubst %.sgml, %.aux, $(BOOKS)) -TEX := $(patsubst %.sgml, %.tex, $(BOOKS)) -LOG := $(patsubst %.sgml, %.log, $(BOOKS)) -OUT := $(patsubst %.sgml, %.out, $(BOOKS)) - -clean: - @rm -f $(BOOKS) - @rm -f $(DVI) $(AUX) $(TEX) $(LOG) $(OUT) - @rm -f $(PNG-parportbook) $(EPS-parportbook) - @rm -f $(C-procfs-example) - -mrproper: - @rm -f $(PS) $(PDF) - @rm -f -r $(HTML) $(patsubst %.html,%,$(HTML)) +clean-files := $(DOCBOOKS) \ + $(patsubst %.sgml, %.dvi, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.aux, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.tex, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.log, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.out, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.ps, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.pdf, $(DOCBOOKS)) \ + $(patsubst %.sgml, %.html, $(DOCBOOKS)) \ + $(patsubst %.fig,%.eps, $(IMG-parportbook)) \ + $(patsubst %.fig,%.png, $(IMG-parportbook)) \ + $(C-procfs-example) + +clean-rule := rm -rf $(patsubst %.html,%,$(HTML)) include $(TOPDIR)/Rules.make diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt new file mode 100644 index 000000000000..d1d1c9e5a839 --- /dev/null +++ b/Documentation/filesystems/sysfs.txt @@ -0,0 +1,342 @@ + +sysfs - _The_ filesystem for exporting kernel objects. + +Patrick Mochel <mochel@osdl.org> + +17 October 2002 + + +Note (17 Oct 2002): the name has just been changed from driverfs to +sysfs. Updates to the documentation will come soon; after the +conversion to use it is completely finished. + + + +What it is: +~~~~~~~~~~~ +driverfs is a ram-based filesystem. It was created by copying +ramfs/inode.c to driverfs/inode.c and doing a little search-and-replace. + +driverfs is a means to export kernel data structures, their +attributes, and the linkages between them to userspace. + +driverfs provides a unified interface for exporting attributes to +userspace. Currently, this interface is available only to device and +bus drivers. + + +Using driverfs +~~~~~~~~~~~~~~ +driverfs is always compiled in. You can access it by doing something like: + + mount -t driverfs driverfs /devices + + +Top Level Directory Layout +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driverfs directory arrangement exposes the relationship of kernel +data structures. + +The top level driverfs diretory looks like: + +bus/ +root/ + +root/ contains a filesystem representation of the device tree. It maps +directly to the internal kernel device tree, which is a hierarchy of +struct device. + +bus/ contains flat directory layout of the various bus types in the +kernel. Each bus's directory contains two subdirectories: + + devices/ + drivers/ + +devices/ contains symlinks for each device discovered in the system +that point to the device's directory under root/. + +drivers/ contains a directory for each device driver that is loaded +for devices on that particular bus (this assmumes that drivers do not +span multiple bus types). + + +More information can device-model specific features can be found in +Documentation/device-model/. + + +Directory Contents +~~~~~~~~~~~~~~~~~~ +Each object that is represented in driverfs gets a directory, rather +than a file, to make it simple to export attributes of that object. +Attributes are exported via ASCII text files. The programming +interface is discussed below. + +Instead of having monolithic files that are difficult to parse, all +files are intended to export one attribute. The name of the attribute +is the name of the file. The value of the attribute are the contents +of the file. + +There should be few, if any, exceptions to this rule. You should not +violate it, for fear of public humilation. + + +The Two-Tier Model +~~~~~~~~~~~~~~~~~~ + +driverfs is a very simple, low-level interface. In order for kernel +objects to use it, there must be an intermediate layer in place for +each object type. + +All calls in driverfs are intended to be as type-safe as possible. +In order to extend driverfs to support multiple data types, a layer of +abstraction was required. This intermediate layer converts between the +generic calls and data structures of the driverfs core to the +subsystem-specific objects and calls. + + +The Subsystem Interface +~~~~~~~~~~~~~~~~~~~~~~~ + +The subsystems bear the responsibility of implementing driverfs +extensions for the objects they control. Fortunately, it's intended to +be really easy to do so. + +It's divided into three sections: directories, files, and operations. + + +Directories +~~~~~~~~~~~ + +struct driver_dir_entry { + char * name; + struct dentry * dentry; + mode_t mode; + struct driverfs_ops * ops; +}; + + +int +driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); + +void +driverfs_remove_dir(struct driver_dir_entry * entry); + +The directory structure should be statically allocated, and reside in +a subsystem-specific data structure: + +struct device { + ... + struct driver_dir_entry dir; +}; + +The subsystem is responsible for initializing the name, mode, and ops +fields of the directory entry. (More on struct driverfs_ops later) + + +Files +~~~~~ + +struct attribute { + char * name; + mode_t mode; +}; + + +int +driverfs_create_file(struct attribute * attr, struct driver_dir_entry * parent); + +void +driverfs_remove_file(struct driver_dir_entry *, const char * name); + + +The attribute structure is a simple, common token that the driverfs +core handles. It has little use on its own outside of the +core. Objects cannot use a plain struct attribute to export +attributes, since there are no callbacks for reading and writing data. + +Therefore, the subsystem is required to define a data structure that +encapsulates the attribute structure, and provides type-safe callbacks +for reading and writing data. + +An example looks like this: + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); +}; + + +Note that there is a struct attribute embedded in the structure. In +order to relieve pain in declaring attributes, the subsystem should +also define a macro, like: + +#define DEVICE_ATTR(_name,_mode,_show,_store) \ +struct device_attribute dev_attr_##_name = { \ + .attr = {.name = __stringify(_name) , .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +This hides the initialization of the embedded struct, and in general, +the internals of each structure. It yields a structure by the name of +dev_attr_<name>. + +In order for objects to create files, the subsystem should create +wrapper functions, like this: + +int device_create_file(struct device *device, struct device_attribute * entry); +void device_remove_file(struct device * dev, struct device_attribute * attr); + +..and forward the call on to the driverfs functions. + +Note that there is no unique information in the attribute structures, +so the same structure can be used to describe files of several +different object instances. + + +Operations +~~~~~~~~~~ + +struct driverfs_ops { + int (*open)(struct driver_dir_entry *); + int (*close)(struct driver_dir_entry *); + ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t); + ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t); +}; + + +Subsystems are required to implement this set of callbacks. Their +purpose is to translate the generic data structures into the specific +objects, and operate on them. This can be done by defining macros like +this: + +#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) + +#define to_device(d) container_of(d, struct device, dir) + + +Since the directories are statically allocated in the object, you can +derive the pointer to the object that owns the file. Ditto for the +attribute structures. + +Current Interfaces +~~~~~~~~~~~~~~~~~~ + +The following interface layers currently exist in driverfs: + + +- devices (include/linux/device.h) +---------------------------------- +Structure: + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); +}; + +Declaring: + +DEVICE_ATTR(_name,_str,_mode,_show,_store); + +Creation/Removal: + +int device_create_file(struct device *device, struct device_attribute * entry); +void device_remove_file(struct device * dev, struct device_attribute * attr); + + +- bus drivers (include/linux/device.h) +-------------------------------------- +Structure: + +struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); +}; + +Declaring: + +BUS_ATTR(_name,_mode,_show,_store) + +Creation/Removal: + +int bus_create_file(struct bus_type *, struct bus_attribute *); +void bus_remove_file(struct bus_type *, struct bus_attribute *); + + +- device drivers (include/linux/device.h) +----------------------------------------- + +Structure: + +struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); +}; + +Declaring: + +DRIVER_ATTR(_name,_mode,_show,_store) + +Creation/Removal: + +int driver_create_file(struct device_driver *, struct driver_attribute *); +void driver_remove_file(struct device_driver *, struct driver_attribute *); + + +Reading/Writing Data +~~~~~~~~~~~~~~~~~~~~ +The callback functionality is similar to the way procfs works. When a +user performs a read(2) or write(2) on the file, it first calls a +driverfs function. This calls to the subsystem, which then calls to +the object's show() or store() function. + +The buffer pointer, offset, and length should be passed to each +function. The downstream callback should fill the buffer and return +the number of bytes read/written. + + +What driverfs is not: +~~~~~~~~~~~~~~~~~~~~~ +It is not a replacement for either devfs or procfs. + +It does not handle device nodes, like devfs is intended to do. I think +this functionality is possible, but indeed think that integration of +the device nodes and control files should be done. Whether driverfs or +devfs, or something else, is the place to do it, I don't know. + +It is not intended to be a replacement for all of the procfs +functionality. I think that many of the driver files should be moved +out of /proc (and maybe a few other things as well ;). + + + +Limitations: +~~~~~~~~~~~~ +The driverfs functions assume that at most a page is being either read +or written each time. + +There is a race condition that is really, really hard to fix; if not +impossible. There exists a race between a driverfs file being opened +and the object that owns the file going away. During the driverfs +open() callback, the reference count for the owning object needs to be +incremented. + +For drivers, we can put a struct module * owner in struct driver_dir_entry +and do try_inc_mod_count() when we open a file. However, this won't +work for devices, that aren't tied to a module. And, it is still not +guaranteed to solve the race. + +I'm looking into fixing this, but it may not be doable without making +a separate filesystem instance for each object. It's fun stuff. Please +mail me with creative ideas that you know will work. + + +Possible bugs: +~~~~~~~~~~~~~~ +It may not deal with offsets and/or seeks very well, especially if +they cross a page boundary. + diff --git a/MAINTAINERS b/MAINTAINERS index a9b191413d74..b3daddefc143 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,3 +1,4 @@ + List of maintainers and how to submit kernel changes Please try to follow the guidelines below. This will make things @@ -261,7 +262,6 @@ BFS FILE SYSTEM P: Tigran A. Aivazian M: tigran@veritas.com L: linux-kernel@vger.kernel.org -W: http://www.ocston.org/~tigran/patches/bfs S: Maintained BLOCK LAYER @@ -654,8 +654,8 @@ W: http://www.nyx.net/~arobinso S: Maintained HFS FILESYSTEM -P: Adrian Sun -M: asun@cobaltnet.com +P: Oliver Neukum +M: oliver@neukum.org L: linux-kernel@vger.kernel.org S: Maintained @@ -239,7 +239,7 @@ ifdef include-config # If .config doesn't exist - tough luck -.config: arch/$(ARCH)/config.in $(shell find . -name Config.in) +.config: arch/$(ARCH)/config.in # FIXME $(shell find . -name Config.in) @echo '***' @if [ -f $@ ]; then \ echo '*** The tree was updated, so your .config may be'; \ @@ -456,18 +456,23 @@ include/linux/version.h: Makefile depend dep: .hdepend -# .hdepend is our (misnomed) marker for whether we've run +# .hdepend is our (misnomed) marker for whether we've # generated module versions -.hdepend: $(if $(filter dep depend,$(MAKECMDGOALS)),FORCE) +make-versions := $(strip $(if $(filter dep depend,$(MAKECMDGOALS)),1) \ + $(if $(wildcard .hdepend),,1)) + +.hdepend: prepare FORCE +ifneq ($(make-versions),) @$(MAKE) include/linux/modversions.h @touch $@ +endif ifdef CONFIG_MODVERSIONS # Update modversions.h, but only if it would change. -include/linux/modversions.h: scripts/fixdep prepare FORCE +include/linux/modversions.h: FORCE @rm -rf .tmp_export-objs @$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) @echo -n ' Generating $@' @@ -661,90 +666,61 @@ allmodconfig: defconfig: yes '' | $(CONFIG_SHELL) $(src)/scripts/Configure -d arch/$(ARCH)/config.in -# Cleaning up -# --------------------------------------------------------------------------- +### +# Cleaning is done on three levels. +# make clean Delete all automatically generated files, including +# tools and firmware. +# make mrproper Delete the current configuration, and related files +# Any core files spread around is deleted as well +# make distclean Remove editor backup files, patch leftover files and the like -# files removed with 'make clean' -CLEAN_FILES += \ - include/linux/compile.h \ - vmlinux System.map \ - drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ - drivers/char/conmakehash \ - drivers/char/drm/*-mod.c \ - drivers/char/defkeymap.c drivers/char/qtronixmap.c \ - drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \ - drivers/zorro/devlist.h drivers/zorro/gen-devlist \ - sound/oss/bin2hex sound/oss/hex2hex \ - drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \ - drivers/scsi/aic7xxx/aic7xxx_seq.h \ - drivers/scsi/aic7xxx/aic7xxx_reg.h \ - drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \ - drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \ - drivers/scsi/aic7xxx/aicasm/y.tab.h \ - drivers/scsi/aic7xxx/aicasm/aicasm \ - drivers/scsi/53c700_d.h drivers/scsi/sim710_d.h \ - drivers/scsi/53c7xx_d.h drivers/scsi/53c7xx_u.h \ - drivers/scsi/53c8xx_d.h drivers/scsi/53c8xx_u.h \ - net/802/cl2llc.c net/802/transit/pdutr.h net/802/transit/timertr.h \ - net/802/pseudo/pseudocode.h \ - net/khttpd/make_times_h net/khttpd/times.h \ - submenu* - -# files removed with 'make mrproper' +# Files removed with 'make clean' +CLEAN_FILES += vmlinux System.map MC* + +# Files removed with 'make mrproper' MRPROPER_FILES += \ include/linux/autoconf.h include/linux/version.h \ - drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \ - drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \ - drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \ - drivers/net/hamradio/soundmodem/gentbl \ - sound/oss/*_boot.h sound/oss/.*.boot \ - sound/oss/msndinit.c \ - sound/oss/msndperm.c \ - sound/oss/pndsperm.c \ - sound/oss/pndspini.c \ - drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \ - .version .config* config.in config.old \ - scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \ - scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ + .version .config .config.old config.in config.old \ .menuconfig.log \ include/asm \ .hdepend include/linux/modversions.h \ tags TAGS kernel.spec \ .tmp* -# directories removed with 'make mrproper' +# Directories removed with 'make mrproper' MRPROPER_DIRS += \ .tmp_export-objs \ include/config \ include/linux/modules -clean: archclean - @echo 'Cleaning up' - @find . $(RCS_FIND_IGNORE) \ - \( -name \*.[oas] -o -name core -o -name .\*.cmd -o \ - -name .\*.tmp -o -name .\*.d \) -type f -print \ - | grep -v lxdialog/ | xargs rm -f - @rm -f $(CLEAN_FILES) - +@$(call descend,Documentation/DocBook,clean) - -mrproper: clean archmrproper - @echo 'Making mrproper' +# clean - Delete all intermediate files +# +clean-dirs += $(ALL_SUBDIRS) Documentation/DocBook scripts + +$(addprefix _clean_,$(clean-dirs)): + +@$(call descend,$(patsubst _clean_%,%,$@), subdirclean) + +quiet_cmd_rmclean = RM $$(CLEAN_FILES) +cmd_rmclean = rm -f $(CLEAN_FILES) +clean: archclean $(addprefix _clean_,$(clean-dirs)) + $(call cmd,rmclean) @find . $(RCS_FIND_IGNORE) \ - \( -name .depend -o -name .\*.cmd \) \ - -type f -print | xargs rm -f - @rm -rf $(MRPROPER_DIRS) - @rm -f $(MRPROPER_FILES) - +@$(call descend,scripts,mrproper) - +@$(call descend,Documentation/DocBook,mrproper) + \( -name '*.[oas]' -o -name '.*.cmd' -o -name '.*.d' \ + -o -name '.*.tmp' \) -type f -print | xargs rm -f -distclean: mrproper - @echo 'Making distclean' +# mrproper - delete configuration + modules + core files +# +quiet_cmd_mrproper = RM $$(MRPROPER_DIRS) + $$(MRPROPER_FILES) +cmd_mrproper = rm -rf $(MRPROPER_DIRS) && rm -f $(MRPROPER_FILES) +mrproper distclean: clean archmrproper + @echo ' Making $@ in the srctree' @find . $(RCS_FIND_IGNORE) \ - \( -not -type d \) -and \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f \ - -print | xargs rm -f + -o -name '.*.rej' -o -size 0 \ + -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ + -type f -print | xargs rm -f + $(call cmd,mrproper) # Generate tags for editors # --------------------------------------------------------------------------- diff --git a/Rules.make b/Rules.make index affdf72286ae..56e62f97f333 100644 --- a/Rules.make +++ b/Rules.make @@ -87,6 +87,7 @@ obj-m := $(filter-out %/, $(obj-m)) # Subdirectories we need to descend into subdir-ym := $(sort $(subdir-y) $(subdir-m)) +subdir-ymn := $(sort $(subdir-ym) $(subdir-n) $(subdir-)) # export.o is never a composite object, since $(export-objs) has a # fixed meaning (== objects which EXPORT_SYMBOL()) @@ -113,6 +114,10 @@ real-objs-m := $(foreach m, $(obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m # Only build module versions for files which are selected to be built export-objs := $(filter $(export-objs),$(real-objs-y) $(real-objs-m)) +host-progs-single := $(foreach m,$(host-progs),$(if $($(m)-objs),,$(m))) +host-progs-multi := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m))) +host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs)) + # Add subdir path EXTRA_TARGETS := $(addprefix $(obj)/,$(EXTRA_TARGETS)) @@ -127,12 +132,19 @@ multi-used-m := $(addprefix $(obj)/,$(multi-used-m)) multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y)) multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m)) subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) +subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn)) +clean-files := $(addprefix $(obj)/,$(clean-files)) +host-progs := $(addprefix $(obj)/,$(host-progs)) +host-progs-single := $(addprefix $(obj)/,$(host-progs-single)) +host-progs-multi := $(addprefix $(obj)/,$(host-progs-multi)) +host-progs-multi-objs := $(addprefix $(obj)/,$(host-progs-multi-objs)) # The temporary file to save gcc -MD generated dependencies must not # contain a comma depfile = $(subst $(comma),_,$(@D)/.$(@F).d) -# We're called for one of three purposes: +# We're called for one of four purposes: +# o subdirclean: Delete intermidiate files in the current directory # o fastdep: build module version files (.ver) for $(export-objs) in # the current directory # o modules_install: install the modules in the current directory @@ -142,6 +154,19 @@ depfile = $(subst $(comma),_,$(@D)/.$(@F).d) # When targets are given directly (like foo.o), we just build these # targets (That happens when someone does make some/dir/foo.[ois]) +ifeq ($(MAKECMDGOALS),subdirclean) + +__clean-files := $(wildcard $(EXTRA_TARGETS) $(host-progs) $(clean-files)) + +subdirclean: $(subdir-ymn) +ifneq ($(strip $(__clean-files) $(clean-rule)),) + rm -f $(__clean-files) + $(clean-rule) +else + @/bin/true +endif + +else ifeq ($(MAKECMDGOALS),fastdep) # =========================================================================== @@ -161,7 +186,7 @@ else # This sets version suffixes on exported symbols # --------------------------------------------------------------------------- -MODVERDIR := include/linux/modules/ +MODVERDIR := include/linux/modules # # Added the SMP separator to stop module accidents between uniprocessor @@ -399,14 +424,6 @@ targets += $(multi-used-y) $(multi-used-m) # Compile programs on the host # =========================================================================== -host-progs-single := $(foreach m,$(host-progs),$(if $($(m)-objs),,$(m))) -host-progs-multi := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m))) -host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs)) -host-progs := $(addprefix $(obj)/,$(host-progs)) -host-progs-single := $(addprefix $(obj)/,$(host-progs-single)) -host-progs-multi := $(addprefix $(obj)/,$(host-progs-multi)) -host-progs-multi-objs := $(addprefix $(obj)/,$(host-progs-multi-objs)) - quiet_cmd_host_cc__c = HOSTCC $(echo_target) cmd_host_cc__c = $(HOSTCC) -Wp,-MD,$(depfile) \ $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ @@ -431,6 +448,7 @@ $(host-progs-multi): %: $(host-progs-multi-objs) FORCE targets += $(host-progs-single) $(host-progs-multi-objs) $(host-progs-multi) +endif # ! subdirclean endif # ! modules_install endif # ! fastdep @@ -480,9 +498,9 @@ cmd_gzip = gzip -f -9 < $< > $@ # Descending # --------------------------------------------------------------------------- -.PHONY: $(subdir-ym) +.PHONY: $(subdir-ymn) -$(subdir-ym): +$(subdir-ymn): +@$(call descend,$@,$(MAKECMDGOALS)) # Add FORCE to the prequisites of a target to force it to be always rebuilt. diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 4cb68c31b86e..2b291c31ff8b 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -1114,7 +1114,7 @@ int ecard_register_driver(struct ecard_driver *drv) void ecard_remove_driver(struct ecard_driver *drv) { - remove_driver(&drv->drv); + driver_unregister(&drv->drv); } static int ecard_match(struct device *_dev, struct device_driver *_drv) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 4df45365d6f0..dbd363bdb52f 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -88,6 +88,6 @@ install: vmlinux +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install) archclean: - +@$(call makeboot,clean) + +@$(call makeboot,subdirclean) archmrproper: diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index 3369bfc67700..b06bab8ccd43 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -28,6 +28,8 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA EXTRA_TARGETS := vmlinux.bin bootsect bootsect.o \ setup setup.o zImage bzImage +subdir- := compressed + host-progs := tools/build # Default @@ -79,11 +81,6 @@ zlilo: $(BOOTIMAGE) install: $(BOOTIMAGE) sh $(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" -clean: - @echo 'Cleaning up (boot)' - @rm -f $(host-progs) $(EXTRA_TARGETS) - +@$(call descend,$(obj)/compressed) clean - archhelp: @echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)' @echo ' install - Install kernel using' diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 53af39a4408e..16383b2df2fb 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -24,7 +24,3 @@ LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) - -clean: - @echo 'Cleaning up (boot/compressed)' - @rm -f $(EXTRA_TARGETS) diff --git a/arch/i386/config.in b/arch/i386/config.in index 1026d1a0a1f4..5777724de6f0 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -453,6 +453,7 @@ fi bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index 5e5ef23f39b9..5941b9da5985 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -300,7 +300,6 @@ static void mce_checkregs (void *info) static void do_mce_timer(void *data) { - mce_checkregs(NULL); smp_call_function (mce_checkregs, NULL, 1, 1); } diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index 3f95d0b1f189..df360f06616e 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -42,6 +42,21 @@ static void __init init_amd(struct cpuinfo_x86 *c) switch(c->x86) { + case 4: + /* + * General Systems BIOSen alias the cpu frequency registers + * of the Elan at 0x000df000. Unfortuantly, one of the Linux + * drivers subsequently pokes it, and changes the CPU speed. + * Workaround : Remove the unneeded alias. + */ +#define CBAR (0xfffc) /* Configuration Base Address (32-bit) */ +#define CBAR_ENB (0x80000000) +#define CBAR_KEY (0X000000CB) + if (c->x86_model==9 || c->x86_model == 10) { + if (inl (CBAR) & CBAR_ENB) + outl (0 | CBAR_KEY, CBAR); + } + case 5: if( c->x86_model < 6 ) { diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5bc54a30c2f8..4bb71d80fb1f 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -856,7 +856,9 @@ void __init print_IO_APIC(void) printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)®_00); printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID); - if (reg_00.__reserved_1 || reg_00.__reserved_2) + printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.delivery_type); + printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.LTS); + if (reg_00.__reserved_0 || reg_00.__reserved_1 || reg_00.__reserved_2) UNEXPECTED_IO_APIC(); printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 2ac7753a5f66..fdddbf524c01 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -328,8 +328,22 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; + long esp; irq_enter(); + +#ifdef CONFIG_DEBUG_STACKOVERFLOW + /* Debugging check for stack overflow: is there less than 1KB free? */ + __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191)); + if (unlikely(esp < (sizeof(struct task_struct) + 1024))) { + extern void show_stack(unsigned long *); + + printk("do_IRQ: stack overflow: %ld\n", + esp - sizeof(struct task_struct)); + __asm__ __volatile__("movl %%esp,%0" : "=r" (esp)); + show_stack((void *)esp); + } +#endif kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index ccdebea64733..58201846cf7c 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -260,7 +260,7 @@ static void do_update_one(void *unused) if (microcode[i].rev < rev) { spin_unlock_irqrestore(µcode_update_lock, flags); - printk(KERN_ERR + printk(KERN_INFO "microcode: CPU%d not 'upgrading' to earlier revision" " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); return; @@ -268,7 +268,7 @@ static void do_update_one(void *unused) /* notify the caller of success on this cpu */ req->err = 0; spin_unlock_irqrestore(µcode_update_lock, flags); - printk(KERN_ERR + printk(KERN_INFO "microcode: CPU%d already at revision" " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); return; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 5218fd2ea29a..ca8a9d54f116 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -482,7 +482,7 @@ void __init mem_init(void) datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), num_physpages << (PAGE_SHIFT-10), codesize >> 10, @@ -584,14 +584,14 @@ void free_initmem(void) free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c index db71a8c73b5b..9cfc595855de 100644 --- a/arch/i386/pci/i386.c +++ b/arch/i386/pci/i386.c @@ -291,7 +291,7 @@ void pcibios_set_master(struct pci_dev *dev) lat = pcibios_max_latency; else return; - printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat); + printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat); pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } diff --git a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S index 41e54abb9b5a..99301e99ae50 100644 --- a/arch/i386/vmlinux.lds.S +++ b/arch/i386/vmlinux.lds.S @@ -8,6 +8,7 @@ jiffies = jiffies_64; SECTIONS { . = 0xC0000000 + 0x100000; + /* read-only */ _text = .; /* Text and read-only data */ .text : { *(.text) @@ -29,16 +30,34 @@ SECTIONS __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + + /* writeable */ .data : { /* Data */ *(.data) CONSTRUCTORS } + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + _edata = .; /* End of data section */ . = ALIGN(8192); /* init_task */ .data.init_task : { *(.data.init_task) } + /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ __init_begin = .; .init.text : { *(.init.text) } @@ -64,23 +83,8 @@ SECTIONS __per_cpu_end = .; . = ALIGN(4096); __init_end = .; - - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - __start___kallsyms = .; /* All kernel symbols */ - __kallsyms : { *(__kallsyms) } - __stop___kallsyms = .; - + /* freed after init ends here */ + __bss_start = .; /* BSS */ .bss : { *(.bss) } __bss_stop = .; diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index c430e823ef08..5fa3e289b581 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -3763,12 +3763,15 @@ do_smb_super_data_conv(void *raw_data) struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = s32->mounted_uid; s->uid = s32->uid; s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 8fc59afbc307..75467652ef37 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -64,7 +64,7 @@ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ drivers-$(CONFIG_8260) += arch/ppc/8260_io/ -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +makeboot = $(call descend,arch/ppc/boot,$(1)) BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd pImage vmlinux.sm @@ -74,14 +74,14 @@ AFLAGS_vmlinux.lds.o := -Upowerpc bzImage: zImage $(BOOT_TARGETS): vmlinux - @$(MAKEBOOT) $@ + +@$(call makeboot,$@) %_config: arch/ppc/configs/%_defconfig rm -f .config arch/ppc/defconfig cp -f arch/ppc/configs/$(@:config=defconfig) .config archclean: - @$(MAKEBOOT) clean + +@$(call makeboot,clean) archmrproper: diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 7fc8e3dac69e..a6a312b7ba26 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -10,25 +10,16 @@ # modified by Cort (cort@cs.nmt.edu) # -GZIP_FLAGS = -v9f - CFLAGS += -fno-builtin -D__BOOTER__ -I$(TOPDIR)/arch/$(ARCH)/boot/include AFLAGS += -D__BOOTER__ OBJCOPY_ARGS = -O elf32-powerpc -MKIMAGE := ./utils/mkimage.wrapper - -lib/lib.a: lib/zlib.c - $(MAKE) -C lib +subdir-y := simple +subdir-$(CONFIG_ALL_PPC) := openfirmware prep -images/vmlinux.gz: $(TOPDIR)/vmlinux - $(MAKE) -C images vmlinux.gz +HOSTCFLAGS += -Iarch/$(ARCH)/boot/include -# Subdirs and tools needed for each. Assume we always need to go into -# 'simple' unless told otherwise. -subdir-y := lib common simple -subdir-$(CONFIG_ALL_PPC) := openfirmware prep tools-$(CONFIG_ALL_PPC) := addnote mknote hack-coff mkprep tools-$(CONFIG_PPLUS) := mkbugboot mkprep tools-$(CONFIG_4xx) := mktree @@ -40,49 +31,24 @@ tools-$(CONFIG_PRPMC750) := mkbugboot mkprep tools-$(CONFIG_PRPMC800) := mkbugboot mkprep tools-$(CONFIG_SPRUCE) := mktree -# These are dirs we don't want to go into on BOOT_TARGETS. We have them for -# the 'depend' stage. -NONBOOT := lib common +all-tools := addnote mknote hack-coff mkprep mkbugboot mktree -# These are the subdirs we want to use -BOOTDIRS = $(filter-out $(NONBOOT), $(subdir-y)) +host-progs := $(addprefix utils/,$(tools-y)) -makeof1275: - $(MAKE) -C of1275 - -# This will make the tools we need. We do it like this to ensure that we use -# HOSTCC. -- Tom -maketools: - $(MAKE) -C utils $(tools-y) - -# The targets all boards support for boot images. -BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd +include $(TOPDIR)/Rules.make -$(BOOT_TARGETS): vmapus lib/lib.a images/vmlinux.gz makeof1275 maketools -ifneq ($(BOOTDIRS),) - for d in $(BOOTDIRS); do $(MAKE) -C $$d $@; done -endif +zImage zImage.initrd znetboot znetboot.initrd: $(subdir-y) -vmapus: $(TOPDIR)/vmlinux -ifdef CONFIG_APUS - $(STRIP) $(TOPDIR)/vmlinux -o images/vmapus - gzip $(GZIP_FLAGS) images/vmapus -endif +simple openfirmware prep: lib common images +openfirmware prep: of1275 -# Make an image for PPCBoot -pImage: images/vmlinux.gz - $(MKIMAGE) -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \ - -n 'Linux-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)' \ - -d $< images/vmlinux.PPCBoot - ln -sf vmlinux.PPCBoot images/pImage +lib common of1275 images: FORCE + +@$(call descend,$(obj)/$@,) -vmlinux.sm: $(TOPDIR)/vmlinux utils/addSystemMap - ./utils/addSystemMap $(TOPDIR)/System.map $(TOPDIR)/vmlinux images/vmlinux.sm +openfirmware prep simple: FORCE + +@$(call descend,$(obj)/$@,$(MAKECMDGOALS)) -# These are subdirs with files not normally rm'ed. -- Tom -clean: - $(MAKE) -C images clean - $(MAKE) -C utils clean - $(MAKE) -C openfirmware clean +CLEAN_FILES += $(addprefix $(obj)/utils,$(all-tools)) -include $(TOPDIR)/Rules.make +clean: FORCE + +@$(call descend,$(obj)/images,clean) diff --git a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile index 5295d53bb8a8..0b882179eef6 100644 --- a/arch/ppc/boot/common/Makefile +++ b/arch/ppc/boot/common/Makefile @@ -8,7 +8,12 @@ # Tom Rini January 2001 # -coffcrt0.o: - $(CC) $(AFLAGS) -DXCOFF -traditional -c -o coffcrt0.o crt0.S +L_TARGET := lib.a + +obj-y := string.o util.o misc-common.o +obj-$(CONFIG_ALL_PPC) += mpc10x_memory.o +obj-$(CONFIG_LOPEC) += mpc10x_memory.o +obj-$(CONFIG_PAL4) += cpc700_memory.o +obj-$(CONFIG_SERIAL_8250_CONSOLE) += ns16550.o include $(TOPDIR)/Rules.make diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile index 8723f6c5519e..f37cc9e47a0f 100644 --- a/arch/ppc/boot/images/Makefile +++ b/arch/ppc/boot/images/Makefile @@ -2,11 +2,16 @@ # This dir holds all of the images for PPC machines. # Tom Rini January 2001 +all: $(obj)/vmlinux.gz + include $(TOPDIR)/Rules.make -vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) --strip-all -S -O binary $(TOPDIR)/vmlinux vmlinux - gzip -vf9 vmlinux +GZIP_FLAGS = -v9f + +$(obj)/vmlinux.gz: vmlinux + $(OBJCOPY) -S -O binary vmlinux $(obj)/vmlinux + gzip $(GZIP_FLAGS) $(obj)/vmlinux clean: - rm -f sImage vmapus vmlinux* miboot* zImage* zvmlinux* + rm -f $(obj)/sImage $(obj)/vmapus $(obj)/vmlinux* $(obj)/miboot* + rm -f $(obj)/zImage* z$(obj)/vmlinux* diff --git a/arch/ppc/boot/include/mpc10x.h b/arch/ppc/boot/include/mpc10x.h index e71b667a683e..bef99d1f6b18 100644 --- a/arch/ppc/boot/include/mpc10x.h +++ b/arch/ppc/boot/include/mpc10x.h @@ -58,7 +58,7 @@ #define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */ #define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */ -#define MPC10X_MCTLR_MEM_END_2i 0x94 /* Banks 4-7 */ +#define MPC10X_MCTLR_MEM_END_2 0x94 /* Banks 4-7 */ #define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */ #define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */ diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile index f1bd994045f0..4984baf0ff96 100644 --- a/arch/ppc/boot/lib/Makefile +++ b/arch/ppc/boot/lib/Makefile @@ -4,6 +4,6 @@ L_TARGET := lib.a -obj-y := zlib.o +obj-y := zlib.o div64.o include $(TOPDIR)/Rules.make diff --git a/arch/ppc/boot/lib/div64.S b/arch/ppc/boot/lib/div64.S new file mode 100644 index 000000000000..3527569e9926 --- /dev/null +++ b/arch/ppc/boot/lib/div64.S @@ -0,0 +1,58 @@ +/* + * Divide a 64-bit unsigned number by a 32-bit unsigned number. + * This routine assumes that the top 32 bits of the dividend are + * non-zero to start with. + * On entry, r3 points to the dividend, which get overwritten with + * the 64-bit quotient, and r4 contains the divisor. + * On exit, r3 contains the remainder. + * + * Copyright (C) 2002 Paul Mackerras, IBM Corp. + * + * 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. + */ +#include <asm/ppc_asm.h> +#include <asm/processor.h> + +_GLOBAL(__div64_32) + lwz r5,0(r3) # get the dividend into r5/r6 + lwz r6,4(r3) + cmplw r5,r4 + li r7,0 + li r8,0 + blt 1f + divwu r7,r5,r4 # if dividend.hi >= divisor, + mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor + subf. r5,r0,r5 # dividend.hi %= divisor + beq 3f +1: mr r11,r5 # here dividend.hi != 0 + andis. r0,r5,0xc000 + bne 2f + cntlzw r0,r5 # we are shifting the dividend right + li r10,-1 # to make it < 2^32, and shifting + srw r10,r10,r0 # the divisor right the same amount, + add r9,r4,r10 # rounding up (so the estimate cannot + andc r11,r6,r10 # ever be too large, only too small) + andc r9,r9,r10 + or r11,r5,r11 + rotlw r9,r9,r0 + rotlw r11,r11,r0 + divwu r11,r11,r9 # then we divide the shifted quantities +2: mullw r10,r11,r4 # to get an estimate of the quotient, + mulhwu r9,r11,r4 # multiply the estimate by the divisor, + subfc r6,r10,r6 # take the product from the divisor, + add r8,r8,r11 # and add the estimate to the accumulated + subfe. r5,r9,r5 # quotient + bne 1b +3: cmplw r6,r4 + blt 4f + divwu r0,r6,r4 # perform the remaining 32-bit division + mullw r10,r0,r4 # and get the remainder + add r8,r8,r0 + subf r6,r10,r6 +4: stw r7,0(r3) # return the quotient in *r3 + stw r8,4(r3) + mr r3,r6 # return the remainder in r3 + blr diff --git a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile index e855cb64b28f..1d3a1f8bef49 100644 --- a/arch/ppc/boot/of1275/Makefile +++ b/arch/ppc/boot/of1275/Makefile @@ -2,7 +2,7 @@ # Makefile of1275 stuff # -L_TARGET := of1275.a +L_TARGET := lib.a obj-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ ofstdio.o read.o release.o write.o diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile index c34d71381350..210f162442e4 100644 --- a/arch/ppc/boot/openfirmware/Makefile +++ b/arch/ppc/boot/openfirmware/Makefile @@ -10,24 +10,37 @@ # Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the # rules. +EXTRA_TARGETS := start.o misc.o crt0.o coffcrt0.o coffmain.o chrpmain.o \ + newworldmain.o common.o + +boot: zImage + +include $(TOPDIR)/Rules.make + +boot := arch/ppc/boot +common := $(boot)/common +utils := $(boot)/utils +bootlib := $(boot)/lib +of1275 := $(boot)/of1275 +images := $(boot)/images + OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic -CHRP_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00400000 -NEWWORLD_LD_ARGS = -T ../ld.script -e _start -Ttext 0x01000000 +COFF_LD_ARGS = -T $(boot)/ld.script -e _start -Ttext 0x00700000 -Bstatic +CHRP_LD_ARGS = -T $(boot)/ld.script -e _start -Ttext 0x00800000 +NEWWORLD_LD_ARGS = -T $(boot)/ld.script -e _start -Ttext 0x01000000 -COMMONOBJS = start.o misc.o ../common/string.o common.o -COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o -CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o -NEWWORLDOBJS = ../common/crt0.o $(COMMONOBJS) newworldmain.o +COMMONOBJS = $(obj)/start.o $(obj)/misc.o $(obj)/common.o +COFFOBJS = $(obj)/coffcrt0.o $(COMMONOBJS) $(obj)/coffmain.o +CHRPOBJS = $(obj)/crt0.o $(COMMONOBJS) $(obj)/chrpmain.o +NEWWORLDOBJS = $(obj)/crt0.o $(COMMONOBJS) $(obj)/newworldmain.o -EXTRA_TARGETS := $(COFFOBJS) $(CHRPOBJS) $(NEWWORLDOBJS) -LIBS = $(TOPDIR)/lib/lib.a ../lib/lib.a ../of1275/of1275.a +LIBS = lib/lib.a $(bootlib)/lib.a $(of1275)/lib.a $(common)/lib.a -ADDNOTE := ../utils/addnote -MKNOTE := ../utils/mknote -SIZE := ../utils/size -OFFSET := ../utils/offset -HACKCOFF := ../utils/hack-coff +ADDNOTE := $(utils)/addnote +MKNOTE := $(utils)/mknote +SIZE := $(utils)/size +OFFSET := $(utils)/offset +HACKCOFF := $(utils)/hack-coff ifdef CONFIG_SMP END := .smp @@ -38,12 +51,12 @@ endif TFTPIMAGE=/tftpboot/zImage. -../common/coffcrt0.o: - $(MAKE) -C ../common coffcrt0.o +$(obj)/dummy.o: $(common)/dummy.c + $(CC) -c -o $@ $(common)/dummy.c -image.o: ../images/vmlinux.gz ../common/dummy.o - $(OBJCOPY) ../common/dummy.o $@ -R .comment \ - --add-section=.image=../images/vmlinux.gz \ +$(obj)/image.o: $(images)/vmlinux.gz $(obj)/dummy.o + $(OBJCOPY) $(obj)/dummy.o $@ -R .comment \ + --add-section=.image=$(images)/vmlinux.gz \ --set-section-flags=.image=contents,alloc,load,readonly,data ifdef CONFIG_XMON $(OBJCOPY) $@ $@ \ @@ -52,86 +65,93 @@ ifdef CONFIG_XMON endif # Place the ramdisk in the initrd image. -image-initrd.o: image.o ../images/ramdisk.image.gz - $(OBJCOPY) image.o $@ \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ +$(obj)/image-initrd.o: $(obj)/image.o $(images)/ramdisk.image.gz + $(OBJCOPY) $(obj)/image.o $@ \ + --add-section=.ramdisk=$(images)/ramdisk.image.gz \ --set-section-flags=.ramdisk=contents,alloc,load,readonly,data # Create the note section for New-World PowerMacs. -note: $(MKNOTE) - $(MKNOTE) > note - -znetboot: vmlinux.coff vmlinux.elf-pmac zImage - cp ../images/vmlinux.coff $(TFTPIMAGE).pmac$(END) - cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END)elf - cp ../images/zImage.chrp $(TFTPIMAGE).chrp$(END) - -znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac - cp ../images/vmlinux.initrd.coff $(TFTPIMAGE).pmac$(END) - cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf - cp ../images/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END) +$(obj)/note: $(MKNOTE) + $(MKNOTE) > $(obj)/note + +znetboot: $(images)/vmlinux.coff $(images)/vmlinux.elf-pmac $(images)/zImage.chrp + cp $(images)/vmlinux.coff $(TFTPIMAGE).pmac$(END) + cp $(images)/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END)elf + cp $(images)/zImage.chrp $(TFTPIMAGE).chrp$(END) + +znetboot.initrd: $(images)/vmlinux.initrd.coff \ + $(images)/vmlinux.initrd.elf-pmac \ + $(images)/zImage.initrd.chrp + cp $(images)/vmlinux.initrd.coff $(TFTPIMAGE).pmac$(END) + cp $(images)/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf + cp $(images)/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END) + +$(images)/miboot.image: $(obj)/dummy.o $(images)/vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=$(images)/vmlinux.gz \ + $(obj)/dummy.o $@ + +$(images)/miboot.initrd.image: $(images)/miboot.image $(images)/ramdisk.image.gz + $(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section=initrd=$(images)/ramdisk.image.gz \ + $(images)/miboot.image $@ -miboot.image: ../common/dummy.o ../images/vmlinux.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ - ../common/dummy.o ../images/$@ +$(obj)/coffcrt0.o: $(common)/crt0.S + $(CC) $(AFLAGS) -DXCOFF -traditional -c -o $@ $(common)/crt0.S -miboot.initrd.image: miboot.image ../images/ramdisk.image.gz - $(OBJCOPY) $(OBJCOPY_ARGS) \ - --add-section=initrd=../images/ramdisk.image.gz \ - ../images/miboot.image ../images/$@ +$(obj)/crt0.o: $(common)/crt0.S + $(CC) $(AFLAGS) -traditional -c -o $@ $(common)/crt0.S -coffboot: $(COFFOBJS) image.o $(LIBS) +$(obj)/coffboot: $(COFFOBJS) $(obj)/image.o $(LIBS) $(LD) -o $@ $(COFF_LD_ARGS) $^ $(OBJCOPY) $@ $@ -R .comment -R .ramdisk -coffboot.initrd: $(COFFOBJS) image-initrd.o $(LIBS) +$(obj)/coffboot.initrd: $(COFFOBJS) $(obj)/image-initrd.o $(LIBS) $(LD) -o $@ $(COFF_LD_ARGS) $^ $(OBJCOPY) $@ $@ -R .comment -vmlinux.coff: coffboot $(HACKCOFF) - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ - $(HACKCOFF) ../images/$@ - rm -f coffboot - ln -sf vmlinux.coff ../images/zImage.pmac - -vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF) - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ - $(HACKCOFF) ../images/$@ - rm -f coffboot.initrd - ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac - -vmlinux.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image.o - $(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^ - -vmlinux.initrd.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image-initrd.o - $(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^ - -zImage.chrp: $(CHRPOBJS) image.o $(LIBS) - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^ - -zImage.initrd.chrp: $(CHRPOBJS) image-initrd.o $(LIBS) - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^ - -zImage: vmlinux.coff vmlinux.elf-pmac zImage.chrp miboot.image $(ADDNOTE) \ - note - $(OBJCOPY) ../images/vmlinux.elf-pmac ../images/vmlinux.elf-pmac \ - --add-section=.note=note -R .comment -R .ramdisk - $(OBJCOPY) ../images/zImage.chrp ../images/zImage.chrp \ - -R .comment -R .ramdisk - cp ../images/zImage.chrp ../images/zImage.chrp-rs6k - $(ADDNOTE) ../images/zImage.chrp-rs6k - -zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac zImage.initrd.chrp \ - miboot.initrd.image $(ADDNOTE) note - $(OBJCOPY) ../images/vmlinux.initrd.elf-pmac \ - ../images/vmlinux.initrd.elf-pmac --add-section=.note=note \ - -R .comment - $(OBJCOPY) ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp \ - -R .comment - cp ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp-rs6k - $(ADDNOTE) ../images/zImage.initrd.chrp-rs6k +$(images)/vmlinux.coff: $(obj)/coffboot + $(OBJCOPY) $(OBJCOPY_ARGS) $(obj)/coffboot $@ + $(HACKCOFF) $@ + ln -sf vmlinux.coff $(images)/zImage.pmac -clean: - rm -f note +$(images)/vmlinux.initrd.coff: $(obj)/coffboot.initrd + $(OBJCOPY) $(OBJCOPY_ARGS) $(obj)/coffboot.initrd $@ + $(HACKCOFF) $@ + ln -sf vmlinux.initrd.coff $(images)/zImage.initrd.pmac -include $(TOPDIR)/Rules.make +$(images)/vmlinux.elf-pmac: $(NEWWORLDOBJS) $(LIBS) $(obj)/image.o $(obj)/note + $(LD) $(NEWWORLD_LD_ARGS) -o $@ $(NEWWORLDOBJS) $(LIBS) $(obj)/image.o + $(OBJCOPY) $@ $@ \ + --add-section=.note=$(obj)/note -R .comment -R .ramdisk + +$(images)/vmlinux.initrd.elf-pmac: $(NEWWORLDOBJS) $(LIBS) \ + $(obj)/image-initrd.o $(obj)/note + $(LD) $(NEWWORLD_LD_ARGS) -o $@ $(NEWWORLDOBJS) $(LIBS) \ + $(obj)/image-initrd.o + $(OBJCOPY) $@ $@ \ + --add-section=.note=$(obj)/note -R .comment + +$(images)/zImage.chrp: $(CHRPOBJS) $(obj)/image.o $(LIBS) + $(LD) $(CHRP_LD_ARGS) -o $@ $^ + $(OBJCOPY) $@ $@ -R .comment -R .ramdisk + +$(images)/zImage.initrd.chrp: $(CHRPOBJS) $(obj)/image-initrd.o $(LIBS) + $(LD) $(CHRP_LD_ARGS) -o $@ $^ + $(OBJCOPY) $@ $@ -R .comment + +$(images)/zImage.chrp-rs6k: $(images)/zImage.chrp + cp $(images)/zImage.chrp $@ + $(ADDNOTE) $@ + +$(images)/zImage.initrd.chrp-rs6k: $(images)/zImage.initrd.chrp + cp $(images)/zImage.initrd.chrp $@ + $(ADDNOTE) $@ + +zImage: $(images)/vmlinux.coff $(images)/vmlinux.elf-pmac \ + $(images)/zImage.chrp $(images)/miboot.image + +zImage.initrd: $(images)/vmlinux.initrd.coff $(images)/vmlinux.initrd.elf-pmac\ + $(images)/zImage.initrd.chrp $(images)/miboot.initrd.image + +clean: + rm -f $(obj)/note $(obj)/image.o $(obj)/coffboot $(obj)/coffboot.initrd diff --git a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile index e3617f80113f..b472f2bce21d 100644 --- a/arch/ppc/boot/prep/Makefile +++ b/arch/ppc/boot/prep/Makefile @@ -13,65 +13,79 @@ # modified by Cort (cort@cs.nmt.edu) # +boot: zImage + TFTPIMAGE = /tftpboot/zImage.prep ifeq ($(CONFIG_SMP),y) TFTPIMAGE = $(TFTPBOOT).smp endif -LD_ARGS = -T ../ld.script -Ttext 0x00800000 -Bstatic -boot-y := head.o ../simple/legacy.o misc.o \ - ../common/util.o ../common/string.o \ - ../common/misc-common.o \ - ../common/mpc10x_memory.o +LD_ARGS = -T $(boot)/ld.script -Ttext 0x00800000 -Bstatic OBJCOPY_ARGS = -O elf32-powerpc -LIBS = ../lib/lib.a +LIBS = $(common)/lib.a $(bootlib)/lib.a -boot-$(CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o +boot-y := head.o misc.o boot-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o -EXTRA_TARGETS := $(boot-y) +EXTRA_TARGETS := $(boot-y) ../simple/legacy.o + +include $(TOPDIR)/Rules.make + +boot := arch/ppc/boot +common := $(boot)/common +utils := $(boot)/utils +bootlib := $(boot)/lib +of1275 := $(boot)/of1275 +images := $(boot)/images +simple := $(boot)/simple + +OBJS := $(addprefix $(obj)/,$(boot-y)) $(simple)/legacy.o # Tools -MKPREP := ../utils/mkprep -SIZE := ../utils/size -OFFSET := ../utils/offset +MKPREP := $(utils)/mkprep +SIZE := $(utils)/size +OFFSET := $(utils)/offset # Extra include search dirs -CFLAGS_kbd.o += -I$(TOPDIR)/drivers/char +CFLAGS_kbd.o += -Idrivers/char -all: zImage +zImage: $(images)/zImage.prep +zImage.initrd: $(images)/zImage.initrd.prep -zImage: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o \ - $(MKPREP) +$(obj)/dummy.o: $(common)/dummy.c + $(CC) -c -o $@ $(common)/dummy.c + +$(images)/zImage.prep: $(OBJS) $(LIBS) $(boot)/ld.script \ + $(images)/vmlinux.gz $(obj)/dummy.o $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=.image=../images/vmlinux.gz \ + --add-section=.image=$(images)/vmlinux.gz \ --set-section-flags=.image=contents,alloc,load,readonly,data \ - ../common/dummy.o image.o - $(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr - $(MKPREP) -pbp $@ ../images/$@.prep - rm -f $@ - -zImage.initrd: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz $(MKPREP) \ - ../common/dummy.o + $(obj)/dummy.o $(obj)/image.o + $(LD) $(LD_ARGS) -o $(obj)/zImage $(OBJS) $(obj)/image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $(obj)/zImage $(obj)/zImage \ + -R .comment -R .stab -R .stabstr + $(MKPREP) -pbp $(obj)/zImage $@ + rm -f $(obj)/zImage + +$(images)/zImage.initrd.prep: $(OBJS) $(LIBS) $(boot)/ld.script \ + $(images)/vmlinux.gz $(obj)/dummy.o $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ + --add-section=.ramdisk=$(images)/ramdisk.image.gz \ --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \ - --add-section=.image=../images/vmlinux.gz \ + --add-section=.image=$(images)/vmlinux.gz \ --set-section-flags=.image=contents,alloc,load,readonly,data \ - ../common/dummy.o image.o - $(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr - $(MKPREP) -pbp $@ ../images/$@.prep - rm -f $@ + $(obj)/dummy.o $(obj)/image.o + $(LD) $(LD_ARGS) -o $(obj)/zImage.initrd $(OBJS) $(obj)/image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $(obj)/zImage.initrd $(obj)/zImage.initrd \ + -R .comment -R .stab -R .stabstr + $(MKPREP) -pbp $(obj)/zImage.initrd $@ + rm -f $(obj)/zImage.initrd floppy: zImage - dd if=../images/zImage.prep of=/dev/fd0H1440 bs=64b + dd if=$(images)/zImage.prep of=/dev/fd0H1440 bs=64b znetboot : zImage - cp ../images/zImage.prep $(TFTPIMAGE) + cp $(images)/zImage.prep $(TFTPIMAGE) znetboot.initrd : zImage.initrd - cp ../images/zImage.initrd.prep $(TFTPIMAGE) - -include $(TOPDIR)/Rules.make + cp $(images)/zImage.initrd.prep $(TFTPIMAGE) diff --git a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c index c92348aa6572..7f6680036cea 100644 --- a/arch/ppc/boot/prep/misc.c +++ b/arch/ppc/boot/prep/misc.c @@ -132,11 +132,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, vga_init((unsigned char *)0xC0000000); #endif /* CONFIG_VGA_CONSOLE */ - /* - * Find out how much memory we have. - */ - TotalMemory = get_mem_size(); - /* * Tell the user where we were loaded at and where we were relocated * to for debugging this process. @@ -215,6 +210,29 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, puts("No residual data found.\n"); } + /* First, figure out what kind of host bridge we are on. If it's + * an MPC10x, we can ask it directly how much memory it has. + * Otherwise, see if the residual data has anything. This isn't + * the best way, but it can be the only way. If there's nothing, + * assume 32MB. -- Tom. + */ + /* See what our host bridge is. */ + pci_read_config_32(0x00, 0x00, &pci_viddid); + pci_did = (pci_viddid & 0xffff0000) >> 16; + /* See if we are on an MPC10x. */ + if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA) + && ((pci_did == PCI_DEVICE_ID_MOTOROLA_MPC105) + || (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC106) + || (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC107))) + TotalMemory = get_mem_size(); + /* If it's not, see if we have anything in the residual data. */ + else if (residual && residual->TotalMemory) + TotalMemory = residual->TotalMemory; + /* Fall back to hard-coding 32MB. */ + else + TotalMemory = 32*1024*1024; + + /* assume the chunk below 8M is free */ end_avail = (char *)0x00800000; diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index a659b52cfb16..947d507774d9 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -24,9 +24,11 @@ # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. -# Normally, we use the 'misc-simple.c' file for decompress_kernel and +boot: zImage + +# Normally, we use the 'misc.c' file for decompress_kernel and # whatnot. Sometimes we need to override this however. -MISC := ../common/misc-simple.o +MISC := misc.o ifeq ($(CONFIG_IBM_OPENBIOS),y) ZIMAGE := zImage-TREE ZIMAGEINITRD := zImage.initrd-TREE @@ -38,6 +40,14 @@ ifeq ($(CONFIG_EMBEDDEDBOOT),y) TFTPIMAGE := /tftpboot/zImage.embedded MISC := misc-embedded.o endif +ifeq ($(CONFIG_EBONY),y) +ZIMAGE := zImage-TREE +ZIMAGEINITRD := zImage.initrd-TREE +EXTRA := direct.o +END := ebony +ENTRYPOINT := 0x01000000 +TFTPIMAGE := /tftpboot/zImage.$(END) +endif ifeq ($(CONFIG_EV64260),y) EXTRA := direct.o misc-ev64260.o TFTPIMAGE := /tftpboot/zImage.ev64260 @@ -72,11 +82,8 @@ endif ifeq ($(CONFIG_PPLUS),y) EXTRA := legacy.o endif -ifeq ($(CONFIG_LOPEC),y) -EXTRA += ../common/mpc10x_memory.o -endif ifeq ($(CONFIG_PAL4),y) -EXTRA := direct.o ../common/cpc700_memory.o +EXTRA := direct.o endif ifeq ($(CONFIG_PCORE)$(CONFIG_POWERPMC250),y) ZIMAGE := zImage-STRIPELF @@ -122,21 +129,25 @@ endif # Default linker args. Link at 0x00800000 or 0x00400000 by default, but # allow it to be overridden. ifeq ($(CONFIG_BOOT_LOAD_BOOL),y) -LD_ARGS := -T ../ld.script -Ttext $(CONFIG_BOOT_LOAD) \ - -Bstatic +LD_ARGS := -T $(boot)/ld.script \ + -Ttext $(CONFIG_BOOT_LOAD) -Bstatic else -LD_ARGS = -T ../ld.script -Ttext 0x00800000 -Bstatic -ifeq ($(CONFIG_8260)$(CONFIG_4xx)$(CONFIG_8xx),y) -LD_ARGS := -T ../ld.script -Ttext 0x00400000 -Bstatic +LD_ARGS = -T $(boot)/ld.script \ + -Ttext 0x00800000 -Bstatic +ifeq ($(CONFIG_8260)$(CONFIG_40x)$(CONFIG_8xx),y) +LD_ARGS := -T $(boot)/ld.script -Ttext 0x00400000 \ + -Bstatic +endif +ifeq ($(CONFIG_440),y) +LD_ARGS := -T $(boot)/ld.script -Ttext 0x01000000 \ + -Bstatic endif endif OBJCOPY_ARGS := -O elf32-powerpc -# head.o and ../common/relocate.o must be at the start. -boot-y := head.o ../common/relocate.o $(EXTRA) \ - $(MISC) ../common/misc-common.o \ - ../common/string.o ../common/util.o -boot-$(CONFIG_4xx) += embed_config.o +# head.o and relocate.o must be at the start. +boot-y := head.o relocate.o $(EXTRA) $(MISC) +boot-$(CONFIG_40x) += embed_config.o boot-$(CONFIG_8xx) += embed_config.o boot-$(CONFIG_8260) += embed_config.o boot-$(CONFIG_BSEIP) += iic.o @@ -149,84 +160,97 @@ boot-$(CONFIG_8xx) += m8xx_tty.o boot-$(CONFIG_8260) += m8260_tty.o boot-$(CONFIG_GT64260_CONSOLE) += gt64260_tty.o endif -boot-$(CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o + +boot := arch/ppc/boot +common := $(boot)/common +utils := $(boot)/utils +bootlib := $(boot)/lib +images := $(boot)/images EXTRA_TARGETS := $(boot-y) -LIBS := ../lib/lib.a +LIBS := $(common)/lib.a $(bootlib)/lib.a + +include $(TOPDIR)/Rules.make + +OBJS := $(addprefix $(obj)/,$(boot-y)) # Tools -MKBUGBOOT := ../utils/mkbugboot -MKPREP := ../utils/mkprep -MKTREE := ../utils/mktree +MKBUGBOOT := $(utils)/mkbugboot +MKPREP := $(utils)/mkprep +MKTREE := $(utils)/mktree + +$(obj)/dummy.o: $(common)/dummy.c + $(CC) -c -o $@ $(common)/dummy.c -zvmlinux: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o +$(obj)/zvmlinux: $(OBJS) $(LIBS) $(boot)/ld.script $(images)/vmlinux.gz \ + $(obj)/dummy.o $(OBJCOPY) $(OBJCOPY_ARGS) \ - --add-section=.image=../images/vmlinux.gz \ + --add-section=.image=$(images)/vmlinux.gz \ --set-section-flags=.image=contents,alloc,load,readonly,data \ - ../common/dummy.o image.o - $(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \ - -R .ramdisk -R .sysmap + $(obj)/dummy.o $(obj)/image.o + $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \ + -R .stabstr -R .ramdisk -R .sysmap -zvmlinux.initrd: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz \ - ../common/dummy.o +$(obj)/zvmlinux.initrd: $(OBJS) $(LIBS) $(boot)/ld.script \ + $(images)/vmlinux.gz $(obj)/dummy.o $(OBJCOPY) $(OBJCOPY_ARGS) \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ + --add-section=.ramdisk=$(images)/ramdisk.image.gz \ --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \ - --add-section=.image=../images/vmlinux.gz \ + --add-section=.image=$(images)/vmlinux.gz \ --set-section-flags=.image=contents,alloc,load,readonly,data \ - ../common/dummy.o image.o - $(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \ - -R .sysmap + $(obj)/dummy.o $(obj)/image.o + $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \ + -R .stabstr -R .sysmap # Sort-of dummy rules, that let us format the image we want. -zImage: $(ZIMAGE) zvmlinux - cp -f zvmlinux ../images/zImage.elf - rm -f zvmlinux +zImage: $(images)/$(ZIMAGE) $(obj)/zvmlinux + cp -f $(obj)/zvmlinux $(images)/zImage.elf + rm -f $(obj)/zvmlinux -zImage.initrd: $(ZIMAGEINITRD) zvmlinux.initrd - cp -f zvmlinux.initrd ../images/zImage.initrd.elf - rm -f zvmlinux.initrd +zImage.initrd: $(images)/$(ZIMAGEINITRD) $(obj)/zvmlinux.initrd + cp -f $(obj)/zvmlinux.initrd $(images)/zImage.initrd.elf + rm -f $(obj)/zvmlinux.initrd znetboot: zImage ifneq ($(ZNETBOOT),) - cp ../images/$(ZNETBOOT) $(TFTPIMAGE) + cp $(images)/$(ZNETBOOT) $(TFTPIMAGE) else - cp ../images/zImage.* $(TFTPIMAGE) + cp $(images)/zImage.* $(TFTPIMAGE) endif znetboot.initrd: zImage.initrd ifneq ($(ZNETBOOTRD),) - cp ../images/$(ZNETBOOTRD) $(TFTPIMAGE) + cp $(images)/$(ZNETBOOTRD) $(TFTPIMAGE) else - cp ../images/zImage.* $(TFTPIMAGE) + cp $(images)/zImage.* $(TFTPIMAGE) endif -zImage-STRIPELF: zvmlinux - dd if=zvmlinux of=../images/zImage.$(END) skip=64 bs=1k +$(images)/zImage-STRIPELF: $(obj)/zvmlinux + dd if=$(obj)/zvmlinux of=$(images)/zImage.$(END) skip=64 bs=1k -zImage.initrd-STRIPELF: zvmlinux.initrd - dd if=zvmlinux.initrd of=../images/zImage.initrd.$(END) skip=64 bs=1k +$(images)/zImage.initrd-STRIPELF: $(obj)/zvmlinux.initrd + dd if=$(obj)/zvmlinux.initrd of=$(images)/zImage.initrd.$(END) \ + skip=64 bs=1k -zImage-TREE: zvmlinux - $(MKTREE) zvmlinux ../images/zImage.$(END) $(ENTRYPOINT) +$(images)/zImage-TREE: $(obj)/zvmlinux + $(MKTREE) $(obj)/zvmlinux $(images)/zImage.$(END) $(ENTRYPOINT) -zImage.initrd-TREE: zvmlinux.initrd - $(MKTREE) zvmlinux.initrd ../images/zImage.initrd.$(END) $(ENTRYPOINT) +$(images)/zImage.initrd-TREE: $(obj)/zvmlinux.initrd + $(MKTREE) $(obj)/zvmlinux.initrd $(images)/zImage.initrd.$(END) \ + $(ENTRYPOINT) -zImage-MENF1: zvmlinux - $(MKPREP) -pbp zvmlinux ../images/zImage.menf1 +$(images)/zImage-MENF1: $(obj)/zvmlinux + $(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.menf1 -zImage.initrd-MENF1: zvmlinux.initrd - $(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.menf1 +$(images)/zImage.initrd-MENF1: $(obj)/zvmlinux.initrd + $(MKPREP) -pbp $(obj)/zvmlinux.initrd $(images)/zImage.initrd.menf1 -zImage-PPLUS: zvmlinux $(MKPREP) $(MKBUGBOOT) - $(MKPREP) -pbp zvmlinux ../images/zImage.pplus - $(MKBUGBOOT) zvmlinux ../images/zImage.bugboot +$(images)/zImage-PPLUS: $(obj)/zvmlinux $(MKPREP) $(MKBUGBOOT) + $(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.pplus + $(MKBUGBOOT) $(obj)/zvmlinux $(images)/zImage.bugboot -zImage.initrd-PPLUS: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT) - $(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.pplus - $(MKBUGBOOT) zvmlinux.initrd ../images/zImage.initrd.bugboot - -include $(TOPDIR)/Rules.make +$(images)/zImage.initrd-PPLUS: $(obj)/zvmlinux.initrd $(MKPREP) $(MKBUGBOOT) + $(MKPREP) -pbp $(obj)/zvmlinux.initrd $(images)/zImage.initrd.pplus + $(MKBUGBOOT) $(obj)/zvmlinux.initrd $(images)/zImage.initrd.bugboot diff --git a/arch/ppc/boot/common/misc-simple.c b/arch/ppc/boot/simple/misc.c index 74693dc19a0a..74693dc19a0a 100644 --- a/arch/ppc/boot/common/misc-simple.c +++ b/arch/ppc/boot/simple/misc.c diff --git a/arch/ppc/boot/common/relocate.S b/arch/ppc/boot/simple/relocate.S index 9c49a9c09f80..9c49a9c09f80 100644 --- a/arch/ppc/boot/common/relocate.S +++ b/arch/ppc/boot/simple/relocate.S diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 84f098ad2753..88f8dff3cd99 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -131,6 +131,7 @@ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then Motorola-Sandpoint CONFIG_SANDPOINT \ SBS-Adirondack CONFIG_ADIR \ SBS-K2 CONFIG_K2 \ + SBS-Palomar4 CONFIG_PAL4 \ Synergy-Gemini CONFIG_GEMINI \ Zynx-ZX4500 CONFIG_ZX4500" CHRP/PowerMac/PReP @@ -584,23 +585,31 @@ source lib/Config.in mainmenu_option next_comment comment 'Kernel hacking' -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK -bool 'Include kgdb kernel debugger' CONFIG_KGDB -if [ "$CONFIG_KGDB" = "y" ]; then - choice 'Serial Port' \ - "ttyS0 CONFIG_KGDB_TTYS0 \ - ttyS1 CONFIG_KGDB_TTYS1 \ - ttyS2 CONFIG_KGDB_TTYS2 \ - ttyS3 CONFIG_KGDB_TTYS3" ttyS1 -fi -bool 'Include xmon kernel debugger' CONFIG_XMON -bool 'Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH -if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \ - -o "$CONFIG_BDI_SWITCH" = "y" ]; then - bool 'Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS - if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then - string 'Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb" +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" = "y" ]; then + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + if [ "$CONFIG_HIGHMEM" = "y" ]; then + bool ' Highmem debugging' CONFIG_DEBUG_HIGHMEM + fi + bool ' Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS + bool ' Include kgdb kernel debugger' CONFIG_KGDB + if [ "$CONFIG_KGDB" = "y" ]; then + choice ' Serial Port' \ + "ttyS0 CONFIG_KGDB_TTYS0 \ + ttyS1 CONFIG_KGDB_TTYS1 \ + ttyS2 CONFIG_KGDB_TTYS2 \ + ttyS3 CONFIG_KGDB_TTYS3" ttyS1 + fi + bool ' Include xmon kernel debugger' CONFIG_XMON + bool ' Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH + if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \ + -o "$CONFIG_BDI_SWITCH" = "y" ]; then + bool ' Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS + if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then + string ' Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb" + fi fi fi diff --git a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c index e5db04a84a68..a012f65b3a4e 100644 --- a/arch/ppc/kernel/indirect_pci.c +++ b/arch/ppc/kernel/indirect_pci.c @@ -27,13 +27,18 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, { struct pci_controller *hose = bus->sysdata; volatile unsigned char *cfg_data; + u8 cfg_type = 0; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; + + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; out_be32(hose->cfg_addr, - ((offset & 0xfc) << 24) | (devfn << 16) + (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16) | ((bus->number - hose->bus_offset) << 8) | 0x80); /* * Note: the caller has already checked that offset is @@ -60,13 +65,18 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, { struct pci_controller *hose = bus->sysdata; volatile unsigned char *cfg_data; + u8 cfg_type = 0; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; + out_be32(hose->cfg_addr, - ((offset & 0xfc) << 24) | (devfn << 16) + (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16) | ((bus->number - hose->bus_offset) << 8) | 0x80); /* * Note: the caller has already checked that offset is diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index edd62a0bcaf9..c25bc5824e58 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -752,21 +752,6 @@ _GLOBAL(copy_page) #endif /* CONFIG_PPC_ISERIES */ /* - * Atomic [test&set] exchange - * - * unsigned long xchg_u32(void *ptr, unsigned long val) - * Changes the memory location '*ptr' to be val and returns - * the previous value stored there. - */ -_GLOBAL(xchg_u32) - mr r5,r3 /* Save pointer */ -10: lwarx r3,0,r5 /* Fetch old value & reserve */ - PPC405_ERR77(0,r5) - stwcx. r4,0,r5 /* Update with new value */ - bne- 10b /* Retry if "reservation" (i.e. lock) lost */ - blr - -/* * void atomic_clear_mask(atomic_t mask, atomic_t *addr) * void atomic_set_mask(atomic_t mask, atomic_t *addr); */ diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 78cacd63f7cf..ef796b2915f6 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -30,6 +30,8 @@ #include <linux/pmu.h> #include <asm/prom.h> #include <asm/system.h> +#define __KERNEL_SYSCALLS__ +#include <asm/unistd.h> #include <asm/pci-bridge.h> #include <asm/irq.h> #include <asm/pmac_feature.h> @@ -180,6 +182,10 @@ EXPORT_SYMBOL(consistent_free); EXPORT_SYMBOL(consistent_sync); #endif +EXPORT_SYMBOL(open); +EXPORT_SYMBOL(read); +EXPORT_SYMBOL(lseek); +EXPORT_SYMBOL(close); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); @@ -191,7 +197,6 @@ EXPORT_SYMBOL(flush_dcache_range); EXPORT_SYMBOL(flush_icache_user_range); EXPORT_SYMBOL(flush_icache_page); EXPORT_SYMBOL(flush_dcache_page); -EXPORT_SYMBOL(xchg_u32); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(last_task_used_altivec); EXPORT_SYMBOL(giveup_altivec); diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile index 6019aa16e6d4..1567db763078 100644 --- a/arch/ppc/lib/Makefile +++ b/arch/ppc/lib/Makefile @@ -4,7 +4,7 @@ export-objs := dec_and_lock.o -obj-y := checksum.o string.o strcase.o dec_and_lock.o +obj-y := checksum.o string.o strcase.o dec_and_lock.o div64.o obj-$(CONFIG_SMP) += locks.o diff --git a/arch/ppc/lib/div64.S b/arch/ppc/lib/div64.S new file mode 100644 index 000000000000..3527569e9926 --- /dev/null +++ b/arch/ppc/lib/div64.S @@ -0,0 +1,58 @@ +/* + * Divide a 64-bit unsigned number by a 32-bit unsigned number. + * This routine assumes that the top 32 bits of the dividend are + * non-zero to start with. + * On entry, r3 points to the dividend, which get overwritten with + * the 64-bit quotient, and r4 contains the divisor. + * On exit, r3 contains the remainder. + * + * Copyright (C) 2002 Paul Mackerras, IBM Corp. + * + * 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. + */ +#include <asm/ppc_asm.h> +#include <asm/processor.h> + +_GLOBAL(__div64_32) + lwz r5,0(r3) # get the dividend into r5/r6 + lwz r6,4(r3) + cmplw r5,r4 + li r7,0 + li r8,0 + blt 1f + divwu r7,r5,r4 # if dividend.hi >= divisor, + mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor + subf. r5,r0,r5 # dividend.hi %= divisor + beq 3f +1: mr r11,r5 # here dividend.hi != 0 + andis. r0,r5,0xc000 + bne 2f + cntlzw r0,r5 # we are shifting the dividend right + li r10,-1 # to make it < 2^32, and shifting + srw r10,r10,r0 # the divisor right the same amount, + add r9,r4,r10 # rounding up (so the estimate cannot + andc r11,r6,r10 # ever be too large, only too small) + andc r9,r9,r10 + or r11,r5,r11 + rotlw r9,r9,r0 + rotlw r11,r11,r0 + divwu r11,r11,r9 # then we divide the shifted quantities +2: mullw r10,r11,r4 # to get an estimate of the quotient, + mulhwu r9,r11,r4 # multiply the estimate by the divisor, + subfc r6,r10,r6 # take the product from the divisor, + add r8,r8,r11 # and add the estimate to the accumulated + subfe. r5,r9,r5 # quotient + bne 1b +3: cmplw r6,r4 + blt 4f + divwu r0,r6,r4 # perform the remaining 32-bit division + mullw r10,r0,r4 # and get the remainder + add r8,r8,r0 + subf r6,r10,r6 +4: stw r7,0(r3) # return the quotient in *r3 + stw r8,4(r3) + mr r3,r6 # return the remainder in r3 + blr diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index 2c2f72c81774..b90f75b8b0ab 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_LOPEC) += lopec_setup.o lopec_pci.o obj-$(CONFIG_MCPN765) += mcpn765_setup.o mcpn765_pci.o obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o obj-$(CONFIG_MVME5100) += mvme5100_setup.o mvme5100_pci.o +obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o cpc700_pic.o obj-$(CONFIG_PCORE) += pcore_setup.o pcore_pci.o obj-$(CONFIG_POWERPMC250) += powerpmc250.o obj-$(CONFIG_PPLUS) += pplus_pci.o pplus_setup.o diff --git a/arch/ppc/platforms/pal4.h b/arch/ppc/platforms/pal4.h new file mode 100644 index 000000000000..ab111ff83ad6 --- /dev/null +++ b/arch/ppc/platforms/pal4.h @@ -0,0 +1,44 @@ +/* + * arch/ppc/platforms/pal4.h + * + * Definitions for SBS Palomar IV board + * + * Author: Dan Cox + * + * Copyright 2002 MontaVista Software Inc. + * + * 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. + */ + +#ifndef __PPC_PLATFORMS_PAL4_H +#define __PPC_PLATFORMS_PAL4_H + +#define PAL4_NVRAM 0xfffc0000 +#define PAL4_NVRAM_SIZE 0x8000 + +#define PAL4_DRAM 0xfff80000 +#define PAL4_DRAM_BR_MASK 0xc0 +#define PAL4_DRAM_BR_SHIFT 6 +#define PAL4_DRAM_RESET 0x10 +#define PAL4_DRAM_EREADY 0x40 + +#define PAL4_MISC 0xfff80004 +#define PAL4_MISC_FB_MASK 0xc0 +#define PAL4_MISC_FLASH 0x20 /* StratFlash mapping: 1->0xff80, 0->0xfff0 */ +#define PAL4_MISC_MISC 0x08 +#define PAL4_MISC_BITF 0x02 +#define PAL4_MISC_NVKS 0x01 + +#define PAL4_L2 0xfff80008 +#define PAL4_L2_MASK 0x07 + +#define PAL4_PLDR 0xfff8000c + +/* Only two Ethernet devices on the board... */ +#define PAL4_ETH 31 +#define PAL4_INTA 20 + +#endif /* __PPC_PLATFORMS_PAL4_H */ diff --git a/arch/ppc/platforms/pal4_pci.c b/arch/ppc/platforms/pal4_pci.c new file mode 100644 index 000000000000..372e846f3e54 --- /dev/null +++ b/arch/ppc/platforms/pal4_pci.c @@ -0,0 +1,78 @@ +/* + * arch/ppc/platforms/pal4_pci.c + * + * PCI support for SBS Palomar IV + * + * Author: Dan Cox + * + * Copyright 2002 MontaVista Software Inc. + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/byteorder.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/pci-bridge.h> +#include <asm/uaccess.h> + +#include "cpc700.h" +#include "pal4.h" + +/* not much to this.... */ +static inline int __init +pal4_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + if (idsel == 9) + return PAL4_ETH; + else + return PAL4_INTA + (idsel - 3); +} + +void __init +pal4_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = 0; + + /* Could snatch these from the CPC700.... */ + pci_init_resource(&hose->io_resource, + 0x0, + 0x03ffffff, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + 0x90000000, + 0x9fffffff, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = 0x00800000; + hose->io_space.end = 0x03ffffff; + hose->mem_space.start = 0x90000000; + hose->mem_space.end = 0x9fffffff; + hose->io_base_virt = (void *) 0xf8000000; + + setup_indirect_pci(hose, CPC700_PCI_CONFIG_ADDR, + CPC700_PCI_CONFIG_DATA); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = pal4_map_irq; +} diff --git a/arch/ppc/platforms/pal4_serial.h b/arch/ppc/platforms/pal4_serial.h new file mode 100644 index 000000000000..452486c3d226 --- /dev/null +++ b/arch/ppc/platforms/pal4_serial.h @@ -0,0 +1,41 @@ +/* + * arch/ppc/platforms/pal4_serial.h + * + * Definitions for SBS PalomarIV serial support + * + * Author: Dan Cox + * + * Copyright 2002 MontaVista Software Inc. + * + * 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. + */ + +#ifndef __PPC_PAL4_SERIAL_H +#define __PPC_PAL4_SERIAL_H + +#define CPC700_SERIAL_1 0xff600300 +#define CPC700_SERIAL_2 0xff600400 + +#define RS_TABLE_SIZE 2 +#define BASE_BAUD (33333333 / 4 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define SERIAL_PORT_DFNS \ + {0, BASE_BAUD, CPC700_SERIAL_1, 3, STD_COM_FLAGS, \ + iomem_base: (unsigned char *) CPC700_SERIAL_1, \ + io_type: SERIAL_IO_MEM}, /* ttyS0 */ \ + {0, BASE_BAUD, CPC700_SERIAL_2, 4, STD_COM_FLAGS, \ + iomem_base: (unsigned char *) CPC700_SERIAL_2, \ + io_type: SERIAL_IO_MEM} + +#endif diff --git a/arch/ppc/platforms/pal4_setup.c b/arch/ppc/platforms/pal4_setup.c new file mode 100644 index 000000000000..f4ad2252da2f --- /dev/null +++ b/arch/ppc/platforms/pal4_setup.c @@ -0,0 +1,176 @@ +/* + * arch/ppc/platforms/pal4_setup.c + * + * Board setup routines for the SBS PalomarIV. + * + * Author: Dan Cox + * + * Copyright 2002 MontaVista Software Inc. + * + * 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. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/time.h> +#include <linux/irq.h> +#include <linux/kdev_t.h> +#include <linux/blk.h> +#include <linux/console.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/io.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> + +#include "cpc700.h" +#include "pal4.h" + +extern void pal4_find_bridges(void); + +unsigned int cpc700_irq_assigns[][2] = { + {1, 1}, /* IRQ 0: ECC correctable error */ + {1, 1}, /* IRQ 1: PCI write to memory range */ + {0, 1}, /* IRQ 2: PCI write to command register */ + {0, 1}, /* IRQ 3: UART 0 */ + {0, 1}, /* IRQ 4: UART 1 */ + {0, 1}, /* IRQ 5: ICC 0 */ + {0, 1}, /* IRQ 6: ICC 1 */ + {0, 1}, /* IRQ 7: GPT compare 0 */ + {0, 1}, /* IRQ 8: GPT compare 1 */ + {0, 1}, /* IRQ 9: GPT compare 2 */ + {0, 1}, /* IRQ 10: GPT compare 3 */ + {0, 1}, /* IRQ 11: GPT compare 4 */ + {0, 1}, /* IRQ 12: GPT capture 0 */ + {0, 1}, /* IRQ 13: GPT capture 1 */ + {0, 1}, /* IRQ 14: GPT capture 2 */ + {0, 1}, /* IRQ 15: GPT capture 3 */ + {0, 1}, /* IRQ 16: GPT capture 4 */ + {0, 0}, /* IRQ 17: reserved */ + {0, 0}, /* IRQ 18: reserved */ + {0, 0}, /* IRQ 19: reserved */ + {0, 0}, /* IRQ 20: reserved */ + {0, 1}, /* IRQ 21: Ethernet */ + {0, 0}, /* IRQ 22: reserved */ + {0, 0}, /* IRQ 23: reserved */ + {0, 0}, /* IRQ 24: resreved */ + {0, 0}, /* IRQ 25: reserved */ + {0, 0}, /* IRQ 26: reserved */ + {0, 0}, /* IRQ 27: reserved */ + {0, 0}, /* IRQ 28: reserved */ + {0, 0}, /* IRQ 29: reserved */ + {0, 0}, /* IRQ 30: reserved */ + {0, 0}, /* IRQ 31: reserved */ +}; + +static int +pal4_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "board\t\t: SBS Palomar IV\n"); + + return 0; +} + +static void +pal4_restart(char *cmd) +{ + __cli(); + __asm__ __volatile__("lis 3,0xfff0\n \ + ori 3,3,0x100\n \ + mtspr 26,3\n \ + li 3,0\n \ + mtspr 27,3\n \ + rfi"); + + for(;;); +} + +static void +pal4_power_off(void) +{ + __cli(); + for(;;); +} + +static void +pal4_halt(void) +{ + pal4_power_off(); +} + +TODC_ALLOC(); + +static void __init +pal4_setup_arch(void) +{ + unsigned long l2; + + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(PAL4_NVRAM, PAL4_NVRAM_SIZE), 8); + + pal4_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = Root_NFS; + + /* The L2 gets disabled in the bootloader, but all the proper + bits should be present from the fw, so just re-enable it */ + l2 = _get_L2CR(); + if (!(l2 & L2CR_L2E)) { + /* presume that it was initially set if the size is + still present. */ + if (l2 ^ L2CR_L2SIZ_MASK) + _set_L2CR(l2 | L2CR_L2E); + else + printk("L2 not set by firmware; left disabled.\n"); + } +} + +static void __init +pal4_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + isa_io_base = 0 /*PAL4_ISA_IO_BASE*/; + pci_dram_offset = 0 /*PAL4_PCI_SYS_MEM_BASE*/; + + ppc_md.setup_arch = pal4_setup_arch; + ppc_md.show_cpuinfo = pal4_show_cpuinfo; + + ppc_md.setup_io_mappings = pal4_map_io; + + ppc_md.init_IRQ = cpc700_init_IRQ; + ppc_md.get_irq = cpc700_get_irq; + + ppc_md.restart = pal4_restart; + ppc_md.halt = pal4_halt; + ppc_md.power_off = pal4_power_off; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +} + diff --git a/arch/ppc/platforms/pcore_setup.c b/arch/ppc/platforms/pcore_setup.c index 14a01e866b07..06dcf811447e 100644 --- a/arch/ppc/platforms/pcore_setup.c +++ b/arch/ppc/platforms/pcore_setup.c @@ -168,13 +168,7 @@ pcore_init_IRQ(void) for ( i = 0 ; i < 16 ; i++ ) irq_desc[i].handler = &i8259_pic; - i8259_init(NULL); -} - -static int -pcore_get_irq(struct pt_regs *regs) -{ - return i8259_poll(); + i8259_init(0); } /* @@ -184,22 +178,16 @@ static __inline__ void pcore_set_bat(void) { unsigned long bat3u, bat3l; - static int mapping_set = 0; - - if (!mapping_set) { - __asm__ __volatile__( - " lis %0,0xf000\n \ - ori %1,%0,0x002a\n \ - ori %0,%0,0x1ffe\n \ - mtspr 0x21e,%0\n \ - mtspr 0x21f,%1\n \ - isync\n \ - sync " - : "=r" (bat3u), "=r" (bat3l)); - - mapping_set = 1; - } - return; + + __asm__ __volatile__( + " lis %0,0xf000\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x1ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + : "=r" (bat3u), "=r" (bat3l)); } static unsigned long __init @@ -233,7 +221,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = pcore_setup_arch; ppc_md.show_cpuinfo = pcore_show_cpuinfo; ppc_md.init_IRQ = pcore_init_IRQ; - ppc_md.get_irq = pcore_get_irq; + ppc_md.get_irq = i8259_irq; ppc_md.find_end_of_memory = pcore_find_end_of_memory; ppc_md.setup_io_mappings = pcore_map_io; diff --git a/arch/ppc/vmlinux.lds.S b/arch/ppc/vmlinux.lds.S index cc8b249ddd13..a934f99f3274 100644 --- a/arch/ppc/vmlinux.lds.S +++ b/arch/ppc/vmlinux.lds.S @@ -87,9 +87,9 @@ SECTIONS . = ALIGN(4096); __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { - *(.data.init); + .init.text : { *(.init.text) } + .init.data : { + *(.init.data); __vtop_table_begin = .; *(.vtop_fixup); __vtop_table_end = .; @@ -99,7 +99,7 @@ SECTIONS } . = ALIGN(16); __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __initcall_start = .; .initcall.init : { @@ -121,29 +121,29 @@ SECTIONS . = ALIGN(4096); __pmac_begin = .; - .text.pmac : { *(.text.pmac) } - .data.pmac : { *(.data.pmac) } + .pmac.text : { *(.pmac.text) } + .pmac.data : { *(.pmac.data) } . = ALIGN(4096); __pmac_end = .; . = ALIGN(4096); __prep_begin = .; - .text.prep : { *(.text.prep) } - .data.prep : { *(.data.prep) } + .prep.text : { *(.prep.text) } + .prep.data : { *(.prep.data) } . = ALIGN(4096); __prep_end = .; . = ALIGN(4096); __chrp_begin = .; - .text.chrp : { *(.text.chrp) } - .data.chrp : { *(.data.chrp) } + .chrp.text : { *(.chrp.text) } + .chrp.data : { *(.chrp.data) } . = ALIGN(4096); __chrp_end = .; . = ALIGN(4096); __openfirmware_begin = .; - .text.openfirmware : { *(.text.openfirmware) } - .data.openfirmware : { *(.data.openfirmware) } + .openfirmware.text : { *(.openfirmware.text) } + .openfirmware.data : { *(.openfirmware.data) } . = ALIGN(4096); __openfirmware_end = .; diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 4da5a00d54d3..045ddbe964f0 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -333,12 +333,15 @@ static void *do_smb_super_data_conv(void *raw_data) struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = s32->mounted_uid; s->uid = s32->uid; s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff --git a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c index 4d52a49cccf8..8490920b29b3 100644 --- a/arch/s390x/kernel/linux32.c +++ b/arch/s390x/kernel/linux32.c @@ -1563,12 +1563,15 @@ static void *do_smb_super_data_conv(void *raw_data) struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = low2highuid(s32->mounted_uid); s->uid = low2highuid(s32->uid); s->gid = low2highgid(s32->gid); s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 9aab951ad642..24dcb2ca05b8 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.49 2001/07/27 09:42:22 davem Exp $ +# # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -47,16 +47,24 @@ image: vmlinux $(MAKE) -C arch/sparc/boot image archclean: + rm -f arch/sparc/kernel/include rm -f $(TOPDIR)/vmlinux.aout -$(MAKE) -C arch/sparc/boot clean archmrproper: rm -f $(TOPDIR)/include/asm-sparc/asm_offsets.h -prepare: check_asm +prepare: include/asm-$(ARCH)/asm_offsets.h + +arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/asm_offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s + @$(generate-asm-offsets.h) < $< > $@ -check_asm: include/linux/version.h include/asm include/config/MARKER - $(MAKE) -C arch/sparc/kernel check_asm +include/asm-$(ARCH)/asm_offsets.h: include/asm-$(ARCH)/asm_offsets.h.tmp + @echo -n ' Generating $@' + @$(update-if-changed) tftpboot.img: $(MAKE) -C arch/sparc/boot tftpboot.img diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index dbe551f3cd63..ebc035a23e29 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -23,7 +23,7 @@ clean: rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s image BTOBJS := $(HEAD) $(init-y) -BTLIBS := $(core-y) $(LIBS) $(drivers-y) $(net-y) +BTLIBS := $(core-y) $(libs-y) $(drivers-y) $(net-y) # Actual linking image: btfix.o diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 69bab606ea3f..6adecbe49035 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -28,95 +28,3 @@ obj-y += sys_sunos.o sunos_ioctl.o endif include $(TOPDIR)/Rules.make - -HPATH := $(objtree)/include - -check_asm: FORCE - @if [ ! -r $(HPATH)/asm/asm_offsets.h ] ; then \ - touch $(HPATH)/asm/asm_offsets.h ; \ - fi - @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h - @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h - @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#include <linux/config.h>" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#ifndef CONFIG_SMP" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#include <linux/config.h>" > tmp.c - @echo "#undef CONFIG_SMP" >> tmp.c - @echo "#include <linux/sched.h>" >> tmp.c - $(CPP) $(CPPFLAGS) tmp.c -o tmp.i - @echo "/* Automatically generated. Do not edit. */" > check_asm_data.c - @echo "#include <linux/config.h>" >> check_asm_data.c - @echo "#undef CONFIG_SMP" >> check_asm_data.c - @echo "#include <linux/sched.h>" >> check_asm_data.c - @echo "unsigned int check_asm_data[] = {" >> check_asm_data.c - $(SH) ./check_asm.sh -data task tmp.i check_asm_data.c - $(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c - $(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c - @echo '};' >> check_asm_data.c - $(CC) $(CFLAGS) -S -o check_asm_data.s check_asm_data.c - @echo "/* Automatically generated. Do not edit. */" > check_asm.c - @echo 'extern int printf(const char *fmt, ...);' >>check_asm.c - @echo "unsigned int check_asm_data[] = {" >> check_asm.c - $(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c - @echo "};" >> check_asm.c - @echo 'int main(void) {' >> check_asm.c - @echo 'int i = 0;' >> check_asm.c - $(SH) ./check_asm.sh -printf task tmp.i check_asm.c - $(SH) ./check_asm.sh -printf mm tmp.i check_asm.c - $(SH) ./check_asm.sh -printf thread tmp.i check_asm.c - @echo 'return 0; }' >> check_asm.c - @rm -f tmp.[ci] check_asm_data.[cs] - $(HOSTCC) -o check_asm check_asm.c - ./check_asm >> asm_offsets.h - @rm -f check_asm check_asm.c - @echo "" >> asm_offsets.h - @echo "#else /* CONFIG_SMP */" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#include <linux/config.h>" > tmp.c - @echo "#undef CONFIG_SMP" >> tmp.c - @echo "#define CONFIG_SMP 1" >> tmp.c - @echo "#include <linux/sched.h>" >> tmp.c - $(CPP) $(CPPFLAGS) tmp.c -o tmp.i - @echo "/* Automatically generated. Do not edit. */" > check_asm_data.c - @echo "#include <linux/config.h>" >> check_asm_data.c - @echo "#undef CONFIG_SMP" >> check_asm_data.c - @echo "#define CONFIG_SMP 1" >> check_asm_data.c - @echo "#include <linux/sched.h>" >> check_asm_data.c - @echo "unsigned int check_asm_data[] = {" >> check_asm_data.c - $(SH) ./check_asm.sh -data task tmp.i check_asm_data.c - $(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c - $(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c - @echo '};' >> check_asm_data.c - $(CC) $(CFLAGS) -S -o check_asm_data.s check_asm_data.c - @echo "/* Automatically generated. Do not edit. */" > check_asm.c - @echo 'extern int printf(const char *fmt, ...);' >>check_asm.c - @echo "unsigned int check_asm_data[] = {" >> check_asm.c - $(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c - @echo "};" >> check_asm.c - @echo 'int main(void) {' >> check_asm.c - @echo 'int i = 0;' >> check_asm.c - $(SH) ./check_asm.sh -printf task tmp.i check_asm.c - $(SH) ./check_asm.sh -printf mm tmp.i check_asm.c - $(SH) ./check_asm.sh -printf thread tmp.i check_asm.c - @echo 'return 0; }' >> check_asm.c - @rm -f tmp.[ci] check_asm_data.[cs] - $(HOSTCC) -o check_asm check_asm.c - ./check_asm >> asm_offsets.h - @rm -f check_asm check_asm.c - @echo "" >> asm_offsets.h - @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h - @if test -r $(HPATH)/asm/asm_offsets.h; then \ - if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \ - echo $(HPATH)/asm/asm_offsets.h is unchanged; \ - rm -f asm_offsets.h; \ - else \ - mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \ - fi; \ - else \ - mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \ - fi diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c new file mode 100644 index 000000000000..fa2e8a95ca45 --- /dev/null +++ b/arch/sparc/kernel/asm-offsets.c @@ -0,0 +1,53 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * On sparc, thread_info data is static and TI_XXX offsets are computed by hand. + */ + +#include <linux/config.h> +#include <linux/sched.h> +// #include <linux/mm.h> + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int foo(void) +{ + DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread)); + DEFINE(AOFF_task_ptrace, offsetof(struct task_struct, ptrace)); + DEFINE(AOFF_task_blocked, offsetof(struct task_struct, blocked)); + BLANK(); + /* XXX This is the stuff for sclow.S, kill it. */ + DEFINE(AOFF_task_pid, offsetof(struct task_struct, pid)); + DEFINE(AOFF_task_uid, offsetof(struct task_struct, uid)); + DEFINE(AOFF_task_gid, offsetof(struct task_struct, gid)); + DEFINE(AOFF_task_euid, offsetof(struct task_struct, euid)); + DEFINE(AOFF_task_egid, offsetof(struct task_struct, egid)); + /* DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); */ + DEFINE(ASIZ_task_uid, sizeof(current->uid)); + DEFINE(ASIZ_task_gid, sizeof(current->gid)); + DEFINE(ASIZ_task_euid, sizeof(current->euid)); + DEFINE(ASIZ_task_egid, sizeof(current->egid)); + BLANK(); + DEFINE(AOFF_thread_fork_kpsr, + offsetof(struct thread_struct, fork_kpsr)); + BLANK(); + DEFINE(AOFF_thread_w_saved, offsetof(struct thread_struct, w_saved)); + DEFINE(AOFF_thread_rwbuf_stkptrs, + offsetof(struct thread_struct, rwbuf_stkptrs)); + DEFINE(AOFF_thread_reg_window, + offsetof(struct thread_struct, reg_window)); + BLANK(); + DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context)); + + /* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */ + return 0; +} diff --git a/arch/sparc/kernel/check_asm.sh b/arch/sparc/kernel/check_asm.sh deleted file mode 100755 index a4d5e6d95708..000000000000 --- a/arch/sparc/kernel/check_asm.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -case $1 in - -printf) - sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ -/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0 0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0 0x%08x\\n", check_asm_data[i++]);/' >> $4 - echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4 - ;; - -data) - sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ -/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/ ((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)), sizeof(((struct '$2'_struct *)0)->\0),/' >> $4 - echo " sizeof(struct $2_struct)," >> $4 - ;; - -ints) - sed -n -e '/check_asm_data:/,/\.size/p' <$2 | sed -e 's/check_asm_data://' -e 's/\.size.*//' -e 's/\.ident.*//' -e 's/\.global.*//' -e 's/\.long[ ]\([0-9]*\)/\1,/' >>$3 ;; - *) - exit 1 - ;; -esac -exit 0 diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 0e3396ed5cfd..2e6d220cd8f0 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -17,6 +17,7 @@ #include <asm/kgdb.h> #include <asm/contregs.h> #include <asm/ptrace.h> +#include <asm/asm_offsets.h> #include <asm/psr.h> #include <asm/cprefix.h> #include <asm/vaddrs.h> diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S index 4a98b3ca42b9..fc4979449d07 100644 --- a/arch/sparc/kernel/etrap.S +++ b/arch/sparc/kernel/etrap.S @@ -12,6 +12,7 @@ #include <asm/page.h> #include <asm/psr.h> #include <asm/ptrace.h> +#include <asm/asm_offsets.h> #include <asm/winmacro.h> #include <asm/asmmacro.h> #include <asm/thread_info.h> diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index 814be2e57645..19251358f3d9 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S @@ -7,6 +7,7 @@ #include <asm/cprefix.h> #include <asm/page.h> #include <asm/ptrace.h> +#include <asm/asm_offsets.h> #include <asm/psr.h> #include <asm/asi.h> #include <asm/smp.h> diff --git a/arch/sparc/kernel/sclow.S b/arch/sparc/kernel/sclow.S index 1ad511f4f4dc..594783abc295 100644 --- a/arch/sparc/kernel/sclow.S +++ b/arch/sparc/kernel/sclow.S @@ -36,18 +36,6 @@ LABEL(sunosnop): CC_AND_RETT -#if 0 -/* Not SMP safe */ - .globl LABEL(sunosgetpid) -LABEL(sunosgetpid): - LOAD_CURRENT(l4, l5) - ld [%l4 + TI_TASK], %l4 - ld [%l4 + AOFF_task_pid], %i0 - ld [%l4 + AOFF_task_p_opptr], %l5 - ld [%l5 + AOFF_task_pid], %i1 - CC_AND_RETT -#endif - #if (ASIZ_task_uid == 2 && ASIZ_task_euid == 2) .globl LABEL(sunosgetuid) LABEL(sunosgetuid): diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S index fb107aadadd3..f7aff720df94 100644 --- a/arch/sparc/kernel/wof.S +++ b/arch/sparc/kernel/wof.S @@ -8,6 +8,7 @@ #include <asm/contregs.h> #include <asm/page.h> #include <asm/ptrace.h> +#include <asm/asm_offsets.h> #include <asm/psr.h> #include <asm/smp.h> #include <asm/asi.h> diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S index 7b924013a396..221f61e69613 100644 --- a/arch/sparc/kernel/wuf.S +++ b/arch/sparc/kernel/wuf.S @@ -8,6 +8,7 @@ #include <asm/contregs.h> #include <asm/page.h> #include <asm/ptrace.h> +#include <asm/asm_offsets.h> #include <asm/psr.h> #include <asm/smp.h> #include <asm/asi.h> diff --git a/arch/sparc/vmlinux.lds.S b/arch/sparc/vmlinux.lds.S index f02a3045400c..6403f5398d5d 100644 --- a/arch/sparc/vmlinux.lds.S +++ b/arch/sparc/vmlinux.lds.S @@ -38,12 +38,12 @@ SECTIONS . = ALIGN(4096); __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { *(.init.text) } __init_text_end = .; - .data.init : { *(.data.init) } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup_init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __initcall_start = .; .initcall.init : { diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 9b62bbe3a655..388b557b015c 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1582,6 +1582,8 @@ static void *do_smb_super_data_conv(void *raw_data) struct smb_mount_data news, *s = &news; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = low2highuid(s32->mounted_uid); s->uid = low2highuid(s32->uid); @@ -1589,6 +1591,7 @@ static void *do_smb_super_data_conv(void *raw_data) s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; memcpy(raw_data, s, sizeof(struct smb_mount_data)); +out: return raw_data; } diff --git a/arch/sparc64/vmlinux.lds.S b/arch/sparc64/vmlinux.lds.S index dd256448c7b2..50baaf6f3c4c 100644 --- a/arch/sparc64/vmlinux.lds.S +++ b/arch/sparc64/vmlinux.lds.S @@ -40,11 +40,11 @@ SECTIONS __stop___kallsyms = .; . = ALIGN(8192); __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .init.text : { *(.init.text) } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup_init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __initcall_start = .; .initcall.init : { diff --git a/arch/um/Makefile b/arch/um/Makefile index f4265f94529b..dd28bfdb90b9 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -70,7 +70,7 @@ LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o vmlinux: $(ARCH_DIR)/main.o -$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S +$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S scripts FORCE $(call if_changed_dep,as_s_S) AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 68c8e1ca81d1..f961e21e68fb 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -51,22 +51,19 @@ static int ubd_open(struct inode * inode, struct file * filp); static int ubd_release(struct inode * inode, struct file * file); static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); -static int ubd_revalidate(kdev_t rdev); +static int ubd_revalidate(struct gendisk *disk); #define MAX_DEV (8) -#define MAX_MINOR (MAX_DEV << UBD_SHIFT) - -#define DEVICE_NR(n) (minor(n) >> UBD_SHIFT) static struct block_device_operations ubd_blops = { - .open = ubd_open, - .release = ubd_release, - .ioctl = ubd_ioctl, - .revalidate = ubd_revalidate, + .open = ubd_open, + .release = ubd_release, + .ioctl = ubd_ioctl, + .revalidate_disk= ubd_revalidate, }; /* Protected by the queue_lock */ -static request_queue_t *ubd_queue; +static request_queue_t ubd_queue; /* Protected by ubd_lock */ static int fake_major = 0; @@ -347,30 +344,31 @@ int thread_fd = -1; */ int intr_count = 0; -static void ubd_finish(int error) +static void ubd_finish(struct request *req, int error) { int nsect; if(error){ spin_lock(&ubd_io_lock); - end_request(CURRENT, 0); + end_request(req, 0); spin_unlock(&ubd_io_lock); return; } - nsect = CURRENT->current_nr_sectors; - CURRENT->sector += nsect; - CURRENT->buffer += nsect << 9; - CURRENT->errors = 0; - CURRENT->nr_sectors -= nsect; - CURRENT->current_nr_sectors = 0; + nsect = req->current_nr_sectors; + req->sector += nsect; + req->buffer += nsect << 9; + req->errors = 0; + req->nr_sectors -= nsect; + req->current_nr_sectors = 0; spin_lock(&ubd_io_lock); - end_request(CURRENT, 1); + end_request(req, 1); spin_unlock(&ubd_io_lock); } static void ubd_handler(void) { struct io_thread_req req; + struct request *rq = elv_next_request(&ubd_queue); int n; do_ubd = NULL; @@ -380,18 +378,18 @@ static void ubd_handler(void) printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " "errno = %d\n", os_getpid(), -n); spin_lock(&ubd_io_lock); - end_request(CURRENT, 0); + end_request(rq, 0); spin_unlock(&ubd_io_lock); return; } - if((req.offset != ((__u64) (CURRENT->sector)) << 9) || - (req.length != (CURRENT->current_nr_sectors) << 9)) + if((req.offset != ((__u64) (rq->sector)) << 9) || + (req.length != (rq->current_nr_sectors) << 9)) panic("I/O op mismatch"); - ubd_finish(req.error); + ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); - do_ubd_request(ubd_queue); + do_ubd_request(&ubd_queue); } static void ubd_intr(int irq, void *dev, struct pt_regs *unused) @@ -483,9 +481,13 @@ static int ubd_add(int n) goto out_unregister; ubd_dev[n].fake = fake; + fake_disk->private_data = &ubd_dev[n]; + fake_disk->queue = &ubd_queue; add_disk(fake_disk); } + disk->private_data = &ubd_dev[n]; + disk->queue = &ubd_queue; add_disk(disk); make_ide_entries(disk->disk_name); return(0); @@ -574,11 +576,6 @@ static int ubd_mc_init(void) __initcall(ubd_mc_init); -static request_queue_t *ubd_get_queue(kdev_t device) -{ - return(ubd_queue); -} - int ubd_init(void) { int i; @@ -588,9 +585,8 @@ int ubd_init(void) printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR); return -1; } - ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(ubd_queue, do_ubd_request, &ubd_io_lock); - elevator_init(ubd_queue, &elevator_noop); + blk_init_queue(&ubd_queue, do_ubd_request, &ubd_io_lock); + elevator_init(&ubd_queue, &elevator_noop); if(fake_major != 0){ char name[sizeof("ubd_nnn\0")]; @@ -601,7 +597,6 @@ int ubd_init(void) fake_major); return -1; } - blk_dev[fake_major].queue = ubd_get_queue; } for(i = 0; i < MAX_DEV; i++) ubd_add(i); @@ -698,8 +693,8 @@ static int ubd_open_dev(struct ubd *dev) static int ubd_open(struct inode *inode, struct file *filp) { - int n = DEVICE_NR(inode->i_rdev); - struct ubd *dev = &ubd_dev[n]; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ubd *dev = disk->private_data; int err; if(dev->is_dir == 1) goto out; @@ -709,8 +704,8 @@ static int ubd_open(struct inode *inode, struct file *filp) err = ubd_open_dev(dev); if(err){ - printk(KERN_ERR "ubd%d: Can't open \"%s\": " - "errno = %d\n", n, dev->file, -err); + printk(KERN_ERR "%s: Can't open \"%s\": " + "errno = %d\n", disk->disk_name, dev->file, -err); goto out; } } @@ -725,9 +720,10 @@ static int ubd_open(struct inode *inode, struct file *filp) static int ubd_release(struct inode * inode, struct file * file) { - int n = DEVICE_NR(inode->i_rdev); - if(--ubd_dev[n].count == 0) - ubd_close(&ubd_dev[n]); + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ubd *dev = disk->private_data; + if(dev->count == 0) + ubd_close(dev); return(0); } @@ -771,15 +767,13 @@ void cowify_req(struct io_thread_req *req, struct ubd *dev) static int prepare_request(struct request *req, struct io_thread_req *io_req) { - struct ubd *dev; + struct gendisk *disk = req->rq_disk; + struct ubd *dev = disk->private_data; __u64 block; - int nsect, min, n; + int nsect; - if(req->rq_status == RQ_INACTIVE) return(1); + if (req->rq_status == RQ_INACTIVE) return(1); - min = minor(req->rq_dev); - n = min >> UBD_SHIFT; - dev = &ubd_dev[n]; if(dev->is_dir){ strcpy(req->buffer, "HOSTFS:"); strcat(req->buffer, dev->file); @@ -790,7 +784,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) } if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ - printk("Write attempted on readonly ubd device %d\n", n); + printk("Write attempted on readonly ubd device %s\n", disk->disk_name); spin_lock(&ubd_io_lock); end_request(req, 0); spin_unlock(&ubd_io_lock); @@ -829,7 +823,7 @@ static void do_ubd_request(request_queue_t *q) err = prepare_request(req, &io_req); if(!err){ do_io(&io_req); - ubd_finish(io_req.error); + ubd_finish(req, io_req.error); } } } @@ -852,21 +846,15 @@ static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { struct hd_geometry *loc = (struct hd_geometry *) arg; + struct ubd *dev = inode->i_bdev->bd_disk->private_data; + int err; struct ubd *dev; - int n, min, err; struct hd_driveid ubd_id = { .cyls = 0, .heads = 128, .sectors = 32, }; - - if(!inode) return(-EINVAL); - min = minor(inode->i_rdev); - n = min >> UBD_SHIFT; - if(n > MAX_DEV) - return(-EINVAL); - dev = &ubd_dev[n]; switch (cmd) { struct hd_geometry g; struct cdrom_volctrl volume; @@ -880,7 +868,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file, case HDIO_SET_UNMASKINTR: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (min & ((1 << UBD_SHIFT) - 1))) + if((arg > 1) || inode->i_bdev->bd_contains != inode->i_bdev) return(-EINVAL); return(0); @@ -900,7 +888,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file, case HDIO_SET_MULTCOUNT: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(min & ((1 << UBD_SHIFT) - 1)) + if (inode->i_bdev->bd_contains != inode->i_bdev) return(-EINVAL); return(0); @@ -925,14 +913,11 @@ static int ubd_ioctl(struct inode * inode, struct file * file, return(-EINVAL); } -static int ubd_revalidate(kdev_t rdev) +static int ubd_revalidate(struct gendisk *disk) { __u64 size; - int n, err; - struct ubd *dev; - - n = minor(rdev) >> UBD_SHIFT; - dev = &ubd_dev[n]; + int err; + struct ubd *dev = disk->private_data; err = 0; spin_lock(&ubd_lock); @@ -941,9 +926,7 @@ static int ubd_revalidate(kdev_t rdev) err = ubd_file_size(dev, &size); if (!err) { - set_capacity(ubd_gendisk[n], size / 512); - if(fake_major != 0) - set_capacity(fake_gendisk[n], size / 512); + set_capacity(disk, size / 512); dev->size = size; } out: diff --git a/arch/x86_64/kernel/mtrr.c b/arch/x86_64/kernel/mtrr.c index 47c35bd43a5d..9d478fa81f6b 100644 --- a/arch/x86_64/kernel/mtrr.c +++ b/arch/x86_64/kernel/mtrr.c @@ -1,7 +1,7 @@ /* x86-64 MTRR (Memory Type Range Register) driver. Based largely upon arch/i386/kernel/mtrr.c - Copyright (C) 1997-2000 Richard Gooch + Copyright (C) 1997-2000 Richard Gooch Copyright (C) 2002 Dave Jones. This library is free software; you can redistribute it and/or @@ -20,7 +20,7 @@ (For earlier history, see arch/i386/kernel/mtrr.c) v2.00 September 2001 Dave Jones <davej@suse.de> - Initial rewrite for x86-64. + Initial rewrite for x86-64. Removal of non-Intel style MTRR code. v2.01 June 2002 Dave Jones <davej@suse.de> Removal of redundant abstraction layer. @@ -84,7 +84,7 @@ typedef u8 mtrr_type; -#define LINE_SIZE 80 +#define LINE_SIZE 80 #ifdef CONFIG_SMP #define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) @@ -124,42 +124,42 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) local_irq_save(ctxt->flags); local_irq_disable(); - /* Save value of CR4 and clear Page Global Enable (bit 7) */ + /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (cpu_has_pge) { ctxt->cr4val = read_cr4(); write_cr4(ctxt->cr4val & ~(1UL << 7)); - } + } - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ cr0 = read_cr0() | 0x40000000; - wbinvd(); + wbinvd(); write_cr0(cr0); - wbinvd(); + wbinvd(); - /* Disable MTRRs, and set the default type to uncached */ + /* Disable MTRRs, and set the default type to uncached */ rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); } -/* Restore the processor after a set_mtrr_prepare */ +/* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) { - /* Flush caches and TLBs */ - wbinvd(); + /* Flush caches and TLBs */ + wbinvd(); - /* Restore MTRRdefType */ + /* Restore MTRRdefType */ wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - /* Enable caches */ + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ + /* Restore value of CR4 */ if (cpu_has_pge) write_cr4 (ctxt->cr4val); - /* Re-enable interrupts locally (if enabled previously) */ + /* Re-enable interrupts locally (if enabled previously) */ local_irq_restore(ctxt->flags); } @@ -193,21 +193,21 @@ static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type) rdmsr (MSR_MTRRphysMask(reg), mask_lo, mask_hi); if ((mask_lo & 0x800) == 0) { - /* Invalid (i.e. free) range */ - *base = 0; - *size = 0; - *type = 0; - return; - } + /* Invalid (i.e. free) range */ + *base = 0; + *size = 0; + *type = 0; + return; + } rdmsr (MSR_MTRRphysBase(reg), base_lo, base_hi); - /* Work out the shifted address mask. */ + /* Work out the shifted address mask. */ newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800); newsize = ~newsize+1; *size = (u32) newsize >> PAGE_SHIFT; - *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; - *type = base_lo & 0xff; + *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; + *type = base_lo & 0xff; } @@ -224,7 +224,7 @@ static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type) static void set_mtrr_up (unsigned int reg, u64 base, u32 size, mtrr_type type, int do_safe) { - struct set_mtrr_context ctxt; + struct set_mtrr_context ctxt; u64 base64; u64 size64; @@ -232,8 +232,8 @@ static void set_mtrr_up (unsigned int reg, u64 base, set_mtrr_prepare (&ctxt); if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ wrmsr (MSR_MTRRphysMask(reg), 0, 0); } else { base64 = (base << PAGE_SHIFT) & size_and_mask; @@ -242,7 +242,7 @@ static void set_mtrr_up (unsigned int reg, u64 base, size64 = ~((size << PAGE_SHIFT) - 1); size64 = size64 & size_and_mask; wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32)); - } + } if (do_safe) set_mtrr_done (&ctxt); } @@ -259,7 +259,7 @@ struct mtrr_var_range { /* Get the MSR pair relating to a var range */ static void __init get_mtrr_var_range (unsigned int index, - struct mtrr_var_range *vr) + struct mtrr_var_range *vr) { rdmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi); rdmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi); @@ -272,35 +272,35 @@ static int __init set_mtrr_var_range_testing (unsigned int index, struct mtrr_var_range *vr) { u32 lo, hi; - int changed = FALSE; + int changed = FALSE; rdmsr (MSR_MTRRphysBase(index), lo, hi); if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) || (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi); - changed = TRUE; - } + changed = TRUE; + } rdmsr (MSR_MTRRphysMask(index), lo, hi); if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) || (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi); - changed = TRUE; - } - return changed; + changed = TRUE; + } + return changed; } static void __init get_fixed_ranges (mtrr_type * frs) { u32 *p = (u32 *) frs; - int i; + int i; rdmsr (MSR_MTRRfix64K_00000, p[0], p[1]); - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) rdmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) rdmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]); } @@ -308,8 +308,8 @@ static void __init get_fixed_ranges (mtrr_type * frs) static int __init set_fixed_ranges_testing (mtrr_type * frs) { u32 *p = (u32 *) frs; - int changed = FALSE; - int i; + int changed = FALSE; + int i; u32 lo, hi; printk (KERN_INFO "mtrr: rdmsr 64K_00000\n"); @@ -317,8 +317,8 @@ static int __init set_fixed_ranges_testing (mtrr_type * frs) if (p[0] != lo || p[1] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi); wrmsr (MSR_MTRRfix64K_00000, p[0], p[1]); - changed = TRUE; - } + changed = TRUE; + } printk (KERN_INFO "mtrr: rdmsr 16K_80000\n"); for (i = 0; i < 2; i++) { @@ -326,9 +326,9 @@ static int __init set_fixed_ranges_testing (mtrr_type * frs) if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi ); wrmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); - changed = TRUE; + changed = TRUE; + } } - } printk (KERN_INFO "mtrr: rdmsr 4K_C0000\n"); for (i = 0; i < 8; i++) { @@ -337,18 +337,18 @@ static int __init set_fixed_ranges_testing (mtrr_type * frs) if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi); wrmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]); - changed = TRUE; + changed = TRUE; + } } - } - return changed; + return changed; } struct mtrr_state { - unsigned int num_var_ranges; - struct mtrr_var_range *var_ranges; - mtrr_type fixed_ranges[NUM_FIXED_RANGES]; - mtrr_type def_type; + unsigned int num_var_ranges; + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + mtrr_type def_type; unsigned char enabled; }; @@ -356,23 +356,23 @@ struct mtrr_state { /* Grab all of the MTRR state for this CPU into *state */ static void __init get_mtrr_state (struct mtrr_state *state) { - unsigned int nvrs, i; - struct mtrr_var_range *vrs; + unsigned int nvrs, i; + struct mtrr_var_range *vrs; u32 lo, dummy; nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges - = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); - if (vrs == NULL) - nvrs = state->num_var_ranges = 0; + vrs = state->var_ranges + = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); + if (vrs == NULL) + nvrs = state->num_var_ranges = 0; - for (i = 0; i < nvrs; i++) - get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); + for (i = 0; i < nvrs; i++) + get_mtrr_var_range (i, &vrs[i]); + get_fixed_ranges (state->fixed_ranges); rdmsr (MSR_MTRRdefType, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; } @@ -392,26 +392,26 @@ static void __init finalize_mtrr_state (struct mtrr_state *state) * [RETURNS] 0 if no changes made, else a mask indication what was changed. */ static u64 __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) + struct set_mtrr_context *ctxt) { - unsigned int i; + unsigned int i; u64 change_mask = 0; - for (i = 0; i < state->num_var_ranges; i++) + for (i = 0; i < state->num_var_ranges; i++) if (set_mtrr_var_range_testing (i, &state->var_ranges[i])) - change_mask |= MTRR_CHANGE_MASK_VARIABLE; + change_mask |= MTRR_CHANGE_MASK_VARIABLE; if (set_fixed_ranges_testing (state->fixed_ranges)) - change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ + change_mask |= MTRR_CHANGE_MASK_FIXED; + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) { - ctxt->deftype_lo |= (state->def_type | state->enabled << 10); - change_mask |= MTRR_CHANGE_MASK_DEFTYPE; - } + ctxt->deftype_lo |= (state->def_type | state->enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } - return change_mask; + return change_mask; } @@ -422,8 +422,8 @@ static volatile int wait_barrier_cache_enable = FALSE; struct set_mtrr_data { u64 smp_base; u32 smp_size; - unsigned int smp_reg; - mtrr_type smp_type; + unsigned int smp_reg; + mtrr_type smp_type; }; /* @@ -431,67 +431,67 @@ struct set_mtrr_data { */ static void ipi_handler (void *info) { - struct set_mtrr_data *data = info; - struct set_mtrr_context ctxt; + struct set_mtrr_data *data = info; + struct set_mtrr_context ctxt; set_mtrr_prepare (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); + /* Notify master that I've flushed and disabled my cache */ + atomic_dec (&undone_count); while (wait_barrier_execute) barrier (); - /* The master has cleared me to execute */ + /* The master has cleared me to execute */ set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, - data->smp_type, FALSE); + data->smp_type, FALSE); - /* Notify master CPU that I've executed the function */ - atomic_dec (&undone_count); + /* Notify master CPU that I've executed the function */ + atomic_dec (&undone_count); - /* Wait for master to clear me to enable cache and return */ + /* Wait for master to clear me to enable cache and return */ while (wait_barrier_cache_enable) barrier (); - set_mtrr_done (&ctxt); + set_mtrr_done (&ctxt); } static void set_mtrr_smp (unsigned int reg, u64 base, u32 size, mtrr_type type) { - struct set_mtrr_data data; - struct set_mtrr_context ctxt; - - data.smp_reg = reg; - data.smp_base = base; - data.smp_size = size; - data.smp_type = type; - wait_barrier_execute = TRUE; - wait_barrier_cache_enable = TRUE; + struct set_mtrr_data data; + struct set_mtrr_context ctxt; + + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; + wait_barrier_execute = TRUE; + wait_barrier_cache_enable = TRUE; atomic_set (&undone_count, num_online_cpus() - 1); - /* Start the ball rolling on other CPUs */ - if (smp_call_function (ipi_handler, &data, 1, 0) != 0) - panic ("mtrr: timed out waiting for other CPUs\n"); + /* Start the ball rolling on other CPUs */ + if (smp_call_function (ipi_handler, &data, 1, 0) != 0) + panic ("mtrr: timed out waiting for other CPUs\n"); - /* Flush and disable the local CPU's cache */ + /* Flush and disable the local CPU's cache */ set_mtrr_prepare (&ctxt); - /* Wait for all other CPUs to flush and disable their caches */ + /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) barrier (); /* Set up for completion wait and then release other CPUs to change MTRRs */ atomic_set (&undone_count, num_online_cpus() - 1); - wait_barrier_execute = FALSE; + wait_barrier_execute = FALSE; set_mtrr_up (reg, base, size, type, FALSE); - /* Now wait for other CPUs to complete the function */ + /* Now wait for other CPUs to complete the function */ while (atomic_read (&undone_count) > 0) barrier (); - /* Now all CPUs should have finished the function. Release the barrier to - allow them to re-enable their caches and return from their interrupt, - then enable the local cache and return */ - wait_barrier_cache_enable = FALSE; - set_mtrr_done (&ctxt); + /* Now all CPUs should have finished the function. Release the barrier to + allow them to re-enable their caches and return from their interrupt, + then enable the local cache and return */ + wait_barrier_cache_enable = FALSE; + set_mtrr_done (&ctxt); } @@ -500,44 +500,44 @@ static void __init mtrr_state_warn (u32 mask) { if (!mask) return; - if (mask & MTRR_CHANGE_MASK_FIXED) - printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); - printk ("mtrr: probably your BIOS does not setup all CPUs\n"); + if (mask & MTRR_CHANGE_MASK_FIXED) + printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk ("mtrr: probably your BIOS does not setup all CPUs\n"); } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ static inline char * attrib_to_str (int x) { - return (x <= 6) ? mtrr_strings[x] : "?"; + return (x <= 6) ? mtrr_strings[x] : "?"; } static void __init init_table (void) { - int i, max; + int i, max; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) { - printk ("mtrr: could not allocate\n"); - return; - } + printk ("mtrr: could not allocate\n"); + return; + } for (i = 0; i < max; i++) usage_table[i] = 1; #ifdef USERSPACE_INTERFACE if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return; - } - ascii_buf_bytes = 0; - compute_ascii (); + printk ("mtrr: could not allocate\n"); + return; + } + ascii_buf_bytes = 0; + compute_ascii (); #endif } @@ -548,18 +548,18 @@ static void __init init_table (void) */ static int get_free_region(void) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase; u32 lsize; - max = get_num_var_ranges (); + max = get_num_var_ranges (); for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); if (lsize == 0) return i; - } - return -ENOSPC; + } + return -ENOSPC; } @@ -597,16 +597,16 @@ static int get_free_region(void) int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase, last; u32 lsize; if (base + size < 0x100) { printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n", - base, size); - return -EINVAL; + base, size); + return -EINVAL; } #if defined(__x86_64__) && defined(CONFIG_AGP) @@ -621,7 +621,7 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) #endif /* Check upper bits of base and last are equal and lower bits are 0 - for base and 1 for last */ + for base and 1 for last */ last = base + size - 1; for (lbase = base; !(lbase & 1) && (last & 1); lbase = lbase >> 1, last = last >> 1) ; @@ -630,35 +630,36 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) printk (KERN_WARNING "mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n", base, size); - return -EINVAL; - } + return -EINVAL; + } if (type >= MTRR_NUM_TYPES) { - printk ("mtrr: type: %u illegal\n", type); - return -EINVAL; - } + printk ("mtrr: type: %u illegal\n", type); + return -EINVAL; + } - /* If the type is WC, check that this processor supports it */ + /* If the type is WC, check that this processor supports it */ if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) { printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n"); - return -ENOSYS; - } + return -ENOSYS; + } if (base & (size_or_mask>>PAGE_SHIFT)) { printk (KERN_WARNING "mtrr: base(%lx) exceeds the MTRR width(%lx)\n", - base, (size_or_mask>>PAGE_SHIFT)); + (unsigned long) base, + (unsigned long) (size_or_mask>>PAGE_SHIFT)); return -EINVAL; } if (size & (size_or_mask>>PAGE_SHIFT)) { printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n"); - return -EINVAL; - } + return -EINVAL; + } - increment = increment ? 1 : 0; - max = get_num_var_ranges (); - /* Search for existing MTRR */ + increment = increment ? 1 : 0; + max = get_num_var_ranges (); + /* Search for existing MTRR */ down (&mtrr_lock); for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); @@ -667,15 +668,15 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) if ((base < lbase) && (base + size <= lbase)) continue; - /* At this point we know there is some kind of overlap/enclosure */ + /* At this point we know there is some kind of overlap/enclosure */ if ((base < lbase) || (base + size > lbase + lsize)) { up (&mtrr_lock); printk (KERN_WARNING "mtrr: 0x%Lx000,0x%x000 overlaps existing" " 0x%Lx000,0x%x000\n", base, size, lbase, lsize); - return -EINVAL; - } - /* New region is enclosed by an existing region */ + return -EINVAL; + } + /* New region is enclosed by an existing region */ if (ltype != type) { if (type == MTRR_TYPE_UNCACHABLE) continue; @@ -685,26 +686,26 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) base, size, attrib_to_str (ltype), attrib_to_str (type)); - return -EINVAL; - } + return -EINVAL; + } if (increment) ++usage_table[i]; - compute_ascii (); + compute_ascii (); up (&mtrr_lock); - return i; - } - /* Search for an empty MTRR */ + return i; + } + /* Search for an empty MTRR */ i = get_free_region(); if (i < 0) { up (&mtrr_lock); - printk ("mtrr: no more MTRRs available\n"); - return i; - } - set_mtrr (i, base, size, type); - usage_table[i] = 1; - compute_ascii (); + printk ("mtrr: no more MTRRs available\n"); + return i; + } + set_mtrr (i, base, size, type); + usage_table[i] = 1; + compute_ascii (); up (&mtrr_lock); - return i; + return i; } @@ -744,10 +745,10 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) int mtrr_add (u64 base, u32 size, unsigned int type, char increment) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); - return -EINVAL; - } + return -EINVAL; + } return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } @@ -767,56 +768,56 @@ int mtrr_add (u64 base, u32 size, unsigned int type, char increment) * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del_page (int reg, u64 base, u32 size) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase; u32 lsize; - max = get_num_var_ranges (); + max = get_num_var_ranges (); down (&mtrr_lock); if (reg < 0) { - /* Search for existing MTRR */ + /* Search for existing MTRR */ for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); if (lbase == base && lsize == size) { - reg = i; - break; - } - } + reg = i; + break; + } + } if (reg < 0) { up (&mtrr_lock); printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size); - return -EINVAL; + return -EINVAL; + } } - } if (reg >= max) { up (&mtrr_lock); - printk ("mtrr: register: %d too big\n", reg); - return -EINVAL; - } + printk ("mtrr: register: %d too big\n", reg); + return -EINVAL; + } get_mtrr (reg, &lbase, &lsize, <ype); if (lsize < 1) { up (&mtrr_lock); - printk ("mtrr: MTRR %d not used\n", reg); - return -EINVAL; - } + printk ("mtrr: MTRR %d not used\n", reg); + return -EINVAL; + } if (usage_table[reg] < 1) { up (&mtrr_lock); - printk ("mtrr: reg: %d has count=0\n", reg); - return -EINVAL; - } + printk ("mtrr: reg: %d has count=0\n", reg); + return -EINVAL; + } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); - compute_ascii (); + compute_ascii (); up (&mtrr_lock); - return reg; + return reg; } @@ -834,14 +835,14 @@ int mtrr_del_page (int reg, u64 base, u32 size) * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del (int reg, u64 base, u32 size) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); - return -EINVAL; - } + return -EINVAL; + } return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } @@ -851,64 +852,64 @@ int mtrr_del (int reg, u64 base, u32 size) static int mtrr_file_add (u64 base, u32 size, unsigned int type, struct file *file, int page) { - int reg, max; - unsigned int *fcount = file->private_data; + int reg, max; + unsigned int *fcount = file->private_data; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if (fcount == NULL) { if ((fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return -ENOMEM; + printk ("mtrr: could not allocate\n"); + return -ENOMEM; + } + memset (fcount, 0, max * sizeof *fcount); + file->private_data = fcount; } - memset (fcount, 0, max * sizeof *fcount); - file->private_data = fcount; - } - if (!page) { + if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); - return -EINVAL; + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_add_page (base, size, type, 1); + reg = mtrr_add_page (base, size, type, 1); if (reg >= 0) ++fcount[reg]; - return reg; + return reg; } static int mtrr_file_del (u64 base, u32 size, - struct file *file, int page) + struct file *file, int page) { - int reg; - unsigned int *fcount = file->private_data; + int reg; + unsigned int *fcount = file->private_data; - if (!page) { + if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); - return -EINVAL; + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_del_page (-1, base, size); + reg = mtrr_del_page (-1, base, size); if (reg < 0) return reg; if (fcount == NULL) return reg; if (fcount[reg] < 1) return -EINVAL; - --fcount[reg]; - return reg; + --fcount[reg]; + return reg; } @@ -924,8 +925,8 @@ static ssize_t mtrr_read (struct file *file, char *buf, size_t len, if (copy_to_user (buf, ascii_buffer + *ppos, len)) return -EFAULT; - *ppos += len; - return len; + *ppos += len; + return len; } @@ -939,240 +940,240 @@ static ssize_t mtrr_write (struct file *file, const char *buf, int i, err, reg; u64 base; u32 size; - char *ptr; - char line[LINE_SIZE]; + char *ptr; + char line[LINE_SIZE]; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - /* Can't seek (pwrite) on this device */ + /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; - memset (line, 0, LINE_SIZE); + memset (line, 0, LINE_SIZE); if (len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user (line, buf, len - 1)) return -EFAULT; - ptr = line + strlen (line) - 1; + ptr = line + strlen (line) - 1; if (*ptr == '\n') *ptr = '\0'; if (!strncmp (line, "disable=", 8)) { - reg = simple_strtoul (line + 8, &ptr, 0); - err = mtrr_del_page (reg, 0, 0); + reg = simple_strtoul (line + 8, &ptr, 0); + err = mtrr_del_page (reg, 0, 0); if (err < 0) return err; - return len; - } + return len; + } if (strncmp (line, "base=", 5)) { - printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); + return -EINVAL; + } - base = simple_strtoull (line + 5, &ptr, 0); + base = simple_strtoull (line + 5, &ptr, 0); for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "size=", 5)) { - printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); + return -EINVAL; + } - size = simple_strtoull (ptr + 5, &ptr, 0); + size = simple_strtoull (ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); - return -EINVAL; - } + return -EINVAL; + } for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "type=", 5)) { - printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); - return -EINVAL; - } - ptr += 5; + printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); + return -EINVAL; + } + ptr += 5; for (; isspace (*ptr); ++ptr) ; for (i = 0; i < MTRR_NUM_TYPES; ++i) { if (strcmp (ptr, mtrr_strings[i])) continue; - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; err = mtrr_add_page ((u64) base, size, i, 1); if (err < 0) return err; - return len; - } - printk ("mtrr: illegal type: \"%s\"\n", ptr); - return -EINVAL; + return len; + } + printk ("mtrr: illegal type: \"%s\"\n", ptr); + return -EINVAL; } static int mtrr_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int err; - mtrr_type type; - struct mtrr_sentry sentry; - struct mtrr_gentry gentry; + int err; + mtrr_type type; + struct mtrr_sentry sentry; + struct mtrr_gentry gentry; switch (cmd) { - default: - return -ENOIOCTLCMD; + default: + return -ENOIOCTLCMD; - case MTRRIOC_ADD_ENTRY: + case MTRRIOC_ADD_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; + return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_ENTRY: + case MTRRIOC_SET_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_ENTRY: + case MTRRIOC_DEL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 0); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_ENTRY: + case MTRRIOC_KILL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_ENTRY: + case MTRRIOC_GET_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); - /* Hide entries that go above 4GB */ + /* Hide entries that go above 4GB */ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) - gentry.base = gentry.size = gentry.type = 0; - else { - gentry.base <<= PAGE_SHIFT; - gentry.size <<= PAGE_SHIFT; - gentry.type = type; - } + gentry.base = gentry.size = gentry.type = 0; + else { + gentry.base <<= PAGE_SHIFT; + gentry.size <<= PAGE_SHIFT; + gentry.type = type; + } if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) - return -EFAULT; - break; + return -EFAULT; + break; - case MTRRIOC_ADD_PAGE_ENTRY: + case MTRRIOC_ADD_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; + return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_PAGE_ENTRY: + case MTRRIOC_SET_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_PAGE_ENTRY: + case MTRRIOC_DEL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 1); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_PAGE_ENTRY: + case MTRRIOC_KILL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del_page (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del_page (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_PAGE_ENTRY: + case MTRRIOC_GET_PAGE_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); - gentry.type = type; + gentry.type = type; if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) - return -EFAULT; - break; - } - return 0; + return -EFAULT; + break; + } + return 0; } static int mtrr_close (struct inode *ino, struct file *file) { - int i, max; - unsigned int *fcount = file->private_data; + int i, max; + unsigned int *fcount = file->private_data; if (fcount == NULL) return 0; lock_kernel (); - max = get_num_var_ranges (); + max = get_num_var_ranges (); for (i = 0; i < max; ++i) { while (fcount[i] > 0) { if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i); - --fcount[i]; + --fcount[i]; + } } - } unlock_kernel (); - kfree (fcount); - file->private_data = NULL; - return 0; + kfree (fcount); + file->private_data = NULL; + return 0; } static struct file_operations mtrr_fops = { .owner = THIS_MODULE, - .read = mtrr_read, - .write = mtrr_write, + .read = mtrr_read, + .write = mtrr_write, .ioctl = mtrr_ioctl, .release = mtrr_close, }; @@ -1185,38 +1186,38 @@ static devfs_handle_t devfs_handle; static void compute_ascii (void) { - char factor; - int i, max; - mtrr_type type; + char factor; + int i, max; + mtrr_type type; u64 base; u32 size; - ascii_buf_bytes = 0; - max = get_num_var_ranges (); + ascii_buf_bytes = 0; + max = get_num_var_ranges (); for (i = 0; i < max; i++) { get_mtrr (i, &base, &size, &type); if (size == 0) usage_table[i] = 0; else { if (size < (0x100000 >> PAGE_SHIFT)) { - /* less than 1MB */ - factor = 'K'; - size <<= PAGE_SHIFT - 10; + /* less than 1MB */ + factor = 'K'; + size <<= PAGE_SHIFT - 10; } else { - factor = 'M'; - size >>= 20 - PAGE_SHIFT; - } + factor = 'M'; + size >>= 20 - PAGE_SHIFT; + } sprintf (ascii_buffer + ascii_buf_bytes, "reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n", i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor, - attrib_to_str (type), usage_table[i]); + attrib_to_str (type), usage_table[i]); ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); + } } - } - devfs_set_file_size (devfs_handle, ascii_buf_bytes); + devfs_set_file_size (devfs_handle, ascii_buf_bytes); #ifdef CONFIG_PROC_FS - if (proc_root_mtrr) - proc_root_mtrr->size = ascii_buf_bytes; + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; #endif } @@ -1225,7 +1226,7 @@ static void compute_ascii (void) EXPORT_SYMBOL (mtrr_add); EXPORT_SYMBOL (mtrr_del); - + static void __init mtrr_setup (void) { printk ("mtrr: v%s)\n", MTRR_VERSION); @@ -1234,7 +1235,7 @@ static void __init mtrr_setup (void) /* Query the width (in bits) of the physical addressable memory on the Hammer family. */ if ((cpuid_eax (0x80000000) >= 0x80000008)) { - u32 phys_addr; + u32 phys_addr; phys_addr = cpuid_eax (0x80000008) & 0xff; size_or_mask = ~((1L << phys_addr) - 1); /* @@ -1263,30 +1264,30 @@ void __init mtrr_init_secondary_cpu (void) { u64 mask; int count; - struct set_mtrr_context ctxt; + struct set_mtrr_context ctxt; - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ + /* Note that this is not ideal, since the cache is only flushed/disabled + for this CPU while the MTRRs are changed, but changing this requires + more invasive changes to the way the kernel boots */ set_mtrr_prepare (&ctxt); - mask = set_mtrr_state (&smp_mtrr_state, &ctxt); - set_mtrr_done (&ctxt); + mask = set_mtrr_state (&smp_mtrr_state, &ctxt); + set_mtrr_done (&ctxt); - /* Use the atomic bitops to update the global mask */ + /* Use the atomic bitops to update the global mask */ for (count = 0; count < sizeof mask * 8; ++count) { if (mask & 0x01) set_bit (count, &smp_changes_mask); - mask >>= 1; - } + mask >>= 1; + } } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ int __init mtrr_init (void) { #ifdef CONFIG_SMP - /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ + /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); @@ -1295,17 +1296,17 @@ int __init mtrr_init (void) #endif #ifdef CONFIG_PROC_FS - proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - if (proc_root_mtrr) { - proc_root_mtrr->owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; - } + proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif #ifdef CONFIG_DEVFS_FS - devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUGO | S_IWUSR, - &mtrr_fops, NULL); + devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, + &mtrr_fops, NULL); #endif - init_table (); - return 0; + init_table (); + return 0; } diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 1d55917a10f8..3c0ae2ebb5a9 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -156,6 +156,7 @@ #define FLOPPY_DMA 0 #define DEVICE_NAME "floppy" #define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#define QUEUE (&floppy_queue) #include <linux/blk.h> /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with @@ -179,6 +180,8 @@ #define DPRINT(a) #endif +static struct request_queue floppy_queue; + /* Disk types: DD */ static struct archy_disk_type { const char *name; @@ -1140,14 +1143,11 @@ static void floppy_off(unsigned int nr) - but if it sees a disc change line go high (?) it flips to using it. Well maybe I'll add that in the future (!?) */ -static int check_floppy_change(dev_t dev) +static int check_floppy_change(struct gendisk *disk) { - unsigned int drive = (dev & 0x03); + struct archy_floppy_struct *p = disk->private_data; + unsigned int drive = p - unit; - if (major(dev) != MAJOR_NR) { - printk("floppy_changed: not a floppy\n"); - return 0; - } if (test_bit(drive, &fake_change)) { /* simulated change (e.g. after formatting) */ return 1; @@ -1156,7 +1156,7 @@ static int check_floppy_change(dev_t dev) /* surely changed (the WP signal changed at least once) */ return 1; } - if (unit[drive].wpstat) { + if (p->wpstat) { /* WP is on -> could be changed: to be sure, buffers should be * invalidated... */ @@ -1165,9 +1165,10 @@ static int check_floppy_change(dev_t dev) return 1; /* DAG - was 0 */ } -static int floppy_revalidate(dev_t dev) +static int floppy_revalidate(struct gendisk *disk) { - int drive = dev & 3; + struct archy_floppy_struct *p = disk->private_data; + unsigned int drive = p - unit; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || unit[drive].disktype == 0) { @@ -1176,7 +1177,7 @@ static int floppy_revalidate(dev_t dev) #endif clear_bit(drive, &fake_change); clear_bit(drive, &changed_floppies); - unit[drive].disktype = 0; + p->disktype = 0; } return 0; } @@ -1521,23 +1522,24 @@ static int floppy_release(struct inode *inode, struct file *filp) static struct block_device_operations floppy_fops = { - .open = floppy_open, - .release = floppy_release, - .ioctl = fd_ioctl, - .check_media_change = check_floppy_change, - .revalidate = floppy_revalidate, + .open = floppy_open, + .release = floppy_release, + .ioctl = fd_ioctl, + .media_changed = check_floppy_change, + .revalidate_disk= floppy_revalidate, }; -static struct gendisk *floppy_find(int minor) +static struct gendisk *floppy_find(dev_t dev, int *part, void *data) { - int drive = minor & 3; - if ((minor>> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS) + int drive = *part & 3; + if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS) return NULL; - return disks[drive]; + return get_disk(disks[drive]); } int fd1772_init(void) { + static spinlock_t lock = SPIN_LOCK_UNLOCKED; int i; if (!machine_is_archimedes()) @@ -1580,16 +1582,19 @@ int fd1772_init(void) out of some special memory... */ DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */ #endif - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request); + blk_init_queue(&floppy_queue, do_fd_request, &lock); for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; disks[i]->major = MAJOR_NR; disks[i]->first_minor = 0; disks[i]->fops = &floppy_fops; sprintf(disks[i]->disk_name, "fd%d", i); + disks[i]->private_data = &unit[i]; + disks[i]->queue = &floppy_queue; set_capacity(disks[i], MAX_DISK_SIZE * 2); } - blk_set_probe(MAJOR_NR, floppy_find); + blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, + floppy_find, NULL, NULL); for (i = 0; i < FD_MAX_UNITS; i++) add_disk(disks[i]); diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index d4c01d605559..95471970b5d8 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -114,7 +114,7 @@ #include <linux/delay.h> #define MAJOR_NR MFM_ACORN_MAJOR -#define DEVICE_NR(device) (minor(device) >> 6) +#define QUEUE (&mfm_queue) #include <linux/blk.h> #include <linux/blkpg.h> @@ -128,6 +128,8 @@ #include <asm/hardware/ioc.h> static void (*do_mfm)(void) = NULL; +static struct request_queue mfm_queue; +static spinlock_t mfm_lock = SPIN_LOCK_UNLOCKED; /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc */ @@ -225,7 +227,7 @@ static void mfm_seek(void); static void mfm_rerequest(void); static void mfm_request(void); static void mfm_specify (void); -static void issue_request(int dev, unsigned int block, unsigned int nsect, +static void issue_request(unsigned int block, unsigned int nsect, struct request *req); static unsigned int mfm_addr; /* Controller address */ @@ -739,7 +741,7 @@ static void request_done(int uptodate) /* Yep - a partial access */ /* and issue the remainder */ - issue_request(minor(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); return; } @@ -794,30 +796,31 @@ static struct cont rw_cont = * Actually gets round to issuing the request - note everything at this * point is in 256 byte sectors not Linux 512 byte blocks */ -static void issue_request(int dev, unsigned int block, unsigned int nsect, +static void issue_request(unsigned int block, unsigned int nsect, struct request *req) { + struct gendisk *disk = req->rq_disk; + struct mfm_info *p = disk->private_data; int track, start_head, start_sector; int sectors_to_next_cyl; + dev = p - mfm_info; - dev >>= 6; - - track = block / mfm_info[dev].sectors; - start_sector = block % mfm_info[dev].sectors; - start_head = track % mfm_info[dev].heads; + track = block / p->sectors; + start_sector = block % p->sectors; + start_head = track % p->heads; /* First get the number of whole tracks which are free before the next track */ - sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors; + sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors; /* Then add in the number of sectors left on this track */ - sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector); + sectors_to_next_cyl += (p->sectors - start_sector); - DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track); + DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track); raw_cmd.dev = dev; raw_cmd.sector = start_sector; raw_cmd.head = start_head; - raw_cmd.cylinder = track / mfm_info[dev].heads; + raw_cmd.cylinder = track / p->heads; raw_cmd.cmdtype = CURRENT->cmd; raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ @@ -895,7 +898,7 @@ static void mfm_request(void) Busy = 1; while (1) { - unsigned int dev, block, nsect, unit; + unsigned int block, nsect; struct gendisk *disk; DBG("mfm_request: loop start\n"); @@ -912,16 +915,9 @@ static void mfm_request(void) DBG("mfm_request: before arg extraction\n"); - dev = minor(CURRENT->rq_dev); - unit = dev>>6; + disk = CURRENT->rq_disk; block = CURRENT->sector; nsect = CURRENT->nr_sectors; -#ifdef DEBUG - /*if (unit==1) */ console_printf("mfm_request: raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect); -#endif - if (unit >= mfm_drives) - printk("mfm: bad disk number: %d\n", unit); - disk = mfm_gendisk[unit]; if (block >= get_capacity(disk) || block+nsect > get_capacity(disk)) { printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n", @@ -951,7 +947,7 @@ static void mfm_request(void) printk("mfm: continue 4\n"); continue; } - issue_request(dev, block, nsect, CURRENT); + issue_request(block, nsect, CURRENT); break; } @@ -1006,6 +1002,7 @@ static void mfm_geometry(int drive) { struct mfm_info *p = mfm_info + drive; struct gendisk *disk = mfm_gendisk[drive]; + disk->private_data = p; if (p->cylinders) printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", disk->disk_name, @@ -1166,21 +1163,18 @@ static int mfm_initdrives(void) static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { + struct mfm_info *p = inode->i_bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; - int device = DEVICE_NR(minor(inode->i_rdev)); - if (device >= mfm_drives) - return -EINVAL; if (cmd != HDIO_GETGEO) return -EINVAL; if (!arg) return -EINVAL; - if (put_user (mfm_info[device].heads, &geo->heads)) + if (put_user (p->heads, &geo->heads)) return -EFAULT; - if (put_user (mfm_info[device].sectors, &geo->sectors)) + if (put_user (p->sectors, &geo->sectors)) return -EFAULT; - if (put_user (mfm_info[device].cylinders, &geo->cylinders)) + if (put_user (p->cylinders, &geo->cylinders)) return -EFAULT; - start = get_start_sect(inode->i_bdev); if (put_user (get_start_sect(inode->i_bdev), &geo->start)) return -EFAULT; return 0; @@ -1203,24 +1197,26 @@ void mfm_setup(char *str, int *ints) void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack, unsigned char heads, unsigned int secsize) { - int drive = MINOR(bdev->bd_dev) >> 6; + struct mfm_info *p = bdev->bd_disk->private_data; + int drive = p - mfm_info; unsigned long disksize = bdev->bd_inode->i_size; - if (mfm_info[drive].cylinders == 1) { - mfm_info[drive].sectors = secsptrack; - mfm_info[drive].heads = heads; - mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize); + if (p->cylinders == 1) { + p->sectors = secsptrack; + p->heads = heads; + p->cylinders = discsize / (secsptrack * heads * secsize); - if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) { - printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + drive); + if ((heads < 1) || (p->cylinders > 1024)) { + printk("%s: Insane disc shape! Setting to 512/4/32\n", + bdev->bd_disk->disk_name); /* These values are fairly arbitary, but are there so that if your * lucky you can pick apart your disc to find out what is going on - * I reckon these figures won't hurt MOST drives */ - mfm_info[drive].sectors = 32; - mfm_info[drive].heads = 4; - mfm_info[drive].cylinders = 512; + p->sectors = 32; + p->heads = 4; + p->cylinders = 512; } if (raw_cmd.dev == drive) mfm_specify (); @@ -1317,7 +1313,7 @@ static int __init mfm_init (void) hdc63463_irqpolladdress = mfm_IRQPollLoc; hdc63463_irqpollmask = irqmask; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mfm_request); + blk_init_queue(&mfm_queue, do_mfm_request, &mfm_lock); Busy = 0; lastspecifieddrive = -1; @@ -1349,6 +1345,7 @@ static int __init mfm_init (void) for (i = 0; i < mfm_drives; i++) { mfm_geometry(i); + mfm_gendisk[i]->queue = &mfm_queue; add_disk(mfm_gendisk[i]); } return 0; @@ -1357,7 +1354,7 @@ out4: for (i = 0; i < mfm_drives; i++) put_disk(mfm_gendisk[i]); out3: - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mfm_queue); unregister_blkdev(MAJOR_NR, "mfm"); out2: release_region(mfm_addr, 10); @@ -1380,7 +1377,7 @@ static void __exit mfm_exit(void) del_gendisk(mfm_gendisk[i]); put_disk(mfm_gendisk[i]); } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mfm_queue); unregister_blkdev(MAJOR_NR, "mfm"); if (ecs) ecard_release(ecs); diff --git a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c index b0b8a490a214..6ab6f0d3b126 100644 --- a/drivers/acorn/scsi/acornscsi.c +++ b/drivers/acorn/scsi/acornscsi.c @@ -3010,14 +3010,12 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset, int length, int host_no, int inout) { int pos, begin = 0, devidx; - struct Scsi_Host *instance = scsi_hostlist; + struct Scsi_Host *instance; Scsi_Device *scd; AS_Host *host; char *p = buffer; - for (instance = scsi_hostlist; - instance && instance->host_no != host_no; - instance = instance->next); + instance = scsi_host_hn_get(host_no); if (inout == 1 || !instance) return -EINVAL; diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c index 646aada2b49b..016d019fb59f 100644 --- a/drivers/acorn/scsi/arxescsi.c +++ b/drivers/acorn/scsi/arxescsi.c @@ -384,15 +384,11 @@ int arxescsi_proc_info(char *buffer, char **start, off_t offset, int length, int host_no, int inout) { int pos, begin; - struct Scsi_Host *host = scsi_hostlist; + struct Scsi_Host *host; ARXEScsi_Info *info; Scsi_Device *scd; - while (host) { - if (host->host_no == host_no) - break; - host = host->next; - } + host = scsi_host_hn_get(host_no); if (!host) return 0; diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c index 15dd45c3871f..010b31b6ee23 100644 --- a/drivers/acorn/scsi/cumana_2.c +++ b/drivers/acorn/scsi/cumana_2.c @@ -498,15 +498,11 @@ int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, int length, int host_no, int inout) { int pos, begin; - struct Scsi_Host *host = scsi_hostlist; + struct Scsi_Host *host; CumanaScsi2_Info *info; Scsi_Device *scd; - while (host) { - if (host->host_no == host_no) - break; - host = host->next; - } + host = scsi_host_hn_get(host_no); if (!host) return 0; diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c index d010d4430c23..f64f67cb3082 100644 --- a/drivers/acorn/scsi/eesox.c +++ b/drivers/acorn/scsi/eesox.c @@ -499,15 +499,11 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset, int length, int host_no, int inout) { int pos, begin; - struct Scsi_Host *host = scsi_hostlist; + struct Scsi_Host *host; EESOXScsi_Info *info; Scsi_Device *scd; - while (host) { - if (host->host_no == host_no) - break; - host = host->next; - } + host = scsi_host_hn_get(host_no); if (!host) return 0; diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c index f5783217a5f8..7f90b93793a5 100644 --- a/drivers/acorn/scsi/powertec.c +++ b/drivers/acorn/scsi/powertec.c @@ -404,15 +404,11 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset, int length, int host_no, int inout) { int pos, begin; - struct Scsi_Host *host = scsi_hostlist; + struct Scsi_Host *host; PowerTecScsi_Info *info; Scsi_Device *scd; - while (host) { - if (host->host_no == host_no) - break; - host = host->next; - } + host = scsi_host_hn_get(host_no); if (!host) return 0; diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index ccae789befa9..2d88513912c0 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -8,6 +8,10 @@ export-objs := uPD98402.o suni.o idt77105.o fore_200e-objs := fore200e.o host-progs := fore200e_mkfirm +# Files generated that shall be removed upon make clean +clean-files := {atmsar11,pca200e,pca200e_ecd,sba200e_ecd}.{bin,bin1,bin2} +# Firmware generated that shall be removed upon make clean +clean-files += fore200e_pca_fw.c fore200e_sba_fw.c obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o obj-$(CONFIG_ATM_NICSTAR) += nicstar.o @@ -61,6 +65,6 @@ $(obj)/fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ # deal with the various suffixes of the binary firmware images -$(obj)/%.bin $(obj)/%.bin1 $(obj)/%.bin2: $(obj)/%.data +$(obj)/%.bin $(obj)/%.bin1 $(obj)/%.bin2: $(src)/%.data objcopy -Iihex $< -Obinary $@.gz gzip -df $@.gz diff --git a/drivers/base/base.h b/drivers/base/base.h index 0c05ae058971..3f294f8cafff 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -8,6 +8,7 @@ extern struct list_head global_device_list; extern spinlock_t device_lock; +extern struct semaphore device_sem; extern struct device * get_device_locked(struct device *); @@ -20,6 +21,9 @@ extern void device_remove_dir(struct device * dev); extern int bus_make_dir(struct bus_type * bus); extern void bus_remove_dir(struct bus_type * bus); +extern int bus_add_driver(struct device_driver *); +extern void bus_remove_driver(struct device_driver *); + extern int driver_make_dir(struct device_driver * drv); extern void driver_remove_dir(struct device_driver * drv); @@ -48,9 +52,6 @@ extern int interface_add(struct device_class *, struct device *); extern void interface_remove(struct device_class *, struct device *); -extern int driver_attach(struct device_driver * drv); -extern void driver_detach(struct device_driver * drv); - #ifdef CONFIG_HOTPLUG extern int dev_hotplug(struct device *dev, const char *action); #else diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7daffbfd9913..207270822e3c 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -43,28 +43,23 @@ int bus_for_each_dev(struct bus_type * bus, void * data, int (*callback)(struct device * dev, void * data)) { struct list_head * node; - struct device * prev = NULL; int error = 0; - get_bus(bus); - spin_lock(&device_lock); - list_for_each(node,&bus->devices) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - spin_unlock(&device_lock); - error = callback(dev,data); - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); - if (error) - break; + bus = get_bus(bus); + if (bus) { + down_read(&bus->rwsem); + list_for_each(node,&bus->devices) { + struct device * dev = get_device(to_dev(node)); + if (dev) { + error = callback(dev,data); + put_device(dev); + if (error) + break; + } } + up_read(&bus->rwsem); + put_bus(bus); } - spin_unlock(&device_lock); - if (prev) - put_device(prev); - put_bus(bus); return error; } @@ -72,33 +67,127 @@ int bus_for_each_drv(struct bus_type * bus, void * data, int (*callback)(struct device_driver * drv, void * data)) { struct list_head * node; - struct device_driver * prev = NULL; int error = 0; - /* pin bus in memory */ - get_bus(bus); + bus = get_bus(bus); + if (bus) { + down_read(&bus->rwsem); + list_for_each(node,&bus->drivers) { + struct device_driver * drv = get_driver(to_drv(node)); + if (drv) { + error = callback(drv,data); + put_driver(drv); + if (error) + break; + } + } + up_read(&bus->rwsem); + put_bus(bus); + } + return error; +} - spin_lock(&device_lock); - list_for_each(node,&bus->drivers) { - struct device_driver * drv = get_driver(to_drv(node)); - if (drv) { - spin_unlock(&device_lock); - error = callback(drv,data); - if (prev) - put_driver(prev); - prev = drv; - spin_lock(&device_lock); - if (error) - break; +static void attach(struct device * dev) +{ + pr_debug("bound device '%s' to driver '%s'\n", + dev->bus_id,dev->driver->name); + list_add_tail(&dev->driver_list,&dev->driver->devices); +} + +static int bus_match(struct device * dev, struct device_driver * drv) +{ + int error = -ENODEV; + if (dev->bus->match(dev,drv)) { + dev->driver = drv; + if (drv->probe) { + if (!(error = drv->probe(dev))) + attach(dev); + else + dev->driver = NULL; + } else + attach(dev); + } + return error; +} + +static int device_attach(struct device * dev) +{ + struct bus_type * bus = dev->bus; + struct list_head * entry; + int error = 0; + + if (dev->driver) { + attach(dev); + return 0; + } + + if (!bus->match) + return 0; + + list_for_each(entry,&bus->drivers) { + struct device_driver * drv = + get_driver(container_of(entry,struct device_driver,bus_list)); + if (!drv) + continue; + error = bus_match(dev,drv); + put_driver(drv); + if (!error) + break; + } + return error; +} + +static int driver_attach(struct device_driver * drv) +{ + struct bus_type * bus = drv->bus; + struct list_head * entry; + int error = 0; + + if (!bus->match) + return 0; + + list_for_each(entry,&bus->devices) { + struct device * dev = container_of(entry,struct device,bus_list); + if (get_device(dev)) { + if (!dev->driver) { + if (!bus_match(dev,drv) && dev->driver) + devclass_add_device(dev); + } + put_device(dev); } } - spin_unlock(&device_lock); - if (prev) - put_driver(prev); - put_bus(bus); return error; } +static void detach(struct device * dev, struct device_driver * drv) +{ + if (drv) { + list_del_init(&dev->driver_list); + devclass_remove_device(dev); + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } +} + +static void device_detach(struct device * dev) +{ + detach(dev,dev->driver); +} + +static void driver_detach(struct device_driver * drv) +{ + struct list_head * entry, * next; + list_for_each_safe(entry,next,&drv->devices) { + struct device * dev = container_of(entry,struct device,driver_list); + if (get_device(dev)) { + detach(dev,drv); + put_device(dev); + } + } + +} + /** * bus_add_device - add device to bus * @dev: device being added @@ -110,12 +199,13 @@ int bus_for_each_drv(struct bus_type * bus, void * data, */ int bus_add_device(struct device * dev) { - if (dev->bus) { - pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); - get_bus(dev->bus); - spin_lock(&device_lock); + struct bus_type * bus = get_bus(dev->bus); + if (bus) { + down_write(&dev->bus->rwsem); + pr_debug("bus %s: add device %s\n",bus->name,dev->bus_id); list_add_tail(&dev->bus_list,&dev->bus->devices); - spin_unlock(&device_lock); + device_attach(dev); + up_write(&dev->bus->rwsem); device_bus_link(dev); } return 0; @@ -131,17 +221,70 @@ int bus_add_device(struct device * dev) void bus_remove_device(struct device * dev) { if (dev->bus) { + down_write(&dev->bus->rwsem); + pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); device_remove_symlink(&dev->bus->device_dir,dev->bus_id); + device_detach(dev); + list_del_init(&dev->bus_list); + up_write(&dev->bus->rwsem); put_bus(dev->bus); } } +int bus_add_driver(struct device_driver * drv) +{ + struct bus_type * bus = get_bus(drv->bus); + if (bus) { + down_write(&bus->rwsem); + pr_debug("bus %s: add driver %s\n",bus->name,drv->name); + list_add_tail(&drv->bus_list,&bus->drivers); + driver_attach(drv); + up_write(&bus->rwsem); + driver_make_dir(drv); + } + return 0; +} + +void bus_remove_driver(struct device_driver * drv) +{ + if (drv->bus) { + down_write(&drv->bus->rwsem); + pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name); + driver_detach(drv); + list_del_init(&drv->bus_list); + up_write(&drv->bus->rwsem); + } +} + +struct bus_type * get_bus(struct bus_type * bus) +{ + struct bus_type * ret = bus; + spin_lock(&device_lock); + if (bus && bus->present && atomic_read(&bus->refcount)) + atomic_inc(&bus->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + +void put_bus(struct bus_type * bus) +{ + if (!atomic_dec_and_lock(&bus->refcount,&device_lock)) + return; + list_del_init(&bus->node); + spin_unlock(&device_lock); + BUG_ON(bus->present); + bus_remove_dir(bus); +} + int bus_register(struct bus_type * bus) { - rwlock_init(&bus->lock); + init_rwsem(&bus->rwsem); INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->drivers); atomic_set(&bus->refcount,2); + bus->present = 1; spin_lock(&device_lock); list_add_tail(&bus->node,&bus_driver_list); @@ -156,13 +299,14 @@ int bus_register(struct bus_type * bus) return 0; } -void put_bus(struct bus_type * bus) +void bus_unregister(struct bus_type * bus) { - if (!atomic_dec_and_lock(&bus->refcount,&device_lock)) - return; - list_del_init(&bus->node); + spin_lock(&device_lock); + bus->present = 0; spin_unlock(&device_lock); - bus_remove_dir(bus); + + pr_debug("bus %s: unregistering\n",bus->name); + put_bus(bus); } EXPORT_SYMBOL(bus_for_each_dev); @@ -170,4 +314,6 @@ EXPORT_SYMBOL(bus_for_each_drv); EXPORT_SYMBOL(bus_add_device); EXPORT_SYMBOL(bus_remove_device); EXPORT_SYMBOL(bus_register); +EXPORT_SYMBOL(bus_unregister); +EXPORT_SYMBOL(get_bus); EXPORT_SYMBOL(put_bus); diff --git a/drivers/base/class.c b/drivers/base/class.c index dfef9793871a..7328f3231a65 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -10,27 +10,29 @@ static LIST_HEAD(class_list); int devclass_add_driver(struct device_driver * drv) { - if (drv->devclass) { - pr_debug("Registering driver %s:%s with class %s\n", - drv->bus->name,drv->name,drv->devclass->name); - - spin_lock(&device_lock); - list_add_tail(&drv->class_list,&drv->devclass->drivers); - spin_unlock(&device_lock); + struct device_class * cls = get_devclass(drv->devclass); + if (cls) { + down_write(&cls->rwsem); + pr_debug("device class %s: adding driver %s:%s\n", + cls->name,drv->bus->name,drv->name); + list_add_tail(&drv->class_list,&cls->drivers); devclass_drv_link(drv); + up_write(&cls->rwsem); } return 0; } void devclass_remove_driver(struct device_driver * drv) { - if (drv->devclass) { - pr_debug("Removing driver %s:%s:%s\n", - drv->devclass->name,drv->bus->name,drv->name); - spin_lock(&device_lock); + struct device_class * cls = drv->devclass; + if (cls) { + down_write(&cls->rwsem); + pr_debug("device class %s: removing driver %s:%s\n", + cls->name,drv->bus->name,drv->name); list_del_init(&drv->class_list); - spin_unlock(&device_lock); devclass_drv_unlink(drv); + up_write(&cls->rwsem); + put_devclass(cls); } } @@ -38,9 +40,7 @@ void devclass_remove_driver(struct device_driver * drv) static void enum_device(struct device_class * cls, struct device * dev) { u32 val; - spin_lock(&device_lock); val = cls->devnum++; - spin_unlock(&device_lock); dev->class_num = val; devclass_dev_link(cls,dev); } @@ -51,18 +51,44 @@ static void unenum_device(struct device_class * cls, struct device * dev) dev->class_num = 0; } +/** + * devclass_add_device - register device with device class + * @dev: device to be registered + * + * This is called when a device is either registered with the + * core, or after the a driver module is loaded and bound to + * the device. + * The class is determined by looking at @dev's driver, so one + * way or another, it must be bound to something. Once the + * class is determined, it's set to prevent against concurrent + * calls for the same device stomping on each other. + * + * /sbin/hotplug should be called once the device is added to + * class and all the interfaces. + */ int devclass_add_device(struct device * dev) { - struct device_class * cls = dev->driver->devclass; + struct device_class * cls; int error = 0; - if (cls) { - pr_debug("adding device '%s' to class '%s'\n", - dev->name,cls->name); - if (cls->add_device) - error = cls->add_device(dev); - if (!error) { - enum_device(cls,dev); - interface_add(cls,dev); + + if (dev->driver) { + cls = get_devclass(dev->driver->devclass); + if (cls) { + down_write(&cls->rwsem); + pr_debug("device class %s: adding device %s\n", + cls->name,dev->name); + if (cls->add_device) + error = cls->add_device(dev); + if (!error) { + enum_device(cls,dev); + interface_add(cls,dev); + } + + /* notify userspace (call /sbin/hotplug) here */ + + up_write(&cls->rwsem); + if (error) + put_devclass(cls); } } return error; @@ -70,40 +96,74 @@ int devclass_add_device(struct device * dev) void devclass_remove_device(struct device * dev) { - struct device_class * cls = dev->driver->devclass; - if (cls) { - pr_debug("removing device '%s' from class '%s'\n", - dev->name,cls->name); - interface_remove(cls,dev); - unenum_device(cls,dev); - if (cls->remove_device) - cls->remove_device(dev); + struct device_class * cls; + + if (dev->driver) { + cls = dev->driver->devclass; + if (cls) { + down_write(&cls->rwsem); + pr_debug("device class %s: removing device %s\n", + cls->name,dev->name); + interface_remove(cls,dev); + unenum_device(cls,dev); + if (cls->remove_device) + cls->remove_device(dev); + up_write(&cls->rwsem); + put_devclass(cls); + } } } +struct device_class * get_devclass(struct device_class * cls) +{ + struct device_class * ret = cls; + spin_lock(&device_lock); + if (cls && cls->present && atomic_read(&cls->refcount) > 0) + atomic_inc(&cls->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + +void put_devclass(struct device_class * cls) +{ + if (atomic_dec_and_lock(&cls->refcount,&device_lock)) { + list_del_init(&cls->node); + spin_unlock(&device_lock); + devclass_remove_dir(cls); + } +} + + int devclass_register(struct device_class * cls) { INIT_LIST_HEAD(&cls->drivers); INIT_LIST_HEAD(&cls->intf_list); - - pr_debug("registering device class '%s'\n",cls->name); + init_rwsem(&cls->rwsem); + atomic_set(&cls->refcount,2); + cls->present = 1; + pr_debug("device class '%s': registering\n",cls->name); spin_lock(&device_lock); list_add_tail(&cls->node,&class_list); spin_unlock(&device_lock); devclass_make_dir(cls); + put_devclass(cls); return 0; } void devclass_unregister(struct device_class * cls) { - pr_debug("unregistering device class '%s'\n",cls->name); - devclass_remove_dir(cls); spin_lock(&device_lock); - list_del_init(&class_list); + cls->present = 0; spin_unlock(&device_lock); + pr_debug("device class '%s': unregistering\n",cls->name); + put_devclass(cls); } EXPORT_SYMBOL(devclass_register); EXPORT_SYMBOL(devclass_unregister); +EXPORT_SYMBOL(get_devclass); +EXPORT_SYMBOL(put_devclass); diff --git a/drivers/base/core.c b/drivers/base/core.c index 83c31723d844..bd82a792d877 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -19,136 +19,12 @@ LIST_HEAD(global_device_list); int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL; +DECLARE_MUTEX(device_sem); + spinlock_t device_lock = SPIN_LOCK_UNLOCKED; #define to_dev(node) container_of(node,struct device,driver_list) -static int probe(struct device * dev, struct device_driver * drv) -{ - dev->driver = drv; - return drv->probe ? drv->probe(dev) : 0; -} - -static void attach(struct device * dev) -{ - spin_lock(&device_lock); - list_add_tail(&dev->driver_list,&dev->driver->devices); - spin_unlock(&device_lock); - devclass_add_device(dev); -} - -/** - * found_match - do actual binding of device to driver - * @dev: device - * @drv: driver - * - * We're here because the bus's match callback returned success for this - * pair. We call the driver's probe callback to verify they're really a - * match made in heaven. - * - * In the future, we may want to notify userspace of the binding. (But, - * we might not want to do it here). - * - * We may also want to create a symlink in the driver's directory to the - * device's physical directory. - */ -static int found_match(struct device * dev, struct device_driver * drv) -{ - int error = 0; - - if (!(error = probe(dev,get_driver(drv)))) { - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id,drv->name); - attach(dev); - } else { - put_driver(drv); - dev->driver = NULL; - } - return error; -} - -/** - * device_attach - try to associated device with a driver - * @drv: current driver to try - * @data: device in disguise - * - * This function is used as a callback to bus_for_each_drv. - * It calls the bus's match callback to check if the driver supports - * the device. If so, it calls the found_match() function above to - * take care of all the details. - */ -static int do_device_attach(struct device_driver * drv, void * data) -{ - struct device * dev = (struct device *)data; - int error = 0; - - if (drv->bus->match && drv->bus->match(dev,drv)) - error = found_match(dev,drv); - return error; -} - -static int device_attach(struct device * dev) -{ - int error = 0; - if (!dev->driver) { - if (dev->bus) - error = bus_for_each_drv(dev->bus,dev,do_device_attach); - } else - attach(dev); - return error; -} - -static void device_detach(struct device * dev) -{ - struct device_driver * drv = dev->driver; - - if (drv) { - devclass_remove_device(dev); - if (drv && drv->remove) - drv->remove(dev); - dev->driver = NULL; - } -} - -static int do_driver_attach(struct device * dev, void * data) -{ - struct device_driver * drv = (struct device_driver *)data; - int error = 0; - - if (!dev->driver) { - if (dev->bus->match && dev->bus->match(dev,drv)) - error = found_match(dev,drv); - } - return error; -} - -int driver_attach(struct device_driver * drv) -{ - return bus_for_each_dev(drv->bus,drv,do_driver_attach); -} - -void driver_detach(struct device_driver * drv) -{ - struct list_head * node; - struct device * prev = NULL; - - spin_lock(&device_lock); - list_for_each(node,&drv->devices) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - if (prev) - list_del_init(&prev->driver_list); - spin_unlock(&device_lock); - device_detach(dev); - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); - } - } - spin_unlock(&device_lock); -} - int device_add(struct device *dev) { int error; @@ -156,14 +32,14 @@ int device_add(struct device *dev) if (!dev || !strlen(dev->bus_id)) return -EINVAL; - spin_lock(&device_lock); - dev->present = 1; + down(&device_sem); + dev->state = DEVICE_REGISTERED; if (dev->parent) { list_add_tail(&dev->g_list,&dev->parent->g_list); list_add_tail(&dev->node,&dev->parent->children); } else list_add_tail(&dev->g_list,&global_device_list); - spin_unlock(&device_lock); + up(&device_sem); pr_debug("DEV: registering device: ID = '%s', name = %s\n", dev->bus_id, dev->name); @@ -173,9 +49,6 @@ int device_add(struct device *dev) bus_add_device(dev); - /* bind to driver */ - device_attach(dev); - /* notify platform of device entry */ if (platform_notify) platform_notify(dev); @@ -183,12 +56,13 @@ int device_add(struct device *dev) /* notify userspace of device entry */ dev_hotplug(dev, "add"); + devclass_add_device(dev); register_done: if (error) { - spin_lock(&device_lock); + up(&device_sem); list_del_init(&dev->g_list); list_del_init(&dev->node); - spin_unlock(&device_lock); + up(&device_sem); } return error; } @@ -203,6 +77,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->intf_list); spin_lock_init(&dev->lock); atomic_set(&dev->refcount,1); + dev->state = DEVICE_INITIALIZED; if (dev->parent) get_device(dev->parent); } @@ -234,22 +109,15 @@ int device_register(struct device *dev) return error; } -struct device * get_device_locked(struct device * dev) +struct device * get_device(struct device * dev) { struct device * ret = dev; - if (dev && dev->present && atomic_read(&dev->refcount) > 0) + down(&device_sem); + if (device_present(dev) && atomic_read(&dev->refcount) > 0) atomic_inc(&dev->refcount); else ret = NULL; - return ret; -} - -struct device * get_device(struct device * dev) -{ - struct device * ret; - spin_lock(&device_lock); - ret = get_device_locked(dev); - spin_unlock(&device_lock); + up(&device_sem); return ret; } @@ -259,34 +127,23 @@ struct device * get_device(struct device * dev) */ void put_device(struct device * dev) { - struct device * parent; - if (!atomic_dec_and_lock(&dev->refcount,&device_lock)) + down(&device_sem); + if (!atomic_dec_and_test(&dev->refcount)) { + up(&device_sem); return; - parent = dev->parent; - dev->parent = NULL; - spin_unlock(&device_lock); + } + list_del_init(&dev->node); + list_del_init(&dev->g_list); + up(&device_sem); - BUG_ON(dev->present); + BUG_ON((dev->state != DEVICE_GONE)); - if (dev->release) - dev->release(dev); - - if (parent) - put_device(parent); + device_del(dev); } void device_del(struct device * dev) { - spin_lock(&device_lock); - dev->present = 0; - list_del_init(&dev->node); - list_del_init(&dev->g_list); - list_del_init(&dev->bus_list); - list_del_init(&dev->driver_list); - spin_unlock(&device_lock); - - pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", - dev->bus_id,dev->name); + struct device * parent = dev->parent; /* Notify the platform of the removal, in case they * need to do anything... @@ -297,11 +154,16 @@ void device_del(struct device * dev) /* notify userspace that this device is about to disappear */ dev_hotplug (dev, "remove"); - device_detach(dev); bus_remove_device(dev); /* remove the driverfs directory */ device_remove_dir(dev); + + if (dev->release) + dev->release(dev); + + if (parent) + put_device(parent); } /** @@ -315,22 +177,15 @@ void device_del(struct device * dev) */ void device_unregister(struct device * dev) { - device_del(dev); - put_device(dev); -} - -static int __init device_init(void) -{ - int error; + down(&device_sem); + dev->state = DEVICE_GONE; + up(&device_sem); - error = init_driverfs_fs(); - if (error) - panic("DEV: could not initialize driverfs"); - return 0; + pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", + dev->bus_id,dev->name); + put_device(dev); } -core_initcall(device_init); - EXPORT_SYMBOL(device_register); EXPORT_SYMBOL(device_unregister); EXPORT_SYMBOL(get_device); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 221e525736bd..4bf4a005b918 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -16,29 +16,61 @@ int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback)(struct device *, void * )) { struct list_head * node; - struct device * prev = NULL; int error = 0; - get_driver(drv); - spin_lock(&device_lock); - list_for_each(node,&drv->devices) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - spin_unlock(&device_lock); - error = callback(dev,data); - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); - if (error) - break; + drv = get_driver(drv); + if (drv) { + down_read(&drv->bus->rwsem); + list_for_each(node,&drv->devices) { + struct device * dev = get_device(to_dev(node)); + if (dev) { + error = callback(dev,data); + put_device(dev); + if (error) + break; + } } + up_read(&drv->bus->rwsem); + put_driver(drv); } - spin_unlock(&device_lock); - put_driver(drv); return error; } +struct device_driver * get_driver(struct device_driver * drv) +{ + struct device_driver * ret = drv; + spin_lock(&device_lock); + if (drv && drv->present && atomic_read(&drv->refcount) > 0) + atomic_inc(&drv->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + + +void remove_driver(struct device_driver * drv) +{ + BUG(); +} + +/** + * put_driver - decrement driver's refcount and clean up if necessary + * @drv: driver in question + */ +void put_driver(struct device_driver * drv) +{ + struct bus_type * bus = drv->bus; + if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) + return; + spin_unlock(&device_lock); + BUG_ON(drv->present); + bus_remove_driver(drv); + if (drv->release) + drv->release(drv); + put_bus(bus); +} + /** * driver_register - register driver with bus * @drv: driver to register @@ -50,54 +82,29 @@ int driver_register(struct device_driver * drv) if (!drv->bus) return -EINVAL; - pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name); + pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name); get_bus(drv->bus); atomic_set(&drv->refcount,2); rwlock_init(&drv->lock); INIT_LIST_HEAD(&drv->devices); - spin_lock(&device_lock); - list_add(&drv->bus_list,&drv->bus->drivers); - spin_unlock(&device_lock); - driver_make_dir(drv); - driver_attach(drv); + drv->present = 1; + bus_add_driver(drv); put_driver(drv); return 0; } -static void __remove_driver(struct device_driver * drv) -{ - pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name); - driver_detach(drv); - driver_remove_dir(drv); - if (drv->release) - drv->release(drv); - put_bus(drv->bus); -} - -void remove_driver(struct device_driver * drv) +void driver_unregister(struct device_driver * drv) { spin_lock(&device_lock); - atomic_set(&drv->refcount,0); - list_del_init(&drv->bus_list); + drv->present = 0; spin_unlock(&device_lock); - __remove_driver(drv); -} - -/** - * put_driver - decrement driver's refcount and clean up if necessary - * @drv: driver in question - */ -void put_driver(struct device_driver * drv) -{ - if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) - return; - list_del_init(&drv->bus_list); - spin_unlock(&device_lock); - __remove_driver(drv); + pr_debug("driver %s:%s: unregistering\n",drv->bus->name,drv->name); + put_driver(drv); } EXPORT_SYMBOL(driver_for_each_dev); EXPORT_SYMBOL(driver_register); +EXPORT_SYMBOL(driver_unregister); +EXPORT_SYMBOL(get_driver); EXPORT_SYMBOL(put_driver); -EXPORT_SYMBOL(remove_driver); diff --git a/drivers/base/interface.c b/drivers/base/interface.c index a585b729c5c4..8a5c6e6bc226 100644 --- a/drivers/base/interface.c +++ b/drivers/base/interface.c @@ -19,7 +19,7 @@ static DEVICE_ATTR(name,S_IRUGO,device_read_name,NULL); static ssize_t device_read_power(struct device * dev, char * page, size_t count, loff_t off) { - return off ? 0 : sprintf(page,"%d\n",dev->current_state); + return off ? 0 : sprintf(page,"%d\n",dev->power_state); } static ssize_t diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 29c90e34e67e..3856bc52b411 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -39,7 +39,7 @@ int platform_device_register(struct platform_device * pdev) void platform_device_unregister(struct platform_device * pdev) { if (pdev) - put_device(&pdev->dev); + device_unregister(&pdev->dev); } static int platform_match(struct device * dev, struct device_driver * drv) diff --git a/drivers/base/power.c b/drivers/base/power.c index c98984dfd8ab..176be19b72d1 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -8,6 +8,8 @@ * */ +#define DEBUG 0 + #include <linux/device.h> #include <linux/module.h> #include "base.h" @@ -28,34 +30,21 @@ int device_suspend(u32 state, u32 level) { struct list_head * node; - struct device * prev = NULL; int error = 0; - if(level == SUSPEND_POWER_DOWN) - printk(KERN_EMERG "Shutting down devices\n"); - else - printk(KERN_EMERG "Suspending devices\n"); + printk(KERN_EMERG "Suspending devices\n"); - spin_lock(&device_lock); + down(&device_sem); list_for_each(node,&global_device_list) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - spin_unlock(&device_lock); - if(dev->driver) { - if(level == SUSPEND_POWER_DOWN) { - if(dev->driver->remove) - dev->driver->remove(dev); - } else if(dev->driver->suspend) - error = dev->driver->suspend(dev,state,level); - } - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); + struct device * dev = to_dev(node); + if (device_present(dev) && dev->driver && dev->driver->suspend) { + pr_debug("suspending device %s\n",dev->name); + error = dev->driver->suspend(dev,state,level); + if (error) + printk(KERN_ERR "%s: suspend returned %d\n",dev->name,error); } } - spin_unlock(&device_lock); - + up(&device_sem); return error; } @@ -70,33 +59,38 @@ int device_suspend(u32 state, u32 level) void device_resume(u32 level) { struct list_head * node; - struct device * prev = NULL; - spin_lock(&device_lock); + down(&device_sem); list_for_each_prev(node,&global_device_list) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - spin_unlock(&device_lock); - if (dev->driver && dev->driver->resume) - dev->driver->resume(dev,level); - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); + struct device * dev = to_dev(node); + if (device_present(dev) && dev->driver && dev->driver->resume) { + pr_debug("resuming device %s\n",dev->name); + dev->driver->resume(dev,level); } } - spin_unlock(&device_lock); + up(&device_sem); printk(KERN_EMERG "Devices Resumed\n"); } /** - * device_shutdown - call device_suspend with status set to shutdown, to - * cause all devices to remove themselves cleanly + * device_shutdown - call ->remove() on each device to shutdown. */ void device_shutdown(void) { - device_suspend(4, SUSPEND_POWER_DOWN); + struct list_head * entry; + + printk(KERN_EMERG "Shutting down devices\n"); + + down(&device_sem); + list_for_each(entry,&global_device_list) { + struct device * dev = to_dev(entry); + if (device_present(dev) && dev->driver && dev->driver->shutdown) { + pr_debug("shutting down %s\n",dev->name); + dev->driver->shutdown(dev); + } + } + up(&device_sem); } EXPORT_SYMBOL(device_suspend); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index a61fea973d36..cd681d1190bd 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -10,6 +10,8 @@ * add themselves as children of the system bus. */ +#define DEBUG 1 + #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> @@ -76,8 +78,8 @@ int sys_register_root(struct sys_root * root) */ void sys_unegister_root(struct sys_root * root) { - put_device(&root->sysdev); - put_device(&root->dev); + device_unregister(&root->sysdev); + device_unregister(&root->dev); } /** @@ -125,7 +127,7 @@ int sys_device_register(struct sys_device * sysdev) void sys_device_unregister(struct sys_device * sysdev) { if (sysdev) - put_device(&sysdev->dev); + device_unregister(&sysdev->dev); } struct bus_type system_bus_type = { diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 1c1a72e440e6..dca532fef7a2 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -75,18 +75,18 @@ static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers] = { NULL }; -static int DAC960_revalidate(kdev_t); +static int DAC960_revalidate(struct gendisk *); /* DAC960_BlockDeviceOperations is the Block Device Operations structure for DAC960 Logical Disk Devices. */ static struct block_device_operations DAC960_BlockDeviceOperations = { - owner: THIS_MODULE, - open: DAC960_Open, - release: DAC960_Release, - ioctl: DAC960_IOCTL, - revalidate: DAC960_revalidate, + .owner = THIS_MODULE, + .open = DAC960_Open, + .release = DAC960_Release, + .ioctl = DAC960_IOCTL, + .revalidate_disk= DAC960_revalidate, }; @@ -308,9 +308,9 @@ static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) static void DAC960_WaitForCommand(DAC960_Controller_T *Controller) { - spin_unlock_irq(Controller->RequestQueue->queue_lock); + spin_unlock_irq(Controller->RequestQueue.queue_lock); __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands); - spin_lock_irq(Controller->RequestQueue->queue_lock); + spin_lock_irq(Controller->RequestQueue.queue_lock); } @@ -1931,7 +1931,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) { int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; RequestQueue_T *RequestQueue; - int MinorNumber; int n; /* @@ -1947,7 +1946,7 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) /* Initialize the I/O Request Queue. */ - RequestQueue = BLK_DEFAULT_QUEUE(MajorNumber); + RequestQueue = &Controller->RequestQueue; Controller->queue_lock = SPIN_LOCK_UNLOCKED; blk_init_queue(RequestQueue, DAC960_RequestFunction, &Controller->queue_lock); RequestQueue->queuedata = Controller; @@ -1956,7 +1955,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) blk_queue_max_phys_segments(RequestQueue, ~0); blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand); - Controller->RequestQueue = RequestQueue; for (n = 0; n < DAC960_MaxLogicalDrives; n++) { struct gendisk *disk = Controller->disks[n]; sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n); @@ -1989,7 +1987,7 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) /* Remove the I/O Request Queue. */ - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MajorNumber)); + blk_cleanup_queue(&Controller->RequestQueue); } static long disk_size(DAC960_Controller_T *Controller, int disk) @@ -2019,12 +2017,16 @@ static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller) set_capacity(Controller->disks[disk], disk_size(Controller, disk)); } -static int DAC960_revalidate(kdev_t dev) +static int DAC960_revalidate(struct gendisk *disk) { - int ctlr = DAC960_ControllerNumber(dev); - int disk = DAC960_LogicalDriveNumber(dev); - DAC960_Controller_T *p = DAC960_Controllers[ctlr]; - set_capacity(p->disks[disk], disk_size(p, disk)); + DAC960_Controller_T *p = disk->private_data; + int unit; + for (unit = 0; unit < DAC960_MaxLogicalDrives; unit++) { + if (p->disks[unit] == disk) { + set_capacity(disk, disk_size(p, unit)); + return 0; + } + } return 0; } @@ -2093,6 +2095,7 @@ static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller, static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) { void (*InterruptHandler)(int, void *, Registers_T *) = NULL; + DAC960_Controller_T *Controller = NULL; DAC960_FirmwareType_T FirmwareType = 0; unsigned short VendorID = 0, DeviceID = 0; unsigned int MemoryWindowSize = 0; @@ -2145,7 +2148,6 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) } while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL) { - DAC960_Controller_T *Controller = NULL; DAC960_IO_Address_T IO_Address = 0; DAC960_PCI_Address_T PCI_Address = 0; unsigned char Bus = PCI_Device->bus->number; @@ -2155,6 +2157,7 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) unsigned char ErrorStatus, Parameter0, Parameter1; unsigned int IRQ_Channel = PCI_Device->irq; void *BaseAddress; + Controller = NULL; if (pci_enable_device(PCI_Device) != 0) continue; switch (HardwareType) { @@ -2202,6 +2205,8 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits); if (!Controller->disks[i]) goto Enomem; + Controller->disks[i]->private_data = Controller; + Controller->disks[i]->queue = &Controller->RequestQueue; } Controller->ControllerNumber = DAC960_ControllerCount; init_waitqueue_head(&Controller->CommandWaitQueue); @@ -2831,7 +2836,7 @@ static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *Command) static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, boolean WaitForCommand) { - RequestQueue_T *RequestQueue = Controller->RequestQueue; + RequestQueue_T *RequestQueue = &Controller->RequestQueue; ListHead_T *RequestQueueHead; IO_Request_T *Request; DAC960_Command_T *Command; @@ -5225,7 +5230,6 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData) } } - /* DAC960_Open is the Device Open Function for the DAC960 Driver. */ @@ -5265,9 +5269,8 @@ static int DAC960_Open(Inode_T *Inode, File_T *File) long size; Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true; size = disk_size(Controller, LogicalDriveNumber); - /* BROKEN, same as modular ide-floppy/ide-disk; same fix - ->probe() */ set_capacity(Controller->disks[LogicalDriveNumber], size); - add_disk(Controller->disks[LogicalDriveNumber]); + Inode->i_bdev->bd_invalidated = 1; } if (!get_capacity(Controller->disks[LogicalDriveNumber])) return -ENXIO; @@ -5314,7 +5317,6 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File, int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); DiskGeometry_T Geometry, *UserGeometry; DAC960_Controller_T *Controller; - int res; if (File != NULL && (File->f_flags & O_NONBLOCK)) return DAC960_UserIOCTL(Inode, File, Request, Argument); @@ -5379,7 +5381,7 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File, static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, unsigned int Request, unsigned long Argument) { - int ErrorCode; + int ErrorCode = 0; if (!capable(CAP_SYS_ADMIN)) return -EACCES; switch (Request) { @@ -5492,11 +5494,11 @@ static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, while (Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID]) { - spin_unlock_irq(Controller->RequestQueue->queue_lock); + spin_unlock_irq(Controller->RequestQueue.queue_lock); __wait_event(Controller->CommandWaitQueue, !Controller->V1.DirectCommandActive [DCDB.Channel][DCDB.TargetID]); - spin_lock_irq(Controller->RequestQueue->queue_lock); + spin_lock_irq(Controller->RequestQueue.queue_lock); } Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID] = true; diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index fcc3ac714542..e66cd95f87dd 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2364,7 +2364,7 @@ typedef struct DAC960_Controller DAC960_Command_T *FreeCommands; unsigned char *CombinedStatusBuffer; unsigned char *CurrentStatusBuffer; - RequestQueue_T *RequestQueue; + RequestQueue_T RequestQueue; spinlock_t queue_lock; WaitQueue_T CommandWaitQueue; WaitQueue_T HealthStatusWaitQueue; @@ -2504,7 +2504,7 @@ static inline void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_lock_irqsave(Controller->RequestQueue->queue_lock, *ProcessorFlags); + spin_lock_irqsave(Controller->RequestQueue.queue_lock, *ProcessorFlags); } @@ -2516,7 +2516,7 @@ static inline void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_unlock_irqrestore(Controller->RequestQueue->queue_lock, *ProcessorFlags); + spin_unlock_irqrestore(Controller->RequestQueue.queue_lock, *ProcessorFlags); } @@ -2553,7 +2553,7 @@ static inline void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_lock_irqsave(Controller->RequestQueue->queue_lock, *ProcessorFlags); + spin_lock_irqsave(Controller->RequestQueue.queue_lock, *ProcessorFlags); } @@ -2566,7 +2566,7 @@ static inline void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_unlock_irqrestore(Controller->RequestQueue->queue_lock, *ProcessorFlags); + spin_unlock_irqrestore(Controller->RequestQueue.queue_lock, *ProcessorFlags); } #error I am a non-portable driver, please convert me to use the Documentation/DMA-mapping.txt interfaces diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 520eeabab869..8b3daa5771c6 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -45,7 +45,6 @@ #define MAJOR_NR ACSI_MAJOR #define DEVICE_NAME "ACSI" -#define DEVICE_NR(device) (minor(device) >> 4) #include <linux/config.h> #include <linux/module.h> @@ -59,6 +58,7 @@ #include <linux/delay.h> #include <linux/mm.h> #include <linux/major.h> +#define QUEUE (&acsi_queue) #include <linux/blk.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -80,6 +80,7 @@ typedef void Scsi_Device; /* hack to avoid including scsi.h */ #include <asm/atari_stram.h> static void (*do_acsi)(void) = NULL; +static struct request_queue acsi_queue; #define DEBUG #undef DEBUG_DETECT @@ -119,6 +120,7 @@ struct acsi_info_struct { unsigned old_atari_disk : 1; /* Is an old Atari disk */ unsigned changed : 1; /* Medium has been changed */ unsigned long size; /* #blocks */ + int access_count; } acsi_info[MAX_DEV]; /* @@ -232,8 +234,8 @@ typedef union { /* Default size if capacity cannot be determined (1 GByte) */ #define DEFAULT_SIZE 0x1fffff -#define CARTRCH_STAT(dev,buf) \ - (acsi_info[(dev)].old_atari_disk ? \ +#define CARTRCH_STAT(aip,buf) \ + (aip->old_atari_disk ? \ (((buf)[0] & 0x7f) == 0x28) : \ ((((buf)[0] & 0x70) == 0x70) ? \ (((buf)[2] & 0x0f) == 0x06) : \ @@ -245,7 +247,6 @@ char *acsi_buffer; unsigned long phys_acsi_buffer; static int NDevices; -static int access_count[MAX_DEV]; static int CurrentNReq; static int CurrentNSect; @@ -348,7 +349,7 @@ struct acsi_error { static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable); static int acsi_reqsense( char *buffer, int targ, int lun); -static void acsi_print_error( const unsigned char *errblk, int dev ); +static void acsi_print_error(const unsigned char *errblk, int struct acsi_info_struct *aip); static void acsi_interrupt (int irq, void *data, struct pt_regs *fp); static void unexpected_acsi_interrupt( void ); static void bad_rw_intr( void ); @@ -364,10 +365,10 @@ static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static int acsi_open( struct inode * inode, struct file * filp ); static int acsi_release( struct inode * inode, struct file * file ); -static void acsi_prevent_removal( int target, int flag ); +static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag ); static int acsi_change_blk_size( int target, int lun); static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ); -static int acsi_revalidate (kdev_t); +static int acsi_revalidate (struct gendisk *disk); /************************* End of Prototypes **************************/ @@ -691,12 +692,12 @@ int acsi_extcmd( unsigned char *buffer, int cnt ) #endif -static void acsi_print_error( const unsigned char *errblk, int dev ) +static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip) { int atari_err, i, errcode; struct acsi_error *arr; - atari_err = acsi_info[dev].old_atari_disk; + atari_err = aip->old_atari_disk; if (atari_err) errcode = errblk[0] & 0x7f; else @@ -780,15 +781,15 @@ static void read_intr( void ) status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(CURRENT->rq_dev); - printk( KERN_ERR "ad%c: ", dev+'a' ); - if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, - acsi_info[dev].lun)) + struct gendisk *disk = CURRENT->rq_disk; + struct acsi_info_struct *aip = disk->private_data; + printk(KERN_ERR "%s: ", disk->disk_name); + if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); else { - acsi_print_error( acsi_buffer, dev ); - if (CARTRCH_STAT( dev, acsi_buffer )) - acsi_info[dev].changed = 1; + acsi_print_error(acsi_buffer, aip); + if (CARTRCH_STAT(aip, acsi_buffer)) + aip->changed = 1; } ENABLE_IRQ(); bad_rw_intr(); @@ -811,15 +812,15 @@ static void write_intr(void) status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(CURRENT->rq_dev); - printk( KERN_ERR "ad%c: ", dev+'a' ); - if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, - acsi_info[dev].lun)) + struct gendisk *disk = CURRENT->rq_disk; + struct acsi_info_struct *aip = disk->private_data; + printk( KERN_ERR "%s: ", disk->disk_name); + if (!acsi_reqsense( acsi_buffer, aip->target, aip->lun)) printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); else { - acsi_print_error( acsi_buffer, dev ); - if (CARTRCH_STAT( dev, acsi_buffer )) - acsi_info[dev].changed = 1; + acsi_print_error(acsi_buffer, aip); + if (CARTRCH_STAT(aip, acsi_buffer)) + aip->changed = 1; } bad_rw_intr(); redo_acsi_request(); @@ -944,11 +945,13 @@ static void do_acsi_request( request_queue_t * q ) static void redo_acsi_request( void ) - -{ unsigned block, dev, target, lun, nsect; +{ + unsigned block, target, lun, nsect; char *buffer; unsigned long pbuffer; struct buffer_head *bh; + struct gendisk *disk; + struct acsi_info_struct *aip; repeat: CLEAR_TIMER(); @@ -963,35 +966,33 @@ static void redo_acsi_request( void ) return; } - if (major(CURRENT->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": request list destroyed"); + disk = CURRENT->rq_disk; + aip = disk->private_data; if (CURRENT->bh) { if (!CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); } - dev = DEVICE_NR(CURRENT->rq_dev); block = CURRENT->sector; - if (dev >= NDevices || - block+CURRENT->nr_sectors >= get_capacity(acsi_gendisk[dev])) { + if (block+CURRENT->nr_sectors >= get_capacity(disk)) { #ifdef DEBUG - printk( "ad%c: attempted access for blocks %d...%ld past end of device at block %ld.\n", - dev+'a', + printk( "%s: attempted access for blocks %d...%ld past end of device at block %ld.\n", + disk->disk_name, block, block + CURRENT->nr_sectors - 1, - get_capacity(acsi_gendisk[dev])); + get_capacity(disk)); #endif end_request(CURRENT, 0); goto repeat; } - if (acsi_info[dev].changed) { - printk( KERN_NOTICE "ad%c: request denied because cartridge has " - "been changed.\n", dev+'a' ); + if (aip->changed) { + printk( KERN_NOTICE "%s: request denied because cartridge has " + "been changed.\n", disk->disk_name); end_request(CURRENT, 0); goto repeat; } - target = acsi_info[dev].target; - lun = acsi_info[dev].lun; + target = aip->target; + lun = aip->lun; /* Find out how many sectors should be transferred from/to * consecutive buffers and thus can be done with a single command. @@ -1085,7 +1086,8 @@ static void redo_acsi_request( void ) static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { - int dev = DEVICE_NR(inode->i_rdev); + struct gendisk *disk = inode->i_bdev->bd_disk; + struct acsi_info_struct *aip = disk->private_data; switch (cmd) { case HDIO_GETGEO: /* HDIO_GETGEO is supported more for getting the partition's @@ -1095,13 +1097,13 @@ static int acsi_ioctl( struct inode *inode, struct file *file, * easy, use Adaptec's usual 64/32 mapping */ put_user( 64, &geo->heads ); put_user( 32, &geo->sectors ); - put_user( acsi_info[dev].size >> 11, &geo->cylinders ); + put_user( aip->size >> 11, &geo->cylinders ); put_user(get_start_sect(inode->i_bdev), &geo->start); return 0; } case SCSI_IOCTL_GET_IDLUN: /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ - put_user( acsi_info[dev].target | (acsi_info[dev].lun << 8), + put_user( aip->target | (aip->lun << 8), &((Scsi_Idlun *) arg)->dev_id ); put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); return 0; @@ -1128,19 +1130,19 @@ static int acsi_ioctl( struct inode *inode, struct file *file, static int acsi_open( struct inode * inode, struct file * filp ) { - int device = DEVICE_NR(inode->i_rdev); - struct acsi_info_struct *aip = &acsi_info[device]; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct acsi_info_struct *aip = disk->private_data; - if (access_count[device] == 0 && aip->removable) { + if (aip->access_count == 0 && aip->removable) { #if 0 aip->changed = 1; /* safety first */ #endif check_disk_change( inode->i_bdev ); if (aip->changed) /* revalidate was not successful (no medium) */ return -ENXIO; - acsi_prevent_removal(device, 1); + acsi_prevent_removal(aip, 1); } - access_count[device]++; + aip->access_count++; if (filp && filp->f_mode) { check_disk_change( inode->i_bdev ); @@ -1162,9 +1164,10 @@ static int acsi_open( struct inode * inode, struct file * filp ) static int acsi_release( struct inode * inode, struct file * file ) { - int device = DEVICE_NR(inode->i_rdev); - if (--access_count[device] == 0 && acsi_info[device].removable) - acsi_prevent_removal(device, 0); + struct gendisk *disk = inode->i_bdev->bd_disk; + struct acsi_info_struct *aip = disk->private_data; + if (--aip->access_count == 0 && aip->removable) + acsi_prevent_removal(aip, 0); return( 0 ); } @@ -1172,12 +1175,11 @@ static int acsi_release( struct inode * inode, struct file * file ) * Prevent or allow a media change for removable devices. */ -static void acsi_prevent_removal(int device, int flag) +static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag) { stdma_lock( NULL, NULL ); - CMDSET_TARG_LUN(pa_med_rem_cmd, acsi_info[device].target, - acsi_info[device].lun); + CMDSET_TARG_LUN(pa_med_rem_cmd, aip->target, aip->lun); CMDSET_LEN( pa_med_rem_cmd, flag ); if (acsicmd_nodma(pa_med_rem_cmd, 0) && acsi_wait_for_IRQ(3*HZ)) @@ -1188,12 +1190,10 @@ static void acsi_prevent_removal(int device, int flag) stdma_release(); } -static int acsi_media_change (kdev_t dev) +static int acsi_media_change(struct gendisk *disk) { - int device = DEVICE_NR(dev); - struct acsi_info_struct *aip; + struct acsi_info_struct *aip = disk->private_data; - aip = &acsi_info[device]; if (!aip->removable) return 0; @@ -1214,19 +1214,19 @@ static int acsi_media_change (kdev_t dev) acsi_wait_for_IRQ(3*HZ)) { if (acsi_getstatus()) { if (acsi_reqsense(acsi_buffer, aip->target, aip->lun)) { - if (CARTRCH_STAT(device, acsi_buffer)) + if (CARTRCH_STAT(aip, acsi_buffer)) aip->changed = 1; } else { - printk( KERN_ERR "ad%c: REQUEST SENSE failed in test for " - "medium change; assuming a change\n", device + 'a' ); + printk( KERN_ERR "%s: REQUEST SENSE failed in test for " + "medium change; assuming a change\n", disk->disk_name ); aip->changed = 1; } } } else { - printk( KERN_ERR "ad%c: Test for medium changed timed out; " - "assuming a change\n", device + 'a'); + printk( KERN_ERR "%s: Test for medium changed timed out; " + "assuming a change\n", disk->disk_name); aip->changed = 1; } ENABLE_IRQ(); @@ -1591,12 +1591,12 @@ int SLM_devices[8]; #endif static struct block_device_operations acsi_fops = { - owner: THIS_MODULE, - open: acsi_open, - release: acsi_release, - ioctl: acsi_ioctl, - check_media_change: acsi_media_change, - revalidate: acsi_revalidate, + .owner = THIS_MODULE, + .open = acsi_open, + .release = acsi_release, + .ioctl = acsi_ioctl, + .media_changed = acsi_media_change, + .revalidate_disk= acsi_revalidate, }; #ifdef CONFIG_ATARI_SLM_MODULE @@ -1640,7 +1640,7 @@ int acsi_init( void ) phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_acsi_request, &acsi_lock); + blk_init_queue(&acsi_queue, do_acsi_request, &acsi_lock); #ifdef CONFIG_ATARI_SLM err = slm_init(); #endif @@ -1737,7 +1737,9 @@ int acsi_init( void ) disk->minors = 1; } disk->fops = &acsi_fops; + disk->private_data = &acsi_info[i]; set_capacity(disk, acsi_info[i].size); + disk->queue = &acsi_queue; add_disk(disk); } return 0; @@ -1745,7 +1747,7 @@ out4: while (i--) put_disk(acsi_gendisk[i]); out3: - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&acsi_queue); atari_stram_free( acsi_buffer ); out2: unregister_blkdev( MAJOR_NR, "ad" ); @@ -1772,7 +1774,7 @@ void cleanup_module(void) { int i; del_timer( &acsi_timer ); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&acsi_queue); atari_stram_free( acsi_buffer ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) @@ -1804,10 +1806,9 @@ void cleanup_module(void) * */ -static int acsi_revalidate(kdev_t dev) +static int acsi_revalidate(struct gendisk *disk) { - int unit = DEVICE_NR(dev); - struct acsi_info_struct *aip = &acsi_info[unit]; + struct acsi_info_struct *aip = disk->private_data; stdma_lock( NULL, NULL ); if (acsi_devinit(aip) != DEV_SUPPORTED) { printk( KERN_ERR "ACSI: revalidate failed for target %d lun %d\n", @@ -1820,6 +1821,6 @@ static int acsi_revalidate(kdev_t dev) ENABLE_IRQ(); stdma_release(); - set_capacity(acsi_gendisk[unit], aip->size); + set_capacity(disk, aip->size); return 0; } diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 9e6ae34ae194..c6481047ae64 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -81,7 +81,7 @@ #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" -#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#define QUEUE (&floppy_queue) #include <linux/blk.h> #undef DEBUG /* print _LOTS_ of infos */ @@ -123,6 +123,8 @@ static long int fd_def_df0 = FD_DD_3; /* default for df0 if it doesn't ident MODULE_PARM(fd_def_df0,"l"); MODULE_LICENSE("GPL"); +static struct request_queue floppy_queue; + /* * Macros */ @@ -1377,14 +1379,10 @@ static void redo_fd_request(void) return; } - if (major(CURRENT->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": request list destroyed"); - device = minor(CURRENT->rq_dev); if (device < 8) { /* manual selection */ drive = device & 3; - floppy = unit + drive; } else { /* Auto-detection */ #ifdef DEBUG @@ -1392,8 +1390,8 @@ static void redo_fd_request(void) printk("redo_fd_request: default to normal\n"); #endif drive = device & 3; - floppy = unit + drive; } + floppy = CURRENT->rq_disk->private_data; /* Here someone could investigate to be more efficient */ for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { @@ -1428,11 +1426,11 @@ static void redo_fd_request(void) switch (rq_data_dir(CURRENT)) { case READ: - memcpy(data, unit[drive].trackbuf + sector * 512, 512); + memcpy(data, floppy->trackbuf + sector * 512, 512); break; case WRITE: - memcpy(unit[drive].trackbuf + sector * 512, data, 512); + memcpy(floppy->trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ if (!fd_motor_on(drive)) { @@ -1446,7 +1444,7 @@ static void redo_fd_request(void) save_flags (flags); cli(); - unit[drive].dirty = 1; + floppy->dirty = 1; /* reset the timer */ del_timer (flush_track_timer + drive); @@ -1674,9 +1672,10 @@ static int floppy_release(struct inode * inode, struct file * filp) * to the desired drive, but it will probably not survive the sleep if * several floppies are used at the same time: thus the loop. */ -static int amiga_floppy_change(kdev_t dev) +static int amiga_floppy_change(struct gendisk *disk) { - int drive = minor(dev) & 3; + struct amiga_floppy_struct *p = disk->private_data; + int drive = p - unit; int changed; static int first_time = 1; @@ -1692,8 +1691,8 @@ static int amiga_floppy_change(kdev_t dev) if (changed) { fd_probe(drive); - unit[drive].track = -1; - unit[drive].dirty = 0; + p->track = -1; + p->dirty = 0; writepending = 0; /* if this was true before, too bad! */ writefromint = 0; return 1; @@ -1702,11 +1701,11 @@ static int amiga_floppy_change(kdev_t dev) } static struct block_device_operations floppy_fops = { - .owner = THIS_MODULE, - .open = floppy_open, - .release = floppy_release, - .ioctl = fd_ioctl, - .check_media_change = amiga_floppy_change, + .owner = THIS_MODULE, + .open = floppy_open, + .release = floppy_release, + .ioctl = fd_ioctl, + .media_changed = amiga_floppy_change, }; void __init amiga_floppy_setup (char *str, int *ints) @@ -1745,6 +1744,8 @@ static int __init fd_probe_drives(void) disk->first_minor = drive; disk->fops = &floppy_fops; sprintf(disk->disk_name, "fd%d", drive); + disk->private_data = &unit[drive]; + disk->queue = &floppy_queue; set_capacity(disk, 880*2); add_disk(disk); } @@ -1758,12 +1759,12 @@ static int __init fd_probe_drives(void) return -ENOMEM; } -static struct gendisk *floppy_find(int minor) +static struct gendisk *floppy_find(dev_t dev, int *part, void *data) { - int drive = minor & 3; + int drive = *part & 3; if (unit[drive].type->code == FD_NODRIVE) return NULL; - return unit[drive].gendisk; + return get_disk(unit[drive].gendisk); } int __init amiga_floppy_init(void) @@ -1808,9 +1809,7 @@ int __init amiga_floppy_init(void) unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } - blk_set_probe(MAJOR_NR, floppy_find); if (fd_probe_drives() < 1) { /* No usable drives */ - blk_set_probe(MAJOR_NR, NULL); free_irq(IRQ_AMIGA_CIAA_TB, NULL); free_irq(IRQ_AMIGA_DSKBLK, NULL); amiga_chip_free(raw_buf); @@ -1818,6 +1817,8 @@ int __init amiga_floppy_init(void) unregister_blkdev(MAJOR_NR,"fd"); return -ENXIO; } + blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, + floppy_find, NULL, NULL); /* initialize variables */ init_timer(&motor_on_timer); @@ -1842,7 +1843,7 @@ int __init amiga_floppy_init(void) post_write_timer.data = 0; post_write_timer.function = post_write; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &amiflop_lock); + blk_init_queue(&floppy_queue, do_fd_request, &amiflop_lock); for (i = 0; i < 128; i++) mfmdecode[i]=255; for (i = 0; i < 16; i++) @@ -1877,12 +1878,12 @@ void cleanup_module(void) kfree(unit[i].trackbuf); } } - blk_set_probe(MAJOR_NR, NULL); + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); free_irq(IRQ_AMIGA_CIAA_TB, NULL); free_irq(IRQ_AMIGA_DSKBLK, NULL); custom.dmacon = DMAF_DISK; /* disable DMA */ amiga_chip_free(raw_buf); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&floppy_queue); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR, "fd"); } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index c2ae35bb875b..897fa52e2f61 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -94,7 +94,7 @@ #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" -#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#define QUEUE (&floppy_queue) #include <linux/blk.h> #include <linux/blkpg.h> @@ -102,6 +102,8 @@ #undef DEBUG +static struct request_queue floppy_queue; + /* Disk types: DD, HD, ED */ static struct atari_disk_type { const char *name; @@ -1355,9 +1357,10 @@ static int fd_device[4] = { 0,0,0,0 }; * due to unrecognised disk changes. */ -static int check_floppy_change (kdev_t dev) +static int check_floppy_change(struct gendisk *disk) { - unsigned int drive = minor(dev) & 0x03; + struct atari_floppy_struct *p = disk->private_data; + unsigned int drive = p - unit; if (test_bit (drive, &fake_change)) { /* simulated change (e.g. after formatting) */ return 1; @@ -1376,9 +1379,10 @@ static int check_floppy_change (kdev_t dev) return 0; } -static int floppy_revalidate (kdev_t dev) +static int floppy_revalidate(struct gendisk *disk) { - int drive = minor(dev) & 3; + struct atari_floppy_struct *p = disk->private_data; + unsigned int drive = p - unit; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || @@ -1530,6 +1534,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, { int drive, type; kdev_t device; + struct gendisk *disk = inode->i_bdev->bd_disk; struct atari_format_descr fmt_desc; struct atari_disk_type *dtp; struct floppy_struct getprm; @@ -1591,8 +1596,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, * or the next access will revalidate - and clear UDT :-( */ - if (check_floppy_change(device)) - floppy_revalidate(device); + if (check_floppy_change(disk)) + floppy_revalidate(disk); if (UD.flags & FTD_MSG) printk (KERN_INFO "floppy%d: setting size %d spt %d str %d!\n", @@ -1902,21 +1907,21 @@ static int floppy_release( struct inode * inode, struct file * filp ) } static struct block_device_operations floppy_fops = { - owner: THIS_MODULE, - open: floppy_open, - release: floppy_release, - ioctl: fd_ioctl, - check_media_change: check_floppy_change, - revalidate: floppy_revalidate, + .owner = THIS_MODULE, + .open = floppy_open, + .release = floppy_release, + .ioctl = fd_ioctl, + .media_changed = check_floppy_change, + .revalidate_disk= floppy_revalidate, }; -static struct gendisk *floppy_find(int minor) +static struct gendisk *floppy_find(dev_t dev, int *part, void *data) { - int drive = minor & 3; - int type = minor >> 2; + int drive = *part & 3; + int type = *part >> 2; if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return NULL; - return unit[drive].disk; + return get_disk(unit[drive].disk); } int __init atari_floppy_init (void) @@ -1963,6 +1968,8 @@ int __init atari_floppy_init (void) PhysTrackBuffer = virt_to_phys(TrackBuffer); BufferDrive = BufferSide = BufferTrack = -1; + blk_init_queue(&floppy_queue, do_fd_request, &ataflop_lock); + for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; unit[i].flags = 0; @@ -1970,12 +1977,14 @@ int __init atari_floppy_init (void) unit[i].disk->first_minor = i; sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; + unit[i].disk->private_data = &unit[i]; + unit[i].disk->queue = &floppy_queue; set_capacity(unit[i].disk, MAX_DISK_SIZE * 2); add_disk(unit[i].disk); } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &ataflop_lock); - blk_set_probe(MAJOR_NR, floppy_find); + blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, + floppy_find, NULL, NULL); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', @@ -2033,14 +2042,14 @@ int init_module (void) void cleanup_module (void) { int i; + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); for (i = 0; i < FD_MAX_UNITS; i++) { del_gendisk(unit[i].disk); put_disk(unit[i].disk); } unregister_blkdev(MAJOR_NR, "fd"); - blk_set_probe(MAJOR_NR, NULL); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&floppy_queue); del_timer_sync(&fd_timer); atari_stram_free( DMABuffer ); } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index caa30e1c6e84..ec16c3bfae72 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -105,7 +105,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); static int revalidate_allvol(kdev_t dev); -static int cciss_revalidate(kdev_t dev); +static int cciss_revalidate(struct gendisk *disk); static int deregister_disk(int ctlr, int logvol); static int register_new_disk(int cltr); @@ -125,11 +125,11 @@ static void cciss_procinit(int i) {} #endif /* CONFIG_PROC_FS */ static struct block_device_operations cciss_fops = { - owner: THIS_MODULE, - open: cciss_open, - release: cciss_release, - ioctl: cciss_ioctl, - revalidate: cciss_revalidate, + .owner = THIS_MODULE, + .open = cciss_open, + .release = cciss_release, + .ioctl = cciss_ioctl, + .revalidate_disk= cciss_revalidate, }; #include "cciss_scsi.c" /* For SCSI tape support */ @@ -699,12 +699,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, } -static int cciss_revalidate(kdev_t dev) +static int cciss_revalidate(struct gendisk *disk) { - int ctlr = major(dev) - MAJOR_NR; - int target = minor(dev) >> NWD_SHIFT; - struct gendisk *disk = hba[ctlr]->gendisk[target]; - set_capacity(disk, hba[ctlr]->drv[target].nr_blocks); + drive_info_struct *drv = disk->private_data; + set_capacity(disk, drv->nr_blocks); return 0; } @@ -765,7 +763,7 @@ static int revalidate_allvol(kdev_t dev) drive_info_struct *drv = &(hba[ctlr]->drv[i]); if (!drv->nr_blocks) continue; - (BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size; + hba[ctlr]->queue.hardsect_size = drv->block_size; set_capacity(disk, drv->nr_blocks); add_disk(disk); } @@ -1690,10 +1688,11 @@ static void do_cciss_request(request_queue_t *q) { ctlr_info_t *h= q->queuedata; CommandList_struct *c; - int log_unit, start_blk, seg; + int start_blk, seg; struct request *creq; u64bit temp64; struct scatterlist tmp_sg[MAXSGENTRIES]; + drive_info_struct *drv; int i, dir; if (blk_queue_plugged(q)) @@ -1707,16 +1706,6 @@ queue: if (creq->nr_phys_segments > MAXSGENTRIES) BUG(); - if (h->ctlr != major(creq->rq_dev)-MAJOR_NR ) - { - printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", - h->ctlr, major(creq->rq_dev), creq); - blkdev_dequeue_request(creq); - complete_buffers(creq->bio, 0); - end_that_request_last(creq); - goto startio; - } - if (( c = cmd_alloc(h, 1)) == NULL) goto startio; @@ -1728,10 +1717,10 @@ queue: c->rq = creq; /* fill in the request */ - log_unit = minor(creq->rq_dev) >> NWD_SHIFT; + drv = creq->rq_disk->private_data; c->Header.ReplyQueue = 0; // unused in simple mode c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag - c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.VolId= drv->LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; // 12 byte commands not in FW yet; c->Request.Type.Type = TYPE_CMD; // It is a command. @@ -1854,7 +1843,7 @@ static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) * See if we can queue up some more IO */ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); - blk_start_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr)); + blk_start_queue(&h->queue); } /* * We cannot read the structure directly, for portablity we must use @@ -2425,7 +2414,7 @@ static int __init cciss_init_one(struct pci_dev *pdev, cciss_procinit(i); - q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); + q = &hba[i]->queue; q->queuedata = hba[i]; spin_lock_init(&hba[i]->lock); blk_init_queue(q, do_cciss_request, &hba[i]->lock); @@ -2447,9 +2436,12 @@ static int __init cciss_init_one(struct pci_dev *pdev, sprintf(disk->disk_name, "cciss/c%dd%d", i, j); disk->major = MAJOR_NR + i; disk->first_minor = j << NWD_SHIFT; + disk->fops = &cciss_fops; + disk->queue = &hba[i]->queue; + disk->private_data = drv; if( !(drv->nr_blocks)) continue; - (BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size; + hba[i]->queue.hardsect_size = drv->block_size; set_capacity(disk, drv->nr_blocks); add_disk(disk); } diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 30d569d1aacb..10d5d261fd76 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -70,6 +70,7 @@ struct ctlr_info unsigned int maxQsinceinit; unsigned int maxSG; spinlock_t lock; + struct request_queue queue; //* pointers to command and error info pool */ CommandList_struct *cmd_pool; @@ -245,7 +246,7 @@ struct board_type { struct access_method *access; }; -#define CCISS_LOCK(i) ((BLK_DEFAULT_QUEUE(MAJOR_NR + i))->queue_lock) +#define CCISS_LOCK(i) (hba[i]->queue.queue_lock) #endif /* CCISS_H */ diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index ceedd2d59575..6a1b2d18eec6 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1250,8 +1250,6 @@ cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length) 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 */ @@ -1268,24 +1266,9 @@ cciss_scsi_proc_info(char *buffer, /* data buffer */ 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. */ + sh = scsi_host_hn_get(hostnum); + if (sh == NULL) /* This really shouldn't ever happen. */ return -EINVAL; ci = (ctlr_info_t *) sh->hostdata[0]; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 5893a6e528c2..f8ba4997ead6 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -150,7 +150,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout); static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); static void ida_timer(unsigned long tdata); -static int ida_revalidate(kdev_t dev); +static int ida_revalidate(struct gendisk *disk); static int revalidate_allvol(kdev_t dev); #ifdef CONFIG_PROC_FS @@ -163,11 +163,11 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, #endif static struct block_device_operations ida_fops = { - owner: THIS_MODULE, - open: ida_open, - release: ida_release, - ioctl: ida_ioctl, - revalidate: ida_revalidate, + .owner = THIS_MODULE, + .open = ida_open, + .release = ida_release, + .ioctl = ida_ioctl, + .revalidate_disk= ida_revalidate, }; @@ -296,7 +296,7 @@ static void __exit cpqarray_exit(void) iounmap(hba[i]->vaddr); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); del_timer(&hba[i]->timer); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i)); + blk_cleanup_queue(&hba[i]->queue); remove_proc_entry(hba[i]->devname, proc_array); pci_free_consistent(hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool), @@ -378,7 +378,7 @@ static int __init cpqarray_init(void) ida_procinit(i); - q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); + q = &hba[i]->queue; q->queuedata = hba[i]; spin_lock_init(&hba[i]->lock); blk_init_queue(q, do_ida_request, &hba[i]->lock); @@ -409,8 +409,10 @@ static int __init cpqarray_init(void) disk->fops = &ida_fops; if (!drv->nr_blks) continue; - (BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->blk_size; + hba[i]->queue.hardsect_size = drv->blk_size; set_capacity(disk, drv->nr_blks); + disk->queue = &hba[i]->queue; + disk->private_data = drv; add_disk(disk); } } @@ -1004,7 +1006,7 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) /* * See if we can queue up some more IO */ - do_ida_request(BLK_DEFAULT_QUEUE(MAJOR_NR+h->ctlr)); + do_ida_request(&h->queue); spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); } @@ -1446,8 +1448,10 @@ static int revalidate_allvol(kdev_t dev) drv_info_t *drv = &hba[ctlr]->drv[i]; if (!drv->nr_blks) continue; - (BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->blk_size; + hba[ctlr]->queue.hardsect_size = drv->blk_size; set_capacity(disk, drv->nr_blks); + disk->queue = &hba[ctlr]->queue; + disk->private_data = drv; add_disk(disk); } @@ -1455,12 +1459,10 @@ static int revalidate_allvol(kdev_t dev) return 0; } -static int ida_revalidate(kdev_t dev) +static int ida_revalidate(struct gendisk *disk) { - int ctlr = major(dev) - MAJOR_NR; - int target = DEVICE_NR(dev); - struct gendisk *gdev = ida_gendisk[ctlr][target]; - set_capacity(gdev, hba[ctlr]->drv[target].nr_blks); + drv_info_t *drv = disk->private_data; + set_capacity(disk, drv->nr_blks); return 0; } diff --git a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h index 54b115635cc0..38bf3b457328 100644 --- a/drivers/block/cpqarray.h +++ b/drivers/block/cpqarray.h @@ -105,6 +105,7 @@ struct ctlr_info { cmdlist_t *cmd_pool; dma_addr_t cmd_pool_dhandle; unsigned long *cmd_pool_bits; + struct request_queue queue; spinlock_t lock; unsigned int Qdepth; @@ -117,7 +118,7 @@ struct ctlr_info { unsigned int misc_tflags; }; -#define IDA_LOCK(i) ((BLK_DEFAULT_QUEUE(MAJOR_NR + i))->queue_lock) +#define IDA_LOCK(i) (&hba[i]->lock) #endif diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 3fde460ce7ea..7206ab3847a5 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -243,13 +243,13 @@ static int irqdma_allocated; #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" #define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) - #include <linux/blk.h> #include <linux/blkpg.h> #include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/completion.h> static struct request *current_req; +static struct request_queue floppy_queue; #ifndef fd_get_dma_residue #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA) @@ -2295,12 +2295,10 @@ static int do_format(kdev_t device, struct format_descr *tmp_format_req) static inline void end_request(struct request *req, int uptodate) { - kdev_t dev = req->rq_dev; - if (end_that_request_first(req, uptodate, current_count_sectors)) return; - add_blkdev_randomness(major(dev)); - floppy_off(DEVICE_NR(dev)); + add_blkdev_randomness(MAJOR_NR); + floppy_off((int)req->rq_disk->private_data); blkdev_dequeue_request(req); end_that_request_last(req); @@ -2313,7 +2311,7 @@ static inline void end_request(struct request *req, int uptodate) * logical buffer */ static void request_done(int uptodate) { - struct request_queue *q = QUEUE; + struct request_queue *q = &floppy_queue; struct request *req = current_req; unsigned long flags; int block; @@ -2913,7 +2911,7 @@ static void redo_fd_request(void) for (;;) { if (!current_req) { - struct request *req = elv_next_request(QUEUE); + struct request *req = elv_next_request(&floppy_queue); if (!req) { do_floppy = NULL; unlock_fdc(); @@ -2921,9 +2919,6 @@ static void redo_fd_request(void) } current_req = req; } - if (major(current_req->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": request list destroyed"); - device = current_req->rq_dev; set_fdc(DRIVE(device)); reschedule_timeout(current_reqD, "redo fd request", 0); @@ -3796,14 +3791,9 @@ static int floppy_open(struct inode * inode, struct file * filp) /* * Check if the disk has been changed or if a change has been faked. */ -static int check_floppy_change(kdev_t dev) +static int check_floppy_change(struct gendisk *disk) { - int drive = DRIVE(dev); - - if (major(dev) != MAJOR_NR) { - DPRINT("check_floppy_change: not a floppy\n"); - return 0; - } + int drive = (int)disk->private_data; if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) return 1; @@ -3822,7 +3812,7 @@ static int check_floppy_change(kdev_t dev) if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || - (!TYPE(dev) && !current_type[drive])) + (!ITYPE(UDRS->fd_device) && !current_type[drive])) return 1; return 0; } @@ -3884,16 +3874,17 @@ static int __floppy_read_block_0(struct block_device *bdev) return 0; } -static int floppy_read_block_0(kdev_t dev) +static int floppy_read_block_0(struct gendisk *disk) { struct block_device *bdev; int ret; - bdev = bdget(kdev_t_to_nr(dev)); + bdev = bdget(MKDEV(disk->major, disk->first_minor)); if (!bdev) { - printk("No block device for %s\n", __bdevname(dev)); + printk("No block device for %s\n", disk->disk_name); BUG(); } + bdev->bd_disk = disk; /* ewww */ ret = __floppy_read_block_0(bdev); atomic_dec(&bdev->bd_count); return ret; @@ -3903,10 +3894,10 @@ static int floppy_read_block_0(kdev_t dev) * the bootblock (block 0). "Autodetection" is also needed to check whether * there is a disk in the drive at all... Thus we also do it for fixed * geometry formats */ -static int floppy_revalidate(kdev_t dev) +static int floppy_revalidate(struct gendisk *disk) { -#define NO_GEOM (!current_type[drive] && !TYPE(dev)) - int drive=DRIVE(dev); + int drive=(int)disk->private_data; +#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device)) int cf; int res = 0; @@ -3934,24 +3925,24 @@ static int floppy_revalidate(kdev_t dev) UDRS->generation++; if (NO_GEOM){ /* auto-sensing */ - res = floppy_read_block_0(dev); + res = floppy_read_block_0(disk); } else { if (cf) poll_drive(0, FD_RAW_NEED_DISK); process_fd_request(); } } - set_capacity(disks[drive], floppy_sizes[minor(dev)]); + set_capacity(disk, floppy_sizes[UDRS->fd_device]); return res; } static struct block_device_operations floppy_fops = { - owner: THIS_MODULE, - open: floppy_open, - release: floppy_release, - ioctl: fd_ioctl, - check_media_change: check_floppy_change, - revalidate: floppy_revalidate, + .owner = THIS_MODULE, + .open = floppy_open, + .release = floppy_release, + .ioctl = fd_ioctl, + .media_changed = check_floppy_change, + .revalidate_disk= floppy_revalidate, }; static void __init register_devfs_entries (int drive) @@ -4212,14 +4203,14 @@ static struct platform_device floppy_device = { }, }; -static struct gendisk *floppy_find(int minor) +static struct gendisk *floppy_find(dev_t dev, int *part, void *data) { - int drive = (minor&3) | ((minor&0x80) >> 5); + int drive = (*part&3) | ((*part&0x80) >> 5); if (drive >= N_DRIVE || !(allowed_drive_mask & (1 << drive)) || fdc_state[FDC(drive)].version == FDC_NONE) return NULL; - return disks[drive]; + return get_disk(disks[drive]); } int __init floppy_init(void) @@ -4249,7 +4240,8 @@ int __init floppy_init(void) sprintf(disks[i]->disk_name, "fd%d", i); } - blk_set_probe(MAJOR_NR, floppy_find); + blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, + floppy_find, NULL, NULL); for (i=0; i<256; i++) if (ITYPE(i)) @@ -4257,7 +4249,7 @@ int __init floppy_init(void) else floppy_sizes[i] = MAX_DISK_SIZE << 1; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &floppy_lock); + blk_init_queue(&floppy_queue, do_fd_request, &floppy_lock); reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); config_types(); @@ -4359,6 +4351,9 @@ int __init floppy_init(void) continue; if (fdc_state[FDC(drive)].version == FDC_NONE) continue; + /* to be cleaned up... */ + disks[drive]->private_data = (void*)drive; + disks[drive]->queue = &floppy_queue; add_disk(disks[drive]); } @@ -4368,9 +4363,9 @@ int __init floppy_init(void) out1: del_timer(&fd_timeout); out2: + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); unregister_blkdev(MAJOR_NR,"fd"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - blk_set_probe(MAJOR_NR, NULL); + blk_cleanup_queue(&floppy_queue); out: for (i=0; i<N_DRIVE; i++) put_disk(disks[i]); @@ -4563,8 +4558,8 @@ void cleanup_module(void) platform_device_unregister(&floppy_device); devfs_unregister (devfs_handle); + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); unregister_blkdev(MAJOR_NR, "fd"); - blk_set_probe(MAJOR_NR, NULL); for (drive = 0; drive < N_DRIVE; drive++) { if ((allowed_drive_mask & (1 << drive)) && fdc_state[FDC(drive)].version != FDC_NONE) @@ -4572,7 +4567,7 @@ void cleanup_module(void) put_disk(disks[drive]); } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&floppy_queue); /* eject disk, if any */ fd_eject(0); } diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 449e69061bbc..24200d33cf0a 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/kmod.h> static rwlock_t gendisk_lock; @@ -33,22 +34,74 @@ static rwlock_t gendisk_lock; */ static LIST_HEAD(gendisk_list); -/* - * TEMPORARY KLUDGE. - */ -static struct { - struct list_head list; - struct gendisk *(*get)(int minor); -} gendisks[MAX_BLKDEV]; +struct blk_probe { + struct blk_probe *next; + dev_t dev; + unsigned long range; + struct module *owner; + struct gendisk *(*get)(dev_t dev, int *part, void *data); + void (*lock)(dev_t, void *); + void *data; +} *probes[MAX_BLKDEV]; + +/* index in the above */ +static inline int dev_to_index(dev_t dev) +{ + return MAJOR(dev); +} + +void blk_register_region(dev_t dev, unsigned long range, struct module *module, + struct gendisk *(*probe)(dev_t, int *, void *), + void (*lock)(dev_t, void *), void *data) +{ + int index = dev_to_index(dev); + struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); + struct blk_probe **s; + p->owner = module; + p->get = probe; + p->lock = lock; + p->dev = dev; + p->range = range; + p->data = data; + write_lock(&gendisk_lock); + for (s = &probes[index]; *s && (*s)->range < range; s = &(*s)->next) + ; + p->next = *s; + *s = p; + write_unlock(&gendisk_lock); +} -void blk_set_probe(int major, struct gendisk *(p)(int)) +void blk_unregister_region(dev_t dev, unsigned long range) { + int index = dev_to_index(dev); + struct blk_probe **s; write_lock(&gendisk_lock); - gendisks[major].get = p; + for (s = &probes[index]; *s; s = &(*s)->next) { + struct blk_probe *p = *s; + if (p->dev == dev || p->range == range) { + *s = p->next; + kfree(p); + break; + } + } write_unlock(&gendisk_lock); } -EXPORT_SYMBOL(blk_set_probe); /* Will go away */ - + +EXPORT_SYMBOL(blk_register_region); +EXPORT_SYMBOL(blk_unregister_region); + +static struct gendisk *exact_match(dev_t dev, int *part, void *data) +{ + struct gendisk *p = data; + *part = MINOR(dev) - p->first_minor; + return p; +} + +static void exact_lock(dev_t dev, void *data) +{ + struct gendisk *p = data; + get_disk(p); +} /** * add_gendisk - add partitioning information to kernel list @@ -60,10 +113,11 @@ EXPORT_SYMBOL(blk_set_probe); /* Will go away */ void add_disk(struct gendisk *disk) { write_lock(&gendisk_lock); - list_add(&disk->list, &gendisks[disk->major].list); list_add_tail(&disk->full_list, &gendisk_list); write_unlock(&gendisk_lock); disk->flags |= GENHD_FL_UP; + blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, + NULL, exact_match, exact_lock, disk); register_disk(disk); } @@ -74,8 +128,9 @@ void unlink_gendisk(struct gendisk *disk) { write_lock(&gendisk_lock); list_del_init(&disk->full_list); - list_del_init(&disk->list); write_unlock(&gendisk_lock); + blk_unregister_region(MKDEV(disk->major, disk->first_minor), + disk->minors); } /** @@ -88,30 +143,40 @@ void unlink_gendisk(struct gendisk *disk) struct gendisk * get_gendisk(dev_t dev, int *part) { + int index = dev_to_index(dev); struct gendisk *disk; - struct list_head *p; - int major = MAJOR(dev); - int minor = MINOR(dev); + struct blk_probe *p; + unsigned best = ~0U; - *part = 0; +retry: read_lock(&gendisk_lock); - if (gendisks[major].get) { - disk = gendisks[major].get(minor); - if (disk) - get_disk(disk); - read_unlock(&gendisk_lock); - return disk; - } - list_for_each(p, &gendisks[major].list) { - disk = list_entry(p, struct gendisk, list); - if (disk->first_minor > minor) + for (p = probes[index]; p; p = p->next) { + struct gendisk *(*probe)(dev_t, int *, void *); + struct module *owner; + void *data; + if (p->dev > dev || p->dev + p->range <= dev) continue; - if (disk->first_minor + disk->minors <= minor) + if (p->range >= best) { + read_unlock(&gendisk_lock); + return NULL; + } + if (!try_inc_mod_count(p->owner)) continue; - get_disk(disk); + owner = p->owner; + data = p->data; + probe = p->get; + best = p->range; + *part = dev - p->dev; + if (p->lock) + p->lock(dev, data); read_unlock(&gendisk_lock); - *part = minor - disk->first_minor; - return disk; + disk = probe(dev, part, data); + /* Currently ->owner protects _only_ ->probe() itself. */ + if (owner) + __MOD_DEC_USE_COUNT(owner); + if (disk) + return disk; + goto retry; } read_unlock(&gendisk_lock); return NULL; @@ -183,8 +248,6 @@ struct seq_operations partitions_op = { extern int blk_dev_init(void); -extern int soc_probe(void); -extern int atmdev_init(void); struct device_class disk_devclass = { .name = "disk", @@ -193,13 +256,26 @@ struct device_class disk_devclass = { static struct bus_type disk_bus = { name: "block", }; + +static struct gendisk *base_probe(dev_t dev, int *part, void *data) +{ + char name[20]; + sprintf(name, "block-major-%d", MAJOR(dev)); + request_module(name); + return NULL; +} int __init device_init(void) { + struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); int i; rwlock_init(&gendisk_lock); - for (i = 0; i < MAX_BLKDEV; i++) - INIT_LIST_HEAD(&gendisks[i].list); + memset(base, 0, sizeof(struct blk_probe)); + base->dev = MKDEV(1,0); + base->range = MKDEV(MAX_BLKDEV-1, 255) - base->dev + 1; + base->get = base_probe; + for (i = 1; i < MAX_BLKDEV; i++) + probes[i] = base; blk_dev_init(); devclass_register(&disk_devclass); bus_register(&disk_bus); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index eb877e50a8d1..c5697e05a6b8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -670,12 +670,10 @@ void blk_dump_rq_flags(struct request *rq, char *msg) bit++; } while (bit < __REQ_NR_BITS); - if (rq->flags & REQ_CMD) - printk("sector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector, + printk("sector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); - - printk("\n"); + printk("bio %p, biotail %p\n", rq->bio, rq->biotail); } void blk_recount_segments(request_queue_t *q, struct bio *bio) @@ -1927,7 +1925,7 @@ inline void blk_recalc_rq_segments(struct request *rq) inline void blk_recalc_rq_sectors(struct request *rq, int nsect) { - if (rq->flags & REQ_CMD) { + if (rq->bio) { rq->hard_sector += nsect; rq->nr_sectors = rq->hard_nr_sectors -= nsect; rq->sector = rq->hard_sector; @@ -1968,20 +1966,28 @@ int end_that_request_first(struct request *req, int uptodate, int nr_sectors) req->errors = 0; if (!uptodate) { - printk("end_request: I/O error, dev %s, sector %llu\n", - kdevname(req->rq_dev), (unsigned long long)req->sector); error = -EIO; + if (!(req->flags & REQ_QUIET)) + printk("end_request: I/O error, dev %s, sector %llu\n", + kdevname(req->rq_dev), + (unsigned long long)req->sector); } while ((bio = req->bio)) { - const int nsect = bio_iovec(bio)->bv_len >> 9; - int new_bio = 0; + int new_bio = 0, nsect; + + if (unlikely(bio->bi_idx >= bio->bi_vcnt)) { + printk("%s: bio idx %d >= vcnt %d\n", __FUNCTION__, + bio->bi_idx, bio->bi_vcnt); + break; + } BIO_BUG_ON(bio_iovec(bio)->bv_len > bio->bi_size); /* * not a complete bvec done */ + nsect = bio_iovec(bio)->bv_len >> 9; if (unlikely(nsect > nr_sectors)) { int partial = nr_sectors << 9; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 14fa8720f8db..ea1c987812cf 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -437,7 +437,7 @@ static struct bio *loop_get_bio(struct loop_device *lo) static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err) { struct bio *rbh = bio->bi_private; - struct loop_device *lo = &loop_dev[minor(to_kdev_t(rbh->bi_bdev->bd_dev))]; + struct loop_device *lo = rbh->bi_bdev->bd_disk->private_data; if (bio->bi_size) return 1; @@ -916,20 +916,9 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) static int lo_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - struct loop_device *lo; - int dev, err; + struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + int err; - if (!inode) - return -EINVAL; - if (major(inode->i_rdev) != MAJOR_NR) { - printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n", - MAJOR_NR); - return -ENODEV; - } - dev = minor(inode->i_rdev); - if (dev >= max_loop) - return -ENODEV; - lo = &loop_dev[dev]; down(&lo->lo_ctl_mutex); switch (cmd) { case LOOP_SET_FD: @@ -953,14 +942,9 @@ static int lo_ioctl(struct inode * inode, struct file * file, static int lo_open(struct inode *inode, struct file *file) { - struct loop_device *lo; - int dev, type; - - dev = minor(inode->i_rdev); - if (dev >= max_loop) - return -ENODEV; + struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + int type; - lo = &loop_dev[dev]; down(&lo->lo_ctl_mutex); type = lo->lo_encrypt_type; @@ -973,14 +957,9 @@ static int lo_open(struct inode *inode, struct file *file) static int lo_release(struct inode *inode, struct file *file) { - struct loop_device *lo; - int dev, type; - - dev = minor(inode->i_rdev); - if (dev >= max_loop) - return 0; + struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + int type; - lo = &loop_dev[dev]; down(&lo->lo_ctl_mutex); type = lo->lo_encrypt_type; --lo->lo_refcnt; @@ -1034,16 +1013,6 @@ int loop_unregister_transfer(int number) EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); -request_queue_t *loop_get_queue(kdev_t dev) -{ - int minor = minor(dev); - - if (minor < max_loop) - return &loop_dev[minor].lo_queue; - - return NULL; -} - int __init loop_init(void) { int i; @@ -1093,11 +1062,10 @@ int __init loop_init(void) disk->first_minor = i; disk->fops = &lo_fops; sprintf(disk->disk_name, "loop%d", i); + disk->private_data = lo; + disk->queue = &lo->lo_queue; add_disk(disk); } - - blk_dev[LOOP_MAJOR].queue = loop_get_queue; - printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); return 0; diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c index 0a7126756371..e325adc996f2 100644 --- a/drivers/block/paride/epat.c +++ b/drivers/block/paride/epat.c @@ -304,7 +304,6 @@ static void epat_log_adapter( PIA *pi, char * scratch, int verbose ) static void epat_init_proto( PIA *pi) { MOD_INC_USE_COUNT; - printk("epat_init_proto"); } static void epat_release_proto( PIA *pi) diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 95bedb2a580c..44101ada1e45 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -239,6 +239,7 @@ static int pcd_bufblk = -1; /* block in buffer, in CD units, */ static struct pcd_unit *pcd_current; /* current request's drive */ +static struct request *pcd_req; static int pcd_retries; /* retries on current request */ static int pcd_busy; /* request being processed ? */ static int pcd_sector; /* address of next requested sector */ @@ -249,12 +250,37 @@ static int pcd_warned; /* Have we logged a phase warning ? */ /* kernel glue structures */ +static int pcd_block_open(struct inode *inode, struct file *file) +{ + struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_open(&cd->info, inode, file); +} + +static int pcd_block_release(struct inode *inode, struct file *file) +{ + struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_release(&cd->info, file); +} + +static int pcd_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_ioctl(&cd->info, inode, cmd, arg); +} + +static int pcd_block_media_changed(struct gendisk *disk) +{ + struct pcd_unit *cd = disk->private_data; + return cdrom_media_changed(&cd->info); +} + static struct block_device_operations pcd_bdops = { - .owner = THIS_MODULE, - .open = cdrom_open, - .release = cdrom_release, - .ioctl = cdrom_ioctl, - .check_media_change = cdrom_media_changed, + .owner = THIS_MODULE, + .open = pcd_block_open, + .release = pcd_block_release, + .ioctl = pcd_block_ioctl, + .media_changed = pcd_block_media_changed, }; static struct cdrom_device_ops pcd_dops = { @@ -297,7 +323,6 @@ static void pcd_init_units(void) snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit); cd->info.ops = &pcd_dops; cd->info.handle = cd; - cd->info.dev = mk_kdev(major, unit); cd->info.speed = 0; cd->info.capacity = 1; cd->info.mask = 0; @@ -714,32 +739,43 @@ static int pcd_detect(void) } /* I/O request processing */ +static struct request_queue pcd_queue; static void do_pcd_request(request_queue_t * q) { if (pcd_busy) return; while (1) { - struct request *req; - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) return; - req = CURRENT; - if (rq_data_dir(req) == READ) { - struct pcd_unit *cd = pcd + minor(req->rq_dev); + pcd_req = elv_next_request(q); + if (rq_data_dir(pcd_req) == READ) { + struct pcd_unit *cd = pcd_req->rq_disk->private_data; if (cd != pcd_current) pcd_bufblk = -1; pcd_current = cd; - pcd_sector = req->sector; - pcd_count = req->current_nr_sectors; - pcd_buf = req->buffer; + pcd_sector = pcd_req->sector; + pcd_count = pcd_req->current_nr_sectors; + pcd_buf = pcd_req->buffer; pcd_busy = 1; ps_set_intr(do_pcd_read, 0, 0, nice); return; } else - end_request(req, 0); + end_request(pcd_req, 0); } } +static inline void next_request(int success) +{ + long saved_flags; + + spin_lock_irqsave(&pcd_lock, saved_flags); + end_request(pcd_req, success); + pcd_busy = 0; + do_pcd_request(&pcd_queue); + spin_unlock_irqrestore(&pcd_lock, saved_flags); +} + static int pcd_ready(void) { return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ)); @@ -761,7 +797,6 @@ static void pcd_start(void) { int b, i; char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; - unsigned long saved_flags; pcd_bufblk = pcd_sector / 4; b = pcd_bufblk; @@ -772,11 +807,7 @@ static void pcd_start(void) if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) { pcd_bufblk = -1; - spin_lock_irqsave(&pcd_lock, saved_flags); - pcd_busy = 0; - end_request(CURRENT, 0); - do_pcd_request(NULL); - spin_unlock_irqrestore(&pcd_lock, saved_flags); + next_request(0); return; } @@ -791,12 +822,7 @@ static void do_pcd_read(void) pcd_retries = 0; pcd_transfer(); if (!pcd_count) { - unsigned long saved_flags; - spin_lock_irqsave(&pcd_lock, saved_flags); - end_request(CURRENT, 1); - pcd_busy = 0; - do_pcd_request(NULL); - spin_unlock_irqrestore(&pcd_lock, saved_flags); + next_request(1); return; } @@ -814,18 +840,14 @@ static void do_pcd_read_drq(void) pi_do_claimed(pcd_current->pi, pcd_start); return; } - spin_lock_irqsave(&pcd_lock, saved_flags); - pcd_busy = 0; pcd_bufblk = -1; - end_request(CURRENT, 0); - do_pcd_request(NULL); - spin_unlock_irqrestore(&pcd_lock, saved_flags); + next_request(0); return; } do_pcd_read(); spin_lock_irqsave(&pcd_lock, saved_flags); - do_pcd_request(NULL); + do_pcd_request(&pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags); } @@ -934,15 +956,17 @@ static int __init pcd_init(void) return -1; } + blk_init_queue(&pcd_queue, do_pcd_request, &pcd_lock); + for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { if (cd->present) { register_cdrom(&cd->info); + cd->disk->private_data = cd; + cd->disk->queue = &pcd_queue; add_disk(cd->disk); } } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock); - return 0; } @@ -959,6 +983,7 @@ static void __exit pcd_exit(void) } put_disk(cd->disk); } + blk_cleanup_queue(&pcd_queue); unregister_blkdev(MAJOR_NR, name); } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 2278ee4928ab..ba58a2af3ebb 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -196,9 +196,6 @@ MODULE_PARM(drive3, "1-8i"); #include "pseudo.h" #define PD_BITS 4 -#define DEVICE_NR(device) (minor(device)>>PD_BITS) -#define PD_PARTNS (1<<PD_BITS) -#define PD_DEVS PD_PARTNS*PD_UNITS /* numbers for "SCSI" geometry */ @@ -249,7 +246,7 @@ static void do_pd_request(request_queue_t * q); static int pd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int pd_release(struct inode *inode, struct file *file); -static int pd_revalidate(kdev_t dev); +static int pd_revalidate(struct gendisk *p); static int pd_detect(void); static void do_pd_read(void); static void do_pd_read_start(void); @@ -284,7 +281,7 @@ struct pd_unit pd[PD_UNITS]; static int pd_identify(struct pd_unit *disk); static void pd_media_check(struct pd_unit *disk); static void pd_doorlock(struct pd_unit *disk, int func); -static int pd_check_media(kdev_t dev); +static int pd_check_media(struct gendisk *p); static void pd_eject(struct pd_unit *disk); static char pd_scratch[512]; /* scratch block buffer */ @@ -315,12 +312,12 @@ static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR", extern struct block_device_operations pd_fops; static struct block_device_operations pd_fops = { - .owner = THIS_MODULE, - .open = pd_open, - .release = pd_release, - .ioctl = pd_ioctl, - .check_media_change = pd_check_media, - .revalidate = pd_revalidate + .owner = THIS_MODULE, + .open = pd_open, + .release = pd_release, + .ioctl = pd_ioctl, + .media_changed = pd_check_media, + .revalidate_disk= pd_revalidate }; static void pd_init_units(void) @@ -347,8 +344,7 @@ static void pd_init_units(void) static int pd_open(struct inode *inode, struct file *file) { - int unit = DEVICE_NR(inode->i_rdev); - struct pd_unit *disk = pd + unit; + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; disk->access++; @@ -362,9 +358,9 @@ static int pd_open(struct inode *inode, struct file *file) static int pd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; struct hd_geometry g; - struct pd_unit *disk = pd + DEVICE_NR(inode->i_rdev); switch (cmd) { case CDROMEJECT: @@ -392,8 +388,7 @@ static int pd_ioctl(struct inode *inode, struct file *file, static int pd_release(struct inode *inode, struct file *file) { - int unit = DEVICE_NR(inode->i_rdev); - struct pd_unit *disk = pd + unit; + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; if (!--disk->access && disk->removable) pd_doorlock(disk, IDE_DOORUNLOCK); @@ -401,10 +396,10 @@ static int pd_release(struct inode *inode, struct file *file) return 0; } -static int pd_check_media(kdev_t dev) +static int pd_check_media(struct gendisk *p) { - int r, unit = DEVICE_NR(dev); - struct pd_unit *disk = pd + unit; + struct pd_unit *disk = p->private_data; + int r; if (!disk->removable) return 0; pd_media_check(disk); @@ -413,14 +408,13 @@ static int pd_check_media(kdev_t dev) return r; } -static int pd_revalidate(kdev_t dev) +static int pd_revalidate(struct gendisk *p) { - int unit = DEVICE_NR(dev); - struct pd_unit *disk = pd + unit; + struct pd_unit *disk = p->private_data; if (pd_identify(disk)) - set_capacity(disk->gd, disk->capacity); + set_capacity(p, disk->capacity); else - set_capacity(disk->gd, 0); + set_capacity(p, 0); return 0; } @@ -665,6 +659,8 @@ static int pd_probe_drive(struct pd_unit *disk) return pd_identify(disk); } +static struct request_queue pd_queue; + static int pd_detect(void) { int k, unit; @@ -712,6 +708,8 @@ static int pd_detect(void) p->first_minor = unit << PD_BITS; set_capacity(p, disk->capacity); disk->gd = p; + p->private_data = disk; + p->queue = &pd_queue; add_disk(p); } } @@ -730,26 +728,18 @@ static int pd_ready(void) static void do_pd_request(request_queue_t * q) { - int unit; - if (pd_busy) return; repeat: - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) return; - pd_req = elv_next_request(QUEUE); - unit = DEVICE_NR(pd_req->rq_dev); - if (unit >= PD_UNITS) { - end_request(pd_req, 0); - goto repeat; - } - + pd_req = elv_next_request(q); pd_block = pd_req->sector; pd_run = pd_req->nr_sectors; pd_count = pd_req->current_nr_sectors; - pd_current = pd + unit; - if (pd_block + pd_count > get_capacity(pd_current->gd)) { + pd_current = pd_req->rq_disk->private_data; + if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) { end_request(pd_req, 0); goto repeat; } @@ -797,7 +787,7 @@ static inline void next_request(int success) spin_lock_irqsave(&pd_lock, saved_flags); end_request(pd_req, success); pd_busy = 0; - do_pd_request(NULL); + do_pd_request(&pd_queue); spin_unlock_irqrestore(&pd_lock, saved_flags); } @@ -903,16 +893,14 @@ static void do_pd_write_done(void) static int __init pd_init(void) { - request_queue_t *q; if (disable) return -1; if (register_blkdev(MAJOR_NR, name, &pd_fops)) { printk("%s: unable to get major number %d\n", name, major); return -1; } - q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, do_pd_request, &pd_lock); - blk_queue_max_sectors(q, cluster); + blk_init_queue(&pd_queue, do_pd_request, &pd_lock); + blk_queue_max_sectors(&pd_queue, cluster); printk("%s: %s version %s, major %d, cluster %d, nice %d\n", name, name, PD_VERSION, major, cluster, nice); @@ -938,6 +926,7 @@ static void __exit pd_exit(void) pi_release(disk->pi); } } + blk_cleanup_queue(&pd_queue); } MODULE_LICENSE("GPL"); diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 9598323b5694..7ab87ba87d7d 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -191,7 +191,6 @@ MODULE_PARM(drive3, "1-7i"); /* set up defines for blk.h, why don't all drivers do it this way ? */ #define MAJOR_NR major -#define DEVICE_NR(device) minor(device) #include <linux/blk.h> #include <linux/blkpg.h> @@ -272,7 +271,7 @@ struct pf_unit units[PF_UNITS]; static int pf_identify(struct pf_unit *pf); static void pf_lock(struct pf_unit *pf, int func); static void pf_eject(struct pf_unit *pf); -static int pf_check_media(kdev_t dev); +static int pf_check_media(struct gendisk *disk); static char pf_scratch[512]; /* scratch block buffer */ @@ -294,11 +293,11 @@ static char *pf_buf; /* buffer for request in progress */ /* kernel glue structures */ static struct block_device_operations pf_fops = { - .owner = THIS_MODULE, - .open = pf_open, - .release = pf_release, - .ioctl = pf_ioctl, - .check_media_change = pf_check_media, + .owner = THIS_MODULE, + .open = pf_open, + .release = pf_release, + .ioctl = pf_ioctl, + .media_changed = pf_check_media, }; void pf_init_units(void) @@ -328,8 +327,7 @@ void pf_init_units(void) static int pf_open(struct inode *inode, struct file *file) { - int unit = DEVICE_NR(inode->i_rdev); - struct pf_unit *pf = units + unit; + struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; pf_identify(pf); @@ -348,10 +346,9 @@ static int pf_open(struct inode *inode, struct file *file) static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int unit = DEVICE_NR(inode->i_rdev); + struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; struct hd_geometry g; - struct pf_unit *pf = units + unit; sector_t capacity; if (cmd == CDROMEJECT) { @@ -380,10 +377,9 @@ static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un static int pf_release(struct inode *inode, struct file *file) { - int unit = DEVICE_NR(inode->i_rdev); - struct pf_unit *pf = units + unit; + struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; - if ((unit >= PF_UNITS) || (pf->access <= 0)) + if (pf->access <= 0) return -EINVAL; pf->access--; @@ -395,7 +391,7 @@ static int pf_release(struct inode *inode, struct file *file) } -static int pf_check_media(kdev_t dev) +static int pf_check_media(struct gendisk *disk) { return 1; } @@ -784,25 +780,23 @@ static int pf_ready(void) return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask)); } +static struct request_queue pf_queue; + static void do_pf_request(request_queue_t * q) { - int unit; - if (pf_busy) return; - repeat: - if (elv_queue_empty(QUEUE)) +repeat: + if (elv_queue_empty(q)) return; - pf_req = elv_next_request(QUEUE); - unit = DEVICE_NR(pf_req->rq_dev); - pf_current = units + unit; + pf_req = elv_next_request(q); + pf_current = pf_req->rq_disk->private_data; pf_block = pf_req->sector; pf_run = pf_req->nr_sectors; pf_count = pf_req->current_nr_sectors; - if ((unit >= PF_UNITS) || - (pf_block + pf_count > get_capacity(pf_current->disk))) { + if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { end_request(pf_req, 0); goto repeat; } @@ -849,7 +843,7 @@ static inline void next_request(int success) spin_lock_irqsave(&pf_spin_lock, saved_flags); end_request(pf_req, success); pf_busy = 0; - do_pf_request(NULL); + do_pf_request(&pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); } @@ -960,7 +954,6 @@ static int __init pf_init(void) { /* preliminary initialisation */ struct pf_unit *pf; int unit; - request_queue_t *q; if (disable) return -1; @@ -977,15 +970,16 @@ static int __init pf_init(void) put_disk(pf->disk); return -1; } - q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, do_pf_request, &pf_spin_lock); - blk_queue_max_phys_segments(q, cluster); - blk_queue_max_hw_segments(q, cluster); + blk_init_queue(&pf_queue, do_pf_request, &pf_spin_lock); + blk_queue_max_phys_segments(&pf_queue, cluster); + blk_queue_max_hw_segments(&pf_queue, cluster); for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { struct gendisk *disk = pf->disk; if (!pf->present) continue; + disk->private_data = pf; + disk->queue = &pf_queue; add_disk(disk); } return 0; @@ -1003,6 +997,7 @@ static void __exit pf_exit(void) put_disk(pf->disk); pi_release(pf->pi); } + blk_cleanup_queue(&pf_queue); } MODULE_LICENSE("GPL"); diff --git a/drivers/block/rd.c b/drivers/block/rd.c index bbd247fa29dc..3129c2da894b 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -51,6 +51,7 @@ #include <linux/init.h> #include <linux/devfs_fs_kernel.h> #include <linux/buffer_head.h> /* for invalidate_bdev() */ +#include <linux/backing-dev.h> #include <asm/uaccess.h> /* @@ -89,7 +90,7 @@ static struct block_device *rd_bdev[NUM_RAMDISKS];/* Protected device data */ */ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ /* - * It would be very desiderable to have a soft-blocksize (that in the case + * It would be very desirable to have a soft-blocksize (that in the case * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages @@ -351,6 +352,10 @@ static struct file_operations initrd_fops = { #endif +static struct backing_dev_info rd_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; static int rd_open(struct inode * inode, struct file * filp) { @@ -379,6 +384,7 @@ static int rd_open(struct inode * inode, struct file * filp) rd_bdev[unit]->bd_openers++; rd_bdev[unit]->bd_block_size = rd_blocksize; rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops; + rd_bdev[unit]->bd_inode->i_mapping->backing_dev_info = &rd_backing_dev_info; rd_bdev[unit]->bd_inode->i_size = rd_length[unit]; rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue; rd_bdev[unit]->bd_disk = get_disk(rd_disks[unit]); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 2a5f3afefbfa..0dba63e52d4b 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -34,10 +34,11 @@ #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" -#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#define QUEUE (&swim3_queue) #include <linux/blk.h> #include <linux/devfs_fs_kernel.h> +static struct request_queue swim3_queue; static struct gendisk *disks[2]; #define MAX_FLOPPIES 2 @@ -246,8 +247,8 @@ static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); static int floppy_open(struct inode *inode, struct file *filp); static int floppy_release(struct inode *inode, struct file *filp); -static int floppy_check_change(kdev_t dev); -static int floppy_revalidate(kdev_t dev); +static int floppy_check_change(struct gendisk *disk); +static int floppy_revalidate(struct gendisk *disk); static int swim3_add_device(struct device_node *swims); int swim3_init(void); @@ -819,18 +820,12 @@ static struct floppy_struct floppy_type = static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { - struct floppy_state *fs; + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; int err; - int devnum = minor(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) return -EPERM; - fs = &floppy_states[devnum]; - if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; @@ -851,19 +846,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp, static int floppy_open(struct inode *inode, struct file *filp) { - struct floppy_state *fs; - volatile struct swim3 *sw; - int n, err; - int devnum = minor(inode->i_rdev); + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + volatile struct swim3 *sw = fs->swim3; + int n, err = 0; - if (devnum >= floppy_count) - return -ENODEV; - if (filp == 0) - return -EIO; - - fs = &floppy_states[devnum]; - sw = fs->swim3; - err = 0; if (fs->ref_count == 0) { if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; @@ -926,15 +912,8 @@ static int floppy_open(struct inode *inode, struct file *filp) static int floppy_release(struct inode *inode, struct file *filp) { - struct floppy_state *fs; - volatile struct swim3 *sw; - int devnum = minor(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - - fs = &floppy_states[devnum]; - sw = fs->swim3; + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + volatile struct swim3 *sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, 0xff); @@ -942,29 +921,17 @@ static int floppy_release(struct inode *inode, struct file *filp) return 0; } -static int floppy_check_change(kdev_t dev) +static int floppy_check_change(struct gendisk *disk) { - struct floppy_state *fs; - int devnum = minor(dev); - - if (major(dev) != MAJOR_NR || (devnum >= floppy_count)) - return 0; - - fs = &floppy_states[devnum]; + struct floppy_state *fs = disk->private_data; return fs->ejected; } -static int floppy_revalidate(kdev_t dev) +static int floppy_revalidate(struct gendisk *disk) { - struct floppy_state *fs; + struct floppy_state *fs = disk->private_data; volatile struct swim3 *sw; int ret, n; - int devnum = minor(dev); - - if (major(dev) != MAJOR_NR || (devnum >= floppy_count)) - return 0; - - fs = &floppy_states[devnum]; if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; @@ -1002,11 +969,11 @@ static void floppy_off(unsigned int nr) } static struct block_device_operations floppy_fops = { - open: floppy_open, - release: floppy_release, - ioctl: floppy_ioctl, - check_media_change: floppy_check_change, - revalidate: floppy_revalidate, + .open = floppy_open, + .release = floppy_release, + .ioctl = floppy_ioctl, + .media_changed = floppy_check_change, + .revalidate_disk= floppy_revalidate, }; static devfs_handle_t floppy_devfs_handle; @@ -1047,12 +1014,14 @@ int swim3_init(void) err = -EBUSY; goto out; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &swim3_lock); + blk_init_queue(&swim3_queue, do_fd_request, &swim3_lock); for (i = 0; i < floppy_count; i++) { struct gendisk *disk = disks[i]; disk->major = MAJOR_NR; disk->first_minor = i; disk->fops = &floppy_fops; + disk->private_data = &floppy_states[i]; + disk->queue = &swim3_queue; sprintf(disk->disk_name, "fd%d", i); set_capacity(disk, 2880); add_disk(disk); diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index 3ec747c3f80f..fdc9567d60a0 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -28,7 +28,7 @@ #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" -#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#define QUEUE (&swim_queue) #include <linux/stddef.h> #include <linux/kernel.h> @@ -97,7 +97,7 @@ static char *drive_names[7] = { int swimiop_init(void); static void swimiop_init_request(struct swim_iop_req *); -static int swimiop_send_request(CURRENT, struct swim_iop_req *); +static int swimiop_send_request(struct swim_iop_req *); static void swimiop_receive(struct iop_msg *, struct pt_regs *); static void swimiop_status_update(int, struct swim_drvstatus *); static int swimiop_eject(struct floppy_state *fs); @@ -106,8 +106,8 @@ static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); static int floppy_open(struct inode *inode, struct file *filp); static int floppy_release(struct inode *inode, struct file *filp); -static int floppy_check_change(kdev_t dev); -static int floppy_revalidate(kdev_t dev); +static int floppy_check_change(struct gendisk *disk); +static int floppy_revalidate(struct gendisk *disk); static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible); static void release_drive(struct floppy_state *fs); @@ -118,13 +118,14 @@ static void do_fd_request(request_queue_t * q); static void start_request(struct floppy_state *fs); static struct block_device_operations floppy_fops = { - open: floppy_open, - release: floppy_release, - ioctl: floppy_ioctl, - check_media_change: floppy_check_change, - revalidate: floppy_revalidate, + .open = floppy_open, + .release = floppy_release, + .ioctl = floppy_ioctl, + .media_changed = floppy_check_change, + .revalidate_disk= floppy_revalidate, }; +static struct request_queue swim_queue; /* * SWIM IOP initialization */ @@ -147,8 +148,7 @@ int swimiop_init(void) MAJOR_NR); return -EBUSY; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, - &swim_iop_lock); + blk_init_queue(&swim_queue, do_fd_request, &swim_iop_lock); printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n", DRIVER_VERSION); @@ -166,7 +166,7 @@ int swimiop_init(void) swimiop_init_request(&req); cmd->code = CMD_STATUS; cmd->drive_num = i + 1; - if (swimiop_send_request(CURRENT, &req) != 0) continue; + if (swimiop_send_request(&req) != 0) continue; while (!req.complete); if (cmd->error != 0) { printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error); @@ -195,6 +195,8 @@ int swimiop_init(void) disk->first_minor = i; disk->fops = &floppy_fops; sprintf(disk->disk_name, "fd%d", i); + disk->private_data = &floppy_states[i]; + disk->queue = &swim_queue; set_capacity(disk, 2880 * 2); add_disk(disk); } @@ -209,7 +211,7 @@ static void swimiop_init_request(struct swim_iop_req *req) req->done = NULL; } -static int swimiop_send_request(CURRENT, struct swim_iop_req *req) +static int swimiop_send_request(struct swim_iop_req *req) { unsigned long cpu_flags; int err; @@ -324,7 +326,7 @@ static int swimiop_eject(struct floppy_state *fs) swimiop_init_request(&req); cmd->code = CMD_EJECT; cmd->drive_num = fs->drive_num; - err = swimiop_send_request(CURRENT, &req); + err = swimiop_send_request(&req); if (err) { release_drive(fs); return err; @@ -348,18 +350,12 @@ static struct floppy_struct floppy_type = static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { - struct floppy_state *fs; + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; int err; - int devnum = MINOR(inode->i_rdev); - if (devnum >= floppy_count) - return -ENODEV; - if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) return -EPERM; - fs = &floppy_states[devnum]; - switch (cmd) { case FDEJECT: if (fs->ref_count != 1) @@ -377,32 +373,19 @@ static int floppy_ioctl(struct inode *inode, struct file *filp, static int floppy_open(struct inode *inode, struct file *filp) { - struct floppy_state *fs; - int err; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - if (filp == 0) - return -EIO; - - fs = &floppy_states[devnum]; - err = 0; - if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; - - if (err == 0 && (filp->f_flags & O_NDELAY) == 0 - && (filp->f_mode & 3)) { + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + + if (fs->ref_count == -1 || filp->f_flags & O_EXCL) + return -EBUSY; + + if ((filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { check_disk_change(inode->i_bdev); if (fs->ejected) - err = -ENXIO; + return -ENXIO; } - if (err == 0 && (filp->f_mode & 2)) { - if (fs->write_prot) - err = -EROFS; - } - - if (err) return err; + if ((filp->f_mode & 2) && fs->write_prot) + return -EROFS; if (filp->f_flags & O_EXCL) fs->ref_count = -1; @@ -414,43 +397,24 @@ static int floppy_open(struct inode *inode, struct file *filp) static int floppy_release(struct inode *inode, struct file *filp) { - struct floppy_state *fs; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - - fs = &floppy_states[devnum]; - if (fs->ref_count > 0) fs->ref_count--; + struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + if (fs->ref_count > 0) + fs->ref_count--; return 0; } -static int floppy_check_change(kdev_t dev) +static int floppy_check_change(struct gendisk *disk) { - struct floppy_state *fs; - int devnum = MINOR(dev); - - if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) - return 0; - - fs = &floppy_states[devnum]; + struct floppy_state *fs = disk->private_data; return fs->ejected; } -static int floppy_revalidate(kdev_t dev) +static int floppy_revalidate(struct gendisk *disk) { - struct floppy_state *fs; - int devnum = MINOR(dev); - - if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) - return 0; - - fs = &floppy_states[devnum]; - + struct floppy_state *fs = disk->private_data; grab_drive(fs, revalidating, 0); /* yadda, yadda */ release_drive(fs); - return 0; } @@ -604,7 +568,7 @@ static void start_request(struct floppy_state *fs) cmd->first_block = CURRENT->sector; cmd->num_blocks = CURRENT->current_nr_sectors; - if (swimiop_send_request(CURRENT, &req)) { + if (swimiop_send_request(&req)) { end_request(CURRENT, 0); continue; } diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 4a2b212f1261..8abd7ea68233 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -67,7 +67,6 @@ #define MM_BLKSIZE 1024 /* 1k blocks */ #define MM_HARDSECT 512 /* 512-byte hardware sectors */ #define MM_SHIFT 6 /* max 64 partitions on 4 cards */ -#define DEVICE_NR(device) (minor(device)>>MM_SHIFT) /* * Version Information @@ -812,10 +811,10 @@ static void del_battery_timer(void) * That's crap, since doing that while some partitions are opened * or mounted will give you really nasty results. */ -static int mm_revalidate(kdev_t i_rdev) +static int mm_revalidate(struct gendisk *disk) { - int card_number = DEVICE_NR(i_rdev); - set_capacity(mm_gendisk[card_number], cards[card_number].mm_size << 1); + struct cardinfo *card = disk->private_data; + set_capacity(disk, card->mm_size << 1); return 0; } /* @@ -826,17 +825,14 @@ static int mm_revalidate(kdev_t i_rdev) static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) { if (cmd == HDIO_GETGEO) { - unsigned int minor = minor(i->i_rdev); - int err, size, card_number = (minor >> MM_SHIFT); + struct cardinfo *card = i->i_bdev->bd_disk->private_data; + int size = card->mm_size * (1024 / MM_HARDSECT); struct hd_geometry geo; /* * get geometry: we have to fake one... trim the size to a * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, * whatever cylinders. */ - err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo)); - if (err) return -EFAULT; - size = cards[card_number].mm_size * (1024 / MM_HARDSECT); geo.heads = 64; geo.sectors = 32; geo.start = get_start_sect(i->i_bdev); @@ -855,13 +851,9 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned ----------------------------------------------------------------------------------- Future support for removable devices */ -static int mm_check_change(kdev_t i_rdev) +static int mm_check_change(struct gendisk *disk) { - int card_number = DEVICE_NR(i_rdev); -/* struct cardinfo *dev = cards + card_number; */ - if (card_number >= num_cards) /* paranoid */ - return 0; - +/* struct cardinfo *dev = disk->private_data; */ return 0; } /* @@ -870,10 +862,10 @@ static int mm_check_change(kdev_t i_rdev) ----------------------------------------------------------------------------------- */ static struct block_device_operations mm_fops = { - owner: THIS_MODULE, - ioctl: mm_ioctl, - revalidate: mm_revalidate, - check_media_change: mm_check_change, + .owner = THIS_MODULE, + .ioctl = mm_ioctl, + .revalidate_disk= mm_revalidate, + .media_changed = mm_check_change, }; /* ----------------------------------------------------------------------------------- @@ -1149,16 +1141,6 @@ static struct pci_driver mm_pci_driver = { ----------------------------------------------------------------------------------- */ -static request_queue_t * mm_queue_proc(kdev_t dev) -{ - int c = DEVICE_NR(dev); - - if (c < MM_MAXCARDS) - return &cards[c].queue; - else - return BLK_DEFAULT_QUEUE(MAJOR_NR); -} - int __init mm_init(void) { int retval, i; @@ -1183,7 +1165,6 @@ int __init mm_init(void) } devfs_handle = devfs_mk_dir(NULL, "umem", NULL); - blk_dev[MAJOR_NR].queue = mm_queue_proc; for (i = 0; i < num_cards; i++) { struct gendisk *disk = mm_gendisk[i]; sprintf(disk->disk_name, "umem%c", 'a'+i); @@ -1191,6 +1172,8 @@ int __init mm_init(void) disk->major = major_nr; disk->first_minor = i << MM_SHIFT; disk->fops = &mm_fops; + disk->private_data = &cards[i]; + disk->queue = &cards[i].queue; set_capacity(disk, cards[i].mm_size << 1); add_disk(disk); } diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index edb2676680e3..2311552b77e7 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -345,11 +345,10 @@ static struct block_device_operations z2_fops = .release = z2_release, }; -static struct gendisk *z2_find(int minor) +static struct gendisk *z2_find(dev_t dev, int *part, void *data) { - if (minor > Z2MINOR_COUNT) - return NULL; - return z2ram_gendisk; + *part = 0; + return get_disk(z2ram_gendisk); } int __init @@ -377,7 +376,8 @@ z2_init( void ) blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_z2_request, &z2ram_lock); add_disk(z2ram_gendisk); - blk_set_probe(MAJOR_NR, z2_find); + blk_register_region(MKDEV(MAJOR_NR, 0), Z2MINOR_COUNT, THIS_MODULE, + z2_find, NULL, NULL); return 0; } @@ -404,8 +404,7 @@ void cleanup_module( void ) { int i, j; - - blk_set_probe(MAJOR_NR, NULL); + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); if ( unregister_blkdev( MAJOR_NR, DEVICE_NAME ) != 0 ) printk( KERN_ERR DEVICE_NAME ": unregister of device failed\n"); diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index b8e1880d8714..93745b274cee 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -168,8 +168,7 @@ #include <linux/version.h> #define MAJOR_NR AZTECH_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) - +#define QUEUE (&azt_queue) #include <linux/blk.h> #include "aztcd.h" @@ -227,10 +226,11 @@ #define AZT_DEBUG_MULTISESSION #endif +static struct request_queue azt_queue; + static int current_valid(void) { return !blk_queue_empty(QUEUE) && - major(CURRENT->rq_dev) == MAJOR_NR && CURRENT->cmd == READ && CURRENT->sector != -1; } @@ -329,18 +329,18 @@ static int aztGetMultiDiskInfo(void); static int aztGetToc(int multi); /* Kernel Interface Functions */ -static int check_aztcd_media_change(kdev_t full_dev); +static int check_aztcd_media_change(struct gendisk *disk); static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int aztcd_open(struct inode *ip, struct file *fp); static int aztcd_release(struct inode *inode, struct file *file); static struct block_device_operations azt_fops = { - .owner = THIS_MODULE, - .open = aztcd_open, - .release = aztcd_release, - .ioctl = aztcd_ioctl, - .check_media_change = check_aztcd_media_change, + .owner = THIS_MODULE, + .open = aztcd_open, + .release = aztcd_release, + .ioctl = aztcd_ioctl, + .media_changed = check_aztcd_media_change, }; /* Aztcd State Machine: Controls Drive Operating State */ @@ -790,7 +790,7 @@ static int aztGetQChannelInfo(struct azt_Toc *qp) /* * Read the table of contents (TOC) and TOC header if necessary */ -static int aztUpdateToc() +static int aztUpdateToc(void) { int st; @@ -1141,7 +1141,7 @@ __setup("aztcd=", aztcd_setup); /* * Checking if the media has been changed */ -static int check_aztcd_media_change(kdev_t full_dev) +static int check_aztcd_media_change(struct gendisk *disk) { if (aztDiskChanged) { /* disk changed */ aztDiskChanged = 0; @@ -1677,8 +1677,8 @@ static int aztcd_release(struct inode *inode, struct file *file) { #ifdef AZT_DEBUG printk("aztcd: executing aztcd_release\n"); - printk("inode: %p, inode->i_rdev: %x file: %p\n", inode, - inode->i_rdev, file); + printk("inode: %p, device: %s file: %p\n", inode, + inode->i_bdev->bd_disk->disk_name, file); #endif if (!--azt_open_count) { azt_invalidate_buffers(); @@ -1917,12 +1917,13 @@ static int __init aztcd_init(void) ret = -EIO; goto err_out3; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_aztcd_request, &aztSpin); - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); + blk_init_queue(&azt_queue, do_aztcd_request, &aztSpin); + blk_queue_hardsect_size(&azt_queue, 2048); azt_disk->major = MAJOR_NR; azt_disk->first_minor = 0; azt_disk->fops = &azt_fops; sprintf(azt_disk->disk_name, "aztcd"); + azt_disk->queue = &azt_queue; add_disk(azt_disk); azt_invalidate_buffers(); @@ -1952,7 +1953,7 @@ static void __exit aztcd_exit(void) printk("What's that: can't unregister aztcd\n"); return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&azt_queue); if ((azt_port == 0x1f0) || (azt_port == 0x170)) { SWITCH_IDE_MASTER; release_region(azt_port, 8); /*IDE-interface */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 0fce58ecee6f..a4f52acc1e9e 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -267,6 +267,7 @@ #include <linux/blkpg.h> #include <linux/init.h> #include <linux/fcntl.h> +#include <linux/blkdev.h> #include <asm/uaccess.h> @@ -338,14 +339,11 @@ static struct cdrom_device_info *topCdromPtr; int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed; - int major = major(cdi->dev); struct cdrom_device_ops *cdo = cdi->ops; int *change_capability = (int *)&cdo->capability; /* hack */ cdinfo(CD_OPEN, "entering register_cdrom\n"); - if (major < 0 || major >= MAX_BLKDEV) - return -1; if (cdo->open == NULL || cdo->release == NULL) return -2; if ( !banner_printed ) { @@ -389,16 +387,11 @@ int register_cdrom(struct cdrom_device_info *cdi) int unregister_cdrom(struct cdrom_device_info *unreg) { struct cdrom_device_info *cdi, *prev; - int major = major(unreg->dev); - cdinfo(CD_OPEN, "entering unregister_cdrom\n"); - if (major < 0 || major >= MAX_BLKDEV) - return -1; - prev = NULL; cdi = topCdromPtr; - while (cdi != NULL && !kdev_same(cdi->dev, unreg->dev)) { + while (cdi && cdi != unreg) { prev = cdi; cdi = cdi->next; } @@ -414,17 +407,6 @@ int unregister_cdrom(struct cdrom_device_info *unreg) return 0; } -static struct cdrom_device_info *cdrom_find_device(kdev_t dev) -{ - struct cdrom_device_info *cdi; - - cdi = topCdromPtr; - while (cdi != NULL && !kdev_same(cdi->dev, dev)) - cdi = cdi->next; - - return cdi; -} - /* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. @@ -433,16 +415,11 @@ static struct cdrom_device_info *cdrom_find_device(kdev_t dev) * is in their own interest: device control becomes a lot easier * this way. */ -int cdrom_open(struct inode *ip, struct file *fp) +int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) { - struct cdrom_device_info *cdi; - kdev_t dev = ip->i_rdev; int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); - if ((cdi = cdrom_find_device(dev)) == NULL) - return -ENODEV; - /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) @@ -627,10 +604,8 @@ int check_for_audio_disc(struct cdrom_device_info * cdi, /* Admittedly, the logic below could be performed in a nicer way. */ -int cdrom_release(struct inode *ip, struct file *fp) +int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) { - kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; int opened_for_data; @@ -843,9 +818,8 @@ int media_changed(struct cdrom_device_info *cdi, int queue) return ret; } -int cdrom_media_changed(kdev_t dev) +int cdrom_media_changed(struct cdrom_device_info *cdi) { - struct cdrom_device_info *cdi = cdrom_find_device(dev); /* This talks to the VFS, which doesn't like errors - just 1 or 0. * Returning "0" is always safe (media hasn't been changed). Do that * if the low-level cdrom driver dosn't support media changed. */ @@ -1457,14 +1431,17 @@ static int cdrom_read_block(struct cdrom_device_info *cdi, * these days. ATAPI / SCSI specific code now mainly resides in * mmc_ioct(). */ -int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, - unsigned long arg) +int cdrom_ioctl(struct cdrom_device_info *cdi, struct inode *ip, + unsigned int cmd, unsigned long arg) { - kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; int ret; + /* Try the generic SCSI command ioctl's first.. */ + ret = scsi_cmd_ioctl(ip->i_bdev, cmd, arg); + if (ret != -ENOTTY) + return ret; + /* the first few commands do not deal with audio drive_info, but only with routines in cdrom device operations. */ switch (cmd) { @@ -1614,7 +1591,7 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); if (!CDROM_CAN(CDC_RESET)) return -ENOSYS; - invalidate_buffers(dev); + invalidate_bdev(ip->i_bdev, 0); return cdo->reset(cdi); } diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index f4077094707a..686fe183eb1b 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -177,7 +177,6 @@ #include "cdu31a.h" #define MAJOR_NR CDU31A_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) #include <linux/blk.h> #define CDU31A_READAHEAD 4 /* 128 sector, 64kB, 32 reads read-ahead */ @@ -238,6 +237,7 @@ static volatile unsigned short sony_cd_result_reg; static volatile unsigned short sony_cd_read_reg; static volatile unsigned short sony_cd_fifost_reg; +static struct request_queue cdu31a_queue; static spinlock_t cdu31a_lock = SPIN_LOCK_UNLOCKED; /* queue lock */ static int sony_spun_up = 0; /* Has the drive been spun up? */ @@ -1531,6 +1531,7 @@ read_data_block(char *buffer, */ static void do_cdu31a_request(request_queue_t * q) { + struct request *req; int block; int nblock; unsigned char res_reg[12]; @@ -1578,125 +1579,111 @@ static void do_cdu31a_request(request_queue_t * q) del_timer(&cdu31a_abort_timer); while (1) { - cdu31a_request_startover: /* * The beginning here is stolen from the hard disk driver. I hope * it's right. */ - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) goto end_do_cdu31a_request; - if (!sony_spun_up) { + if (!sony_spun_up) scd_spinup(); - } - block = CURRENT->sector; - nblock = CURRENT->nr_sectors; + req = elv_next_request(q); + block = req->sector; + nblock = req->nr_sectors; if (!sony_toc_read) { printk("CDU31A: TOC not read\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; + end_request(req, 0); + continue; } - if(CURRENT->flags & REQ_CMD) { - switch (rq_data_dir(CURRENT)) { - case READ: - /* - * If the block address is invalid or the request goes beyond the end of - * the media, return an error. - */ - if ((block / 4) >= sony_toc.lead_out_start_lba) { - printk - ("CDU31A: Request past end of media\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } - if (((block + nblock) / 4) >= - sony_toc.lead_out_start_lba) { - printk - ("CDU31A: Request past end of media\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } + /* WTF??? */ + if (!(req->flags & REQ_CMD)) + continue; + if (rq_data_dir(req) == WRITE) { + end_request(req, 0); + continue; + } + if (rq_data_dir(req) != READ) + panic("CDU31A: Unknown cmd"); + /* + * If the block address is invalid or the request goes beyond the end of + * the media, return an error. + */ + if ((block / 4) >= sony_toc.lead_out_start_lba) { + printk("CDU31A: Request past end of media\n"); + end_request(req, 0); + continue; + } + if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { + printk("CDU31A: Request past end of media\n"); + end_request(req, 0); + continue; + } - num_retries = 0; + num_retries = 0; - try_read_again: - while (handle_sony_cd_attention()); + try_read_again: + while (handle_sony_cd_attention()); - if (!sony_toc_read) { - printk("CDU31A: TOC not read\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } + if (!sony_toc_read) { + printk("CDU31A: TOC not read\n"); + end_request(req, 0); + continue; + } - /* If no data is left to be read from the drive, start the - next request. */ - if (sony_blocks_left == 0) { - if (start_request - (block / 4, CDU31A_READAHEAD / 4, 0)) { - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } - } - /* If the requested block is not the next one waiting in - the driver, abort the current operation and start a - new one. */ - else if (block != sony_next_block) { + /* If no data is left to be read from the drive, start the + next request. */ + if (sony_blocks_left == 0) { + if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) { + end_request(req, 0); + continue; + } + } + /* If the requested block is not the next one waiting in + the driver, abort the current operation and start a + new one. */ + else if (block != sony_next_block) { #if DEBUG - printk - ("CDU31A Warning: Read for block %d, expected %d\n", - block, sony_next_block); + printk("CDU31A Warning: Read for block %d, expected %d\n", + block, sony_next_block); #endif - abort_read(); - if (!sony_toc_read) { - printk("CDU31A: TOC not read\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } - if (start_request - (block / 4, CDU31A_READAHEAD / 4, 0)) { - printk - ("CDU31a: start request failed\n"); - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } - } + abort_read(); + if (!sony_toc_read) { + printk("CDU31A: TOC not read\n"); + end_request(req, 0); + continue; + } + if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) { + printk("CDU31a: start request failed\n"); + end_request(req, 0); + continue; + } + } - read_data_block(CURRENT->buffer, block, nblock, - res_reg, &res_size); - if (res_reg[0] == 0x20) { - if (num_retries > MAX_CDU31A_RETRIES) { - end_request(CURRENT, 0); - goto cdu31a_request_startover; - } + read_data_block(req->buffer, block, nblock, res_reg, &res_size); - num_retries++; - if (res_reg[1] == SONY_NOT_SPIN_ERR) { - do_sony_cd_cmd(SONY_SPIN_UP_CMD, - NULL, 0, res_reg, - &res_size); - } else { - printk - ("CDU31A: %s error for block %d, nblock %d\n", - translate_error(res_reg[1]), - block, nblock); - } - goto try_read_again; - } else { - end_request(CURRENT, 1); - } - break; + if (res_reg[0] != 0x20) { + end_request(req, 1); + continue; + } - case WRITE: - end_request(CURRENT, 0); - break; + if (num_retries > MAX_CDU31A_RETRIES) { + end_request(req, 0); + continue; + } - default: - panic("CDU31A: Unknown cmd"); - } + num_retries++; + if (res_reg[1] == SONY_NOT_SPIN_ERR) { + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, + &res_size); + } else { + printk("CDU31A: %s error for block %d, nblock %d\n", + translate_error(res_reg[1]), block, nblock); } + goto try_read_again; } end_do_cdu31a_request: spin_lock_irq(q->queue_lock); @@ -3151,15 +3138,6 @@ static void scd_release(struct cdrom_device_info *cdi) sony_usage--; } -struct block_device_operations scd_bdops = -{ - .owner = THIS_MODULE, - .open = cdrom_open, - .release = cdrom_release, - .ioctl = cdrom_ioctl, - .check_media_change = cdrom_media_changed, -}; - static struct cdrom_device_ops scd_dops = { .open = scd_open, .release = scd_release, @@ -3188,6 +3166,36 @@ static struct cdrom_device_info scd_info = { .name = "cdu31a" }; +static int scd_block_open(struct inode *inode, struct file *file) +{ + return cdrom_open(&scd_info, inode, file); +} + +static int scd_block_release(struct inode *inode, struct file *file) +{ + return cdrom_release(&scd_info, file); +} + +static int scd_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return cdrom_ioctl(&scd_info, inode, cmd, arg); +} + +static int scd_block_media_changed(struct gendisk *disk) +{ + return cdrom_media_changed(&scd_info); +} + +struct block_device_operations scd_bdops = +{ + .owner = THIS_MODULE, + .open = scd_block_open, + .release = scd_block_release, + .ioctl = scd_block_ioctl, + .media_changed = scd_block_media_changed, +}; + static struct gendisk *scd_gendisk; /* The different types of disc loading mechanisms supported */ @@ -3430,18 +3438,16 @@ int __init cdu31a_init(void) is_a_cdu31a = strcmp("CD-ROM CDU31A", drive_config.product_id) == 0; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), - do_cdu31a_request, - &cdu31a_lock); + blk_init_queue(&cdu31a_queue, do_cdu31a_request, &cdu31a_lock); init_timer(&cdu31a_abort_timer); cdu31a_abort_timer.function = handle_abort_timeout; - scd_info.dev = mk_kdev(MAJOR_NR, 0); scd_info.mask = deficiency; scd_gendisk = disk; if (register_cdrom(&scd_info)) goto errout0; + disk->queue = &cdu31a_queue; add_disk(disk); disk_changed = 1; @@ -3449,7 +3455,7 @@ int __init cdu31a_init(void) errout0: printk("Unable to register CDU-31a with Uniform cdrom driver\n"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&cdu31a_queue); put_disk(disk); errout1: if (unregister_blkdev(MAJOR_NR, "cdu31a")) { @@ -3476,7 +3482,7 @@ void __exit cdu31a_exit(void) return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&cdu31a_queue); if (cdu31a_irq > 0) free_irq(cdu31a_irq, NULL); diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index 8a83a381bcc1..aa3b09000a88 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -198,7 +198,6 @@ History: #include <asm/io.h> #define MAJOR_NR CM206_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) #include <linux/blk.h> @@ -302,6 +301,7 @@ struct cm206_struct { #define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ static struct cm206_struct *cd; /* the main memory structure */ +static struct request_queue cm206_queue; static spinlock_t cm206_lock = SPIN_LOCK_UNLOCKED; /* First, we define some polling functions. These are actually @@ -770,15 +770,6 @@ void get_disc_status(void) } } -struct block_device_operations cm206_bdops = -{ - .owner = THIS_MODULE, - .open = cdrom_open, - .release = cdrom_release, - .ioctl = cdrom_ioctl, - .check_media_change = cdrom_media_changed, -}; - /* The new open. The real opening strategy is defined in cdrom.c. */ static int cm206_open(struct cdrom_device_info *cdi, int purpose) @@ -860,24 +851,25 @@ static void do_cm206_request(request_queue_t * q) long int i, cd_sec_no; int quarter, error; uch *source, *dest; + struct request *req; - while (1) { /* repeat until all requests have been satisfied */ - if (blk_queue_empty(QUEUE)) + while (1) { /* repeat until all requests have been satisfied */ + if (blk_queue_empty(q)) return; - if (CURRENT->cmd != READ) { - debug(("Non-read command %d on cdrom\n", - CURRENT->cmd)); - end_request(CURRENT, 0); + req = elv_next_request(q); + if (req->cmd != READ) { + debug(("Non-read command %d on cdrom\n", req->cmd)); + end_request(req, 0); continue; } spin_unlock_irq(q->queue_lock); error = 0; - for (i = 0; i < CURRENT->nr_sectors; i++) { + for (i = 0; i < req->nr_sectors; i++) { int e1, e2; - cd_sec_no = (CURRENT->sector + i) / BLOCKS_ISO; /* 4 times 512 bytes */ - quarter = (CURRENT->sector + i) % BLOCKS_ISO; - dest = CURRENT->buffer + i * LINUX_BLOCK_SIZE; + cd_sec_no = (req->sector + i) / BLOCKS_ISO; /* 4 times 512 bytes */ + quarter = (req->sector + i) % BLOCKS_ISO; + dest = req->buffer + i * LINUX_BLOCK_SIZE; /* is already in buffer memory? */ if (cd->sector_first <= cd_sec_no && cd_sec_no < cd->sector_last) { @@ -899,7 +891,7 @@ static void do_cm206_request(request_queue_t * q) } } spin_lock_irq(q->queue_lock); - end_request(CURRENT, !error); + end_request(req, !error); } } @@ -1357,6 +1349,36 @@ static struct cdrom_device_info cm206_info = { .name = "cm206", }; +static int cm206_block_open(struct inode *inode, struct file *file) +{ + return cdrom_open(&cm206_info, inode, file); +} + +static int cm206_block_release(struct inode *inode, struct file *file) +{ + return cdrom_release(&cm206_info, file); +} + +static int cm206_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return cdrom_ioctl(&cm206_info, inode, cmd, arg); +} + +static int cm206_block_media_changed(struct gendisk *disk) +{ + return cdrom_media_changed(&cm206_info); +} + +static struct block_device_operations cm206_bdops = +{ + .owner = THIS_MODULE, + .open = cm206_block_open, + .release = cm206_block_release, + .ioctl = cm206_block_ioctl, + .media_changed = cm206_block_media_changed, +}; + static struct gendisk *cm206_gendisk; /* This function probes for the adapter card. It returns the base @@ -1479,15 +1501,14 @@ int __init cm206_init(void) disk->fops = &cm206_bdops; disk->flags = GENHD_FL_CD; cm206_gendisk = disk; - cm206_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&cm206_info) != 0) { printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); goto out_cdrom; } + blk_init_queue(&cm206_queue, do_cm206_request, &cm206_lock); + blk_queue_hardsect_size(&cm206_queue, 2048); + disk->queue = &cm206_queue; add_disk(disk); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_cm206_request, - &cm206_lock); - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ cd->sector_last = -1; /* flag no data buffered */ @@ -1550,7 +1571,7 @@ void __exit cm206_exit(void) printk("Can't unregister major cm206\n"); return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&cm206_queue); free_irq(cm206_irq, NULL); kfree(cd); release_region(cm206_base, 16); diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index d82b99f5a4b5..44ed8327f795 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -70,7 +70,6 @@ #include <asm/uaccess.h> #define MAJOR_NR GOLDSTAR_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) #include <linux/blk.h> #define gscd_port gscd /* for compatible parameter passing with "insmod" */ #include "gscd.h" @@ -86,7 +85,7 @@ MODULE_PARM(gscd, "h"); * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); */ -static void gscd_read_cmd(void); +static void gscd_read_cmd(struct request *req); static void gscd_hsg2msf(long hsg, struct msf *msf); static void gscd_bin2bcd(unsigned char *p); @@ -97,7 +96,7 @@ static int gscd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static int gscd_open(struct inode *, struct file *); static int gscd_release(struct inode *, struct file *); -static int check_gscd_med_chg(kdev_t); +static int check_gscd_med_chg(struct gendisk *disk); /* GoldStar Funktionen */ @@ -151,35 +150,25 @@ static int AudioEnd_f; static struct timer_list gscd_timer; static spinlock_t gscd_lock = SPIN_LOCK_UNLOCKED; +struct request_queue gscd_queue; static struct block_device_operations gscd_fops = { - .owner = THIS_MODULE, - .open = gscd_open, - .release = gscd_release, - .ioctl = gscd_ioctl, - .check_media_change = check_gscd_med_chg, + .owner = THIS_MODULE, + .open = gscd_open, + .release = gscd_release, + .ioctl = gscd_ioctl, + .media_changed = check_gscd_med_chg, }; /* * Checking if the media has been changed * (not yet implemented) */ -static int check_gscd_med_chg(kdev_t full_dev) +static int check_gscd_med_chg(struct gendisk *disk) { - int target; - - - target = minor(full_dev); - - if (target > 0) { - printk - ("GSCD: GoldStar CD-ROM request error: invalid device.\n"); - return 0; - } #ifdef GSCD_DEBUG printk("gscd: check_med_change\n"); #endif - return 0; } @@ -240,16 +229,14 @@ static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, * When Linux gets variable block sizes this will probably go away. */ -static void gscd_transfer(void) +static void gscd_transfer(struct request *req) { - long offs; - - while (CURRENT->nr_sectors > 0 && gscd_bn == CURRENT->sector / 4) { - offs = (CURRENT->sector & 3) * 512; - memcpy(CURRENT->buffer, gscd_buf + offs, 512); - CURRENT->nr_sectors--; - CURRENT->sector++; - CURRENT->buffer += 512; + while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { + long offs = (req->sector & 3) * 512; + memcpy(req->buffer, gscd_buf + offs, 512); + req->nr_sectors--; + req->sector++; + req->buffer += 512; } } @@ -265,46 +252,40 @@ static void do_gscd_request(request_queue_t * q) static void __do_gscd_request(unsigned long dummy) { - unsigned int block, dev; + struct request *req; + unsigned int block; unsigned int nsect; - repeat: - if (blk_queue_empty(QUEUE)) +repeat: + if (blk_queue_empty(&gscd_queue)) return; - dev = minor(CURRENT->rq_dev); - block = CURRENT->sector; - nsect = CURRENT->nr_sectors; + req = elv_next_request(&gscd_queue); + block = req->sector; + nsect = req->nr_sectors; - if (CURRENT->sector == -1) + if (req->sector == -1) goto out; - if (CURRENT->cmd != READ) { - printk("GSCD: bad cmd %p\n", CURRENT->cmd); - end_request(CURRENT, 0); + if (req->cmd != READ) { + printk("GSCD: bad cmd %d\n", req->cmd); + end_request(req, 0); goto repeat; } - if (dev != 0) { - printk("GSCD: this version supports only one device\n"); - end_request(CURRENT, 0); - goto repeat; - } - - gscd_transfer(); + gscd_transfer(req); /* if we satisfied the request from the buffer, we're done. */ - if (CURRENT->nr_sectors == 0) { - end_request(CURRENT, 1); + if (req->nr_sectors == 0) { + end_request(req, 1); goto repeat; } #ifdef GSCD_DEBUG - printk("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect); + printk("GSCD: block %d, nsect %d\n", block, nsect); #endif - - gscd_read_cmd(); - out: + gscd_read_cmd(req); +out: return; } @@ -315,25 +296,23 @@ static void __do_gscd_request(unsigned long dummy) * read-data command. */ -static void gscd_read_cmd(void) +static void gscd_read_cmd(struct request *req) { long block; struct gscd_Play_msf gscdcmd; char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ - - cmd_status(); if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { printk("GSCD: no disk or door open\n"); - end_request(CURRENT, 0); + end_request(req, 0); } else { if (disk_state & ST_INVALID) { printk("GSCD: disk invalid\n"); - end_request(CURRENT, 0); + end_request(req, 0); } else { gscd_bn = -1; /* purge our buffer */ - block = CURRENT->sector / 4; + block = req->sector / 4; gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ cmd[2] = gscdcmd.start.min; @@ -347,9 +326,9 @@ static void gscd_read_cmd(void) cmd_out(TYPE_DATA, (char *) &cmd, (char *) &gscd_buf[0], 1); - gscd_bn = CURRENT->sector / 4; - gscd_transfer(); - end_request(CURRENT, 1); + gscd_bn = req->sector / 4; + gscd_transfer(req); + end_request(req, 1); } } SET_TIMER(__do_gscd_request, 1); @@ -911,7 +890,7 @@ static void __exit gscd_exit(void) printk("What's that: can't unregister GoldStar-module\n"); return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&gscd_queue); release_region(gscd_port, GSCD_IO_EXTENT); printk(KERN_INFO "GoldStar-module released.\n"); } @@ -989,11 +968,12 @@ static int __init gscd_init(void) devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_gscd_request, &gscd_lock); + blk_init_queue(&gscd_queue, do_gscd_request, &gscd_lock); disk_state = 0; gscdPresent = 1; + gscd_disk->queue = &gscd_queue; add_disk(gscd_disk); printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index e6c72eabda52..a12e6c63d2a4 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -102,7 +102,7 @@ #include <asm/uaccess.h> #define MAJOR_NR MITSUMI_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) +#define QUEUE (&mcd_queue) #include <linux/blk.h> #define mcd_port mcd /* for compatible parameter passing with "insmod" */ @@ -116,6 +116,7 @@ static int mcd1xhold; /* Is the drive connected properly and responding?? */ static int mcdPresent; +static struct request_queue mcd_queue; #define QUICK_LOOP_DELAY udelay(45) /* use udelay */ #define QUICK_LOOP_COUNT 20 @@ -123,7 +124,6 @@ static int mcdPresent; static int current_valid(void) { return !blk_queue_empty(QUEUE) && - major(CURRENT->rq_dev) == MAJOR_NR && CURRENT->cmd == READ && CURRENT->sector != -1; } @@ -188,18 +188,9 @@ static void mcd_release(struct cdrom_device_info *cdi); static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr); static int mcd_tray_move(struct cdrom_device_info *cdi, int position); static spinlock_t mcd_spinlock = SPIN_LOCK_UNLOCKED; -int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, +static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg); -int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); - -struct block_device_operations mcd_bdops = -{ - .owner = THIS_MODULE, - .open = cdrom_open, - .release = cdrom_release, - .ioctl = cdrom_ioctl, - .check_media_change = cdrom_media_changed, -}; +static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); static struct timer_list mcd_timer; @@ -221,6 +212,36 @@ static struct cdrom_device_info mcd_info = { .name = "mcd", }; +static int mcd_block_open(struct inode *inode, struct file *file) +{ + return cdrom_open(&mcd_info, inode, file); +} + +static int mcd_block_release(struct inode *inode, struct file *file) +{ + return cdrom_release(&mcd_info, file); +} + +static int mcd_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return cdrom_ioctl(&mcd_info, inode, cmd, arg); +} + +static int mcd_block_media_changed(struct gendisk *disk) +{ + return cdrom_media_changed(&mcd_info); +} + +static struct block_device_operations mcd_bdops = +{ + .owner = THIS_MODULE, + .open = mcd_block_open, + .release = mcd_block_release, + .ioctl = mcd_block_ioctl, + .media_changed = mcd_block_media_changed, +}; + static struct gendisk *mcd_gendisk; #ifndef MODULE @@ -1055,8 +1076,7 @@ int __init mcd_init(void) goto out_region; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcd_request, - &mcd_spinlock); + blk_init_queue(&mcd_queue, do_mcd_request, &mcd_spinlock); /* check for card */ @@ -1128,12 +1148,12 @@ int __init mcd_init(void) disk->fops = &mcd_bdops; disk->flags = GENHD_FL_CD; mcd_gendisk = disk; - mcd_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&mcd_info) != 0) { printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n"); goto out_cdrom; } + disk->queue = &mcd_queue; add_disk(disk); printk(msg); return 0; @@ -1144,7 +1164,7 @@ out_probe: release_region(mcd_port, 4); out_region: unregister_blkdev(MAJOR_NR, "mcd"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mcd_queue); put_disk(disk); return -EIO; } @@ -1523,7 +1543,7 @@ void __exit mcd_exit(void) printk(KERN_WARNING "Can't unregister major mcd\n"); return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mcd_queue); del_timer_sync(&mcd_timer); } diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 9747c15b926b..1227392aeac0 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -220,13 +220,38 @@ struct s_drive_stuff { int mcdx_init(void); void do_mcdx_request(request_queue_t * q); -struct block_device_operations mcdx_bdops = +static int mcdx_block_open(struct inode *inode, struct file *file) { - owner: THIS_MODULE, - open: cdrom_open, - release: cdrom_release, - ioctl: cdrom_ioctl, - check_media_change: cdrom_media_changed, + struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; + return cdrom_open(&p->info, inode, file); +} + +static int mcdx_block_release(struct inode *inode, struct file *file) +{ + struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; + return cdrom_release(&p->info, file); +} + +static int mcdx_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; + return cdrom_ioctl(&p->info, inode, cmd, arg); +} + +static int mcdx_block_media_changed(struct gendisk *disk) +{ + struct s_drive_stuff *p = disk->private_data; + return cdrom_media_changed(&p->info); +} + +static struct block_device_operations mcdx_bdops = +{ + .owner = THIS_MODULE, + .open = mcdx_block_open, + .release = mcdx_block_release, + .ioctl = mcdx_block_ioctl, + .media_changed = mcdx_block_media_changed, }; @@ -292,6 +317,7 @@ static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED; +static struct request_queue mcdx_queue; MODULE_PARM(mcdx, "1-4i"); static struct cdrom_device_ops mcdx_dops = { @@ -550,66 +576,63 @@ static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, void do_mcdx_request(request_queue_t * q) { - int dev; struct s_drive_stuff *stuffp; + struct request *req; again: - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) return; - dev = minor(CURRENT->rq_dev); - stuffp = mcdx_stuffp[dev]; + req = elv_next_request(q); + stuffp = req->rq_disk->private_data; - if ((dev < 0) - || (dev >= MCDX_NDRIVES) - || !stuffp || (!stuffp->present)) { - xwarn("do_request(): bad device: %s\n", - kdevname(CURRENT->rq_dev)); + if (!stuffp->present) { + xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name); xtrace(REQUEST, "end_request(0): bad device\n"); - end_request(CURRENT, 0); + end_request(req, 0); return; } if (stuffp->audio) { xwarn("do_request() attempt to read from audio cd\n"); xtrace(REQUEST, "end_request(0): read from audio\n"); - end_request(CURRENT, 0); + end_request(req, 0); return; } xtrace(REQUEST, "do_request() (%lu + %lu)\n", - CURRENT->sector, CURRENT->nr_sectors); + req->sector, req->nr_sectors); - if (CURRENT->cmd != READ) { + if (req->cmd != READ) { xwarn("do_request(): non-read command to cd!!\n"); xtrace(REQUEST, "end_request(0): write\n"); - end_request(CURRENT, 0); + end_request(req, 0); return; } else { stuffp->status = 0; - while (CURRENT->nr_sectors) { + while (req->nr_sectors) { int i; i = mcdx_transfer(stuffp, - CURRENT->buffer, - CURRENT->sector, - CURRENT->nr_sectors); + req->buffer, + req->sector, + req->nr_sectors); if (i == -1) { - end_request(CURRENT, 0); + end_request(req, 0); goto again; } - CURRENT->sector += i; - CURRENT->nr_sectors -= i; - CURRENT->buffer += (i * 512); + req->sector += i; + req->nr_sectors -= i; + req->buffer += (i * 512); } - end_request(CURRENT, 1); + end_request(req, 1); goto again; xtrace(REQUEST, "end_request(1)\n"); - end_request(CURRENT, 1); + end_request(req, 1); } goto again; @@ -1041,10 +1064,10 @@ void __exit mcdx_exit(void) kfree(stuffp); } - if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) { + if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) { xwarn("cleanup() unregister_blkdev() failed\n"); } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mcdx_queue); #if !MCDX_QUIET else xinfo("cleanup() succeeded\n"); @@ -1179,8 +1202,7 @@ int __init mcdx_init_drive(int drive) return 1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcdx_request, - &mcdx_lock); + blk_init_queue(&mcdx_queue, do_mcdx_request, &mcdx_lock); xtrace(INIT, "init() subscribe irq and i/o\n"); mcdx_irq_map[stuffp->irq] = stuffp; @@ -1190,7 +1212,7 @@ int __init mcdx_init_drive(int drive) xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); stuffp->irq = 0; - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mcdx_queue); kfree(stuffp); put_disk(disk); return 0; @@ -1218,7 +1240,6 @@ int __init mcdx_init_drive(int drive) stuffp->info.capacity = 1; stuffp->info.handle = stuffp; sprintf(stuffp->info.name, "mcdx%d", drive); - stuffp->info.dev = mk_kdev(MAJOR_NR, drive); disk->major = MAJOR_NR; disk->first_minor = drive; strcpy(disk->disk_name, stuffp->info.name); @@ -1240,9 +1261,11 @@ int __init mcdx_init_drive(int drive) put_disk(disk); if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&mcdx_queue); return 2; } + disk->private_data = stuffp; + disk->queue = &mcdx_queue; add_disk(disk); printk(msg); return 0; diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 6abce539684e..01e2cff57400 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -76,7 +76,7 @@ #include <asm/io.h> #define MAJOR_NR OPTICS_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) +#define QUEUE (&opt_queue) #include <linux/blk.h> #include <linux/cdrom.h> @@ -265,8 +265,8 @@ static int sleep_timeout; /* max # of ticks to sleep */ static DECLARE_WAIT_QUEUE_HEAD(waitq); static void sleep_timer(unsigned long data); static struct timer_list delay_timer = {function: sleep_timer}; -spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED; - +static spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED; +static struct request_queue opt_queue; /* Timer routine: wake up when desired flag goes low, or when timeout expires. */ @@ -977,7 +977,6 @@ static int update_toc(void) static int current_valid(void) { return !blk_queue_empty(QUEUE) && - major(CURRENT->rq_dev) == MAJOR_NR && CURRENT->cmd == READ && CURRENT->sector != -1; } @@ -1896,8 +1895,8 @@ static int opt_release(struct inode *ip, struct file *fp) int status; DEBUG((DEBUG_VFS, "executing opt_release")); - DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n", - ip, ip -> i_rdev, fp)); + DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n", + ip, ip->i_bdev->bd_disk->disk_name, fp)); if (!--open_count) { toc_uptodate = 0; @@ -1918,10 +1917,11 @@ static int opt_release(struct inode *ip, struct file *fp) /* Check if disk has been changed */ -static int opt_media_change(kdev_t dev) +static int opt_media_change(struct gendisk *disk) { DEBUG((DEBUG_VFS, "executing opt_media_change")); - DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed)); + DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n", + disk->disk_name, disk_changed)); if (disk_changed) { disk_changed = 0; @@ -1973,11 +1973,11 @@ static int __init version_ok(void) static struct block_device_operations opt_fops = { - .owner = THIS_MODULE, - .open = opt_open, - .release = opt_release, - .ioctl = opt_ioctl, - .check_media_change = opt_media_change, + .owner = THIS_MODULE, + .open = opt_open, + .release = opt_release, + .ioctl = opt_ioctl, + .media_changed = opt_media_change, }; #ifndef MODULE @@ -2054,9 +2054,9 @@ static int __init optcd_init(void) } devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_optcd_request, - &optcd_lock); - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); + blk_init_queue(&opt_queue, do_optcd_request, &optcd_lock); + blk_queue_hardsect_size(&opt_queue, 2048); + optcd_disk->queue = &opt_queue; add_disk(optcd_disk); printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); @@ -2073,7 +2073,7 @@ static void __exit optcd_exit(void) printk(KERN_ERR "optcd: what's that: can't unregister\n"); return; } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&opt_queue); release_region(optcd_port, 4); printk(KERN_INFO "optcd: module released.\n"); } diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 22a4ca708c6f..58eaf08e4d57 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -354,6 +354,13 @@ * Marcin Dalecki */ +/* + * Add bio/kdev_t changes for 2.5.x required to make it work again. + * Still room for improvement in the request handling here if anyone + * actually cares. Bring your own chainsaw. Paul G. 02/2002 + */ + + #include <linux/module.h> #include <linux/version.h> @@ -456,12 +463,15 @@ static int sbpcd[] = * Protects access to global structures etc. */ static spinlock_t sbpcd_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; +static struct request_queue sbpcd_queue; MODULE_PARM(sbpcd, "2i"); MODULE_PARM(max_drives, "i"); #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) +static spinlock_t sbpcd_lock = SPIN_LOCK_UNLOCKED; + /*==========================================================================*/ #define INLINE inline @@ -4841,7 +4851,7 @@ static void do_sbpcd_request(request_queue_t * q) #ifdef DEBUG_GTL xnr=++xx_nr; - if(blk_queue_empty(QUEUE)) + if(blk_queue_empty(q)) { printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", xnr, current->pid, jiffies); @@ -4850,32 +4860,27 @@ static void do_sbpcd_request(request_queue_t * q) return; } + req = elv_next_request(q); + printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", - xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); + xnr, req, req->sector, req->nr_sectors, current->pid, jiffies); #endif - - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) return; - req = CURRENT; /* take out our request so no other */ - blkdev_dequeue_request(req); /* task can fuck it up GTL */ + req = elv_next_request(q); /* take out our request so no other */ if (req -> sector == -1) - end_request(CURRENT, 0); + end_request(req, 0); spin_unlock_irq(q->queue_lock); down(&ioctl_read_sem); - if (req->cmd != READ) + if (rq_data_dir(CURRENT) != READ) { - msg(DBG_INF, "bad cmd %d\n", req->cmd); - goto err_done; - } - p = D_S + minor(req->rq_dev); - if (p->drv_id==-1) { - msg(DBG_INF, "do_request: bad device: %s\n", - kdevname(req->rq_dev)); + msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); goto err_done; } + p = req->rq_disk->private_data; #if OLD_BUSY while (busy_audio) sbp_sleep(HZ); /* wait a bit */ busy_data=1; @@ -4903,7 +4908,7 @@ static void do_sbpcd_request(request_queue_t * q) #endif up(&ioctl_read_sem); spin_lock_irq(q->queue_lock); - end_request(CURRENT, 1); + end_request(req, 1); goto request_loop; } @@ -4944,7 +4949,7 @@ static void do_sbpcd_request(request_queue_t * q) #endif up(&ioctl_read_sem); spin_lock_irq(q->queue_lock); - end_request(CURRENT, 1); + end_request(req, 1); goto request_loop; } } @@ -4960,7 +4965,7 @@ static void do_sbpcd_request(request_queue_t * q) up(&ioctl_read_sem); sbp_sleep(0); /* wait a bit, try again */ spin_lock_irq(q->queue_lock); - end_request(CURRENT, 0); + end_request(req, 0); goto request_loop; } /*==========================================================================*/ @@ -5351,13 +5356,38 @@ static int sbp_data(struct request *req) } /*==========================================================================*/ +static int sbpcd_block_open(struct inode *inode, struct file *file) +{ + struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; + return cdrom_open(p->sbpcd_infop, inode, file); +} + +static int sbpcd_block_release(struct inode *inode, struct file *file) +{ + struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; + return cdrom_release(p->sbpcd_infop, file); +} + +static int sbpcd_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; + return cdrom_ioctl(p->sbpcd_infop, inode, cmd, arg); +} + +static int sbpcd_block_media_changed(struct gendisk *disk) +{ + struct sbpcd_drive *p = disk->private_data; + return cdrom_media_changed(p->sbpcd_infop); +} + static struct block_device_operations sbpcd_bdops = { - owner: THIS_MODULE, - open: cdrom_open, - release: cdrom_release, - ioctl: cdrom_ioctl, - check_media_change: cdrom_media_changed, + .owner = THIS_MODULE, + .open = sbpcd_block_open, + .release = sbpcd_block_release, + .ioctl = sbpcd_block_ioctl, + .media_changed = sbpcd_block_media_changed, }; /*==========================================================================*/ /* @@ -5752,6 +5782,12 @@ int __init sbpcd_init(void) if (i>=0) p->CD_changed=1; } + if (!request_region(CDo_command,4,major_name)) + { + printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); + return -EIO; + } + /* * Turn on the CD audio channels. * The addresses are obtained from SOUND_BASE (see sbpcd.h). @@ -5770,11 +5806,10 @@ int __init sbpcd_init(void) goto init_done; #endif /* MODULE */ } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sbpcd_request, &sbpcd_lock); - - request_region(CDo_command,4,major_name); + blk_init_queue(&sbpcd_queue, do_sbpcd_request, &sbpcd_lock); devfs_handle = devfs_mk_dir (NULL, "sbp", NULL); + for (j=0;j<NR_SBPCD;j++) { struct cdrom_device_info * sbpcd_infop; @@ -5804,7 +5839,7 @@ int __init sbpcd_init(void) printk("Can't unregister %s\n", major_name); } release_region(CDo_command,4); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sbpcd_queue); return -EIO; } #ifdef MODULE @@ -5820,7 +5855,7 @@ int __init sbpcd_init(void) if (sbpcd_infop == NULL) { release_region(CDo_command,4); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sbpcd_queue); return -ENOMEM; } memset(sbpcd_infop, 0, sizeof(struct cdrom_device_info)); @@ -5828,7 +5863,6 @@ int __init sbpcd_init(void) sbpcd_infop->speed = 2; sbpcd_infop->capacity = 1; sprintf(sbpcd_infop->name, "sbpcd%d", j); - sbpcd_infop->dev = mk_kdev(MAJOR_NR, j); sbpcd_infop->handle = p; p->sbpcd_infop = sbpcd_infop; disk = alloc_disk(1); @@ -5844,9 +5878,11 @@ int __init sbpcd_init(void) { printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n"); } + disk->private_data = p; + disk->queue = &sbpcd_queue; add_disk(disk); } - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CD_FRAMESIZE); + blk_queue_hardsect_size(&sbpcd_queue, CD_FRAMESIZE); #ifndef MODULE init_done: @@ -5865,7 +5901,7 @@ void sbpcd_exit(void) return; } release_region(CDo_command,4); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sbpcd_queue); devfs_unregister (devfs_handle); for (j=0;j<NR_SBPCD;j++) { @@ -5874,7 +5910,6 @@ void sbpcd_exit(void) put_disk(D_S[j].disk); vfree(D_S[j].sbp_buf); if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf); - devfs_unregister(D_S[j].disk.de); if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL)) { msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name); @@ -5885,6 +5920,7 @@ void sbpcd_exit(void) msg(DBG_INF, "%s module released.\n", major_name); } + module_init(__sbpcd_init) /*HACK!*/; module_exit(sbpcd_exit); @@ -5899,8 +5935,7 @@ static int sbpcd_media_changed(struct cdrom_device_info *cdi, int disc_nr) { p->CD_changed=0; msg(DBG_CHK,"medium changed (drive %s)\n", cdi->name); - /* BUG! Should invalidate buffers! --AJK */ - /* Why should it do the above at all?! --mdcki */ + invalidate_buffers(full_dev); current_drive->diskstate_flags &= ~toc_bit; current_drive->diskstate_flags &= ~cd_size_bit; #if SAFE_MIXED diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 9dcdda8741b0..58f111663d85 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -77,11 +77,12 @@ #include <asm/uaccess.h> #define MAJOR_NR SANYO_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) +#define QUEUE (&sjcd_queue) #include <linux/blk.h> #include "sjcd.h" static int sjcd_present = 0; +static struct request_queue sjcd_queue; #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ @@ -453,15 +454,11 @@ static void sjcd_get_status(void) /* * Check the drive if the disk is changed. Should be revised. */ -static int sjcd_disk_change(kdev_t full_dev) +static int sjcd_disk_change(struct gendisk *disk) { #if 0 - printk("SJCD: sjcd_disk_change( 0x%x )\n", full_dev); + printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name); #endif - if (minor(full_dev) > 0) { - printk("SJCD: request error: invalid device minor.\n"); - return 0; - } if (!sjcd_command_is_in_progress) sjcd_get_status(); return (sjcd_status_valid ? sjcd_media_is_changed : 0); @@ -1067,7 +1064,6 @@ static void sjcd_invalidate_buffers(void) static int current_valid(void) { return !blk_queue_empty(QUEUE) && - major(CURRENT->rq_dev) == MAJOR_NR && CURRENT->cmd == READ && CURRENT->sector != -1; } @@ -1645,11 +1641,11 @@ static int sjcd_release(struct inode *inode, struct file *file) * A list of file operations allowed for this cdrom. */ static struct block_device_operations sjcd_fops = { - .owner = THIS_MODULE, - .open = sjcd_open, - .release = sjcd_release, - .ioctl = sjcd_ioctl, - .check_media_change = sjcd_disk_change, + .owner = THIS_MODULE, + .open = sjcd_open, + .release = sjcd_release, + .ioctl = sjcd_ioctl, + .media_changed = sjcd_disk_change, }; /* @@ -1686,8 +1682,8 @@ static int __init sjcd_init(void) return (-EIO); } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock); - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); + blk_init_queue(&sjcd_queue, do_sjcd_request, &sjcd_lock); + blk_queue_hardsect_size(&sjcd_queue, 2048); sjcd_disk = alloc_disk(1); if (!sjcd_disk) { @@ -1786,13 +1782,14 @@ static int __init sjcd_init(void) printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); devfs_register(NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL); + sjcd_disk->queue = &sjcd_queue; add_disk(sjcd_disk); sjcd_present++; return (0); out3: release_region(sjcd_base, 4); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sjcd_queue); out2: put_disk(sjcd_disk); out1: @@ -1807,11 +1804,10 @@ static void __exit sjcd_exit(void) del_gendisk(sjcd_disk); put_disk(sjcd_disk); release_region(sjcd_base, 4); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sjcd_queue); if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) printk("SJCD: cannot unregister device.\n"); printk(KERN_INFO "SJCD: module: removed.\n"); - return (0); } module_init(sjcd_init); diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index 68e8103a7223..20d010e83bd9 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -135,7 +135,6 @@ #include <linux/cdrom.h> #define MAJOR_NR CDU535_CDROM_MAJOR -#define DEVICE_NR(device) (minor(device)) #include <linux/blk.h> #define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ @@ -221,6 +220,7 @@ static unsigned short read_status_reg; static unsigned short data_reg; static spinlock_t sonycd535_lock = SPIN_LOCK_UNLOCKED; /* queue lock */ +static struct request_queue sonycd535_queue; static int initialized; /* Has the drive been initialized? */ static int sony_disc_changed = 1; /* Has the disk been changed @@ -280,17 +280,10 @@ static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. */ static int -cdu535_check_media_change(kdev_t full_dev) +cdu535_check_media_change(struct gendisk *disk) { - int retval; - - if (minor(full_dev) != 0) { - printk(CDU535_MESSAGE_NAME " request error: invalid device.\n"); - return 0; - } - /* if driver is not initialized, always return 0 */ - retval = initialized ? sony_disc_changed : 0; + int retval = initialized ? sony_disc_changed : 0; sony_disc_changed = 0; return retval; } @@ -793,7 +786,7 @@ size_to_buf(unsigned int size, Byte *buf) static void do_cdu535_request(request_queue_t * q) { - unsigned int dev; + struct request *req; unsigned int read_size; int block; int nsect; @@ -804,130 +797,121 @@ do_cdu535_request(request_queue_t * q) Byte cmd[2]; while (1) { - if (blk_queue_empty(QUEUE)) + if (blk_queue_empty(q)) return; - dev = minor(CURRENT->rq_dev); - block = CURRENT->sector; - nsect = CURRENT->nr_sectors; - if (dev != 0) { - end_request(CURRENT, 0); + req = elv_next_request(q); + block = req->sector; + nsect = req->nr_sectors; + if (!(req->flags & REQ_CMD)) + continue; /* FIXME */ + if (rq_data_dir(req) == WRITE) { + end_request(req, 0); continue; } - if(CURRENT->flags & REQ_CMD) { - switch (rq_data_dir(CURRENT)) { - case READ: + if (rq_data_dir(req) != READ) + panic("Unknown SONY CD cmd"); + /* + * If the block address is invalid or the request goes beyond + * the end of the media, return an error. + */ + if (sony_toc->lead_out_start_lba <= (block/4)) { + end_request(req, 0); + return; + } + if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { + end_request(req, 0); + return; + } + while (0 < nsect) { + /* + * If the requested sector is not currently in + * the read-ahead buffer, it must be read in. + */ + if ((block < sony_first_block) || (sony_last_block < block)) { + sony_first_block = (block / 4) * 4; + log_to_msf(block / 4, params); + /* - * If the block address is invalid or the request goes beyond the end of - * the media, return an error. + * If the full read-ahead would go beyond the end of the media, trim + * it back to read just till the end of the media. */ - if (sony_toc->lead_out_start_lba <= (block / 4)) { - end_request(CURRENT, 0); - return; - } - if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { - end_request(CURRENT, 0); - return; + if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { + sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; + read_size = sony_toc->lead_out_start_lba - (block / 4); + } else { + sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; + read_size = sony_buffer_sectors; } - while (0 < nsect) { + size_to_buf(read_size, ¶ms[3]); + + /* + * Read the data. If the drive was not spinning, + * spin it up and try some more. + */ + for (spin_up_retry=0 ;; ++spin_up_retry) { + /* This loop has been modified to support the Sony + * CDU-510/515 series, thanks to Claudio Porfiri + * <C.Porfiri@nisms.tei.ericsson.se>. + */ /* - * If the requested sector is not currently in the read-ahead buffer, - * it must be read in. + * This part is to deal with very slow hardware. We + * try at most MAX_SPINUP_RETRY times to read the same + * block. A check for seek_and_read_N_blocks' result is + * performed; if the result is wrong, the CDROM's engine + * is restarted and the operation is tried again. */ - if ((block < sony_first_block) || (sony_last_block < block)) { - sony_first_block = (block / 4) * 4; - log_to_msf(block / 4, params); - - /* - * If the full read-ahead would go beyond the end of the media, trim - * it back to read just till the end of the media. - */ - if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { - sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; - read_size = sony_toc->lead_out_start_lba - (block / 4); - } else { - sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; - read_size = sony_buffer_sectors; - } - size_to_buf(read_size, ¶ms[3]); - - /* - * Read the data. If the drive was not spinning, - * spin it up and try some more. - */ - for (spin_up_retry=0 ;; ++spin_up_retry) { - /* This loop has been modified to support the Sony - * CDU-510/515 series, thanks to Claudio Porfiri - * <C.Porfiri@nisms.tei.ericsson.se>. - */ - /* - * This part is to deal with very slow hardware. We - * try at most MAX_SPINUP_RETRY times to read the same - * block. A check for seek_and_read_N_blocks' result is - * performed; if the result is wrong, the CDROM's engine - * is restarted and the operation is tried again. - */ - /* - * 1995-06-01: The system got problems when downloading - * from Slackware CDROM, the problem seems to be: - * seek_and_read_N_blocks returns BAD_STATUS and we - * should wait for a while before retrying, so a new - * part was added to discriminate the return value from - * seek_and_read_N_blocks for the various cases. - */ - int readStatus = seek_and_read_N_blocks(params, read_size, - status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); - if (0 <= readStatus) /* Good data; common case, placed first */ - break; - if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { - /* give up */ - if (readStatus == NO_ROOM) - printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); - else - printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", - status[0]); - sony_first_block = -1; - sony_last_block = -1; - end_request(CURRENT, 0); - return; - } - if (readStatus == BAD_STATUS) { - /* Sleep for a while, then retry */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); - } -#if DEBUG > 0 - printk(CDU535_MESSAGE_NAME - " debug: calling spin up when reading data!\n"); -#endif - cmd[0] = SONY535_SPIN_UP; - do_sony_cmd(cmd, 1, status, NULL, 0, 0); - } - } /* - * The data is in memory now, copy it to the buffer and advance to the - * next block to read. + * 1995-06-01: The system got problems when downloading + * from Slackware CDROM, the problem seems to be: + * seek_and_read_N_blocks returns BAD_STATUS and we + * should wait for a while before retrying, so a new + * part was added to discriminate the return value from + * seek_and_read_N_blocks for the various cases. */ - copyoff = block - sony_first_block; - memcpy(CURRENT->buffer, - sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); - - block += 1; - nsect -= 1; - CURRENT->buffer += 512; + int readStatus = seek_and_read_N_blocks(params, read_size, + status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); + if (0 <= readStatus) /* Good data; common case, placed first */ + break; + if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { + /* give up */ + if (readStatus == NO_ROOM) + printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); + else + printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", + status[0]); + sony_first_block = -1; + sony_last_block = -1; + end_request(req, 0); + return; + } + if (readStatus == BAD_STATUS) { + /* Sleep for a while, then retry */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); + } +#if DEBUG > 0 + printk(CDU535_MESSAGE_NAME + " debug: calling spin up when reading data!\n"); +#endif + cmd[0] = SONY535_SPIN_UP; + do_sony_cmd(cmd, 1, status, NULL, 0, 0); } - - end_request(CURRENT, 1); - break; - - case WRITE: - end_request(CURRENT, 0); - break; - - default: - panic("Unknown SONY CD cmd"); } + /* + * The data is in memory now, copy it to the buffer and advance to the + * next block to read. + */ + copyoff = block - sony_first_block; + memcpy(req->buffer, + sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); + + block += 1; + nsect -= 1; + req->buffer += 512; } + + end_request(req, 1); } } @@ -1071,20 +1055,12 @@ cdu_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg) { - unsigned int dev; Byte status[2]; Byte cmd_buff[10], params[10]; int i; int dsc_status; int err; - if (!inode) { - return -EINVAL; - } - dev = minor(inode->i_rdev) >> 6; - if (dev != 0) { - return -EINVAL; - } if (check_drive_status() != 0) return -EIO; @@ -1447,11 +1423,11 @@ cdu_release(struct inode *inode, static struct block_device_operations cdu_fops = { - .owner = THIS_MODULE, - .open = cdu_open, - .release = cdu_release, - .ioctl = cdu_ioctl, - .check_media_change = cdu535_check_media_change, + .owner = THIS_MODULE, + .open = cdu_open, + .release = cdu_release, + .ioctl = cdu_ioctl, + .media_changed = cdu535_check_media_change, }; static struct gendisk *cdu_disk; @@ -1582,10 +1558,9 @@ static int __init sony535_init(void) err = -EIO; goto out1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_cdu535_request, - &sonycd535_lock); - blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CDU535_BLOCK_SIZE); - sony_toc = kamlloc(sizeof(struct s535_sony_toc), GFP_KERNEL); + blk_init_queue(&sonycd535_queue, do_cdu535_request, &sonycd535_lock); + blk_queue_hardsect_size(&sonycd535_queue, CDU535_BLOCK_SIZE); + sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); err = -ENOMEM; if (!sony_toc) goto out2; @@ -1618,6 +1593,7 @@ static int __init sony535_init(void) sony535_cd_base_io); goto out7; } + cdu_disk->queue = &sonycd535_queue; add_disk(cdu_disk); return 0; @@ -1634,7 +1610,7 @@ out4: out3: kfree(sony_toc); out2: - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + blk_cleanup_queue(&sonycd535_queue); unregister_blkdev(MAJOR_NR, CDU535_HANDLE); out1: devfs_unregister(sony_devfs_handle); @@ -1699,6 +1675,7 @@ static sony535_exit(void) DEVFS_SPECIAL_BLK, 0); del_gendisk(cdu_disk); put_disk(cdu_disk); + blk_cleanup_queue(&sonycd535_queue); if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); else diff --git a/drivers/char/Config.help b/drivers/char/Config.help index b03cd9da93b0..34e204aca958 100644 --- a/drivers/char/Config.help +++ b/drivers/char/Config.help @@ -40,93 +40,6 @@ CONFIG_MWAVE The module will be called mwave.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -CONFIG_AGP - AGP (Accelerated Graphics Port) is a bus system mainly used to - connect graphics cards to the rest of the system. - - If you have an AGP system and you say Y here, it will be possible to - use the AGP features of your 3D rendering video card. This code acts - as a sort of "AGP driver" for the motherboard's chipset. - - If you need more texture memory than you can get with the AGP GART - (theoretically up to 256 MB, but in practice usually 64 or 128 MB - due to kernel allocation issues), you could use PCI accesses - and have up to a couple gigs of texture space. - - Note that this is the only means to have XFree4/GLX use - write-combining with MTRR support on the AGP bus. Without it, OpenGL - direct rendering will be a lot slower but still faster than PIO. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - - This driver is available as a module. If you want to compile it as - a module, say M here and read <file:Documentation/modules.txt>. The - module will be called agpgart.o. - -CONFIG_AGP_INTEL - This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - -CONFIG_AGP_I810 - This option gives you AGP support for the Xserver on the Intel 810 - 815 and 830m chipset boards for their on-board integrated graphics. This - is required to do any useful video modes with these boards. - -CONFIG_AGP_I460 - This option gives you AGP GART support for the Intel 460GX chipset - for IA64 processors. - -CONFIG_AGP_VIA - This option gives you AGP support for the GLX component of the - XFree86 4.x on VIA MPV3/Apollo Pro chipsets. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - -CONFIG_AGP_AMD - This option gives you AGP support for the GLX component of the - XFree86 4.x on AMD Irongate, 761, and 762 chipsets. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - -CONFIG_AGP_SIS - This option gives you AGP support for the GLX component of the "soon - to be released" XFree86 4.x on Silicon Integrated Systems [SiS] - chipsets. - - Note that 5591/5592 AGP chipsets are NOT supported. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - -CONFIG_AGP_SWORKS - Say Y here to support the Serverworks AGP card. See - <http://www.serverworks.com/> for product descriptions and images. - -CONFIG_AGP_ALI - This option gives you AGP support for the GLX component of the - XFree86 4.x on the following ALi chipsets. The supported chipsets - include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. - For the ALi-chipset question, ALi suggests you refer to - <http://www.ali.com.tw/eng/support/index.shtml>. - - The M1541 chipset can do AGP 1x and 2x, but note that there is an - acknowledged incompatibility with Matrox G200 cards. Due to - timing issues, this chipset cannot do AGP 2x with the G200. - This is a hardware limitation. AGP 1x seems to be fine, though. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - -CONFIG_AGP_HP_ZX1 - This option gives you AGP GART support for the HP ZX1 chipset - for IA64 processors. - CONFIG_I810_TCO Hardware driver for the TCO timer built into the Intel i810 and i815 chipset family. The TCO (Total Cost of Ownership) timer is a diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d0be4dd0e8cb..e65360cf6538 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -104,6 +104,9 @@ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ obj-$(CONFIG_PCMCIA) += pcmcia/ +# Files generated that shall be removed upon make clean +clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c + include $(TOPDIR)/Rules.make $(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c index 95880a482d79..f55cf6ab41bc 100644 --- a/drivers/char/drm/sis_ds.c +++ b/drivers/char/drm/sis_ds.c @@ -50,15 +50,16 @@ set_t *setInit(void) set_t *set; set = (set_t *)MALLOC(sizeof(set_t)); - for(i = 0; i < SET_SIZE; i++){ - set->list[i].free_next = i+1; - set->list[i].alloc_next = -1; - } - set->list[SET_SIZE-1].free_next = -1; - set->free = 0; - set->alloc = -1; - set->trace = -1; - + if (set) { + for(i = 0; i < SET_SIZE; i++){ + set->list[i].free_next = i+1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + } return set; } @@ -172,7 +173,8 @@ static void *calloc(size_t nmemb, size_t size) { void *addr; addr = kmalloc(nmemb*size, GFP_KERNEL); - memset(addr, 0, nmemb*size); + if (addr) + memset(addr, 0, nmemb*size); return addr; } #define free(n) kfree(n) diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h index df2b8b0cd93c..f93d224413e0 100644 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ b/drivers/char/ftape/lowlevel/ftape-rw.h @@ -71,7 +71,7 @@ typedef struct { /* Count nr of 1's in pattern. */ -extern inline int count_ones(unsigned long mask) +static inline int count_ones(unsigned long mask) { int bits; diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h index 7248db11c9f5..63de244153ce 100644 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ b/drivers/char/ftape/zftape/zftape-vtbl.h @@ -168,11 +168,11 @@ extern int zft_fake_volume_headers (eof_mark_union *eof_map, extern int zft_weof (unsigned int count, zft_position *pos); extern void zft_move_past_eof (zft_position *pos); -extern inline int zft_tape_at_eod (const zft_position *pos); -extern inline int zft_tape_at_lbot (const zft_position *pos); -extern inline void zft_position_before_eof (zft_position *pos, +static inline int zft_tape_at_eod (const zft_position *pos); +static inline int zft_tape_at_lbot (const zft_position *pos); +static inline void zft_position_before_eof (zft_position *pos, const zft_volinfo *volume); -extern inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, +static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, const zft_position *pos); /* this function decrements the zft_seg_pos counter if we are right @@ -180,7 +180,7 @@ extern inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, * need to position before the eof mark. NOTE: zft_tape_pos is not * changed */ -extern inline void zft_position_before_eof(zft_position *pos, +static inline void zft_position_before_eof(zft_position *pos, const zft_volinfo *volume) { TRACE_FUN(ft_t_flow); @@ -195,7 +195,7 @@ extern inline void zft_position_before_eof(zft_position *pos, /* Mmmh. Is the position at the end of the last volume, that is right * before the last EOF mark also logical an EOD condition? */ -extern inline int zft_tape_at_eod(const zft_position *pos) +static inline int zft_tape_at_eod(const zft_position *pos) { TRACE_FUN(ft_t_any); @@ -207,7 +207,7 @@ extern inline int zft_tape_at_eod(const zft_position *pos) } } -extern inline int zft_tape_at_lbot(const zft_position *pos) +static inline int zft_tape_at_lbot(const zft_position *pos) { if (zft_qic_mode) { return (pos->seg_pos <= zft_first_vtbl->start_seg && @@ -220,7 +220,7 @@ extern inline int zft_tape_at_lbot(const zft_position *pos) /* This one checks for EOF. return remaing space (may be negative) */ -extern inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, +static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, const zft_position *pos) { return (__s64)(vtbl->size - pos->volume_pos); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 713ed380c7b7..eb6f325bc19c 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -122,7 +122,7 @@ struct miscdevice isiloader_device = { }; -extern inline int WaitTillCardIsFree(unsigned short base) +static inline int WaitTillCardIsFree(unsigned short base) { unsigned long count=0; while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000)); @@ -358,7 +358,7 @@ static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev return 0; } -extern inline void schedule_bh(struct isi_port * port) +static inline void schedule_bh(struct isi_port * port) { queue_task(&port->bh_tqueue, &tq_isicom); mark_bh(ISICOM_BH); @@ -823,7 +823,7 @@ static void isicom_config_port(struct isi_port * port) /* open et all */ -extern inline void isicom_setup_board(struct isi_board * bp) +static inline void isicom_setup_board(struct isi_board * bp) { int channel; struct isi_port * port; @@ -1091,7 +1091,7 @@ static int isicom_open(struct tty_struct * tty, struct file * filp) /* close et all */ -extern inline void isicom_shutdown_board(struct isi_board * bp) +static inline void isicom_shutdown_board(struct isi_board * bp) { int channel; struct isi_port * port; @@ -1353,7 +1353,7 @@ static int isicom_chars_in_buffer(struct tty_struct * tty) } /* ioctl et all */ -extern inline void isicom_send_break(struct isi_port * port, unsigned long length) +static inline void isicom_send_break(struct isi_port * port, unsigned long length) { struct isi_board * card = port->card; short wait = 10; diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index b8fdb02ba674..baa80dfb6626 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -53,7 +53,6 @@ #include <linux/fcntl.h> #include <linux/major.h> #include <linux/delay.h> -#include <linux/tqueue.h> #include <linux/version.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index b4d46077daa8..c04abce4a6c3 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -239,28 +239,28 @@ static inline int sx_paranoia_check(struct specialix_port const * port, */ /* Get board number from pointer */ -extern inline int board_No (struct specialix_board * bp) +static inline int board_No (struct specialix_board * bp) { return bp - sx_board; } /* Get port number from pointer */ -extern inline int port_No (struct specialix_port const * port) +static inline int port_No (struct specialix_port const * port) { return SX_PORT(port - sx_port); } /* Get pointer to board from pointer to port */ -extern inline struct specialix_board * port_Board(struct specialix_port const * port) +static inline struct specialix_board * port_Board(struct specialix_port const * port) { return &sx_board[SX_BOARD(port - sx_port)]; } /* Input Byte from CL CD186x register */ -extern inline unsigned char sx_in(struct specialix_board * bp, unsigned short reg) +static inline unsigned char sx_in(struct specialix_board * bp, unsigned short reg) { bp->reg = reg | 0x80; outb (reg | 0x80, bp->base + SX_ADDR_REG); @@ -269,7 +269,7 @@ extern inline unsigned char sx_in(struct specialix_board * bp, unsigned short r /* Output Byte to CL CD186x register */ -extern inline void sx_out(struct specialix_board * bp, unsigned short reg, +static inline void sx_out(struct specialix_board * bp, unsigned short reg, unsigned char val) { bp->reg = reg | 0x80; @@ -279,7 +279,7 @@ extern inline void sx_out(struct specialix_board * bp, unsigned short reg, /* Input Byte from CL CD186x register */ -extern inline unsigned char sx_in_off(struct specialix_board * bp, unsigned short reg) +static inline unsigned char sx_in_off(struct specialix_board * bp, unsigned short reg) { bp->reg = reg; outb (reg, bp->base + SX_ADDR_REG); @@ -288,7 +288,7 @@ extern inline unsigned char sx_in_off(struct specialix_board * bp, unsigned sho /* Output Byte to CL CD186x register */ -extern inline void sx_out_off(struct specialix_board * bp, unsigned short reg, +static inline void sx_out_off(struct specialix_board * bp, unsigned short reg, unsigned char val) { bp->reg = reg; @@ -298,7 +298,7 @@ extern inline void sx_out_off(struct specialix_board * bp, unsigned short reg, /* Wait for Channel Command Register ready */ -extern inline void sx_wait_CCR(struct specialix_board * bp) +static inline void sx_wait_CCR(struct specialix_board * bp) { unsigned long delay; @@ -311,7 +311,7 @@ extern inline void sx_wait_CCR(struct specialix_board * bp) /* Wait for Channel Command Register ready */ -extern inline void sx_wait_CCR_off(struct specialix_board * bp) +static inline void sx_wait_CCR_off(struct specialix_board * bp) { unsigned long delay; @@ -327,13 +327,13 @@ extern inline void sx_wait_CCR_off(struct specialix_board * bp) * specialix IO8+ IO range functions. */ -extern inline int sx_check_io_range(struct specialix_board * bp) +static inline int sx_check_io_range(struct specialix_board * bp) { return check_region (bp->base, SX_IO_SPACE); } -extern inline void sx_request_io_range(struct specialix_board * bp) +static inline void sx_request_io_range(struct specialix_board * bp) { request_region(bp->base, bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE, @@ -341,7 +341,7 @@ extern inline void sx_request_io_range(struct specialix_board * bp) } -extern inline void sx_release_io_range(struct specialix_board * bp) +static inline void sx_release_io_range(struct specialix_board * bp) { release_region(bp->base, bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE); @@ -351,7 +351,7 @@ extern inline void sx_release_io_range(struct specialix_board * bp) /* Must be called with enabled interrupts */ /* Ugly. Very ugly. Don't use this for anything else than initialization code */ -extern inline void sx_long_delay(unsigned long delay) +static inline void sx_long_delay(unsigned long delay) { unsigned long i; @@ -599,7 +599,7 @@ static int sx_probe(struct specialix_board *bp) * Interrupt processing routines. * */ -extern inline void sx_mark_event(struct specialix_port * port, int event) +static inline void sx_mark_event(struct specialix_port * port, int event) { /* * I'm not quite happy with current scheme all serial @@ -616,7 +616,7 @@ extern inline void sx_mark_event(struct specialix_port * port, int event) } -extern inline struct specialix_port * sx_get_port(struct specialix_board * bp, +static inline struct specialix_port * sx_get_port(struct specialix_board * bp, unsigned char const * what) { unsigned char channel; @@ -635,7 +635,7 @@ extern inline struct specialix_port * sx_get_port(struct specialix_board * bp, } -extern inline void sx_receive_exc(struct specialix_board * bp) +static inline void sx_receive_exc(struct specialix_board * bp) { struct specialix_port *port; struct tty_struct *tty; @@ -701,7 +701,7 @@ extern inline void sx_receive_exc(struct specialix_board * bp) } -extern inline void sx_receive(struct specialix_board * bp) +static inline void sx_receive(struct specialix_board * bp) { struct specialix_port *port; struct tty_struct *tty; @@ -732,7 +732,7 @@ extern inline void sx_receive(struct specialix_board * bp) } -extern inline void sx_transmit(struct specialix_board * bp) +static inline void sx_transmit(struct specialix_board * bp) { struct specialix_port *port; struct tty_struct *tty; @@ -802,7 +802,7 @@ extern inline void sx_transmit(struct specialix_board * bp) } -extern inline void sx_check_modem(struct specialix_board * bp) +static inline void sx_check_modem(struct specialix_board * bp) { struct specialix_port *port; struct tty_struct *tty; @@ -962,7 +962,7 @@ void turn_ints_on (struct specialix_board *bp) /* Called with disabled interrupts */ -extern inline int sx_setup_board(struct specialix_board * bp) +static inline int sx_setup_board(struct specialix_board * bp) { int error; @@ -986,7 +986,7 @@ extern inline int sx_setup_board(struct specialix_board * bp) /* Called with disabled interrupts */ -extern inline void sx_shutdown_board(struct specialix_board *bp) +static inline void sx_shutdown_board(struct specialix_board *bp) { if (!(bp->flags & SX_BOARD_ACTIVE)) return; @@ -1867,7 +1867,7 @@ static int sx_set_modem_info(struct specialix_port * port, unsigned int cmd, } -extern inline void sx_send_break(struct specialix_port * port, unsigned long length) +static inline void sx_send_break(struct specialix_port * port, unsigned long length) { struct specialix_board *bp = port_Board(port); unsigned long flags; @@ -1886,7 +1886,7 @@ extern inline void sx_send_break(struct specialix_port * port, unsigned long len } -extern inline int sx_set_serial_info(struct specialix_port * port, +static inline int sx_set_serial_info(struct specialix_port * port, struct serial_struct * newinfo) { struct serial_struct tmp; @@ -1942,7 +1942,7 @@ extern inline int sx_set_serial_info(struct specialix_port * port, } -extern inline int sx_get_serial_info(struct specialix_port * port, +static inline int sx_get_serial_info(struct specialix_port * port, struct serial_struct * retinfo) { struct serial_struct tmp; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 8fffe423ab14..864053a676dd 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -2647,7 +2647,6 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *devinfo = &info->devinfo; - devinfo->dev = mk_kdev(drive->disk->major, drive->disk->first_minor); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed; @@ -3026,15 +3025,9 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int error; - - /* Try the generic SCSI command ioctl's first.. */ - error = scsi_cmd_ioctl(inode->i_bdev, cmd, arg); - if (error != -ENOTTY) - return error; + struct cdrom_info *info = drive->driver_data; - /* Then the generic cdrom ioctl's.. */ - return cdrom_ioctl(inode, file, cmd, arg); + return cdrom_ioctl(&info->devinfo, inode, cmd, arg); } static @@ -3044,9 +3037,9 @@ int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) int rc = -ENOMEM; MOD_INC_USE_COUNT; - if (info->buffer == NULL) + if (!info->buffer) info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL); - if ((info->buffer == NULL) || (rc = cdrom_open(ip, fp))) { + if (!info->buffer || (rc = cdrom_open(&info->devinfo, ip, fp))) { drive->usage--; MOD_DEC_USE_COUNT; } @@ -3057,15 +3050,16 @@ static void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *drive) { - cdrom_release (inode, file); + struct cdrom_info *info = drive->driver_data; + cdrom_release (&info->devinfo, file); MOD_DEC_USE_COUNT; } static int ide_cdrom_check_media_change (ide_drive_t *drive) { - return cdrom_media_changed(mk_kdev(drive->disk->major, - drive->disk->first_minor)); + struct cdrom_info *info = drive->driver_data; + return cdrom_media_changed(&info->devinfo); } static diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c index dba3cda964aa..52d5e84726e4 100644 --- a/drivers/ide/ide-geometry.c +++ b/drivers/ide/ide-geometry.c @@ -83,7 +83,6 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) } -extern ide_drive_t * get_info_ptr(kdev_t); extern unsigned long current_capacity (ide_drive_t *); /* @@ -147,19 +146,15 @@ static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int * Returns 1 if the geometry translation was successful. */ -int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg) +int ide_xlate_1024 (struct block_device *bdev, int xparm, int ptheads, const char *msg) { - ide_drive_t *drive; + ide_drive_t *drive = bdev->bd_disk->private_data; const char *msg1 = ""; int heads = 0; int c, h, s; int transl = 1; /* try translation */ int ret = 0; - drive = get_info_ptr(i_rdev); - if (!drive) - return 0; - /* remap? */ if (drive->remap_0_to_1 != 2) { if (xparm == 1) { /* DM */ diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 478bffc6aed8..3cb2ffff7c91 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -47,6 +47,7 @@ #include <linux/ide.h> #include <linux/spinlock.h> #include <linux/pci.h> +#include <linux/kmod.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -971,6 +972,41 @@ int init_irq (ide_hwif_t *hwif) EXPORT_SYMBOL(init_irq); +static void ata_lock(dev_t dev, void *data) +{ + ide_hwif_t *hwif = data; + int unit = MINOR(dev) >> PARTN_BITS; + get_disk(hwif->drives[unit].disk); +} + +struct gendisk *ata_probe(dev_t dev, int *part, void *data) +{ + ide_hwif_t *hwif = data; + int unit = MINOR(dev) >> PARTN_BITS; + ide_drive_t *drive = &hwif->drives[unit]; + if (!drive->present) { + put_disk(drive->disk); + return NULL; + } + if (!drive->driver) { + if (drive->media == ide_disk) + (void) request_module("ide-disk"); + if (drive->scsi) + (void) request_module("ide-scsi"); + if (drive->media == ide_cdrom) + (void) request_module("ide-cd"); + if (drive->media == ide_tape) + (void) request_module("ide-tape"); + if (drive->media == ide_floppy) + (void) request_module("ide-floppy"); + } + if (!drive->driver) { + put_disk(drive->disk); + return NULL; + } + return drive->disk; +} + /* * init_gendisk() (as opposed to ide_geninit) is called for each major device, * after probing for drives, to allocate partition tables and other data @@ -992,12 +1028,15 @@ static void init_gendisk (ide_hwif_t *hwif) } for (unit = 0; unit < units; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; struct gendisk *disk = disks[unit]; disk->major = hwif->major; disk->first_minor = unit << PARTN_BITS; sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit); disk->fops = ide_fops; - hwif->drives[unit].disk = disk; + disk->private_data = drive; + disk->queue = &drive->queue; + drive->disk = disk; } for (unit = 0; unit < units; ++unit) { @@ -1024,6 +1063,9 @@ static void init_gendisk (ide_hwif_t *hwif) device_register(&drive->gendev); } + blk_register_region(MKDEV(hwif->major, 0), units << PARTN_BITS, + THIS_MODULE, ata_probe, ata_lock, hwif); + return; err_kmalloc_gd: @@ -1083,10 +1125,7 @@ int hwif_init (ide_hwif_t *hwif) printk("%s: probed IRQ %d failed, using default.\n", hwif->name, hwif->irq); } - init_gendisk(hwif); - blk_dev[hwif->major].data = hwif; - blk_dev[hwif->major].queue = ide_get_queue; hwif->present = 1; /* success */ return 1; } @@ -1150,7 +1189,7 @@ int ideprobe_init (void) } #ifdef MODULE -extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *); +extern int (*ide_xlate_1024_hook)(struct block_device *, int, int, const char *); int init_module (void) { diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 00830680bb42..23d39bcf3e0b 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -878,7 +878,6 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; unsigned long block; - unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS; ide_hwif_t *hwif = HWIF(drive); BUG_ON(!(rq->flags & REQ_STARTED)); @@ -897,15 +896,8 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) * bail early if we've sent a device to sleep, however how to wake * this needs to be a masked flag. FIXME for proper operations. */ - if (drive->suspend_reset) { + if (drive->suspend_reset) goto kill_rq; - } - - if (unit >= MAX_DRIVES) { - printk("%s: bad device number: %s\n", - hwif->name, kdevname(rq->rq_dev)); - goto kill_rq; - } block = rq->sector; if (blk_fs_request(rq) && @@ -1172,18 +1164,6 @@ queue_next: EXPORT_SYMBOL(ide_do_request); /* - * ide_get_queue() returns the queue which corresponds to a given device. - */ -request_queue_t *ide_get_queue (kdev_t dev) -{ - ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data; - - return &hwif->drives[DEVICE_NR(dev) & 1].queue; -} - -EXPORT_SYMBOL(ide_get_queue); - -/* * Passes the stuff to ide_do_request */ void do_ide_request(request_queue_t *q) @@ -1496,32 +1476,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) EXPORT_SYMBOL(ide_intr); /* - * get_info_ptr() returns the (ide_drive_t *) for a given device number. - * It returns NULL if the given device number does not match any present drives. - */ -ide_drive_t *get_info_ptr (kdev_t i_rdev) -{ - int major = major(i_rdev); - unsigned int h; - - for (h = 0; h < MAX_HWIFS; ++h) { - ide_hwif_t *hwif = &ide_hwifs[h]; - if (hwif->present && major == hwif->major) { - unsigned unit = DEVICE_NR(i_rdev); - if (unit < MAX_DRIVES) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present) - return drive; - } - break; - } - } - return NULL; -} - -EXPORT_SYMBOL(get_info_ptr); - -/* * This function is intended to be used prior to invoking ide_do_drive_cmd(). */ void ide_init_drive_cmd (struct request *rq) @@ -1572,7 +1526,20 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio #endif rq->errors = 0; rq->rq_status = RQ_ACTIVE; - rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS); + + /* + * Aiee. This is ugly, but it gets called before "drive->disk" + * has been initialized. Al will fix it, I'm sure. + */ + if (drive->disk) + rq->rq_dev = mk_kdev(drive->disk->major, drive->disk->first_minor); + else { + printk("IDE init is ugly:"); + dump_stack(); + rq->rq_dev = mk_kdev(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS); + } + + rq->rq_disk = drive->disk; if (action == ide_wait) rq->waiting = &wait; spin_lock_irqsave(&ide_lock, flags); @@ -1615,18 +1582,14 @@ EXPORT_SYMBOL(ide_revalidate_drive); * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -int ide_revalidate_disk (kdev_t i_rdev) +static int ide_revalidate_disk(struct gendisk *disk) { - ide_drive_t *drive; - if ((drive = get_info_ptr(i_rdev)) == NULL) - return -ENODEV; + ide_drive_t *drive = disk->private_data; if (DRIVER(drive)->revalidate) DRIVER(drive)->revalidate(drive); return 0; } -EXPORT_SYMBOL(ide_revalidate_disk); - void ide_probe_module (void) { if (!ide_probe) { @@ -1642,28 +1605,9 @@ EXPORT_SYMBOL(ide_probe_module); static int ide_open (struct inode * inode, struct file * filp) { - ide_drive_t *drive; - - if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENXIO; - if (drive->driver == NULL) { - if (drive->media == ide_disk) - (void) request_module("ide-disk"); - if (drive->scsi) - (void) request_module("ide-scsi"); - if (drive->media == ide_cdrom) - (void) request_module("ide-cd"); - if (drive->media == ide_tape) - (void) request_module("ide-tape"); - if (drive->media == ide_floppy) - (void) request_module("ide-floppy"); - } + ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; drive->usage++; - if (drive->driver != NULL) - return DRIVER(drive)->open(inode, filp, drive); - printk (KERN_WARNING "%s: driver not present\n", drive->name); - drive->usage--; - return -ENXIO; + return DRIVER(drive)->open(inode, filp, drive); } /* @@ -1672,13 +1616,9 @@ static int ide_open (struct inode * inode, struct file * filp) */ static int ide_release (struct inode * inode, struct file * file) { - ide_drive_t *drive; - - if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { - drive->usage--; - if (drive->driver != NULL) - DRIVER(drive)->release(inode, file, drive); - } + ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + DRIVER(drive)->release(inode, file, drive); + drive->usage--; return 0; } @@ -1772,7 +1712,6 @@ void ide_unregister (unsigned int index) ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; unsigned long flags; - unsigned int p, minor; ide_hwif_t old_hwif; if (index >= MAX_HWIFS) @@ -1792,25 +1731,10 @@ void ide_unregister (unsigned int index) } hwif->present = 0; - /* - * All clear? Then blow away the buffer cache - */ spin_unlock_irqrestore(&ide_lock, flags); - for (unit = 0; unit < MAX_DRIVES; ++unit) { - drive = &hwif->drives[unit]; - if (!drive->present) - continue; - minor = drive->select.b.unit << PARTN_BITS; - for (p = 0; p < (1<<PARTN_BITS); ++p) { - if (get_capacity(drive->disk)) { - kdev_t devp = mk_kdev(hwif->major, minor+p); - invalidate_device(devp, 0); - } - } #ifdef CONFIG_PROC_FS - destroy_proc_ide_drives(hwif); + destroy_proc_ide_drives(hwif); #endif - } spin_lock_irqsave(&ide_lock, flags); hwgroup = hwif->hwgroup; @@ -1885,9 +1809,8 @@ void ide_unregister (unsigned int index) /* * Remove us from the kernel's knowledge */ + blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); unregister_blkdev(hwif->major, hwif->name); - blk_dev[hwif->major].data = NULL; - blk_dev[hwif->major].queue = NULL; for (i = 0; i < MAX_DRIVES; i++) { struct gendisk *disk = hwif->drives[i].disk; hwif->drives[i].disk = NULL; @@ -2482,28 +2405,21 @@ EXPORT_SYMBOL(ata_attach); static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err = 0, major, minor; - ide_drive_t *drive; - struct request rq; - kdev_t dev; + ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; ide_settings_t *setting; - - major = major(dev); minor = minor(dev); - if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENODEV; + int err = 0; if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { if (cmd == setting->read_ioctl) { err = ide_read_setting(drive, setting); return err >= 0 ? put_user(err, (long *) arg) : err; } else { - if ((minor(inode->i_rdev) & PARTN_MASK)) + if (inode->i_bdev != inode->i_bdev->bd_contains) return -EINVAL; return ide_write_setting(drive, setting, arg); } } - ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: { @@ -2532,7 +2448,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: - if (minor(inode->i_rdev) & PARTN_MASK) + if (inode->i_bdev != inode->i_bdev->bd_contains) return -EINVAL; if (drive->id == NULL) return -ENOMSG; @@ -2662,12 +2578,9 @@ static int ide_ioctl (struct inode *inode, struct file *file, } } -static int ide_check_media_change (kdev_t i_rdev) +static int ide_check_media_change(struct gendisk *disk) { - ide_drive_t *drive; - - if ((drive = get_info_ptr(i_rdev)) == NULL) - return -ENODEV; + ide_drive_t *drive = disk->private_data; if (drive->driver != NULL) return DRIVER(drive)->media_change(drive); return 0; @@ -3491,12 +3404,12 @@ void ide_unregister_driver(ide_driver_t *driver) EXPORT_SYMBOL(ide_unregister_driver); struct block_device_operations ide_fops[] = {{ - .owner = THIS_MODULE, - .open = ide_open, - .release = ide_release, - .ioctl = ide_ioctl, - .check_media_change = ide_check_media_change, - .revalidate = ide_revalidate_disk + .owner = THIS_MODULE, + .open = ide_open, + .release = ide_release, + .ioctl = ide_ioctl, + .media_changed = ide_check_media_change, + .revalidate_disk= ide_revalidate_disk }}; EXPORT_SYMBOL(ide_fops); @@ -3538,8 +3451,6 @@ int __init ide_init (void) return 0; } -module_init(ide_init); - #ifdef MODULE char *options = NULL; MODULE_PARM(options,"s"); @@ -3589,4 +3500,6 @@ void cleanup_module (void) __setup("", ide_setup); +module_init(ide_init); + #endif /* MODULE */ diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 502d3c90b864..01dc3c0681f2 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -354,7 +354,7 @@ static int __init ps2_init(void) static void __exit ps2_exit(void) { - remove_driver(&ps2_driver.drv); + driver_unregister(&ps2_driver.drv); } module_init(ps2_init); diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index 407501c0d6b1..58c4e6d3ed35 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -19,7 +19,7 @@ isdn-objs := isdn_net.o isdn_net_lib.o \ # Optional parts of multipart objects. -isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o +isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 6049970e1f2a..c48275b76141 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -907,16 +907,15 @@ static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff * *************************************************************/ static struct isdn_ppp_compressor ippp_bsd_compress = { - NULL,NULL, /* prev,next: overwritten by isdn_ppp */ - CI_BSD_COMPRESS, /* compress_proto */ - bsd_alloc, /* alloc */ - bsd_free, /* free */ - bsd_init, /* init */ - bsd_reset, /* reset */ - bsd_compress, /* compress */ - bsd_decompress, /* decompress */ - bsd_incomp, /* incomp */ - bsd_stats /* comp_stat */ + .num = CI_BSD_COMPRESS, + .alloc = bsd_alloc, + .free = bsd_free, + .init = bsd_init, + .reset = bsd_reset, + .compress = bsd_compress, + .decompress = bsd_decompress, + .incomp = bsd_incomp, + .stat = bsd_stats, }; /************************************************************* diff --git a/drivers/isdn/i4l/isdn_ciscohdlck.c b/drivers/isdn/i4l/isdn_ciscohdlck.c index 0f08f3daea88..cab5b1a2100f 100644 --- a/drivers/isdn/i4l/isdn_ciscohdlck.c +++ b/drivers/isdn/i4l/isdn_ciscohdlck.c @@ -20,6 +20,19 @@ #include <linux/if_arp.h> #include <linux/inetdevice.h> +/* + * Definitions for Cisco-HDLC header. + */ + +#define CISCO_ADDR_UNICAST 0x0f +#define CISCO_ADDR_BROADCAST 0x8f +#define CISCO_CTRL 0x00 +#define CISCO_TYPE_CDP 0x2000 +#define CISCO_TYPE_SLARP 0x8035 +#define CISCO_SLARP_REQUEST 0 +#define CISCO_SLARP_REPLY 1 +#define CISCO_SLARP_KEEPALIVE 2 + /* * CISCO HDLC keepalive specific stuff */ diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h index 3c81ffcb5d80..64e1c1e9c819 100644 --- a/drivers/isdn/i4l/isdn_common.h +++ b/drivers/isdn/i4l/isdn_common.h @@ -47,7 +47,7 @@ #endif #define isdn_BUG() \ -do { printk(KERN_WARNING "ISDN Bug at %s:%d\n", __FILE__, __LINE__); \ +do { printk(KERN_WARNING "ISDN BUG at %s:%d\n", __FILE__, __LINE__); \ } while(0) #define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__) diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 4b504da722de..f41603c1287d 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -33,412 +33,8 @@ #include "isdn_concap.h" #include "isdn_ciscohdlck.h" -/* - * Outline of new tbusy handling: - * - * Old method, roughly spoken, consisted of setting tbusy when entering - * isdn_net_start_xmit() and at several other locations and clearing - * it from isdn_net_start_xmit() thread when sending was successful. - * - * With 2.3.x multithreaded network core, to prevent problems, tbusy should - * only be set by the isdn_net_start_xmit() thread and only when a tx-busy - * condition is detected. Other threads (in particular isdn_net_stat_callb()) - * are only allowed to clear tbusy. - * - * -HE - */ - -/* - * About SOFTNET: - * Most of the changes were pretty obvious and basically done by HE already. - * - * One problem of the isdn net device code is that is uses struct net_device - * for masters and slaves. However, only master interface are registered to - * the network layer, and therefore, it only makes sense to call netif_* - * functions on them. - * - * --KG - */ - -/* - * Find out if the netdevice has been ifup-ed yet. - */ -static inline int -isdn_net_device_started(isdn_net_dev *idev) -{ - return netif_running(&idev->mlp->dev); -} - -/* - * stop the network -> net_device queue. - */ -static inline void -isdn_net_dev_stop_queue(isdn_net_dev *idev) -{ - netif_stop_queue(&idev->mlp->dev); -} - -/* - * find out if the net_device which this lp belongs to (lp can be - * master or slave) is busy. It's busy iff all (master and slave) - * queues are busy - */ -static inline int -isdn_net_device_busy(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - unsigned long flags; - int retval = 1; - - if (!isdn_net_dev_busy(idev)) - return 0; - - spin_lock_irqsave(&mlp->online_lock, flags); - list_for_each_entry(idev, &mlp->online, online) { - if (!isdn_net_dev_busy(idev)) { - retval = 0; - break; - } - } - spin_unlock_irqrestore(&mlp->online_lock, flags); - return retval; -} - -static inline -void isdn_net_inc_frame_cnt(isdn_net_dev *idev) -{ - atomic_inc(&idev->frame_cnt); - if (isdn_net_device_busy(idev)) - isdn_net_dev_stop_queue(idev); -} - -static inline void -isdn_net_dec_frame_cnt(isdn_net_dev *idev) -{ - atomic_dec(&idev->frame_cnt); - - if (!isdn_net_device_busy(idev)) { - if (!skb_queue_empty(&idev->super_tx_queue)) - tasklet_schedule(&idev->tlet); - else - isdn_net_dev_wake_queue(idev); - } -} - -static inline -void isdn_net_zero_frame_cnt(isdn_net_dev *idev) -{ - atomic_set(&idev->frame_cnt, 0); -} - -/* Prototypes */ - -int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); - char *isdn_net_revision = "$Revision: 1.140.6.11 $"; -/* A packet has successfully been sent out. */ - -int -isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c) -{ - isdn_net_local *mlp = idev->mlp; - - isdn_net_dec_frame_cnt(idev); - mlp->stats.tx_packets++; - mlp->stats.tx_bytes += c->parm.length; - return 1; -} - -static void -isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) -{ - u_short proto = ntohs(skb->protocol); - - printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", - dev->name, - (reason != NULL) ? reason : "unknown", - (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); - - dst_link_failure(skb); -} - -static void -isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev) -{ - unsigned char *p = skb->nh.raw; /* hopefully, this was set correctly */ - unsigned short proto = ntohs(skb->protocol); - int data_ofs; - struct ip_ports { - unsigned short source; - unsigned short dest; - } *ipp; - char addinfo[100]; - - data_ofs = ((p[0] & 15) * 4); - switch (proto) { - case ETH_P_IP: - switch (p[9]) { - case IPPROTO_ICMP: - strcpy(addinfo, "ICMP"); - break; - case IPPROTO_TCP: - case IPPROTO_UDP: - ipp = (struct ip_ports *) (&p[data_ofs]); - sprintf(addinfo, "%s, port: %d -> %d", - p[9] == IPPROTO_TCP ? "TCP" : "UDP", - ntohs(ipp->source), ntohs(ipp->dest)); - break; - default: - sprintf(addinfo, "type %d", p[9]); - } - printk(KERN_INFO - "OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s\n", - - NIPQUAD(*(u32 *)(p + 12)), NIPQUAD(*(u32 *)(p + 16)), - addinfo); - break; - case ETH_P_ARP: - printk(KERN_INFO - "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", - NIPQUAD(*(u32 *)(p + 14)), NIPQUAD(*(u32 *)(p + 24))); - break; - default: - printk(KERN_INFO "OPEN: unknown proto %#x\n", proto); - } -} - -/* - * this function is used to send supervisory data, i.e. data which was - * not received from the network layer, but e.g. frames from ipppd, CCP - * reset frames etc. - */ -void -isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb) -{ - if (in_irq()) { - // we can't grab the lock from irq context, - // so we just queue the packet - skb_queue_tail(&idev->super_tx_queue, skb); - - tasklet_schedule(&idev->tlet); - return; - } - - spin_lock_bh(&idev->xmit_lock); - if (!isdn_net_dev_busy(idev)) { - isdn_net_writebuf_skb(idev, skb); - } else { - skb_queue_tail(&idev->super_tx_queue, skb); - } - spin_unlock_bh(&idev->xmit_lock); -} - -/* - * all frames sent from the (net) LL to a HL driver should go via this function - * it's serialized by the caller holding the idev->xmit_lock spinlock - */ -void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb) -{ - isdn_net_local *mlp = idev->mlp; - int ret; - int len = skb->len; /* save len */ - - /* before obtaining the lock the caller should have checked that - the lp isn't busy */ - if (isdn_net_dev_busy(idev)) { - isdn_BUG(); - goto error; - } - - if (!isdn_net_online(idev)) { - isdn_BUG(); - goto error; - } - ret = isdn_slot_write(idev->isdn_slot, skb); - if (ret != len) { - /* we should never get here */ - printk(KERN_WARNING "%s: HL driver queue full\n", idev->name); - goto error; - } - - idev->transcount += len; - isdn_net_inc_frame_cnt(idev); - return; - - error: - dev_kfree_skb(skb); - mlp->stats.tx_errors++; -} - -static void -isdn_net_dial_slave(isdn_net_local *mlp) -{ - isdn_net_dev *idev; - - list_for_each_entry(idev, &mlp->slaves, slaves) { - if (!isdn_net_bound(idev)) { - isdn_net_dial(idev); - break; - } - } -} - -/* - * Based on cps-calculation, check if device is overloaded. - * If so, and if a slave exists, trigger dialing for it. - * If any slave is online, deliver packets using a simple round robin - * scheme. - * - * Return: 0 on success, !0 on failure. - */ - -int -isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_dev *idev; - isdn_net_local *mlp = ndev->priv; - - ndev->trans_start = jiffies; - - if (list_empty(&mlp->online)) - return isdn_net_autodial(skb, ndev); - - idev = isdn_net_get_locked_dev(mlp); - if (!idev) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - netif_stop_queue(ndev); - return 1; - } - /* we have our idev locked from now on */ - - isdn_net_writebuf_skb(idev, skb); - spin_unlock_bh(&idev->xmit_lock); - - /* the following stuff is here for backwards compatibility. - * in future, start-up and hangup of slaves (based on current load) - * should move to userspace and get based on an overall cps - * calculation - */ - if (jiffies != idev->last_jiffies) { - idev->cps = idev->transcount * HZ / (jiffies - idev->last_jiffies); - idev->last_jiffies = jiffies; - idev->transcount = 0; - } - if (dev->net_verbose > 3) - printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps); - - if (idev->cps > mlp->triggercps) { - if (!idev->sqfull) { - /* First time overload: set timestamp only */ - idev->sqfull = 1; - idev->sqfull_stamp = jiffies; - } else { - /* subsequent overload: if slavedelay exceeded, start dialing */ - if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) { - isdn_net_dial_slave(mlp); - } - } - } else { - if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) { - idev->sqfull = 0; - } - /* this is a hack to allow auto-hangup for slaves on moderate loads */ - list_del(&mlp->online); - list_add_tail(&mlp->online, &idev->online); - } - - return 0; -} - -int -isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_local *mlp = ndev->priv; - isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves); - - /* are we dialing already? */ - if (isdn_net_bound(idev)) - goto stop_queue; - - if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) - goto discard; - - if (isdn_net_dial(idev) < 0) - goto discard; - - /* Log packet, which triggered dialing */ - if (dev->net_verbose) - isdn_net_log_skb(skb, idev); - - stop_queue: - netif_stop_queue(ndev); - return 1; - - discard: - isdn_net_unreachable(ndev, skb, "dial rejected"); - dev_kfree_skb(skb); - return 0; -} - - -/* - * Got a packet from ISDN-Channel. - */ -static void -isdn_net_receive(isdn_net_dev *idev, struct sk_buff *skb) -{ - isdn_net_local *mlp = idev->mlp; - - idev->transcount += skb->len; - - mlp->stats.rx_packets++; - mlp->stats.rx_bytes += skb->len; - skb->dev = &mlp->dev; - skb->pkt_type = PACKET_HOST; - skb->mac.raw = skb->data; - isdn_dumppkt("R:", skb->data, skb->len, 40); - - mlp->ops->receive(mlp, idev, skb); -} - -/* - * A packet arrived via ISDN. Search interface-chain for a corresponding - * interface. If found, deliver packet to receiver-function and return 1, - * else return 0. - */ -int -isdn_net_rcv_skb(int idx, struct sk_buff *skb) -{ - isdn_net_dev *idev = isdn_slot_idev(idx); - - if (!idev) { - HERE; - return 0; - } - if (!isdn_net_online(idev)) - return 0; - - isdn_net_receive(idev, skb); - return 0; -} - -/* - * This is called from certain upper protocol layers (multilink ppp - * and x25iface encapsulation module) that want to initiate dialing - * themselves. - */ -int -isdn_net_dial_req(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - /* is there a better error code? */ - if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) - return -EBUSY; - - return isdn_net_dial(idev); -} - // ISDN_NET_ENCAP_IPTYP // ethernet type field // ====================================================================== @@ -581,6 +177,8 @@ static struct isdn_netif_ops ether_ops = { void isdn_net_init(void) { + isdn_net_lib_init(); + register_isdn_netif(ISDN_NET_ENCAP_ETHER, ðer_ops); register_isdn_netif(ISDN_NET_ENCAP_RAWIP, &rawip_ops); register_isdn_netif(ISDN_NET_ENCAP_IPTYP, &iptyp_ops); @@ -593,7 +191,11 @@ isdn_net_init(void) #ifdef CONFIG_ISDN_PPP register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP, &isdn_ppp_ops); #endif +} - isdn_net_lib_init(); +void +isdn_net_exit(void) +{ + isdn_net_lib_exit(); } diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index 16a443f584dd..14f94befc91f 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -14,138 +14,29 @@ #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/isdn.h> - /* Definitions for hupflags: */ -#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ -#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ -#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ -/* - * Definitions for Cisco-HDLC header. - */ - -#define CISCO_ADDR_UNICAST 0x0f -#define CISCO_ADDR_BROADCAST 0x8f -#define CISCO_CTRL 0x00 -#define CISCO_TYPE_CDP 0x2000 -#define CISCO_TYPE_SLARP 0x8035 -#define CISCO_SLARP_REQUEST 0 -#define CISCO_SLARP_REPLY 1 -#define CISCO_SLARP_KEEPALIVE 2 - -extern void isdn_net_init(void); -extern void isdn_net_exit(void); -extern void isdn_net_lib_init(void); -extern void isdn_net_lib_exit(void); -extern void isdn_net_hangup_all(void); -extern int isdn_net_ioctl(struct inode *, struct file *, uint, ulong); - -extern int register_isdn_netif(int encap, struct isdn_netif_ops *ops); -extern int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev); -extern int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev); - -extern int isdn_net_dial(isdn_net_dev *idev); - -extern int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c); - -extern int isdn_net_stat_callback(int, isdn_ctrl *); -extern int isdn_net_find_icall(int, int, int, setup_parm *); -extern int isdn_net_hangup(isdn_net_dev *); -extern int isdn_net_rcv_skb(int, struct sk_buff *); -extern int isdn_net_dial_req(isdn_net_dev *); -extern void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb); -extern void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb); -extern int isdn_net_online(isdn_net_dev *); - -enum { - ST_CHARGE_NULL, - ST_CHARGE_GOT_CINF, /* got a first charge info */ - ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */ -}; - -#define ISDN_NET_MAX_QUEUE_LENGTH 2 - -/* - * is this particular channel busy? - */ -static inline int -isdn_net_dev_busy(isdn_net_dev *idev) -{ - if (atomic_read(&idev->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) - return 0; - else - return 1; -} - -/* - * For the given net device, this will get a non-busy channel out of the - * corresponding bundle. The returned channel is locked. - */ -static inline isdn_net_dev * -isdn_net_get_locked_dev(isdn_net_local *mlp) -{ - unsigned long flags; - isdn_net_dev *idev; - - spin_lock_irqsave(&mlp->online_lock, flags); - - list_for_each_entry(idev, &mlp->online, online) { - spin_lock_bh(&idev->xmit_lock); - if (!isdn_net_dev_busy(idev)) { - /* point the head to next online channel */ - list_del(&mlp->online); - list_add(&mlp->online, &idev->online); - goto found; - } - spin_unlock_bh(&idev->xmit_lock); - } - idev = NULL; - - found: - spin_unlock_irqrestore(&mlp->online_lock, flags); - return idev; -} - -/* - * add a channel to a bundle - */ -static inline void -isdn_net_add_to_bundle(isdn_net_local *mlp, isdn_net_dev *idev) -{ - unsigned long flags; - - spin_lock_irqsave(&mlp->online_lock, flags); - list_add(&idev->online, &mlp->online); - spin_unlock_irqrestore(&mlp->online_lock, flags); -} -/* - * remove a channel from the bundle it belongs to - */ -static inline void -isdn_net_rm_from_bundle(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - unsigned long flags; - - spin_lock_irqsave(&mlp->online_lock, flags); - // list_del(&idev->online); FIXME - spin_unlock_irqrestore(&mlp->online_lock, flags); -} - -/* - * wake up the network -> net_device queue. - * For slaves, wake the corresponding master interface. - */ -static inline void -isdn_net_dev_wake_queue(isdn_net_dev *idev) -{ - netif_wake_queue(&idev->mlp->dev); -} - -static inline int -isdn_net_bound(isdn_net_dev *idev) -{ - return idev->isdn_slot >= 0; -} +void isdn_net_init(void); +void isdn_net_exit(void); +void isdn_net_lib_init(void); +void isdn_net_lib_exit(void); +void isdn_net_hangup_all(void); +int isdn_net_ioctl(struct inode *, struct file *, uint, ulong); + +int register_isdn_netif(int encap, struct isdn_netif_ops *ops); +int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev); +void isdn_net_online(isdn_net_dev *idev); +void isdn_net_offline(isdn_net_dev *idev); + +int isdn_net_stat_callback(int, isdn_ctrl *); +int isdn_net_find_icall(int, int, int, setup_parm *); +int isdn_net_rcv_skb(int, struct sk_buff *); + +int isdn_net_hangup(isdn_net_dev *); +int isdn_net_dial_req(isdn_net_dev *); +void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb); +void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb); +int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev); +isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp); static inline int put_u8(unsigned char *p, u8 x) diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c index 4cb417240aae..ba0144200c1f 100644 --- a/drivers/isdn/i4l/isdn_net_lib.c +++ b/drivers/isdn/i4l/isdn_net_lib.c @@ -80,12 +80,13 @@ lp_put(isdn_net_local *lp) isdn_BUG(); } -int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); /* FIXME */ - +static int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); static void isdn_net_tasklet(unsigned long data); static void isdn_net_dial_timer(unsigned long data); static int isdn_init_netif(struct net_device *ndev); static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...); +static int isdn_net_dial(isdn_net_dev *idev); +static int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c); static struct fsm isdn_net_fsm; @@ -151,6 +152,18 @@ static char *isdn_net_ev_str[] = { "EV_DO_ACCEPT", }; +/* Definitions for hupflags: */ + +#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ +#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ +#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ + +enum { + ST_CHARGE_NULL, + ST_CHARGE_GOT_CINF, /* got a first charge info */ + ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */ +}; + /* ====================================================================== */ /* Registration of ISDN network interface types */ /* ====================================================================== */ @@ -208,7 +221,8 @@ isdn_net_set_encap(isdn_net_local *lp, int encap) if (lp->ops && lp->ops->cleanup) lp->ops->cleanup(lp); - if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) { + if (encap < 0 || encap >= ISDN_NET_ENCAP_NR || + !isdn_netif_ops[encap]) { lp->p_encap = -1; lp->ops = NULL; retval = -EINVAL; @@ -348,7 +362,6 @@ isdn_net_addif(char *name, isdn_net_local *mlp) strcpy(idev->name, name); tasklet_init(&idev->tlet, isdn_net_tasklet, (unsigned long) idev); - spin_lock_init(&idev->xmit_lock); skb_queue_head_init(&idev->super_tx_queue); idev->isdn_slot = -1; @@ -356,7 +369,7 @@ isdn_net_addif(char *name, isdn_net_local *mlp) idev->pre_channel = -1; idev->exclusive = -1; - idev->ppp_slot = -1; + idev->ipppd = NULL; idev->pppbind = -1; init_timer(&idev->dial_timer); @@ -380,6 +393,7 @@ isdn_net_addif(char *name, isdn_net_local *mlp) mlp->magic = ISDN_NET_MAGIC; INIT_LIST_HEAD(&mlp->slaves); INIT_LIST_HEAD(&mlp->online); + spin_lock_init(&mlp->xmit_lock); mlp->p_encap = -1; isdn_net_set_encap(mlp, ISDN_NET_ENCAP_RAWIP); @@ -1007,7 +1021,7 @@ isdn_net_hangup_all(void) * Remove all network-interfaces */ void -isdn_net_exit(void) +isdn_net_cleanup(void) { isdn_net_dev *idev; int retval; @@ -1025,9 +1039,6 @@ isdn_net_exit(void) isdn_BUG(); } up(&sem); - - // FIXME - isdn_net_lib_exit(); } /* ====================================================================== */ @@ -1053,7 +1064,7 @@ isdn_net_open(struct net_device *dev) if (lp->ops->open) retval = lp->ops->open(lp); - if (!retval) + if (retval) return retval; netif_start_queue(dev); @@ -1069,7 +1080,6 @@ isdn_net_open(struct net_device *dev) /* * Shutdown a net-interface. */ -// FIXME share? static int isdn_net_close(struct net_device *dev) { @@ -1083,14 +1093,14 @@ isdn_net_close(struct net_device *dev) netif_stop_queue(dev); - list_for_each_safe(l, n, &lp->online) { - sdev = list_entry(l, isdn_net_dev, online); + list_for_each_safe(l, n, &lp->slaves) { + sdev = list_entry(l, isdn_net_dev, slaves); isdn_net_hangup(sdev); } /* The hangup will make the refcnt drop back to * 1 (referenced by list only) soon. */ spin_lock_irqsave(&running_devs_lock, flags); - while (atomic_read(&dev->refcnt) != 1) { + while (atomic_read(&lp->refcnt) != 1) { spin_unlock_irqrestore(&running_devs_lock, flags); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); @@ -1147,29 +1157,12 @@ isdn_init_netif(struct net_device *ndev) } /* ====================================================================== */ - -static void -isdn_net_tasklet(unsigned long data) -{ - isdn_net_dev *idev = (isdn_net_dev *) data; - struct sk_buff *skb; - - spin_lock_bh(&idev->xmit_lock); - while (!isdn_net_dev_busy(idev)) { - skb = skb_dequeue(&idev->super_tx_queue); - if (!skb) - break; - isdn_net_writebuf_skb(idev, skb); - } - spin_unlock_bh(&idev->xmit_lock); -} - -/* ====================================================================== */ /* call control state machine */ /* ====================================================================== */ // FIXME -int isdn_net_online(isdn_net_dev *idev) +static int +isdn_net_is_connected(isdn_net_dev *idev) { return idev->fi.state == ST_ACTIVE; } @@ -1234,7 +1227,7 @@ isdn_net_bind_channel(isdn_net_dev *idev, int slot) return retval; } -int +static int isdn_net_dial(isdn_net_dev *idev) { int retval; @@ -1250,6 +1243,127 @@ isdn_net_dial(isdn_net_dev *idev) return retval; } +static void +isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) +{ + u_short proto = ntohs(skb->protocol); + + printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", + dev->name, + (reason != NULL) ? reason : "unknown", + (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); + + dst_link_failure(skb); +} + +/* + * This is called from certain upper protocol layers (multilink ppp + * and x25iface encapsulation module) that want to initiate dialing + * themselves. + */ +int +isdn_net_dial_req(isdn_net_dev *idev) +{ + isdn_net_local *mlp = idev->mlp; + /* is there a better error code? */ + if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) + return -EBUSY; + + return isdn_net_dial(idev); +} + +static void +isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev) +{ + unsigned char *p = skb->nh.raw; /* hopefully, this was set correctly */ + unsigned short proto = ntohs(skb->protocol); + int data_ofs; + struct ip_ports { + unsigned short source; + unsigned short dest; + } *ipp; + char addinfo[100]; + + data_ofs = ((p[0] & 15) * 4); + switch (proto) { + case ETH_P_IP: + switch (p[9]) { + case IPPROTO_ICMP: + strcpy(addinfo, "ICMP"); + break; + case IPPROTO_TCP: + case IPPROTO_UDP: + ipp = (struct ip_ports *) (&p[data_ofs]); + sprintf(addinfo, "%s, port: %d -> %d", + p[9] == IPPROTO_TCP ? "TCP" : "UDP", + ntohs(ipp->source), ntohs(ipp->dest)); + break; + default: + sprintf(addinfo, "type %d", p[9]); + } + printk(KERN_INFO + "OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s\n", + + NIPQUAD(*(u32 *)(p + 12)), NIPQUAD(*(u32 *)(p + 16)), + addinfo); + break; + case ETH_P_ARP: + printk(KERN_INFO + "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", + NIPQUAD(*(u32 *)(p + 14)), NIPQUAD(*(u32 *)(p + 24))); + break; + default: + printk(KERN_INFO "OPEN: unknown proto %#x\n", proto); + } +} + +int +isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev) +{ + isdn_net_local *mlp = ndev->priv; + isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves); + int retval; + + if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) + goto discard; + + retval = isdn_net_dial(idev); + if (retval == -ESRCH) + goto stop_queue; + + if (retval < 0) + goto discard; + + /* Log packet, which triggered dialing */ + if (dev->net_verbose) + isdn_net_log_skb(skb, idev); + + stop_queue: + netif_stop_queue(ndev); + return 1; + + discard: + isdn_net_unreachable(ndev, skb, "dial rejected"); + dev_kfree_skb(skb); + return 0; +} + + +static void +isdn_net_dial_slave(isdn_net_local *mlp) +{ + isdn_net_dev *idev; + + if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) + return; + + list_for_each_entry(idev, &mlp->slaves, slaves) { + if (fsm_event(&idev->fi, EV_DO_DIAL, NULL) != -ESRCH) { + break; + } + } +} + static int accept_icall(struct fsm_inst *fi, int pr, void *arg) { @@ -1640,14 +1754,12 @@ bconn(struct fsm_inst *fi, int pr, void *arg) del_timer(&idev->dial_timer); } - isdn_net_add_to_bundle(mlp, idev); - printk(KERN_INFO "%s connected\n", idev->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ idev->chargetime = jiffies; - + idev->frame_cnt = 0; idev->transcount = 0; idev->cps = 0; idev->last_jiffies = jiffies; @@ -1655,8 +1767,8 @@ bconn(struct fsm_inst *fi, int pr, void *arg) if (mlp->ops->connected) mlp->ops->connected(idev); else - isdn_net_dev_wake_queue(idev); - + isdn_net_online(idev); + return 0; } @@ -1669,11 +1781,11 @@ bhup(struct fsm_inst *fi, int pr, void *arg) del_timer(&idev->dial_timer); if (mlp->ops->disconnected) mlp->ops->disconnected(idev); + else + isdn_net_offline(idev); printk(KERN_INFO "%s: disconnected\n", idev->name); fsm_change_state(fi, ST_WAIT_DHUP); - isdn_net_rm_from_bundle(idev); - return 0; } static int @@ -1748,10 +1860,7 @@ isdn_net_hangup(isdn_net_dev *idev) isdn_ctrl cmd; del_timer(&idev->dial_timer); - if (!isdn_net_bound(idev)) { - isdn_BUG(); - return 1; - } + printk(KERN_INFO "%s: local hangup\n", idev->name); isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd); return 1; @@ -1769,7 +1878,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) isdn_net_dev *idev = isdn_slot_idev(idx); if (!idev) { - HERE; return 0; } switch (c->command) { @@ -1791,7 +1899,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) } } -int +static int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg) { fsm_event(&idev->fi, pr, arg); @@ -1873,6 +1981,326 @@ static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...) printk(KERN_DEBUG "%s\n", buf); } +/* ====================================================================== */ +/* xmit path */ +/* ====================================================================== */ + +#define ISDN_NET_MAX_QUEUE_LENGTH 2 + +/* + * is this particular channel busy? + */ +static inline int +isdn_net_dev_busy(isdn_net_dev *idev) +{ + return idev->frame_cnt >= ISDN_NET_MAX_QUEUE_LENGTH; +} + +/* + * find out if the net_device which this mlp is belongs to is busy. + * It's busy iff all channels are busy. + * must hold mlp->xmit_lock + * FIXME: Use a mlp->frame_cnt instead of loop? + */ +static inline int +isdn_net_local_busy(isdn_net_local *mlp) +{ + isdn_net_dev *idev; + + list_for_each_entry(idev, &mlp->online, online) { + if (!isdn_net_dev_busy(idev)) + return 0; + } + return 1; +} + +/* + * For the given net device, this will get a non-busy channel out of the + * corresponding bundle. + * must hold mlp->xmit_lock + */ +isdn_net_dev * +isdn_net_get_xmit_dev(isdn_net_local *mlp) +{ + isdn_net_dev *idev; + + list_for_each_entry(idev, &mlp->online, online) { + if (!isdn_net_dev_busy(idev)) { + /* point the head to next online channel */ + list_del(&mlp->online); + list_add(&mlp->online, &idev->online); + return idev; + } + } + return NULL; +} + +/* mlp->xmit_lock must be held */ +static inline void +isdn_net_inc_frame_cnt(isdn_net_dev *idev) +{ + isdn_net_local *mlp = idev->mlp; + + if (isdn_net_dev_busy(idev)) + isdn_BUG(); + + idev->frame_cnt++; + if (isdn_net_local_busy(mlp)) + netif_stop_queue(&mlp->dev); +} + +/* mlp->xmit_lock must be held */ +static inline void +isdn_net_dec_frame_cnt(isdn_net_dev *idev) +{ + isdn_net_local *mlp = idev->mlp; + + idev->frame_cnt--; + + if (isdn_net_dev_busy(idev)) + isdn_BUG(); + + if (!skb_queue_empty(&idev->super_tx_queue)) + tasklet_schedule(&idev->tlet); + else + netif_wake_queue(&mlp->dev); +} + +static void +isdn_net_tasklet(unsigned long data) +{ + isdn_net_dev *idev = (isdn_net_dev *) data; + isdn_net_local *mlp = idev->mlp; + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&mlp->xmit_lock, flags); + while (!isdn_net_dev_busy(idev) && + (skb = skb_dequeue(&idev->super_tx_queue))) { + isdn_net_writebuf_skb(idev, skb); + } + spin_unlock_irqrestore(&mlp->xmit_lock, flags); +} + +/* We're good to accept (IP/whatever) traffic now */ + +void +isdn_net_online(isdn_net_dev *idev) +{ + // FIXME check we're connected + isdn_net_local *mlp = idev->mlp; + unsigned long flags; + + spin_lock_irqsave(&mlp->xmit_lock, flags); + list_add(&idev->online, &mlp->online); + spin_unlock_irqrestore(&mlp->xmit_lock, flags); + + netif_wake_queue(&mlp->dev); +} + +/* No more (IP/whatever) traffic over the net interface */ + +void +isdn_net_offline(isdn_net_dev *idev) +{ + isdn_net_local *mlp = idev->mlp; + unsigned long flags; + + spin_lock_irqsave(&mlp->xmit_lock, flags); + list_del(&idev->online); + spin_unlock_irqrestore(&mlp->xmit_lock, flags); + + skb_queue_purge(&idev->super_tx_queue); +} + +/* + * all frames sent from the (net) LL to a HL driver should go via this function + * must hold mlp->xmit_lock + */ +void +isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb) +{ + isdn_net_local *mlp = idev->mlp; + int ret; + int len = skb->len; /* save len */ + + /* before obtaining the lock the caller should have checked that + the lp isn't busy */ + if (isdn_net_dev_busy(idev)) { + isdn_BUG(); + goto error; + } + + if (!isdn_net_is_connected(idev)) { + isdn_BUG(); + goto error; + } + ret = isdn_slot_write(idev->isdn_slot, skb); + if (ret != len) { + /* we should never get here */ + printk(KERN_WARNING "%s: HL driver queue full\n", idev->name); + goto error; + } + + idev->transcount += len; + isdn_net_inc_frame_cnt(idev); + return; + + error: + dev_kfree_skb(skb); + mlp->stats.tx_errors++; +} + +/* A packet has successfully been sent out. */ + +static int +isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c) +{ + isdn_net_local *mlp = idev->mlp; + unsigned long flags; + + spin_lock_irqsave(&mlp->xmit_lock, flags); + isdn_net_dec_frame_cnt(idev); + spin_unlock_irqrestore(&mlp->xmit_lock, flags); + mlp->stats.tx_packets++; + mlp->stats.tx_bytes += c->parm.length; + return 1; +} + +/* + * Based on cps-calculation, check if device is overloaded. + * If so, and if a slave exists, trigger dialing for it. + * If any slave is online, deliver packets using a simple round robin + * scheme. + * + * Return: 0 on success, !0 on failure. + */ + +int +isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + isdn_net_dev *idev; + isdn_net_local *mlp = ndev->priv; + unsigned long flags; + int retval; + + ndev->trans_start = jiffies; + + spin_lock_irqsave(&mlp->xmit_lock, flags); + + if (list_empty(&mlp->online)) { + retval = isdn_net_autodial(skb, ndev); + goto out; + } + + idev = isdn_net_get_xmit_dev(mlp); + if (!idev) { + printk(KERN_INFO "%s: all channels busy - requeuing!\n", ndev->name); + netif_stop_queue(ndev); + retval = 1; + goto out; + } + + isdn_net_writebuf_skb(idev, skb); + + /* the following stuff is here for backwards compatibility. + * in future, start-up and hangup of slaves (based on current load) + * should move to userspace and get based on an overall cps + * calculation + */ + if (jiffies != idev->last_jiffies) { + idev->cps = idev->transcount * HZ / (jiffies - idev->last_jiffies); + idev->last_jiffies = jiffies; + idev->transcount = 0; + } + if (dev->net_verbose > 3) + printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps); + + if (idev->cps > mlp->triggercps) { + if (!idev->sqfull) { + /* First time overload: set timestamp only */ + idev->sqfull = 1; + idev->sqfull_stamp = jiffies; + } else { + /* subsequent overload: if slavedelay exceeded, start dialing */ + if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) { + isdn_net_dial_slave(mlp); + } + } + } else { + if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) { + idev->sqfull = 0; + } + /* this is a hack to allow auto-hangup for slaves on moderate loads */ + list_del(&mlp->online); + list_add_tail(&mlp->online, &idev->online); + } + + retval = 0; + out: + spin_unlock_irqrestore(&mlp->xmit_lock, flags); + return retval; +} + +/* + * this function is used to send supervisory data, i.e. data which was + * not received from the network layer, but e.g. frames from ipppd, CCP + * reset frames etc. + * must hold mlp->xmit_lock + */ +void +isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb) +{ + if (!isdn_net_dev_busy(idev)) { + isdn_net_writebuf_skb(idev, skb); + } else { + skb_queue_tail(&idev->super_tx_queue, skb); + } +} + +/* ====================================================================== */ +/* receive path */ +/* ====================================================================== */ + +/* + * A packet arrived via ISDN. Search interface-chain for a corresponding + * interface. If found, deliver packet to receiver-function and return 1, + * else return 0. + */ +int +isdn_net_rcv_skb(int idx, struct sk_buff *skb) +{ + isdn_net_dev *idev = isdn_slot_idev(idx); + isdn_net_local *mlp; + + if (!idev) { + isdn_BUG(); + return 0; + } + if (!isdn_net_is_connected(idev)) { + isdn_BUG(); + return 0; + } + + mlp = idev->mlp; + + idev->transcount += skb->len; + + mlp->stats.rx_packets++; + mlp->stats.rx_bytes += skb->len; + skb->dev = &mlp->dev; + skb->pkt_type = PACKET_HOST; + isdn_dumppkt("R:", skb->data, skb->len, 40); + + mlp->ops->receive(mlp, idev, skb); + + return 1; +} + +/* ====================================================================== */ +/* init / exit */ +/* ====================================================================== */ + void isdn_net_lib_init(void) { @@ -1882,5 +2310,7 @@ isdn_net_lib_init(void) void isdn_net_lib_exit(void) { + isdn_net_cleanup(); + fsm_free(&isdn_net_fsm); } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 3c59a373459b..13395d86720a 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -18,635 +18,535 @@ #include "isdn_common.h" #include "isdn_ppp.h" +#include "isdn_ppp_ccp.h" #include "isdn_net.h" -/* Prototypes */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); -static int isdn_ppp_closewait(int slot); -static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb, int proto); -static int isdn_ppp_if_get_unit(char *namebuf); -static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *); -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *,struct ippp_struct *,int *proto); -static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, - struct sk_buff *skb,int proto); -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, - struct ippp_struct *is,struct ippp_struct *master,int type); -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); +static struct sk_buff * +isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask); -/* New CCP stuff */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is); -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_timer_callback(unsigned long closure); -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp); -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id); +static int +isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *); +/* ====================================================================== */ +/* IPPPD handling */ +/* ====================================================================== */ +/* We use reference counting for struct ipppd. It is alloced on + * open() on /dev/ipppX and saved into file->private, making for one + * reference. release() will release this reference, after all other + * references are gone, the destructor frees it. + * + * Another reference is taken by isdn_ppp_bind() and freed by + * isdn_ppp_unbind(). The callbacks from isdn_net_lib.c happen only + * between isdn_ppp_bind() and isdn_ppp_unbind(), i.e. access to + * idev->ipppd is safe without further locking. + */ -#ifdef CONFIG_ISDN_MPP -static ippp_bundle * isdn_ppp_bundle_arr = NULL; - -static int isdn_ppp_mp_bundle_array_init(void); -static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to); -static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb); -static void isdn_ppp_mp_cleanup(isdn_net_local *lp ); +#define IPPPD_DEBUG -static int isdn_ppp_bundle(struct ippp_struct *, int unit); -#endif /* CONFIG_ISDN_MPP */ - -char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; +#ifdef IPPPD_DEBUG +#define ipppd_debug(i, fmt, arg...) \ + printk(KERN_DEBUG "ipppd %p minor %d state %#x %s: " fmt "\n", (i), \ + (i)->minor, (i)->state, __FUNCTION__ , ## arg) +#else +#define ipppd_debug(...) do { } while (0) +#endif -static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; +/* ipppd::flags */ +enum { + IPPPD_FL_HUP = 0x01, + IPPPD_FL_WAKEUP = 0x02, +}; -static struct isdn_ppp_compressor *ipc_head = NULL; +/* ipppd::state */ +enum { + IPPPD_ST_OPEN, + IPPPD_ST_ASSIGNED, + IPPPD_ST_CONNECTED, +}; + +struct ipppd { + struct list_head ipppds; + int state; + int flags; + struct sk_buff_head rq; + wait_queue_head_t wq; + struct isdn_net_dev_s *idev; + int unit; + int minor; + unsigned long debug; + atomic_t refcnt; +}; + +/* ====================================================================== */ + +static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(ipppds); -/* - * frame log (debug) - */ static void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) +ipppd_destroy(struct ipppd *ipppd) { - int cnt, - j, - i; - char buf[80]; + HERE; - if (len < maxlen) - maxlen = len; + skb_queue_purge(&ipppd->rq); + kfree(ipppd); +} - for (i = 0, cnt = 0; cnt < maxlen; i++) { - for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) - sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); - printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); - } +static inline struct ipppd * +ipppd_get(struct ipppd *ipppd) +{ + atomic_inc(&ipppd->refcnt); + printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt)); + return ipppd; } -/* - * unbind isdn_net_local <=> ippp-device - * note: it can happen, that we hangup/free the master before the slaves - * in this case we bind another lp to the master device - */ -static void -isdn_ppp_free(isdn_net_dev *idev) +static inline void +ipppd_put(struct ipppd *ipppd) +{ + printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt)); + + if (atomic_dec_and_test(&ipppd->refcnt)) + ipppd_destroy(ipppd); +} + +/* ====================================================================== */ +/* char dev ops */ + +/* --- open ------------------------------------------------------------- */ + +static int +ipppd_open(struct inode *ino, struct file *file) { unsigned long flags; - struct ippp_struct *is; + unsigned int minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; + struct ipppd *ipppd; - if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); - return; - } + ipppd = kmalloc(sizeof(*ipppd), GFP_KERNEL); + if (!ipppd) + return -ENOMEM; - save_flags(flags); - cli(); + memset(ipppd, 0, sizeof(*ipppd)); + atomic_set(&ipppd->refcnt, 0); + + /* file->private_data holds a reference */ + file->private_data = ipppd_get(ipppd); + + ipppd->unit = -1; /* set by isdn_ppp_bind */ + ipppd->minor = minor; + ipppd->state = IPPPD_ST_OPEN; + init_waitqueue_head(&ipppd->wq); + skb_queue_head_init(&ipppd->rq); + + spin_lock_irqsave(&ipppds, flags); + list_add(&ipppd->ipppds, &ipppds); + spin_unlock_irqrestore(&ipppds, flags); + + ipppd_debug(ipppd, "minor %d", minor); -#ifdef CONFIG_ISDN_MPP - spin_lock(&idev->pb->lock); -#endif - isdn_net_rm_from_bundle(idev); -#ifdef CONFIG_ISDN_MPP - if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ - isdn_ppp_mp_cleanup(lp); + return 0; +} - lp->netdev->pb->ref_ct--; - spin_unlock(&lp->netdev->pb->lock); -#endif /* CONFIG_ISDN_MPP */ - if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __FUNCTION__ , idev->ppp_slot); - restore_flags(flags); - return; - } - is = ippp_table[idev->ppp_slot]; - if ((is->state & IPPP_CONNECT)) - isdn_ppp_closewait(idev->ppp_slot); /* force wakeup on ippp device */ - else if (is->state & IPPP_ASSIGNED) - is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ +/* --- release --------------------------------------------------------- */ - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %p\n", idev->ppp_slot, is->idev); +static int +ipppd_release(struct inode *ino, struct file *file) +{ + unsigned long flags; + struct ipppd *ipppd = file->private_data; - is->idev = NULL; /* link is down .. set lp to NULL */ - idev->ppp_slot = -1; /* is this OK ?? */ + ipppd_debug(ipppd, ""); - restore_flags(flags); - return; + if (ipppd->state == IPPPD_ST_CONNECTED) + isdn_net_hangup(ipppd->idev); + + spin_lock_irqsave(&ipppds, flags); + list_del(&ipppd->ipppds); + spin_unlock_irqrestore(&ipppds, flags); + + ipppd_put(ipppd); + + return 0; } -/* - * bind isdn_net_local <=> ippp-device - */ -int -isdn_ppp_bind(isdn_net_dev *idev) +/* --- read ------------------------------------------------------------- */ + +/* read() is always non blocking */ +static ssize_t +ipppd_read(struct file *file, char *buf, size_t count, loff_t *off) { - int i; - int unit = 0; - long flags; - struct ippp_struct *is; + struct ipppd *is; + struct sk_buff *skb; int retval; - save_flags(flags); - cli(); - if (idev->pppbind < 0) { /* device bound to ippp device ? */ - struct list_head *l; - char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive, 0, ISDN_MAX_CHANNELS); - /* step through net devices to find exclusive minors */ - list_for_each(l, &isdn_net_devs) { - isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); - if (p->pppbind >= 0) - exclusive[p->pppbind] = 1; - } - /* - * search a free device / slot - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ - break; - } - } - } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->minor == idev->pppbind && - (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) - break; - } - } + if (off != &file->f_pos) + return -ESPIPE; + + is = file->private_data; - if (i >= ISDN_MAX_CHANNELS) { - restore_flags(flags); - printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - retval = -1; + skb = skb_dequeue(&is->rq); + if (!skb) { + retval = -EAGAIN; goto out; } - unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */ - if (unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", idev->name); - retval = -1; - goto out; + if (skb->len > count) { + retval = -EMSGSIZE; + goto out_free; } - - idev->ppp_slot = i; - is = ippp_table[i]; - is->idev = idev; - is->unit = unit; - is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ -#ifdef CONFIG_ISDN_MPP - retval = isdn_ppp_mp_init(lp, NULL); - if (retval < 0) - goto out; -#endif /* CONFIG_ISDN_MPP */ - - retval = idev->ppp_slot; + if (copy_to_user(buf, skb->data, skb->len)) { + retval = -EFAULT; + goto out_free; + } + retval = skb->len; + out_free: + dev_kfree_skb(skb); out: - restore_flags(flags); return retval; } -/* - * kick the ipppd on the device - * (wakes up daemon after B-channel connect) - */ +/* --- write ------------------------------------------------------------ */ -static void -isdn_ppp_wakeup_daemon(isdn_net_dev *idev) +/* write() is always non blocking */ +static ssize_t +ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off) { - if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, idev->ppp_slot); - return; - } - ippp_table[idev->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - wake_up_interruptible(&ippp_table[idev->ppp_slot]->wq); -} + isdn_net_dev *idev; + struct ipppd *ipppd; + struct sk_buff *skb; + char *p; + int retval; + u16 proto; -/* - * there was a hangup on the netdevice - * force wakeup of the ippp device - * go into 'device waits for release' state - */ -static int -isdn_ppp_closewait(int slot) -{ - struct ippp_struct *is; + if (off != &file->f_pos) + return -ESPIPE; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__ , slot); - return 0; - } - is = ippp_table[slot]; - if (is->state) - wake_up_interruptible(&is->wq); - is->state = IPPP_CLOSEWAIT; - return 1; -} + ipppd = file->private_data; + ipppd_debug(ipppd, "count = %d", count); -/* - * isdn_ppp_find_slot / isdn_ppp_free_slot - */ + if (ipppd->state != IPPPD_ST_CONNECTED) { + retval = -ENOTCONN; + goto out; + } -static int -isdn_ppp_get_slot(void) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!ippp_table[i]->state) - return i; + idev = ipppd->idev; + if (!idev) { + isdn_BUG(); + retval = -ENODEV; + goto out; } - return -1; + /* Daemon needs to send at least full header, AC + proto */ + if (count < 4) { + retval = -EMSGSIZE; + goto out; + } + skb = isdn_ppp_dev_alloc_skb(idev, count, GFP_KERNEL); + if (!skb) { + retval = -ENOMEM; + goto out; + } + p = skb_put(skb, count); + if (copy_from_user(p, buf, count)) { + kfree_skb(skb); + retval = -EFAULT; + goto out; + } + /* Don't reset huptimer for LCP packets. (Echo requests). */ + proto = PPP_PROTOCOL(p); + if (proto != PPP_LCP) + idev->huptimer = 0; + + /* Keeps CCP/compression states in sync */ + switch (proto) { + case PPP_CCP: + ippp_ccp_send_ccp(idev->mlp->ccp, skb); + break; + case PPP_CCPFRAG: + ippp_ccp_send_ccp(idev->ccp, skb); + break; + } + /* FIXME: Somewhere we need protection against the + * queue growing too large */ + isdn_net_write_super(idev, skb); + + retval = count; + + out: + return retval; } -/* - * isdn_ppp_open - */ +/* --- poll ------------------------------------------------------------- */ -static int -isdn_ppp_open(struct inode *ino, struct file *file) +static unsigned int +ipppd_poll(struct file *file, poll_table * wait) { - uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; - int slot; - struct ippp_struct *is; + unsigned int mask; + struct ipppd *is; - slot = isdn_ppp_get_slot(); - if (slot < 0) { - return -EBUSY; - } - is = file->private_data = ippp_table[slot]; + is = file->private_data; - printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state); + ipppd_debug(is, ""); - /* compression stuff */ - is->link_compressor = is->compressor = NULL; - is->link_decompressor = is->decompressor = NULL; - is->link_comp_stat = is->comp_stat = NULL; - is->link_decomp_stat = is->decomp_stat = NULL; - is->compflags = 0; + /* just registers wait_queue hook. This doesn't really wait. */ + poll_wait(file, &is->wq, wait); - is->reset = isdn_ppp_ccp_reset_alloc(is); + if (is->flags & IPPPD_FL_HUP) { + mask = POLLHUP; + goto out; + } + /* we're always ready to send .. */ + mask = POLLOUT | POLLWRNORM; - is->idev = NULL; - is->mp_seqno = 0; /* MP sequence number */ - is->pppcfg = 0; /* ppp configuration */ - is->mpppcfg = 0; /* mppp configuration */ - is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - is->unit = -1; /* set, when we have our interface */ - is->mru = 1524; /* MRU, default 1524 */ - is->maxcid = 16; /* VJ: maxcid */ - is->tk = current; - init_waitqueue_head(&is->wq); - is->minor = minor; -#ifdef CONFIG_ISDN_PPP_VJ /* - * VJ header compression init + * if IPPP_FL_WAKEUP is set we return even if we have nothing to read */ - is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ -#endif - - is->state = IPPP_OPEN; - isdn_lock_drivers(); - - return 0; -} - -/* - * release ippp device - */ -static int -isdn_ppp_release(struct inode *ino, struct file *file) -{ - uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; - struct ippp_struct *is; - - lock_kernel(); - - is = file->private_data; - - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp: release, minor: %d %p\n", minor, is->idev); - - if (is->idev) { /* a lp address says: this link is still up */ - /* - * isdn_net_hangup() calls isdn_ppp_free() - * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 - * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() - */ - is->state &= ~IPPP_CONNECT; - isdn_net_hangup(is->idev); + if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) { + is->flags &= ~IPPPD_FL_WAKEUP; + mask |= POLLIN | POLLRDNORM; + set_current_state(TASK_INTERRUPTIBLE); // FIXME + schedule_timeout(HZ); } - skb_queue_purge(&is->rq); - -#ifdef CONFIG_ISDN_PPP_VJ -/* TODO: if this was the previous master: link the slcomp to the new master */ - slhc_free(is->slcomp); - is->slcomp = NULL; -#endif -/* TODO: if this was the previous master: link the the stuff to the new master */ - if(is->comp_stat) - is->compressor->free(is->comp_stat); - if(is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - if(is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - if(is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->compressor = is->link_compressor = NULL; - is->decompressor = is->link_decompressor = NULL; - is->comp_stat = is->link_comp_stat = NULL; - is->decomp_stat = is->link_decomp_stat = NULL; - - /* Clean up if necessary */ - if(is->reset) - isdn_ppp_ccp_reset_free(is); - - /* this slot is ready for new connections */ - is->state = 0; - - isdn_unlock_drivers(); - - unlock_kernel(); - return 0; + out: + return mask; } -/* - * get_arg .. ioctl helper - */ +/* --- ioctl ------------------------------------------------------------ */ + +/* get_arg .. ioctl helper */ static int -get_arg(void *b, void *val, int len) +get_arg(unsigned long arg, void *val, int len) { - if (len <= 0) - len = sizeof(void *); - if (copy_from_user((void *) val, b, len)) + if (copy_from_user((void *) val, (void *) arg, len)) return -EFAULT; return 0; } -/* - * set arg .. ioctl helper - */ +/* set arg .. ioctl helper */ static int -set_arg(void *b, void *val,int len) +set_arg(unsigned long arg, void *val,int len) { - if (copy_to_user(b, (void *) val, len)) + if (copy_to_user((void *) arg, (void *) val, len)) return -EFAULT; return 0; } -/* - * ippp device ioctl - */ static int -isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg) +ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, + unsigned long arg) { isdn_net_dev *idev; unsigned long val; - int r,i,j; - struct ippp_struct *is; + int r; + struct ipppd *is; struct isdn_ppp_comp_data data; + unsigned int cfg; - is = (struct ippp_struct *) file->private_data; + is = file->private_data; idev = is->idev; - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state); - - if (!(is->state & IPPP_OPEN)) - return -EINVAL; + ipppd_debug(is, "cmd %#x", cmd); switch (cmd) { - case PPPIOCBUNDLE: + case PPPIOCBUNDLE: #ifdef CONFIG_ISDN_MPP - if (!(is->state & IPPP_CONNECT)) - return -EINVAL; - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) - return r; - printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) is->minor, (int) is->unit, (int) val); - return isdn_ppp_bundle(is, val); -#else - return -1; -#endif - break; - case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) - return r; - break; - case PPPIOCGIFNAME: - if(!idev) - return -EINVAL; - if ((r = set_arg((void *) arg, idev->name, strlen(idev->name)))) - return r; - break; - case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) - return r; + if (is->state != IPPPD_ST_CONNECTED) { + r = -EINVAL; break; - case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) - return r; - is->mpppcfg = val; - break; - case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) - return r; + } + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { - return r; - } - if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { - if (idev) { - /* OK .. we are ready to send buffers */ - isdn_net_dev_wake_queue(idev); - } - } - is->pppcfg = val; + + printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", + is->minor, is->unit, val); + r = isdn_ppp_bundle(is, val); +#else + r = -EINVAL; +#endif + break; + case PPPIOCGUNIT: /* get ppp/isdn unit number */ + r = set_arg(arg, &is->unit, sizeof(is->unit)); + break; + case PPPIOCGDEBUG: + r = set_arg(arg, &is->debug, sizeof(is->debug)); + break; + case PPPIOCSDEBUG: + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCGIDLE: /* get idle time information */ - if (idev) { - struct ppp_idle pidle; - pidle.xmit_idle = pidle.recv_idle = idev->huptimer; - if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) - return r; - } + is->debug = val; + if (idev) { + idev->debug = val; + idev->mlp->debug = val; + } + break; + case PPPIOCGCOMPRESSORS: + { + unsigned long protos[8]; + ippp_ccp_get_compressors(protos); + r = set_arg(arg, protos, sizeof(protos)); + break; + } + default: + r = -ENOTTY; + break; + } + + if (r != -ENOTTY) + goto out; + + if (!idev) { + r = -ENODEV; + goto out; + } + + switch (cmd) { + case PPPIOCGIFNAME: + r = set_arg(arg, idev->name, strlen(idev->name)+1); + break; + case PPPIOCGMPFLAGS: /* get configuration flags */ + r = set_arg(arg, &idev->mlp->mpppcfg, sizeof(idev->mlp->mpppcfg)); + break; + case PPPIOCSMPFLAGS: /* set configuration flags */ + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) - return r; - is->mru = val; + idev->mlp->mpppcfg = val; + break; + case PPPIOCGFLAGS: /* get configuration flags */ + cfg = idev->pppcfg | ippp_ccp_get_flags(idev->ccp); + r = set_arg(arg, &cfg, sizeof(cfg)); + break; + case PPPIOCSFLAGS: /* set configuration flags */ + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCSMPMRU: + if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) { + idev->pppcfg = val; + /* OK .. we are ready to send buffers */ + isdn_net_online(idev); break; - case PPPIOCSMPMTU: + } + idev->pppcfg = val; + break; + case PPPIOCGIDLE: /* get idle time information */ + { + struct ppp_idle pidle; + pidle.xmit_idle = pidle.recv_idle = idev->huptimer; + r = set_arg(arg, &pidle,sizeof(pidle)); + break; + } + case PPPIOCSMRU: /* set receive unit size for PPP */ + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) - return r; - val++; - if (is->maxcid != val) { -#ifdef CONFIG_ISDN_PPP_VJ - struct slcompress *sltmp; -#endif - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); - is->maxcid = val; + r = ippp_ccp_set_mru(idev->ccp, val); + break; + case PPPIOCSMPMRU: + break; + case PPPIOCSMPMTU: + break; #ifdef CONFIG_ISDN_PPP_VJ - sltmp = slhc_init(16, val); - if (!sltmp) { - printk(KERN_ERR "ippp, can't realloc slhc struct\n"); - return -ENOMEM; - } - if (is->slcomp) - slhc_free(is->slcomp); - is->slcomp = sltmp; -#endif - } - break; - case PPPIOCGDEBUG: - if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) - return r; + case PPPIOCSMAXCID: /* set the maximum compression slot id */ + { + struct slcompress *sltmp; + r = get_arg(arg, &val, sizeof(val)); + if (r) break; - case PPPIOCSDEBUG: - if ((r = get_arg((void *) arg, &val, sizeof(val) ))) - return r; - is->debug = val; + val++; + sltmp = slhc_init(16, val); + if (!sltmp) { + r = -ENOMEM; break; - case PPPIOCGCOMPRESSORS: - { - unsigned long protos[8] = {0,}; - struct isdn_ppp_compressor *ipc = ipc_head; - while(ipc) { - j = ipc->num / (sizeof(long)*8); - i = ipc->num % (sizeof(long)*8); - if(j < 8) - protos[j] |= (0x1<<i); - ipc = ipc->next; - } - if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) - return r; - } + } + if (idev->mlp->slcomp) + slhc_free(idev->mlp->slcomp); + idev->mlp->slcomp = sltmp; + r = 0; + break; + } +#endif + case PPPIOCSCOMPRESSOR: + r = get_arg(arg, &data, sizeof(data)); + if (r) break; - case PPPIOCSCOMPRESSOR: - if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) - return r; - return isdn_ppp_set_compressor(is, &data); - case PPPIOCGCALLINFO: - { - isdn_net_local *mlp; - struct isdn_net_phone *phone; - struct pppcallinfo pci; - int i; - memset((char *) &pci,0,sizeof(struct pppcallinfo)); - if(idev) { - mlp = idev->mlp; - strncpy(pci.local_num, mlp->msn, 63); - i = 0; - list_for_each_entry(phone, &mlp->phone[1], list) { - if (i++ == idev->dial) { - strncpy(pci.remote_num,phone->num,63); - break; - } - } - pci.charge_units = idev->charge; - if(idev->outgoing) - pci.calltype = CALLTYPE_OUTGOING; - else - pci.calltype = CALLTYPE_INCOMING; - if(mlp->flags & ISDN_NET_CALLBACK) - pci.calltype |= CALLTYPE_CALLBACK; - } - return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); + r = isdn_ppp_set_compressor(idev, &data); + break; + case PPPIOCGCALLINFO: + { + isdn_net_local *mlp; + struct isdn_net_phone *phone; + struct pppcallinfo pci; + int i; + memset(&pci, 0, sizeof(pci)); + + mlp = idev->mlp; + strncpy(pci.local_num, mlp->msn, 63); + i = 0; + list_for_each_entry(phone, &mlp->phone[1], list) { + if (i++ == idev->dial) { + strncpy(pci.remote_num,phone->num,63); + break; } - default: - break; - } - return 0; -} - -static unsigned int -isdn_ppp_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - struct ippp_struct *is; - - is = file->private_data; - - if (is->debug & 0x2) - printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", - minor(file->f_dentry->d_inode->i_rdev)); - - /* just registers wait_queue hook. This doesn't really wait. */ - poll_wait(file, &is->wq, wait); - - if (!(is->state & IPPP_OPEN)) { - if(is->state == IPPP_CLOSEWAIT) { - mask = POLLHUP; - goto out; } - printk(KERN_DEBUG "isdn_ppp: device not open\n"); - mask = POLLERR; - goto out; + pci.charge_units = idev->charge; + if (idev->outgoing) + pci.calltype = CALLTYPE_OUTGOING; + else + pci.calltype = CALLTYPE_INCOMING; + if (mlp->flags & ISDN_NET_CALLBACK) + pci.calltype |= CALLTYPE_CALLBACK; + r = set_arg(arg, &pci, sizeof(pci)); + break; } - /* we're always ready to send .. */ - mask = POLLOUT | POLLWRNORM; - - /* - * if IPPP_NOBLOCK is set we return even if we have nothing to read - */ - if (!skb_queue_empty(&is->rq) || is->state & IPPP_NOBLOCK) { - is->state &= ~IPPP_NOBLOCK; - mask |= POLLIN | POLLRDNORM; + default: + r = -ENOTTY; + break; } - out: - return mask; + return r; } -/* - * fill up isdn_ppp_read() queue .. - */ +/* --- fops ------------------------------------------------------------- */ + +struct file_operations isdn_ppp_fops = +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ipppd_read, + .write = ipppd_write, + .poll = ipppd_poll, + .ioctl = ipppd_ioctl, + .open = ipppd_open, + .release = ipppd_release, +}; + +/* --- ipppd_queue_read ------------------------------------------------- */ + +/* Queue packets for ipppd to read(). */ static int -isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) +ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len) { struct sk_buff *skb; unsigned char *p; - struct ippp_struct *is; - - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); - return 0; - } - is = ippp_table[slot]; + int retval; - if (!(is->state & IPPP_CONNECT)) { - printk(KERN_DEBUG "ippp: device not activated.\n"); - return 0; + if (is->state != IPPPD_ST_CONNECTED) { + printk(KERN_DEBUG "ippp: device not connected.\n"); + retval = -ENOTCONN; + goto out; } if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) { printk(KERN_WARNING "ippp: Queue is full\n"); - return 0; + retval = -EBUSY; + goto out; } skb = dev_alloc_skb(len + 4); if (!skb) { printk(KERN_WARNING "ippp: Can't alloc buf\n"); - return 0; + retval = -ENOMEM; + goto out; } p = skb_put(skb, 4); p += put_u8(p, PPP_ALLSTATIONS); @@ -655,151 +555,274 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) memcpy(skb_put(skb, len), buf, len); skb_queue_tail(&is->rq, skb); - wake_up_interruptible(&is->wq); + wake_up(&is->wq); - return len; + retval = len; + out: + return retval; } +/* ====================================================================== */ + +/* Prototypes */ +static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, + struct sk_buff *skb, int proto); +static int isdn_ppp_if_get_unit(char *namebuf); + +static void +isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto); + +static void +isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb); + +static struct sk_buff * +isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask); + +static void +isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto); + +/* New CCP stuff */ +static void +isdn_ppp_dev_kick_up(void *priv); + +#ifdef CONFIG_ISDN_MPP +static ippp_bundle * isdn_ppp_bundle_arr = NULL; + +static int isdn_ppp_mp_bundle_array_init(void); +static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to); +static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev, + struct sk_buff *skb); +static void isdn_ppp_mp_cleanup(isdn_net_local *lp ); + +static int isdn_ppp_bundle(struct ipppd *, int unit); +#endif /* CONFIG_ISDN_MPP */ + +char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; + /* - * read() .. non-blocking: ipppd calls it only after select() - * reports, that there is data + * frame log (debug) */ - -static ssize_t -isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off) +void +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) { - struct ippp_struct *is; - struct sk_buff *skb; - int retval; + int cnt, + j, + i; + char buf[80]; - if (off != &file->f_pos) - return -ESPIPE; - - is = file->private_data; + if (len < maxlen) + maxlen = len; - if (!(is->state & IPPP_OPEN)) { - retval = 0; - goto out; - } - skb = skb_dequeue(&is->rq); - if (!skb) { - retval = -EAGAIN; - goto out; - } - if (skb->len > count) { - retval = -EMSGSIZE; - goto out_free; + for (i = 0, cnt = 0; cnt < maxlen; i++) { + for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) + sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); + printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); } - if (copy_to_user(buf, skb->data, skb->len)) { - retval = -EFAULT; - goto out_free; +} + + +static void +isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto) +{ + unsigned char *p; + + if (skb_headroom(skb) < 4) { + isdn_BUG(); + return; } - retval = skb->len; - out_free: - dev_kfree_skb(skb); - out: - return retval; + if ((idev->pppcfg & SC_COMP_PROT) && proto <= 0xff) + put_u8(skb_push(skb, 1), proto); + else + put_u16(skb_push(skb, 2), proto); + + if (idev->pppcfg & SC_COMP_AC) + return; + + p = skb_push(skb, 2); + p += put_u8(p, PPP_ALLSTATIONS); + p += put_u8(p, PPP_UI); } /* - * ipppd wanna write a packet to the card .. non-blocking + * unbind isdn_net_local <=> ippp-device + * note: it can happen, that we hangup/free the master before the slaves + * in this case we bind another lp to the master device */ - -static ssize_t -isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off) +static void +isdn_ppp_unbind(isdn_net_dev *idev) { - isdn_net_dev *idev; - struct ippp_struct *is; - int proto; - unsigned char protobuf[4]; - int retval; + struct ipppd *is = idev->ipppd; + + if (!is) { + isdn_BUG(); + return; + } - if (off != &file->f_pos) - return -ESPIPE; + ipppd_debug(is, ""); - lock_kernel(); + if (is->state != IPPPD_ST_ASSIGNED) + isdn_BUG(); - is = file->private_data; + is->state = IPPPD_ST_OPEN; - if (!(is->state & IPPP_CONNECT)) { - retval = 0; - goto out; - } + /* is->idev will be invalid shortly */ + ippp_ccp_free(idev->ccp); - /* -> push it directly to the lowlevel interface */ + is->idev = NULL; + /* lose the reference we took on isdn_ppp_bind */ + ipppd_put(is); + idev->ipppd = NULL; - idev = is->idev; - if (!idev) - printk(KERN_DEBUG "isdn_ppp_write: idev == NULL\n"); - else { + return; +} + +/* + * bind isdn_net_local <=> ippp-device + */ +int +isdn_ppp_bind(isdn_net_dev *idev) +{ + int unit = 0; + unsigned long flags; + int retval = 0; + struct ipppd *ipppd; + + if (idev->ipppd) { + isdn_BUG(); + return 0; + } + + spin_lock_irqsave(&ipppds_lock, flags); + if (idev->pppbind < 0) { /* device bound to ippp device ? */ + struct list_head *l; + char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ + memset(exclusive, 0, ISDN_MAX_CHANNELS); + /* step through net devices to find exclusive minors */ + list_for_each(l, &isdn_net_devs) { + isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); + if (p->pppbind >= 0 && p->pppbind < ISDN_MAX_CHANNELS) + exclusive[p->pppbind] = 1; + } /* - * Don't reset huptimer for - * LCP packets. (Echo requests). + * search a free device / slot */ - if (copy_from_user(protobuf, buf, 4)) { - retval = -EFAULT; - goto out; + list_for_each_entry(ipppd, &ipppds, ipppds) { + if (!ipppd) + continue; + if (ipppd->state != IPPPD_ST_OPEN) + continue; + if (!exclusive[ipppd->minor]) + break; + goto found; } - proto = PPP_PROTOCOL(protobuf); - if (proto != PPP_LCP) - idev->huptimer = 0; - - if (idev->isdn_slot < 0) { - retval = 0; - goto out; + } else { + list_for_each_entry(ipppd, &ipppds, ipppds) { + if (!ipppd) + continue; + if (ipppd->state != IPPPD_ST_OPEN) + continue; + if (ipppd->minor == idev->pppbind) + goto found; } - if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING) && - isdn_net_online(idev)) { - unsigned short hl; - struct sk_buff *skb; - /* - * we need to reserve enought space in front of - * sk_buff. old call to dev_alloc_skb only reserved - * 16 bytes, now we are looking what the driver want - */ - hl = isdn_slot_hdrlen(idev->isdn_slot); - skb = alloc_skb(hl+count, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); - retval = count; - goto out; - } - skb_reserve(skb, hl); - if (copy_from_user(skb_put(skb, count), buf, count)) - { - kfree_skb(skb); - retval = -EFAULT; - goto out; - } - if (is->debug & 0x40) { - printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,idev->ppp_slot); - } + } - isdn_ppp_send_ccp(idev,idev->mlp,skb); /* keeps CCP/compression states in sync */ + printk(KERN_INFO "isdn_ppp_bind: no ipppd\n"); + retval = -ESRCH; + goto err; - isdn_net_write_super(idev, skb); - } + found: + unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */ + if (unit < 0) { + printk(KERN_INFO "isdn_ppp_bind: illegal interface name %s.\n", idev->name); + retval = -ENODEV; + goto err; } - retval = count; + ipppd->unit = unit; + ipppd->state = IPPPD_ST_ASSIGNED; + ipppd->idev = idev; + /* we hold a reference until isdn_ppp_unbind() */ + idev->ipppd = ipppd_get(ipppd); + spin_unlock_irqrestore(&ipppds_lock, flags); + + idev->pppcfg = 0; /* config flags */ + /* seq no last seen, maybe set to bundle min, when joining? */ + idev->pppseq = -1; + + idev->ccp = ippp_ccp_alloc(); + if (!idev->ccp) { + retval = -ENOMEM; + goto out; + } + idev->ccp->proto = PPP_COMPFRAG; + idev->ccp->priv = idev; + idev->ccp->alloc_skb = isdn_ppp_dev_alloc_skb; + idev->ccp->push_header = isdn_ppp_dev_push_header; + idev->ccp->xmit = isdn_ppp_dev_xmit; + idev->ccp->kick_up = isdn_ppp_dev_kick_up; + +#ifdef CONFIG_ISDN_MPP + retval = isdn_ppp_mp_init(lp, NULL); +#endif /* CONFIG_ISDN_MPP */ out: - unlock_kernel(); + if (retval) { + idev->ipppd->state = IPPPD_ST_OPEN; + ipppd_put(idev->ipppd); + idev->ipppd = NULL; + } + + return retval; + + err: + spin_unlock_irqrestore(&ipppds_lock, flags); return retval; } -struct file_operations isdn_ppp_fops = +/* + * kick the ipppd on the device + * (wakes up daemon after B-channel connect) + */ + +static void +isdn_ppp_connected(isdn_net_dev *idev) { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_ppp_read, - .write = isdn_ppp_write, - .poll = isdn_ppp_poll, - .ioctl = isdn_ppp_ioctl, - .open = isdn_ppp_open, - .release = isdn_ppp_release, -}; + struct ipppd *ipppd = idev->ipppd; + + ipppd_debug(ipppd, ""); + + ipppd->state = IPPPD_ST_CONNECTED; + ipppd->flags |= IPPPD_FL_WAKEUP; + wake_up(&ipppd->wq); +} + +static void +isdn_ppp_disconnected(isdn_net_dev *idev) +{ + struct ipppd *ipppd = idev->ipppd; + + ipppd_debug(ipppd, ""); + + if (idev->pppcfg & SC_ENABLE_IP) + isdn_net_offline(idev); + + if (ipppd->state != IPPPD_ST_CONNECTED) + isdn_BUG(); + + ipppd->state = IPPPD_ST_ASSIGNED; + ipppd->flags |= IPPPD_FL_HUP; + wake_up(&ipppd->wq); + +#ifdef CONFIG_ISDN_MPP + spin_lock(&idev->pb->lock); + if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ + isdn_ppp_mp_cleanup(lp); + + lp->netdev->pb->ref_ct--; + spin_unlock(&lp->netdev->pb->lock); +#endif /* CONFIG_ISDN_MPP */ + +} /* * init memory, structures etc. @@ -808,37 +831,17 @@ struct file_operations isdn_ppp_fops = int isdn_ppp_init(void) { - int i, - j; - #ifdef CONFIG_ISDN_MPP if( isdn_ppp_mp_bundle_array_init() < 0 ) return -ENOMEM; #endif /* CONFIG_ISDN_MPP */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!(ippp_table[i] = (struct ippp_struct *) - kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - for (j = 0; j < i; j++) - kfree(ippp_table[j]); - return -1; - } - memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); - ippp_table[i]->state = 0; - skb_queue_head_init(&ippp_table[i]->rq); - } return 0; } void isdn_ppp_cleanup(void) { - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(ippp_table[i]); - #ifdef CONFIG_ISDN_MPP if (isdn_ppp_bundle_arr) kfree(isdn_ppp_bundle_arr); @@ -850,25 +853,31 @@ isdn_ppp_cleanup(void) * check for address/control field and skip if allowed * retval != 0 -> discard packet silently */ -static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) +static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb) { + u8 val; + if (skb->len < 1) return -1; - if (skb->data[0] == 0xff) { - if (skb->len < 2) - return -1; - - if (skb->data[1] != 0x03) + get_u8(skb->data, &val); + if (val != PPP_ALLSTATIONS) { + /* if AC compression was not negotiated, but no AC present, + discard packet */ + if (idev->pppcfg & SC_REJ_COMP_AC) return -1; - // skip address/control (AC) field - skb_pull(skb, 2); - } else { - if (is->pppcfg & SC_REJ_COMP_AC) - // if AC compression was not negotiated, but used, discard packet - return -1; + return 0; } + if (skb->len < 2) + return -1; + + get_u8(skb->data + 1, &val); + if (val != PPP_UI) + return -1; + + /* skip address/control (AC) field */ + skb_pull(skb, 2); return 0; } @@ -876,84 +885,80 @@ static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) * get the PPP protocol header and pull skb * retval < 0 -> discard packet silently */ -static int isdn_ppp_strip_proto(struct sk_buff *skb) +int isdn_ppp_strip_proto(struct sk_buff *skb) { - int proto; - + u16 proto; + u8 val; + if (skb->len < 1) return -1; - if (skb->data[0] & 0x1) { - // protocol field is compressed - proto = skb->data[0]; + get_u8(skb->data, &val); + if (val & 0x1) { + /* protocol field is compressed */ + proto = val; skb_pull(skb, 1); } else { if (skb->len < 2) return -1; - proto = ((int) skb->data[0] << 8) + skb->data[1]; + get_u16(skb->data, &proto); skb_pull(skb, 2); } return proto; } - /* * handler for incoming packets on a syncPPP interface */ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb) { - struct ippp_struct *is; - int slot; + struct ipppd *is; int proto; - /* - * If encapsulation is syncppp, don't reset - * huptimer on LCP packets. - */ - if (PPP_PROTOCOL(skb->data) != PPP_LCP) - idev->huptimer = 0; - - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return; - } - is = ippp_table[slot]; + is = idev->ipppd; + if (!is) + goto err; if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: is:%p lp:%p slot:%d unit:%d len:%d\n", - is,lp,idev->ppp_slot,is->unit,(int) skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,idev->ppp_slot); + printk(KERN_DEBUG "ippp_receive: is:%p lp:%p unit:%d len:%d\n", + is, lp, is->unit, skb->len); + isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,-1); } - if (isdn_ppp_skip_ac(is, skb) < 0) { - kfree_skb(skb); - return; - } + if (isdn_ppp_skip_ac(idev, skb) < 0) + goto err; + proto = isdn_ppp_strip_proto(skb); - if (proto < 0) { - kfree_skb(skb); - return; - } + if (proto < 0) + goto err; + + /* Don't reset huptimer on LCP packets. */ + if (proto != PPP_LCP) + idev->huptimer = 0; #ifdef CONFIG_ISDN_MPP if (is->compflags & SC_LINK_DECOMP_ON) { skb = isdn_ppp_decompress(skb, is, NULL, &proto); if (!skb) // decompression error - return; + goto put; } if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP if (proto == PPP_MP) { isdn_ppp_mp_receive(lp, idev, skb); - return; + goto put; } } -#endif isdn_ppp_push_higher(lp, idev, skb, proto); + put: +#else + isdn_ppp_push_higher(lp, idev, skb, proto); +#endif + return; + + err: + kfree_skb(skb); } /* @@ -966,28 +971,16 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto) { struct net_device *dev = &lp->dev; - struct ippp_struct *is, *mis; - int slot; - - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", - slot); - goto drop_packet; - } - is = ippp_table[slot]; - - mis = ippp_table[slot]; + struct ipppd *is = idev->ipppd; if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,slot); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, -1); } - if (mis->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, mis, &proto); - if (!skb) // decompression error - return; - } + skb = ippp_ccp_decompress(lp->ccp, skb, &proto); + if (!skb) // decompression error + goto out; + switch (proto) { case PPP_IPX: /* untested */ if (is->debug & 0x20) @@ -1002,19 +995,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, case PPP_COMP: case PPP_COMPFRAG: printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop_packet; + goto drop; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if (idev->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); - goto drop_packet; - } - if (slhc_remember(ippp_table[idev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { + if (slhc_remember(lp->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - goto drop_packet; + goto drop; } skb->protocol = htons(ETH_P_IP); break; @@ -1029,82 +1017,55 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); skb = skb_old; - goto drop_packet; + goto drop; } skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); - if (idev->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); - goto drop_packet; - } - pkt_len = slhc_uncompress(ippp_table[idev->ppp_slot]->slcomp, + pkt_len = slhc_uncompress(lp->slcomp, skb->data, skb_old->len); kfree_skb(skb_old); if (pkt_len < 0) - goto drop_packet; + goto drop; skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); } break; #endif - case PPP_CCP: case PPP_CCPFRAG: - isdn_ppp_receive_ccp(idev,lp,skb,proto); + ippp_ccp_receive_ccp(idev->ccp, skb); + goto ccp; + case PPP_CCP: + ippp_ccp_receive_ccp(lp->ccp, skb); + ccp: /* Dont pop up ResetReq/Ack stuff to the daemon any longer - the job is done already */ if(skb->data[0] == CCP_RESETREQ || skb->data[0] == CCP_RESETACK) - break; + goto free; /* fall through */ default: - isdn_ppp_fill_rq(skb->data, skb->len, proto, idev->ppp_slot); /* push data to pppd device */ - kfree_skb(skb); - return; + // FIXME use skb directly + ipppd_queue_read(is, proto, skb->data, skb->len); + goto free; } /* Reset hangup-timer */ idev->huptimer = 0; skb->dev = dev; - skb->mac.raw = skb->data; netif_rx(skb); /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ + out: return; - drop_packet: + drop: lp->stats.rx_dropped++; + free: kfree_skb(skb); } /* - * isdn_ppp_skb_push .. - * checks whether we have enough space at the beginning of the skb - * and allocs a new SKB if necessary - */ -static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len) -{ - struct sk_buff *skb = *skb_p; - - if(skb_headroom(skb) < len) { - struct sk_buff *nskb = skb_realloc_headroom(skb, len); - - if (!nskb) { - printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); - dev_kfree_skb(skb); - return NULL; - } - printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); - dev_kfree_skb(skb); - *skb_p = nskb; - return skb_push(nskb, len); - } - return skb_push(skb,len); -} - - -/* * send ppp frame .. we expect a PIDCOMPressable proto -- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) * @@ -1118,30 +1079,13 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_local *mlp = ndev->priv; isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online); unsigned int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt,*ipts; - int slot; + struct ipppd *ipppd; ndev->trans_start = jiffies; if (list_empty(&mlp->online)) return isdn_net_autodial(skb, ndev); - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return 0; - } - ipts = ippp_table[slot]; - - if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - if (ipts->debug & 0x1) - printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); - netif_stop_queue(ndev); - return 1; - } - switch (ntohs(skb->protocol)) { case ETH_P_IP: proto = PPP_IP; @@ -1153,42 +1097,32 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", skb->protocol); dev_kfree_skb(skb); - return 0; + goto out; } - idev = isdn_net_get_locked_dev(mlp); + idev = isdn_net_get_xmit_dev(mlp); if (!idev) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - netif_stop_queue(ndev); - return 1; + printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); + goto stop; } - /* we have our lp locked from now on */ - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return 0; + if (!(idev->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + isdn_BUG(); + goto stop; } - ipt = ippp_table[slot]; + ipppd = idev->ipppd; idev->huptimer = 0; /* * after this line .. requeueing in the device queue is no longer allowed!!! */ - /* Pull off the fake header we stuck on earlier to keep - * the fragmentation code happy. - */ - skb_pull(skb,IPPP_MAX_HEADER); - - if (ipt->debug & 0x4) + if (ipppd->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); - if (ipts->debug & 0x40) - isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,idev->ppp_slot); + if (ipppd->debug & 0x40) + isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipppd->unit, -1); #ifdef CONFIG_ISDN_PPP_VJ - if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ + if (proto == PPP_IP && idev->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ struct sk_buff *new_skb; unsigned short hl; /* @@ -1213,8 +1147,8 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb_put(new_skb, skb->len); buf = skb->data; - pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, - &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); + pktlen = slhc_compress(mlp->slcomp, skb->data, skb->len, new_skb->data, + &buf, !(idev->pppcfg & SC_NO_TCP_CCID)); if (buf != skb->data) { if (new_skb->data != buf) @@ -1241,17 +1175,9 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* * normal (single link) or bundle compression */ - if(ipts->compflags & SC_COMP_ON) { - /* We send compressed only if both down- und upstream - compression is negotiated, that means, CCP is up */ - if(ipts->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); - } else { - printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); - } - } + skb = ippp_ccp_compress(mlp->ccp, skb, &proto); - if (ipt->debug & 0x24) + if (ipppd->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); #ifdef CONFIG_ISDN_MPP @@ -1281,45 +1207,29 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) } #endif +#if 0 /* * 'link in bundle' compression ... */ - if(ipt->compflags & SC_LINK_COMP_ON) + if (ipt->compflags & SC_LINK_COMP_ON) skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); +#endif - if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { - unsigned char *data = isdn_ppp_skb_push(&skb,1); - if(!data) - goto unlock; - data[0] = proto & 0xff; - } - else { - unsigned char *data = isdn_ppp_skb_push(&skb,2); - if(!data) - goto unlock; - data[0] = (proto >> 8) & 0xff; - data[1] = proto & 0xff; - } - if(!(ipt->pppcfg & SC_COMP_AC)) { - unsigned char *data = isdn_ppp_skb_push(&skb,2); - if(!data) - goto unlock; - data[0] = 0xff; /* All Stations */ - data[1] = 0x03; /* Unnumbered information */ - } - - /* tx-stats are now updated via BSENT-callback */ + isdn_ppp_push_header(idev, skb, proto); - if (ipts->debug & 0x40) { + if (ipppd->debug & 0x40) { printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,idev->ppp_slot); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipppd->unit, -1); } isdn_net_writebuf_skb(idev, skb); - unlock: - spin_unlock_bh(&idev->xmit_lock); + out: return 0; + + stop: + netif_stop_queue(ndev); + return 1; } #ifdef CONFIG_ISDN_MPP @@ -1372,7 +1282,7 @@ static ippp_bundle * isdn_ppp_mp_bundle_alloc(void) static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) { isdn_net_dev *idev = lp->netdev; - struct ippp_struct * is; + struct ipppd * is; if (idev->ppp_slot < 0) { printk(KERN_ERR "%s: >ppp_slot(%d) out of range\n", @@ -1396,7 +1306,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) } lp->netdev->pb->ref_ct++; - is->last_link_seqno = 0; + is->pppseq = 0; return 0; } @@ -1413,7 +1323,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, struct sk_buff *skb) { isdn_net_dev *idev = lp->netdev; - struct ippp_struct *is; + struct ipppd *is; isdn_net_dev *qdev; ippp_bundle * mp; isdn_mppp_stats * stats; @@ -1442,7 +1352,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, isdn_ppp_mp_print_recv_pkt(slot, skb); newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, - skb, is->last_link_seqno); + skb, is->pppseq); /* if this packet seq # is less than last already processed one, @@ -1460,14 +1370,14 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, } /* find the minimum received sequence number over all links */ - is->last_link_seqno = minseq = newseq; + is->pppseq = minseq = newseq; list_for_each_entry(qdev, &lp->online, online) { slot = qdev->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", __FUNCTION__ ,slot); } else { - u32 lls = ippp_table[slot]->last_link_seqno; + u32 lls = ippp_table[slot]->pppseq; if (MP_LT(lls, minseq)) minseq = lls; } @@ -1754,7 +1664,7 @@ static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ) } static int -isdn_ppp_bundle(struct ippp_struct *is, int unit) +isdn_ppp_bundle(struct ipppd *is, int unit) { char ifn[IFNAMSIZ + 1]; isdn_net_dev *p; @@ -1804,11 +1714,11 @@ out: */ static int -isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) +isdn_ppp_dev_ioctl_stats(struct ifreq *ifr, struct net_device *dev) { - struct ppp_stats *res, - t; + struct ppp_stats *res, t; isdn_net_local *lp = (isdn_net_local *) dev->priv; + struct slcompress *slcomp; int err; res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; @@ -1828,8 +1738,8 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) t.p.ppp_obytes = lp->stats.tx_bytes; t.p.ppp_oerrors = lp->stats.tx_errors; #ifdef CONFIG_ISDN_PPP_VJ - if (slot >= 0 && ippp_table[slot]->slcomp) { - struct slcompress *slcomp = ippp_table[slot]->slcomp; + slcomp = lp->slcomp; + if (slcomp) { t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; t.vj.vjs_compressed = slcomp->sls_o_compressed; t.vj.vjs_searches = slcomp->sls_o_searches; @@ -1858,17 +1768,18 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; switch (cmd) { - case SIOCGPPPVER: - r = (char *) ifr->ifr_ifru.ifru_data; - len = strlen(PPP_VERSION) + 1; - if(copy_to_user(r, PPP_VERSION, len)) error = -EFAULT; - break; - case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats(0, ifr, dev); - break; - default: - error = -EINVAL; - break; + case SIOCGPPPVER: + r = (char *) ifr->ifr_ifru.ifru_data; + len = strlen(PPP_VERSION) + 1; + if (copy_to_user(r, PPP_VERSION, len)) + error = -EFAULT; + break; + case SIOCGPPPSTATS: + error = isdn_ppp_dev_ioctl_stats(ifr, dev); + break; + default: + error = -EINVAL; + break; } return error; } @@ -1962,868 +1873,167 @@ isdn_ppp_hangup_slave(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is) +static void isdn_ppp_dev_kick_up(void *priv) { - isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->idev->ppp_slot); + isdn_net_dev *idev = priv; + + ipppd_queue_read(idev->ipppd, PPP_COMPFRAG, NULL, 0); } -/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, - but absolutely nontrivial. The most abstruse problem we are facing is - that the generation, reception and all the handling of timeouts and - resends including proper request id management should be entirely left - to the (de)compressor, but indeed is not covered by the current API to - the (de)compressor. The API is a prototype version from PPP where only - some (de)compressors have yet been implemented and all of them are - rather simple in their reset handling. Especially, their is only one - outstanding ResetAck at a time with all of them and ResetReq/-Acks do - not have parameters. For this very special case it was sufficient to - just return an error code from the decompressor and have a single - reset() entry to communicate all the necessary information between - the framework and the (de)compressor. Bad enough, LZS is different - (and any other compressor may be different, too). It has multiple - histories (eventually) and needs to Reset each of them independently - and thus uses multiple outstanding Acks and history numbers as an - additional parameter to Reqs/Acks. - All that makes it harder to port the reset state engine into the - kernel because it is not just the same simple one as in (i)pppd but - it must be able to pass additional parameters and have multiple out- - standing Acks. We are trying to achieve the impossible by handling - reset transactions independent by their id. The id MUST change when - the data portion changes, thus any (de)compressor who uses more than - one resettable state must provide and recognize individual ids for - each individual reset transaction. The framework itself does _only_ - differentiate them by id, because it has no other semantics like the - (de)compressor might. - This looks like a major redesign of the interface would be nice, - but I don't have an idea how to do it better. */ - -/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is - getting that lengthy because there is no simple "send-this-frame-out" - function above but every wrapper does a bit different. Hope I guess - correct in this hack... */ - -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len) +static void isdn_ppp_lp_kick_up(void *priv) { - struct sk_buff *skb; - unsigned char *p; - int hl; - int cnt = 0; - isdn_net_dev *idev = is->idev; - - /* Alloc large enough skb */ - hl = isdn_slot_hdrlen(idev->isdn_slot); - skb = alloc_skb(len + hl + 16,GFP_ATOMIC); - if(!skb) { - printk(KERN_WARNING - "ippp: CCP cannot send reset - out of memory\n"); - return; - } - skb_reserve(skb, hl); - - /* We may need to stuff an address and control field first */ - if(!(is->pppcfg & SC_COMP_AC)) { - p = skb_put(skb, 2); - *p++ = 0xff; - *p++ = 0x03; - } + isdn_net_local *lp = priv; + isdn_net_dev *idev; - /* Stuff proto, code, id and length */ - p = skb_put(skb, 6); - *p++ = (proto >> 8); - *p++ = (proto & 0xff); - *p++ = code; - *p++ = id; - cnt = 4 + len; - *p++ = (cnt >> 8); - *p++ = (cnt & 0xff); - - /* Now stuff remaining bytes */ - if(len) { - p = skb_put(skb, len); - memcpy(p, data, len); + if (list_empty(&lp->online)) { + isdn_BUG(); + return; } - - /* skb is now ready for xmit */ - printk(KERN_DEBUG "Sending CCP Frame:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot); - - isdn_net_write_super(idev, skb); + idev = list_entry(lp->online.next, isdn_net_dev, online); + ipppd_queue_read(idev->ipppd, PPP_COMP, NULL, 0); } -/* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) -{ - struct ippp_ccp_reset *r; - r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); - if(!r) { - printk(KERN_ERR "ippp_ccp: failed to allocate reset data" - " structure - no mem\n"); - return NULL; - } - memset(r, 0, sizeof(struct ippp_ccp_reset)); - printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); - is->reset = r; - return r; -} +/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */ -/* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) +static struct sk_buff * +__isdn_ppp_alloc_skb(isdn_net_dev *idev, int len, unsigned int gfp_mask) { - unsigned int id; + int hl = IPPP_MAX_HEADER + isdn_slot_hdrlen(idev->isdn_slot); + struct sk_buff *skb; - printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", - is->reset); - for(id = 0; id < 256; id++) { - if(is->reset->rs[id]) { - isdn_ppp_ccp_reset_free_state(is, (unsigned char)id); - } - } - kfree(is->reset); - is->reset = NULL; -} + skb = alloc_skb(hl + len, gfp_mask); + if (!skb) + return NULL; -/* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - if(is->reset->rs[id]) { - printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); - rs = is->reset->rs[id]; - /* Make sure the kernel will not call back later */ - if(rs->ta) - del_timer(&rs->timer); - is->reset->rs[id] = NULL; - kfree(rs); - } else { - printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); - } + skb_reserve(skb, hl); + return skb; } -/* The timer callback function which is called when a ResetReq has timed out, - aka has never been answered by a ResetAck */ -static void isdn_ppp_ccp_timer_callback(unsigned long closure) +static struct sk_buff * +isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask) { - struct ippp_ccp_reset_state *rs = - (struct ippp_ccp_reset_state *)closure; + isdn_net_dev *idev = priv; - if(!rs) { - printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); - return; - } - if(rs->ta && rs->state == CCPResetSentReq) { - /* We are correct here */ - if(!rs->expra) { - /* Hmm, there is no Ack really expected. We can clean - up the state now, it will be reallocated if the - decompressor insists on another reset */ - rs->ta = 0; - isdn_ppp_ccp_reset_free_state(rs->is, rs->id); - return; - } - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); - /* Push it again */ - isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Restart timer */ - rs->timer.expires = jiffies + HZ*5; - add_timer(&rs->timer); - } else { - printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", - rs->state); - } + return __isdn_ppp_alloc_skb(idev, len, gfp_mask); } -/* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id) +static struct sk_buff * +isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask) { - struct ippp_ccp_reset_state *rs; - if(is->reset->rs[id]) { - printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", - id); + isdn_net_local *lp = priv; + isdn_net_dev *idev; + + if (list_empty(&lp->online)) { + isdn_BUG(); return NULL; - } else { - rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); - if(!rs) - return NULL; - memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); - rs->state = CCPResetIdle; - rs->is = is; - rs->id = id; - rs->timer.data = (unsigned long)rs; - rs->timer.function = isdn_ppp_ccp_timer_callback; - is->reset->rs[id] = rs; } - return rs; + idev = list_entry(lp->online.next, isdn_net_dev, online); + return __isdn_ppp_alloc_skb(idev, len, gfp_mask); } - -/* A decompressor wants a reset with a set of parameters - do what is - necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp) +static void +isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto) { - struct ippp_ccp_reset_state *rs; - - if(rp->valid) { - /* The decompressor defines parameters by itself */ - if(rp->rsend) { - /* And he wants us to send a request */ - if(!(rp->idval)) { - printk(KERN_ERR "ippp_ccp: decompressor must" - " specify reset id\n"); - return; - } - if(is->reset->rs[rp->id]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[rp->id]; - if(rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - /* Ok, this is a new transaction */ - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", rp->id); - rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); - if(!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - rs->expra = rp->expra; - if(rp->dtval) { - rs->dlen = rp->dlen; - memcpy(rs->data, rp->data, rp->dlen); - } - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, - CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Start the timer */ - rs->timer.expires = jiffies + 5*HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } else { - printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); - } - } else { - /* The reset params are invalid. The decompressor does not - care about them, so we just send the minimal requests - and increase ids only when an Ack is received for a - given id */ - if(is->reset->rs[is->reset->lastid]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[is->reset->lastid]; - if(rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", is->reset->lastid); - rs = isdn_ppp_ccp_reset_alloc_state(is, - is->reset->lastid); - if(!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - /* We always expect an Ack if the decompressor doesnt - know better */ - rs->expra = 1; - rs->dlen = 0; - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, - rs->id, NULL, 0); - /* Start the timer */ - rs->timer.expires = jiffies + 5*HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } -} + isdn_net_dev *idev = priv; -/* An Ack was received for this id. This means we stop the timer and clean - up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs = is->reset->rs[id]; - - if(rs) { - if(rs->ta && rs->state == CCPResetSentReq) { - /* Great, we are correct */ - if(!rs->expra) - printk(KERN_DEBUG "ippp_ccp: ResetAck received" - " for id %d but not expected\n", id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received out of" - "sync for id %d\n", id); - } - if(rs->ta) { - rs->ta = 0; - del_timer(&rs->timer); - } - isdn_ppp_ccp_reset_free_state(is, id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" - " %d\n", id); - } - /* Make sure the simple reset stuff uses a new id next time */ - is->reset->lastid++; + isdn_ppp_push_header(idev, skb, proto); } -/* - * decompress packet - * - * if master = 0, we're trying to uncompress an per-link compressed packet, - * as opposed to an compressed reconstructed-from-MPPP packet. - * proto is updated to protocol field of uncompressed packet. - * - * retval: decompressed packet, - * same packet if uncompressed, - * NULL if decompression error - */ - -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, - int *proto) +static void +isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto) { - void *stat = NULL; - struct isdn_ppp_compressor *ipc = NULL; - struct sk_buff *skb_out; - int len; - struct ippp_struct *ri; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - if(!master) { - // per-link decompression - stat = is->link_decomp_stat; - ipc = is->link_decompressor; - ri = is; - } else { - stat = master->decomp_stat; - ipc = master->decompressor; - ri = master; - } - - if (!ipc) { - // no decompressor -> we can't decompress. - printk(KERN_DEBUG "ippp: no decompressor defined!\n"); - return skb; - } - if (!stat) // if we have a compressor, stat has been set as well - BUG(); - - if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) { - // compressed packets are compressed by their protocol type + isdn_net_local *lp = priv; + isdn_net_dev *idev; - // Set up reset params for the decompressor - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - - skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); - len = ipc->decompress(stat, skb, skb_out, &rsparm); - kfree_skb(skb); - if (len <= 0) { - switch(len) { - case DECOMP_ERROR: - printk(KERN_INFO "ippp: decomp wants reset %s params\n", - rsparm.valid ? "with" : "without"); - - isdn_ppp_ccp_reset_trans(ri, &rsparm); - break; - case DECOMP_FATALERROR: - ri->pppcfg |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - isdn_ppp_ccp_kickup(ri); - break; - } - kfree_skb(skb_out); - return NULL; - } - *proto = isdn_ppp_strip_proto(skb_out); - if (*proto < 0) { - kfree_skb(skb_out); - return NULL; - } - return skb_out; - } else { - // uncompressed packets are fed through the decompressor to - // update the decompressor state - ipc->incomp(stat, skb, *proto); - return skb; + if (list_empty(&lp->online)) { + isdn_BUG(); + return; } + idev = list_entry(lp->online.next, isdn_net_dev, online); + isdn_ppp_push_header(idev, skb, proto); } -/* - * compress a frame - * type=0: normal/bundle compression - * =1: link compression - * returns original skb if we haven't compressed the frame - * and a new skb pointer if we've done it - */ -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, - struct ippp_struct *is,struct ippp_struct *master,int type) +static void +isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb) { - int ret; - int new_proto; - struct isdn_ppp_compressor *compressor; - void *stat; - struct sk_buff *skb_out; - - /* we do not compress control protocols */ - if(*proto < 0 || *proto > 0x3fff) { - return skb_in; - } - - if(type) { /* type=1 => Link compression */ - return skb_in; - } - else { - if(!master) { - compressor = is->compressor; - stat = is->comp_stat; - } - else { - compressor = master->compressor; - stat = master->comp_stat; - } - new_proto = PPP_COMP; - } - - if(!compressor) { - printk(KERN_ERR "isdn_ppp: No compressor set!\n"); - return skb_in; - } - if(!stat) { - printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); - return skb_in; - } + isdn_net_dev *idev = priv; - /* Allow for at least 150 % expansion (for now) */ - skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 + - skb_headroom(skb_in), GFP_ATOMIC); - if(!skb_out) - return skb_in; - skb_reserve(skb_out, skb_headroom(skb_in)); - - ret = (compressor->compress)(stat,skb_in,skb_out,*proto); - if(!ret) { - dev_kfree_skb(skb_out); - return skb_in; - } - - dev_kfree_skb(skb_in); - *proto = new_proto; - return skb_out; + isdn_net_write_super(idev, skb); } -/* - * we received a CCP frame .. - * not a clean solution, but we MUST handle a few cases in the kernel - */ -static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, - struct sk_buff *skb,int proto) +static void +isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb) { - struct ippp_struct *is; - struct ippp_struct *mis; - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + isdn_net_local *lp = priv; + isdn_net_dev *idev; - printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", - idev->ppp_slot); - if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); + if (list_empty(&lp->online)) { + isdn_BUG(); return; } - is = ippp_table[idev->ppp_slot]; - isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot); - - mis = is; - - switch(skb->data[0]) { - case CCP_CONFREQ: - if(is->debug & 0x10) - printk(KERN_DEBUG "Disable compression here!\n"); - if(proto == PPP_CCP) - mis->compflags &= ~SC_COMP_ON; - else - is->compflags &= ~SC_LINK_COMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if(is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if(proto == PPP_CCP) - mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we RECEIVE an ackowledge we enable the decompressor */ - if(is->debug & 0x10) - printk(KERN_DEBUG "Enable decompression here!\n"); - if(proto == PPP_CCP) { - if (!mis->decompressor) - break; - mis->compflags |= SC_DECOMP_ON; - } else { - if (!is->decompressor) - break; - is->compflags |= SC_LINK_DECOMP_ON; - } - break; - - case CCP_RESETACK: - printk(KERN_DEBUG "Received ResetAck from peer\n"); - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - - if(proto == PPP_CCP) { - /* If a reset Ack was outstanding for this id, then - clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); - if(mis->decompressor && mis->decomp_stat) - mis->decompressor-> - reset(mis->decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: This is not easy to decide here */ - mis->compflags &= ~SC_DECOMP_DISCARD; - } - else { - isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); - if(is->link_decompressor && is->link_decomp_stat) - is->link_decompressor-> - reset(is->link_decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: neither here */ - is->compflags &= ~SC_LINK_DECOMP_DISCARD; - } - break; - - case CCP_RESETREQ: - printk(KERN_DEBUG "Received ResetReq from peer\n"); - /* Receiving a ResetReq means we must reset our compressor */ - /* Set up reset params for the reset entry */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* Isolate data length */ - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - if(proto == PPP_CCP) { - if(mis->compressor && mis->comp_stat) - mis->compressor-> - reset(mis->comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - else { - if(is->link_compressor && is->link_comp_stat) - is->link_compressor-> - reset(is->link_comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - /* Ack the Req as specified by rsparm */ - if(rsparm.valid) { - /* Compressor reset handler decided how to answer */ - if(rsparm.rsend) { - /* We should send a Frame */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - rsparm.idval ? rsparm.id - : skb->data[1], - rsparm.dtval ? - rsparm.data : NULL, - rsparm.dtval ? - rsparm.dlen : 0); - } else { - printk(KERN_DEBUG "ResetAck suppressed\n"); - } - } else { - /* We answer with a straight reflected Ack */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - skb->data[1], - len ? &skb->data[4] : NULL, - len); - } - break; - } + idev = list_entry(lp->online.next, isdn_net_dev, online); + isdn_net_write_super(idev, skb); } - -/* - * Daemon sends a CCP frame ... - */ - -/* TODO: Clean this up with new Reset semantics */ - -/* I believe the CCP handling as-is is done wrong. Compressed frames - * should only be sent/received after CCP reaches UP state, which means - * both sides have sent CONF_ACK. Currently, we handle both directions - * independently, which means we may accept compressed frames too early - * (supposedly not a problem), but may also mean we send compressed frames - * too early, which may turn out to be a problem. - * This part of state machine should actually be handled by (i)pppd, but - * that's too big of a change now. --kai - */ - -/* Actually, we might turn this into an advantage: deal with the RFC in - * the old tradition of beeing generous on what we accept, but beeing - * strict on what we send. Thus we should just - * - accept compressed frames as soon as decompression is negotiated - * - send compressed frames only when decomp *and* comp are negotiated - * - drop rx compressed frames if we cannot decomp (instead of pushing them - * up to ipppd) - * and I tried to modify this file according to that. --abp - */ - -static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb) +static int +isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data) { - struct ippp_struct *mis,*is; - int proto, slot = idev->ppp_slot; - unsigned char *data; - - if(!skb || skb->len < 3) - return; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__ , slot); - return; - } - is = ippp_table[slot]; - /* Daemon may send with or without address and control field comp */ - data = skb->data; - if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { - data += 2; - if(skb->len < 5) - return; - } - - proto = ((int)data[0]<<8)+data[1]; - if(proto != PPP_CCP && proto != PPP_CCPFRAG) - return; + struct ippp_ccp *ccp; - printk(KERN_DEBUG "Received CCP frame from daemon:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot); + if (data->flags & IPPP_COMP_FLAG_LINK) + ccp = idev->ccp; + else + ccp = idev->mlp->ccp; - mis = is; - if (mis != is) - printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); - - switch(data[2]) { - case CCP_CONFREQ: - if(is->debug & 0x10) - printk(KERN_DEBUG "Disable decompression here!\n"); - if(proto == PPP_CCP) - is->compflags &= ~SC_DECOMP_ON; - else - is->compflags &= ~SC_LINK_DECOMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if(is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if(proto == PPP_CCP) - is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we SEND an ackowledge we can/must enable the compressor */ - if(is->debug & 0x10) - printk(KERN_DEBUG "Enable compression here!\n"); - if(proto == PPP_CCP) { - if (!is->compressor) - break; - is->compflags |= SC_COMP_ON; - } else { - if (!is->compressor) - break; - is->compflags |= SC_LINK_COMP_ON; - } - break; - case CCP_RESETACK: - /* If we send a ACK we should reset our compressor */ - if(is->debug & 0x10) - printk(KERN_DEBUG "Reset decompression state here!\n"); - printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - if(proto == PPP_CCP) { - /* link to master? */ - if(is->compressor && is->comp_stat) - is->compressor->reset(is->comp_stat, 0, 0, - NULL, 0, NULL); - is->compflags &= ~SC_COMP_DISCARD; - } - else { - if(is->link_compressor && is->link_comp_stat) - is->link_compressor->reset(is->link_comp_stat, - 0, 0, NULL, 0, NULL); - is->compflags &= ~SC_LINK_COMP_DISCARD; - } - break; - case CCP_RESETREQ: - /* Just let it pass by */ - printk(KERN_DEBUG "ResetReq from daemon passed by\n"); - break; - } + return ippp_ccp_set_compressor(ccp, idev->ipppd->unit, data); } -int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) -{ - ipc->next = ipc_head; - ipc->prev = NULL; - if(ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; - return 0; -} +// ISDN_NET_ENCAP_SYNCPPP +// ====================================================================== -int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) +static int +isdn_ppp_open(isdn_net_local *lp) { - if(ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if(ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; - return 0; -} + lp->mpppcfg = 0; /* mppp configuration */ + lp->mp_seqno = 0; /* MP sequence number */ -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) -{ - struct isdn_ppp_compressor *ipc = ipc_head; - int ret; - void *stat; - int num = data->num; - - if(is->debug & 0x10) - printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, - (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); - - /* If is has no valid reset state vector, we cannot allocate a - decompressor. The decompressor would cause reset transactions - sooner or later, and they need that vector. */ - - if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) { - printk(KERN_ERR "ippp_ccp: no reset data structure - can't" - " allow decompression.\n"); +#ifdef CONFIG_ISDN_PPP_VJ + lp->slcomp = slhc_init(16, 16); +#endif + lp->ccp = ippp_ccp_alloc(); + if (!lp->ccp) return -ENOMEM; - } + lp->ccp->proto = PPP_COMP; + lp->ccp->priv = lp; + lp->ccp->alloc_skb = isdn_ppp_lp_alloc_skb; + lp->ccp->push_header = isdn_ppp_lp_push_header; + lp->ccp->xmit = isdn_ppp_lp_xmit; + lp->ccp->kick_up = isdn_ppp_lp_kick_up; - while(ipc) { - if(ipc->num == num) { - stat = ipc->alloc(data); - if(stat) { - ret = ipc->init(stat,data,is->unit,0); - if(!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - stat = NULL; - break; - } - } - else { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } - - if(data->flags & IPPP_COMP_FLAG_XMIT) { - if(data->flags & IPPP_COMP_FLAG_LINK) { - if(is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - is->link_comp_stat = stat; - is->link_compressor = ipc; - } - else { - if(is->comp_stat) - is->compressor->free(is->comp_stat); - is->comp_stat = stat; - is->compressor = ipc; - } - } - else { - if(data->flags & IPPP_COMP_FLAG_LINK) { - if(is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - is->link_decomp_stat = stat; - is->link_decompressor = ipc; - } - else { - if(is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->decomp_stat = stat; - is->decompressor = ipc; - } - } - return 0; - } - ipc = ipc->next; - } - return -EINVAL; + return 0; } -// ISDN_NET_ENCAP_SYNCPPP -// ====================================================================== - -static int -isdn_ppp_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned plen) +static void +isdn_ppp_close(isdn_net_local *lp) { - skb_push(skb, IPPP_MAX_HEADER); - - return IPPP_MAX_HEADER; +#ifdef CONFIG_ISDN_PPP_VJ + slhc_free(lp->slcomp); + lp->slcomp = NULL; +#endif + ippp_ccp_free(lp->ccp); + lp->ccp = NULL; } struct isdn_netif_ops isdn_ppp_ops = { .hard_start_xmit = isdn_ppp_start_xmit, - .hard_header = isdn_ppp_header, .do_ioctl = isdn_ppp_dev_ioctl, .flags = IFF_NOARP | IFF_POINTOPOINT, .type = ARPHRD_PPP, .receive = isdn_ppp_receive, - .connected = isdn_ppp_wakeup_daemon, + .connected = isdn_ppp_connected, + .disconnected = isdn_ppp_disconnected, .bind = isdn_ppp_bind, - .unbind = isdn_ppp_free, - + .unbind = isdn_ppp_unbind, + .open = isdn_ppp_open, + .close = isdn_ppp_close, }; diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h index af6f50fd11db..20745b31ef1d 100644 --- a/drivers/isdn/i4l/isdn_ppp.h +++ b/drivers/isdn/i4l/isdn_ppp.h @@ -15,17 +15,15 @@ extern struct file_operations isdn_ppp_fops; extern struct isdn_netif_ops isdn_ppp_ops; -extern int isdn_ppp_init(void); -extern void isdn_ppp_cleanup(void); -extern int isdn_ppp_dial_slave(char *); -extern int isdn_ppp_hangup_slave(char *); +int isdn_ppp_init(void); +void isdn_ppp_cleanup(void); +int isdn_ppp_dial_slave(char *); +int isdn_ppp_hangup_slave(char *); -#define IPPP_OPEN 0x01 -#define IPPP_CONNECT 0x02 -#define IPPP_CLOSEWAIT 0x04 -#define IPPP_NOBLOCK 0x08 -#define IPPP_ASSIGNED 0x10 +void +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, + int unit, int slot); +int +isdn_ppp_strip_proto(struct sk_buff *skb); #define IPPP_MAX_HEADER 10 - - diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c new file mode 100644 index 000000000000..ab573e7a6376 --- /dev/null +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -0,0 +1,601 @@ + +#include "isdn_ppp_ccp.h" +#include "isdn_common.h" +#include "isdn_net.h" +#include "isdn_ppp.h" +#include <linux/ppp-comp.h> + +/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, + but absolutely nontrivial. The most abstruse problem we are facing is + that the generation, reception and all the handling of timeouts and + resends including proper request id management should be entirely left + to the (de)compressor, but indeed is not covered by the current API to + the (de)compressor. The API is a prototype version from PPP where only + some (de)compressors have yet been implemented and all of them are + rather simple in their reset handling. Especially, their is only one + outstanding ResetAck at a time with all of them and ResetReq/-Acks do + not have parameters. For this very special case it was sufficient to + just return an error code from the decompressor and have a single + reset() entry to communicate all the necessary information between + the framework and the (de)compressor. Bad enough, LZS is different + (and any other compressor may be different, too). It has multiple + histories (eventually) and needs to Reset each of them independently + and thus uses multiple outstanding Acks and history numbers as an + additional parameter to Reqs/Acks. + All that makes it harder to port the reset state engine into the + kernel because it is not just the same simple one as in (i)pppd but + it must be able to pass additional parameters and have multiple out- + standing Acks. We are trying to achieve the impossible by handling + reset transactions independent by their id. The id MUST change when + the data portion changes, thus any (de)compressor who uses more than + one resettable state must provide and recognize individual ids for + each individual reset transaction. The framework itself does _only_ + differentiate them by id, because it has no other semantics like the + (de)compressor might. + This looks like a major redesign of the interface would be nice, + but I don't have an idea how to do it better. */ + +/* ====================================================================== */ + +/* Free a given state and clear everything up for later reallocation */ +static void +ippp_ccp_reset_free_state(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; + + if (!rs) + return; + + if (rs->ta) // FIXME? + del_timer_sync(&rs->timer); + + kfree(rs); + ccp->reset->rs[id] = NULL; +} + +static void +do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id, + unsigned char *data, int len) +{ + struct sk_buff *skb; + unsigned char *p; + u16 proto = ccp->proto == PPP_COMP ? PPP_CCP : PPP_CCPFRAG; + + skb = ccp->alloc_skb(ccp->priv, 4 + len, GFP_ATOMIC); + ccp->push_header(ccp->priv, skb, proto); + + p = skb_put(skb, 4); + p += put_u8 (p, code); + p += put_u8 (p, id); + p += put_u16(p, len + 4); + + if (len) + memcpy(skb_put(skb, len), data, len); + + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1); + + ccp->xmit(ccp->priv, skb); +} + +/* The timer callback function which is called when a ResetReq has timed out, + aka has never been answered by a ResetAck */ +static void +isdn_ppp_ccp_timer_callback(unsigned long data) +{ + struct ippp_ccp_reset_state *rs = (struct ippp_ccp_reset_state *) data; + + if (!rs->ta) { + isdn_BUG(); + return; + } + if (rs->state != CCPResetSentReq) { + printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", + rs->state); + rs->ta = 0; + return; + } + /* We are correct here */ + if (!rs->expra) { + /* Hmm, there is no Ack really expected. We can clean + up the state now, it will be reallocated if the + decompressor insists on another reset */ + rs->ta = 0; + ippp_ccp_reset_free_state(rs->ccp, rs->id); + return; + } + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); + /* Push it again */ + do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); + + mod_timer(&rs->timer, jiffies + 5 * HZ); +} + +/* Allocate a new reset transaction state */ +static struct ippp_ccp_reset_state * +ippp_ccp_reset_alloc_state(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->ccp = ccp; + rs->id = id; + init_timer(&rs->timer); + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + + ccp->reset->rs[id] = rs; + return rs; +} + +/* A decompressor wants a reset with a set of parameters - do what is + necessary to fulfill it */ +static void +ippp_ccp_reset_xmit(struct ippp_ccp *ccp, + struct isdn_ppp_resetparams *rp) +{ + struct ippp_ccp_reset_state *rs; + int id; + + if (rp->valid) { + /* The decompressor defines parameters by itself */ + if (!rp->rsend) + return; + + /* And it wants us to send a request */ + if (!rp->idval) { + isdn_BUG(); + return; + } + id = rp->id; + } else { + /* The reset params are invalid. The decompressor does not + care about them, so we just send the minimal requests + and increase ids only when an Ack is received for a + given id */ + id = ccp->reset->lastid++; + /* We always expect an Ack if the decompressor doesnt + know better */ + rp->expra = 1; + rp->dtval = 0; + } + rs = ccp->reset->rs[id]; + if (rs) { + printk(KERN_INFO "ippp_ccp: reset xmit in wrong state %d " + "for id %d (%d)\n", rs->state, id, rs->ta); + return; + } + /* Ok, this is a new transaction */ + printk(KERN_DEBUG "ippp_ccp: new xmit for id %d\n", id); + rs = ippp_ccp_reset_alloc_state(ccp, id); + if(!rs) { + printk(KERN_INFO "ippp_ccp: out of mem allocing ccp trans\n"); + return; + } + rs->expra = rp->expra; + rs->id = id; + if (rp->dtval) { + rs->dlen = rp->dlen; + memcpy(rs->data, rp->data, rp->dlen); + } else { + rs->dlen = 0; + } + + rs->state = CCPResetSentReq; + do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); + + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; +} + +/* ====================================================================== */ + +struct ippp_ccp * +ippp_ccp_alloc(void) +{ + struct ippp_ccp *ccp; + + ccp = kmalloc(sizeof(*ccp), GFP_ATOMIC); // FIXME + memset(ccp, 0, sizeof(*ccp)); + ccp->mru = 1524; /* MRU, default 1524 */ + ccp->reset = kmalloc(sizeof(*ccp->reset), GFP_ATOMIC); // FIXME alloc together? + if (!ccp->reset) { + kfree(ccp); + return NULL; + } + memset(ccp->reset, 0, sizeof(*ccp->reset)); + return ccp; +} + +void +ippp_ccp_free(struct ippp_ccp *ccp) +{ + int id; + + if (ccp->comp_stat) + ccp->compressor->free(ccp->comp_stat); + if (ccp->decomp_stat) + ccp->decompressor->free(ccp->decomp_stat); + + for (id = 0; id < 256; id++) { + if (ccp->reset->rs[id]) + ippp_ccp_reset_free_state(ccp, id); + } + kfree(ccp->reset); + kfree(ccp); +} + +int +ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru) +{ + ccp->mru = mru; + return 0; +} + +unsigned int +ippp_ccp_get_flags(struct ippp_ccp *ccp) +{ + return ccp->compflags & (SC_DC_ERROR|SC_DC_FERROR); +} + +/* + * compress a frame + * returns original skb if we did not compress the frame + * and a new skb otherwise + */ +struct sk_buff * +ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto) +{ + struct sk_buff *skb; + + if (!(ccp->compflags & (SC_COMP_ON|SC_DECOMP_ON))) { + /* We send compressed only if both down- und upstream + compression is negotiated, that means, CCP is up */ + return skb_in; + } + /* we do not compress control protocols */ + if (*proto < 0 || *proto > 0x3fff) { + return skb_in; + } + if (!ccp->compressor || !ccp->comp_stat) { + isdn_BUG(); + return skb_in; + } + /* Allow for at least 150 % expansion (for now) */ + skb = alloc_skb(skb_in->len*2 + skb_headroom(skb_in), GFP_ATOMIC); + if (!skb) + return skb_in; + + skb_reserve(skb, skb_headroom(skb_in)); + if (!ccp->compressor->compress(ccp->comp_stat, skb_in, skb, *proto)) { + dev_kfree_skb(skb); + return skb_in; + } + isdn_ppp_frame_log("comp in:", skb_in->data, skb_in->len, 20, -1, -1); + isdn_ppp_frame_log("comp out:", skb->data, skb->len, 20, -1, -1); + dev_kfree_skb(skb_in); + *proto = ccp->proto; + return skb; +} + +/* + * decompress packet + * + * proto is updated to protocol field of uncompressed packet. + * retval: decompressed packet, + * same packet if uncompressed, + * NULL if decompression error + */ + +struct sk_buff * +ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto) +{ + struct sk_buff *skb; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + int len; + + if (!(ccp->compflags & SC_DECOMP_ON)) { + return skb_in; + } + if (!ccp->decompressor || !ccp->decomp_stat) { + isdn_BUG(); + return skb_in; + } + if (*proto != ccp->proto) { + /* uncompressed packets are fed through the decompressor to + * update the decompressor state */ + ccp->decompressor->incomp(ccp->decomp_stat, skb_in, *proto); + return skb_in; + } + skb = dev_alloc_skb(ccp->mru + PPP_HDRLEN); // FIXME oom? + + // Set up reset params for the decompressor + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + + len = ccp->decompressor->decompress(ccp->decomp_stat, skb_in, skb, + &rsparm); + isdn_ppp_frame_log("deco in:", skb_in->data, skb_in->len, 20, -1, -1); + isdn_ppp_frame_log("deco out:", skb->data, skb->len, 20, -1, -1); + kfree_skb(skb_in); + + if (len <= 0) { + switch(len) { + case DECOMP_ERROR: + printk(KERN_INFO "ippp: decomp wants reset with%s params\n", + rsparm.valid ? "" : "out"); + + ippp_ccp_reset_xmit(ccp, &rsparm); + break; + case DECOMP_FATALERROR: + ccp->compflags |= SC_DC_FERROR; + /* Kick ipppd to recognize the error */ + ccp->kick_up(ccp->priv); + break; + } + kfree_skb(skb); + return NULL; + } + *proto = isdn_ppp_strip_proto(skb); + if (*proto < 0) { + kfree_skb(skb); + return NULL; + } + return skb; +} + +/* An Ack was received for this id. This means we stop the timer and clean + up the state prior to calling the decompressors reset routine. */ +static void +isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; + + if (!rs) { + printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" + " %d\n", id); + return; + } + + if (rs->ta && rs->state == CCPResetSentReq) { + /* Great, we are correct */ + if(!rs->expra) + printk(KERN_DEBUG "ippp_ccp: ResetAck received" + " for id %d but not expected\n", id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received out of" + "sync for id %d\n", id); + } + if(rs->ta) { + rs->ta = 0; + del_timer(&rs->timer); + } + ippp_ccp_reset_free_state(ccp, id); +} + +void +ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) +{ + int len; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + + isdn_ppp_frame_log("ccp-recv", skb->data, skb->len, 32, -1, -1); + + switch(skb->data[0]) { + case CCP_CONFREQ: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable compression here!\n"); + + ccp->compflags &= ~SC_COMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + + ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + break; + case CCP_CONFACK: + /* if we RECEIVE an ackowledge we enable the decompressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Enable decompression here!\n"); + + if (!ccp->decomp_stat) + break; + ccp->compflags |= SC_DECOMP_ON; + break; + case CCP_RESETACK: + printk(KERN_DEBUG "Received ResetAck from peer\n"); + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + + /* If a reset Ack was outstanding for this id, then + clean up the state engine */ + isdn_ppp_ccp_reset_ack_rcvd(ccp, skb->data[1]); + if (ccp->decomp_stat) + ccp->decompressor->reset(ccp->decomp_stat, + skb->data[0], skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: This is not easy to decide here */ + ccp->compflags &= ~SC_DECOMP_DISCARD; + break; + case CCP_RESETREQ: + printk(KERN_DEBUG "Received ResetReq from peer\n"); + /* Receiving a ResetReq means we must reset our compressor */ + /* Set up reset params for the reset entry */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + /* Isolate data length */ + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + if (ccp->comp_stat) + ccp->compressor->reset(ccp->comp_stat, + skb->data[0], skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + /* Ack the Req as specified by rsparm */ + if (rsparm.valid) { + /* Compressor reset handler decided how to answer */ + if (!rsparm.rsend) { + printk(KERN_DEBUG "ResetAck suppressed\n"); + return; + } + /* We should send a Frame */ + do_xmit_reset(ccp, CCP_RESETACK, + rsparm.idval ? rsparm.id : skb->data[1], + rsparm.data, + rsparm.dtval ? rsparm.dlen : 0); + return; + } + /* We answer with a straight reflected Ack */ + do_xmit_reset(ccp, CCP_RESETACK, skb->data[1], + skb->data + 4, len); + } +} + +void +ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) +{ + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1); + + switch (skb->data[2]) { + case CCP_CONFREQ: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable decompression here!\n"); + + ccp->compflags &= ~SC_DECOMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + + ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + break; + case CCP_CONFACK: + /* if we SEND an ackowledge we can/must enable the compressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Enable compression here!\n"); + + if (!ccp->compressor) + break; + + ccp->compflags |= SC_COMP_ON; + break; + case CCP_RESETACK: + /* If we send a ACK we should reset our compressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Reset decompression state here!\n"); + + printk(KERN_DEBUG "ResetAck from daemon passed by\n"); + + if (!ccp->comp_stat) + break; + + ccp->compressor->reset(ccp->comp_stat, 0, 0, NULL, 0, NULL); + ccp->compflags &= ~SC_COMP_DISCARD; + break; + case CCP_RESETREQ: + /* Just let it pass by */ + printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + break; + } +} + +static struct isdn_ppp_compressor *ipc_head = NULL; + +int +ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, + struct isdn_ppp_comp_data *data) +{ + struct isdn_ppp_compressor *ipc = ipc_head; + int ret; + void *stat; + int num = data->num; + + if (ccp->debug & 0x10) + printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, + data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); + + for (ipc = ipc_head; ipc; ipc = ipc->next) { + if (ipc->num != num) + continue; + + stat = ipc->alloc(data); + if (!stat) { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + break; + } + ret = ipc->init(stat, data, unit, 0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + break; + } + if (data->flags & IPPP_COMP_FLAG_XMIT) { + if (ccp->comp_stat) + ccp->compressor->free(ccp->comp_stat); + ccp->comp_stat = stat; + ccp->compressor = ipc; + } else { + if (ccp->decomp_stat) + ccp->decompressor->free(ccp->decomp_stat); + ccp->decomp_stat = stat; + ccp->decompressor = ipc; + } + return 0; + } + return -EINVAL; +} + +void +ippp_ccp_get_compressors(unsigned long protos[8]) +{ + struct isdn_ppp_compressor *ipc; + int i, j; + + memset(protos, 0, sizeof(unsigned long) * 8); + for (ipc = ipc_head; ipc; ipc = ipc->next) { + j = ipc->num / (sizeof(long)*8); + i = ipc->num % (sizeof(long)*8); + if (j < 8) + protos[j] |= 1 << i; + } +} + +int +isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) +{ + ipc->next = ipc_head; + ipc->prev = NULL; + if (ipc_head) { + ipc_head->prev = ipc; + } + ipc_head = ipc; + return 0; +} + +int +isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) +{ + if (ipc->prev) + ipc->prev->next = ipc->next; + else + ipc_head = ipc->next; + if (ipc->next) + ipc->next->prev = ipc->prev; + ipc->prev = ipc->next = NULL; + return 0; +} + diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.h b/drivers/isdn/i4l/isdn_ppp_ccp.h new file mode 100644 index 000000000000..d9ece852d24f --- /dev/null +++ b/drivers/isdn/i4l/isdn_ppp_ccp.h @@ -0,0 +1,66 @@ + +#include <linux/kernel.h> +#include <linux/isdn_ppp.h> + +/* for ippp_ccp::flags */ + +#define SC_DECOMP_ON 0x01 +#define SC_COMP_ON 0x02 +#define SC_DECOMP_DISCARD 0x04 +#define SC_COMP_DISCARD 0x08 + +/* SC_DC_ERROR/FERROR go in here as well, but are defined elsewhere + + #define SC_DC_FERROR 0x00800000 + #define SC_DC_ERROR 0x00400000 +*/ + +struct ippp_ccp { + int proto; + struct isdn_ppp_compressor *compressor; + struct isdn_ppp_compressor *decompressor; + void *comp_stat; + void *decomp_stat; + unsigned long compflags; + struct ippp_ccp_reset *reset; + int mru; + int debug; + void *priv; + void (*xmit)(void *priv, struct sk_buff *skb); + void (*kick_up)(void *priv); + void (*push_header)(void *priv, struct sk_buff *skb, u16); + struct sk_buff *(*alloc_skb)(void *priv, int len, int gfp_mask); +}; + +struct ippp_ccp * +ippp_ccp_alloc(void); + +void +ippp_ccp_free(struct ippp_ccp *ccp); + +int +ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru); + +unsigned int +ippp_ccp_get_flags(struct ippp_ccp *ccp); + +struct sk_buff * +ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto); + +struct sk_buff * +ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto); + +void +ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); + +void +ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); + +void +ippp_ccp_get_compressors(unsigned long protos[8]); + +int +ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, + struct isdn_ppp_comp_data *data); + + diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index e757d5063398..612c7b19c85a 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -11,11 +11,12 @@ #include <linux/config.h> #include <linux/module.h> +#include <linux/interrupt.h> #include <linux/init.h> #include "isdnloop.h" static char *revision = "$Revision: 1.11.6.7 $"; -static char *isdnloop_id; +static char *isdnloop_id = "loop0"; MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); MODULE_AUTHOR("Fritz Elfert"); @@ -76,7 +77,7 @@ isdnloop_bchan_send(isdnloop_card * card, int ch) }; cmd.command = ISDN_STAT_BSENT; cmd.parm.length = len; - if ( ack ) card->interface.statcallb(&cmd); + card->interface.statcallb(&cmd); } else card->sndcount[ch] = 0; } @@ -421,8 +422,9 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) return 0; save_flags(flags); cli(); - nskb = skb_clone(skb, GFP_ATOMIC); + nskb = dev_alloc_skb(skb->len); if (nskb) { + memcpy(skb_put(nskb, len), skb->data, len); skb_queue_tail(&card->bqueue[channel], nskb); dev_kfree_skb(skb); } else diff --git a/drivers/md/md.c b/drivers/md/md.c index 784e3b69213e..a60461dee898 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -200,6 +200,7 @@ static mddev_t * mddev_find(int unit) INIT_LIST_HEAD(&new->disks); INIT_LIST_HEAD(&new->all_mddevs); atomic_set(&new->active, 1); + blk_queue_make_request(&new->queue, md_fail_request); goto retry; } @@ -1275,6 +1276,39 @@ abort: return 1; } +static struct gendisk *md_probe(dev_t dev, int *part, void *data) +{ + static DECLARE_MUTEX(disks_sem); + int unit = MINOR(dev); + mddev_t *mddev = mddev_find(unit); + struct gendisk *disk; + + if (!mddev) + return NULL; + + down(&disks_sem); + if (disks[unit]) { + up(&disks_sem); + mddev_put(mddev); + return NULL; + } + disk = alloc_disk(1); + if (!disk) { + up(&disks_sem); + mddev_put(mddev); + return NULL; + } + disk->major = MD_MAJOR; + disk->first_minor = mdidx(mddev); + sprintf(disk->disk_name, "md%d", mdidx(mddev)); + disk->fops = &md_fops; + disk->private_data = mddev; + disk->queue = &mddev->queue; + add_disk(disk); + disks[mdidx(mddev)] = disk; + up(&disks_sem); + return NULL; +} #define TOO_BIG_CHUNKSIZE KERN_ERR \ "too big chunk_size: %d > %d\n" @@ -1394,14 +1428,10 @@ static int do_md_run(mddev_t * mddev) #endif } - disk = alloc_disk(1); + md_probe(mdidx(mddev), NULL, NULL); + disk = disks[mdidx(mddev)]; if (!disk) return -ENOMEM; - disk->major = MD_MAJOR; - disk->first_minor = mdidx(mddev); - sprintf(disk->disk_name, "md%d", mdidx(mddev)); - disk->fops = &md_fops; - mddev->pers = pers[pnum]; blk_queue_make_request(&mddev->queue, mddev->pers->make_request); @@ -1417,7 +1447,6 @@ static int do_md_run(mddev_t * mddev) if (err) { printk(KERN_ERR "md: pers->run() failed ...\n"); mddev->pers = NULL; - put_disk(disk); return -EINVAL; } @@ -1430,9 +1459,6 @@ static int do_md_run(mddev_t * mddev) md_update_sb(mddev); md_recover_arrays(); set_capacity(disk, md_size[mdidx(mddev)]<<1); - add_disk(disk); - disks[mdidx(mddev)] = disk; - return (0); } @@ -1543,13 +1569,8 @@ static int do_md_stop(mddev_t * mddev, int ro) md_size[mdidx(mddev)] = 0; disk = disks[mdidx(mddev)]; - disks[mdidx(mddev)] = NULL; - - if (disk) { - del_gendisk(disk); - put_disk(disk); - } - + if (disk) + set_capacity(disk, 0); } else printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev)); err = 0; @@ -3083,18 +3104,6 @@ static void md_geninit(void) #endif } -request_queue_t * md_queue_proc(kdev_t dev) -{ - mddev_t *mddev = mddev_find(minor(dev)); - request_queue_t *q = BLK_DEFAULT_QUEUE(MAJOR_NR); - if (mddev) { - if (mddev->pers) - q = &mddev->queue; - mddev_put(mddev); - } - return q; -} - int __init md_init(void) { static char * name = "mdrecoveryd"; @@ -3109,6 +3118,8 @@ int __init md_init(void) return (-1); } devfs_handle = devfs_mk_dir (NULL, "md", NULL); + blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE, + md_probe, NULL, NULL); for (minor=0; minor < MAX_MD_DEVS; ++minor) { char devname[128]; sprintf (devname, "%u", minor); @@ -3117,10 +3128,6 @@ int __init md_init(void) S_IFBLK | S_IRUSR | S_IWUSR, &md_fops, NULL); } - /* all requests on an uninitialised device get failed... */ - blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_fail_request); - blk_dev[MAJOR_NR].queue = md_queue_proc; - md_recovery_thread = md_register_thread(md_do_recovery, NULL, name); if (!md_recovery_thread) printk(KERN_ALERT @@ -3447,6 +3454,8 @@ int init_module(void) void cleanup_module(void) { + int i; + blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS); md_unregister_thread(md_recovery_thread); devfs_unregister(devfs_handle); @@ -3456,8 +3465,16 @@ void cleanup_module(void) #ifdef CONFIG_PROC_FS remove_proc_entry("mdstat", NULL); #endif - - blk_dev[MAJOR_NR].queue = NULL; + for (i = 0; i < MAX_MD_DEVS; i++) { + struct gendisk *disk = disks[i]; + mddev_t *mddev; + if (!disks[i]) + continue; + mddev = disk->private_data; + del_gendisk(disk); + put_disk(disk); + mddev_put(mddev); + } } #endif diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h index a6e7ecdcb4e1..99575438c027 100644 --- a/drivers/message/fusion/linux_compat.h +++ b/drivers/message/fusion/linux_compat.h @@ -75,11 +75,11 @@ typedef int (*__init_module_func_t)(void); typedef void (*__cleanup_module_func_t)(void); #define module_init(x) \ int init_module(void) __attribute__((alias(#x))); \ - extern inline __init_module_func_t __init_module_inline(void) \ + static inline __init_module_func_t __init_module_inline(void) \ { return x; } #define module_exit(x) \ void cleanup_module(void) __attribute__((alias(#x))); \ - extern inline __cleanup_module_func_t __cleanup_module_inline(void) \ + static inline __cleanup_module_func_t __cleanup_module_inline(void) \ { return x; } #else diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index b6f8af6193f1..08731b7c5977 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -225,7 +225,6 @@ static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int static void i2ob_end_request(struct request *); static void i2ob_request(request_queue_t *); static int i2ob_init_iop(unsigned int); -static request_queue_t* i2ob_get_queue(kdev_t); static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); static int i2ob_evt(void *); @@ -1284,14 +1283,6 @@ static int i2ob_init_iop(unsigned int unit) } /* - * Get the request queue for the given device. - */ -static request_queue_t* i2ob_get_queue(kdev_t dev) -{ - return I2O_UNIT(dev).req_queue; -} - -/* * Probe the I2O subsytem for block class devices */ static void i2ob_scan(int bios) @@ -1551,10 +1542,9 @@ void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) /* * Have we seen a media change ? */ -static int i2ob_media_change(kdev_t dev) +static int i2ob_media_change(struct gendisk *disk) { - int i=minor(dev); - i>>=4; + int i = (int)disk->private_data; if(i2ob_media_change_flag[i]) { i2ob_media_change_flag[i]=0; @@ -1563,11 +1553,11 @@ static int i2ob_media_change(kdev_t dev) return 0; } -static int i2ob_revalidate(kdev_t dev) +static int i2ob_revalidate(struct gendisk *disk) { - int minor = minor(dev) & ~15; - return i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev, - minor); + int i = (int)disk->private_data; + return i2ob_install_device(i2ob_dev[i<<4].controller, + i2ob_dev[i<<4].i2odev, i<<4); } /* @@ -1616,12 +1606,12 @@ static void i2ob_reboot_event(void) static struct block_device_operations i2ob_fops = { - owner: THIS_MODULE, - open: i2ob_open, - release: i2ob_release, - ioctl: i2ob_ioctl, - check_media_change: i2ob_media_change, - revalidate: i2ob_revalidate, + .owner = THIS_MODULE, + .open = i2ob_open, + .release = i2ob_release, + .ioctl = i2ob_ioctl, + .media_changed = i2ob_media_change, + .revalidate_disk= i2ob_revalidate, }; /* @@ -1650,6 +1640,9 @@ static int i2o_block_init(void) struct gendisk *disk = alloc_disk(16); if (!disk) goto oom; + /* to be cleaned up */ + disk->private_data = (void*)i; + disk->queue = i2ob_dev[i<<4].req_queue; i2o_disk[i] = disk; } #ifdef MODULE @@ -1660,8 +1653,6 @@ static int i2o_block_init(void) * Now fill in the boiler plate */ - blk_dev[MAJOR_NR].queue = i2ob_get_queue; - for (i = 0; i < MAX_I2OB << 4; i++) { i2ob_dev[i].refcnt = 0; i2ob_dev[i].flags = 0; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index e40e34d3c7d6..d3e54f36e118 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -175,16 +175,16 @@ static int ftl_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg); static int ftl_open(struct inode *inode, struct file *file); static release_t ftl_close(struct inode *inode, struct file *file); -static int ftl_revalidate(kdev_t dev); +static int ftl_revalidate(struct gendisk *disk); static void ftl_erase_callback(struct erase_info *done); static struct block_device_operations ftl_blk_fops = { - owner: THIS_MODULE, - open: ftl_open, - release: ftl_close, - ioctl: ftl_ioctl, - revalidate: ftl_revalidate, + .owner = THIS_MODULE, + .open = ftl_open, + .release = ftl_close, + .ioctl = ftl_ioctl, + .revalidate_disk= ftl_revalidate, }; /*====================================================================== @@ -823,61 +823,53 @@ static u_int32_t find_free(partition_t *part) static int ftl_open(struct inode *inode, struct file *file) { - int minor = minor(inode->i_rdev); - partition_t *partition; + partition_t *partition = inode->i_bdev->bd_disk->private_data; + if (!partition) + return -ENODEV; - if (minor>>4 >= MAX_MTD_DEVICES) - return -ENODEV; - - partition = myparts[minor>>4]; - - if (!partition) - return -ENODEV; - - if (partition->state != FTL_FORMATTED) - return -ENXIO; + if (partition->state != FTL_FORMATTED) + return -ENXIO; - if (get_capacity(partition->disk) == 0) - return -ENXIO; + if (get_capacity(partition->disk) == 0) + return -ENXIO; - if (!get_mtd_device(partition->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; + if (!get_mtd_device(partition->mtd, -1)) + return /* -E'SBUGGEREDOFF */ -ENXIO; - if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { - put_mtd_device(partition->mtd); - return -EROFS; - } + if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { + put_mtd_device(partition->mtd); + return -EROFS; + } - DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor); + DEBUG(0, "ftl_cs: ftl_open(%s)\n", inode->i_bdev->b_disk->disk_name); - atomic_inc(&partition->open); + atomic_inc(&partition->open); - return 0; + return 0; } /*====================================================================*/ static release_t ftl_close(struct inode *inode, struct file *file) { - int minor = minor(inode->i_rdev); - partition_t *part = myparts[minor >> 4]; - int i; + partition_t *part = inode->i_bdev->bd_disk->private_data; + int i; - DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); + DEBUG(0, "ftl_cs: ftl_close(%s)\n", inode->i_bdev->b_disk->disk_name); - /* Wait for any pending erase operations to complete */ - if (part->mtd->sync) - part->mtd->sync(part->mtd); + /* Wait for any pending erase operations to complete */ + if (part->mtd->sync) + part->mtd->sync(part->mtd); - for (i = 0; i < part->header.NumTransferUnits; i++) { - if (part->XferInfo[i].state == XFER_ERASED) - prepare_xfer(part, i); - } + for (i = 0; i < part->header.NumTransferUnits; i++) { + if (part->XferInfo[i].state == XFER_ERASED) + prepare_xfer(part, i); + } - atomic_dec(&part->open); + atomic_dec(&part->open); - put_mtd_device(part->mtd); - release_return(0); + put_mtd_device(part->mtd); + release_return(0); } /* ftl_close */ @@ -1091,25 +1083,26 @@ static int ftl_write(partition_t *part, caddr_t buffer, static int ftl_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - struct hd_geometry *geo = (struct hd_geometry *)arg; - int ret = 0, minor = minor(inode->i_rdev); - partition_t *part= myparts[minor >> 4]; - u_long sect; - - if (!part) - return -ENODEV; /* How? */ - - if (cmd != HDIO_GETGEO) - return -EINVAL; - ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo)); - if (ret) return ret; - /* Sort of arbitrary: round size down to 4K boundary */ - sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; - put_user(1, (char *)&geo->heads); - put_user(8, (char *)&geo->sectors); - put_user((sect>>3), (short *)&geo->cylinders); - put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start); - return 0; + partition_t *part = inode->i_bdev->bd_disk->private_data; + struct hd_geometry *geo = (struct hd_geometry *)arg; + int ret = 0; + u_long sect; + + if (!part) + return -ENODEV; /* How? */ + + if (cmd != HDIO_GETGEO) + return -EINVAL; + ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo)); + if (ret) + return ret; + /* Sort of arbitrary: round size down to 4K boundary */ + sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; + put_user(1, (char *)&geo->heads); + put_user(8, (char *)&geo->sectors); + put_user((sect>>3), (short *)&geo->cylinders); + put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start); + return 0; } /* ftl_ioctl */ /*====================================================================== @@ -1118,13 +1111,11 @@ static int ftl_ioctl(struct inode *inode, struct file *file, ======================================================================*/ -static int ftl_revalidate(kdev_t dev) +static int ftl_revalidate(struct gendisk *disk) { - int unit = minor(dev) >> 4; - partition_t *part = myparts[unit]; + partition_t *part = disk->private_data; scan_header(part); - set_capacity(part->disk, - le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); + set_capacity(disk, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); return 0; } @@ -1134,50 +1125,48 @@ static int ftl_revalidate(kdev_t dev) ======================================================================*/ -static void do_ftl_request(request_arg_t) -{ - int ret, minor; - partition_t *part; +static struct request_queue ftl_queue; - do { - // sti(); - if (blk_queue_empty(QUEUE)) - return; +static void do_ftl_request(struct request_queue *q) +{ + struct request *req; + partition_t *part; + int ret; + + do { + // sti(); + if (blk_queue_empty(q)) + return; + req = elv_next_request(q); + part = req->rq_disk->private_data; + if (part) { + ret = 0; + switch (rq_data_dir(CURRENT)) { + case READ: + ret = ftl_read(part, req->buffer, req->sector, + req->current_nr_sectors); + if (ret) + printk("ftl_read returned %d\n", ret); + break; + case WRITE: + ret = ftl_write(part, req->buffer, req->sector, + req->current_nr_sectors); + if (ret) + printk("ftl_write returned %d\n", ret); + break; + default: + panic("ftl_cs: unknown block command!\n"); + } + } else { + ret = 1; + printk("NULL part in ftl_request\n"); + } + + if (!ret) + req->sector += req->current_nr_sectors; - minor = minor(CURRENT->rq_dev); - - part = myparts[minor >> 4]; - if (part) { - ret = 0; - - switch (rq_data_dir(CURRENT)) { - case READ: - ret = ftl_read(part, CURRENT->buffer, CURRENT->sector, - CURRENT->current_nr_sectors); - if (ret) printk("ftl_read returned %d\n", ret); - break; - - case WRITE: - ret = ftl_write(part, CURRENT->buffer, CURRENT->sector, - CURRENT->current_nr_sectors); - if (ret) printk("ftl_write returned %d\n", ret); - break; - - default: - panic("ftl_cs: unknown block command!\n"); - - } - } else { - ret = 1; - printk("NULL part in ftl_request\n"); - } - - if (!ret) { - CURRENT->sector += CURRENT->current_nr_sectors; - } - - end_request(CURRENT, (ret == 0) ? 1 : 0); - } while (1); + end_request(req, (ret == 0) ? 1 : 0); + } while (1); } /* do_ftl_request */ /*====================================================================*/ @@ -1246,6 +1235,8 @@ static void ftl_notify_add(struct mtd_info *mtd) atomic_set(&partition->open, 0); myparts[device] = partition; set_capacity(disk, le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE); + disk->private_data = partition; + disk->queue = &ftl_queue; add_disk(disk); #ifdef PCMCIA_DEBUG printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n", @@ -1287,31 +1278,29 @@ static void ftl_notify_remove(struct mtd_info *mtd) int init_ftl(void) { - static spinlock_t lock = SPIN_LOCK_UNLOCKED; - DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n"); - - if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { - printk(KERN_NOTICE "ftl_cs: unable to grab major " - "device number!\n"); - return -EAGAIN; - } - blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request, &lock); - register_mtd_user(&ftl_notifier); - - return 0; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n"); + + if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { + printk(KERN_NOTICE "ftl_cs: unable to grab major " + "device number!\n"); + return -EAGAIN; + } + blk_init_queue(&ftl_queue, &do_ftl_request, &lock); + register_mtd_user(&ftl_notifier); + return 0; } static void __exit cleanup_ftl(void) { - unregister_mtd_user(&ftl_notifier); - unregister_blkdev(FTL_MAJOR, "ftl"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR)); + unregister_mtd_user(&ftl_notifier); + unregister_blkdev(FTL_MAJOR, "ftl"); + blk_cleanup_queue(&ftl_queue); } module_init(init_ftl); module_exit(cleanup_ftl); - MODULE_LICENSE("Dual MPL/GPL"); MODULE_AUTHOR("David Hinds <dhinds@sonic.net>"); MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000"); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 47bf73b1fa1d..e0d807c8b065 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2052,7 +2052,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->ip_summed != CHECKSUM_HW) vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); else - vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum); + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum); if (!skb_shinfo(skb)->nr_frags) { vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, diff --git a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile index a3fe3f4e61cd..77de2ca25c87 100644 --- a/drivers/net/hamradio/soundmodem/Makefile +++ b/drivers/net/hamradio/soundmodem/Makefile @@ -19,6 +19,12 @@ soundmodem-objs := $(soundmodem-y) host-progs := gentbl HOST_LOADLIBES := -lm +# Files generated that shall be removed upon make clean +clean-files := sm_tbl_afsk1200.h sm_tbl_afsk2400_7.h \ + sm_tbl_afsk2400_8.h sm_tbl_afsk2666.h \ + sm_tbl_psk4800.h sm_tbl_hapn4800.h \ + sm_tbl_fsk9600.h + include $(TOPDIR)/Rules.make # Dependencies on generates files need to be listed explicitly diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index 85b4c3e09348..2071ce5ffa10 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -72,7 +72,7 @@ struct nubus_board* nubus_boards; Etcetera, etcetera. Hopefully this clears up some confusion over what the following code actually does. */ -extern inline int not_useful(void *p, int map) +static inline int not_useful(void *p, int map) { unsigned long pv=(unsigned long)p; pv &= 3; @@ -148,14 +148,14 @@ static void nubus_move(unsigned char **ptr, int len, int map) have to expand it from a 24-bit signed number to a 32-bit signed number. */ -extern inline long nubus_expand32(long foo) +static inline long nubus_expand32(long foo) { if(foo & 0x00800000) /* 24bit negative */ foo |= 0xFF000000; return foo; } -extern inline void *nubus_rom_addr(int slot) +static inline void *nubus_rom_addr(int slot) { /* * Returns the first byte after the card. We then walk diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 307ea814439a..d26c2e02ef62 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,6 +31,9 @@ endif host-progs := gen-devlist +# Files generated that shall be removed upon make clean +clean-files := devlist.h classlist.h + include $(TOPDIR)/Rules.make # Dependencies on generated files need to be listed explicitly diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 040cc588981b..3ef7d9eb6e84 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -141,7 +141,7 @@ pci_register_driver(struct pci_driver *drv) void pci_unregister_driver(struct pci_driver *drv) { - remove_driver(&drv->driver); + driver_unregister(&drv->driver); } static struct pci_driver pci_compat_driver = { diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 9bf1a6c392d4..7afea0c7b3aa 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -297,7 +297,7 @@ static int __init sa1111_drv_pcmcia_init(void) static void __exit sa1111_drv_pcmcia_exit(void) { - remove_driver(&pcmcia_driver.drv); + driver_unregister(&pcmcia_driver.drv); } module_init(sa1111_drv_pcmcia_init); diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 35158ea70aa1..9724e5f269e6 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -170,6 +170,8 @@ STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_proc_directory_info(char *, char **, off_t, int, int, int); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); +STATIC int NCR_700_slave_attach(Scsi_Device *SDpnt); +STATIC void NCR_700_slave_detach(Scsi_Device *SDpnt); static char *NCR_700_phase[] = { "", @@ -280,9 +282,11 @@ NCR_700_detect(Scsi_Host_Template *tpnt, tpnt->eh_host_reset_handler = NCR_700_host_reset; tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST; tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; - tpnt->cmd_per_lun = NCR_700_MAX_TAGS; + tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; tpnt->use_clustering = DISABLE_CLUSTERING; tpnt->proc_info = NCR_700_proc_directory_info; + tpnt->slave_attach = NCR_700_slave_attach; + tpnt->slave_detach = NCR_700_slave_detach; tpnt->use_blk_tcq = 1; tpnt->highmem_io = 1; @@ -891,8 +895,8 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); hostdata->tag_negotiated &= ~(1<<SCp->target); - SCp->device->tagged_queue = 0; SCp->device->tagged_supported = 0; + scsi_deactivate_tcq(SCp->device); } else { printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n", host->host_no, pun, lun, @@ -1719,13 +1723,11 @@ NCR_700_proc_directory_info(char *proc_buf, char **startp, { static char buf[4096]; /* 1 page should be sufficient */ int len = 0; - struct Scsi_Host *host = scsi_hostlist; + struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; Scsi_Device *SDp; - while(host != NULL && host->host_no != host_no) - host = host->next; - + host = scsi_host_hn_get(host_no); if(host == NULL) return 0; @@ -1739,7 +1741,7 @@ NCR_700_proc_directory_info(char *proc_buf, char **startp, Target Depth Active Next Tag\n\ ====== ===== ====== ========\n"); for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) { - len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag); + len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->current_queue_depth, NCR_700_get_depth(SDp), SDp->current_tag); } if((len -= offset) <= 0) return 0; @@ -1776,13 +1778,13 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n", SCp->host->host_no, SCp->target, SCp->lun, NCR_700_get_depth(SCp->device))); - return 1; + return SCSI_MLQUEUE_DEVICE_BUSY; } if(NCR_700_get_depth(SCp->device) >= NCR_700_MAX_TAGS) { DEBUG((KERN_ERR "scsi%d (%d:%d) has max tag depth %d\n", SCp->host->host_no, SCp->target, SCp->lun, NCR_700_get_depth(SCp->device))); - return 1; + return SCSI_MLQUEUE_DEVICE_BUSY; } NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1); @@ -1998,6 +2000,25 @@ NCR_700_host_reset(Scsi_Cmnd * SCp) return SUCCESS; } +STATIC int +NCR_700_slave_attach(Scsi_Device *SDp) +{ + /* to do here: allocate memory; build a queue_full list */ + if(SDp->tagged_supported) { + /* do TCQ stuff here */ + } else { + /* initialise to default depth */ + scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); + } + return 0; +} + +STATIC void +NCR_700_slave_detach(Scsi_Device *SDp) +{ + /* to do here: deallocate memory */ +} + EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index ccb675372935..f01bdb2e1321 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -30,6 +30,11 @@ /* Alter this with care: too many tags won't give the elevator a chance to * work; too few will cause the device to operate less efficiently */ #define NCR_700_MAX_TAGS 16 +/* This is the default number of commands per LUN in the untagged case. + * two is a good value because it means we can have one command active and + * one command fully prepared and waiting + */ +#define NCR_700_CMD_PER_LUN 2 /* magic byte identifying an internally generated REQUEST_SENSE command */ #define NCR_700_INTERNAL_SENSE_MAGIC 0x42 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index b9f1779ff00f..1edb859c1b50 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -132,6 +132,10 @@ a100u2w-objs := inia100.o i60uscsi.o cpqfc-objs := cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \ cpqfcTSworker.o cpqfcTStrigger.o +# Files generated that shall be removed upon make clean +clean-files := 53c8xx_d.h 53c7xx_d.h sim710_d.h 53c700_d.h \ + 53c8xx_u.h 53c7xx_u.h sim710_u.h 53c700_u.h + include $(TOPDIR)/Rules.make $(obj)/53c7,8xx.o: $(obj)/53c8xx_d.h $(obj)/53c8xx_u.h diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index a83d865e925d..f880e78f0454 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -289,7 +289,7 @@ static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) #endif #ifdef DEBUG_ESP_CMDS -extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, +inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, unchar cmd) { esp->espcmdlog[esp->espcmdent] = cmd; diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 5afa780d5593..bfcab7bbabf7 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1060,7 +1060,8 @@ int aac_scsi_cmd(Scsi_Cmnd * scsicmd) */ spin_unlock_irq(scsicmd->host->host_lock); - fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->sc_request->sr_request->rq_dev); + fsa_dev_ptr->devno[cid] = + DEVICE_NR(scsicmd->request->rq_dev); ret = aac_read(scsicmd, cid); spin_lock_irq(scsicmd->host->host_lock); return ret; diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile index d92ba2bdc047..ea95d8a13309 100644 --- a/drivers/scsi/aic7xxx/Makefile +++ b/drivers/scsi/aic7xxx/Makefile @@ -20,6 +20,13 @@ endif #EXTRA_CFLAGS += -g +# Files generated that shall be removed upon make clean +clean-files := aic7xxx_seq.h aic7xxx_reg.h + +# Command to be executed upon make clean +# Note: Assignment without ':' to force late evaluation of $(src) +clean-rule = @$(MAKE) -C $(src)/aicasm clean + include $(TOPDIR)/Rules.make # Dependencies for generated files need to be listed explicitly @@ -30,12 +37,13 @@ $(addprefix $(obj)/,$(aic7xxx-objs)): $(obj)/aic7xxx_reg.h ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) -$(obj)/aic7xxx_seq.h $(obj)/aic7xxx_reg.h: $(src)/aic7xxx.seq \ - $(src)/aic7xxx.reg \ - $(obj)/aicasm/aicasm +$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg \ + $(obj)/aicasm/aicasm $(obj)/aicasm/aicasm -I. -r $(obj)/aic7xxx_reg.h \ -o $(obj)/aic7xxx_seq.h $(src)/aic7xxx.seq +$(obj)/aic7xxx_reg.h: $(obj)/aix7xxx_seq.h + $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] $(MAKE) -C $(src)/aicasm diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h index de53201f4df1..27ba7345c53a 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h @@ -63,7 +63,6 @@ int ahc_linux_abort(Scsi_Cmnd *); * to do with card config are filled in after the card is detected. */ #define AIC7XXX { \ - next: NULL, \ module: NULL, \ proc_dir: NULL, \ proc_info: ahc_linux_proc_info, \ diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index 790402e0dd68..39acae36dcac 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -43,7 +43,7 @@ aicdb.h: fi clean: - rm -f $(CLEANFILES) $(PROG) + @rm -f $(CLEANFILES) $(PROG) y.tab.h aicasm_gram.c: aicasm_gram.y $(YACC) $(YFLAGS) aicasm_gram.y diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h index 4d9ba148d0d5..016a1b2e2ee6 100644 --- a/drivers/scsi/aic7xxx_old/aic7xxx.h +++ b/drivers/scsi/aic7xxx_old/aic7xxx.h @@ -30,14 +30,10 @@ * to do with card config are filled in after the card is detected. */ #define AIC7XXX { \ - next: NULL, \ - module: NULL, \ proc_info: aic7xxx_proc_info, \ - name: NULL, \ detect: aic7xxx_detect, \ release: aic7xxx_release, \ info: aic7xxx_info, \ - command: NULL, \ queuecommand: aic7xxx_queue, \ eh_strategy_handler: NULL, \ eh_abort_handler: NULL, \ diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index 03954b23e494..8c002c0ee76b 100644 --- a/drivers/scsi/cpqfcTSinit.c +++ b/drivers/scsi/cpqfcTSinit.c @@ -938,9 +938,7 @@ int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, char buf[81]; // Search the Scsi host list for our controller - for (host=scsi_hostlist; host; host=host->next) - if (host->host_no == hostno) - break; + host = scsi_host_hn_get(hostno); if (!host) return -ESRCH; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 6634124b45b4..921f4369a3e9 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -378,7 +378,7 @@ static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) #endif #ifdef DEBUG_ESP_CMDS -extern inline void esp_cmd(struct esp *esp, u8 cmd) +static inline void esp_cmd(struct esp *esp, u8 cmd) { esp->espcmdlog[esp->espcmdent] = cmd; esp->espcmdent = (esp->espcmdent + 1) & 31; diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c index 77192c05310f..12c127b0b4cd 100644 --- a/drivers/scsi/fcal.c +++ b/drivers/scsi/fcal.c @@ -213,9 +213,7 @@ int fcal_proc_info (char *buffer, char **start, off_t offset, int length, int ho char *pos = buffer; int i, j; - for (host=scsi_hostlist; host; host=host->next) - if (host->host_no == hostno) - break; + host = scsi_host_hn_get(hostno); if (!host) return -ESRCH; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 520f31dfbf82..b3d725b16add 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -15,12 +15,15 @@ * Updated to reflect the new initialization scheme for the higher * level of scsi drivers (sd/sr/st) * September 17, 2000 Torben Mathiasen <tmm@image.dk> + * + * Restructured scsi_host lists and associated functions. + * September 04, 2002 Mike Anderson (andmike@us.ibm.com) */ /* * This file contains the medium level SCSI - * host interface initialization, as well as the scsi_hosts array of SCSI + * host interface initialization, as well as the scsi_hosts list of SCSI * hosts currently present in the system. */ @@ -31,232 +34,711 @@ #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/init.h> +#include <linux/list.h> +#include <linux/smp_lock.h> #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> +#include <asm/dma.h> #include "scsi.h" #include "hosts.h" -/* -static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $"; -*/ +LIST_HEAD(scsi_host_tmpl_list); +LIST_HEAD(scsi_host_hn_list); -/* - * The scsi host entries should be in the order you wish the - * cards to be detected. A driver may appear more than once IFF - * it can deal with being detected (and therefore initialized) - * with more than one simultaneous host number, can handle being - * reentrant, etc. +LIST_HEAD(scsi_host_list); +spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED; + +struct Scsi_Device_Template * scsi_devicelist; + +static int scsi_host_next_hn; /* host_no for next new host */ +static int scsi_hosts_registered; /* cnt of registered scsi hosts */ + +/** + * scsi_tp_for_each_host - call function for each scsi host off a template + * @shost_tp: a pointer to a scsi host template + * @callback: a pointer to callback function * - * They may appear in any order, as each SCSI host is told which host - * number it is during detection. - */ + * Return value: + * 0 on Success / 1 on Failure + **/ +int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int + (*callback)(struct Scsi_Host *shost)) +{ + struct list_head *lh, *lh_sf; + struct Scsi_Host *shost; -/* - * When figure is run, we don't want to link to any object code. Since - * the macro for each host will contain function pointers, we cannot - * use it and instead must use a "blank" that does no such - * idiocy. - */ + spin_lock(&scsi_host_list_lock); -Scsi_Host_Template * scsi_hosts; + list_for_each_safe(lh, lh_sf, &scsi_host_list) { + shost = list_entry(lh, struct Scsi_Host, sh_list); + if (shost->hostt == shost_tp) { + spin_unlock(&scsi_host_list_lock); + callback(shost); + spin_lock(&scsi_host_list_lock); + } + } + spin_unlock(&scsi_host_list_lock); -/* - * Our semaphores and timeout counters, where size depends on - * MAX_SCSI_HOSTS here. - */ + return 0; +} -Scsi_Host_Name * scsi_host_no_list; -struct Scsi_Host * scsi_hostlist; -struct Scsi_Device_Template * scsi_devicelist; +/** + * scsi_host_generic_release - default release function for hosts + * @shost: + * + * Description: + * This is the default case for the release function. It should do + * the right thing for most correctly written host adapters. + **/ +static void scsi_host_generic_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); +} + +/** + * scsi_host_chk_and_release - check a scsi host for release and release + * @shost: a pointer to a scsi host to release + * + * Return value: + * 0 on Success / 1 on Failure + **/ +int scsi_host_chk_and_release(struct Scsi_Host *shost) +{ + int pcount; + Scsi_Device *sdev; + struct Scsi_Device_Template *sdev_tp; + Scsi_Cmnd *scmd; + + /* + * Current policy is all shosts go away on unregister. + */ + if (shost->hostt->module && GET_USE_COUNT(shost->hostt->module)) + return 1; + + /* + * FIXME Do ref counting. We force all of the devices offline to + * help prevent race conditions where other hosts/processors could + * try and get in and queue a command. + */ + for (sdev = shost->host_queue; sdev; sdev = sdev->next) + sdev->online = FALSE; + + for (sdev = shost->host_queue; sdev; sdev = sdev->next) { + /* + * Loop over all of the commands associated with the + * device. If any of them are busy, then set the state + * back to inactive and bail. + */ + for (scmd = sdev->device_queue; scmd; scmd = scmd->next) { + if (scmd->request && scmd->request->rq_status != + RQ_INACTIVE) { + printk(KERN_ERR "SCSI device not inactive" + "- rq_status=%d, target=%d, pid=%ld," + "state=%d, owner=%d.\n", + scmd->request->rq_status, + scmd->target, scmd->pid, + scmd->state, scmd->owner); + for (sdev = shost->host_queue; sdev; + sdev = sdev->next) { + for (scmd = sdev->device_queue; scmd; + scmd = scmd->next) + if (scmd->request->rq_status == + RQ_SCSI_DISCONNECTING) + scmd->request->rq_status = RQ_INACTIVE; + } + printk(KERN_ERR "Device busy???\n"); + return 1; + } + /* + * No, this device is really free. Mark it as such, and + * continue on. + */ + scmd->state = SCSI_STATE_DISCONNECTING; + if (scmd->request) + scmd->request->rq_status = + RQ_SCSI_DISCONNECTING; /* Mark as + busy */ + } + } -int max_scsi_hosts; -int next_scsi_host; - -void -scsi_unregister(struct Scsi_Host * sh){ - struct Scsi_Host * shpnt; - Scsi_Host_Name *shn; - - if(scsi_hostlist == sh) - scsi_hostlist = sh->next; - else { - shpnt = scsi_hostlist; - while(shpnt->next != sh) shpnt = shpnt->next; - shpnt->next = shpnt->next->next; - } - - /* - * We have to unregister the host from the scsi_host_no_list as well. - * Decide by the host_no not by the name because most host drivers are - * able to handle more than one adapters from the same kind (or family). - */ - for ( shn=scsi_host_no_list; shn && (sh->host_no != shn->host_no); - shn=shn->next); - if (shn) shn->host_registered = 0; - /* else {} : This should not happen, we should panic here... */ - - /* If we are removing the last host registered, it is safe to reuse - * its host number (this avoids "holes" at boot time) (DB) - * It is also safe to reuse those of numbers directly below which have - * been released earlier (to avoid some holes in numbering). - */ - if(sh->host_no == max_scsi_hosts - 1) { - while(--max_scsi_hosts >= next_scsi_host) { - shpnt = scsi_hostlist; - while(shpnt && shpnt->host_no != max_scsi_hosts - 1) - shpnt = shpnt->next; - if(shpnt) - break; + /* + * Next we detach the high level drivers from the Scsi_Device + * structures + */ + for (sdev = shost->host_queue; sdev; sdev = sdev->next) { + for (sdev_tp = scsi_devicelist; sdev_tp; + sdev_tp = sdev_tp->next) + if (sdev_tp->detach) + (*sdev_tp->detach) (sdev); + + /* If something still attached, punt */ + if (sdev->attached) { + printk(KERN_ERR "Attached usage count = %d\n", + sdev->attached); + return 1; + } + + if (shost->hostt->slave_detach) + (*shost->hostt->slave_detach) (sdev); + + devfs_unregister(sdev->de); + device_unregister(&sdev->sdev_driverfs_dev); + } + + /* Next we free up the Scsi_Cmnd structures for this host */ + + for (sdev = shost->host_queue; sdev; + sdev = shost->host_queue) { + scsi_release_commandblocks(sdev); + blk_cleanup_queue(&sdev->request_queue); + /* Next free up the Scsi_Device structures for this host */ + shost->host_queue = sdev->next; + if (sdev->inquiry) + kfree(sdev->inquiry); + kfree(sdev); + } + + /* Remove the instance of the individual hosts */ + pcount = scsi_hosts_registered; + if (shost->hostt->release) + (*shost->hostt->release) (shost); + else { + scsi_host_generic_release(shost); } - } - next_scsi_host--; - kfree((char *) sh); + + if (pcount == scsi_hosts_registered) + scsi_unregister(shost); + + return 0; } -/* We call this when we come across a new host adapter. We only do this - * once we are 100% sure that we want to use this host adapter - it is a - * pain to reverse this, so we try to avoid it - */ +/** + * scsi_unregister - unregister a scsi host + * @shost: scsi host to be unregistered + **/ +void scsi_unregister(struct Scsi_Host *shost) +{ + struct list_head *lh; + Scsi_Host_Name *shost_name; + + /* Remove shost from scsi_host_list */ + spin_lock(&scsi_host_list_lock); + list_del(&shost->sh_list); + spin_unlock(&scsi_host_list_lock); + + /* Unregister from scsi_host_hn_list */ + list_for_each(lh, &scsi_host_hn_list) { + shost_name = list_entry(lh, Scsi_Host_Name, shn_list); + if (shost->host_no == shost_name->host_no) + shost_name->host_registered = 0; + } + + /* + * Next, kill the kernel error recovery thread for this host. + */ + if (shost->ehandler) { + DECLARE_MUTEX_LOCKED(sem); + shost->eh_notify = &sem; + send_sig(SIGHUP, shost->ehandler, 1); + down(&sem); + shost->eh_notify = NULL; + } + + scsi_hosts_registered--; + shost->hostt->present--; + + /* Cleanup proc and driverfs */ +#ifdef CONFIG_PROC_FS + scsi_proc_host_rm(shost); + if (!shost->hostt->present) + remove_proc_entry(shost->hostt->proc_name, proc_scsi); +#endif + device_unregister(&shost->host_driverfs_dev); + + kfree(shost); +} + +/** + * scsi_host_hn_add - allocate and add new Scsi_Host_Name + * @name: String to store in name field + * + * Return value: + * Pointer to a new Scsi_Host_Name + **/ +Scsi_Host_Name *scsi_host_hn_add(char *name) +{ + Scsi_Host_Name *shost_name; + int len; + + len = strlen(name); + shost_name = kmalloc(sizeof(*shost_name), GFP_KERNEL); + if (!shost_name) { + printk(KERN_ERR "%s: out of memory at line %d.\n", + __FUNCTION__, __LINE__); + return NULL; + } + shost_name->name = kmalloc(len + 1, GFP_KERNEL); + if (!shost_name->name) { + kfree(shost_name); + printk(KERN_ERR "%s: out of memory at line %d.\n", + __FUNCTION__, __LINE__); + return NULL; + } + + if (len) + strncpy(shost_name->name, name, len); + shost_name->name[len] = 0; + shost_name->host_no = scsi_host_next_hn++; + shost_name->host_registered = 0; + list_add_tail(&shost_name->shn_list, &scsi_host_hn_list); + + return shost_name; +} + +/** + * scsi_register - register a scsi host adapter instance. + * @shost_tp: pointer to scsi host template + * @xtr_bytes: extra bytes to allocate for driver + * + * Note: + * We call this when we come across a new host adapter. We only do + * this once we are 100% sure that we want to use this host adapter - + * it is a pain to reverse this, so we try to avoid it + * + * Return value: + * Pointer to a new Scsi_Host + **/ extern int blk_nohighio; -struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j) +struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) { - struct Scsi_Host * retval, *shpnt, *o_shp; - Scsi_Host_Name *shn, *shn2; - int flag_new = 1; - const char * hname; - size_t hname_len; - retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j, - (tpnt->unchecked_isa_dma && j ? - GFP_DMA : 0) | GFP_ATOMIC); - if(retval == NULL) - { - printk("scsi: out of memory in scsi_register.\n"); - return NULL; - } - - memset(retval, 0, sizeof(struct Scsi_Host) + j); - - /* trying to find a reserved entry (host_no) */ - hname = (tpnt->proc_name) ? tpnt->proc_name : ""; - hname_len = strlen(hname); - for (shn = scsi_host_no_list;shn;shn = shn->next) { - if (!(shn->host_registered) && - (hname_len > 0) && (0 == strncmp(hname, shn->name, hname_len))) { - flag_new = 0; - retval->host_no = shn->host_no; - shn->host_registered = 1; - break; + struct Scsi_Host *shost, *shost_scr; + Scsi_Host_Name *shost_name = NULL; + Scsi_Host_Name *shn = NULL; + char *hname; + size_t hname_len; + struct list_head *lh; + int gfp_mask; + DECLARE_MUTEX_LOCKED(sem); + + gfp_mask = GFP_KERNEL; + if (shost_tp->unchecked_isa_dma && xtr_bytes) + gfp_mask |= __GFP_DMA; + + shost = kmalloc(sizeof(struct Scsi_Host) + xtr_bytes, gfp_mask); + if (!shost) { + printk(KERN_ERR "%s: out of memory.\n", __FUNCTION__); + return NULL; } - } - 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 (flag_new) { - shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC); - if (!shn) { - kfree(retval); - printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n"); - return NULL; - } - shn->name = kmalloc(hname_len + 1, GFP_ATOMIC); - if (hname_len > 0) - strncpy(shn->name, hname, hname_len); - shn->name[hname_len] = 0; - shn->host_no = max_scsi_hosts++; - shn->host_registered = 1; - shn->next = NULL; - if (scsi_host_no_list) { - for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next) - ; - shn2->next = shn; + + memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes); + + /* + * Determine host number. Check reserved first before allocating + * new one + */ + hname = (shost_tp->proc_name) ? shost_tp->proc_name : ""; + hname_len = strlen(hname); + + if (hname_len) + list_for_each(lh, &scsi_host_hn_list) { + shn = list_entry(lh, Scsi_Host_Name, shn_list); + if (!(shn->host_registered) && + !strncmp(hname, shn->name, hname_len)) { + shost_name = shn; + break; + } + } + + if (!shost_name) { + shost_name = scsi_host_hn_add(hname); + if (!shost_name) { + kfree(shost); + return NULL; + } } - else - scsi_host_no_list = shn; - retval->host_no = shn->host_no; - } - next_scsi_host++; - retval->host_queue = NULL; - init_waitqueue_head(&retval->host_wait); - retval->resetting = 0; - retval->last_reset = 0; - retval->irq = 0; - retval->dma_channel = 0xff; - - /* These three are default values which can be overridden */ - retval->max_channel = 0; - retval->max_id = 8; - retval->max_lun = 8; - - /* - * All drivers right now should be able to handle 12 byte commands. - * Every so often there are requests for 16 byte commands, but individual - * low-level drivers need to certify that they actually do something - * sensible with such commands. - */ - retval->max_cmd_len = 12; - - retval->unique_id = 0; - retval->io_port = 0; - retval->hostt = tpnt; - retval->next = NULL; - retval->in_recovery = 0; - retval->ehandler = NULL; /* Initial value until the thing starts up. */ - retval->eh_notify = NULL; /* Who we notify when we exit. */ - - retval->max_host_blocked = tpnt->max_host_blocked ? tpnt->max_host_blocked : SCSI_DEFAULT_HOST_BLOCKED; - - retval->host_blocked = 0; - retval->host_self_blocked = FALSE; + + shost->host_no = shost_name->host_no; + shost_name->host_registered = 1; + scsi_hosts_registered++; + + spin_lock_init(&shost->default_lock); + scsi_assign_lock(shost, &shost->default_lock); + atomic_set(&shost->host_active,0); + + init_waitqueue_head(&shost->host_wait); + shost->dma_channel = 0xff; + + /* These three are default values which can be overridden */ + shost->max_channel = 0; + shost->max_id = 8; + shost->max_lun = 8; + + /* + * All drivers right now should be able to handle 12 byte + * commands. Every so often there are requests for 16 byte + * commands, but individual low-level drivers need to certify that + * they actually do something sensible with such commands. + */ + shost->max_cmd_len = 12; + shost->hostt = shost_tp; + shost->host_blocked = FALSE; + shost->host_self_blocked = FALSE; #ifdef DEBUG - printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j); + printk("%s: %x %x: %d\n", __FUNCTION_ (int)shost, + (int)shost->hostt, xtr_bytes); #endif - /* The next six are the default values which can be overridden - * if need be */ - retval->this_id = tpnt->this_id; - retval->can_queue = tpnt->can_queue; - retval->sg_tablesize = tpnt->sg_tablesize; - retval->cmd_per_lun = tpnt->cmd_per_lun; - retval->unchecked_isa_dma = tpnt->unchecked_isa_dma; - retval->use_clustering = tpnt->use_clustering; - if (!blk_nohighio) - retval->highmem_io = tpnt->highmem_io; - - retval->max_sectors = tpnt->max_sectors; - retval->use_blk_tcq = tpnt->use_blk_tcq; - - if(!scsi_hostlist) - scsi_hostlist = retval; - else { - shpnt = scsi_hostlist; - if (retval->host_no < shpnt->host_no) { - retval->next = shpnt; - wmb(); /* want all to see these writes in this order */ - scsi_hostlist = retval; + /* + * The next six are the default values which can be overridden if + * need be + */ + shost->this_id = shost_tp->this_id; + shost->can_queue = shost_tp->can_queue; + shost->sg_tablesize = shost_tp->sg_tablesize; + shost->cmd_per_lun = shost_tp->cmd_per_lun; + shost->unchecked_isa_dma = shost_tp->unchecked_isa_dma; + shost->use_clustering = shost_tp->use_clustering; + if (!blk_nohighio) + shost->highmem_io = shost_tp->highmem_io; + + shost->max_sectors = shost_tp->max_sectors; + shost->use_blk_tcq = shost_tp->use_blk_tcq; + + spin_lock(&scsi_host_list_lock); + /* + * FIXME When device naming is complete remove this step that + * orders the scsi_host_list by host number and just do a + * list_add_tail. + */ + list_for_each(lh, &scsi_host_list) { + shost_scr = list_entry(lh, struct Scsi_Host, sh_list); + if (shost->host_no < shost_scr->host_no) { + __list_add(&shost->sh_list, shost_scr->sh_list.prev, + &shost_scr->sh_list); + goto found; + } } - else { - for (o_shp = shpnt, shpnt = shpnt->next; shpnt; - o_shp = shpnt, shpnt = shpnt->next) { - if (retval->host_no < shpnt->host_no) { - retval->next = shpnt; - wmb(); - o_shp->next = retval; - break; + list_add_tail(&shost->sh_list, &scsi_host_list); +found: + spin_unlock(&scsi_host_list_lock); + +#ifdef CONFIG_PROC_FS + /* Add the new driver to /proc/scsi if not already there */ + if (!shost_tp->proc_dir) + scsi_proc_host_mkdir(shost_tp); + scsi_proc_host_add(shost); +#endif + + strncpy(shost->host_driverfs_dev.name, shost_tp->proc_name, + DEVICE_NAME_SIZE-1); + sprintf(shost->host_driverfs_dev.bus_id, "scsi%d", + shost->host_no); + + shost->eh_notify = &sem; + kernel_thread((int (*)(void *)) scsi_error_handler, (void *) shost, 0); + /* + * Now wait for the kernel error thread to initialize itself + * as it might be needed when we scan the bus. + */ + down(&sem); + shost->eh_notify = NULL; + + shost->hostt->present++; + + return shost; +} + + +/** + * scsi_register_host - register a low level host driver + * @shost_tp: pointer to a scsi host driver template + * + * Return value: + * 0 on Success / 1 on Failure. + **/ +int scsi_register_host(Scsi_Host_Template *shost_tp) +{ + int cur_cnt; + Scsi_Device *sdev; + struct Scsi_Device_Template *sdev_tp; + struct list_head *lh; + struct Scsi_Host *shost; + + /* + * Check no detect routine. + */ + if (!shost_tp->detect) + return 1; + + /* If max_sectors isn't set, default to max */ + if (!shost_tp->max_sectors) + shost_tp->max_sectors = 1024; + + cur_cnt = scsi_hosts_registered; + + MOD_INC_USE_COUNT; + + /* + * The detect routine must carefully spinunlock/spinlock if it + * enables interrupts, since all interrupt handlers do spinlock as + * well. + */ + + /* + * detect should do its own locking + * FIXME present is now set is scsi_register which breaks manual + * registration code below. + */ + shost_tp->detect(shost_tp); + + if (shost_tp->present) { + /* + * FIXME Who needs manual registration and why??? + */ + if (cur_cnt == scsi_hosts_registered) { + if (shost_tp->present > 1) { + printk(KERN_ERR "scsi: Failure to register" + "low-level scsi driver"); + scsi_unregister_host(shost_tp); + return 1; + } + /* + * The low-level driver failed to register a driver. + * We can do this now. + */ + if(scsi_register(shost_tp, 0)==NULL) { + printk(KERN_ERR "scsi: register failed.\n"); + scsi_unregister_host(shost_tp); + return 1; + } + } + + list_add_tail(&shost_tp->shtp_list, &scsi_host_tmpl_list); + + /* The next step is to call scan_scsis here. This generates the + * Scsi_Devices entries + */ + list_for_each(lh, &scsi_host_list) { + shost = list_entry(lh, struct Scsi_Host, sh_list); + if (shost->hostt == shost_tp) { + const char *dm_name; + if (shost_tp->info) { + dm_name = shost_tp->info(shost); + } else { + dm_name = shost_tp->name; + } + printk(KERN_INFO "scsi%d : %s\n", + shost->host_no, dm_name); + + /* first register parent with driverfs */ + device_register(&shost->host_driverfs_dev); + scan_scsis(shost, 0, 0, 0, 0); + } + } + + for (sdev_tp = scsi_devicelist; sdev_tp; + sdev_tp = sdev_tp->next) { + if (sdev_tp->init && sdev_tp->dev_noticed) + (*sdev_tp->init) (); + } + + /* + * Next we create the Scsi_Cmnd structures for this host + */ + list_for_each(lh, &scsi_host_list) { + shost = list_entry(lh, struct Scsi_Host, sh_list); + for (sdev = shost->host_queue; sdev; sdev = sdev->next) + if (sdev->host->hostt == shost_tp) { + for (sdev_tp = scsi_devicelist; + sdev_tp; + sdev_tp = sdev_tp->next) + if (sdev_tp->attach) + (*sdev_tp->attach) (sdev); + if (sdev->attached) { + scsi_build_commandblocks(sdev); + if (sdev->current_queue_depth == 0) + goto out_of_space; + } + } + } + + /* This does any final handling that is required. */ + for (sdev_tp = scsi_devicelist; sdev_tp; + sdev_tp = sdev_tp->next) { + if (sdev_tp->finish && sdev_tp->nr_dev) { + (*sdev_tp->finish) (); + } } - } - if (! shpnt) - o_shp->next = retval; - } - } - - return retval; + } + + return 0; + +out_of_space: + scsi_unregister_host(shost_tp); /* easiest way to clean up?? */ + return 1; +} + +/** + * scsi_unregister_host - unregister a low level host adapter driver + * @shost_tp: scsi host template to unregister. + * + * Description: + * Similarly, this entry point should be called by a loadable module + * if it is trying to remove a low level scsi driver from the system. + * + * Return value: + * 0 on Success / 1 on Failure + * + * Notes: + * rmmod does not care what we return here the module will be + * removed. + **/ +int scsi_unregister_host(Scsi_Host_Template *shost_tp) +{ + int pcount; + + /* get the big kernel lock, so we don't race with open() */ + lock_kernel(); + + pcount = scsi_hosts_registered; + + scsi_tp_for_each_host(shost_tp, scsi_host_chk_and_release); + + if (pcount != scsi_hosts_registered) + printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered, + (scsi_hosts_registered == 1) ? "" : "s"); + + /* + * Remove it from the list if all + * hosts were successfully removed (ie preset == 0) + */ + if (!shost_tp->present) { + list_del(&shost_tp->shtp_list); + } + + MOD_DEC_USE_COUNT; + + unlock_kernel(); + return 0; + +} + +/** + * *scsi_host_get_next - get scsi host and inc ref count + * @shost: pointer to a Scsi_Host or NULL to start. + * + * Return value: + * A pointer to next Scsi_Host in list or NULL. + **/ +struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *shost) +{ + struct list_head *lh = NULL; + + spin_lock(&scsi_host_list_lock); + if (shost) { + /* XXX Dec ref on cur shost */ + lh = shost->sh_list.next; + } else { + lh = scsi_host_list.next; + } + + if (lh == &scsi_host_list) { + shost = (struct Scsi_Host *)NULL; + goto done; + } + + shost = list_entry(lh, struct Scsi_Host, sh_list); + /* XXX Inc ref count */ + +done: + spin_unlock(&scsi_host_list_lock); + return shost; +} + +/** + * scsi_host_hn_get - get a Scsi_Host by host no and inc ref count + * @host_no: host number to locate + * + * Return value: + * A pointer to located Scsi_Host or NULL. + **/ +struct Scsi_Host *scsi_host_hn_get(unsigned short host_no) +{ + struct list_head *lh; + struct Scsi_Host *shost; + + spin_lock(&scsi_host_list_lock); + list_for_each(lh, &scsi_host_list) { + shost = list_entry(lh, struct Scsi_Host, sh_list); + if (shost->host_no == host_no) { + /* XXX Inc ref count */ + goto done; + } + } + + shost = (struct Scsi_Host *)NULL; +done: + spin_unlock(&scsi_host_list_lock); + return shost; +} + +/** + * *scsi_host_put - dec a Scsi_Host ref count + * @shost: Pointer to Scsi_Host to dec. + **/ +void scsi_host_put(struct Scsi_Host *shost) +{ + + /* XXX Get list lock */ + /* XXX dec ref count */ + /* XXX Release list lock */ + return; +} + +/** + * scsi_host_hn_init - init scsi host number list from string + * @shost_hn: string of scsi host driver names. + **/ +void __init scsi_host_hn_init(char *shost_hn) +{ + char *temp = shost_hn; + + while (temp) { + while (*temp && (*temp != ':') && (*temp != ',')) + temp++; + if (!*temp) + temp = NULL; + else + *temp++ = 0; + (void)scsi_host_hn_add(shost_hn); + shost_hn = temp; + } +} + +/** + * scsi_host_no_release - free all entries in scsi host number list + **/ +void __exit scsi_host_hn_release() +{ + struct list_head *lh, *next; + Scsi_Host_Name *shn; + + list_for_each_safe(lh, next, &scsi_host_hn_list) { + shn = list_entry(lh, Scsi_Host_Name, shn_list); + if (shn->name) + kfree(shn->name); + kfree(shn); + } } void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev) @@ -279,8 +761,7 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev) if (shost->in_recovery && (shost->host_busy == shost->host_failed)) { up(shost->eh_wait); SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - "thread (%d)\n", - atomic_read(&shost->eh_wait->count))); + " thread\n")); } spin_unlock_irqrestore(shost->host_lock, flags); } @@ -295,8 +776,7 @@ void scsi_host_failed_inc_and_test(struct Scsi_Host *shost) if (shost->host_busy == shost->host_failed) { up(shost->eh_wait); SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - "thread (%d)\n", - atomic_read(&shost->eh_wait->count))); + " thread\n")); } spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index a899c89ded0b..bf835126f727 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -16,15 +16,14 @@ * of the same type. * * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * Restructured scsi_host lists and associated functions. + * September 04, 2002 Mike Anderson (andmike@us.ibm.com) */ #ifndef _HOSTS_H #define _HOSTS_H -/* - $Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $ -*/ - #include <linux/config.h> #include <linux/proc_fs.h> #include <linux/pci.h> @@ -58,8 +57,7 @@ typedef struct scsi_disk Disk; typedef struct SHT { - /* Used with loadable modules so we can construct a linked list. */ - struct SHT * next; + struct list_head shtp_list; /* Used with loadable modules so that we know when it is safe to unload */ struct module * module; @@ -374,7 +372,7 @@ struct Scsi_Host * This information is private to the scsi mid-layer. Wrapping it in a * struct private is a way of marking it in a sort of C++ type of way. */ - struct Scsi_Host * next; + struct list_head sh_list; Scsi_Device * host_queue; struct list_head all_scsi_hosts; struct list_head my_devices; @@ -510,28 +508,26 @@ struct Scsi_Host * thing. This physical pseudo-device isn't real and won't be available * from any high-level drivers. */ -extern void scsi_free_host_dev(Scsi_Device * SDpnt); -extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt); +extern void scsi_free_host_dev(Scsi_Device *); +extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *); -extern void scsi_unblock_requests(struct Scsi_Host * SHpnt); -extern void scsi_block_requests(struct Scsi_Host * SHpnt); -extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel); +extern void scsi_unblock_requests(struct Scsi_Host *); +extern void scsi_block_requests(struct Scsi_Host *); +extern void scsi_report_bus_reset(struct Scsi_Host *, int); typedef struct SHN - { - struct SHN * next; - char * name; - unsigned short host_no; - unsigned short host_registered; - } Scsi_Host_Name; +{ + struct list_head shn_list; + char *name; + unsigned short host_no; + unsigned short host_registered; +} Scsi_Host_Name; -extern Scsi_Host_Name * scsi_host_no_list; -extern struct Scsi_Host * scsi_hostlist; extern struct Scsi_Device_Template * scsi_devicelist; -extern Scsi_Host_Template * scsi_hosts; - -extern void build_proc_dir_entries(Scsi_Host_Template *); +extern void scsi_proc_host_mkdir(Scsi_Host_Template *); +extern void scsi_proc_host_add(struct Scsi_Host *); +extern void scsi_proc_host_rm(struct Scsi_Host *); /* * scsi_init initializes the scsi hosts. @@ -540,34 +536,33 @@ extern void build_proc_dir_entries(Scsi_Host_Template *); 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); +extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int); +extern void scsi_unregister(struct Scsi_Host *); +extern void scsi_register_blocked_host(struct Scsi_Host *); +extern void scsi_deregister_blocked_host(struct Scsi_Host *); -static inline void scsi_assign_lock(struct Scsi_Host *host, spinlock_t *lock) +static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) { - host->host_lock = lock; + shost->host_lock = lock; } -static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt, +static inline void scsi_set_pci_device(struct Scsi_Host *shost, struct pci_dev *pdev) { - SHpnt->pci_dev = pdev; - SHpnt->host_driverfs_dev.parent=&pdev->dev; + shost->pci_dev = pdev; + shost->host_driverfs_dev.parent=&pdev->dev; + + /* register parent with driverfs */ + device_register(&shost->host_driverfs_dev); } /* * Prototypes for functions/data in scsi_scan.c */ -extern void scan_scsis(struct Scsi_Host *shpnt, - uint hardcoded, - uint hchannel, - uint hid, - uint hlun); +extern void scan_scsis(struct Scsi_Host *, uint, uint, uint, uint); -extern void scsi_mark_host_reset(struct Scsi_Host *Host); +extern void scsi_mark_host_reset(struct Scsi_Host *); #define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -596,7 +591,7 @@ struct Scsi_Device_Template struct device_driver scsi_driverfs_driver; }; -void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); +void scsi_initialize_queue(Scsi_Device *, struct Scsi_Host *); /* @@ -607,6 +602,12 @@ extern int scsi_unregister_device(struct Scsi_Device_Template *); extern int scsi_register_host(Scsi_Host_Template *); extern int scsi_unregister_host(Scsi_Host_Template *); +extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *); +extern struct Scsi_Host *scsi_host_hn_get(unsigned short); +extern void scsi_host_put(struct Scsi_Host *); +extern void scsi_host_hn_init(char *); +extern void scsi_host_hn_release(void); + /* * host_busy inc/dec/test functions */ @@ -614,7 +615,6 @@ extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_failed_inc_and_test(struct Scsi_Host *); - /* * This is an ugly hack. If we expect to be able to load devices at run time, * we need to leave extra room in some of the data structures. Doing a @@ -643,21 +643,22 @@ extern void scsi_host_failed_inc_and_test(struct Scsi_Host *); /** * scsi_find_device - find a device given the host + * @shost: SCSI host pointer * @channel: SCSI channel (zero if only one channel) * @pun: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number **/ -static inline Scsi_Device *scsi_find_device(struct Scsi_Host *host, +static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost, int channel, int pun, int lun) { - Scsi_Device *SDpnt; + Scsi_Device *sdev; - for(SDpnt = host->host_queue; - SDpnt != NULL; - SDpnt = SDpnt->next) - if(SDpnt->channel == channel && SDpnt->id == pun - && SDpnt->lun ==lun) + for (sdev = shost->host_queue; + sdev != NULL; + sdev = sdev->next) + if (sdev->channel == channel && sdev->id == pun + && sdev->lun ==lun) break; - return SDpnt; + return sdev; } #endif diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 13d2ecb5a6ba..9e0c43d5ae97 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -407,7 +407,6 @@ */ #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) #define IPS { \ - next : NULL, \ module : NULL, \ proc_info : NULL, \ proc_dir : NULL, \ @@ -437,7 +436,6 @@ } #elif LINUX_VERSION_CODE < LinuxVersionCode(2,5,0) #define IPS { \ - next : NULL, \ module : NULL, \ proc_info : NULL, \ name : NULL, \ @@ -466,7 +464,6 @@ } #else #define IPS { \ - next : NULL, \ module : NULL, \ proc_info : NULL, \ name : NULL, \ diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index fc5f5aa2f1bb..99c8a8f2f26c 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -322,8 +322,6 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, } } - if (SRpnt->sr_device->scsi_level <= SCSI_2) - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; init_completion(&STp->wait); SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 5882c11b1ac9..f466b76ca6e2 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -294,7 +294,8 @@ static void aha152x_config_cs(dev_link_t *link) tail = &link->dev; info->ndev = 0; - for (host = scsi_hostlist; host; host = host->next) + for (host = scsi_host_get_next(NULL); host; + host = scsi_host_get_next(host)) if (host->hostt == &driver_template) for (dev = host->host_queue; dev; dev = dev->next) { u_long arg[2], id; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 3149c5bb8596..d8e6294cc667 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -258,7 +258,8 @@ static void fdomain_config(dev_link_t *link) tail = &link->dev; info->ndev = 0; - for (host = scsi_hostlist; host; host = host->next) + for (host = scsi_host_get_next(NULL); host; + host = scsi_host_get_next(host)) if (host->hostt == &driver_template) for (dev = host->host_queue; dev; dev = dev->next) { u_long arg[2], id; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index fc521c26e672..82916db1c391 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1520,7 +1520,8 @@ static void nsp_cs_config(dev_link_t *link) DEBUG(0, "GET_SCSI_INFO\n"); tail = &link->dev; info->ndev = 0; - for (host = scsi_hostlist; host != NULL; host = host->next) { + for (host = scsi_host_get_next(NULL); host; + host = scsi_host_get_next(host)) if (host->hostt == &driver_template) { for (dev = host->host_queue; dev != NULL; dev = dev->next) { u_long arg[2], id; diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 0bfa59d14e5f..6e01a0c82fae 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -281,7 +281,8 @@ static void qlogic_config(dev_link_t *link) tail = &link->dev; info->ndev = 0; - for (host = scsi_hostlist; host; host = host->next) + for (host = scsi_host_get_next(NULL); host; + host = scsi_host_get_next(host)) if (host->hostt == &driver_template) for (dev = host->host_queue; dev; dev = dev->next) { u_long arg[2], id; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d05400f6d047..6df3f92793e8 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -798,6 +798,12 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) serial_number = 1; SCpnt->serial_number = serial_number; SCpnt->pid = scsi_pid++; + /* + * If SCSI-2 or lower, store the LUN value in cmnd. + */ + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = (SCpnt->cmnd[1] & 0x1f) | + (SCpnt->lun << 5 & 0xe0); /* * We will wait MIN_RESET_DELAY clock ticks after the last reset so @@ -1659,33 +1665,6 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags) } } -void __init scsi_host_no_insert(char *str, int n) -{ - Scsi_Host_Name *shn, *shn2; - int len; - - len = strlen(str); - if (len && (shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC))) { - if ((shn->name = kmalloc(len+1, GFP_ATOMIC))) { - strncpy(shn->name, str, len); - shn->name[len] = 0; - shn->host_no = n; - shn->host_registered = 0; - shn->next = NULL; - if (scsi_host_no_list) { - for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next) - ; - shn2->next = shn; - } - else - scsi_host_no_list = shn; - max_scsi_hosts = n+1; - } - else - kfree((char *) shn); - } -} - #ifdef CONFIG_PROC_FS static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) { @@ -1698,7 +1677,8 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) /* * First, see if there are any attached devices or not. */ - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr; + HBA_ptr = scsi_host_get_next(HBA_ptr)) { if (HBA_ptr->host_queue != NULL) { break; } @@ -1706,7 +1686,8 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none"); len += size; pos = begin + len; - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr; + HBA_ptr = scsi_host_get_next(HBA_ptr)) { #if 0 size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname); @@ -1873,7 +1854,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel, id, lun); - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr; + HBA_ptr = scsi_host_get_next(HBA_ptr)) { if (HBA_ptr->host_no == host) { break; } @@ -1918,7 +1900,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, lun = simple_strtoul(p + 1, &p, 0); - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr; + HBA_ptr = scsi_host_get_next(HBA_ptr)) { if (HBA_ptr->host_no == host) { break; } @@ -1988,369 +1971,6 @@ out: #endif /* - * This entry point should be called by a driver if it is trying - * to add a low level scsi driver to the system. - */ -int scsi_register_host(Scsi_Host_Template * tpnt) -{ - int pcount; - struct Scsi_Host *shpnt; - Scsi_Device *SDpnt; - struct Scsi_Device_Template *sdtpnt; - const char *name; - int out_of_space = 0; - - if (tpnt->next || !tpnt->detect) - return 1; /* Must be already loaded, or - * no detect routine available - */ - - /* If max_sectors isn't set, default to max */ - if (!tpnt->max_sectors) - tpnt->max_sectors = 1024; - - pcount = next_scsi_host; - - MOD_INC_USE_COUNT; - - /* The detect routine must carefully spinunlock/spinlock if - it enables interrupts, since all interrupt handlers do - spinlock as well. */ - - /* - * detect should do its own locking - */ - tpnt->present = tpnt->detect(tpnt); - - if (tpnt->present) { - if (pcount == next_scsi_host) { - if (tpnt->present > 1) { - printk(KERN_ERR "scsi: Failure to register low-level scsi driver"); - scsi_unregister_host(tpnt); - return 1; - } - /* - * The low-level driver failed to register a driver. - * We can do this now. - */ - if(scsi_register(tpnt, 0)==NULL) - { - printk(KERN_ERR "scsi: register failed.\n"); - scsi_unregister_host(tpnt); - return 1; - } - } - tpnt->next = scsi_hosts; /* Add to the linked list */ - scsi_hosts = tpnt; - - /* Add the new driver to /proc/scsi */ -#ifdef CONFIG_PROC_FS - build_proc_dir_entries(tpnt); -#endif - - - /* - * Add the kernel threads for each host adapter that will - * handle error correction. - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt == tpnt) { - DECLARE_MUTEX_LOCKED(sem); - - shpnt->eh_notify = &sem; - kernel_thread((int (*)(void *)) scsi_error_handler, - (void *) shpnt, 0); - - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - down(&sem); - shpnt->eh_notify = NULL; - } - } - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt == tpnt) { - if (tpnt->info) { - name = tpnt->info(shpnt); - } else { - name = tpnt->name; - } - printk(KERN_INFO "scsi%d : %s\n", /* And print a little message */ - shpnt->host_no, name); - strncpy(shpnt->host_driverfs_dev.name,name, - DEVICE_NAME_SIZE-1); - sprintf(shpnt->host_driverfs_dev.bus_id, - "scsi%d", - shpnt->host_no); - } - } - - /* The next step is to call scan_scsis here. This generates the - * Scsi_Devices entries - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt == tpnt) { - /* first register parent with driverfs */ - device_register(&shpnt->host_driverfs_dev); - scan_scsis(shpnt, 0, 0, 0, 0); - } - } - - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { - if (sdtpnt->init && sdtpnt->dev_noticed) - (*sdtpnt->init) (); - } - - /* - * Next we create the Scsi_Cmnd structures for this host - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) - if (SDpnt->host->hostt == tpnt) { - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->attach) - (*sdtpnt->attach) (SDpnt); - if (SDpnt->attached) { - scsi_build_commandblocks(SDpnt); - if (SDpnt->current_queue_depth == 0) - out_of_space = 1; - } - } - } - - /* This does any final handling that is required. */ - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { - if (sdtpnt->finish && sdtpnt->nr_dev) { - (*sdtpnt->finish) (); - } - } - } - - if (out_of_space) { - scsi_unregister_host(tpnt); /* easiest way to clean up?? */ - return 1; - } else - return 0; -} - -/* - * Similarly, this entry point should be called by a loadable module if it - * is trying to remove a low level scsi driver from the system. - */ -int scsi_unregister_host(Scsi_Host_Template * tpnt) -{ - int online_status; - int pcount0, pcount; - Scsi_Cmnd *SCpnt; - Scsi_Device *SDpnt; - Scsi_Device *SDpnt1; - struct Scsi_Device_Template *sdtpnt; - struct Scsi_Host *sh1; - struct Scsi_Host *shpnt; - char name[10]; /* host_no>=10^9? I don't think so. */ - - /* get the big kernel lock, so we don't race with open() */ - lock_kernel(); - - /* - * First verify that this host adapter is completely free with no pending - * commands - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - for (SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) { - if (SDpnt->host->hostt == tpnt - && SDpnt->host->hostt->module - && GET_USE_COUNT(SDpnt->host->hostt->module)) - goto err_out; - /* - * FIXME(eric) - We need to find a way to notify the - * low level driver that we are shutting down - via the - * special device entry that still needs to get added. - * - * Is detach interface below good enough for this? - */ - } - } - - /* - * FIXME(eric) put a spinlock on this. We force all of the devices offline - * to help prevent race conditions where other hosts/processors could try and - * get in and queue a command. - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - for (SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) { - if (SDpnt->host->hostt == tpnt) - SDpnt->online = FALSE; - - } - } - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt != tpnt) { - continue; - } - for (SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) { - /* - * Loop over all of the commands associated with the device. If any of - * them are busy, then set the state back to inactive and bail. - */ - for (SCpnt = SDpnt->device_queue; SCpnt; - SCpnt = SCpnt->next) { - online_status = SDpnt->online; - SDpnt->online = FALSE; - if (SCpnt->request && SCpnt->request->rq_status != RQ_INACTIVE) { - printk(KERN_ERR "SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n", - SCpnt->request->rq_status, SCpnt->target, SCpnt->pid, - SCpnt->state, SCpnt->owner); - for (SDpnt1 = shpnt->host_queue; SDpnt1; - SDpnt1 = SDpnt1->next) { - for (SCpnt = SDpnt1->device_queue; SCpnt; - SCpnt = SCpnt->next) - if (SCpnt->request->rq_status == RQ_SCSI_DISCONNECTING) - SCpnt->request->rq_status = RQ_INACTIVE; - } - SDpnt->online = online_status; - printk(KERN_ERR "Device busy???\n"); - goto err_out; - } - /* - * No, this device is really free. Mark it as such, and - * continue on. - */ - SCpnt->state = SCSI_STATE_DISCONNECTING; - if(SCpnt->request) - SCpnt->request->rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ - } - } - } - /* Next we detach the high level drivers from the Scsi_Device structures */ - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt != tpnt) { - continue; - } - for (SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) { - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->detach) - (*sdtpnt->detach) (SDpnt); - - /* If something still attached, punt */ - if (SDpnt->attached) { - printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached); - goto err_out; - } - if (shpnt->hostt->slave_detach) - (*shpnt->hostt->slave_detach) (SDpnt); - devfs_unregister (SDpnt->de); - put_device(&SDpnt->sdev_driverfs_dev); - } - } - - /* - * Next, kill the kernel error recovery thread for this host. - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt == tpnt - && shpnt->ehandler != NULL) { - DECLARE_MUTEX_LOCKED(sem); - - shpnt->eh_notify = &sem; - send_sig(SIGHUP, shpnt->ehandler, 1); - down(&sem); - shpnt->eh_notify = NULL; - } - } - - /* Next we free up the Scsi_Cmnd structures for this host */ - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostt != tpnt) { - continue; - } - for (SDpnt = shpnt->host_queue; SDpnt; - SDpnt = shpnt->host_queue) { - scsi_release_commandblocks(SDpnt); - - blk_cleanup_queue(&SDpnt->request_queue); - /* Next free up the Scsi_Device structures for this host */ - shpnt->host_queue = SDpnt->next; - if (SDpnt->inquiry) - kfree(SDpnt->inquiry); - kfree((char *) SDpnt); - - } - } - - /* Next we go through and remove the instances of the individual hosts - * that were detected */ - - pcount0 = next_scsi_host; - for (shpnt = scsi_hostlist; shpnt; shpnt = sh1) { - sh1 = shpnt->next; - if (shpnt->hostt != tpnt) - continue; - pcount = next_scsi_host; - /* Remove the /proc/scsi directory entry */ - sprintf(name,"%d",shpnt->host_no); - remove_proc_entry(name, tpnt->proc_dir); - put_device(&shpnt->host_driverfs_dev); - if (tpnt->release) - (*tpnt->release) (shpnt); - else { - /* This is the default case for the release function. - * It should do the right thing for most correctly - * written host adapters. - */ - if (shpnt->irq) - free_irq(shpnt->irq, NULL); - if (shpnt->dma_channel != 0xff) - free_dma(shpnt->dma_channel); - if (shpnt->io_port && shpnt->n_io_port) - release_region(shpnt->io_port, shpnt->n_io_port); - } - if (pcount == next_scsi_host) - scsi_unregister(shpnt); - tpnt->present--; - } - - if (pcount0 != next_scsi_host) - printk(KERN_INFO "scsi : %d host%s left.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); - - /* - * Remove it from the linked list and /proc if all - * hosts were successfully removed (ie preset == 0) - */ - if (!tpnt->present) { - Scsi_Host_Template **SHTp = &scsi_hosts; - Scsi_Host_Template *SHT; - - while ((SHT = *SHTp) != NULL) { - if (SHT == tpnt) { - *SHTp = SHT->next; - remove_proc_entry(tpnt->proc_name, proc_scsi); - break; - } - SHTp = &SHT->next; - } - } - MOD_DEC_USE_COUNT; - - unlock_kernel(); - return 0; - -err_out: - unlock_kernel(); - return -1; -} - -/* * This entry point should be called by a loadable module if it is trying * add a high level scsi driver to the system. */ @@ -2361,7 +1981,7 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) int out_of_space = 0; #ifdef CONFIG_KMOD - if (scsi_hosts == NULL) + if (scsi_host_get_next(NULL) == NULL) request_module("scsi_hostadapter"); #endif @@ -2375,7 +1995,8 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) * First scan the devices that we know about, and see if we notice them. */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (shpnt = scsi_host_get_next(NULL); shpnt; + shpnt = scsi_host_get_next(shpnt)) { for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { if (tpnt->detect) @@ -2394,7 +2015,8 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) /* * Now actually connect the devices to the new driver. */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (shpnt = scsi_host_get_next(NULL); shpnt; + shpnt = scsi_host_get_next(shpnt)) { for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { if (tpnt->attach) @@ -2444,7 +2066,8 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt) * Next, detach the devices from the driver. */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (shpnt = scsi_host_get_next(NULL); shpnt; + shpnt = scsi_host_get_next(shpnt)) { for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { if (tpnt->detach) @@ -2516,7 +2139,8 @@ static void scsi_dump_status(int level) Scsi_Device *SDpnt; printk(KERN_INFO "Dump of scsi host parameters:\n"); i = 0; - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (shpnt = scsi_host_get_next(NULL); shpnt; + shpnt = scsi_host_get_next(shpnt)) { printk(KERN_INFO " %d %d %d : %d %d\n", shpnt->host_failed, shpnt->host_busy, @@ -2527,7 +2151,8 @@ static void scsi_dump_status(int level) printk(KERN_INFO "\n\n"); printk(KERN_INFO "Dump of scsi command parameters:\n"); - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (shpnt = scsi_host_get_next(NULL); shpnt; + shpnt = scsi_host_get_next(shpnt)) { printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n"); for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { @@ -2565,26 +2190,6 @@ static void scsi_dump_status(int level) } #endif /* CONFIG_PROC_FS */ -static int __init scsi_host_no_init (char *str) -{ - static int next_no = 0; - char *temp; - - while (str) { - temp = str; - while (*temp && (*temp != ':') && (*temp != ',')) - temp++; - if (!*temp) - temp = NULL; - else - *temp++ = 0; - scsi_host_no_insert(str, next_no); - str = temp; - next_no++; - } - return 1; -} - static char *scsihosts; MODULE_PARM(scsihosts, "s"); @@ -2724,9 +2329,8 @@ static int __init init_scsi(void) #endif scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL); - if (scsihosts) - printk(KERN_INFO "scsi: host order: %s\n", scsihosts); - scsi_host_no_init (scsihosts); + + scsi_host_hn_init(scsihosts); bus_register(&scsi_driverfs_bus_type); @@ -2738,19 +2342,11 @@ static int __init init_scsi(void) static void __exit exit_scsi(void) { - Scsi_Host_Name *shn, *shn2 = NULL; int i; devfs_unregister (scsi_devfs_handle); - for (shn = scsi_host_no_list;shn;shn = shn->next) { - if (shn->name) - kfree(shn->name); - if (shn2) - kfree (shn2); - shn2 = shn; - } - if (shn2) - kfree (shn2); + + scsi_host_hn_release(); #ifdef CONFIG_PROC_FS /* No, we're not here anymore. Don't show the /proc/scsi files. */ diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index f616c4b8cdf7..710e34267961 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -877,6 +877,12 @@ struct scsi_cmnd { extern int scsi_reset_provider(Scsi_Device *, int); +#define MSG_SIMPLE_TAG 0x20 +#define MSG_HEAD_TAG 0x21 +#define MSG_ORDERED_TAG 0x22 + +#define SCSI_NO_TAG (-1) /* identify no tag in use */ + /** * scsi_activate_tcq - turn on tag command queueing * @SDpnt: device to turn on TCQ for @@ -892,7 +898,7 @@ static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { if(SDpnt->tagged_supported && !blk_queue_tagged(q)) { blk_queue_init_tags(q, depth); - SDpnt->tagged_queue = 1; + scsi_adjust_queue_depth(SDpnt, MSG_ORDERED_TAG, depth); } } @@ -902,13 +908,8 @@ static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { **/ static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt) { blk_queue_free_tags(&SDpnt->request_queue); - SDpnt->tagged_queue = 0; + scsi_adjust_queue_depth(SDpnt, 0, 2); } -#define MSG_SIMPLE_TAG 0x20 -#define MSG_HEAD_TAG 0x21 -#define MSG_ORDERED_TAG 0x22 - -#define SCSI_NO_TAG (-1) /* identify no tag in use */ /** * scsi_populate_tag_msg - place a tag message in a buffer diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 44628796d12e..d32b1a65d6ee 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -108,9 +108,13 @@ static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; #define SDEBUG_SENSE_LEN 32 struct sdebug_dev_info { - Scsi_Device * sdp; unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ + unsigned int channel; + unsigned int target; + unsigned int lun; + struct Scsi_Host *host; char reset; + char used; }; static struct sdebug_dev_info * devInfop; @@ -154,7 +158,7 @@ static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, static int resp_report_luns(unsigned char * cmd, unsigned char * buff, int bufflen, struct sdebug_dev_info * devip); static void timer_intr_handler(unsigned long); -static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp); +static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd); static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, int asc, int asq, int inbandLen); static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip); @@ -222,7 +226,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) return schedule_resp(SCpnt, NULL, done, 0, 0); } - if ((target > driver_template.this_id) || (SCpnt->lun != 0)) + if (SCpnt->lun != 0) return schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16, 0); #if 0 @@ -230,14 +234,10 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) (int)SCpnt->device->host->host_no, (int)SCpnt->device->id, SCpnt->device, (int)*cmd); #endif - if (NULL == SCpnt->device->hostdata) { - devip = devInfoReg(SCpnt->device); - if (NULL == devip) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - SCpnt->device->hostdata = devip; - } - devip = SCpnt->device->hostdata; + devip = devInfoReg(SCpnt); + if (NULL == devip) + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); if ((SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts) && (scsi_debug_every_nth > 0) && @@ -474,8 +474,8 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, int dev_id_num, len; char dev_id_str[6]; - dev_id_num = ((devip->sdp->host->host_no + 1) * 1000) + - devip->sdp->id; + dev_id_num = ((devip->host->host_no + 1) * 1000) + + devip->target; len = snprintf(dev_id_str, 6, "%d", dev_id_num); len = (len > 6) ? 6 : len; if (0 == cmd[2]) { /* supported vital product data pages */ @@ -861,8 +861,7 @@ static int scsi_debug_release(struct Scsi_Host * hpnt) if (++num_releases == num_present) { #ifdef DRIVERFS_SUPPORT do_remove_driverfs_files(); - remove_driver(&sdebug_driverfs_driver); - // driver_unregister(&sdebug_driverfs_driver); + driver_unregister(&sdebug_driverfs_driver); #endif vfree(fake_storep); vfree(devInfop); @@ -870,21 +869,28 @@ static int scsi_debug_release(struct Scsi_Host * hpnt) return 0; } -static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp) +static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd) { int k; struct sdebug_dev_info * devip; for (k = 0; k < scsi_debug_num_devs; ++k) { devip = &devInfop[k]; - if (devip->sdp == sdp) + if ((devip->channel == scmd->channel) && + (devip->target == scmd->target) && + (devip->lun == scmd->lun) && + (devip->host == scmd->host)) return devip; } for (k = 0; k < scsi_debug_num_devs; ++k) { devip = &devInfop[k]; - if (NULL == devip->sdp) { - devip->sdp = sdp; + if (!devip->used) { + devip->channel = scmd->channel; + devip->target = scmd->target; + devip->lun = scmd->lun; + devip->host = scmd->host; devip->reset = 1; + devip->used = 1; memset(devip->sense_buff, 0, SDEBUG_SENSE_LEN); devip->sense_buff[0] = 0x70; return devip; @@ -934,19 +940,15 @@ static int scsi_debug_biosparam(Disk * disk, struct block_device * bdev, static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) { - Scsi_Device * sdp; - int k; + struct sdebug_dev_info * devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: device_reset\n"); ++num_dev_resets; - if (SCpnt && ((sdp = SCpnt->device))) { - for (k = 0; k < scsi_debug_num_devs; ++k) { - if (sdp->hostdata == (devInfop + k)) - break; - } - if (k < scsi_debug_num_devs) - devInfop[k].reset = 1; + if (SCpnt) { + devip = devInfoReg(SCpnt); + if (devip) + devip->reset = 1; } return SUCCESS; } @@ -960,9 +962,9 @@ static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: bus_reset\n"); ++num_bus_resets; - if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { + if (SCpnt && ((sdp = SCpnt->device)) && ((hp = SCpnt->host))) { for (k = 0; k < scsi_debug_num_devs; ++k) { - if (hp == devInfop[k].sdp->host) + if (hp == devInfop[k].host) devInfop[k].reset = 1; } } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 386857db783d..3d9ed3f4442e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -502,6 +502,10 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) */ scmd->owner = SCSI_OWNER_LOWLEVEL; + if (scmd->device->scsi_level <= SCSI_2) + scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | + (scmd->lun << 5 & 0xe0); + if (host->can_queue) { DECLARE_MUTEX_LOCKED(sem); @@ -610,9 +614,6 @@ static int scsi_request_sense(Scsi_Cmnd *scmd) memcpy((void *) scmd->cmnd, (void *) generic_sense, sizeof(generic_sense)); - if (scmd->device->scsi_level <= SCSI_2) - scmd->cmnd[1] = scmd->lun << 5; - scsi_result = (!scmd->host->hostt->unchecked_isa_dma) ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); @@ -839,9 +840,6 @@ retry_tur: memcpy((void *) scmd->cmnd, (void *) tur_command, sizeof(tur_command)); - if (scmd->device->scsi_level <= SCSI_2) - scmd->cmnd[1] = scmd->lun << 5; - /* * zero the sense buffer. the scsi spec mandates that any * untransferred sense data should be interpreted as being zero. @@ -1419,7 +1417,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) } sreq->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL; - sreq->sr_cmnd[1] = (sdev->scsi_level <= SCSI_2) ? (sdev->lun << 5) : 0; + sreq->sr_cmnd[1] = 0; sreq->sr_cmnd[2] = 0; sreq->sr_cmnd[3] = 0; sreq->sr_cmnd[4] = SCSI_REMOVAL_PREVENT; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index d1c431cc4017..f2676bf18282 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -160,7 +160,7 @@ int scsi_set_medium_removal(Scsi_Device *dev, char state) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; + scsi_cmd[1] = 0; scsi_cmd[2] = 0; scsi_cmd[3] = 0; scsi_cmd[4] = state; @@ -297,12 +297,6 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) if(copy_from_user(buf, cmd_in + cmdlen, inlen)) goto error; - /* - * Set the lun field to the correct value. - */ - if (dev->scsi_level <= SCSI_2) - cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); - switch (opcode) { case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; @@ -416,7 +410,6 @@ scsi_ioctl_get_pci(Scsi_Device * dev, void *arg) int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; - char cmd_byte1; /* No idea how this happens.... */ if (!dev) @@ -431,7 +424,6 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) if (!scsi_block_when_processing_errors(dev)) { return -ENODEV; } - cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; switch (cmd) { case SCSI_IOCTL_GET_IDLUN: @@ -484,7 +476,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = cmd_byte1; + scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -492,7 +484,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) break; case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = cmd_byte1; + scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 1; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -500,7 +492,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) break; case SCSI_IOCTL_STOP_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = cmd_byte1; + scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a73a677e6818..dfa18e0c0eb9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -857,7 +857,7 @@ void scsi_request_fn(request_queue_t * q) scsi_init_cmd_from_req(SCpnt, SRpnt); } - } else if (req->flags & REQ_CMD) { + } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { SRpnt = NULL; STpnt = scsi_get_request_dev(req); if (!STpnt) { @@ -919,7 +919,7 @@ void scsi_request_fn(request_queue_t * q) req = NULL; spin_unlock_irq(q->queue_lock); - if (SCpnt->request->flags & REQ_CMD) { + if (SCpnt->request->flags & (REQ_CMD | REQ_BLOCK_PC)) { /* * This will do a couple of things: * 1) Fill in the actual SCSI command. diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c index 980d7047e6e9..ac79b081270c 100644 --- a/drivers/scsi/scsi_merge.c +++ b/drivers/scsi/scsi_merge.c @@ -62,16 +62,28 @@ int scsi_init_io(Scsi_Cmnd *SCpnt) int count, gfp_mask; /* - * First we need to know how many scatter gather segments are needed. + * non-sg block request. FIXME: check bouncing for isa hosts! */ - count = req->nr_phys_segments; + if ((req->flags & REQ_BLOCK_PC) && !req->bio) { + /* + * FIXME: isa bouncing + */ + if (SCpnt->host->unchecked_isa_dma) + goto fail; + + SCpnt->request_bufflen = req->data_len; + SCpnt->request_buffer = req->data; + req->buffer = req->data; + SCpnt->use_sg = 0; + return 1; + } /* * we used to not use scatter-gather for single segment request, * but now we do (it makes highmem I/O easier to support without * kmapping pages) */ - SCpnt->use_sg = count; + SCpnt->use_sg = req->nr_phys_segments; gfp_mask = GFP_NOIO; if (in_interrupt()) { @@ -111,6 +123,7 @@ int scsi_init_io(Scsi_Cmnd *SCpnt) /* * kill it. there should be no leftover blocks in this request */ +fail: SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors); BUG_ON(SCpnt); return 0; diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 2f7e4adcc360..7f49373be381 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -119,35 +119,44 @@ static int proc_scsi_write(struct file * file, const char * buf, return(ret); } -void build_proc_dir_entries(Scsi_Host_Template * tpnt) +void scsi_proc_host_mkdir(Scsi_Host_Template *shost_tp) { - struct Scsi_Host *hpnt; - char name[10]; /* see scsi_unregister_host() */ - - tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi); - if (!tpnt->proc_dir) { - printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries"); + shost_tp->proc_dir = proc_mkdir(shost_tp->proc_name, proc_scsi); + if (!shost_tp->proc_dir) { + printk(KERN_ERR "%s: proc_mkdir failed for %s\n", + __FUNCTION__, shost_tp->proc_name); return; } - tpnt->proc_dir->owner = tpnt->module; - - hpnt = scsi_hostlist; - while (hpnt) { - if (tpnt == hpnt->hostt) { - struct proc_dir_entry *p; - sprintf(name,"%d",hpnt->host_no); - p = create_proc_read_entry(name, - S_IFREG | S_IRUGO | S_IWUSR, - tpnt->proc_dir, - proc_scsi_read, - (void *)hpnt); - if (!p) - panic("Not enough memory to register SCSI HBA in /proc/scsi !\n"); - p->write_proc=proc_scsi_write; - p->owner = tpnt->module; - } - hpnt = hpnt->next; + shost_tp->proc_dir->owner = shost_tp->module; +} + +void scsi_proc_host_add(struct Scsi_Host *shost) +{ + char name[10]; + struct proc_dir_entry *p; + + sprintf(name,"%d",shost->host_no); + p = create_proc_read_entry(name, + S_IFREG | S_IRUGO | S_IWUSR, + shost->hostt->proc_dir, + proc_scsi_read, + (void *)shost); + if (!p) { + printk(KERN_ERR "%s: Failed to register host %d in" + "%s\n", __FUNCTION__, shost->host_no, + shost->hostt->proc_name); + } else { + p->write_proc=proc_scsi_write; + p->owner = shost->hostt->module; } + +} + +void scsi_proc_host_rm(struct Scsi_Host *shost) +{ + char name[10]; + sprintf(name,"%d",shost->host_no); + remove_proc_entry(name, shost->hostt->proc_dir); } /* diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6d174708da82..bbd593135c11 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -291,15 +291,11 @@ __setup("max_scsi_report_luns=", scsi_report_luns_setup); **/ static void scsi_unlock_floptical(Scsi_Request *sreq, unsigned char *result) { - Scsi_Device *sdscan = sreq->sr_device; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; printk(KERN_NOTICE "scsi: unlocking floptical drive\n"); scsi_cmd[0] = MODE_SENSE; - if (sdscan->scsi_level <= SCSI_2) - scsi_cmd[1] = (sdscan->lun << 5) & 0xe0; - else - scsi_cmd[1] = 0; + scsi_cmd[1] = 0; scsi_cmd[2] = 0x2e; scsi_cmd[3] = 0; scsi_cmd[4] = 0x2a; /* size */ @@ -611,8 +607,6 @@ unsigned char *scsi_get_evpd_page(Scsi_Device *sdev, Scsi_Request *sreq) { unsigned char *evpd_page; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; - int lun = sdev->lun; - int scsi_level = sdev->scsi_level; int max_lgth = 255; retry: @@ -629,10 +623,7 @@ retry: memset(scsi_cmd, 0, MAX_COMMAND_SIZE); scsi_cmd[0] = INQUIRY; - if ((lun > 0) && (scsi_level <= SCSI_2)) - scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; - else - scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[1] = 0x01; scsi_cmd[4] = max_lgth; sreq->sr_cmd_len = 0; sreq->sr_sense_buffer[0] = 0; @@ -870,8 +861,6 @@ int scsi_get_deviceid(Scsi_Device *sdev, Scsi_Request *sreq) unsigned char *id_page; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int id_idx, scnt, ret; - int lun = sdev->lun; - int scsi_level = sdev->scsi_level; int max_lgth = 255; retry: @@ -888,10 +877,7 @@ retry: memset(scsi_cmd, 0, MAX_COMMAND_SIZE); scsi_cmd[0] = INQUIRY; - if ((lun > 0) && (scsi_level <= SCSI_2)) - scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; - else - scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[1] = 0x01; scsi_cmd[2] = 0x83; scsi_cmd[4] = max_lgth; sreq->sr_cmd_len = 0; @@ -977,8 +963,6 @@ int scsi_get_serialnumber(Scsi_Device *sdev, Scsi_Request *sreq) { unsigned char *serialnumber_page; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; - int lun = sdev->lun; - int scsi_level = sdev->scsi_level; int max_lgth = 255; retry: @@ -995,10 +979,7 @@ int scsi_get_serialnumber(Scsi_Device *sdev, Scsi_Request *sreq) memset(scsi_cmd, 0, MAX_COMMAND_SIZE); scsi_cmd[0] = INQUIRY; - if ((lun > 0) && (scsi_level <= SCSI_2)) - scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; - else - scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[1] = 0x01; scsi_cmd[2] = 0x80; scsi_cmd[4] = max_lgth; sreq->sr_cmd_len = 0; @@ -1181,8 +1162,6 @@ static void scsi_probe_lun(Scsi_Request *sreq, char *inq_result, memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; - if ((sdev->lun > 0) && (sdev->scsi_level <= SCSI_2)) - scsi_cmd[1] = (sdev->lun << 5) & 0xe0; scsi_cmd[4] = 36; /* issue conservative alloc_length */ sreq->sr_cmd_len = 0; sreq->sr_data_direction = SCSI_DATA_READ; @@ -1230,8 +1209,6 @@ static void scsi_probe_lun(Scsi_Request *sreq, char *inq_result, if (possible_inq_resp_len > 36) { /* do additional INQUIRY */ memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; - if ((sdev->lun > 0) && (sdev->scsi_level <= SCSI_2)) - scsi_cmd[1] = (sdev->lun << 5) & 0xe0; scsi_cmd[4] = (unsigned char) possible_inq_resp_len; sreq->sr_cmd_len = 0; sreq->sr_data_direction = SCSI_DATA_READ; diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index e85aeca9d8e6..bd4e8d0dc859 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -91,8 +91,9 @@ EXPORT_SYMBOL(scsi_reset_provider); /* * These are here only while I debug the rest of the scsi stuff. */ -EXPORT_SYMBOL(scsi_hostlist); -EXPORT_SYMBOL(scsi_hosts); +EXPORT_SYMBOL(scsi_host_get_next); +EXPORT_SYMBOL(scsi_host_hn_get); +EXPORT_SYMBOL(scsi_host_put); EXPORT_SYMBOL(scsi_devicelist); EXPORT_SYMBOL(scsi_device_types); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1b7abd00b167..e5f80585a33b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -51,7 +51,6 @@ #define MAJOR_NR SCSI_DISK0_MAJOR #define LOCAL_END_REQUEST -#define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4)) #include <linux/blk.h> #include <linux/blkpg.h> #include "scsi.h" @@ -87,10 +86,10 @@ static Scsi_Disk ** sd_dsk_arr; static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED; -static int check_scsidisk_media_change(kdev_t); -static int sd_revalidate(kdev_t); +static int check_scsidisk_media_change(struct gendisk *); +static int sd_revalidate(struct gendisk *); -static void sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr); +static void sd_init_onedisk(Scsi_Disk * sdkp, struct gendisk *disk); static int sd_init(void); static void sd_finish(void); @@ -187,17 +186,16 @@ sd_find_target(void *hp, int scsi_id) static int sd_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { - kdev_t dev = inode->i_rdev; - Scsi_Disk * sdkp; - struct Scsi_Host * host; - Scsi_Device * sdp; + struct gendisk *disk = inode->i_bdev->bd_disk; + Scsi_Disk *sdkp = disk->private_data; + Scsi_Device *sdp = sdkp->device; + struct Scsi_Host *host; int diskinfo[4]; - int dsk_nr = DEVICE_NR(dev); + int error; - SCSI_LOG_IOCTL(1, printk("sd_ioctl: dsk_nr=%d, cmd=0x%x\n", - dsk_nr, cmd)); - sdkp = sd_get_sdisk(dsk_nr); - if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) + SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", + disk->disk_name, cmd)); + if (!sdp) return -ENODEV; /* * If we are in the middle of error recovery, don't let anyone @@ -209,6 +207,10 @@ static int sd_ioctl(struct inode * inode, struct file * filp, if( !scsi_block_when_processing_errors(sdp) ) return -ENODEV; + error = scsi_cmd_ioctl(inode->i_bdev, cmd, arg); + if (error != -ENOTTY) + return error; + switch (cmd) { case HDIO_GETGEO: /* Return BIOS disk parameters */ @@ -264,29 +266,6 @@ static void sd_dskname(unsigned int dsk_nr, char *buffer) } } -/** - * sd_find_queue - yields queue associated with device - * @dev: kernel device descriptor (kdev_t) - * - * Returns NULL if no match, otherwise returns pointer to associated - * request queue. - * - * Note: this function is invoked (often) from the block subsystem - * and should not wait on anything (sd_get_sdisk() does have a read - * spinlock). - **/ -static request_queue_t *sd_find_queue(kdev_t dev) -{ - Scsi_Disk *sdkp; - int dsk_nr = DEVICE_NR(dev); - - sdkp = sd_get_sdisk(dsk_nr); - if (sdkp && sdkp->device) - return &sdkp->device->request_queue; - else - return NULL; /* No such device */ -} - static struct gendisk **sd_disks; /** @@ -299,33 +278,54 @@ static struct gendisk **sd_disks; **/ static int sd_init_command(Scsi_Cmnd * SCpnt) { - int dsk_nr, part_nr, this_count; + int this_count, timeout; + struct gendisk *disk; sector_t block; - Scsi_Device *sdp; -#if CONFIG_SCSI_LOGGING - char nbuff[6]; -#endif + Scsi_Device *sdp = SCpnt->device; + + timeout = SD_TIMEOUT; + if (SCpnt->device->type != TYPE_DISK) + timeout = SD_MOD_TIMEOUT; + /* - * don't support specials for nwo + * these are already setup, just copy cdb basically + */ + if (SCpnt->request->flags & REQ_BLOCK_PC) { + struct request *rq = SCpnt->request; + + if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd)) + return 0; + + memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd)); + if (rq_data_dir(rq) == WRITE) + SCpnt->sc_data_direction = SCSI_DATA_WRITE; + else if (rq->data_len) + SCpnt->sc_data_direction = SCSI_DATA_READ; + else + SCpnt->sc_data_direction = SCSI_DATA_NONE; + + this_count = rq->data_len; + if (rq->timeout) + timeout = rq->timeout; + + goto queue; + } + + /* + * we only do REQ_CMD and REQ_BLOCK_PC */ if (!(SCpnt->request->flags & REQ_CMD)) return 0; - part_nr = SD_PARTITION(SCpnt->request->rq_dev); - dsk_nr = DEVICE_NR(SCpnt->request->rq_dev); - + disk = SCpnt->request->rq_disk; block = SCpnt->request->sector; this_count = SCpnt->request_bufflen >> 9; - SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%llu, " - "count=%d\n", dsk_nr, (unsigned long long)block, this_count)); + SCSI_LOG_HLQUEUE(1, printk("sd_command_init: disk=%s, block=%llu, " + "count=%d\n", disk->disk_name, (unsigned long long)block, this_count)); - sdp = SCpnt->device; - /* >>>>> the "(part_nr & 0xf)" excludes 15th partition, why?? */ - /* >>>>> this change is not in the lk 2.5 series */ - if (part_nr >= (sd_template.dev_max << 4) || (part_nr & 0xf) || - !sdp || !sdp->online || - block + SCpnt->request->nr_sectors > get_capacity(sd_disks[dsk_nr])) { + if (!sdp || !sdp->online || + block + SCpnt->request->nr_sectors > get_capacity(disk)) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); @@ -340,9 +340,8 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ return 0; } - SCSI_LOG_HLQUEUE(2, sd_dskname(dsk_nr, nbuff)); - SCSI_LOG_HLQUEUE(2, printk("%s : [part_nr=%d], block=%llu\n", - nbuff, part_nr, (unsigned long long)block)); + SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n", + disk->disk_name, (unsigned long long)block)); /* * If we have a 1K hardware sectorsize, prevent access to single @@ -399,11 +398,10 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) } SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", - nbuff, (rq_data_dir(SCpnt->request) == WRITE) ? + disk->disk_name, (rq_data_dir(SCpnt->request) == WRITE) ? "writing" : "reading", this_count, SCpnt->request->nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? - ((SCpnt->lun << 5) & 0xe0) : 0; + SCpnt->cmnd[1] = 0; if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) { if (this_count > 0xffff) @@ -433,12 +431,12 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) * host adapter, it's safe to assume that we can at least transfer * this many bytes between each connect / disconnect. */ +queue: SCpnt->transfersize = sdp->sector_size; SCpnt->underflow = this_count << 9; SCpnt->allowed = MAX_RETRIES; - SCpnt->timeout_per_command = (SCpnt->device->type == TYPE_DISK ? - SD_TIMEOUT : SD_MOD_TIMEOUT); + SCpnt->timeout_per_command = timeout; /* * This is the completion routine we use. This is matched in terms @@ -468,16 +466,14 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) **/ static int sd_open(struct inode *inode, struct file *filp) { + struct gendisk *disk = inode->i_bdev->bd_disk; + Scsi_Disk *sdkp = disk->private_data; + Scsi_Device * sdp = sdkp->device; int retval = -ENXIO; - Scsi_Device * sdp; - Scsi_Disk * sdkp; - int dsk_nr = DEVICE_NR(inode->i_rdev); - SCSI_LOG_HLQUEUE(3, printk("sd_open: dsk_nr=%d, part_nr=%d\n", - dsk_nr, SD_PARTITION(inode->i_rdev))); + SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name)); - sdkp = sd_get_sdisk(dsk_nr); - if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) + if (!sdkp) return -ENXIO; /* No such device */ /* @@ -555,14 +551,12 @@ error_out: **/ static int sd_release(struct inode *inode, struct file *filp) { - Scsi_Disk * sdkp; - int dsk_nr = DEVICE_NR(inode->i_rdev); - Scsi_Device * sdp; + struct gendisk *disk = inode->i_bdev->bd_disk; + Scsi_Disk *sdkp = disk->private_data; + Scsi_Device *sdp = sdkp->device; - SCSI_LOG_HLQUEUE(3, printk("sd_release: dsk_nr=%d, part_nr=%d\n", - dsk_nr, SD_PARTITION(inode->i_rdev))); - sdkp = sd_get_sdisk(dsk_nr); - if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) + SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name)); + if (!sdp) return -ENODEV; /* open uses ENXIO ?? */ /* ... and what if there are packets in flight and this close() @@ -585,12 +579,12 @@ static int sd_release(struct inode *inode, struct file *filp) static struct block_device_operations sd_fops = { - owner: THIS_MODULE, - open: sd_open, - release: sd_release, - ioctl: sd_ioctl, - check_media_change: check_scsidisk_media_change, - revalidate: sd_revalidate + .owner = THIS_MODULE, + .open = sd_open, + .release = sd_release, + .ioctl = sd_ioctl, + .media_changed = check_scsidisk_media_change, + .revalidate_disk= sd_revalidate }; /** @@ -608,12 +602,8 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt) sector_t block_sectors = 1; sector_t error_sector; #if CONFIG_SCSI_LOGGING - char nbuff[6]; - - SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request->rq_dev), - nbuff)); SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", - nbuff, result)); + SCpnt->request->rq_disk->disk_name, result)); if (0 != result) { SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]" "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0], @@ -714,21 +704,18 @@ sd_set_media_not_present(Scsi_Disk *sdkp) { * * Note: this function is invoked from the block subsystem. **/ -static int check_scsidisk_media_change(kdev_t full_dev) +static int check_scsidisk_media_change(struct gendisk *disk) { + Scsi_Disk *sdkp = disk->private_data; + Scsi_Device *sdp = sdkp->device; int retval; int flag = 0; /* <<<< what is this for?? */ - Scsi_Disk * sdkp; - Scsi_Device * sdp; - int dsk_nr = DEVICE_NR(full_dev); - - sdkp = sd_get_sdisk(dsk_nr); SCSI_LOG_HLQUEUE(3, printk("check_scsidisk_media_change: " - "dsk_nr=%d\n", dsk_nr)); - if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) { - printk(KERN_ERR "check_scsidisk_media_change: dsk_nr=%d, " - "invalid device\n", dsk_nr); + "disk=%s\n", disk->disk_name)); + if (!sdp) { + printk(KERN_ERR "check_scsidisk_media_change: disk=%s, " + "invalid device\n", disk->disk_name); return 0; } if (!sdp->removable) @@ -815,9 +802,7 @@ sd_spinup_disk(Scsi_Disk *sdkp, char *diskname, while (retries < 3) { cmd[0] = TEST_UNIT_READY; - cmd[1] = (sdp->scsi_level <= SCSI_2) ? - ((sdp->lun << 5) & 0xe0) : 0; - memset((void *) &cmd[2], 0, 8); + memset((void *) &cmd[1], 0, 9); SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; @@ -851,9 +836,7 @@ sd_spinup_disk(Scsi_Disk *sdkp, char *diskname, printk(KERN_NOTICE "%s: Spinning up disk...", diskname); cmd[0] = START_STOP; - cmd[1] = (sdp->scsi_level <= SCSI_2) ? - ((sdp->lun << 5) & 0xe0) : 0; - cmd[1] |= 1; /* Return immediately */ + cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ SRpnt->sr_cmd_len = 0; @@ -894,7 +877,6 @@ sd_read_cache_type(Scsi_Disk *sdkp, char *diskname, Scsi_Request *SRpnt, unsigned char *buffer) { unsigned char cmd[10]; - Scsi_Device *sdp = sdkp->device; int the_result, retries; retries = 3; @@ -902,9 +884,7 @@ sd_read_cache_type(Scsi_Disk *sdkp, char *diskname, memset((void *) &cmd[0], 0, 10); cmd[0] = MODE_SENSE; - cmd[1] = (sdp->scsi_level <= SCSI_2) ? - ((sdp->lun << 5) & 0xe0) : 0; - cmd[1] |= 0x08; /* DBD */ + cmd[1] = 0x08; /* DBD */ cmd[2] = 0x08; /* current values, cache page */ cmd[4] = 128; /* allocation length */ @@ -924,20 +904,29 @@ sd_read_cache_type(Scsi_Disk *sdkp, char *diskname, } while (the_result && retries); if (the_result) { - printk(KERN_ERR "%s : MODE SENSE failed.\n" - "%s : status = %x, message = %02x, host = %d, driver = %02x \n", - diskname, diskname, - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result) - ); - if (driver_byte(the_result) & DRIVER_SENSE) - print_req_sense("sd", SRpnt); - else - printk(KERN_ERR "%s : sense not available. \n", diskname); - - printk(KERN_ERR "%s : assuming drive cache: write through\n", diskname); + if(status_byte(the_result) == CHECK_CONDITION + && (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 + && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST + /* The next are ASC 0x24 ASCQ 0x00: Invalid field in CDB */ + && SRpnt->sr_sense_buffer[12] == 0x24 + && SRpnt->sr_sense_buffer[13] == 0x00) { + printk(KERN_NOTICE "SCSI device %s: cache data unavailable\n", diskname); + } else { + printk(KERN_ERR "%s : MODE SENSE failed.\n" + "%s : status = %x, message = %02x, host = %d, driver = %02x \n", + diskname, diskname, + status_byte(the_result), + msg_byte(the_result), + host_byte(the_result), + driver_byte(the_result) + ); + if (driver_byte(the_result) & DRIVER_SENSE) + print_req_sense("sd", SRpnt); + else + printk(KERN_ERR "%s : sense not available. \n", diskname); + + printk(KERN_ERR "%s : assuming drive cache: write through\n", diskname); + } sdkp->WCE = 0; sdkp->RCD = 0; } else { @@ -968,9 +957,7 @@ sd_read_capacity(Scsi_Disk *sdkp, char *diskname, retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (sdp->scsi_level <= SCSI_2) ? - ((sdp->lun << 5) & 0xe0) : 0; - memset((void *) &cmd[2], 0, 8); + memset((void *) &cmd[1], 0, 9); memset((void *) buffer, 0, 8); SRpnt->sr_cmd_len = 0; @@ -1090,7 +1077,6 @@ sd_do_mode_sense6(Scsi_Device *sdp, Scsi_Request *SRpnt, memset((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; - cmd[1] = (sdp->scsi_level <= SCSI_2) ? ((sdp->lun << 5) & 0xe0) : 0; cmd[2] = modepage; cmd[4] = len; @@ -1157,18 +1143,13 @@ sd_read_write_protect_flag(Scsi_Disk *sdkp, char *diskname, * Note: this function is local to this driver. **/ static void -sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr) { - char diskname[40]; +sd_init_onedisk(Scsi_Disk * sdkp, struct gendisk *disk) +{ unsigned char *buffer; Scsi_Device *sdp; Scsi_Request *SRpnt; - SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: dsk_nr=%d\n", dsk_nr)); - - /* - * Get the name of the disk, in case we need to log it somewhere. - */ - sd_dskname(dsk_nr, diskname); + SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: disk=%s\n", disk->disk_name)); /* * If the device is offline, don't try and read capacity or any @@ -1198,14 +1179,14 @@ sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr) { sdkp->media_present = 1; sdkp->write_prot = 0; - sd_spinup_disk(sdkp, diskname, SRpnt, buffer); - sd_read_cache_type(sdkp, diskname, SRpnt, buffer); + sd_spinup_disk(sdkp, disk->disk_name, SRpnt, buffer); + sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer); if (sdkp->media_present) - sd_read_capacity(sdkp, diskname, SRpnt, buffer); + sd_read_capacity(sdkp, disk->disk_name, SRpnt, buffer); if (sdp->removable && sdkp->media_present) - sd_read_write_protect_flag(sdkp, diskname, SRpnt, buffer); + sd_read_write_protect_flag(sdkp, disk->disk_name, SRpnt, buffer); SRpnt->sr_device->ten = 1; SRpnt->sr_device->remap = 1; @@ -1324,18 +1305,18 @@ static void sd_finish() Scsi_Disk * sdkp; SCSI_LOG_HLQUEUE(3, printk("sd_finish: \n")); - for (k = 0; k < N_USED_SD_MAJORS; k++) - blk_dev[SD_MAJOR(k)].queue = sd_find_queue; for (k = 0; k < sd_template.dev_max; ++k) { sdkp = sd_get_sdisk(k); if (sdkp && (0 == sdkp->capacity) && sdkp->device) { - sd_init_onedisk(sdkp, k); - if (!sdkp->has_been_registered) { - set_capacity(sd_disks[k], sdkp->capacity); - add_disk(sd_disks[k]); - sdkp->has_been_registered = 1; - } + sd_init_onedisk(sdkp, sd_disks[k]); + if (sdkp->has_been_registered) + continue; + set_capacity(sd_disks[k], sdkp->capacity); + sd_disks[k]->private_data = sdkp; + sd_disks[k]->queue = &sdkp->device->request_queue; + add_disk(sd_disks[k]); + sdkp->has_been_registered = 1; } } return; @@ -1438,16 +1419,15 @@ static int sd_attach(Scsi_Device * sdp) return 0; } -static int sd_revalidate(kdev_t dev) +static int sd_revalidate(struct gendisk *disk) { - int dsk_nr = DEVICE_NR(dev); - Scsi_Disk * sdkp = sd_get_sdisk(dsk_nr); + Scsi_Disk *sdkp = disk->private_data; - if (!sdkp || !sdkp->device) + if (!sdkp->device) return -ENODEV; - sd_init_onedisk(sdkp, dsk_nr); - set_capacity(sd_disks[dsk_nr], sdkp->capacity); + sd_init_onedisk(sdkp, disk); + set_capacity(disk, sdkp->capacity); return 0; } @@ -1465,7 +1445,6 @@ static int sd_revalidate(kdev_t dev) static void sd_detach(Scsi_Device * sdp) { Scsi_Disk *sdkp = NULL; - kdev_t dev; int dsk_nr; unsigned long iflags; @@ -1495,7 +1474,6 @@ static void sd_detach(Scsi_Device * sdp) if (sdkp->has_been_registered) { sdkp->has_been_registered = 0; - dev = MKDEV_SD(dsk_nr); del_gendisk(sd_disks[dsk_nr]); } sdp->attached--; @@ -1546,10 +1524,8 @@ static void __exit exit_sd(void) vfree(sd_dsk_arr[k]); vfree(sd_dsk_arr); } - for (k = 0; k < N_USED_SD_MAJORS; k++) - blk_dev[SD_MAJOR(k)].queue = NULL; sd_template.dev_max = 0; - remove_driver(&sd_template.scsi_driverfs_driver); + driver_unregister(&sd_template.scsi_driverfs_driver); unregister_reboot_notifier(&sd_notifier_block); } @@ -1611,7 +1587,6 @@ static int sd_synchronize_cache(int index, int verbose) unsigned char cmd[10] = { 0 }; cmd[0] = SYNCHRONIZE_CACHE; - cmd[1] = SDpnt->scsi_level <= SCSI_2 ? (SDpnt->lun << 5) & 0xe0 : 0; /* leave the rest of the command zero to indicate * flush everything */ scsi_wait_req(SRpnt, (void *)cmd, NULL, 0, diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index ad75b842e13d..847e7c403e6c 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -40,6 +40,5 @@ extern kdev_t sd_find_target(void *host, int tgt); #define N_SD_MAJORS 8 #define SD_MAJOR_MASK (N_SD_MAJORS - 1) -#define SD_PARTITION(i) (((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255)) #endif diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index a18bf6db8fcf..4e7682ec0565 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -705,10 +705,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, SRpnt->sr_request->rq_dev = sdp->i_rdev; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; - if (!(hp->flags & SG_FLAG_LUN_INHIBIT)) { - if (sdp->device->scsi_level <= SCSI_2) - cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); - } SRpnt->sr_use_sg = srp->data.k_use_sg; SRpnt->sr_sglist_len = srp->data.sglist_len; SRpnt->sr_bufflen = srp->data.bufflen; @@ -1659,7 +1655,7 @@ exit_sg(void) sg_dev_arr = NULL; } sg_template.dev_max = 0; - remove_driver(&sg_template.scsi_driverfs_driver); + driver_unregister(&sg_template.scsi_driverfs_driver); } static int @@ -3103,7 +3099,8 @@ sg_proc_host_info(char *buffer, int *len, off_t * begin, off_t offset, int size) struct Scsi_Host *shp; int k; - for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for (k = 0, shp = scsi_host_get_next(NULL); shp; + shp = scsi_host_get_next(shp), ++k) { for (; k < shp->host_no; ++k) PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n"); PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n", @@ -3147,7 +3144,8 @@ sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin, char buff[SG_MAX_HOST_STR_LEN]; char *cp; - for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for (k = 0, shp = scsi_host_get_next(NULL); shp; + shp = scsi_host_get_next(shp), ++k) { for (; k < shp->host_no; ++k) PRINT_PROC("<no active host>\n"); strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) : diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 39af5cce16f0..56ca67c79400 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -51,7 +51,6 @@ #define MAJOR_NR SCSI_CDROM_MAJOR #define LOCAL_END_REQUEST -#define DEVICE_NR(device) (minor(device)) #include <linux/blk.h> #include "scsi.h" #include "hosts.h" @@ -196,8 +195,7 @@ static void rw_intr(Scsi_Cmnd * SCpnt) int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 0; - int device_nr = DEVICE_NR(SCpnt->request->rq_dev); - Scsi_CD *cd = &scsi_CDs[device_nr]; + Scsi_CD *cd = SCpnt->request->rq_disk->private_data; #ifdef DEBUG printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data); @@ -247,31 +245,14 @@ static void rw_intr(Scsi_Cmnd * SCpnt) scsi_io_completion(SCpnt, good_sectors, block_sectors); } - -static request_queue_t *sr_find_queue(kdev_t dev) -{ - Scsi_CD *cd; - - if (minor(dev) >= sr_template.dev_max) - return NULL; - cd = &scsi_CDs[minor(dev)]; - if (!cd->device) - return NULL; - return &cd->device->request_queue; -} - static int sr_init_command(Scsi_Cmnd * SCpnt) { - int dev, devm, block=0, this_count, s_size; - Scsi_CD *cd; - - devm = minor(SCpnt->request->rq_dev); - dev = DEVICE_NR(SCpnt->request->rq_dev); - cd = &scsi_CDs[dev]; + int block=0, this_count, s_size, timeout = SR_TIMEOUT; + Scsi_CD *cd = SCpnt->request->rq_disk->private_data; - SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block)); + SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n", disk->disk_name, block)); - if (dev >= sr_template.nr_dev || !cd->device || !cd->device->online) { + if (!cd->device || !cd->device->online) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; @@ -285,6 +266,30 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) return 0; } + /* + * these are already setup, just copy cdb basically + */ + if (SCpnt->request->flags & REQ_BLOCK_PC) { + struct request *rq = SCpnt->request; + + if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd)) + return 0; + + memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd)); + if (rq_data_dir(rq) == WRITE) + SCpnt->sc_data_direction = SCSI_DATA_WRITE; + else if (rq->data_len) + SCpnt->sc_data_direction = SCSI_DATA_READ; + else + SCpnt->sc_data_direction = SCSI_DATA_NONE; + + this_count = rq->data_len; + if (rq->timeout) + timeout = rq->timeout; + + goto queue; + } + if (!(SCpnt->request->flags & REQ_CMD)) { blk_dump_rq_flags(SCpnt->request, "sr unsup command"); return 0; @@ -336,9 +341,7 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) (rq_data_dir(SCpnt->request) == WRITE) ? "writing" : "reading", this_count, SCpnt->request->nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? - ((SCpnt->lun << 5) & 0xe0) : 0; - + SCpnt->cmnd[1] = 0; block = (unsigned int)SCpnt->request->sector / (s_size >> 9); if (this_count > 0xffff) @@ -357,11 +360,12 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) * host adapter, it's safe to assume that we can at least transfer * this many bytes between each connect / disconnect. */ +queue: SCpnt->transfersize = cd->device->sector_size; SCpnt->underflow = this_count << 9; SCpnt->allowed = MAX_RETRIES; - SCpnt->timeout_per_command = SR_TIMEOUT; + SCpnt->timeout_per_command = timeout; /* * This is the completion routine we use. This is matched in terms @@ -388,13 +392,38 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) return 1; } +static int sr_block_open(struct inode *inode, struct file *file) +{ + Scsi_CD *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_open(&cd->cdi, inode, file); +} + +static int sr_block_release(struct inode *inode, struct file *file) +{ + Scsi_CD *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_release(&cd->cdi, file); +} + +static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd, + unsigned long arg) +{ + Scsi_CD *cd = inode->i_bdev->bd_disk->private_data; + return cdrom_ioctl(&cd->cdi, inode, cmd, arg); +} + +static int sr_block_media_changed(struct gendisk *disk) +{ + Scsi_CD *cd = disk->private_data; + return cdrom_media_changed(&cd->cdi); +} + struct block_device_operations sr_bdops = { - owner: THIS_MODULE, - open: cdrom_open, - release: cdrom_release, - ioctl: cdrom_ioctl, - check_media_change: cdrom_media_changed, + .owner = THIS_MODULE, + .open = sr_block_open, + .release = sr_block_release, + .ioctl = sr_block_ioctl, + .media_changed = sr_block_media_changed, }; static int sr_open(struct cdrom_device_info *cdi, int purpose) @@ -486,9 +515,7 @@ static void get_sectorsize(Scsi_CD *cd) do { cmd[0] = READ_CAPACITY; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun << 5) & 0xe0) : 0; - memset((void *) &cmd[2], 0, 8); + memset((void *) &cmd[1], 0, 9); SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ SRpnt->sr_cmd_len = 0; @@ -599,8 +626,6 @@ void get_capabilities(Scsi_CD *cd) } memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = MODE_SENSE; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun << 5) & 0xe0) : 0; cgc.cmd[2] = 0x2a; cgc.cmd[4] = 128; cgc.buffer = buffer; @@ -678,13 +703,6 @@ void get_capabilities(Scsi_CD *cd) */ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) { - Scsi_CD *cd = cdi->handle; - Scsi_Device *device = cd->device; - - /* set the LUN */ - if (device->scsi_level <= SCSI_2) - cgc->cmd[1] |= device->lun << 5; - if (cgc->timeout <= 0) cgc->timeout = IOCTL_TIMEOUT; @@ -730,8 +748,6 @@ void sr_finish() { int i; - blk_dev[MAJOR_NR].queue = sr_find_queue; - for (i = 0; i < sr_template.nr_dev; ++i) { struct gendisk *disk; Scsi_CD *cd = &scsi_CDs[i]; @@ -770,7 +786,6 @@ void sr_finish() cd->cdi.ops = &sr_dops; cd->cdi.handle = cd; - cd->cdi.dev = mk_kdev(MAJOR_NR, i); cd->cdi.mask = 0; cd->cdi.capacity = 1; /* @@ -783,6 +798,8 @@ void sr_finish() disk->driverfs_dev = &cd->device->sdev_driverfs_dev; register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); + disk->private_data = cd; + disk->queue = &cd->device->request_queue; add_disk(disk); } } @@ -839,7 +856,7 @@ static void __exit exit_sr(void) kfree(scsi_CDs); sr_template.dev_max = 0; - remove_driver(&sr_template.scsi_driverfs_driver); + driver_unregister(&sr_template.scsi_driverfs_driver); } module_init(init_sr); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 82c0f0c52a86..c9d7c1f4c11e 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -200,8 +200,6 @@ static int test_unit_ready(Scsi_CD *cd) memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_TEST_UNIT_READY; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.quiet = 1; cgc.data_direction = SCSI_DATA_NONE; cgc.timeout = IOCTL_TIMEOUT; @@ -215,8 +213,6 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos) memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_START_STOP_UNIT; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; cgc.data_direction = SCSI_DATA_NONE; cgc.timeout = IOCTL_TIMEOUT; @@ -293,8 +289,6 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.cmd[2] = 0x40; /* I do want the subchannel info */ cgc.cmd[3] = 0x02; /* Give me medium catalog number info */ cgc.cmd[8] = 24; @@ -327,8 +321,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed) memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ cgc.cmd[3] = speed & 0xff; /* LSB */ cgc.data_direction = SCSI_DATA_NONE; @@ -361,8 +353,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.cmd[8] = 12; /* LSB of length */ cgc.buffer = buffer; cgc.buflen = 12; @@ -382,8 +372,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; cgc.cmd[6] = tocentry->cdte_track; cgc.cmd[8] = 12; /* LSB of length */ @@ -411,8 +399,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) struct cdrom_ti* ti = (struct cdrom_ti*)arg; cgc.cmd[0] = GPCMD_PLAYAUDIO_TI; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; cgc.cmd[4] = ti->cdti_trk0; cgc.cmd[5] = ti->cdti_ind0; cgc.cmd[7] = ti->cdti_trk1; @@ -463,9 +449,7 @@ static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_READ_CD; /* READ_CD */ - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cgc.cmd[1] |= ((format & 7) << 2); + cgc.cmd[1] = ((format & 7) << 2); cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; @@ -521,8 +505,6 @@ static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = GPCMD_READ_10; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index 6803d45c7b26..76a701bb4502 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -124,9 +124,7 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) #endif memset(&cgc, 0, sizeof(struct cdrom_generic_command)); cgc.cmd[0] = MODE_SELECT; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cgc.cmd[1] |= (1 << 4); + cgc.cmd[1] = (1 << 4); cgc.cmd[4] = 12; modesel = (struct ccs_modesel_head *) buffer; memset(modesel, 0, sizeof(*modesel)); @@ -180,8 +178,6 @@ int sr_cd_check(struct cdrom_device_info *cdi) case VENDOR_SCSI3: cgc.cmd[0] = READ_TOC; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; cgc.cmd[8] = 12; cgc.cmd[9] = 0x40; cgc.buffer = buffer; @@ -210,9 +206,7 @@ int sr_cd_check(struct cdrom_device_info *cdi) case VENDOR_NEC:{ unsigned long min, sec, frame; cgc.cmd[0] = 0xde; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cgc.cmd[1] |= 0x03; + cgc.cmd[1] = 0x03; cgc.cmd[2] = 0xb0; cgc.buffer = buffer; cgc.buflen = 0x16; @@ -242,9 +236,7 @@ int sr_cd_check(struct cdrom_device_info *cdi) /* we request some disc information (is it a XA-CD ?, * where starts the last session ?) */ cgc.cmd[0] = 0xc7; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cgc.cmd[1] |= 0x03; + cgc.cmd[1] = 0x03; cgc.buffer = buffer; cgc.buflen = 4; cgc.quiet = 1; @@ -272,8 +264,6 @@ int sr_cd_check(struct cdrom_device_info *cdi) case VENDOR_WRITER: cgc.cmd[0] = READ_TOC; - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; cgc.cmd[8] = 0x04; cgc.cmd[9] = 0x40; cgc.buffer = buffer; @@ -291,8 +281,6 @@ int sr_cd_check(struct cdrom_device_info *cdi) break; } cgc.cmd[0] = READ_TOC; /* Read TOC */ - cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; cgc.cmd[6] = rc & 0x7f; /* number of last session */ cgc.cmd[8] = 0x0c; cgc.cmd[9] = 0x40; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 194077d101ba..43c05cb65e7b 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -381,8 +381,6 @@ static Scsi_Request * } } - if (SRpnt->sr_device->scsi_level <= SCSI_2) - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; init_completion(&STp->wait); SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length); if (SRpnt->sr_use_sg) { @@ -3994,7 +3992,7 @@ static void __exit exit_st(void) kfree(scsi_tapes); } st_template.dev_max = 0; - remove_driver(&st_template.scsi_driverfs_driver); + driver_unregister(&st_template.scsi_driverfs_driver); printk(KERN_INFO "st: Unloaded.\n"); } diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index 4e02050bd885..2085c6fc3ed1 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -1279,16 +1279,6 @@ static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd) #endif /* SCSI_DATA_UNKNOWN */ -/* -** Head of list of NCR boards -** -** For kernel version < 1.3.70, host is retrieved by its irq level. -** For later kernels, the internal host control block address -** (struct ncb) is used as device id parameter of the irq stuff. -*/ - -static struct Scsi_Host *first_host = NULL; - /* ** /proc directory entry and proc_info function @@ -5880,11 +5870,6 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) /* ** Done. - */ - if (!first_host) - first_host = instance; - - /* ** Fill Linux host instance structure ** and return success. */ @@ -14228,36 +14213,30 @@ static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); #endif - for (host = first_host; host; host = host->next) { - if (host->hostt != first_host->hostt) - continue; - if (host->host_no == hostno) { - host_data = (struct host_data *) host->hostdata; - ncb = host_data->ncb; - break; - } - } + host = scsi_host_hn_get(hostno); + if (!host) + return -EINVAL; + host_data = (struct host_data *) host->hostdata; + ncb = host_data->ncb; + retv = -EINVAL; if (!ncb) - return -EINVAL; + goto out; if (func) { #ifdef SCSI_NCR_USER_COMMAND_SUPPORT retv = ncr_user_command(ncb, buffer, length); -#else - retv = -EINVAL; #endif - } - else { + } else { if (start) *start = buffer; #ifdef SCSI_NCR_USER_INFO_SUPPORT retv = ncr_host_info(ncb, buffer, offset, length); -#else - retv = -EINVAL; #endif } +out: + scsi_host_put(host); return retv; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 685a29399965..3b096fc6eaec 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1793,16 +1793,12 @@ static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, hcb_p np = 0; int retv; - for (host = first_host; host; host = host->next) { - if (host->hostt != first_host->hostt) - continue; - if (host->host_no == hostno) { - host_data = (struct host_data *) host->hostdata; - np = host_data->ncb; - break; - } - } + host = scsi_host_hn_get(hostno); + if (!host) + return -EINVAL; + host_data = (struct host_data *) host->hostdata; + np = host_data->ncb; if (!np) return -EINVAL; @@ -1823,6 +1819,7 @@ static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, #endif } + scsi_host_put(host); return retv; } #endif /* SYM_LINUX_PROC_INFO_SUPPORT */ diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 1673571beab0..5ee05c8d2f6a 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -1871,10 +1871,7 @@ Scsi_Cmnd *cmd; int x,i; static int stop = 0; - for (instance=scsi_hostlist; instance; instance=instance->next) { - if (instance->host_no == hn) - break; - } + instance = scsi_host_hn_get(hn); if (!instance) { printk("*** Hmm... Can't find host #%d!\n",hn); return (-ESRCH); diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c index 3d78f9ab1c7e..5c90b0057c64 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -395,7 +395,7 @@ struct usb_audio_state { /* prevent picking up a bogus abs macro */ #undef abs -extern inline int abs(int x) +static inline int abs(int x) { if (x < 0) return -x; @@ -404,7 +404,7 @@ extern inline int abs(int x) /* --------------------------------------------------------------------- */ -extern inline unsigned ld2(unsigned int x) +static inline unsigned ld2(unsigned int x) { unsigned r = 0; @@ -1939,13 +1939,13 @@ static void release(struct usb_audio_state *s) kfree(s); } -extern inline int prog_dmabuf_in(struct usb_audiodev *as) +static inline int prog_dmabuf_in(struct usb_audiodev *as) { usbin_stop(as); return dmabuf_init(&as->usbin.dma); } -extern inline int prog_dmabuf_out(struct usb_audiodev *as) +static inline int prog_dmabuf_out(struct usb_audiodev *as) { usbout_stop(as); return dmabuf_init(&as->usbout.dma); @@ -3253,7 +3253,7 @@ static void prepmixch(struct consmixstate *state) static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid); -extern inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch) +static inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch) { unsigned int idx; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 556dbacb7c23..e31a270ce931 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -208,7 +208,7 @@ void usb_deregister(struct usb_driver *driver) { info("deregistering driver %s", driver->name); - remove_driver (&driver->driver); + driver_unregister (&driver->driver); usbfs_update_special(); } @@ -1394,7 +1394,7 @@ static void __exit usb_exit(void) if (nousb) return; - remove_driver(&usb_generic_driver); + driver_unregister(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); usb_hub_cleanup(); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 98996cd62d6e..e5b729e5ad39 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -413,7 +413,7 @@ static int __init ohci_hcd_sa1111_init (void) static void __exit ohci_hcd_sa1111_cleanup (void) { - remove_driver(&ohci_hcd_sa1111_driver.drv); + driver_unregister(&ohci_hcd_sa1111_driver.drv); } module_init (ohci_hcd_sa1111_init); diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 53d5a335d832..9eb41edb4a49 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -119,6 +119,9 @@ obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o obj-$(CONFIG_FBCON_STI) += fbcon-sti.o obj-$(CONFIG_FBCON_ACCEL) += fbcon-accel.o +# Files generated that shall be removed upon make clean +clean-files := promcon_tbl.c + include $(TOPDIR)/Rules.make $(obj)/promcon_tbl.c: $(src)/prom.uni diff --git a/drivers/zorro/Makefile b/drivers/zorro/Makefile index 9bde458b4322..2131c57fccfa 100644 --- a/drivers/zorro/Makefile +++ b/drivers/zorro/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_PROC_FS) += proc.o host-progs := gen-devlist +# Files generated that shall be removed upon make clean +clean-files := devlist.h + include $(TOPDIR)/Rules.make # Dependencies on generated files need to be listed explicitly diff --git a/fs/Makefile b/fs/Makefile index c28d57ab55a9..68d7074b5ae2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_QUOTACTL) += quota.o obj-$(CONFIG_PROC_FS) += proc/ obj-y += partitions/ -obj-y += driverfs/ +obj-y += driverfs/ sysfs/ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index b95c3625257a..b3eca7db8051 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -129,11 +129,7 @@ static int kafscmd(void *arg) /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around looking for things to attend to */ @@ -360,6 +356,9 @@ void afscm_stop(void) rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */ + _debug("nuking active call %08x.%d", + ntohl(call->conn->conn_id),ntohl(call->call_id)); + rxrpc_put_call(call); rxrpc_put_call(call); spin_lock(&afscm_calls_lock); @@ -248,7 +248,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) write_unlock(&mm->ioctx_list_lock); dprintk("aio: allocated ioctx %p[%ld]: mm=%p mask=0x%x\n", - ctx, ctx->user_id, current->mm, ctx->ring_info.ring->nr); + ctx, ctx->user_id, current->mm, ctx->ring_info.nr); return ctx; out_cleanup: @@ -281,12 +281,12 @@ static void aio_cancel_all(struct kioctx *ctx) struct kiocb *iocb = list_kiocb(pos); list_del_init(&iocb->ki_list); cancel = iocb->ki_cancel; - if (cancel) + if (cancel) { iocb->ki_users++; - spin_unlock_irq(&ctx->ctx_lock); - if (cancel) + spin_unlock_irq(&ctx->ctx_lock); cancel(iocb, &res); - spin_lock_irq(&ctx->ctx_lock); + spin_lock_irq(&ctx->ctx_lock); + } } spin_unlock_irq(&ctx->ctx_lock); } @@ -376,7 +376,7 @@ void __put_ioctx(struct kioctx *ctx) /* aio_get_req * Allocate a slot for an aio request. Increments the users count * of the kioctx so that the kioctx stays around until all requests are - * complete. Returns -EAGAIN if no requests are free. + * complete. Returns NULL if no requests are free. */ static struct kiocb *FASTCALL(__aio_get_req(struct kioctx *ctx)); static struct kiocb *__aio_get_req(struct kioctx *ctx) @@ -409,8 +409,6 @@ static struct kiocb *__aio_get_req(struct kioctx *ctx) req->ki_user_obj = NULL; req->ki_ctx = ctx; req->ki_users = 1; - } else { - kmem_cache_free(kiocb_cachep, req); okay = 1; } kunmap_atomic(ring, KM_USER0); @@ -478,7 +476,7 @@ static void aio_fput_routine(void *data) /* __aio_put_req * Returns true if this put was the last user of the request. */ -static inline int __aio_put_req(struct kioctx *ctx, struct kiocb *req) +static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) { dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n", req, atomic_read(&req->ki_filp->f_count)); @@ -525,7 +523,7 @@ int aio_put_req(struct kiocb *req) /* Lookup an ioctx id. ioctx_list is lockless for reads. * FIXME: this is O(n) and is only suitable for development. */ -static inline struct kioctx *lookup_ioctx(unsigned long ctx_id) +static struct kioctx *lookup_ioctx(unsigned long ctx_id) { struct kioctx *ioctx; struct mm_struct *mm; @@ -845,13 +843,13 @@ static int read_events(struct kioctx *ctx, /* End fast path */ + init_timeout(&to); if (timeout) { struct timespec ts; ret = -EFAULT; if (unlikely(copy_from_user(&ts, timeout, sizeof(ts)))) goto out; - init_timeout(&to); set_timeout(start_jiffies, &to, &ts); } @@ -1197,6 +1195,9 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb *iocb, if (NULL != cancel) { struct io_event tmp; printk("calling cancel\n"); + memset(&tmp, 0, sizeof(tmp)); + tmp.obj = (u64)(unsigned long)kiocb->ki_user_obj; + tmp.data = kiocb->ki_user_data; ret = cancel(kiocb, &tmp); if (!ret) { /* Cancellation succeeded -- copy the result diff --git a/fs/block_dev.c b/fs/block_dev.c index 1ad7f467993b..ae93c51febd5 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -527,16 +527,16 @@ int check_disk_change(struct block_device *bdev) struct block_device_operations * bdops = bdev->bd_op; kdev_t dev = to_kdev_t(bdev->bd_dev); - if (bdops->check_media_change == NULL) + if (!bdops->media_changed) return 0; - if (!bdops->check_media_change(dev)) + if (!bdops->media_changed(bdev->bd_disk)) return 0; if (invalidate_device(dev, 0)) printk("VFS: busy inodes on changed media.\n"); - if (bdops->revalidate) - bdops->revalidate(dev); + if (bdops->revalidate_disk) + bdops->revalidate_disk(bdev->bd_disk); if (bdev->bd_disk->minors > 1) bdev->bd_invalidated = 1; return 1; @@ -601,6 +601,13 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * if (owner) __MOD_INC_USE_COUNT(owner); } + disk = get_gendisk(bdev->bd_dev, &part); + if (!disk) { + if (owner) + __MOD_DEC_USE_COUNT(owner); + bdput(bdev); + return ret; + } down(&bdev->bd_sem); old = bdev->bd_op; @@ -612,9 +619,6 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * if (owner) __MOD_DEC_USE_COUNT(owner); } - disk = get_gendisk(bdev->bd_dev, &part); - if (!disk) - goto out1; if (!bdev->bd_contains) { bdev->bd_contains = bdev; if (part) { @@ -633,10 +637,14 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * if (!bdev->bd_openers) bdev->bd_disk = disk; if (!bdev->bd_queue) { - struct blk_dev_struct *p = blk_dev + major(dev); - bdev->bd_queue = &p->request_queue; - if (p->queue) - bdev->bd_queue = p->queue(dev); + if (disk->queue) + bdev->bd_queue = disk->queue; + else { + struct blk_dev_struct *p = blk_dev + major(dev); + bdev->bd_queue = &p->request_queue; + if (p->queue) + bdev->bd_queue = p->queue(dev); + } } if (bdev->bd_op->open) { ret = bdev->bd_op->open(inode, file); @@ -650,7 +658,6 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * bdi = blk_get_backing_dev_info(bdev); if (bdi == NULL) bdi = &default_backing_dev_info; - inode->i_data.backing_dev_info = bdi; bdev->bd_inode->i_data.backing_dev_info = bdi; } if (bdev->bd_invalidated) @@ -661,8 +668,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * if (!bdev->bd_openers) { struct hd_struct *p; p = disk->part + part - 1; - inode->i_data.backing_dev_info = - bdev->bd_inode->i_data.backing_dev_info = + bdev->bd_inode->i_data.backing_dev_info = bdev->bd_contains->bd_inode->i_data.backing_dev_info; if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) { bdev->bd_contains->bd_part_count--; @@ -685,6 +691,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * out2: if (!bdev->bd_openers) { + bdev->bd_queue = NULL; + bdev->bd_disk = NULL; bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; if (bdev != bdev->bd_contains) { blkdev_put(bdev->bd_contains, BDEV_RAW); diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index 0f35e27e669c..b4b5aa9f6a55 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -509,11 +509,13 @@ static void put_mount(void) DBG("driverfs: mount_count = %d\n",mount_count); } -int __init init_driverfs_fs(void) +static int __init driverfs_init(void) { return register_filesystem(&driverfs_fs_type); } +core_initcall(driverfs_init); + static struct dentry * get_dentry(struct dentry * parent, const char * name) { struct qstr qstr; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 27d57513db65..98165f99b0eb 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -289,13 +289,13 @@ static ssize_t part_start_read(struct device *dev, char *page, size_t count, loff_t off) { struct hd_struct *p = dev->driver_data; - return off ? 0 : sprintf(page, "%llu\n",(u64)p->start_sect); + return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->start_sect); } static ssize_t part_size_read(struct device *dev, char *page, size_t count, loff_t off) { struct hd_struct *p = dev->driver_data; - return off ? 0 : sprintf(page, "%llu\n",(u64)p->nr_sects); + return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->nr_sects); } static struct device_attribute part_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, @@ -375,7 +375,7 @@ static ssize_t disk_size_read(struct device *dev, char *page, size_t count, loff_t off) { struct gendisk *disk = dev->driver_data; - return off ? 0 : sprintf(page, "%llu\n",(u64)get_capacity(disk)); + return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk)); } static struct device_attribute disk_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, @@ -511,8 +511,8 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) bdev->bd_invalidated = 0; for (p = 1; p < disk->minors; p++) delete_partition(disk, p); - if (bdev->bd_op->revalidate) - bdev->bd_op->revalidate(dev); + if (bdev->bd_op->revalidate_disk) + bdev->bd_op->revalidate_disk(disk); if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) return res; for (p = 1; p < state->limit; p++) { diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 61b0bc9bc02b..fd1e70543f46 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -28,7 +28,7 @@ #elif defined(CONFIG_BLK_DEV_IDE_MODULE) #include <linux/module.h> -int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *); +int (*ide_xlate_1024_hook)(struct block_device *, int, int, const char *); EXPORT_SYMBOL(ide_xlate_1024_hook); #define ide_xlate_1024 ide_xlate_1024_hook #endif diff --git a/fs/read_write.c b/fs/read_write.c index a5c0ff37d9a1..a8b23e6367ee 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -121,12 +121,6 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) if (!file) goto bad; - retval = security_ops->file_llseek(file); - if (retval) { - fput(file); - goto bad; - } - retval = -EINVAL; if (origin <= 2) { loff_t res = llseek(file, offset, origin); @@ -153,10 +147,6 @@ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, if (!file) goto bad; - retval = security_ops->file_llseek(file); - if (retval) - goto out_putf; - retval = -EINVAL; if (origin > 2) goto out_putf; diff --git a/fs/sysfs/Makefile b/fs/sysfs/Makefile new file mode 100644 index 000000000000..0aab3de8d9b9 --- /dev/null +++ b/fs/sysfs/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the sysfs virtual filesystem +# + +export-objs := inode.o + +obj-y := inode.o + +include $(TOPDIR)/Rules.make diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c new file mode 100644 index 000000000000..a91f47aaa378 --- /dev/null +++ b/fs/sysfs/inode.c @@ -0,0 +1,642 @@ +/* + * sysfs.c - The filesystem to export kernel objects. + * + * Copyright (c) 2001, 2002 Patrick Mochel + * + * 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. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This is a simple, ramfs-based filesystem, designed to export kernel + * objects, their attributes, and the linkgaes between each other. + * + * Please see Documentation/filesystems/sysfs.txt for more information. + */ + +#include <linux/list.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <linux/stat.h> +#include <linux/fs.h> +#include <linux/dcache.h> +#include <linux/namei.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/backing-dev.h> +#include <linux/sysfs.h> + +#include <asm/uaccess.h> + +/* Random magic number */ +#define SYSFS_MAGIC 0x62656572 + +static struct super_operations sysfs_ops; +static struct file_operations sysfs_file_operations; +static struct inode_operations sysfs_dir_inode_operations; +static struct address_space_operations sysfs_aops; + +static struct vfsmount *sysfs_mount; + +static struct backing_dev_info sysfs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; + +static int sysfs_readpage(struct file *file, struct page * page) +{ + if (!PageUptodate(page)) { + void *kaddr = kmap_atomic(page, KM_USER0); + + memset(kaddr, 0, PAGE_CACHE_SIZE); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + SetPageUptodate(page); + } + unlock_page(page); + return 0; +} + +static int sysfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + if (!PageUptodate(page)) { + void *kaddr = kmap_atomic(page, KM_USER0); + + memset(kaddr, 0, PAGE_CACHE_SIZE); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + SetPageUptodate(page); + } + return 0; +} + +static int sysfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + struct inode *inode = page->mapping->host; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + set_page_dirty(page); + if (pos > inode->i_size) + inode->i_size = pos; + return 0; +} + + +static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_mapping->a_ops = &sysfs_aops; + inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &sysfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +static int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode *inode; + int error = 0; + + if (!dentry->d_inode) { + inode = sysfs_get_inode(dir->i_sb, mode, dev); + if (inode) + d_instantiate(dentry, inode); + else + error = -ENOSPC; + } else + error = -EEXIST; + return error; +} + +static int sysfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int res; + mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR; + res = sysfs_mknod(dir, dentry, mode, 0); + if (!res) + dir->i_nlink++; + return res; +} + +static int sysfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + int res; + mode = (mode & S_IALLUGO) | S_IFREG; + res = sysfs_mknod(dir, dentry, mode, 0); + return res; +} + +static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + if (dentry->d_inode) + return -EEXIST; + + inode = sysfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} + +static inline int sysfs_positive(struct dentry *dentry) +{ + return (dentry->d_inode && !d_unhashed(dentry)); +} + +static int sysfs_empty(struct dentry *dentry) +{ + struct list_head *list; + + spin_lock(&dcache_lock); + + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (sysfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; + } + } + + spin_unlock(&dcache_lock); + return 1; +} + +static int sysfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + down(&inode->i_sem); + dentry->d_inode->i_nlink--; + up(&inode->i_sem); + d_invalidate(dentry); + dput(dentry); + return 0; +} + +/** + * sysfs_read_file - "read" data from a file. + * @file: file pointer + * @buf: buffer to fill + * @count: number of bytes to read + * @ppos: starting offset in file + * + * Userspace wants data from a file. It is up to the creator of the file to + * provide that data. + * There is a struct device_attribute embedded in file->private_data. We + * obtain that and check if the read callback is implemented. If so, we call + * it, passing the data field of the file entry. + * Said callback is responsible for filling the buffer and returning the number + * of bytes it put in it. We update @ppos correctly. + */ +static ssize_t +sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct attribute * attr = file->f_dentry->d_fsdata; + struct driver_dir_entry * dir; + unsigned char *page; + ssize_t retval = 0; + + dir = file->f_dentry->d_parent->d_fsdata; + if (!dir->ops->show) + return 0; + + if (count > PAGE_SIZE) + count = PAGE_SIZE; + + page = (unsigned char*)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + while (count > 0) { + ssize_t len; + + len = dir->ops->show(dir,attr,page,count,*ppos); + + if (len <= 0) { + if (len < 0) + retval = len; + break; + } else if (len > count) + len = count; + + if (copy_to_user(buf,page,len)) { + retval = -EFAULT; + break; + } + + *ppos += len; + count -= len; + buf += len; + retval += len; + } + free_page((unsigned long)page); + return retval; +} + +/** + * sysfs_write_file - "write" to a file + * @file: file pointer + * @buf: data to write + * @count: number of bytes + * @ppos: starting offset + * + * Similarly to sysfs_read_file, we act essentially as a bit pipe. + * We check for a "write" callback in file->private_data, and pass + * @buffer, @count, @ppos, and the file entry's data to the callback. + * The number of bytes written is returned, and we handle updating + * @ppos properly. + */ +static ssize_t +sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct attribute * attr = file->f_dentry->d_fsdata; + struct driver_dir_entry * dir; + ssize_t retval = 0; + char * page; + + dir = file->f_dentry->d_parent->d_fsdata; + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + if (count >= PAGE_SIZE) + count = PAGE_SIZE - 1; + if (copy_from_user(page,buf,count)) + goto done; + *(page + count) = '\0'; + + while (count > 0) { + ssize_t len; + + len = dir->ops->store(dir,attr,page + retval,count,*ppos); + + if (len <= 0) { + if (len < 0) + retval = len; + break; + } + retval += len; + count -= len; + *ppos += len; + buf += len; + } + done: + free_page((unsigned long)page); + return retval; +} + +static loff_t +sysfs_file_lseek(struct file *file, loff_t offset, int orig) +{ + loff_t retval = -EINVAL; + + down(&file->f_dentry->d_inode->i_sem); + switch(orig) { + case 0: + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; + case 1: + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; + default: + break; + } + up(&file->f_dentry->d_inode->i_sem); + return retval; +} + +static int sysfs_open_file(struct inode * inode, struct file * filp) +{ + struct driver_dir_entry * dir; + int error = 0; + + dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; + if (dir) { + struct attribute * attr = filp->f_dentry->d_fsdata; + if (attr && dir->ops) { + if (dir->ops->open) + error = dir->ops->open(dir); + goto Done; + } + } + error = -EINVAL; + Done: + return error; +} + +static int sysfs_release(struct inode * inode, struct file * filp) +{ + struct driver_dir_entry * dir; + dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; + if (dir->ops->close) + dir->ops->close(dir); + return 0; +} + +static struct file_operations sysfs_file_operations = { + .read = sysfs_read_file, + .write = sysfs_write_file, + .llseek = sysfs_file_lseek, + .open = sysfs_open_file, + .release = sysfs_release, +}; + +static struct inode_operations sysfs_dir_inode_operations = { + .lookup = simple_lookup, +}; + +static struct address_space_operations sysfs_aops = { + .readpage = sysfs_readpage, + .writepage = fail_writepage, + .prepare_write = sysfs_prepare_write, + .commit_write = sysfs_commit_write +}; + +static struct super_operations sysfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static int sysfs_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = SYSFS_MAGIC; + sb->s_op = &sysfs_ops; + inode = sysfs_get_inode(sb, S_IFDIR | 0755, 0); + + if (!inode) { + pr_debug("%s: could not get inode!\n",__FUNCTION__); + return -ENOMEM; + } + + root = d_alloc_root(inode); + if (!root) { + pr_debug("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return 0; +} + +static struct super_block *sysfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, sysfs_fill_super); +} + +static struct file_system_type sysfs_fs_type = { + .owner = THIS_MODULE, + .name = "sysfs", + .get_sb = sysfs_get_sb, + .kill_sb = kill_litter_super, +}; + +static int __init sysfs_init(void) +{ + int err; + + err = register_filesystem(&sysfs_fs_type); + if (!err) { + sysfs_mount = kern_mount(&sysfs_fs_type); + if (IS_ERR(sysfs_mount)) { + printk(KERN_ERR "sysfs: could not mount!\n"); + err = PTR_ERR(sysfs_mount); + sysfs_mount = NULL; + } + } + return err; +} + +core_initcall(sysfs_init); + +static struct dentry * get_dentry(struct dentry * parent, const char * name) +{ + struct qstr qstr; + + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); + return lookup_hash(&qstr,parent); +} + +/** + * sysfs_create_dir - create a directory in the filesystem + * @entry: directory entry + * @parent: parent directory entry + */ +int +sysfs_create_dir(struct driver_dir_entry * entry, + struct driver_dir_entry * parent) +{ + struct dentry * dentry = NULL; + struct dentry * parent_dentry; + int error = 0; + + if (!entry) + return -EINVAL; + + parent_dentry = parent ? parent->dentry : NULL; + + if (!parent_dentry) + if (sysfs_mount && sysfs_mount->mnt_sb) + parent_dentry = sysfs_mount->mnt_sb->s_root; + + if (!parent_dentry) + return -EFAULT; + + down(&parent_dentry->d_inode->i_sem); + dentry = get_dentry(parent_dentry,entry->name); + if (!IS_ERR(dentry)) { + dentry->d_fsdata = (void *) entry; + entry->dentry = dentry; + error = sysfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); + } else + error = PTR_ERR(dentry); + up(&parent_dentry->d_inode->i_sem); + + return error; +} + +/** + * sysfs_create_file - create a file + * @entry: structure describing the file + * @parent: directory to create it in + */ +int +sysfs_create_file(struct attribute * entry, + struct driver_dir_entry * parent) +{ + struct dentry * dentry; + int error = 0; + + if (!entry || !parent) + return -EINVAL; + + if (!parent->dentry) + return -EINVAL; + + down(&parent->dentry->d_inode->i_sem); + dentry = get_dentry(parent->dentry,entry->name); + if (!IS_ERR(dentry)) { + dentry->d_fsdata = (void *)entry; + error = sysfs_create(parent->dentry->d_inode,dentry,entry->mode); + } else + error = PTR_ERR(dentry); + up(&parent->dentry->d_inode->i_sem); + return error; +} + +/** + * sysfs_create_symlink - make a symlink + * @parent: directory we're creating in + * @entry: entry describing link + * @target: place we're symlinking to + * + */ +int sysfs_create_symlink(struct driver_dir_entry * parent, + char * name, char * target) +{ + struct dentry * dentry; + int error = 0; + + if (!parent || !parent->dentry) + return -EINVAL; + + down(&parent->dentry->d_inode->i_sem); + dentry = get_dentry(parent->dentry,name); + if (!IS_ERR(dentry)) + error = sysfs_symlink(parent->dentry->d_inode,dentry,target); + else + error = PTR_ERR(dentry); + up(&parent->dentry->d_inode->i_sem); + return error; +} + +/** + * sysfs_remove_file - exported file removal + * @dir: directory the file supposedly resides in + * @name: name of the file + * + * Try and find the file in the dir's list. + * If it's there, call __remove_file() (above) for the dentry. + */ +void sysfs_remove_file(struct driver_dir_entry * dir, const char * name) +{ + struct dentry * dentry; + + if (!dir->dentry) + return; + + down(&dir->dentry->d_inode->i_sem); + dentry = get_dentry(dir->dentry,name); + if (!IS_ERR(dentry)) { + /* make sure dentry is really there */ + if (dentry->d_inode && + (dentry->d_parent->d_inode == dir->dentry->d_inode)) { + sysfs_unlink(dir->dentry->d_inode,dentry); + } + } + up(&dir->dentry->d_inode->i_sem); +} + +/** + * sysfs_remove_dir - exportable directory removal + * @dir: directory to remove + * + * To make sure we don't orphan anyone, first remove + * all the children in the list, then do clean up the directory. + */ +void sysfs_remove_dir(struct driver_dir_entry * dir) +{ + struct list_head * node, * next; + struct dentry * dentry = dir->dentry; + struct dentry * parent; + + if (!dentry) + return; + + parent = dget(dentry->d_parent); + down(&parent->d_inode->i_sem); + down(&dentry->d_inode->i_sem); + + list_for_each_safe(node,next,&dentry->d_subdirs) { + struct dentry * d = list_entry(node,struct dentry,d_child); + /* make sure dentry is still there */ + if (d->d_inode) + sysfs_unlink(dentry->d_inode,d); + } + + d_invalidate(dentry); + if (sysfs_empty(dentry)) { + dentry->d_inode->i_nlink -= 2; + dentry->d_inode->i_flags |= S_DEAD; + parent->d_inode->i_nlink--; + } + up(&dentry->d_inode->i_sem); + dput(dentry); + + up(&parent->d_inode->i_sem); + dput(parent); +} + +EXPORT_SYMBOL(sysfs_create_file); +EXPORT_SYMBOL(sysfs_create_symlink); +EXPORT_SYMBOL(sysfs_create_dir); +EXPORT_SYMBOL(sysfs_remove_file); +EXPORT_SYMBOL(sysfs_remove_dir); +MODULE_LICENSE("GPL"); diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index d337420fdeaf..7c15037a9dac 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -32,7 +32,8 @@ # Makefile for XFS on Linux. # -# This needs -I because everything does #include <xfs.h> instead of "xfs.h". + +# This needs -I. because everything does #include <xfs.h> instead of "xfs.h". # The code is wrong, local files should be included using "xfs.h", not <xfs.h> # but I am not going to change every file at the moment. EXTRA_CFLAGS += -Ifs/xfs -funsigned-char diff --git a/fs/xfs/linux/xfs_file.c b/fs/xfs/linux/xfs_file.c index c292bfc9f119..2776290d7020 100644 --- a/fs/xfs/linux/xfs_file.c +++ b/fs/xfs/linux/xfs_file.c @@ -113,6 +113,32 @@ linvfs_write( } +STATIC ssize_t +linvfs_aio_read( + struct kiocb *iocb, + char *buf, + size_t count, + loff_t pos) +{ + struct iovec iov = {buf, count}; + + return linvfs_readv(iocb->ki_filp, &iov, 1, &iocb->ki_pos); +} + + +STATIC ssize_t +linvfs_aio_write( + struct kiocb *iocb, + const char *buf, + size_t count, + loff_t pos) +{ + struct iovec iov = {(void *)buf, count}; + + return linvfs_writev(iocb->ki_filp, &iov, 1, &iocb->ki_pos); +} + + STATIC int linvfs_open( struct inode *inode, @@ -320,6 +346,8 @@ struct file_operations linvfs_file_operations = { .write = linvfs_write, .readv = linvfs_readv, .writev = linvfs_writev, + .aio_read = linvfs_aio_read, + .aio_write = linvfs_aio_write, .ioctl = linvfs_ioctl, .mmap = linvfs_file_mmap, .open = linvfs_open, diff --git a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c index 7f0ac30a83ba..94105d5fb14f 100644 --- a/fs/xfs/linux/xfs_globals.c +++ b/fs/xfs/linux/xfs_globals.c @@ -64,5 +64,6 @@ EXPORT_SYMBOL(xfs_Gqm); EXPORT_SYMBOL(xfs_next_bit); EXPORT_SYMBOL(xfs_contig_bits); EXPORT_SYMBOL(xfs_bmbt_get_all); +#if ARCH_CONVERT != ARCH_NOCONVERT EXPORT_SYMBOL(xfs_bmbt_disk_get_all); - +#endif diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 5c89a956c866..5dc29c28dbaf 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2135,19 +2135,6 @@ xfs_alloc_put_freelist( (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl), (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl + sizeof(xfs_agblock_t) - 1)); - /* - * Since blocks move to the free list without the coordination - * used in xfs_bmap_finish, we can't allow block to be available - * for reallocation and non-transaction writing (user data) - * until we know that the transaction that moved it to the free - * list is permanently on disk. We track the blocks by declaring - * these blocks as "busy"; the busy list is maintained on a per-ag - * basis and each transaction records which entries should be removed - * when the iclog commits to disk. If a busy block is allocated, - * the iclog is pushed up to the LSN that freed the block. - */ - xfs_alloc_mark_busy(tp, INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); - return 0; } diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 9bb3fe79243d..6ea6af923d2b 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -223,6 +223,23 @@ xfs_alloc_delrec( if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp, NULL, bno))) return error; + /* + * Since blocks move to the free list without the + * coordination used in xfs_bmap_finish, we can't allow + * block to be available for reallocation and + * non-transaction writing (user data) until we know + * that the transaction that moved it to the free list + * is permanently on disk. We track the blocks by + * declaring these blocks as "busy"; the busy list is + * maintained on a per-ag basis and each transaction + * records which entries should be removed when the + * iclog commits to disk. If a busy block is + * allocated, the iclog is pushed up to the LSN + * that freed the block. + */ + xfs_alloc_mark_busy(cur->bc_tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); + xfs_trans_agbtree_delta(cur->bc_tp, -1); xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); @@ -528,6 +545,21 @@ xfs_alloc_delrec( if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp, NULL, rbno))) return error; + /* + * Since blocks move to the free list without the coordination + * used in xfs_bmap_finish, we can't allow block to be available + * for reallocation and non-transaction writing (user data) + * until we know that the transaction that moved it to the free + * list is permanently on disk. We track the blocks by declaring + * these blocks as "busy"; the busy list is maintained on a + * per-ag basis and each transaction records which entries + * should be removed when the iclog commits to disk. If a + * busy block is allocated, the iclog is pushed up to the + * LSN that freed the block. + */ + xfs_alloc_mark_busy(cur->bc_tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); + xfs_trans_agbtree_delta(cur->bc_tp, -1); /* * Adjust the current level's cursor so that we're left referring diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 07d513d24f74..47e5dec6e688 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -253,11 +253,7 @@ xfs_bmbt_trace_cursor( xfs_bmbt_trace_enter(func, cur, s, XFS_BMBT_KTRACE_CUR, line, (cur->bc_nlevels << 24) | (cur->bc_private.b.flags << 16) | cur->bc_private.b.allocated, -#if BMBT_USE_64 INT_GET(r.l0, ARCH_CONVERT) >> 32, (int)INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT) >> 32, (int)INT_GET(r.l1, ARCH_CONVERT), -#else - INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT), INT_GET(r.l2, ARCH_CONVERT), INT_GET(r.l3, ARCH_CONVERT), -#endif (unsigned long)cur->bc_bufs[0], (unsigned long)cur->bc_bufs[1], (unsigned long)cur->bc_bufs[2], (unsigned long)cur->bc_bufs[3], (cur->bc_ptrs[0] << 16) | cur->bc_ptrs[1], diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 8aeefd43c967..1b8aa70f480f 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -658,8 +658,8 @@ xfs_bmbt_disk_set_allf( #else #define xfs_bmbt_disk_set_all(r, s) \ xfs_bmbt_set_all(r, s) -#define xfs_bmbt_disk_set_allf(r, 0, b, c, v) \ - xfs_bmbt_set_allf(r, 0, b, c, v) +#define xfs_bmbt_disk_set_allf(r, o, b, c, v) \ + xfs_bmbt_set_allf(r, o, b, c, v) #endif void diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bd343063b60d..45acdc3999c9 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -602,9 +602,12 @@ xfs_iformat_extents( int whichfork) { xfs_ifork_t *ifp; - int nex, i; + int nex; int real_size; int size; +#if ARCH_CONVERT != ARCH_NOCONVERT + int i; +#endif xfs_bmbt_rec_t *ep, *dp; ifp = XFS_IFORK_PTR(ip, whichfork); diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h index 4970205a5e69..c893dbfc9d37 100644 --- a/fs/xfs/xfs_inode_item.h +++ b/fs/xfs/xfs_inode_item.h @@ -126,7 +126,7 @@ typedef struct xfs_inode_log_format_v1 { #ifdef __KERNEL__ struct xfs_buf; -struct xfs_bmbt_rec_32; +struct xfs_bmbt_rec_64; struct xfs_inode; struct xfs_mount; @@ -141,9 +141,9 @@ typedef struct xfs_inode_log_item { unsigned short ili_flags; /* misc flags */ unsigned short ili_logged; /* flushed logged data */ unsigned int ili_last_fields; /* fields when flushed */ - struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged + struct xfs_bmbt_rec_64 *ili_extents_buf; /* array of logged data exts */ - struct xfs_bmbt_rec_32 *ili_aextents_buf; /* array of logged + struct xfs_bmbt_rec_64 *ili_aextents_buf; /* array of logged attr exts */ unsigned int ili_pushbuf_flag; /* one bit used in push_ail */ diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h index 865d995c4312..e26ea03e7347 100644 --- a/include/asm-i386/io_apic.h +++ b/include/asm-i386/io_apic.h @@ -22,9 +22,12 @@ * The structure of the IO-APIC: */ struct IO_APIC_reg_00 { - __u32 __reserved_2 : 24, + __u32 __reserved_2 : 14, + LTS : 1, + delivery_type : 1, + __reserved_1 : 8, ID : 4, - __reserved_1 : 4; + __reserved_0 : 4; } __attribute__ ((packed)); struct IO_APIC_reg_01 { diff --git a/include/asm-ppc/div64.h b/include/asm-ppc/div64.h index 114e6ab34147..ec3ae5bcb3de 100644 --- a/include/asm-ppc/div64.h +++ b/include/asm-ppc/div64.h @@ -1,10 +1,23 @@ #ifndef __PPC_DIV64 #define __PPC_DIV64 -#define do_div(n,base) ({ \ -int __res; \ -__res = ((unsigned long) n) % (unsigned) base; \ -n = ((unsigned long) n) / (unsigned) base; \ -__res; }) +#include <linux/types.h> + +extern u32 __div64_32(u64 *dividend, u32 div); + +#define do_div(n, div) ({ \ + u64 __n = (n); \ + u32 __d = (div); \ + u32 __q, __r; \ + if ((__n >> 32) == 0) { \ + __q = (u32)__n / __d; \ + __r = (u32)__n - __q * __d; \ + (n) = __q; \ + } else { \ + __r = __div64_32(&__n, __d); \ + (n) = __n; \ + } \ + __r; \ +}) #endif diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 1d7bec303e02..f17cca329ed9 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -68,6 +68,11 @@ struct pci_controller { struct pci_ops *ops; volatile unsigned int *cfg_addr; volatile unsigned char *cfg_data; + /* + * If set, indirect method will set the cfg_type bit as + * needed to generate type 1 configuration transactions. + */ + int set_cfg_type; /* Currently, we limit ourselves to 1 IO range and 3 mem * ranges since the common pci_bus structure can't handle more diff --git a/include/asm-ppc/sections.h b/include/asm-ppc/sections.h index 1f2f5fd05966..564e1e58f141 100644 --- a/include/asm-ppc/sections.h +++ b/include/asm-ppc/sections.h @@ -2,27 +2,27 @@ #ifndef _PPC_SECTIONS_H #define _PPC_SECTIONS_H -#define __pmac __attribute__ ((__section__ (".text.pmac"))) -#define __pmacdata __attribute__ ((__section__ (".data.pmac"))) +#define __pmac __attribute__ ((__section__ (".pmac.text"))) +#define __pmacdata __attribute__ ((__section__ (".pmac.data"))) #define __pmacfunc(__argpmac) \ __argpmac __pmac; \ __argpmac -#define __prep __attribute__ ((__section__ (".text.prep"))) -#define __prepdata __attribute__ ((__section__ (".data.prep"))) +#define __prep __attribute__ ((__section__ (".prep.text"))) +#define __prepdata __attribute__ ((__section__ (".prep.data"))) #define __prepfunc(__argprep) \ __argprep __prep; \ __argprep -#define __chrp __attribute__ ((__section__ (".text.chrp"))) -#define __chrpdata __attribute__ ((__section__ (".data.chrp"))) +#define __chrp __attribute__ ((__section__ (".chrp.text"))) +#define __chrpdata __attribute__ ((__section__ (".chrp.data"))) #define __chrpfunc(__argchrp) \ __argchrp __chrp; \ __argchrp /* this is actually just common chrp/pmac code, not OF code -- Cort */ -#define __openfirmware __attribute__ ((__section__ (".text.openfirmware"))) -#define __openfirmwaredata __attribute__ ((__section__ (".data.openfirmware"))) +#define __openfirmware __attribute__ ((__section__ (".openfirmware.text"))) +#define __openfirmwaredata __attribute__ ((__section__ (".openfirmware.data"))) #define __openfirmwarefunc(__argopenfirmware) \ __argopenfirmware __openfirmware; \ __argopenfirmware diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 58a305b6b0c7..8cbe28a3dc91 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -119,14 +119,14 @@ extern void __xchg_called_with_bad_pointer(void); #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) #define tas(ptr) (xchg((ptr),1)) -static inline unsigned long __xchg(unsigned long x, void * ptr, int size) +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { switch (size) { case 4: - return (unsigned long )xchg_u32(ptr, x); + return (unsigned long) xchg_u32(ptr, x); #if 0 /* xchg_u64 doesn't exist on 32-bit PPC */ case 8: - return (unsigned long )xchg_u64(ptr, x); + return (unsigned long) xchg_u64(ptr, x); #endif /* 0 */ } __xchg_called_with_bad_pointer(); diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index ff3bd04a3253..53d4136efb91 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -73,7 +73,12 @@ extern void show_regs(struct pt_regs *); #define REGWIN_SZ 0x40 #endif -#include <asm/asm_offsets.h> +/* + * The asm_offsets.h is a generated file, so we cannot include it. + * It may be OK for glibc headers, but it's utterly pointless for C code. + * The assembly code using those offsets has to include it explicitly. + */ +/* #include <asm/asm_offsets.h> */ /* These are for pt_regs. */ #define PT_PSR 0x0 diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ccb56d58de6a..42e81a4a0cab 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -235,6 +235,7 @@ struct request_queue #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) #define blk_queue_empty(q) elv_queue_empty(q) #define blk_fs_request(rq) ((rq)->flags & REQ_CMD) +#define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) #define rq_data_dir(rq) ((rq)->flags & 1) diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 4387203c95b7..7ac3926382f8 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -731,7 +731,6 @@ struct cdrom_device_info { struct cdrom_device_info *next; /* next device_info for this major */ void *handle; /* driver-dependent data */ /* specifications */ - kdev_t dev; /* device number */ int mask; /* mask of capability: disables them */ int speed; /* maximum speed for reading data */ int capacity; /* number of discs in jukebox */ @@ -776,10 +775,10 @@ struct cdrom_device_ops { }; /* the general block_device operations structure: */ -extern int cdrom_open(struct inode *, struct file *); -extern int cdrom_release(struct inode *, struct file *); -extern int cdrom_ioctl(struct inode *, struct file *, unsigned, unsigned long); -extern int cdrom_media_changed(kdev_t); +extern int cdrom_open(struct cdrom_device_info *, struct inode *, struct file *); +extern int cdrom_release(struct cdrom_device_info *, struct file *); +extern int cdrom_ioctl(struct cdrom_device_info *, struct inode *, unsigned, unsigned long); +extern int cdrom_media_changed(struct cdrom_device_info *); extern int register_cdrom(struct cdrom_device_info *cdi); extern int unregister_cdrom(struct cdrom_device_info *cdi); diff --git a/include/linux/device.h b/include/linux/device.h index 80a63939f924..3dd9a4081298 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -48,14 +48,22 @@ enum { RESUME_ENABLE, }; +enum device_state { + DEVICE_UNINITIALIZED = 0, + DEVICE_INITIALIZED = 1, + DEVICE_REGISTERED = 2, + DEVICE_GONE = 3, +}; + struct device; struct device_driver; struct device_class; struct bus_type { char * name; - rwlock_t lock; + struct rw_semaphore rwsem; atomic_t refcount; + u32 present; struct list_head node; struct list_head devices; @@ -73,14 +81,9 @@ struct bus_type { extern int bus_register(struct bus_type * bus); +extern void bus_unregister(struct bus_type * bus); -static inline struct bus_type * get_bus(struct bus_type * bus) -{ - BUG_ON(!atomic_read(&bus->refcount)); - atomic_inc(&bus->refcount); - return bus; -} - +extern struct bus_type * get_bus(struct bus_type * bus); extern void put_bus(struct bus_type * bus); extern int bus_for_each_dev(struct bus_type * bus, void * data, @@ -114,6 +117,7 @@ struct device_driver { rwlock_t lock; atomic_t refcount; + u32 present; struct list_head bus_list; struct list_head class_list; @@ -123,7 +127,7 @@ struct device_driver { int (*probe) (struct device * dev); int (*remove) (struct device * dev); - + void (*shutdown) (struct device * dev); int (*suspend) (struct device * dev, u32 state, u32 level); int (*resume) (struct device * dev, u32 level); @@ -131,16 +135,10 @@ struct device_driver { }; - extern int driver_register(struct device_driver * drv); +extern void driver_unregister(struct device_driver * drv); -static inline struct device_driver * get_driver(struct device_driver * drv) -{ - BUG_ON(!atomic_read(&drv->refcount)); - atomic_inc(&drv->refcount); - return drv; -} - +extern struct device_driver * get_driver(struct device_driver * drv); extern void put_driver(struct device_driver * drv); extern void remove_driver(struct device_driver * drv); @@ -172,6 +170,11 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * */ struct device_class { char * name; + struct rw_semaphore rwsem; + + atomic_t refcount; + u32 present; + u32 devnum; struct list_head node; @@ -189,6 +192,9 @@ struct device_class { extern int devclass_register(struct device_class *); extern void devclass_unregister(struct device_class *); +extern struct device_class * get_devclass(struct device_class *); +extern void put_devclass(struct device_class *); + struct devclass_attribute { struct attribute attr; @@ -289,8 +295,8 @@ struct device { void *platform_data; /* Platform specific data (e.g. ACPI, BIOS data relevant to device) */ - u32 present; - u32 current_state; /* Current operating state. In + enum device_state state; + u32 power_state; /* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, and D3 being off. */ @@ -362,6 +368,11 @@ extern int (*platform_notify)(struct device * dev); extern int (*platform_notify_remove)(struct device * dev); +static inline int device_present(struct device * dev) +{ + return (dev && (dev->state == DEVICE_INITIALIZED || dev->state == DEVICE_REGISTERED)); +} + /* device and bus locking helpers. * * FIXME: Is there anything else we need to do? diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index d859f8c2e041..b4270e947a1e 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent, extern void driverfs_remove_file(struct driver_dir_entry *, const char * name); -extern int init_driverfs_fs(void); - #endif /* _DDFS_H_ */ diff --git a/include/linux/fs.h b/include/linux/fs.h index bca164f4265a..c2e39a247227 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -730,8 +730,8 @@ struct block_device_operations { int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); - int (*check_media_change) (kdev_t); - int (*revalidate) (kdev_t); + int (*media_changed) (struct gendisk *); + int (*revalidate_disk) (struct gendisk *); struct module *owner; }; @@ -1251,7 +1251,8 @@ extern ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, lof ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos); extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t); -extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); +extern void do_generic_mapping_read(struct address_space *, struct file_ra_state *, struct file *, + loff_t *, read_descriptor_t *, read_actor_t); extern ssize_t generic_file_direct_IO(int rw, struct file *file, const struct iovec *iov, loff_t offset, unsigned long nr_segs); extern int generic_direct_IO(int rw, struct inode *inode, const struct iovec @@ -1268,6 +1269,18 @@ extern int generic_file_open(struct inode * inode, struct file * filp); extern int generic_vm_writeback(struct page *page, struct writeback_control *wbc); +static inline void do_generic_file_read(struct file * filp, loff_t *ppos, + read_descriptor_t * desc, + read_actor_t actor) +{ + do_generic_mapping_read(filp->f_dentry->d_inode->i_mapping, + &filp->f_ra, + filp, + ppos, + desc, + actor); +} + extern struct file_operations generic_ro_fops; extern int vfs_readlink(struct dentry *, char *, int, const char *); diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 9de2f51ae935..8cd8a826bf6f 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -80,6 +80,8 @@ struct gendisk { char disk_name[16]; /* name of major driver */ struct hd_struct *part; /* [indexed by minor] */ struct block_device_operations *fops; + struct request_queue *queue; + void *private_data; sector_t capacity; struct list_head list; struct list_head full_list; @@ -273,8 +275,12 @@ extern struct gendisk *alloc_disk(int minors); extern struct gendisk *get_disk(struct gendisk *disk); extern void put_disk(struct gendisk *disk); -/* will go away */ -extern void blk_set_probe(int major, struct gendisk *(p)(int)); +extern void blk_register_region(dev_t dev, unsigned long range, + struct module *module, + struct gendisk *(*probe)(dev_t, int *, void *), + void (*lock)(dev_t, void *), + void *data); +extern void blk_unregister_region(dev_t dev, unsigned long range); #endif diff --git a/include/linux/ide.h b/include/linux/ide.h index 44cb38c00b96..607464f740f5 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1256,7 +1256,6 @@ extern int noautodma; */ #define IDE_DRIVER /* Toggle some magic bits in blk.h */ #define LOCAL_END_REQUEST /* Don't generate end_request in blk.h */ -#define DEVICE_NR(device) (minor(device) >> PARTN_BITS) #include <linux/blk.h> extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs); @@ -1316,12 +1315,7 @@ extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long * This routine is called from the partition-table code in genhd.c * to "convert" a drive to a logical geometry with fewer than 1024 cyls. */ -extern int ide_xlate_1024 (kdev_t, int, int, const char *); - -/* - * Convert kdev_t structure into ide_drive_t * one. - */ -extern ide_drive_t *get_info_ptr (kdev_t i_rdev); +extern int ide_xlate_1024(struct block_device *, int, int, const char *); /* * Return the current idea about the total capacity of this drive. @@ -1577,11 +1571,6 @@ extern int ide_system_bus_speed(void); extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout); /* - * ide_get_queue() returns the queue which corresponds to a given device. - */ -extern request_queue_t *ide_get_queue (kdev_t dev); - -/* * CompactFlash cards and their brethern pretend to be removable hard disks, * but they never have a slave unit, and they don't have doorlock mechanisms. * This test catches them, and is invoked elsewhere when setting appropriate diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 8203314e2cb7..0d0ce25b333e 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -338,16 +338,35 @@ typedef struct isdn_net_local_s { /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ - struct list_head slaves; /* list of all bundled channels */ - struct list_head online; /* list of all bundled channels, - which are currently online */ - spinlock_t online_lock; /* lock to protect online list */ + struct list_head slaves; /* list of all bundled channels + protected by serializing config + ioctls / no change allowed when + interface is running */ + struct list_head online; /* list of all bundled channels + which can be used for actual + data (IP) transfer + protected by xmit_lock */ + + spinlock_t xmit_lock; /* used to protect the xmit path of + a net_device, including all + associated channels's frame_cnt */ struct list_head running_devs; /* member of global running_devs */ atomic_t refcnt; /* references held by ISDN code */ #ifdef CONFIG_ISDN_X25 struct concap_device_ops *dops; /* callbacks used by encapsulator */ #endif +#ifdef CONFIG_ISDN_PPP + unsigned int mpppcfg; + long mp_seqno; + struct ippp_ccp *ccp; + unsigned long debug; +#ifdef CONFIG_ISDN_PPP_VJ + unsigned char *cbuf; + struct slcompress *slcomp; +#endif +#endif + /* use an own struct for that in later versions */ ulong cisco_myseq; /* Local keepalive seq. for Cisco */ ulong cisco_mineseen; /* returned keepalive seq. from remote */ @@ -391,14 +410,11 @@ typedef struct isdn_net_dev_s { int chargeint; /* Interval between charge-infos */ int pppbind; /* ippp device for bindings */ - int ppp_slot; /* PPPD device slot number */ + struct ipppd *ipppd; /* /dev/ipppX which controls us */ - spinlock_t xmit_lock; /* used to protect the xmit path of */ - /* a particular channel (including */ - /* the frame_cnt */ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ /* be transmitted asap */ - atomic_t frame_cnt; /* number of frames currently */ + int frame_cnt; /* number of frames currently */ /* queued in HL driver */ struct tasklet_struct tlet; @@ -410,6 +426,11 @@ typedef struct isdn_net_dev_s { char name[10]; /* Name of device */ struct list_head global_list; /* global list of all isdn_net_devs */ #ifdef CONFIG_ISDN_PPP + unsigned int pppcfg; + unsigned int pppseq; /* last seq no seen */ + struct ippp_ccp *ccp; + unsigned long debug; + ippp_bundle * pb; /* pointer to the common bundle structure * with the per-bundle data */ #endif diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 68353a39b98c..ec6016c37421 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -8,7 +8,6 @@ #ifndef _LINUX_ISDN_PPP_H #define _LINUX_ISDN_PPP_H - #define CALLTYPE_INCOMING 0x1 #define CALLTYPE_OUTGOING 0x2 #define CALLTYPE_CALLBACK 0x4 @@ -39,15 +38,6 @@ struct pppcallinfo #define SC_OUT_SHORT_SEQ 0x00000800 #define SC_IN_SHORT_SEQ 0x00004000 -#define SC_DECOMP_ON 0x01 -#define SC_COMP_ON 0x02 -#define SC_DECOMP_DISCARD 0x04 -#define SC_COMP_DISCARD 0x08 -#define SC_LINK_DECOMP_ON 0x10 -#define SC_LINK_COMP_ON 0x20 -#define SC_LINK_DECOMP_DISCARD 0x40 -#define SC_LINK_COMP_DISCARD 0x80 - #define ISDN_PPP_COMP_MAX_OPTIONS 16 #define IPPP_COMP_FLAG_XMIT 0x1 @@ -64,7 +54,8 @@ struct isdn_ppp_comp_data { #include <linux/config.h> - +#include <linux/skbuff.h> +#include <linux/ppp_defs.h> #define DECOMP_ERR_NOMEM (-10) @@ -172,8 +163,8 @@ enum ippp_ccp_reset_states { struct ippp_ccp_reset_state { enum ippp_ccp_reset_states state; /* State of this transaction */ - struct ippp_struct *is; /* Backlink to device stuff */ - unsigned char id; /* Backlink id index */ + struct ippp_ccp *ccp; /* Backlink */ + unsigned char id; /* id index */ unsigned char ta:1; /* The timer is active (flag) */ unsigned char expra:1; /* We expect a ResetAck at all */ int dlen; /* Databytes stored in data */ @@ -191,34 +182,5 @@ struct ippp_ccp_reset { unsigned char lastid; /* Last id allocated by the engine */ }; -struct ippp_struct { - struct ippp_struct *next_link; - int state; - struct sk_buff_head rq; - wait_queue_head_t wq; - struct task_struct *tk; - unsigned int mpppcfg; - unsigned int pppcfg; - unsigned int mru; - unsigned int mpmru; - unsigned int mpmtu; - unsigned int maxcid; - struct isdn_net_dev_s *idev; - int unit; - int minor; - unsigned int last_link_seqno; - long mp_seqno; -#ifdef CONFIG_ISDN_PPP_VJ - unsigned char *cbuf; - struct slcompress *slcomp; -#endif - unsigned long debug; - struct isdn_ppp_compressor *compressor,*decompressor; - struct isdn_ppp_compressor *link_compressor,*link_decompressor; - void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; - struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ - unsigned long compflags; -}; - #endif /* __KERNEL__ */ #endif /* _LINUX_ISDN_PPP_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index d0b9bdb97523..cab2c4342047 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -512,11 +512,18 @@ int write_one_page(struct page *page, int wait); /* readahead.c */ #define VM_MAX_READAHEAD 128 /* kbytes */ #define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */ -int do_page_cache_readahead(struct file *file, +int do_page_cache_readahead(struct address_space *mapping, struct file *filp, unsigned long offset, unsigned long nr_to_read); -void page_cache_readahead(struct file *file, unsigned long offset); -void page_cache_readaround(struct file *file, unsigned long offset); -void handle_ra_miss(struct file *file); +void page_cache_readahead(struct address_space *mapping, + struct file_ra_state *ra, + struct file *filp, + unsigned long offset); +void page_cache_readaround(struct address_space *mapping, + struct file_ra_state *ra, + struct file *filp, + unsigned long offset); +void handle_ra_miss(struct address_space *mapping, + struct file_ra_state *ra); /* Do stack extension */ extern int expand_stack(struct vm_area_struct * vma, unsigned long address); diff --git a/include/linux/security.h b/include/linux/security.h index 072fbe94dd8b..e2f80f6a9dba 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -376,10 +376,6 @@ struct swap_info_struct; * @file_free_security: * Deallocate and free any security structures stored in file->f_security. * @file contains the file structure being modified. - * @file_llseek: - * Check permission before re-positioning the file offset in @file. - * @file contains the file structure being modified. - * Return 0 if permission is granted. * @file_ioctl: * @file contains the file structure. * @cmd contains the operation to perform. @@ -790,7 +786,6 @@ struct security_operations { int (*file_permission) (struct file * file, int mask); int (*file_alloc_security) (struct file * file); void (*file_free_security) (struct file * file); - int (*file_llseek) (struct file * file); int (*file_ioctl) (struct file * file, unsigned int cmd, unsigned long arg); int (*file_mmap) (struct file * file, diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h new file mode 100644 index 000000000000..6479902e1d20 --- /dev/null +++ b/include/linux/sysfs.h @@ -0,0 +1,51 @@ +/* + * sysfs.h - definitions for the device driver filesystem + * + * Copyright (c) 2001,2002 Patrick Mochel + * + * Please see Documentation/filesystems/sysfs.txt for more information. + */ + +#ifndef _SYSFS_H_ +#define _SYSFS_H_ + +struct driver_dir_entry; +struct attribute; + +struct sysfs_ops { + int (*open)(struct driver_dir_entry *); + int (*close)(struct driver_dir_entry *); + ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t); + ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t); +}; + +struct driver_dir_entry { + char * name; + struct dentry * dentry; + mode_t mode; + struct sysfs_ops * ops; +}; + +struct attribute { + char * name; + mode_t mode; +}; + +extern int +sysfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); + +extern void +sysfs_remove_dir(struct driver_dir_entry * entry); + +extern int +sysfs_create_file(struct attribute * attr, + struct driver_dir_entry * parent); + +extern int +sysfs_create_symlink(struct driver_dir_entry * parent, + char * name, char * target); + +extern void +sysfs_remove_file(struct driver_dir_entry *, const char * name); + +#endif /* _SYSFS_H_ */ diff --git a/include/scsi/sg.h b/include/scsi/sg.h index ddf83957b343..b5f80d97f07b 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h @@ -130,7 +130,7 @@ typedef struct sg_io_hdr /* following flag values can be "or"-ed together */ #define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */ -#define SG_FLAG_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */ +#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */ /* command block (when <= SCSI_2) */ #define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */ #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */ diff --git a/init/Makefile b/init/Makefile index 6dbffbfb4b70..60f06f6ccb81 100644 --- a/init/Makefile +++ b/init/Makefile @@ -4,17 +4,20 @@ obj-y := main.o version.o do_mounts.o +# files to be removed upon make clean +clean-files := ../include/linux/compile.h + include $(TOPDIR)/Rules.make # dependencies on generated files need to be listed explicitly -$(obj)/version.o: $(objtree)/include/linux/compile.h +$(obj)/version.o: $(obj)/../include/linux/compile.h # compile.h changes depending on hostname, generation number, etc, # so we regenerate it always. # mkcompile_h will make sure to only update the # actual file if its content has changed. -$(objtree)/include/linux/compile.h: FORCE - @echo -n ' Generating $@' +$(obj)/../include/linux/compile.h: FORCE + @echo -n ' Generating $(echo_target)' @sh $(srctree)/scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)" diff --git a/kernel/ksyms.c b/kernel/ksyms.c index d3eddedb7468..941d5f9eec9d 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -229,7 +229,7 @@ EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(generic_file_sendfile); -EXPORT_SYMBOL(do_generic_file_read); +EXPORT_SYMBOL(do_generic_mapping_read); EXPORT_SYMBOL(generic_file_write); EXPORT_SYMBOL(generic_file_write_nolock); EXPORT_SYMBOL(generic_file_mmap); diff --git a/mm/filemap.c b/mm/filemap.c index b2fbb1cbf90b..67d03d5d7732 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -570,10 +570,15 @@ void mark_page_accessed(struct page *page) * * This is really ugly. But the goto's actually try to clarify some * of the logic when it comes to error handling etc. + * - note the struct file * is only passed for the use of readpage */ -void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor) +void do_generic_mapping_read(struct address_space *mapping, + struct file_ra_state *ra, + struct file * filp, + loff_t *ppos, + read_descriptor_t * desc, + read_actor_t actor) { - struct address_space *mapping = filp->f_dentry->d_inode->i_mapping; struct inode *inode = mapping->host; unsigned long index, offset; struct page *cached_page; @@ -598,7 +603,7 @@ void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * break; } - page_cache_readahead(filp, index); + page_cache_readahead(mapping, ra, filp, index); nr = nr - offset; @@ -610,7 +615,7 @@ find_page: page = radix_tree_lookup(&mapping->page_tree, index); if (!page) { read_unlock(&mapping->page_lock); - handle_ra_miss(filp); + handle_ra_miss(mapping,ra); goto no_cached_page; } page_cache_get(page); @@ -891,6 +896,7 @@ generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos) BUG_ON(iocb->ki_pos != pos); return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); } +EXPORT_SYMBOL(generic_file_aio_read); ssize_t generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos) @@ -946,9 +952,9 @@ ssize_t generic_file_sendfile(struct file *out_file, struct file *in_file, } static ssize_t -do_readahead(struct file *file, unsigned long index, unsigned long nr) +do_readahead(struct address_space *mapping, struct file *filp, + unsigned long index, unsigned long nr) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; unsigned long max; unsigned long active; unsigned long inactive; @@ -962,7 +968,7 @@ do_readahead(struct file *file, unsigned long index, unsigned long nr) if (nr > max) nr = max; - do_page_cache_readahead(file, index, nr); + do_page_cache_readahead(mapping, filp, index, nr); return 0; } @@ -975,10 +981,11 @@ asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count) file = fget(fd); if (file) { if (file->f_mode & FMODE_READ) { + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; unsigned long start = offset >> PAGE_CACHE_SHIFT; unsigned long end = (offset + count - 1) >> PAGE_CACHE_SHIFT; unsigned long len = end - start + 1; - ret = do_readahead(file, start, len); + ret = do_readahead(mapping, file, start, len); } fput(file); } @@ -999,6 +1006,7 @@ struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address int error; struct file *file = area->vm_file; struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct file_ra_state *ra = &file->f_ra; struct inode *inode = mapping->host; struct page *page; unsigned long size, pgoff, endoff; @@ -1031,7 +1039,7 @@ retry_all: */ if (VM_SequentialReadHint(area)) { did_readahead = 1; - page_cache_readahead(area->vm_file, pgoff); + page_cache_readahead(mapping, ra, file, pgoff); } /* @@ -1040,7 +1048,7 @@ retry_all: */ if ((pgoff < size) && !VM_RandomReadHint(area)) { did_readahead = 1; - page_cache_readaround(file, pgoff); + page_cache_readaround(mapping, ra, file, pgoff); } /* @@ -1050,7 +1058,7 @@ retry_find: page = find_get_page(mapping, pgoff); if (!page) { if (did_readahead) { - handle_ra_miss(file); + handle_ra_miss(mapping,ra); did_readahead = 0; } goto no_cached_page; @@ -1650,6 +1658,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const char *buf, { return generic_file_write(iocb->ki_filp, buf, count, &iocb->ki_pos); } +EXPORT_SYMBOL(generic_file_aio_write); ssize_t generic_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) diff --git a/mm/madvise.c b/mm/madvise.c index 4a232cead910..ac845fe3553a 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -80,7 +80,7 @@ static long madvise_willneed(struct vm_area_struct * vma, if ((vma->vm_mm->rss + (end - start)) > rlim_rss) return error; - do_page_cache_readahead(file, start, end - start); + do_page_cache_readahead(file->f_dentry->d_inode->i_mapping, file, start, end - start); return 0; } diff --git a/mm/readahead.c b/mm/readahead.c index e1e68fc006dc..63528f6eed98 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -22,18 +22,18 @@ struct backing_dev_info default_backing_dev_info = { /* * Return max readahead size for this inode in number-of-pages. */ -static inline unsigned long get_max_readahead(struct file *file) +static inline unsigned long get_max_readahead(struct file_ra_state *ra) { - return file->f_ra.ra_pages; + return ra->ra_pages; } -static inline unsigned long get_min_readahead(struct file *file) +static inline unsigned long get_min_readahead(struct file_ra_state *ra) { return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE; } static int -read_pages(struct file *file, struct address_space *mapping, +read_pages(struct address_space *mapping, struct file *filp, struct list_head *pages, unsigned nr_pages) { unsigned page_idx; @@ -48,7 +48,7 @@ read_pages(struct file *file, struct address_space *mapping, struct page *page = list_entry(pages->prev, struct page, list); list_del(&page->list); if (!add_to_page_cache(page, mapping, page->index)) { - mapping->a_ops->readpage(file, page); + mapping->a_ops->readpage(filp, page); if (!pagevec_add(&lru_pvec, page)) __pagevec_lru_add(&lru_pvec); } else { @@ -134,10 +134,11 @@ read_pages(struct file *file, struct address_space *mapping, * * Returns the number of pages which actually had IO started against them. */ -int do_page_cache_readahead(struct file *file, - unsigned long offset, unsigned long nr_to_read) +int do_page_cache_readahead(struct address_space *mapping, + struct file *filp, + unsigned long offset, + unsigned long nr_to_read) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct inode *inode = mapping->host; struct page *page; unsigned long end_index; /* The last page we want to read */ @@ -181,7 +182,7 @@ int do_page_cache_readahead(struct file *file, * will then handle the error. */ if (ret) { - read_pages(file, mapping, &page_pool, ret); + read_pages(mapping, filp, &page_pool, ret); blk_run_queues(); } BUG_ON(!list_empty(&page_pool)); @@ -216,9 +217,9 @@ check_ra_success(struct file_ra_state *ra, pgoff_t attempt, * page_cache_readahead is the main function. If performs the adaptive * readahead window size management and submits the readahead I/O. */ -void page_cache_readahead(struct file *file, unsigned long offset) +void page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, + struct file *filp, unsigned long offset) { - struct file_ra_state *ra = &file->f_ra; unsigned max; unsigned min; unsigned orig_next_size; @@ -239,11 +240,11 @@ void page_cache_readahead(struct file *file, unsigned long offset) if (ra->next_size == -1UL) goto out; /* Maximally shrunk */ - max = get_max_readahead(file); + max = get_max_readahead(ra); if (max == 0) goto out; /* No readahead */ - min = get_min_readahead(file); + min = get_min_readahead(ra); orig_next_size = ra->next_size; if (ra->next_size == 0 && offset == 0) { @@ -316,7 +317,8 @@ do_io: ra->ahead_start = 0; /* Invalidate these */ ra->ahead_size = 0; - actual = do_page_cache_readahead(file, offset, ra->size); + actual = do_page_cache_readahead(mapping, filp, offset, + ra->size); check_ra_success(ra, ra->size, actual, orig_next_size); } else { /* @@ -327,7 +329,7 @@ do_io: if (ra->ahead_start == 0) { ra->ahead_start = ra->start + ra->size; ra->ahead_size = ra->next_size; - actual = do_page_cache_readahead(file, + actual = do_page_cache_readahead(mapping, filp, ra->ahead_start, ra->ahead_size); check_ra_success(ra, ra->ahead_size, actual, orig_next_size); @@ -342,12 +344,11 @@ out: * but somewhat ascending. So readaround favours pages beyond the target one. * We also boost the window size, as it can easily shrink due to misses. */ -void page_cache_readaround(struct file *file, unsigned long offset) +void page_cache_readaround(struct address_space *mapping, struct file_ra_state *ra, + struct file *filp, unsigned long offset) { - struct file_ra_state *ra = &file->f_ra; - if (ra->next_size != -1UL) { - const unsigned long min = get_min_readahead(file) * 2; + const unsigned long min = get_min_readahead(ra) * 2; unsigned long target; unsigned long backward; @@ -365,7 +366,7 @@ void page_cache_readaround(struct file *file, unsigned long offset) target = 0; else target -= backward; - page_cache_readahead(file, target); + page_cache_readahead(mapping, ra, filp, target); } } @@ -383,10 +384,9 @@ void page_cache_readaround(struct file *file, unsigned long offset) * that the readahead window size will stabilise around the maximum level at * which there is no thrashing. */ -void handle_ra_miss(struct file *file) +void handle_ra_miss(struct address_space *mapping, struct file_ra_state *ra) { - struct file_ra_state *ra = &file->f_ra; - const unsigned long min = get_min_readahead(file); + const unsigned long min = get_min_readahead(ra); if (ra->next_size == -1UL) { ra->next_size = min; diff --git a/net/ipv4/ip_proc.c b/net/ipv4/ip_proc.c index 74b67e8dcd67..7d41c499ba9e 100644 --- a/net/ipv4/ip_proc.c +++ b/net/ipv4/ip_proc.c @@ -67,99 +67,185 @@ static char *ax2asc2(ax25_address *a, char *buf) } #endif /* CONFIG_AX25 */ +struct arp_iter_state { + loff_t is_pneigh: 1, + bucket: 6, + pos: sizeof(loff_t) * 8 - 7; +}; + +static __inline__ struct neighbour *neigh_get_bucket(loff_t *pos) +{ + struct neighbour *n = NULL; + struct arp_iter_state* state = (struct arp_iter_state *)pos; + loff_t l = state->pos; + int i, bucket = state->bucket; + + for (; bucket <= NEIGH_HASHMASK; ++bucket) + for (i = 0, n = arp_tbl.hash_buckets[bucket]; n; + ++i, n = n->next) + /* Do not confuse users "arp -a" with magic entries */ + if ((n->nud_state & ~NUD_NOARP) && !l--) { + state->pos = i; + state->bucket = bucket; + goto out; + } +out: + return n; +} + +static __inline__ struct pneigh_entry *pneigh_get_bucket(loff_t *pos) +{ + struct pneigh_entry *n = NULL; + struct arp_iter_state* state = (struct arp_iter_state *)pos; + loff_t l = state->pos; + int i, bucket = state->bucket; + + for (; bucket <= PNEIGH_HASHMASK; ++bucket) + for (i = 0, n = arp_tbl.phash_buckets[bucket]; n; + ++i, n = n->next) + if (!l--) { + state->pos = i; + state->bucket = bucket; + goto out; + } +out: + return n; +} + +static __inline__ void *arp_get_bucket(struct seq_file *seq, loff_t *pos) +{ + void *rc = neigh_get_bucket(pos); + + if (!rc) { + struct arp_iter_state* state = (struct arp_iter_state *)pos; + + read_unlock_bh(&arp_tbl.lock); + state->is_pneigh = 1; + state->bucket = 0; + state->pos = 0; + /* HACK: till there is state we can pass to seq_show... */ + seq->private = (void *)1; + rc = pneigh_get_bucket(pos); + } + return rc; +} + static void *arp_seq_start(struct seq_file *seq, loff_t *pos) { - return (void *)(unsigned long)++*pos; + read_lock_bh(&arp_tbl.lock); + return *pos ? arp_get_bucket(seq, pos) : (void *)1; } static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - return (void *)(unsigned long)((++*pos) >= - (NEIGH_HASHMASK + - PNEIGH_HASHMASK - 1) ? 0 : *pos); + void *rc; + struct arp_iter_state* state; + + if (v == (void *)1) { + rc = arp_get_bucket(seq, pos); + goto out; + } + + state = (struct arp_iter_state *)pos; + if (!state->is_pneigh) { + struct neighbour *n = v; + + rc = n = n->next; + if (n) + goto out; + state->pos = 0; + ++state->bucket; + rc = neigh_get_bucket(pos); + if (rc) + goto out; + read_unlock_bh(&arp_tbl.lock); + /* HACK: till there is state we can pass to seq_show... */ + seq->private = (void *)1; + state->is_pneigh = 1; + state->bucket = 0; + state->pos = 0; + rc = pneigh_get_bucket(pos); + } else { + struct pneigh_entry *pn = v; + + pn = pn->next; + if (!pn) { + ++state->bucket; + state->pos = 0; + pn = pneigh_get_bucket(pos); + } + rc = pn; + } +out: + ++*pos; + return rc; } static void arp_seq_stop(struct seq_file *seq, void *v) { + if (!seq->private) + read_unlock_bh(&arp_tbl.lock); } #define HBUFFERLEN 30 -static __inline__ void arp_format_neigh_table(struct seq_file *seq, int entry) +static __inline__ void arp_format_neigh_entry(struct seq_file *seq, + struct neighbour *n) { char hbuffer[HBUFFERLEN]; const char hexbuf[] = "0123456789ABCDEF"; - struct neighbour *n; int k, j; + char tbuf[16]; + struct net_device *dev = n->dev; + int hatype = dev->type; - read_lock_bh(&arp_tbl.lock); - for (n = arp_tbl.hash_buckets[entry]; n; n = n->next) { - char tbuf[16]; - struct net_device *dev = n->dev; - int hatype = dev->type; - - /* Do not confuse users "arp -a" with magic entries */ - if (!(n->nud_state & ~NUD_NOARP)) - continue; - - read_lock(&n->lock); - /* Convert hardware address to XX:XX:XX:XX ... form. */ + read_lock(&n->lock); + /* Convert hardware address to XX:XX:XX:XX ... form. */ #ifdef CONFIG_AX25 - if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) - ax2asc2((ax25_address *)n->ha, hbuffer); - else { + if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) + ax2asc2((ax25_address *)n->ha, hbuffer); + else { #endif - for (k = 0, j = 0; k < HBUFFERLEN - 3 && - j < dev->addr_len; j++) { - hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15]; - hbuffer[k++] = hexbuf[n->ha[j] & 15]; - hbuffer[k++] = ':'; - } - hbuffer[--k] = 0; + for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) { + hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15]; + hbuffer[k++] = hexbuf[n->ha[j] & 15]; + hbuffer[k++] = ':'; + } + hbuffer[--k] = 0; #ifdef CONFIG_AX25 - } -#endif - sprintf(tbuf, "%u.%u.%u.%u", - NIPQUAD(*(u32*)n->primary_key)); - seq_printf(seq, "%-16s 0x%-10x0x%-10x%s" - " * %s\n", - tbuf, hatype, arp_state_to_flags(n), - hbuffer, dev->name); - read_unlock(&n->lock); } - read_unlock_bh(&arp_tbl.lock); +#endif + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); + seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", + tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); + read_unlock(&n->lock); } -static __inline__ void arp_format_pneigh_table(struct seq_file *seq, int entry) +static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, + struct pneigh_entry *n) { - struct pneigh_entry *n; - - for (n = arp_tbl.phash_buckets[entry]; n; n = n->next) { - struct net_device *dev = n->dev; - int hatype = dev ? dev->type : 0; - char tbuf[16]; - - sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); - seq_printf(seq, "%-16s 0x%-10x0x%-10x%s" - " * %s\n", - tbuf, hatype, ATF_PUBL | ATF_PERM, - "00:00:00:00:00:00", - dev ? dev->name : "*"); - } + + struct net_device *dev = n->dev; + int hatype = dev ? dev->type : 0; + char tbuf[16]; + + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); + seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", + tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", + dev ? dev->name : "*"); } static int arp_seq_show(struct seq_file *seq, void *v) { - unsigned long l = (unsigned long)v - 1; - - if (!l) + if (v == (void *)1) seq_puts(seq, "IP address HW type Flags " "HW address Mask Device\n"); - - if (l <= NEIGH_HASHMASK) - arp_format_neigh_table(seq, l); - else - arp_format_pneigh_table(seq, l - NEIGH_HASHMASK); + else { + if (seq->private) + arp_format_pneigh_entry(seq, v); + else + arp_format_neigh_entry(seq, v); + } return 0; } diff --git a/scripts/Makefile b/scripts/Makefile index 0921e79c6c79..6032efe0f0aa 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -11,6 +11,8 @@ EXTRA_TARGETS := fixdep split-include docproc conmakehash +subdir- := lxdialog + # Yikes. We need to build this stuff here even if the user only wants # modules. @@ -24,6 +26,8 @@ KBUILD_BUILTIN := 1 host-progs := fixdep split-include conmakehash docproc tkparse tkparse-objs := tkparse.o tkcond.o tkgen.o +clean-files := kconfig.tk + include $(TOPDIR)/Rules.make # In reality kconfig.tk should depend on all Config.in files, @@ -56,8 +60,3 @@ lxdialog: # fixdep is needed to compile other host programs $(obj)/split-include $(obj)/docproc $(addprefix $(obj)/,$(tkparse-objs)) \ $(obj)/conmakehash lxdialog: $(obj)/fixdep - -mrproper: - @rm -f $(host-progs) $(addprefix $(obj)/,$(tkparse-objs) kconfig.tk core) - @$(call descend,scripts/lxdialog,mrproper) - diff --git a/scripts/lxdialog/Makefile b/scripts/lxdialog/Makefile index da5e5a1ab32d..252c5bf86cd1 100644 --- a/scripts/lxdialog/Makefile +++ b/scripts/lxdialog/Makefile @@ -42,6 +42,3 @@ ncurses: echo ;\ exit 1 ;\ fi - -mrproper: - @rm -f $(host-progs) $(addprefix $(obj)/,$(lxdialog-objs)) diff --git a/security/capability.c b/security/capability.c index 6f9b25ba65bd..809fac9a470b 100644 --- a/security/capability.c +++ b/security/capability.c @@ -442,11 +442,6 @@ static void cap_file_free_security (struct file *file) return; } -static int cap_file_llseek (struct file *file) -{ - return 0; -} - static int cap_file_ioctl (struct file *file, unsigned int command, unsigned long arg) { @@ -787,7 +782,6 @@ static struct security_operations capability_ops = { .file_permission = cap_file_permission, .file_alloc_security = cap_file_alloc_security, .file_free_security = cap_file_free_security, - .file_llseek = cap_file_llseek, .file_ioctl = cap_file_ioctl, .file_mmap = cap_file_mmap, .file_mprotect = cap_file_mprotect, diff --git a/security/dummy.c b/security/dummy.c index 0b3ca57db95b..aa65562474eb 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -344,11 +344,6 @@ static void dummy_file_free_security (struct file *file) return; } -static int dummy_file_llseek (struct file *file) -{ - return 0; -} - static int dummy_file_ioctl (struct file *file, unsigned int command, unsigned long arg) { @@ -602,7 +597,6 @@ struct security_operations dummy_security_ops = { .file_permission = dummy_file_permission, .file_alloc_security = dummy_file_alloc_security, .file_free_security = dummy_file_free_security, - .file_llseek = dummy_file_llseek, .file_ioctl = dummy_file_ioctl, .file_mmap = dummy_file_mmap, .file_mprotect = dummy_file_mprotect, diff --git a/security/security.c b/security/security.c index 892208b20bc4..57746fb90878 100644 --- a/security/security.c +++ b/security/security.c @@ -241,9 +241,9 @@ asmlinkage long sys_security (unsigned int id, unsigned int call, return security_ops->sys_security (id, call, args); } -EXPORT_SYMBOL (register_security); -EXPORT_SYMBOL (unregister_security); -EXPORT_SYMBOL (mod_reg_security); -EXPORT_SYMBOL (mod_unreg_security); -EXPORT_SYMBOL (capable); -EXPORT_SYMBOL (security_ops); +EXPORT_SYMBOL_GPL(register_security); +EXPORT_SYMBOL_GPL(unregister_security); +EXPORT_SYMBOL_GPL(mod_reg_security); +EXPORT_SYMBOL_GPL(mod_unreg_security); +EXPORT_SYMBOL(capable); +EXPORT_SYMBOL(security_ops); diff --git a/sound/oss/Makefile b/sound/oss/Makefile index c24a584bc43d..de9f457b82cc 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -96,6 +96,10 @@ wavefront-objs := wavfront.o wf_midi.o yss225.o host-progs := bin2hex hex2hex +# Files generated that shall be removed upon make clean +clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \ + pss_boot.h trix_boot.h + include $(TOPDIR)/Rules.make # Firmware files that need translation diff --git a/sound/oss/ite8172.c b/sound/oss/ite8172.c index 85a18bfbdd10..3d9b3ceb17df 100644 --- a/sound/oss/ite8172.c +++ b/sound/oss/ite8172.c @@ -305,7 +305,7 @@ static LIST_HEAD(devs); /* --------------------------------------------------------------------- */ -extern inline unsigned ld2(unsigned int x) +static inline unsigned ld2(unsigned int x) { unsigned r = 0; @@ -510,7 +510,7 @@ static void waitcodec(struct ac97_codec *codec) /* --------------------------------------------------------------------- */ -extern inline void stop_adc(struct it8172_state *s) +static inline void stop_adc(struct it8172_state *s) { struct dmabuf* db = &s->dma_adc; unsigned long flags; @@ -534,7 +534,7 @@ extern inline void stop_adc(struct it8172_state *s) spin_unlock_irqrestore(&s->lock, flags); } -extern inline void stop_dac(struct it8172_state *s) +static inline void stop_dac(struct it8172_state *s) { struct dmabuf* db = &s->dma_dac; unsigned long flags; @@ -633,7 +633,7 @@ static void start_adc(struct it8172_state *s) #define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db) +static inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db) { struct page *page, *pend; @@ -709,7 +709,7 @@ static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db, return 0; } -extern inline int prog_dmabuf_adc(struct it8172_state *s) +static inline int prog_dmabuf_adc(struct it8172_state *s) { stop_adc(s); return prog_dmabuf(s, &s->dma_adc, s->adcrate, @@ -717,7 +717,7 @@ extern inline int prog_dmabuf_adc(struct it8172_state *s) IT_AC_CAPCC); } -extern inline int prog_dmabuf_dac(struct it8172_state *s) +static inline int prog_dmabuf_dac(struct it8172_state *s) { stop_dac(s); return prog_dmabuf(s, &s->dma_dac, s->dacrate, diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h index 050c38df5f21..4838b589cf6e 100644 --- a/sound/oss/sound_config.h +++ b/sound/oss/sound_config.h @@ -113,14 +113,14 @@ struct channel_info { #if OPEN_READ == FMODE_READ && OPEN_WRITE == FMODE_WRITE -extern __inline__ int translate_mode(struct file *file) +static inline int translate_mode(struct file *file) { return file->f_mode; } #else -extern __inline__ int translate_mode(struct file *file) +static inline int translate_mode(struct file *file) { return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) | ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 36f30fb25450..27b9fce23b8a 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -593,7 +593,7 @@ static void snd_es1371_codec_write(ac97_t *ac97, } spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } - snd_printk("codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk("codec write timeout at 0x%lx [0x%lx]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); } static unsigned short snd_es1371_codec_read(ac97_t *ac97, @@ -641,14 +641,14 @@ static unsigned short snd_es1371_codec_read(ac97_t *ac97, } spin_unlock_irqrestore(&ensoniq->reg_lock, flags); if (++fail > 10) { - snd_printk("codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), reg, inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk("codec read timeout (final) at 0x%lx, reg = 0x%x [0x%lx]\n", ES_REG(ensoniq, 1371_CODEC), reg, inl(ES_REG(ensoniq, 1371_CODEC))); return 0; } goto __again; } spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } - snd_printk("es1371: codec read timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk("es1371: codec read timeout at 0x%lx [0x%lx]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); return 0; } |
