Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Oct 2012 23:49:18 +0000 (08:49 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Oct 2012 23:49:18 +0000 (08:49 +0900)
Pull hwmon updates from Jean Delvare:
 "Only trivial things this time"

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: Drop needless includes of <linux/delay.h>
  hwmon: Add missing inclusions of <linux/err.h>
  hwmon: Add missing inclusions of <linux/jiffies.h>
  hwmon: Fix spelling of Celsius
  hwmon: Update Alexey Fisher's name

243 files changed:
Documentation/devicetree/bindings/pwm/imx-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/mxs-pwm.txt
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
Documentation/driver-model/devres.txt
Documentation/filesystems/nfs/nfs.txt
Documentation/kernel-parameters.txt
Documentation/leds/leds-lp5523.txt
Documentation/pwm.txt
Documentation/target/tcm_mod_builder.py
arch/mips/include/asm/mach-jz4740/platform.h
arch/mips/include/asm/mach-jz4740/timer.h
arch/mips/jz4740/Kconfig
arch/mips/jz4740/Makefile
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/pwm.c [deleted file]
arch/mips/jz4740/time.c
arch/mips/jz4740/timer.c
arch/mips/jz4740/timer.h [deleted file]
arch/s390/Kconfig.debug
arch/s390/include/asm/Kbuild
arch/s390/include/asm/chpid.h
arch/s390/include/asm/cmb.h
arch/s390/include/asm/css_chars.h
arch/s390/include/asm/debug.h
arch/s390/include/asm/kvm_para.h
arch/s390/include/asm/mman.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/schid.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/signal.h
arch/s390/include/asm/termios.h
arch/s390/include/asm/types.h
arch/s390/include/asm/unistd.h
arch/s390/include/uapi/asm/Kbuild
arch/s390/include/uapi/asm/auxvec.h [moved from arch/s390/include/asm/auxvec.h with 100% similarity]
arch/s390/include/uapi/asm/bitsperlong.h [moved from arch/s390/include/asm/bitsperlong.h with 100% similarity]
arch/s390/include/uapi/asm/byteorder.h [moved from arch/s390/include/asm/byteorder.h with 100% similarity]
arch/s390/include/uapi/asm/chpid.h [new file with mode: 0644]
arch/s390/include/uapi/asm/chsc.h [moved from arch/s390/include/asm/chsc.h with 92% similarity]
arch/s390/include/uapi/asm/cmb.h [new file with mode: 0644]
arch/s390/include/uapi/asm/dasd.h [moved from arch/s390/include/asm/dasd.h with 100% similarity]
arch/s390/include/uapi/asm/debug.h [new file with mode: 0644]
arch/s390/include/uapi/asm/errno.h [moved from arch/s390/include/asm/errno.h with 100% similarity]
arch/s390/include/uapi/asm/fcntl.h [moved from arch/s390/include/asm/fcntl.h with 100% similarity]
arch/s390/include/uapi/asm/ioctl.h [moved from arch/s390/include/asm/ioctl.h with 100% similarity]
arch/s390/include/uapi/asm/ioctls.h [moved from arch/s390/include/asm/ioctls.h with 100% similarity]
arch/s390/include/uapi/asm/ipcbuf.h [moved from arch/s390/include/asm/ipcbuf.h with 100% similarity]
arch/s390/include/uapi/asm/kvm.h [moved from arch/s390/include/asm/kvm.h with 100% similarity]
arch/s390/include/uapi/asm/kvm_para.h [new file with mode: 0644]
arch/s390/include/uapi/asm/kvm_virtio.h [moved from arch/s390/include/asm/kvm_virtio.h with 100% similarity]
arch/s390/include/uapi/asm/mman.h [new file with mode: 0644]
arch/s390/include/uapi/asm/monwriter.h [moved from arch/s390/include/asm/monwriter.h with 100% similarity]
arch/s390/include/uapi/asm/msgbuf.h [moved from arch/s390/include/asm/msgbuf.h with 100% similarity]
arch/s390/include/uapi/asm/param.h [moved from arch/s390/include/asm/param.h with 100% similarity]
arch/s390/include/uapi/asm/poll.h [moved from arch/s390/include/asm/poll.h with 100% similarity]
arch/s390/include/uapi/asm/posix_types.h [moved from arch/s390/include/asm/posix_types.h with 100% similarity]
arch/s390/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/s390/include/uapi/asm/qeth.h [moved from arch/s390/include/asm/qeth.h with 100% similarity]
arch/s390/include/uapi/asm/resource.h [moved from arch/s390/include/asm/resource.h with 100% similarity]
arch/s390/include/uapi/asm/schid.h [new file with mode: 0644]
arch/s390/include/uapi/asm/sembuf.h [moved from arch/s390/include/asm/sembuf.h with 100% similarity]
arch/s390/include/uapi/asm/setup.h [new file with mode: 0644]
arch/s390/include/uapi/asm/shmbuf.h [moved from arch/s390/include/asm/shmbuf.h with 100% similarity]
arch/s390/include/uapi/asm/sigcontext.h [moved from arch/s390/include/asm/sigcontext.h with 100% similarity]
arch/s390/include/uapi/asm/siginfo.h [moved from arch/s390/include/asm/siginfo.h with 100% similarity]
arch/s390/include/uapi/asm/signal.h [new file with mode: 0644]
arch/s390/include/uapi/asm/socket.h [moved from arch/s390/include/asm/socket.h with 100% similarity]
arch/s390/include/uapi/asm/sockios.h [moved from arch/s390/include/asm/sockios.h with 100% similarity]
arch/s390/include/uapi/asm/stat.h [moved from arch/s390/include/asm/stat.h with 100% similarity]
arch/s390/include/uapi/asm/statfs.h [moved from arch/s390/include/asm/statfs.h with 100% similarity]
arch/s390/include/uapi/asm/swab.h [moved from arch/s390/include/asm/swab.h with 100% similarity]
arch/s390/include/uapi/asm/tape390.h [moved from arch/s390/include/asm/tape390.h with 100% similarity]
arch/s390/include/uapi/asm/termbits.h [moved from arch/s390/include/asm/termbits.h with 100% similarity]
arch/s390/include/uapi/asm/termios.h [new file with mode: 0644]
arch/s390/include/uapi/asm/types.h [new file with mode: 0644]
arch/s390/include/uapi/asm/ucontext.h [moved from arch/s390/include/asm/ucontext.h with 100% similarity]
arch/s390/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/s390/include/uapi/asm/vtoc.h [moved from arch/s390/include/asm/vtoc.h with 100% similarity]
arch/s390/include/uapi/asm/zcrypt.h [moved from arch/s390/include/asm/zcrypt.h with 100% similarity]
arch/s390/kernel/early.c
arch/s390/kernel/entry64.S
arch/s390/kernel/head.S
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/module.c
arch/s390/kernel/setup.c
arch/s390/mm/Makefile
arch/s390/mm/dump_pagetables.c [new file with mode: 0644]
arch/s390/mm/pageattr.c
arch/s390/mm/vmem.c
arch/unicore32/Kconfig
arch/unicore32/include/mach/regs-ost.h
arch/unicore32/kernel/Makefile
arch/unicore32/kernel/pwm.c [deleted file]
drivers/gpu/drm/nouveau/core/core/parent.c
drivers/gpu/drm/nouveau/core/include/core/parent.h
drivers/gpu/drm/nouveau/core/include/subdev/timer.h
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lm3530.c
drivers/leds/leds-lm3556.c [deleted file]
drivers/leds/leds-lm355x.c [new file with mode: 0644]
drivers/leds/leds-lm3642.c [new file with mode: 0644]
drivers/leds/leds-lp5523.c
drivers/leds/leds-pca9633.c
drivers/leds/leds-wm8350.c
drivers/leds/leds.h
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-ab8500.c [moved from drivers/misc/ab8500-pwm.c with 52% similarity]
drivers/pwm/pwm-bfin.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-jz4740.c [new file with mode: 0644]
drivers/pwm/pwm-puv3.c [new file with mode: 0644]
drivers/pwm/pwm-pxa.c
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/s390/block/dcssblk.c
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target.h
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl1.h
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_erl2.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_parameters.h
drivers/target/iscsi/iscsi_target_seq_pdu_list.c
drivers/target/iscsi/iscsi_target_tmr.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_tq.c
drivers/target/iscsi/iscsi_target_tq.h
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.c
drivers/target/sbp/sbp_target.c
drivers/target/target_core_alua.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_fabric_lib.c
drivers/target/target_core_file.c
drivers/target/target_core_file.h
drivers/target/target_core_iblock.c
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_stat.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_conf.c
drivers/target/tcm_fc/tfc_io.c
drivers/target/tcm_fc/tfc_sess.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/vhost/tcm_vhost.c
drivers/vhost/tcm_vhost.h
drivers/video/backlight/pwm_bl.c
fs/lockd/mon.c
fs/lockd/netns.h
fs/lockd/svc.c
fs/nfs/Kconfig
fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/blocklayoutdev.c
fs/nfs/blocklayout/extents.c
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/netns.h
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4sysctl.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/pnfs_dev.c
fs/nfs/super.c
fs/nfs/write.c
include/linux/leds-lp5523.h
include/linux/leds.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/platform_data/leds-lm3556.h [deleted file]
include/linux/platform_data/leds-lm355x.h [new file with mode: 0644]
include/linux/platform_data/leds-lm3642.h [new file with mode: 0644]
include/linux/platform_data/leds-pca9633.h [new file with mode: 0644]
include/linux/pwm.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/xprt.h
include/target/target_core_backend.h
include/target/target_core_fabric.h
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtsock.c

diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
new file mode 100644 (file)
index 0000000..8522bfb
--- /dev/null
@@ -0,0 +1,17 @@
+Freescale i.MX PWM controller
+
+Required properties:
+- compatible: should be "fsl,<soc>-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+- interrupts: The interrupt for the pwm controller
+
+Example:
+
+pwm1: pwm@53fb4000 {
+       #pwm-cells = <2>;
+       compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
+       reg = <0x53fb4000 0x4000>;
+       interrupts = <61>;
+};
index 11963e4..9e3f8f1 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible: should be "fsl,imx23-pwm"
 - reg: physical base address and length of the controller's registers
 - #pwm-cells: should be 2.  The first cell specifies the per-chip index
-  of the PWM to use and the second cell is the duty cycle in nanoseconds.
+  of the PWM to use and the second cell is the period in nanoseconds.
 - fsl,pwm-number: the number of PWM devices
 
 Example:
index bbbeedb..01438ec 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
 - reg: physical base address and length of the controller's registers
 - #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The
   first cell specifies the per-chip index of the PWM to use and the second
-  cell is the duty cycle in nanoseconds.
+  cell is the period in nanoseconds.
 
 Example:
 
index 950856b..43cff70 100644 (file)
@@ -284,3 +284,7 @@ CLOCK
 PINCTRL
   devm_pinctrl_get()
   devm_pinctrl_put()
+
+PWM
+  devm_pwm_get()
+  devm_pwm_put()
index f50f26c..f2571c8 100644 (file)
@@ -12,9 +12,47 @@ and work is in progress on adding support for minor version 1 of the NFSv4
 protocol.
 
 The purpose of this document is to provide information on some of the
-upcall interfaces that are used in order to provide the NFS client with
-some of the information that it requires in order to fully comply with
-the NFS spec.
+special features of the NFS client that can be configured by system
+administrators.
+
+
+The nfs4_unique_id parameter
+============================
+
+NFSv4 requires clients to identify themselves to servers with a unique
+string.  File open and lock state shared between one client and one server
+is associated with this identity.  To support robust NFSv4 state recovery
+and transparent state migration, this identity string must not change
+across client reboots.
+
+Without any other intervention, the Linux client uses a string that contains
+the local system's node name.  System administrators, however, often do not
+take care to ensure that node names are fully qualified and do not change
+over the lifetime of a client system.  Node names can have other
+administrative requirements that require particular behavior that does not
+work well as part of an nfs_client_id4 string.
+
+The nfs.nfs4_unique_id boot parameter specifies a unique string that can be
+used instead of a system's node name when an NFS client identifies itself to
+a server.  Thus, if the system's node name is not unique, or it changes, its
+nfs.nfs4_unique_id stays the same, preventing collision with other clients
+or loss of state during NFS reboot recovery or transparent state migration.
+
+The nfs.nfs4_unique_id string is typically a UUID, though it can contain
+anything that is believed to be unique across all NFS clients.  An
+nfs4_unique_id string should be chosen when a client system is installed,
+just as a system's root file system gets a fresh UUID in its label at
+install time.
+
+The string should remain fixed for the lifetime of the client.  It can be
+changed safely if care is taken that the client shuts down cleanly and all
+outstanding NFSv4 state has expired, to prevent loss of NFSv4 state.
+
+This string can be stored in an NFS client's grub.conf, or it can be provided
+via a net boot facility such as PXE.  It may also be specified as an nfs.ko
+module parameter.  Specifying a uniquifier string is not support for NFS
+clients running in containers.
+
 
 The DNS resolver
 ================
index f777fa9..e2ed336 100644 (file)
@@ -1730,6 +1730,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        will be autodetected by the client, and it will fall
                        back to using the idmapper.
                        To turn off this behaviour, set the value to '0'.
+       nfs.nfs4_unique_id=
+                       [NFS4] Specify an additional fixed unique ident-
+                       ification string that NFSv4 clients can insert into
+                       their nfs_client_id4 string.  This is typically a
+                       UUID that is generated at system install time.
 
        nfs.send_implementation_id =
                        [NFSv4.1] Send client implementation identification
index fad2feb..c2743f5 100644 (file)
@@ -10,8 +10,22 @@ Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
 Description
 -----------
 LP5523 can drive up to 9 channels. Leds can be controlled directly via
-the led class control interface. Channels have generic names:
-lp5523:channelx where x is 0...8
+the led class control interface.
+The name of each channel is configurable in the platform data - name and label.
+There are three options to make the channel name.
+
+a) Define the 'name' in the platform data
+To make specific channel name, then use 'name' platform data.
+/sys/class/leds/R1               (name: 'R1')
+/sys/class/leds/B1               (name: 'B1')
+
+b) Use the 'label' with no 'name' field
+For one device name with channel number, then use 'label'.
+/sys/class/leds/RGB:channelN     (label: 'RGB', N: 0 ~ 8)
+
+c) Default
+If both fields are NULL, 'lp5523' is used by default.
+/sys/class/leds/lp5523:channelN  (N: 0 ~ 8)
 
 The chip provides 3 engines. Each engine can control channels without
 interaction from the main CPU. Details of the micro engine code can be found
@@ -46,12 +60,13 @@ Note - chan_nr can have values between 0 and 8.
 
 static struct lp5523_led_config lp5523_led_config[] = {
         {
+               .name           = "D1",
                 .chan_nr        = 0,
                 .led_current    = 50,
                .max_current    = 130,
         },
 ...
-        }, {
+        {
                 .chan_nr        = 8,
                 .led_current    = 50,
                .max_current    = 130,
index 554290e..7d2b4c9 100644 (file)
@@ -36,7 +36,8 @@ Legacy users can request a PWM device using pwm_request() and free it
 after usage with pwm_free().
 
 New users should use the pwm_get() function and pass to it the consumer
-device or a consumer name. pwm_put() is used to free the PWM device.
+device or a consumer name. pwm_put() is used to free the PWM device. Managed
+variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
 
 After being requested a PWM has to be configured using:
 
index a78879b..3fe0d81 100755 (executable)
@@ -402,8 +402,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .queue_data_in                  = " + fabric_mod_name + "_queue_data_in,\n"
        buf += "        .queue_status                   = " + fabric_mod_name + "_queue_status,\n"
        buf += "        .queue_tm_rsp                   = " + fabric_mod_name + "_queue_tm_rsp,\n"
-       buf += "        .get_fabric_sense_len           = " + fabric_mod_name + "_get_fabric_sense_len,\n"
-       buf += "        .set_fabric_sense_len           = " + fabric_mod_name + "_set_fabric_sense_len,\n"
        buf += "        .is_state_remove                = " + fabric_mod_name + "_is_state_remove,\n"
        buf += "        /*\n"
        buf += "         * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
@@ -906,20 +904,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "}\n\n"
                        bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
 
-               if re.search('get_fabric_sense_len\)\(', fo):
-                       buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n"
-                       buf += "{\n"
-                       buf += "        return 0;\n"
-                       buf += "}\n\n"
-                       bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n"
-
-               if re.search('set_fabric_sense_len\)\(', fo):
-                       buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n"
-                       buf += "{\n"
-                       buf += "        return 0;\n"
-                       buf += "}\n\n"
-                       bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n"
-
                if re.search('is_state_remove\)\(', fo):
                        buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n"
                        buf += "{\n"
index 564ab81..163e81d 100644 (file)
@@ -31,6 +31,7 @@ extern struct platform_device jz4740_pcm_device;
 extern struct platform_device jz4740_codec_device;
 extern struct platform_device jz4740_adc_device;
 extern struct platform_device jz4740_wdt_device;
+extern struct platform_device jz4740_pwm_device;
 
 void jz4740_serial_device_register(void);
 
index 9baa03c..a7759fb 100644 (file)
 #ifndef __ASM_MACH_JZ4740_TIMER
 #define __ASM_MACH_JZ4740_TIMER
 
+#define JZ_REG_TIMER_STOP              0x0C
+#define JZ_REG_TIMER_STOP_SET          0x1C
+#define JZ_REG_TIMER_STOP_CLEAR                0x2C
+#define JZ_REG_TIMER_ENABLE            0x00
+#define JZ_REG_TIMER_ENABLE_SET                0x04
+#define JZ_REG_TIMER_ENABLE_CLEAR      0x08
+#define JZ_REG_TIMER_FLAG              0x10
+#define JZ_REG_TIMER_FLAG_SET          0x14
+#define JZ_REG_TIMER_FLAG_CLEAR                0x18
+#define JZ_REG_TIMER_MASK              0x20
+#define JZ_REG_TIMER_MASK_SET          0x24
+#define JZ_REG_TIMER_MASK_CLEAR                0x28
+
+#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
+#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
+#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
+#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
+
+#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
+#define JZ_TIMER_IRQ_FULL(x) BIT(x)
+
+#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN     BIT(9)
+#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW           BIT(8)
+#define JZ_TIMER_CTRL_PWM_ENABLE               BIT(7)
+#define JZ_TIMER_CTRL_PRESCALE_MASK            0x1c
+#define JZ_TIMER_CTRL_PRESCALE_OFFSET          0x3
+#define JZ_TIMER_CTRL_PRESCALE_1               (0 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_4               (1 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_16              (2 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_64              (3 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_256             (4 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_1024            (5 << 3)
+
+#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
+
+#define JZ_TIMER_CTRL_SRC_EXT          BIT(2)
+#define JZ_TIMER_CTRL_SRC_RTC          BIT(1)
+#define JZ_TIMER_CTRL_SRC_PCLK         BIT(0)
+
+extern void __iomem *jz4740_timer_base;
+void __init jz4740_timer_init(void);
+
 void jz4740_timer_enable_watchdog(void);
 void jz4740_timer_disable_watchdog(void);
 
+static inline void jz4740_timer_stop(unsigned int timer)
+{
+       writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
+}
+
+static inline void jz4740_timer_start(unsigned int timer)
+{
+       writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
+}
+
+static inline bool jz4740_timer_is_enabled(unsigned int timer)
+{
+       return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
+}
+
+static inline void jz4740_timer_enable(unsigned int timer)
+{
+       writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
+}
+
+static inline void jz4740_timer_disable(unsigned int timer)
+{
+       writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
+}
+
+static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
+{
+       writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
+}
+
+static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
+{
+       writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
+}
+
+static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
+{
+       writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline uint16_t jz4740_timer_get_count(unsigned int timer)
+{
+       return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline void jz4740_timer_ack_full(unsigned int timer)
+{
+       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_enable(unsigned int timer)
+{
+       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_disable(unsigned int timer)
+{
+       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
+}
+
+static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
+{
+       writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
+static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
+{
+       return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
 #endif
index 3e7141f..4689030 100644 (file)
@@ -7,6 +7,3 @@ config JZ4740_QI_LB60
        bool "Qi Hardware Ben NanoNote"
 
 endchoice
-
-config HAVE_PWM
-       bool
index e44abea..63bad0e 100644 (file)
@@ -5,7 +5,7 @@
 # Object file lists.
 
 obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
-       gpio.o clock.o platform.o timer.o pwm.o serial.o
+       gpio.o clock.o platform.o timer.o serial.o
 
 obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
 
index 9a3d9de..43d964d 100644 (file)
@@ -437,6 +437,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_codec_device,
        &jz4740_rtc_device,
        &jz4740_adc_device,
+       &jz4740_pwm_device,
        &qi_lb60_gpio_keys,
        &qi_lb60_pwm_beeper,
        &qi_lb60_charger_device,
index e342ed4..6d14dcd 100644 (file)
@@ -323,3 +323,9 @@ struct platform_device jz4740_wdt_device = {
        .num_resources = ARRAY_SIZE(jz4740_wdt_resources),
        .resource      = jz4740_wdt_resources,
 };
+
+/* PWM */
+struct platform_device jz4740_pwm_device = {
+       .name = "jz4740-pwm",
+       .id   = -1,
+};
diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
deleted file mode 100644 (file)
index a26a6fa..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform PWM support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/pwm.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-jz4740/gpio.h>
-#include "timer.h"
-
-static struct clk *jz4740_pwm_clk;
-
-DEFINE_MUTEX(jz4740_pwm_mutex);
-
-struct pwm_device {
-       unsigned int id;
-       unsigned int gpio;
-       bool used;
-};
-
-static struct pwm_device jz4740_pwm_list[] = {
-       { 2, JZ_GPIO_PWM2, false },
-       { 3, JZ_GPIO_PWM3, false },
-       { 4, JZ_GPIO_PWM4, false },
-       { 5, JZ_GPIO_PWM5, false },
-       { 6, JZ_GPIO_PWM6, false },
-       { 7, JZ_GPIO_PWM7, false },
-};
-
-struct pwm_device *pwm_request(int id, const char *label)
-{
-       int ret = 0;
-       struct pwm_device *pwm;
-
-       if (id < 2 || id > 7 || !jz4740_pwm_clk)
-               return ERR_PTR(-ENODEV);
-
-       mutex_lock(&jz4740_pwm_mutex);
-
-       pwm = &jz4740_pwm_list[id - 2];
-       if (pwm->used)
-               ret = -EBUSY;
-       else
-               pwm->used = true;
-
-       mutex_unlock(&jz4740_pwm_mutex);
-
-       if (ret)
-               return ERR_PTR(ret);
-
-       ret = gpio_request(pwm->gpio, label);
-
-       if (ret) {
-               printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
-               pwm->used = false;
-               return ERR_PTR(ret);
-       }
-
-       jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
-
-       jz4740_timer_start(id);
-
-       return pwm;
-}
-
-void pwm_free(struct pwm_device *pwm)
-{
-       pwm_disable(pwm);
-       jz4740_timer_set_ctrl(pwm->id, 0);
-
-       jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
-       gpio_free(pwm->gpio);
-
-       jz4740_timer_stop(pwm->id);
-
-       pwm->used = false;
-}
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long long tmp;
-       unsigned long period, duty;
-       unsigned int prescaler = 0;
-       unsigned int id = pwm->id;
-       uint16_t ctrl;
-       bool is_enabled;
-
-       if (duty_ns < 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
-       do_div(tmp, 1000000000);
-       period = tmp;
-
-       while (period > 0xffff && prescaler < 6) {
-               period >>= 2;
-               ++prescaler;
-       }
-
-       if (prescaler == 6)
-               return -EINVAL;
-
-       tmp = (unsigned long long)period * duty_ns;
-       do_div(tmp, period_ns);
-       duty = period - tmp;
-
-       if (duty >= period)
-               duty = period - 1;
-
-       is_enabled = jz4740_timer_is_enabled(id);
-       if (is_enabled)
-               pwm_disable(pwm);
-
-       jz4740_timer_set_count(id, 0);
-       jz4740_timer_set_duty(id, duty);
-       jz4740_timer_set_period(id, period);
-
-       ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
-               JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
-
-       jz4740_timer_set_ctrl(id, ctrl);
-
-       if (is_enabled)
-               pwm_enable(pwm);
-
-       return 0;
-}
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
-
-       ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_set_ctrl(pwm->id, ctrl);
-       jz4740_timer_enable(pwm->id);
-
-       return 0;
-}
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
-
-       ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_disable(pwm->id);
-       jz4740_timer_set_ctrl(pwm->id, ctrl);
-}
-
-static int __init jz4740_pwm_init(void)
-{
-       int ret = 0;
-
-       jz4740_pwm_clk = clk_get(NULL, "ext");
-
-       if (IS_ERR(jz4740_pwm_clk)) {
-               ret = PTR_ERR(jz4740_pwm_clk);
-               jz4740_pwm_clk = NULL;
-       }
-
-       return ret;
-}
-subsys_initcall(jz4740_pwm_init);
index f83c2dd..39bb4bb 100644 (file)
 #include <linux/clockchips.h>
 
 #include <asm/mach-jz4740/irq.h>
+#include <asm/mach-jz4740/timer.h>
 #include <asm/time.h>
 
 #include "clock.h"
-#include "timer.h"
 
 #define TIMER_CLOCKEVENT 0
 #define TIMER_CLOCKSOURCE 1
index 654d5c3..22f11d7 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#include "timer.h"
-
 #include <asm/mach-jz4740/base.h>
+#include <asm/mach-jz4740/timer.h>
 
 void __iomem *jz4740_timer_base;
+EXPORT_SYMBOL_GPL(jz4740_timer_base);
 
 void jz4740_timer_enable_watchdog(void)
 {
diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h
deleted file mode 100644 (file)
index fca3994..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform timer support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __MIPS_JZ4740_TIMER_H__
-#define __MIPS_JZ4740_TIMER_H__
-
-#include <linux/module.h>
-#include <linux/io.h>
-
-#define JZ_REG_TIMER_STOP              0x0C
-#define JZ_REG_TIMER_STOP_SET          0x1C
-#define JZ_REG_TIMER_STOP_CLEAR                0x2C
-#define JZ_REG_TIMER_ENABLE            0x00
-#define JZ_REG_TIMER_ENABLE_SET                0x04
-#define JZ_REG_TIMER_ENABLE_CLEAR      0x08
-#define JZ_REG_TIMER_FLAG              0x10
-#define JZ_REG_TIMER_FLAG_SET          0x14
-#define JZ_REG_TIMER_FLAG_CLEAR                0x18
-#define JZ_REG_TIMER_MASK              0x20
-#define JZ_REG_TIMER_MASK_SET          0x24
-#define JZ_REG_TIMER_MASK_CLEAR                0x28
-
-#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
-#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
-#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
-#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
-
-#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
-#define JZ_TIMER_IRQ_FULL(x) BIT(x)
-
-#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN     BIT(9)
-#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW           BIT(8)
-#define JZ_TIMER_CTRL_PWM_ENABLE               BIT(7)
-#define JZ_TIMER_CTRL_PRESCALE_MASK            0x1c
-#define JZ_TIMER_CTRL_PRESCALE_OFFSET          0x3
-#define JZ_TIMER_CTRL_PRESCALE_1               (0 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_4               (1 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_16              (2 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_64              (3 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_256             (4 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_1024            (5 << 3)
-
-#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
-
-#define JZ_TIMER_CTRL_SRC_EXT          BIT(2)
-#define JZ_TIMER_CTRL_SRC_RTC          BIT(1)
-#define JZ_TIMER_CTRL_SRC_PCLK         BIT(0)
-
-extern void __iomem *jz4740_timer_base;
-void __init jz4740_timer_init(void);
-
-static inline void jz4740_timer_stop(unsigned int timer)
-{
-       writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
-}
-
-static inline void jz4740_timer_start(unsigned int timer)
-{
-       writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
-}
-
-static inline bool jz4740_timer_is_enabled(unsigned int timer)
-{
-       return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
-}
-
-static inline void jz4740_timer_enable(unsigned int timer)
-{
-       writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
-}
-
-static inline void jz4740_timer_disable(unsigned int timer)
-{
-       writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
-}
-
-
-static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
-{
-       writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
-}
-
-static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
-{
-       writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
-}
-
-static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
-{
-       writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
-}
-
-static inline uint16_t jz4740_timer_get_count(unsigned int timer)
-{
-       return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
-}
-
-static inline void jz4740_timer_ack_full(unsigned int timer)
-{
-       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
-}
-
-static inline void jz4740_timer_irq_full_enable(unsigned int timer)
-{
-       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
-       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
-}
-
-static inline void jz4740_timer_irq_full_disable(unsigned int timer)
-{
-       writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
-}
-
-static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
-{
-       writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
-}
-
-static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
-{
-       return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
-}
-
-#endif
index d76cef3..fc32a2d 100644 (file)
@@ -31,6 +31,18 @@ config DEBUG_STRICT_USER_COPY_CHECKS
 
          If unsure, or if you run an older (pre 4.4) gcc, say N.
 
+config S390_PTDUMP
+       bool "Export kernel pagetable layout to userspace via debugfs"
+       depends on DEBUG_KERNEL
+       select DEBUG_FS
+       ---help---
+         Say Y here if you want to show the kernel pagetable layout in a
+         debugfs file. This information is only useful for kernel developers
+         who are working in architecture specific areas of the kernel.
+         It is probably not a good idea to enable this feature in a production
+         kernel.
+         If in doubt, say "N"
+
 config DEBUG_SET_MODULE_RONX
        def_bool y
        depends on MODULES
index f18fc79..0633dc6 100644 (file)
@@ -1,17 +1,3 @@
-include include/asm-generic/Kbuild.asm
 
-header-y += chpid.h
-header-y += chsc.h
-header-y += cmb.h
-header-y += dasd.h
-header-y += debug.h
-header-y += kvm_virtio.h
-header-y += monwriter.h
-header-y += qeth.h
-header-y += schid.h
-header-y += tape390.h
-header-y += ucontext.h
-header-y += vtoc.h
-header-y += zcrypt.h
 
 generic-y += clkdev.h
index e5bde9f..38c405e 100644 (file)
@@ -1,24 +1,11 @@
 /*
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2012
  *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
-
 #ifndef _ASM_S390_CHPID_H
 #define _ASM_S390_CHPID_H
 
-#include <linux/string.h>
-#include <linux/types.h>
-
-#define __MAX_CHPID 255
-
-struct chp_id {
-       u8 reserved1;
-       u8 cssid;
-       u8 reserved2;
-       u8 id;
-} __attribute__((packed));
-
-#ifdef __KERNEL__
+#include <uapi/asm/chpid.h>
 #include <asm/cio.h>
 
 static inline void chp_id_init(struct chp_id *chpid)
@@ -49,6 +36,4 @@ static inline int chp_id_is_valid(struct chp_id *chpid)
 
 #define chp_id_for_each(c) \
        for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c))
-#endif /* __KERNEL */
-
 #endif /* _ASM_S390_CHPID_H */
index 39ae032..806eac1 100644 (file)
@@ -1,61 +1,12 @@
 #ifndef S390_CMB_H
 #define S390_CMB_H
 
-#include <linux/types.h>
+#include <uapi/asm/cmb.h>
 
-/**
- * struct cmbdata - channel measurement block data for user space
- * @size: size of the stored data
- * @elapsed_time: time since last sampling
- * @ssch_rsch_count: number of ssch and rsch
- * @sample_count: number of samples
- * @device_connect_time: time of device connect
- * @function_pending_time: time of function pending
- * @device_disconnect_time: time of device disconnect
- * @control_unit_queuing_time: time of control unit queuing
- * @device_active_only_time: time of device active only
- * @device_busy_time: time of device busy (ext. format)
- * @initial_command_response_time: initial command response time (ext. format)
- *
- * All values are stored as 64 bit for simplicity, especially
- * in 32 bit emulation mode. All time values are normalized to
- * nanoseconds.
- * Currently, two formats are known, which differ by the size of
- * this structure, i.e. the last two members are only set when
- * the extended channel measurement facility (first shipped in
- * z990 machines) is activated.
- * Potentially, more fields could be added, which would result in a
- * new ioctl number.
- */
-struct cmbdata {
-       __u64 size;
-       __u64 elapsed_time;
- /* basic and exended format: */
-       __u64 ssch_rsch_count;
-       __u64 sample_count;
-       __u64 device_connect_time;
-       __u64 function_pending_time;
-       __u64 device_disconnect_time;
-       __u64 control_unit_queuing_time;
-       __u64 device_active_only_time;
- /* extended format only: */
-       __u64 device_busy_time;
-       __u64 initial_command_response_time;
-};
-
-/* enable channel measurement */
-#define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER, 32)
-/* enable channel measurement */
-#define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER, 33)
-/* read channel measurement data */
-#define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
-
-#ifdef __KERNEL__
 struct ccw_device;
 extern int enable_cmf(struct ccw_device *cdev);
 extern int disable_cmf(struct ccw_device *cdev);
 extern u64 cmf_read(struct ccw_device *cdev, int index);
 extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
 
-#endif /* __KERNEL__ */
 #endif /* S390_CMB_H */
index a06ebc2..7e1c917 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <linux/types.h>
 
-#ifdef __KERNEL__
-
 struct css_general_char {
        u64 : 12;
        u32 dynio : 1;   /* bit 12 */
@@ -35,5 +33,4 @@ struct css_general_char {
 
 extern struct css_general_char css_general_characteristics;
 
-#endif /* __KERNEL__ */
 #endif
index f39677e..188c505 100644 (file)
@@ -3,39 +3,14 @@
  *
  *    Copyright IBM Corp. 1999, 2000
  */
-
 #ifndef DEBUG_H
 #define DEBUG_H
 
-#include <linux/fs.h>
-
-/* Note:
- * struct __debug_entry must be defined outside of #ifdef __KERNEL__ 
- * in order to allow a user program to analyze the 'raw'-view.
- */
-
-struct __debug_entry{
-        union {
-                struct {
-                        unsigned long long clock:52;
-                        unsigned long long exception:1;
-                        unsigned long long level:3;
-                        unsigned long long cpuid:8;
-                } fields;
-
-                unsigned long long stck;
-        } id;
-        void* caller;
-} __attribute__((packed));
-
-
-#define __DEBUG_FEATURE_VERSION      2  /* version of debug feature */
-
-#ifdef __KERNEL__
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/time.h>
+#include <uapi/asm/debug.h>
 
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
 #define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
@@ -254,5 +229,4 @@ int debug_unregister_view(debug_info_t* id, struct debug_view* view);
 #define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
 #endif                         /* DASD_DEBUG */
 
-#endif                         /* __KERNEL__ */
 #endif                         /* DEBUG_H */
index da44867..e0f8423 100644 (file)
@@ -9,12 +9,6 @@
  *
  *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
  */
-
-#ifndef __S390_KVM_PARA_H
-#define __S390_KVM_PARA_H
-
-#ifdef __KERNEL__
-
 /*
  * Hypercalls for KVM on s390. The calling convention is similar to the
  * s390 ABI, so we use R2-R6 for parameters 1-5. In addition we use R1
  *
  * This work is licensed under the terms of the GNU GPL, version 2.
  */
+#ifndef __S390_KVM_PARA_H
+#define __S390_KVM_PARA_H
+
+#include <uapi/asm/kvm_para.h>
+
+
 
 static inline long kvm_hypercall0(unsigned long nr)
 {
@@ -154,6 +154,4 @@ static inline bool kvm_check_and_clear_guest_paused(void)
        return false;
 }
 
-#endif
-
 #endif /* __S390_KVM_PARA_H */
index abc1932..0e47a57 100644 (file)
@@ -3,17 +3,13 @@
  *
  *  Derived from "include/asm-i386/mman.h"
  */
-
 #ifndef __S390_MMAN_H__
 #define __S390_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <uapi/asm/mman.h>
 
-#if defined(__KERNEL__)
 #if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
 int s390_mmap_check(unsigned long addr, unsigned long len);
 #define arch_mmap_check(addr,len,flags)        s390_mmap_check(addr,len)
 #endif
-#endif
-
 #endif /* __S390_MMAN_H__ */
index 27ab3c7..6d53670 100644 (file)
 #include <asm/setup.h>
 #ifndef __ASSEMBLY__
 
+static unsigned long pfmf(unsigned long function, unsigned long address)
+{
+       asm volatile(
+               "       .insn   rre,0xb9af0000,%[function],%[address]"
+               : [address] "+a" (address)
+               : [function] "d" (function)
+               : "memory");
+       return address;
+}
+
 static inline void clear_page(void *page)
 {
        if (MACHINE_HAS_PFMF) {
-               asm volatile(
-                       "       .insn   rre,0xb9af0000,%0,%1"
-                       : : "d" (0x10000), "a" (page) : "memory", "cc");
+               pfmf(0x10000, (unsigned long)page);
        } else {
                register unsigned long reg1 asm ("1") = 0;
                register void *reg2 asm ("2") = page;
index 979fe3d..dd647c9 100644 (file)
@@ -119,13 +119,12 @@ static inline int is_zero_pfn(unsigned long pfn)
 
 #ifndef __ASSEMBLY__
 /*
- * The vmalloc area will always be on the topmost area of the kernel
- * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc,
- * which should be enough for any sane case.
- * By putting vmalloc at the top, we maximise the gap between physical
- * memory and vmalloc to catch misplaced memory accesses. As a side
- * effect, this also makes sure that 64 bit module code cannot be used
- * as system call address.
+ * The vmalloc and module area will always be on the topmost area of the kernel
+ * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules.
+ * On 64 bit kernels we have a 2GB area at the top of the vmalloc area where
+ * modules will reside. That makes sure that inter module branches always
+ * happen without trampolines and in addition the placement within a 2GB frame
+ * is branch prediction unit friendly.
  */
 extern unsigned long VMALLOC_START;
 extern unsigned long VMALLOC_END;
@@ -133,6 +132,14 @@ extern struct page *vmemmap;
 
 #define VMEM_MAX_PHYS ((unsigned long) vmemmap)
 
+#ifdef CONFIG_64BIT
+extern unsigned long MODULES_VADDR;
+extern unsigned long MODULES_END;
+#define MODULES_VADDR  MODULES_VADDR
+#define MODULES_END    MODULES_END
+#define MODULES_LEN    (1UL << 31)
+#endif
+
 /*
  * A 31 bit pagetable entry of S390 has following format:
  *  |   PFRA          |    |  OS  |
@@ -507,6 +514,15 @@ static inline int pmd_none(pmd_t pmd)
        return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL;
 }
 
+static inline int pmd_large(pmd_t pmd)
+{
+#ifdef CONFIG_64BIT
+       return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+#else
+       return 0;
+#endif
+}
+
 static inline int pmd_bad(pmd_t pmd)
 {
        unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV;
index ce20a53..3ee5da3 100644 (file)
  *    Copyright IBM Corp. 1999, 2000
  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  */
-
 #ifndef _S390_PTRACE_H
 #define _S390_PTRACE_H
 
-/*
- * Offsets in the user_regs_struct. They are used for the ptrace
- * system call and in entry.S
- */
-#ifndef __s390x__
-
-#define PT_PSWMASK  0x00
-#define PT_PSWADDR  0x04
-#define PT_GPR0     0x08
-#define PT_GPR1     0x0C
-#define PT_GPR2     0x10
-#define PT_GPR3     0x14
-#define PT_GPR4     0x18
-#define PT_GPR5     0x1C
-#define PT_GPR6     0x20
-#define PT_GPR7     0x24
-#define PT_GPR8     0x28
-#define PT_GPR9     0x2C
-#define PT_GPR10    0x30
-#define PT_GPR11    0x34
-#define PT_GPR12    0x38
-#define PT_GPR13    0x3C
-#define PT_GPR14    0x40
-#define PT_GPR15    0x44
-#define PT_ACR0     0x48
-#define PT_ACR1     0x4C
-#define PT_ACR2     0x50
-#define PT_ACR3     0x54
-#define PT_ACR4            0x58
-#define PT_ACR5            0x5C
-#define PT_ACR6            0x60
-#define PT_ACR7            0x64
-#define PT_ACR8            0x68
-#define PT_ACR9            0x6C
-#define PT_ACR10    0x70
-#define PT_ACR11    0x74
-#define PT_ACR12    0x78
-#define PT_ACR13    0x7C
-#define PT_ACR14    0x80
-#define PT_ACR15    0x84
-#define PT_ORIGGPR2 0x88
-#define PT_FPC     0x90
-/*
- * A nasty fact of life that the ptrace api
- * only supports passing of longs.
- */
-#define PT_FPR0_HI  0x98
-#define PT_FPR0_LO  0x9C
-#define PT_FPR1_HI  0xA0
-#define PT_FPR1_LO  0xA4
-#define PT_FPR2_HI  0xA8
-#define PT_FPR2_LO  0xAC
-#define PT_FPR3_HI  0xB0
-#define PT_FPR3_LO  0xB4
-#define PT_FPR4_HI  0xB8
-#define PT_FPR4_LO  0xBC
-#define PT_FPR5_HI  0xC0
-#define PT_FPR5_LO  0xC4
-#define PT_FPR6_HI  0xC8
-#define PT_FPR6_LO  0xCC
-#define PT_FPR7_HI  0xD0
-#define PT_FPR7_LO  0xD4
-#define PT_FPR8_HI  0xD8
-#define PT_FPR8_LO  0XDC
-#define PT_FPR9_HI  0xE0
-#define PT_FPR9_LO  0xE4
-#define PT_FPR10_HI 0xE8
-#define PT_FPR10_LO 0xEC
-#define PT_FPR11_HI 0xF0
-#define PT_FPR11_LO 0xF4
-#define PT_FPR12_HI 0xF8
-#define PT_FPR12_LO 0xFC
-#define PT_FPR13_HI 0x100
-#define PT_FPR13_LO 0x104
-#define PT_FPR14_HI 0x108
-#define PT_FPR14_LO 0x10C
-#define PT_FPR15_HI 0x110
-#define PT_FPR15_LO 0x114
-#define PT_CR_9            0x118
-#define PT_CR_10    0x11C
-#define PT_CR_11    0x120
-#define PT_IEEE_IP  0x13C
-#define PT_LASTOFF  PT_IEEE_IP
-#define PT_ENDREGS  0x140-1
-
-#define GPR_SIZE       4
-#define CR_SIZE                4
-
-#define STACK_FRAME_OVERHEAD   96      /* size of minimum stack frame */
-
-#else /* __s390x__ */
-
-#define PT_PSWMASK  0x00
-#define PT_PSWADDR  0x08
-#define PT_GPR0     0x10
-#define PT_GPR1     0x18
-#define PT_GPR2     0x20
-#define PT_GPR3     0x28
-#define PT_GPR4     0x30
-#define PT_GPR5     0x38
-#define PT_GPR6     0x40
-#define PT_GPR7     0x48
-#define PT_GPR8     0x50
-#define PT_GPR9     0x58
-#define PT_GPR10    0x60
-#define PT_GPR11    0x68
-#define PT_GPR12    0x70
-#define PT_GPR13    0x78
-#define PT_GPR14    0x80
-#define PT_GPR15    0x88
-#define PT_ACR0     0x90
-#define PT_ACR1     0x94
-#define PT_ACR2     0x98
-#define PT_ACR3     0x9C
-#define PT_ACR4            0xA0
-#define PT_ACR5            0xA4
-#define PT_ACR6            0xA8
-#define PT_ACR7            0xAC
-#define PT_ACR8            0xB0
-#define PT_ACR9            0xB4
-#define PT_ACR10    0xB8
-#define PT_ACR11    0xBC
-#define PT_ACR12    0xC0
-#define PT_ACR13    0xC4
-#define PT_ACR14    0xC8
-#define PT_ACR15    0xCC
-#define PT_ORIGGPR2 0xD0
-#define PT_FPC     0xD8
-#define PT_FPR0     0xE0
-#define PT_FPR1     0xE8
-#define PT_FPR2     0xF0
-#define PT_FPR3     0xF8
-#define PT_FPR4     0x100
-#define PT_FPR5     0x108
-#define PT_FPR6     0x110
-#define PT_FPR7     0x118
-#define PT_FPR8     0x120
-#define PT_FPR9     0x128
-#define PT_FPR10    0x130
-#define PT_FPR11    0x138
-#define PT_FPR12    0x140
-#define PT_FPR13    0x148
-#define PT_FPR14    0x150
-#define PT_FPR15    0x158
-#define PT_CR_9     0x160
-#define PT_CR_10    0x168
-#define PT_CR_11    0x170
-#define PT_IEEE_IP  0x1A8
-#define PT_LASTOFF  PT_IEEE_IP
-#define PT_ENDREGS  0x1B0-1
-
-#define GPR_SIZE       8
-#define CR_SIZE                8
-
-#define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
-
-#endif /* __s390x__ */
-
-#define NUM_GPRS       16
-#define NUM_FPRS       16
-#define NUM_CRS                16
-#define NUM_ACRS       16
-
-#define NUM_CR_WORDS   3
-
-#define FPR_SIZE       8
-#define FPC_SIZE       4
-#define FPC_PAD_SIZE   4 /* gcc insists on aligning the fpregs */
-#define ACR_SIZE       4
-
-
-#define PTRACE_OLDSETOPTIONS         21
+#include <uapi/asm/ptrace.h>
 
 #ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <linux/types.h>
-
-typedef union
-{
-       float   f;
-       double  d;
-        __u64   ui;
-       struct
-       {
-               __u32 hi;
-               __u32 lo;
-       } fp;
-} freg_t;
-
-typedef struct
-{
-       __u32   fpc;
-       freg_t  fprs[NUM_FPRS];              
-} s390_fp_regs;
-
-#define FPC_EXCEPTION_MASK      0xF8000000
-#define FPC_FLAGS_MASK          0x00F80000
-#define FPC_DXC_MASK            0x0000FF00
-#define FPC_RM_MASK             0x00000003
-#define FPC_VALID_MASK          0xF8F8FF03
-
-/* this typedef defines how a Program Status Word looks like */
-typedef struct 
-{
-        unsigned long mask;
-        unsigned long addr;
-} __attribute__ ((aligned(8))) psw_t;
-
-typedef struct
-{
-       __u32   mask;
-       __u32   addr;
-} __attribute__ ((aligned(8))) psw_compat_t;
-
 #ifndef __s390x__
-
-#define PSW_MASK_PER           0x40000000UL
-#define PSW_MASK_DAT           0x04000000UL
-#define PSW_MASK_IO            0x02000000UL
-#define PSW_MASK_EXT           0x01000000UL
-#define PSW_MASK_KEY           0x00F00000UL
-#define PSW_MASK_BASE          0x00080000UL    /* always one */
-#define PSW_MASK_MCHECK                0x00040000UL
-#define PSW_MASK_WAIT          0x00020000UL
-#define PSW_MASK_PSTATE                0x00010000UL
-#define PSW_MASK_ASC           0x0000C000UL
-#define PSW_MASK_CC            0x00003000UL
-#define PSW_MASK_PM            0x00000F00UL
-#define PSW_MASK_RI            0x00000000UL
-#define PSW_MASK_EA            0x00000000UL
-#define PSW_MASK_BA            0x00000000UL
-
-#define PSW_MASK_USER          0x00003F00UL
-
-#define PSW_ADDR_AMODE         0x80000000UL
-#define PSW_ADDR_INSN          0x7FFFFFFFUL
-
-#define PSW_DEFAULT_KEY                (((unsigned long) PAGE_DEFAULT_ACC) << 20)
-
-#define PSW_ASC_PRIMARY                0x00000000UL
-#define PSW_ASC_ACCREG         0x00004000UL
-#define PSW_ASC_SECONDARY      0x00008000UL
-#define PSW_ASC_HOME           0x0000C000UL
-
 #else /* __s390x__ */
-
-#define PSW_MASK_PER           0x4000000000000000UL
-#define PSW_MASK_DAT           0x0400000000000000UL
-#define PSW_MASK_IO            0x0200000000000000UL
-#define PSW_MASK_EXT           0x0100000000000000UL
-#define PSW_MASK_BASE          0x0000000000000000UL
-#define PSW_MASK_KEY           0x00F0000000000000UL
-#define PSW_MASK_MCHECK                0x0004000000000000UL
-#define PSW_MASK_WAIT          0x0002000000000000UL
-#define PSW_MASK_PSTATE                0x0001000000000000UL
-#define PSW_MASK_ASC           0x0000C00000000000UL
-#define PSW_MASK_CC            0x0000300000000000UL
-#define PSW_MASK_PM            0x00000F0000000000UL
-#define PSW_MASK_RI            0x0000008000000000UL
-#define PSW_MASK_EA            0x0000000100000000UL
-#define PSW_MASK_BA            0x0000000080000000UL
-
-#define PSW_MASK_USER          0x00003F8180000000UL
-
-#define PSW_ADDR_AMODE         0x0000000000000000UL
-#define PSW_ADDR_INSN          0xFFFFFFFFFFFFFFFFUL
-
-#define PSW_DEFAULT_KEY                (((unsigned long) PAGE_DEFAULT_ACC) << 52)
-
-#define PSW_ASC_PRIMARY                0x0000000000000000UL
-#define PSW_ASC_ACCREG         0x0000400000000000UL
-#define PSW_ASC_SECONDARY      0x0000800000000000UL
-#define PSW_ASC_HOME           0x0000C00000000000UL
-
 #endif /* __s390x__ */
-
-#ifdef __KERNEL__
 extern long psw_kernel_bits;
 extern long psw_user_bits;
-#endif
-
-/*
- * The s390_regs structure is used to define the elf_gregset_t.
- */
-typedef struct
-{
-       psw_t psw;
-       unsigned long gprs[NUM_GPRS];
-       unsigned int  acrs[NUM_ACRS];
-       unsigned long orig_gpr2;
-} s390_regs;
-
-typedef struct
-{
-       psw_compat_t    psw;
-       __u32           gprs[NUM_GPRS];
-       __u32           acrs[NUM_ACRS];
-       __u32           orig_gpr2;
-} s390_compat_regs;
-
-typedef struct
-{
-       __u32           gprs_high[NUM_GPRS];
-} s390_compat_regs_high;
-
-#ifdef __KERNEL__
 
 /*
  * The pt_regs struct defines the way the registers are stored on
@@ -376,167 +77,8 @@ struct per_struct_kernel {
 #define PER_CONTROL_SUSPENSION         0x00400000UL
 #define PER_CONTROL_ALTERATION         0x00200000UL
 
-#endif
-
-/*
- * Now for the user space program event recording (trace) definitions.
- * The following structures are used only for the ptrace interface, don't
- * touch or even look at it if you don't want to modify the user-space
- * ptrace interface. In particular stay away from it for in-kernel PER.
- */
-typedef struct
-{
-       unsigned long cr[NUM_CR_WORDS];
-} per_cr_words;
-
-#define PER_EM_MASK 0xE8000000UL
-
-typedef        struct
-{
 #ifdef __s390x__
-       unsigned                       : 32;
 #endif /* __s390x__ */
-       unsigned em_branching          : 1;
-       unsigned em_instruction_fetch  : 1;
-       /*
-        * Switching on storage alteration automatically fixes
-        * the storage alteration event bit in the users std.
-        */
-       unsigned em_storage_alteration : 1;
-       unsigned em_gpr_alt_unused     : 1;
-       unsigned em_store_real_address : 1;
-       unsigned                       : 3;
-       unsigned branch_addr_ctl       : 1;
-       unsigned                       : 1;
-       unsigned storage_alt_space_ctl : 1;
-       unsigned                       : 21;
-       unsigned long starting_addr;
-       unsigned long ending_addr;
-} per_cr_bits;
-
-typedef struct
-{
-       unsigned short perc_atmid;
-       unsigned long address;
-       unsigned char access_id;
-} per_lowcore_words;
-
-typedef struct
-{
-       unsigned perc_branching          : 1;
-       unsigned perc_instruction_fetch  : 1;
-       unsigned perc_storage_alteration : 1;
-       unsigned perc_gpr_alt_unused     : 1;
-       unsigned perc_store_real_address : 1;
-       unsigned                         : 3;
-       unsigned atmid_psw_bit_31        : 1;
-       unsigned atmid_validity_bit      : 1;
-       unsigned atmid_psw_bit_32        : 1;
-       unsigned atmid_psw_bit_5         : 1;
-       unsigned atmid_psw_bit_16        : 1;
-       unsigned atmid_psw_bit_17        : 1;
-       unsigned si                      : 2;
-       unsigned long address;
-       unsigned                         : 4;
-       unsigned access_id               : 4;
-} per_lowcore_bits;
-
-typedef struct
-{
-       union {
-               per_cr_words   words;
-               per_cr_bits    bits;
-       } control_regs;
-       /*
-        * Use these flags instead of setting em_instruction_fetch
-        * directly they are used so that single stepping can be
-        * switched on & off while not affecting other tracing
-        */
-       unsigned  single_step       : 1;
-       unsigned  instruction_fetch : 1;
-       unsigned                    : 30;
-       /*
-        * These addresses are copied into cr10 & cr11 if single
-        * stepping is switched off
-        */
-       unsigned long starting_addr;
-       unsigned long ending_addr;
-       union {
-               per_lowcore_words words;
-               per_lowcore_bits  bits;
-       } lowcore; 
-} per_struct;
-
-typedef struct
-{
-       unsigned int  len;
-       unsigned long kernel_addr;
-       unsigned long process_addr;
-} ptrace_area;
-
-/*
- * S/390 specific non posix ptrace requests. I chose unusual values so
- * they are unlikely to clash with future ptrace definitions.
- */
-#define PTRACE_PEEKUSR_AREA           0x5000
-#define PTRACE_POKEUSR_AREA           0x5001
-#define PTRACE_PEEKTEXT_AREA         0x5002
-#define PTRACE_PEEKDATA_AREA         0x5003
-#define PTRACE_POKETEXT_AREA         0x5004
-#define PTRACE_POKEDATA_AREA         0x5005
-#define PTRACE_GET_LAST_BREAK        0x5006
-#define PTRACE_PEEK_SYSTEM_CALL       0x5007
-#define PTRACE_POKE_SYSTEM_CALL              0x5008
-#define PTRACE_ENABLE_TE             0x5009
-#define PTRACE_DISABLE_TE            0x5010
-
-/*
- * PT_PROT definition is loosely based on hppa bsd definition in
- * gdb/hppab-nat.c
- */
-#define PTRACE_PROT                       21
-
-typedef enum
-{
-       ptprot_set_access_watchpoint,
-       ptprot_set_write_watchpoint,
-       ptprot_disable_watchpoint
-} ptprot_flags;
-
-typedef struct
-{
-       unsigned long lowaddr;
-       unsigned long hiaddr;
-       ptprot_flags prot;
-} ptprot_area;                     
-
-/* Sequence of bytes for breakpoint illegal instruction.  */
-#define S390_BREAKPOINT     {0x0,0x1}
-#define S390_BREAKPOINT_U16 ((__u16)0x0001)
-#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
-#define S390_SYSCALL_SIZE   2
-
-/*
- * The user_regs_struct defines the way the user registers are
- * store on the stack for signal handling.
- */
-struct user_regs_struct
-{
-       psw_t psw;
-       unsigned long gprs[NUM_GPRS];
-       unsigned int  acrs[NUM_ACRS];
-       unsigned long orig_gpr2;
-       s390_fp_regs fp_regs;
-       /*
-        * These per registers are in here so that gdb can modify them
-        * itself as there is no "official" ptrace interface for hardware
-        * watchpoints. This is the way intel does it.
-        */
-       per_struct per_info;
-       unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
-};
-
-#ifdef __KERNEL__
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
@@ -562,7 +104,5 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
        return regs->gprs[15] & PSW_ADDR_INSN;
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
-
 #endif /* _S390_PTRACE_H */
index 3e4d401..40b47df 100644 (file)
@@ -1,19 +1,8 @@
 #ifndef ASM_SCHID_H
 #define ASM_SCHID_H
 
-#include <linux/types.h>
-
-struct subchannel_id {
-       __u32 cssid : 8;
-       __u32 : 4;
-       __u32 m : 1;
-       __u32 ssid : 2;
-       __u32 one : 1;
-       __u32 sch_no : 16;
-} __attribute__ ((packed, aligned(4)));
-
-#ifdef __KERNEL__
 #include <linux/string.h>
+#include <uapi/asm/schid.h>
 
 /* Helper function for sane state of pre-allocated subchannel_id. */
 static inline void
@@ -29,6 +18,4 @@ schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2)
        return !memcmp(schid1, schid2, sizeof(struct subchannel_id));
 }
 
-#endif /* __KERNEL__ */
-
 #endif /* ASM_SCHID_H */
index 8cfd731..f69f76b 100644 (file)
@@ -2,15 +2,11 @@
  *  S390 version
  *    Copyright IBM Corp. 1999, 2010
  */
-
 #ifndef _ASM_S390_SETUP_H
 #define _ASM_S390_SETUP_H
 
-#define COMMAND_LINE_SIZE      4096
-
-#define ARCH_COMMAND_LINE_SIZE 896
+#include <uapi/asm/setup.h>
 
-#ifdef __KERNEL__
 
 #define PARMAREA               0x10400
 #define MEMORY_CHUNKS          256
@@ -75,8 +71,8 @@ extern unsigned int s390_user_mode;
 #define MACHINE_FLAG_DIAG9C    (1UL << 7)
 #define MACHINE_FLAG_MVCOS     (1UL << 8)
 #define MACHINE_FLAG_KVM       (1UL << 9)
-#define MACHINE_FLAG_HPAGE     (1UL << 10)
-#define MACHINE_FLAG_PFMF      (1UL << 11)
+#define MACHINE_FLAG_EDAT1     (1UL << 10)
+#define MACHINE_FLAG_EDAT2     (1UL << 11)
 #define MACHINE_FLAG_LPAR      (1UL << 12)
 #define MACHINE_FLAG_SPP       (1UL << 13)
 #define MACHINE_FLAG_TOPOLOGY  (1UL << 14)
@@ -88,6 +84,8 @@ extern unsigned int s390_user_mode;
 #define MACHINE_IS_LPAR                (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
 
 #define MACHINE_HAS_DIAG9C     (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C)
+#define MACHINE_HAS_PFMF       MACHINE_HAS_EDAT1
+#define MACHINE_HAS_HPAGE      MACHINE_HAS_EDAT1
 
 #ifndef CONFIG_64BIT
 #define MACHINE_HAS_IEEE       (S390_lowcore.machine_flags & MACHINE_FLAG_IEEE)
@@ -96,8 +94,8 @@ extern unsigned int s390_user_mode;
 #define MACHINE_HAS_DIAG44     (1)
 #define MACHINE_HAS_MVPG       (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG)
 #define MACHINE_HAS_MVCOS      (0)
-#define MACHINE_HAS_HPAGE      (0)
-#define MACHINE_HAS_PFMF       (0)
+#define MACHINE_HAS_EDAT1      (0)
+#define MACHINE_HAS_EDAT2      (0)
 #define MACHINE_HAS_SPP                (0)
 #define MACHINE_HAS_TOPOLOGY   (0)
 #define MACHINE_HAS_TE         (0)
@@ -109,8 +107,8 @@ extern unsigned int s390_user_mode;
 #define MACHINE_HAS_DIAG44     (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
 #define MACHINE_HAS_MVPG       (1)
 #define MACHINE_HAS_MVCOS      (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
-#define MACHINE_HAS_HPAGE      (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
-#define MACHINE_HAS_PFMF       (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
+#define MACHINE_HAS_EDAT1      (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
+#define MACHINE_HAS_EDAT2      (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
 #define MACHINE_HAS_SPP                (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
 #define MACHINE_HAS_TOPOLOGY   (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
 #define MACHINE_HAS_TE         (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
@@ -173,5 +171,4 @@ extern void (*_machine_power_off)(void);
 #define COMMAND_LINE      0x10480
 
 #endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
 #endif /* _ASM_S390_SETUP_H */
index 6d4d9d1..bffdbdd 100644 (file)
@@ -3,18 +3,11 @@
  *
  *  Derived from "include/asm-i386/signal.h"
  */
-
 #ifndef _ASMS390_SIGNAL_H
 #define _ASMS390_SIGNAL_H
 
-#include <linux/types.h>
-#include <linux/time.h>
-
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-struct pt_regs;
+#include <uapi/asm/signal.h>
 
-#ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
    is taken to make libc match.  */
 #include <asm/sigcontext.h>
@@ -28,94 +21,6 @@ typedef struct {
         unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG            32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP           1
-#define SIGINT           2
-#define SIGQUIT          3
-#define SIGILL           4
-#define SIGTRAP          5
-#define SIGABRT          6
-#define SIGIOT           6
-#define SIGBUS           7
-#define SIGFPE           8
-#define SIGKILL          9
-#define SIGUSR1         10
-#define SIGSEGV         11
-#define SIGUSR2         12
-#define SIGPIPE         13
-#define SIGALRM         14
-#define SIGTERM         15
-#define SIGSTKFLT       16
-#define SIGCHLD         17
-#define SIGCONT         18
-#define SIGSTOP         19
-#define SIGTSTP         20
-#define SIGTTIN         21
-#define SIGTTOU         22
-#define SIGURG          23
-#define SIGXCPU         24
-#define SIGXFSZ         25
-#define SIGVTALRM       26
-#define SIGPROF         27
-#define SIGWINCH        28
-#define SIGIO           29
-#define SIGPOLL         SIGIO
-/*
-#define SIGLOST         29
-*/
-#define SIGPWR          30
-#define SIGSYS         31
-#define SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN        32
-#define SIGRTMAX        _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP    0x00000001
-#define SA_NOCLDWAIT    0x00000002
-#define SA_SIGINFO      0x00000004
-#define SA_ONSTACK      0x08000000
-#define SA_RESTART      0x10000000
-#define SA_NODEFER      0x40000000
-#define SA_RESETHAND    0x80000000
-
-#define SA_NOMASK       SA_NODEFER
-#define SA_ONESHOT      SA_RESETHAND
-
-#define SA_RESTORER     0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK      1
-#define SS_DISABLE      2
-
-#define MINSIGSTKSZ     2048
-#define SIGSTKSZ        8192
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct old_sigaction {
         __sighandler_t sa_handler;
         old_sigset_t sa_mask;
@@ -136,35 +41,4 @@ struct k_sigaction {
 
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-        union {
-          __sighandler_t _sa_handler;
-          void (*_sa_sigaction)(int, struct siginfo *, void *);
-        } _u;
-#ifndef __s390x__ /* lovely */
-        sigset_t sa_mask;
-        unsigned long sa_flags;
-        void (*sa_restorer)(void);
-#else  /* __s390x__ */
-        unsigned long sa_flags;
-        void (*sa_restorer)(void);
-       sigset_t sa_mask;
-#endif /* __s390x__ */
-};
-
-#define sa_handler      _u._sa_handler
-#define sa_sigaction    _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-        void __user *ss_sp;
-        int ss_flags;
-        size_t ss_size;
-} stack_t;
-
-
 #endif
index cb9fe27..db028d1 100644 (file)
@@ -3,49 +3,11 @@
  *
  *  Derived from "include/asm-i386/termios.h"
  */
-
 #ifndef _S390_TERMIOS_H
 #define _S390_TERMIOS_H
 
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
+#include <uapi/asm/termios.h>
 
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
 
 /*     intr=^C         quit=^\         erase=del       kill=^U
        eof=^D          vtime=\0        vmin=\1         sxtc=\0
@@ -60,6 +22,4 @@ struct termio {
 
 #include <asm-generic/termios-base.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _S390_TERMIOS_H */
index 6ba7c2c..dccef3c 100644 (file)
@@ -3,26 +3,14 @@
  *
  *  Derived from "include/asm-i386/types.h"
  */
-
 #ifndef _S390_TYPES_H
 #define _S390_TYPES_H
 
-#include <asm-generic/int-ll64.h>
-
-#ifndef __ASSEMBLY__
-
-/* A address type so that arithmetic can be done on it & it can be upgraded to
-   64 bit when necessary 
-*/
-typedef unsigned long addr_t; 
-typedef __signed__ long saddr_t;
-
-#endif /* __ASSEMBLY__ */
+#include <uapi/asm/types.h>
 
 /*
  * These aren't exported outside the kernel to avoid name space clashes
  */
-#ifdef __KERNEL__
 
 #ifndef __ASSEMBLY__
 
@@ -37,5 +25,4 @@ typedef union {
 
 #endif /* ! CONFIG_64BIT   */
 #endif /* __ASSEMBLY__  */
-#endif /* __KERNEL__    */
 #endif /* _S390_TYPES_H */
index 8192e29..bbbae41 100644 (file)
  *
  *  Derived from "include/asm-i386/unistd.h"
  */
-
 #ifndef _ASM_S390_UNISTD_H_
 #define _ASM_S390_UNISTD_H_
 
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_exit                 1
-#define __NR_fork                 2
-#define __NR_read                 3
-#define __NR_write                4
-#define __NR_open                 5
-#define __NR_close                6
-#define __NR_restart_syscall     7
-#define __NR_creat                8
-#define __NR_link                 9
-#define __NR_unlink              10
-#define __NR_execve              11
-#define __NR_chdir               12
-#define __NR_mknod               14
-#define __NR_chmod               15
-#define __NR_lseek               19
-#define __NR_getpid              20
-#define __NR_mount               21
-#define __NR_umount              22
-#define __NR_ptrace              26
-#define __NR_alarm               27
-#define __NR_pause               29
-#define __NR_utime               30
-#define __NR_access              33
-#define __NR_nice                34
-#define __NR_sync                36
-#define __NR_kill                37
-#define __NR_rename              38
-#define __NR_mkdir               39
-#define __NR_rmdir               40
-#define __NR_dup                 41
-#define __NR_pipe                42
-#define __NR_times               43
-#define __NR_brk                 45
-#define __NR_signal              48
-#define __NR_acct                51
-#define __NR_umount2             52
-#define __NR_ioctl               54
-#define __NR_fcntl               55
-#define __NR_setpgid             57
-#define __NR_umask               60
-#define __NR_chroot              61
-#define __NR_ustat               62
-#define __NR_dup2                63
-#define __NR_getppid             64
-#define __NR_getpgrp             65
-#define __NR_setsid              66
-#define __NR_sigaction           67
-#define __NR_sigsuspend          72
-#define __NR_sigpending          73
-#define __NR_sethostname         74
-#define __NR_setrlimit           75
-#define __NR_getrusage           77
-#define __NR_gettimeofday        78
-#define __NR_settimeofday        79
-#define __NR_symlink             83
-#define __NR_readlink            85
-#define __NR_uselib              86
-#define __NR_swapon              87
-#define __NR_reboot              88
-#define __NR_readdir             89
-#define __NR_mmap                90
-#define __NR_munmap              91
-#define __NR_truncate            92
-#define __NR_ftruncate           93
-#define __NR_fchmod              94
-#define __NR_getpriority         96
-#define __NR_setpriority         97
-#define __NR_statfs              99
-#define __NR_fstatfs            100
-#define __NR_socketcall         102
-#define __NR_syslog             103
-#define __NR_setitimer          104
-#define __NR_getitimer          105
-#define __NR_stat               106
-#define __NR_lstat              107
-#define __NR_fstat              108
-#define __NR_lookup_dcookie     110
-#define __NR_vhangup            111
-#define __NR_idle               112
-#define __NR_wait4              114
-#define __NR_swapoff            115
-#define __NR_sysinfo            116
-#define __NR_ipc                117
-#define __NR_fsync              118
-#define __NR_sigreturn          119
-#define __NR_clone              120
-#define __NR_setdomainname      121
-#define __NR_uname              122
-#define __NR_adjtimex           124
-#define __NR_mprotect           125
-#define __NR_sigprocmask        126
-#define __NR_create_module      127
-#define __NR_init_module        128
-#define __NR_delete_module      129
-#define __NR_get_kernel_syms    130
-#define __NR_quotactl           131
-#define __NR_getpgid            132
-#define __NR_fchdir             133
-#define __NR_bdflush            134
-#define __NR_sysfs              135
-#define __NR_personality        136
-#define __NR_afs_syscall        137 /* Syscall for Andrew File System */
-#define __NR_getdents           141
-#define __NR_flock              143
-#define __NR_msync              144
-#define __NR_readv              145
-#define __NR_writev             146
-#define __NR_getsid             147
-#define __NR_fdatasync          148
-#define __NR__sysctl            149
-#define __NR_mlock              150
-#define __NR_munlock            151
-#define __NR_mlockall           152
-#define __NR_munlockall         153
-#define __NR_sched_setparam             154
-#define __NR_sched_getparam             155
-#define __NR_sched_setscheduler         156
-#define __NR_sched_getscheduler         157
-#define __NR_sched_yield                158
-#define __NR_sched_get_priority_max     159
-#define __NR_sched_get_priority_min     160
-#define __NR_sched_rr_get_interval      161
-#define __NR_nanosleep          162
-#define __NR_mremap             163
-#define __NR_query_module       167
-#define __NR_poll               168
-#define __NR_nfsservctl         169
-#define __NR_prctl              172
-#define __NR_rt_sigreturn       173
-#define __NR_rt_sigaction       174
-#define __NR_rt_sigprocmask     175
-#define __NR_rt_sigpending      176
-#define __NR_rt_sigtimedwait    177
-#define __NR_rt_sigqueueinfo    178
-#define __NR_rt_sigsuspend      179
-#define __NR_pread64            180
-#define __NR_pwrite64           181
-#define __NR_getcwd             183
-#define __NR_capget             184
-#define __NR_capset             185
-#define __NR_sigaltstack        186
-#define __NR_sendfile           187
-#define __NR_getpmsg           188
-#define __NR_putpmsg           189
-#define __NR_vfork             190
-#define __NR_pivot_root         217
-#define __NR_mincore            218
-#define __NR_madvise            219
-#define __NR_getdents64                220
-#define __NR_readahead         222
-#define __NR_setxattr          224
-#define __NR_lsetxattr         225
-#define __NR_fsetxattr         226
-#define __NR_getxattr          227
-#define __NR_lgetxattr         228
-#define __NR_fgetxattr         229
-#define __NR_listxattr         230
-#define __NR_llistxattr                231
-#define __NR_flistxattr                232
-#define __NR_removexattr       233
-#define __NR_lremovexattr      234
-#define __NR_fremovexattr      235
-#define __NR_gettid            236
-#define __NR_tkill             237
-#define __NR_futex             238
-#define __NR_sched_setaffinity 239
-#define __NR_sched_getaffinity 240
-#define __NR_tgkill            241
-/* Number 242 is reserved for tux */
-#define __NR_io_setup          243
-#define __NR_io_destroy                244
-#define __NR_io_getevents      245
-#define __NR_io_submit         246
-#define __NR_io_cancel         247
-#define __NR_exit_group                248
-#define __NR_epoll_create      249
-#define __NR_epoll_ctl         250
-#define __NR_epoll_wait                251
-#define __NR_set_tid_address   252
-#define __NR_fadvise64         253
-#define __NR_timer_create      254
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
-/* Number 263 is reserved for vserver */
-#define __NR_statfs64          265
-#define __NR_fstatfs64         266
-#define __NR_remap_file_pages  267
-/* Number 268 is reserved for new sys_mbind */
-/* Number 269 is reserved for new sys_get_mempolicy */
-/* Number 270 is reserved for new sys_set_mempolicy */
-#define __NR_mq_open           271
-#define __NR_mq_unlink         272
-#define __NR_mq_timedsend      273
-#define __NR_mq_timedreceive   274
-#define __NR_mq_notify         275
-#define __NR_mq_getsetattr     276
-#define __NR_kexec_load                277
-#define __NR_add_key           278
-#define __NR_request_key       279
-#define __NR_keyctl            280
-#define __NR_waitid            281
-#define __NR_ioprio_set                282
-#define __NR_ioprio_get                283
-#define __NR_inotify_init      284
-#define __NR_inotify_add_watch 285
-#define __NR_inotify_rm_watch  286
-/* Number 287 is reserved for new sys_migrate_pages */
-#define __NR_openat            288
-#define __NR_mkdirat           289
-#define __NR_mknodat           290
-#define __NR_fchownat          291
-#define __NR_futimesat         292
-#define __NR_unlinkat          294
-#define __NR_renameat          295
-#define __NR_linkat            296
-#define __NR_symlinkat         297
-#define __NR_readlinkat                298
-#define __NR_fchmodat          299
-#define __NR_faccessat         300
-#define __NR_pselect6          301
-#define __NR_ppoll             302
-#define __NR_unshare           303
-#define __NR_set_robust_list   304
-#define __NR_get_robust_list   305
-#define __NR_splice            306
-#define __NR_sync_file_range   307
-#define __NR_tee               308
-#define __NR_vmsplice          309
-/* Number 310 is reserved for new sys_move_pages */
-#define __NR_getcpu            311
-#define __NR_epoll_pwait       312
-#define __NR_utimes            313
-#define __NR_fallocate         314
-#define __NR_utimensat         315
-#define __NR_signalfd          316
-#define __NR_timerfd           317
-#define __NR_eventfd           318
-#define __NR_timerfd_create    319
-#define __NR_timerfd_settime   320
-#define __NR_timerfd_gettime   321
-#define __NR_signalfd4         322
-#define __NR_eventfd2          323
-#define __NR_inotify_init1     324
-#define __NR_pipe2             325
-#define __NR_dup3              326
-#define __NR_epoll_create1     327
-#define        __NR_preadv             328
-#define        __NR_pwritev            329
-#define __NR_rt_tgsigqueueinfo 330
-#define __NR_perf_event_open   331
-#define __NR_fanotify_init     332
-#define __NR_fanotify_mark     333
-#define __NR_prlimit64         334
-#define __NR_name_to_handle_at 335
-#define __NR_open_by_handle_at 336
-#define __NR_clock_adjtime     337
-#define __NR_syncfs            338
-#define __NR_setns             339
-#define __NR_process_vm_readv  340
-#define __NR_process_vm_writev 341
-#define __NR_s390_runtime_instr 342
-#define __NR_kcmp              343
-#define NR_syscalls 344
-
-/* 
- * There are some system calls that are not present on 64 bit, some
- * have a different name although they do the same (e.g. __NR_chown32
- * is __NR_chown on 64 bit).
- */
-#ifndef __s390x__
-
-#define __NR_time               13
-#define __NR_lchown             16
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_getrlimit          76
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_fchown             95
-#define __NR_ioperm            101
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR__newselect        142
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_chown             182
-#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_fcntl64           221
-#define __NR_sendfile64                223
-#define __NR_fadvise64_64      264
-#define __NR_fstatat64         293
-
-#else
-
-#define __NR_select            142
-#define __NR_getrlimit         191     /* SuS compliant getrlimit */
-#define __NR_lchown            198
-#define __NR_getuid            199
-#define __NR_getgid            200
-#define __NR_geteuid           201
-#define __NR_getegid           202
-#define __NR_setreuid                  203
-#define __NR_setregid                  204
-#define __NR_getgroups         205
-#define __NR_setgroups         206
-#define __NR_fchown            207
-#define __NR_setresuid         208
-#define __NR_getresuid         209
-#define __NR_setresgid         210
-#define __NR_getresgid         211
-#define __NR_chown             212
-#define __NR_setuid            213
-#define __NR_setgid            214
-#define __NR_setfsuid                  215
-#define __NR_setfsgid                  216
-#define __NR_newfstatat                293
-
-#endif
+#include <uapi/asm/unistd.h>
 
-#ifdef __KERNEL__
 
 #ifndef CONFIG_64BIT
 #define __IGNORE_select
  */
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_S390_UNISTD_H_ */
index baebb3d..7bf68ff 100644 (file)
@@ -1,3 +1,48 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += chpid.h
+header-y += chsc.h
+header-y += cmb.h
+header-y += dasd.h
+header-y += debug.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm.h
+header-y += kvm_para.h
+header-y += kvm_virtio.h
+header-y += mman.h
+header-y += monwriter.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += qeth.h
+header-y += resource.h
+header-y += schid.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += tape390.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += ucontext.h
+header-y += unistd.h
+header-y += vtoc.h
+header-y += zcrypt.h
diff --git a/arch/s390/include/uapi/asm/chpid.h b/arch/s390/include/uapi/asm/chpid.h
new file mode 100644 (file)
index 0000000..581992d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _UAPI_ASM_S390_CHPID_H
+#define _UAPI_ASM_S390_CHPID_H
+
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define __MAX_CHPID 255
+
+struct chp_id {
+       u8 reserved1;
+       u8 cssid;
+       u8 reserved2;
+       u8 id;
+} __attribute__((packed));
+
+
+#endif /* _UAPI_ASM_S390_CHPID_H */
similarity index 92%
rename from arch/s390/include/asm/chsc.h
rename to arch/s390/include/uapi/asm/chsc.h
index aea451f..1c6a7f8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ioctl interface for /dev/chsc
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2012
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  */
 
@@ -9,9 +9,12 @@
 #define _ASM_CHSC_H
 
 #include <linux/types.h>
+#include <linux/ioctl.h>
 #include <asm/chpid.h>
 #include <asm/schid.h>
 
+#define CHSC_SIZE 0x1000
+
 struct chsc_async_header {
        __u16 length;
        __u16 code;
@@ -23,15 +26,14 @@ struct chsc_async_header {
 
 struct chsc_async_area {
        struct chsc_async_header header;
-       __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */];
+       __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)];
 } __attribute__ ((packed));
 
-
 struct chsc_response_struct {
        __u16 length;
        __u16 code;
        __u32 parms;
-       __u8 data[PAGE_SIZE - 8];
+       __u8 data[CHSC_SIZE - 2 * sizeof(__u16) - sizeof(__u32)];
 } __attribute__ ((packed));
 
 struct chsc_chp_cd {
diff --git a/arch/s390/include/uapi/asm/cmb.h b/arch/s390/include/uapi/asm/cmb.h
new file mode 100644 (file)
index 0000000..0c086d0
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _UAPIS390_CMB_H
+#define _UAPIS390_CMB_H
+
+#include <linux/types.h>
+
+/**
+ * struct cmbdata - channel measurement block data for user space
+ * @size: size of the stored data
+ * @elapsed_time: time since last sampling
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy (ext. format)
+ * @initial_command_response_time: initial command response time (ext. format)
+ *
+ * All values are stored as 64 bit for simplicity, especially
+ * in 32 bit emulation mode. All time values are normalized to
+ * nanoseconds.
+ * Currently, two formats are known, which differ by the size of
+ * this structure, i.e. the last two members are only set when
+ * the extended channel measurement facility (first shipped in
+ * z990 machines) is activated.
+ * Potentially, more fields could be added, which would result in a
+ * new ioctl number.
+ */
+struct cmbdata {
+       __u64 size;
+       __u64 elapsed_time;
+ /* basic and exended format: */
+       __u64 ssch_rsch_count;
+       __u64 sample_count;
+       __u64 device_connect_time;
+       __u64 function_pending_time;
+       __u64 device_disconnect_time;
+       __u64 control_unit_queuing_time;
+       __u64 device_active_only_time;
+ /* extended format only: */
+       __u64 device_busy_time;
+       __u64 initial_command_response_time;
+};
+
+/* enable channel measurement */
+#define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER, 32)
+/* enable channel measurement */
+#define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER, 33)
+/* read channel measurement data */
+#define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
+
+#endif /* _UAPIS390_CMB_H */
diff --git a/arch/s390/include/uapi/asm/debug.h b/arch/s390/include/uapi/asm/debug.h
new file mode 100644 (file)
index 0000000..c59fc79
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *   S/390 debug facility
+ *
+ *    Copyright IBM Corp. 1999, 2000
+ */
+
+#ifndef _UAPIDEBUG_H
+#define _UAPIDEBUG_H
+
+#include <linux/fs.h>
+
+/* Note:
+ * struct __debug_entry must be defined outside of #ifdef __KERNEL__ 
+ * in order to allow a user program to analyze the 'raw'-view.
+ */
+
+struct __debug_entry{
+        union {
+                struct {
+                        unsigned long long clock:52;
+                        unsigned long long exception:1;
+                        unsigned long long level:3;
+                        unsigned long long cpuid:8;
+                } fields;
+
+                unsigned long long stck;
+        } id;
+        void* caller;
+} __attribute__((packed));
+
+
+#define __DEBUG_FEATURE_VERSION      2  /* version of debug feature */
+
+#endif /* _UAPIDEBUG_H */
diff --git a/arch/s390/include/uapi/asm/kvm_para.h b/arch/s390/include/uapi/asm/kvm_para.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/arch/s390/include/uapi/asm/mman.h b/arch/s390/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..de23da1
--- /dev/null
@@ -0,0 +1,6 @@
+/*
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/mman.h"
+ */
+#include <asm-generic/mman.h>
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..705588a
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ *  S390 version
+ *    Copyright IBM Corp. 1999, 2000
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef _UAPI_S390_PTRACE_H
+#define _UAPI_S390_PTRACE_H
+
+/*
+ * Offsets in the user_regs_struct. They are used for the ptrace
+ * system call and in entry.S
+ */
+#ifndef __s390x__
+
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x04
+#define PT_GPR0     0x08
+#define PT_GPR1     0x0C
+#define PT_GPR2     0x10
+#define PT_GPR3     0x14
+#define PT_GPR4     0x18
+#define PT_GPR5     0x1C
+#define PT_GPR6     0x20
+#define PT_GPR7     0x24
+#define PT_GPR8     0x28
+#define PT_GPR9     0x2C
+#define PT_GPR10    0x30
+#define PT_GPR11    0x34
+#define PT_GPR12    0x38
+#define PT_GPR13    0x3C
+#define PT_GPR14    0x40
+#define PT_GPR15    0x44
+#define PT_ACR0     0x48
+#define PT_ACR1     0x4C
+#define PT_ACR2     0x50
+#define PT_ACR3     0x54
+#define PT_ACR4            0x58
+#define PT_ACR5            0x5C
+#define PT_ACR6            0x60
+#define PT_ACR7            0x64
+#define PT_ACR8            0x68
+#define PT_ACR9            0x6C
+#define PT_ACR10    0x70
+#define PT_ACR11    0x74
+#define PT_ACR12    0x78
+#define PT_ACR13    0x7C
+#define PT_ACR14    0x80
+#define PT_ACR15    0x84
+#define PT_ORIGGPR2 0x88
+#define PT_FPC     0x90
+/*
+ * A nasty fact of life that the ptrace api
+ * only supports passing of longs.
+ */
+#define PT_FPR0_HI  0x98
+#define PT_FPR0_LO  0x9C
+#define PT_FPR1_HI  0xA0
+#define PT_FPR1_LO  0xA4
+#define PT_FPR2_HI  0xA8
+#define PT_FPR2_LO  0xAC
+#define PT_FPR3_HI  0xB0
+#define PT_FPR3_LO  0xB4
+#define PT_FPR4_HI  0xB8
+#define PT_FPR4_LO  0xBC
+#define PT_FPR5_HI  0xC0
+#define PT_FPR5_LO  0xC4
+#define PT_FPR6_HI  0xC8
+#define PT_FPR6_LO  0xCC
+#define PT_FPR7_HI  0xD0
+#define PT_FPR7_LO  0xD4
+#define PT_FPR8_HI  0xD8
+#define PT_FPR8_LO  0XDC
+#define PT_FPR9_HI  0xE0
+#define PT_FPR9_LO  0xE4
+#define PT_FPR10_HI 0xE8
+#define PT_FPR10_LO 0xEC
+#define PT_FPR11_HI 0xF0
+#define PT_FPR11_LO 0xF4
+#define PT_FPR12_HI 0xF8
+#define PT_FPR12_LO 0xFC
+#define PT_FPR13_HI 0x100
+#define PT_FPR13_LO 0x104
+#define PT_FPR14_HI 0x108
+#define PT_FPR14_LO 0x10C
+#define PT_FPR15_HI 0x110
+#define PT_FPR15_LO 0x114
+#define PT_CR_9            0x118
+#define PT_CR_10    0x11C
+#define PT_CR_11    0x120
+#define PT_IEEE_IP  0x13C
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x140-1
+
+#define GPR_SIZE       4
+#define CR_SIZE                4
+
+#define STACK_FRAME_OVERHEAD   96      /* size of minimum stack frame */
+
+#else /* __s390x__ */
+
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x08
+#define PT_GPR0     0x10
+#define PT_GPR1     0x18
+#define PT_GPR2     0x20
+#define PT_GPR3     0x28
+#define PT_GPR4     0x30
+#define PT_GPR5     0x38
+#define PT_GPR6     0x40
+#define PT_GPR7     0x48
+#define PT_GPR8     0x50
+#define PT_GPR9     0x58
+#define PT_GPR10    0x60
+#define PT_GPR11    0x68
+#define PT_GPR12    0x70
+#define PT_GPR13    0x78
+#define PT_GPR14    0x80
+#define PT_GPR15    0x88
+#define PT_ACR0     0x90
+#define PT_ACR1     0x94
+#define PT_ACR2     0x98
+#define PT_ACR3     0x9C
+#define PT_ACR4            0xA0
+#define PT_ACR5            0xA4
+#define PT_ACR6            0xA8
+#define PT_ACR7            0xAC
+#define PT_ACR8            0xB0
+#define PT_ACR9            0xB4
+#define PT_ACR10    0xB8
+#define PT_ACR11    0xBC
+#define PT_ACR12    0xC0
+#define PT_ACR13    0xC4
+#define PT_ACR14    0xC8
+#define PT_ACR15    0xCC
+#define PT_ORIGGPR2 0xD0
+#define PT_FPC     0xD8
+#define PT_FPR0     0xE0
+#define PT_FPR1     0xE8
+#define PT_FPR2     0xF0
+#define PT_FPR3     0xF8
+#define PT_FPR4     0x100
+#define PT_FPR5     0x108
+#define PT_FPR6     0x110
+#define PT_FPR7     0x118
+#define PT_FPR8     0x120
+#define PT_FPR9     0x128
+#define PT_FPR10    0x130
+#define PT_FPR11    0x138
+#define PT_FPR12    0x140
+#define PT_FPR13    0x148
+#define PT_FPR14    0x150
+#define PT_FPR15    0x158
+#define PT_CR_9     0x160
+#define PT_CR_10    0x168
+#define PT_CR_11    0x170
+#define PT_IEEE_IP  0x1A8
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x1B0-1
+
+#define GPR_SIZE       8
+#define CR_SIZE                8
+
+#define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
+
+#endif /* __s390x__ */
+
+#define NUM_GPRS       16
+#define NUM_FPRS       16
+#define NUM_CRS                16
+#define NUM_ACRS       16
+
+#define NUM_CR_WORDS   3
+
+#define FPR_SIZE       8
+#define FPC_SIZE       4
+#define FPC_PAD_SIZE   4 /* gcc insists on aligning the fpregs */
+#define ACR_SIZE       4
+
+
+#define PTRACE_OLDSETOPTIONS         21
+
+#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+typedef union
+{
+       float   f;
+       double  d;
+        __u64   ui;
+       struct
+       {
+               __u32 hi;
+               __u32 lo;
+       } fp;
+} freg_t;
+
+typedef struct
+{
+       __u32   fpc;
+       freg_t  fprs[NUM_FPRS];              
+} s390_fp_regs;
+
+#define FPC_EXCEPTION_MASK      0xF8000000
+#define FPC_FLAGS_MASK          0x00F80000
+#define FPC_DXC_MASK            0x0000FF00
+#define FPC_RM_MASK             0x00000003
+#define FPC_VALID_MASK          0xF8F8FF03
+
+/* this typedef defines how a Program Status Word looks like */
+typedef struct 
+{
+        unsigned long mask;
+        unsigned long addr;
+} __attribute__ ((aligned(8))) psw_t;
+
+typedef struct
+{
+       __u32   mask;
+       __u32   addr;
+} __attribute__ ((aligned(8))) psw_compat_t;
+
+#ifndef __s390x__
+
+#define PSW_MASK_PER           0x40000000UL
+#define PSW_MASK_DAT           0x04000000UL
+#define PSW_MASK_IO            0x02000000UL
+#define PSW_MASK_EXT           0x01000000UL
+#define PSW_MASK_KEY           0x00F00000UL
+#define PSW_MASK_BASE          0x00080000UL    /* always one */
+#define PSW_MASK_MCHECK                0x00040000UL
+#define PSW_MASK_WAIT          0x00020000UL
+#define PSW_MASK_PSTATE                0x00010000UL
+#define PSW_MASK_ASC           0x0000C000UL
+#define PSW_MASK_CC            0x00003000UL
+#define PSW_MASK_PM            0x00000F00UL
+#define PSW_MASK_RI            0x00000000UL
+#define PSW_MASK_EA            0x00000000UL
+#define PSW_MASK_BA            0x00000000UL
+
+#define PSW_MASK_USER          0x00003F00UL
+
+#define PSW_ADDR_AMODE         0x80000000UL
+#define PSW_ADDR_INSN          0x7FFFFFFFUL
+
+#define PSW_DEFAULT_KEY                (((unsigned long) PAGE_DEFAULT_ACC) << 20)
+
+#define PSW_ASC_PRIMARY                0x00000000UL
+#define PSW_ASC_ACCREG         0x00004000UL
+#define PSW_ASC_SECONDARY      0x00008000UL
+#define PSW_ASC_HOME           0x0000C000UL
+
+#else /* __s390x__ */
+
+#define PSW_MASK_PER           0x4000000000000000UL
+#define PSW_MASK_DAT           0x0400000000000000UL
+#define PSW_MASK_IO            0x0200000000000000UL
+#define PSW_MASK_EXT           0x0100000000000000UL
+#define PSW_MASK_BASE          0x0000000000000000UL
+#define PSW_MASK_KEY           0x00F0000000000000UL
+#define PSW_MASK_MCHECK                0x0004000000000000UL
+#define PSW_MASK_WAIT          0x0002000000000000UL
+#define PSW_MASK_PSTATE                0x0001000000000000UL
+#define PSW_MASK_ASC           0x0000C00000000000UL
+#define PSW_MASK_CC            0x0000300000000000UL
+#define PSW_MASK_PM            0x00000F0000000000UL
+#define PSW_MASK_RI            0x0000008000000000UL
+#define PSW_MASK_EA            0x0000000100000000UL
+#define PSW_MASK_BA            0x0000000080000000UL
+
+#define PSW_MASK_USER          0x00003F8180000000UL
+
+#define PSW_ADDR_AMODE         0x0000000000000000UL
+#define PSW_ADDR_INSN          0xFFFFFFFFFFFFFFFFUL
+
+#define PSW_DEFAULT_KEY                (((unsigned long) PAGE_DEFAULT_ACC) << 52)
+
+#define PSW_ASC_PRIMARY                0x0000000000000000UL
+#define PSW_ASC_ACCREG         0x0000400000000000UL
+#define PSW_ASC_SECONDARY      0x0000800000000000UL
+#define PSW_ASC_HOME           0x0000C00000000000UL
+
+#endif /* __s390x__ */
+
+
+/*
+ * The s390_regs structure is used to define the elf_gregset_t.
+ */
+typedef struct
+{
+       psw_t psw;
+       unsigned long gprs[NUM_GPRS];
+       unsigned int  acrs[NUM_ACRS];
+       unsigned long orig_gpr2;
+} s390_regs;
+
+typedef struct
+{
+       psw_compat_t    psw;
+       __u32           gprs[NUM_GPRS];
+       __u32           acrs[NUM_ACRS];
+       __u32           orig_gpr2;
+} s390_compat_regs;
+
+typedef struct
+{
+       __u32           gprs_high[NUM_GPRS];
+} s390_compat_regs_high;
+
+
+/*
+ * Now for the user space program event recording (trace) definitions.
+ * The following structures are used only for the ptrace interface, don't
+ * touch or even look at it if you don't want to modify the user-space
+ * ptrace interface. In particular stay away from it for in-kernel PER.
+ */
+typedef struct
+{
+       unsigned long cr[NUM_CR_WORDS];
+} per_cr_words;
+
+#define PER_EM_MASK 0xE8000000UL
+
+typedef        struct
+{
+#ifdef __s390x__
+       unsigned                       : 32;
+#endif /* __s390x__ */
+       unsigned em_branching          : 1;
+       unsigned em_instruction_fetch  : 1;
+       /*
+        * Switching on storage alteration automatically fixes
+        * the storage alteration event bit in the users std.
+        */
+       unsigned em_storage_alteration : 1;
+       unsigned em_gpr_alt_unused     : 1;
+       unsigned em_store_real_address : 1;
+       unsigned                       : 3;
+       unsigned branch_addr_ctl       : 1;
+       unsigned                       : 1;
+       unsigned storage_alt_space_ctl : 1;
+       unsigned                       : 21;
+       unsigned long starting_addr;
+       unsigned long ending_addr;
+} per_cr_bits;
+
+typedef struct
+{
+       unsigned short perc_atmid;
+       unsigned long address;
+       unsigned char access_id;
+} per_lowcore_words;
+
+typedef struct
+{
+       unsigned perc_branching          : 1;
+       unsigned perc_instruction_fetch  : 1;
+       unsigned perc_storage_alteration : 1;
+       unsigned perc_gpr_alt_unused     : 1;
+       unsigned perc_store_real_address : 1;
+       unsigned                         : 3;
+       unsigned atmid_psw_bit_31        : 1;
+       unsigned atmid_validity_bit      : 1;
+       unsigned atmid_psw_bit_32        : 1;
+       unsigned atmid_psw_bit_5         : 1;
+       unsigned atmid_psw_bit_16        : 1;
+       unsigned atmid_psw_bit_17        : 1;
+       unsigned si                      : 2;
+       unsigned long address;
+       unsigned                         : 4;
+       unsigned access_id               : 4;
+} per_lowcore_bits;
+
+typedef struct
+{
+       union {
+               per_cr_words   words;
+               per_cr_bits    bits;
+       } control_regs;
+       /*
+        * Use these flags instead of setting em_instruction_fetch
+        * directly they are used so that single stepping can be
+        * switched on & off while not affecting other tracing
+        */
+       unsigned  single_step       : 1;
+       unsigned  instruction_fetch : 1;
+       unsigned                    : 30;
+       /*
+        * These addresses are copied into cr10 & cr11 if single
+        * stepping is switched off
+        */
+       unsigned long starting_addr;
+       unsigned long ending_addr;
+       union {
+               per_lowcore_words words;
+               per_lowcore_bits  bits;
+       } lowcore; 
+} per_struct;
+
+typedef struct
+{
+       unsigned int  len;
+       unsigned long kernel_addr;
+       unsigned long process_addr;
+} ptrace_area;
+
+/*
+ * S/390 specific non posix ptrace requests. I chose unusual values so
+ * they are unlikely to clash with future ptrace definitions.
+ */
+#define PTRACE_PEEKUSR_AREA           0x5000
+#define PTRACE_POKEUSR_AREA           0x5001
+#define PTRACE_PEEKTEXT_AREA         0x5002
+#define PTRACE_PEEKDATA_AREA         0x5003
+#define PTRACE_POKETEXT_AREA         0x5004
+#define PTRACE_POKEDATA_AREA         0x5005
+#define PTRACE_GET_LAST_BREAK        0x5006
+#define PTRACE_PEEK_SYSTEM_CALL       0x5007
+#define PTRACE_POKE_SYSTEM_CALL              0x5008
+#define PTRACE_ENABLE_TE             0x5009
+#define PTRACE_DISABLE_TE            0x5010
+
+/*
+ * PT_PROT definition is loosely based on hppa bsd definition in
+ * gdb/hppab-nat.c
+ */
+#define PTRACE_PROT                       21
+
+typedef enum
+{
+       ptprot_set_access_watchpoint,
+       ptprot_set_write_watchpoint,
+       ptprot_disable_watchpoint
+} ptprot_flags;
+
+typedef struct
+{
+       unsigned long lowaddr;
+       unsigned long hiaddr;
+       ptprot_flags prot;
+} ptprot_area;                     
+
+/* Sequence of bytes for breakpoint illegal instruction.  */
+#define S390_BREAKPOINT     {0x0,0x1}
+#define S390_BREAKPOINT_U16 ((__u16)0x0001)
+#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
+#define S390_SYSCALL_SIZE   2
+
+/*
+ * The user_regs_struct defines the way the user registers are
+ * store on the stack for signal handling.
+ */
+struct user_regs_struct
+{
+       psw_t psw;
+       unsigned long gprs[NUM_GPRS];
+       unsigned int  acrs[NUM_ACRS];
+       unsigned long orig_gpr2;
+       s390_fp_regs fp_regs;
+       /*
+        * These per registers are in here so that gdb can modify them
+        * itself as there is no "official" ptrace interface for hardware
+        * watchpoints. This is the way intel does it.
+        */
+       per_struct per_info;
+       unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_S390_PTRACE_H */
diff --git a/arch/s390/include/uapi/asm/schid.h b/arch/s390/include/uapi/asm/schid.h
new file mode 100644 (file)
index 0000000..32f3ab2
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _UAPIASM_SCHID_H
+#define _UAPIASM_SCHID_H
+
+#include <linux/types.h>
+
+struct subchannel_id {
+       __u32 cssid : 8;
+       __u32 : 4;
+       __u32 m : 1;
+       __u32 ssid : 2;
+       __u32 one : 1;
+       __u32 sch_no : 16;
+} __attribute__ ((packed, aligned(4)));
+
+
+#endif /* _UAPIASM_SCHID_H */
diff --git a/arch/s390/include/uapi/asm/setup.h b/arch/s390/include/uapi/asm/setup.h
new file mode 100644 (file)
index 0000000..5a637e3
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *  S390 version
+ *    Copyright IBM Corp. 1999, 2010
+ */
+
+#ifndef _UAPI_ASM_S390_SETUP_H
+#define _UAPI_ASM_S390_SETUP_H
+
+#define COMMAND_LINE_SIZE      4096
+
+#define ARCH_COMMAND_LINE_SIZE 896
+
+#endif /* _UAPI_ASM_S390_SETUP_H */
diff --git a/arch/s390/include/uapi/asm/signal.h b/arch/s390/include/uapi/asm/signal.h
new file mode 100644 (file)
index 0000000..8c6a49e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/signal.h"
+ */
+
+#ifndef _UAPI_ASMS390_SIGNAL_H
+#define _UAPI_ASMS390_SIGNAL_H
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+struct pt_regs;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG            32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP           1
+#define SIGINT           2
+#define SIGQUIT          3
+#define SIGILL           4
+#define SIGTRAP          5
+#define SIGABRT          6
+#define SIGIOT           6
+#define SIGBUS           7
+#define SIGFPE           8
+#define SIGKILL          9
+#define SIGUSR1         10
+#define SIGSEGV         11
+#define SIGUSR2         12
+#define SIGPIPE         13
+#define SIGALRM         14
+#define SIGTERM         15
+#define SIGSTKFLT       16
+#define SIGCHLD         17
+#define SIGCONT         18
+#define SIGSTOP         19
+#define SIGTSTP         20
+#define SIGTTIN         21
+#define SIGTTOU         22
+#define SIGURG          23
+#define SIGXCPU         24
+#define SIGXFSZ         25
+#define SIGVTALRM       26
+#define SIGPROF         27
+#define SIGWINCH        28
+#define SIGIO           29
+#define SIGPOLL         SIGIO
+/*
+#define SIGLOST         29
+*/
+#define SIGPWR          30
+#define SIGSYS         31
+#define SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN        32
+#define SIGRTMAX        _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP    0x00000001
+#define SA_NOCLDWAIT    0x00000002
+#define SA_SIGINFO      0x00000004
+#define SA_ONSTACK      0x08000000
+#define SA_RESTART      0x10000000
+#define SA_NODEFER      0x40000000
+#define SA_RESETHAND    0x80000000
+
+#define SA_NOMASK       SA_NODEFER
+#define SA_ONESHOT      SA_RESETHAND
+
+#define SA_RESTORER     0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK      1
+#define SS_DISABLE      2
+
+#define MINSIGSTKSZ     2048
+#define SIGSTKSZ        8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+        union {
+          __sighandler_t _sa_handler;
+          void (*_sa_sigaction)(int, struct siginfo *, void *);
+        } _u;
+#ifndef __s390x__ /* lovely */
+        sigset_t sa_mask;
+        unsigned long sa_flags;
+        void (*sa_restorer)(void);
+#else  /* __s390x__ */
+        unsigned long sa_flags;
+        void (*sa_restorer)(void);
+       sigset_t sa_mask;
+#endif /* __s390x__ */
+};
+
+#define sa_handler      _u._sa_handler
+#define sa_sigaction    _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+        void __user *ss_sp;
+        int ss_flags;
+        size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_ASMS390_SIGNAL_H */
diff --git a/arch/s390/include/uapi/asm/termios.h b/arch/s390/include/uapi/asm/termios.h
new file mode 100644 (file)
index 0000000..554f973
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/termios.h"
+ */
+
+#ifndef _UAPI_S390_TERMIOS_H
+#define _UAPI_S390_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+
+#endif /* _UAPI_S390_TERMIOS_H */
diff --git a/arch/s390/include/uapi/asm/types.h b/arch/s390/include/uapi/asm/types.h
new file mode 100644 (file)
index 0000000..038f2b9
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/types.h"
+ */
+
+#ifndef _UAPI_S390_TYPES_H
+#define _UAPI_S390_TYPES_H
+
+#include <asm-generic/int-ll64.h>
+
+#ifndef __ASSEMBLY__
+
+/* A address type so that arithmetic can be done on it & it can be upgraded to
+   64 bit when necessary 
+*/
+typedef unsigned long addr_t; 
+typedef __signed__ long saddr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_S390_TYPES_H */
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..63e6078
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/unistd.h"
+ */
+
+#ifndef _UAPI_ASM_S390_UNISTD_H_
+#define _UAPI_ASM_S390_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_exit                 1
+#define __NR_fork                 2
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_restart_syscall     7
+#define __NR_creat                8
+#define __NR_link                 9
+#define __NR_unlink              10
+#define __NR_execve              11
+#define __NR_chdir               12
+#define __NR_mknod               14
+#define __NR_chmod               15
+#define __NR_lseek               19
+#define __NR_getpid              20
+#define __NR_mount               21
+#define __NR_umount              22
+#define __NR_ptrace              26
+#define __NR_alarm               27
+#define __NR_pause               29
+#define __NR_utime               30
+#define __NR_access              33
+#define __NR_nice                34
+#define __NR_sync                36
+#define __NR_kill                37
+#define __NR_rename              38
+#define __NR_mkdir               39
+#define __NR_rmdir               40
+#define __NR_dup                 41
+#define __NR_pipe                42
+#define __NR_times               43
+#define __NR_brk                 45
+#define __NR_signal              48
+#define __NR_acct                51
+#define __NR_umount2             52
+#define __NR_ioctl               54
+#define __NR_fcntl               55
+#define __NR_setpgid             57
+#define __NR_umask               60
+#define __NR_chroot              61
+#define __NR_ustat               62
+#define __NR_dup2                63
+#define __NR_getppid             64
+#define __NR_getpgrp             65
+#define __NR_setsid              66
+#define __NR_sigaction           67
+#define __NR_sigsuspend          72
+#define __NR_sigpending          73
+#define __NR_sethostname         74
+#define __NR_setrlimit           75
+#define __NR_getrusage           77
+#define __NR_gettimeofday        78
+#define __NR_settimeofday        79
+#define __NR_symlink             83
+#define __NR_readlink            85
+#define __NR_uselib              86
+#define __NR_swapon              87
+#define __NR_reboot              88
+#define __NR_readdir             89
+#define __NR_mmap                90
+#define __NR_munmap              91
+#define __NR_truncate            92
+#define __NR_ftruncate           93
+#define __NR_fchmod              94
+#define __NR_getpriority         96
+#define __NR_setpriority         97
+#define __NR_statfs              99
+#define __NR_fstatfs            100
+#define __NR_socketcall         102
+#define __NR_syslog             103
+#define __NR_setitimer          104
+#define __NR_getitimer          105
+#define __NR_stat               106
+#define __NR_lstat              107
+#define __NR_fstat              108
+#define __NR_lookup_dcookie     110
+#define __NR_vhangup            111
+#define __NR_idle               112
+#define __NR_wait4              114
+#define __NR_swapoff            115
+#define __NR_sysinfo            116
+#define __NR_ipc                117
+#define __NR_fsync              118
+#define __NR_sigreturn          119
+#define __NR_clone              120
+#define __NR_setdomainname      121
+#define __NR_uname              122
+#define __NR_adjtimex           124
+#define __NR_mprotect           125
+#define __NR_sigprocmask        126
+#define __NR_create_module      127
+#define __NR_init_module        128
+#define __NR_delete_module      129
+#define __NR_get_kernel_syms    130
+#define __NR_quotactl           131
+#define __NR_getpgid            132
+#define __NR_fchdir             133
+#define __NR_bdflush            134
+#define __NR_sysfs              135
+#define __NR_personality        136
+#define __NR_afs_syscall        137 /* Syscall for Andrew File System */
+#define __NR_getdents           141
+#define __NR_flock              143
+#define __NR_msync              144
+#define __NR_readv              145
+#define __NR_writev             146
+#define __NR_getsid             147
+#define __NR_fdatasync          148
+#define __NR__sysctl            149
+#define __NR_mlock              150
+#define __NR_munlock            151
+#define __NR_mlockall           152
+#define __NR_munlockall         153
+#define __NR_sched_setparam             154
+#define __NR_sched_getparam             155
+#define __NR_sched_setscheduler         156
+#define __NR_sched_getscheduler         157
+#define __NR_sched_yield                158
+#define __NR_sched_get_priority_max     159
+#define __NR_sched_get_priority_min     160
+#define __NR_sched_rr_get_interval      161
+#define __NR_nanosleep          162
+#define __NR_mremap             163
+#define __NR_query_module       167
+#define __NR_poll               168
+#define __NR_nfsservctl         169
+#define __NR_prctl              172
+#define __NR_rt_sigreturn       173
+#define __NR_rt_sigaction       174
+#define __NR_rt_sigprocmask     175
+#define __NR_rt_sigpending      176
+#define __NR_rt_sigtimedwait    177
+#define __NR_rt_sigqueueinfo    178
+#define __NR_rt_sigsuspend      179
+#define __NR_pread64            180
+#define __NR_pwrite64           181
+#define __NR_getcwd             183
+#define __NR_capget             184
+#define __NR_capset             185
+#define __NR_sigaltstack        186
+#define __NR_sendfile           187
+#define __NR_getpmsg           188
+#define __NR_putpmsg           189
+#define __NR_vfork             190
+#define __NR_pivot_root         217
+#define __NR_mincore            218
+#define __NR_madvise            219
+#define __NR_getdents64                220
+#define __NR_readahead         222
+#define __NR_setxattr          224
+#define __NR_lsetxattr         225
+#define __NR_fsetxattr         226
+#define __NR_getxattr          227
+#define __NR_lgetxattr         228
+#define __NR_fgetxattr         229
+#define __NR_listxattr         230
+#define __NR_llistxattr                231
+#define __NR_flistxattr                232
+#define __NR_removexattr       233
+#define __NR_lremovexattr      234
+#define __NR_fremovexattr      235
+#define __NR_gettid            236
+#define __NR_tkill             237
+#define __NR_futex             238
+#define __NR_sched_setaffinity 239
+#define __NR_sched_getaffinity 240
+#define __NR_tgkill            241
+/* Number 242 is reserved for tux */
+#define __NR_io_setup          243
+#define __NR_io_destroy                244
+#define __NR_io_getevents      245
+#define __NR_io_submit         246
+#define __NR_io_cancel         247
+#define __NR_exit_group                248
+#define __NR_epoll_create      249
+#define __NR_epoll_ctl         250
+#define __NR_epoll_wait                251
+#define __NR_set_tid_address   252
+#define __NR_fadvise64         253
+#define __NR_timer_create      254
+#define __NR_timer_settime     (__NR_timer_create+1)
+#define __NR_timer_gettime     (__NR_timer_create+2)
+#define __NR_timer_getoverrun  (__NR_timer_create+3)
+#define __NR_timer_delete      (__NR_timer_create+4)
+#define __NR_clock_settime     (__NR_timer_create+5)
+#define __NR_clock_gettime     (__NR_timer_create+6)
+#define __NR_clock_getres      (__NR_timer_create+7)
+#define __NR_clock_nanosleep   (__NR_timer_create+8)
+/* Number 263 is reserved for vserver */
+#define __NR_statfs64          265
+#define __NR_fstatfs64         266
+#define __NR_remap_file_pages  267
+/* Number 268 is reserved for new sys_mbind */
+/* Number 269 is reserved for new sys_get_mempolicy */
+/* Number 270 is reserved for new sys_set_mempolicy */
+#define __NR_mq_open           271
+#define __NR_mq_unlink         272
+#define __NR_mq_timedsend      273
+#define __NR_mq_timedreceive   274
+#define __NR_mq_notify         275
+#define __NR_mq_getsetattr     276
+#define __NR_kexec_load                277
+#define __NR_add_key           278
+#define __NR_request_key       279
+#define __NR_keyctl            280
+#define __NR_waitid            281
+#define __NR_ioprio_set                282
+#define __NR_ioprio_get                283
+#define __NR_inotify_init      284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch  286
+/* Number 287 is reserved for new sys_migrate_pages */
+#define __NR_openat            288
+#define __NR_mkdirat           289
+#define __NR_mknodat           290
+#define __NR_fchownat          291
+#define __NR_futimesat         292
+#define __NR_unlinkat          294
+#define __NR_renameat          295
+#define __NR_linkat            296
+#define __NR_symlinkat         297
+#define __NR_readlinkat                298
+#define __NR_fchmodat          299
+#define __NR_faccessat         300
+#define __NR_pselect6          301
+#define __NR_ppoll             302
+#define __NR_unshare           303
+#define __NR_set_robust_list   304
+#define __NR_get_robust_list   305
+#define __NR_splice            306
+#define __NR_sync_file_range   307
+#define __NR_tee               308
+#define __NR_vmsplice          309
+/* Number 310 is reserved for new sys_move_pages */
+#define __NR_getcpu            311
+#define __NR_epoll_pwait       312
+#define __NR_utimes            313
+#define __NR_fallocate         314
+#define __NR_utimensat         315
+#define __NR_signalfd          316
+#define __NR_timerfd           317
+#define __NR_eventfd           318
+#define __NR_timerfd_create    319
+#define __NR_timerfd_settime   320
+#define __NR_timerfd_gettime   321
+#define __NR_signalfd4         322
+#define __NR_eventfd2          323
+#define __NR_inotify_init1     324
+#define __NR_pipe2             325
+#define __NR_dup3              326
+#define __NR_epoll_create1     327
+#define        __NR_preadv             328
+#define        __NR_pwritev            329
+#define __NR_rt_tgsigqueueinfo 330
+#define __NR_perf_event_open   331
+#define __NR_fanotify_init     332
+#define __NR_fanotify_mark     333
+#define __NR_prlimit64         334
+#define __NR_name_to_handle_at 335
+#define __NR_open_by_handle_at 336
+#define __NR_clock_adjtime     337
+#define __NR_syncfs            338
+#define __NR_setns             339
+#define __NR_process_vm_readv  340
+#define __NR_process_vm_writev 341
+#define __NR_s390_runtime_instr 342
+#define __NR_kcmp              343
+#define NR_syscalls 344
+
+/* 
+ * There are some system calls that are not present on 64 bit, some
+ * have a different name although they do the same (e.g. __NR_chown32
+ * is __NR_chown on 64 bit).
+ */
+#ifndef __s390x__
+
+#define __NR_time               13
+#define __NR_lchown             16
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_getrlimit          76
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_fchown             95
+#define __NR_ioperm            101
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR__newselect        142
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_chown             182
+#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_lchown32          198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_chown32           212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_fcntl64           221
+#define __NR_sendfile64                223
+#define __NR_fadvise64_64      264
+#define __NR_fstatat64         293
+
+#else
+
+#define __NR_select            142
+#define __NR_getrlimit         191     /* SuS compliant getrlimit */
+#define __NR_lchown            198
+#define __NR_getuid            199
+#define __NR_getgid            200
+#define __NR_geteuid           201
+#define __NR_getegid           202
+#define __NR_setreuid                  203
+#define __NR_setregid                  204
+#define __NR_getgroups         205
+#define __NR_setgroups         206
+#define __NR_fchown            207
+#define __NR_setresuid         208
+#define __NR_getresuid         209
+#define __NR_setresgid         210
+#define __NR_getresgid         211
+#define __NR_chown             212
+#define __NR_setuid            213
+#define __NR_setgid            214
+#define __NR_setfsuid                  215
+#define __NR_setfsgid                  216
+#define __NR_newfstatat                293
+
+#endif
+
+#endif /* _UAPI_ASM_S390_UNISTD_H_ */
index 00d1144..1f0eee9 100644 (file)
@@ -283,14 +283,6 @@ static noinline __init void setup_facility_list(void)
              ARRAY_SIZE(S390_lowcore.stfle_fac_list));
 }
 
-static noinline __init void setup_hpage(void)
-{
-       if (!test_facility(2) || !test_facility(8))
-               return;
-       S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
-       __ctl_set_bit(0, 23);
-}
-
 static __init void detect_mvpg(void)
 {
 #ifndef CONFIG_64BIT
@@ -378,10 +370,14 @@ static __init void detect_diag44(void)
 static __init void detect_machine_facilities(void)
 {
 #ifdef CONFIG_64BIT
+       if (test_facility(8)) {
+               S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1;
+               __ctl_set_bit(0, 23);
+       }
+       if (test_facility(78))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
        if (test_facility(3))
                S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
-       if (test_facility(8))
-               S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
        if (test_facility(27))
                S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
        if (test_facility(40))
@@ -484,7 +480,6 @@ void __init startup_init(void)
        detect_diag9c();
        detect_diag44();
        detect_machine_facilities();
-       setup_hpage();
        setup_topology();
        sclp_facilities_detect();
        detect_memory_layout(memory_chunk);
index f9761f8..07d8de3 100644 (file)
@@ -295,7 +295,7 @@ sysc_sigpending:
        jno     sysc_return
        lmg     %r2,%r7,__PT_R2(%r11)   # load svc arguments
        lghi    %r8,0                   # svc 0 returns -ENOSYS
-       lh      %r1,__PT_INT_CODE+2(%r11)       # load new svc number
+       llgh    %r1,__PT_INT_CODE+2(%r11)       # load new svc number
        cghi    %r1,NR_syscalls
        jnl     sysc_nr_ok              # invalid svc number -> do svc 0
        slag    %r8,%r1,2
index 805b668..984726c 100644 (file)
@@ -52,7 +52,7 @@ __HEAD
        .long   0x02000370,0x60000050           # the channel program the PSW
        .long   0x020003c0,0x60000050           # at location 0 is loaded.
        .long   0x02000410,0x60000050           # Initial processing starts
-       .long   0x02000460,0x60000050           # at 0xf0 = iplstart.
+       .long   0x02000460,0x60000050           # at 0x200 = iplstart.
        .long   0x020004b0,0x60000050
        .long   0x02000500,0x60000050
        .long   0x02000550,0x60000050
@@ -62,11 +62,54 @@ __HEAD
        .long   0x02000690,0x60000050
        .long   0x020006e0,0x20000050
 
-       .org    0xf0
+       .org    0x200
+#
+# subroutine to set architecture mode
+#
+.Lsetmode:
+#ifdef CONFIG_64BIT
+       mvi     __LC_AR_MODE_ID,1       # set esame flag
+       slr     %r0,%r0                 # set cpuid to zero
+       lhi     %r1,2                   # mode 2 = esame (dump)
+       sigp    %r1,%r0,0x12            # switch to esame mode
+       bras    %r13,0f
+       .fill   16,4,0x0
+0:     lmh     %r0,%r15,0(%r13)        # clear high-order half of gprs
+       sam31                           # switch to 31 bit addressing mode
+#else
+       mvi     __LC_AR_MODE_ID,0       # set ESA flag (mode 0)
+#endif
+       br      %r14
+
+#
+# subroutine to wait for end I/O
+#
+.Lirqwait:
+#ifdef CONFIG_64BIT
+       mvc     0x1f0(16),.Lnewpsw      # set up IO interrupt psw
+       lpsw    .Lwaitpsw
+.Lioint:
+       br      %r14
+       .align  8
+.Lnewpsw:
+       .quad   0x0000000080000000,.Lioint
+#else
+       mvc     0x78(8),.Lnewpsw        # set up IO interrupt psw
+       lpsw    .Lwaitpsw
+.Lioint:
+       br      %r14
+       .align  8
+.Lnewpsw:
+       .long   0x00080000,0x80000000+.Lioint
+#endif
+.Lwaitpsw:
+       .long   0x020a0000,0x80000000+.Lioint
+
 #
 # subroutine for loading cards from the reader
 #
 .Lloader:
+       la      %r4,0(%r14)
        la      %r3,.Lorb               # r2 = address of orb into r2
        la      %r5,.Lirb               # r4 = address of irb
        la      %r6,.Lccws
@@ -83,9 +126,7 @@ __HEAD
        ssch    0(%r3)                  # load chunk of 1600 bytes
        bnz     .Llderr
 .Lwait4irq:
-       mvc     0x78(8),.Lnewpsw        # set up IO interrupt psw
-       lpsw    .Lwaitpsw
-.Lioint:
+       bas     %r14,.Lirqwait
        c       %r1,0xb8                # compare subchannel number
        bne     .Lwait4irq
        tsch    0(%r5)
@@ -104,7 +145,7 @@ __HEAD
        sr      %r0,%r3                 # #ccws*80-residual=#bytes read
        ar      %r2,%r0
 
-       br      %r14                    # r2 contains the total size
+       br      %r                    # r2 contains the total size
 
 .Lcont:
        ahi     %r2,0x640               # add 0x640 to total size
@@ -128,10 +169,6 @@ __HEAD
 .Lloadp:.long  0,0
        .align  8
 .Lcrash:.long  0x000a0000,0x00000000
-.Lnewpsw:
-       .long   0x00080000,0x80000000+.Lioint
-.Lwaitpsw:
-       .long   0x020a0000,0x80000000+.Lioint
 
        .align  8
 .Lccws: .rept  19
@@ -140,6 +177,7 @@ __HEAD
        .long   0x02200050,0x00000000
 
 iplstart:
+       bas     %r14,.Lsetmode          # Immediately switch to 64 bit mode
        lh      %r1,0xb8                # test if subchannel number
        bct     %r1,.Lnoload            #  is valid
        l       %r1,0xb8                # load ipl subchannel number
@@ -209,8 +247,8 @@ iplstart:
 #
 # reset files in VM reader
 #
-       stidp   __LC_SAVE_AREA_SYNC     # store cpuid
-       tm      __LC_SAVE_AREA_SYNC,0xff# running VM ?
+       stidp   .Lcpuid                 # store cpuid
+       tm      .Lcpuid,0xff            # running VM ?
        bno     .Lnoreset
        la      %r2,.Lreset
        lhi     %r3,26
@@ -222,23 +260,14 @@ iplstart:
        tm      31(%r5),0xff            # bits is set in the schib
        bz      .Lnoreset
 .Lwaitforirq:
-       mvc     0x78(8),.Lrdrnewpsw     # set up IO interrupt psw
-.Lwaitrdrirq:
-       lpsw    .Lrdrwaitpsw
-.Lrdrint:
+       bas     %r14,.Lirqwait          # wait for IO interrupt
        c       %r1,0xb8                # compare subchannel number
-       bne     .Lwaitrdrirq
+       bne     .Lwaitforirq
        la      %r5,.Lirb
        tsch    0(%r5)
 .Lnoreset:
        b       .Lnoload
 
-       .align  8
-.Lrdrnewpsw:
-       .long   0x00080000,0x80000000+.Lrdrint
-.Lrdrwaitpsw:
-       .long   0x020a0000,0x80000000+.Lrdrint
-
 #
 # everything loaded, go for it
 #
@@ -254,6 +283,8 @@ iplstart:
        .byte   0xc8,0xd6,0xd3,0xc4     # "change rdr all keep nohold"
 .L_eof: .long  0xc5d6c600       /* C'EOF' */
 .L_hdr: .long  0xc8c4d900       /* C'HDR' */
+       .align  8
+.Lcpuid:.fill  8,1,0
 
 #
 # SALIPL loader support. Based on a patch by Rob van der Heij.
@@ -263,6 +294,7 @@ iplstart:
        .org    0x800
 ENTRY(start)
        stm     %r0,%r15,0x07b0         # store registers
+       bas     %r14,.Lsetmode          # Immediately switch to 64 bit mode
        basr    %r12,%r0
 .base:
        l       %r11,.parm
@@ -343,6 +375,18 @@ ENTRY(startup)
 ENTRY(startup_kdump)
        j       .Lep_startup_kdump
 .Lep_startup_normal:
+#ifdef CONFIG_64BIT
+       mvi     __LC_AR_MODE_ID,1       # set esame flag
+       slr     %r0,%r0                 # set cpuid to zero
+       lhi     %r1,2                   # mode 2 = esame (dump)
+       sigp    %r1,%r0,0x12            # switch to esame mode
+       bras    %r13,0f
+       .fill   16,4,0x0
+0:     lmh     %r0,%r15,0(%r13)        # clear high-order half of gprs
+       sam31                           # switch to 31 bit addressing mode
+#else
+       mvi     __LC_AR_MODE_ID,0       # set ESA flag (mode 0)
+#endif
        basr    %r13,0                  # get base
 .LPG0:
        xc      0x200(256),0x200        # partially clear lowcore
@@ -410,22 +454,17 @@ ENTRY(startup_kdump)
 #endif
 
 #ifdef CONFIG_64BIT
-       mvi     __LC_AR_MODE_ID,1       # set esame flag
-       slr     %r0,%r0                 # set cpuid to zero
-       lhi     %r1,2                   # mode 2 = esame (dump)
-       sigp    %r1,%r0,0x12            # switch to esame mode
+       /* Continue with 64bit startup code in head64.S */
        sam64                           # switch to 64 bit mode
-       larl    %r13,4f
-       lmh     %r0,%r15,0(%r13)        # clear high-order half
        jg      startup_continue
-4:     .fill   16,4,0x0
 #else
-       mvi     __LC_AR_MODE_ID,0       # set ESA flag (mode 0)
+       /* Continue with 31bit startup code in head31.S */
        l       %r13,4f-.LPG0(%r13)
        b       0(%r13)
        .align  8
 4:     .long   startup_continue
 #endif
+
        .align  8
 5:     .long   0x7fffffff,0xffffffff
 
index a1372ae..9a99856 100644 (file)
@@ -78,10 +78,7 @@ ENTRY(startup_continue)
 
 ENTRY(_ehead)
 
-#ifdef CONFIG_SHARED_KERNEL
        .org    0x100000 - 0x11000      # head.o ends at 0x11000
-#endif
-
 #
 # startup-code, running in absolute addressing mode
 #
index c108af2..b9e25ae 100644 (file)
@@ -76,10 +76,7 @@ ENTRY(startup_continue)
 
 ENTRY(_ehead)
 
-#ifdef CONFIG_SHARED_KERNEL
        .org    0x100000 - 0x11000      # head.o ends at 0x11000
-#endif
-
 #
 # startup-code, running in absolute addressing mode
 #
index 46412b1..4610dea 100644 (file)
 #define PLT_ENTRY_SIZE 20
 #endif /* CONFIG_64BIT */
 
+#ifdef CONFIG_64BIT
+void *module_alloc(unsigned long size)
+{
+       if (PAGE_ALIGN(size) > MODULES_LEN)
+               return NULL;
+       return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+                                   GFP_KERNEL, PAGE_KERNEL, -1,
+                                   __builtin_return_address(0));
+}
+#endif
+
 /* Free memory returned from module_alloc */
 void module_free(struct module *mod, void *module_region)
 {
index afa9fdb..b1f2be9 100644 (file)
@@ -105,6 +105,11 @@ EXPORT_SYMBOL(VMALLOC_END);
 struct page *vmemmap;
 EXPORT_SYMBOL(vmemmap);
 
+#ifdef CONFIG_64BIT
+unsigned long MODULES_VADDR;
+unsigned long MODULES_END;
+#endif
+
 /* An array with a pointer to the lowcore of every CPU. */
 struct _lowcore *lowcore_ptr[NR_CPUS];
 EXPORT_SYMBOL(lowcore_ptr);
@@ -544,19 +549,23 @@ static void __init setup_memory_end(void)
 
        /* Choose kernel address space layout: 2, 3, or 4 levels. */
 #ifdef CONFIG_64BIT
-       vmalloc_size = VMALLOC_END ?: 128UL << 30;
+       vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN;
        tmp = (memory_end ?: real_memory_size) / PAGE_SIZE;
        tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;
        if (tmp <= (1UL << 42))
                vmax = 1UL << 42;       /* 3-level kernel page table */
        else
                vmax = 1UL << 53;       /* 4-level kernel page table */
+       /* module area is at the end of the kernel address space. */
+       MODULES_END = vmax;
+       MODULES_VADDR = MODULES_END - MODULES_LEN;
+       VMALLOC_END = MODULES_VADDR;
 #else
        vmalloc_size = VMALLOC_END ?: 96UL << 20;
        vmax = 1UL << 31;               /* 2-level kernel page table */
-#endif
        /* vmalloc area is at the end of the kernel address space. */
        VMALLOC_END = vmax;
+#endif
        VMALLOC_START = vmax - vmalloc_size;
 
        /* Split remaining virtual space between 1:1 mapping & vmemmap array */
@@ -768,6 +777,40 @@ static void __init reserve_crashkernel(void)
 #endif
 }
 
+static void __init init_storage_keys(unsigned long start, unsigned long end)
+{
+       unsigned long boundary, function, size;
+
+       while (start < end) {
+               if (MACHINE_HAS_EDAT2) {
+                       /* set storage keys for a 2GB frame */
+                       function = 0x22000 | PAGE_DEFAULT_KEY;
+                       size = 1UL << 31;
+                       boundary = (start + size) & ~(size - 1);
+                       if (boundary <= end) {
+                               do {
+                                       start = pfmf(function, start);
+                               } while (start < boundary);
+                               continue;
+                       }
+               }
+               if (MACHINE_HAS_EDAT1) {
+                       /* set storage keys for a 1MB frame */
+                       function = 0x21000 | PAGE_DEFAULT_KEY;
+                       size = 1UL << 20;
+                       boundary = (start + size) & ~(size - 1);
+                       if (boundary <= end) {
+                               do {
+                                       start = pfmf(function, start);
+                               } while (start < boundary);
+                               continue;
+                       }
+               }
+               page_set_storage_key(start, PAGE_DEFAULT_KEY, 0);
+               start += PAGE_SIZE;
+       }
+}
+
 static void __init setup_memory(void)
 {
         unsigned long bootmap_size;
@@ -846,9 +889,7 @@ static void __init setup_memory(void)
                memblock_add_node(PFN_PHYS(start_chunk),
                                  PFN_PHYS(end_chunk - start_chunk), 0);
                pfn = max(start_chunk, start_pfn);
-               for (; pfn < end_chunk; pfn++)
-                       page_set_storage_key(PFN_PHYS(pfn),
-                                            PAGE_DEFAULT_KEY, 0);
+               init_storage_keys(PFN_PHYS(pfn), PFN_PHYS(end_chunk));
        }
 
        psw_set_key(PAGE_DEFAULT_KEY);
index 0f5536b..1bea6d1 100644 (file)
@@ -7,3 +7,4 @@ obj-y    := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o
+obj-$(CONFIG_S390_PTDUMP) += dump_pagetables.o
diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c
new file mode 100644 (file)
index 0000000..cbc6668
--- /dev/null
@@ -0,0 +1,226 @@
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/sections.h>
+#include <asm/pgtable.h>
+
+static unsigned long max_addr;
+
+struct addr_marker {
+       unsigned long start_address;
+       const char *name;
+};
+
+enum address_markers_idx {
+       IDENTITY_NR = 0,
+       KERNEL_START_NR,
+       KERNEL_END_NR,
+       VMEMMAP_NR,
+       VMALLOC_NR,
+#ifdef CONFIG_64BIT
+       MODULES_NR,
+#endif
+};
+
+static struct addr_marker address_markers[] = {
+       [IDENTITY_NR]     = {0, "Identity Mapping"},
+       [KERNEL_START_NR] = {(unsigned long)&_stext, "Kernel Image Start"},
+       [KERNEL_END_NR]   = {(unsigned long)&_end, "Kernel Image End"},
+       [VMEMMAP_NR]      = {0, "vmemmap Area"},
+       [VMALLOC_NR]      = {0, "vmalloc Area"},
+#ifdef CONFIG_64BIT
+       [MODULES_NR]      = {0, "Modules Area"},
+#endif
+       { -1, NULL }
+};
+
+struct pg_state {
+       int level;
+       unsigned int current_prot;
+       unsigned long start_address;
+       unsigned long current_address;
+       const struct addr_marker *marker;
+};
+
+static void print_prot(struct seq_file *m, unsigned int pr, int level)
+{
+       static const char * const level_name[] =
+               { "ASCE", "PGD", "PUD", "PMD", "PTE" };
+
+       seq_printf(m, "%s ", level_name[level]);
+       if (pr & _PAGE_INVALID)
+               seq_printf(m, "I\n");
+       else
+               seq_printf(m, "%s\n", pr & _PAGE_RO ? "RO" : "RW");
+}
+
+static void note_page(struct seq_file *m, struct pg_state *st,
+                    unsigned int new_prot, int level)
+{
+       static const char units[] = "KMGTPE";
+       int width = sizeof(unsigned long) * 2;
+       const char *unit = units;
+       unsigned int prot, cur;
+       unsigned long delta;
+
+       /*
+        * If we have a "break" in the series, we need to flush the state
+        * that we have now. "break" is either changing perms, levels or
+        * address space marker.
+        */
+       prot = new_prot;
+       cur = st->current_prot;
+
+       if (!st->level) {
+               /* First entry */
+               st->current_prot = new_prot;
+               st->level = level;
+               st->marker = address_markers;
+               seq_printf(m, "---[ %s ]---\n", st->marker->name);
+       } else if (prot != cur || level != st->level ||
+                  st->current_address >= st->marker[1].start_address) {
+               /* Print the actual finished series */
+               seq_printf(m, "0x%0*lx-0x%0*lx",
+                          width, st->start_address,
+                          width, st->current_address);
+               delta = (st->current_address - st->start_address) >> 10;
+               while (!(delta & 0x3ff) && unit[1]) {
+                       delta >>= 10;
+                       unit++;
+               }
+               seq_printf(m, "%9lu%c ", delta, *unit);
+               print_prot(m, st->current_prot, st->level);
+               if (st->current_address >= st->marker[1].start_address) {
+                       st->marker++;
+                       seq_printf(m, "---[ %s ]---\n", st->marker->name);
+               }
+               st->start_address = st->current_address;
+               st->current_prot = new_prot;
+               st->level = level;
+       }
+}
+
+/*
+ * The actual page table walker functions. In order to keep the implementation
+ * of print_prot() short, we only check and pass _PAGE_INVALID and _PAGE_RO
+ * flags to note_page() if a region, segment or page table entry is invalid or
+ * read-only.
+ * After all it's just a hint that the current level being walked contains an
+ * invalid or read-only entry.
+ */
+static void walk_pte_level(struct seq_file *m, struct pg_state *st,
+                          pmd_t *pmd, unsigned long addr)
+{
+       unsigned int prot;
+       pte_t *pte;
+       int i;
+
+       for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) {
+               st->current_address = addr;
+               pte = pte_offset_kernel(pmd, addr);
+               prot = pte_val(*pte) & (_PAGE_RO | _PAGE_INVALID);
+               note_page(m, st, prot, 4);
+               addr += PAGE_SIZE;
+       }
+}
+
+static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
+                          pud_t *pud, unsigned long addr)
+{
+       unsigned int prot;
+       pmd_t *pmd;
+       int i;
+
+       for (i = 0; i < PTRS_PER_PMD && addr < max_addr; i++) {
+               st->current_address = addr;
+               pmd = pmd_offset(pud, addr);
+               if (!pmd_none(*pmd)) {
+                       if (pmd_large(*pmd)) {
+                               prot = pmd_val(*pmd) & _SEGMENT_ENTRY_RO;
+                               note_page(m, st, prot, 3);
+                       } else
+                               walk_pte_level(m, st, pmd, addr);
+               } else
+                       note_page(m, st, _PAGE_INVALID, 3);
+               addr += PMD_SIZE;
+       }
+}
+
+static void walk_pud_level(struct seq_file *m, struct pg_state *st,
+                          pgd_t *pgd, unsigned long addr)
+{
+       pud_t *pud;
+       int i;
+
+       for (i = 0; i < PTRS_PER_PUD && addr < max_addr; i++) {
+               st->current_address = addr;
+               pud = pud_offset(pgd, addr);
+               if (!pud_none(*pud))
+                       walk_pmd_level(m, st, pud, addr);
+               else
+                       note_page(m, st, _PAGE_INVALID, 2);
+               addr += PUD_SIZE;
+       }
+}
+
+static void walk_pgd_level(struct seq_file *m)
+{
+       unsigned long addr = 0;
+       struct pg_state st;
+       pgd_t *pgd;
+       int i;
+
+       memset(&st, 0, sizeof(st));
+       for (i = 0; i < PTRS_PER_PGD && addr < max_addr; i++) {
+               st.current_address = addr;
+               pgd = pgd_offset_k(addr);
+               if (!pgd_none(*pgd))
+                       walk_pud_level(m, &st, pgd, addr);
+               else
+                       note_page(m, &st, _PAGE_INVALID, 1);
+               addr += PGDIR_SIZE;
+       }
+       /* Flush out the last page */
+       st.current_address = max_addr;
+       note_page(m, &st, 0, 0);
+}
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+       walk_pgd_level(m);
+       return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, ptdump_show, NULL);
+}
+
+static const struct file_operations ptdump_fops = {
+       .open           = ptdump_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int pt_dump_init(void)
+{
+       /*
+        * Figure out the maximum virtual address being accessible with the
+        * kernel ASCE. We need this to keep the page table walker functions
+        * from accessing non-existent entries.
+        */
+#ifdef CONFIG_32BIT
+       max_addr = 1UL << 31;
+#else
+       max_addr = (S390_lowcore.kernel_asce & _REGION_ENTRY_TYPE_MASK) >> 2;
+       max_addr = 1UL << (max_addr * 11 + 31);
+       address_markers[MODULES_NR].start_address = MODULES_VADDR;
+#endif
+       address_markers[VMEMMAP_NR].start_address = (unsigned long) vmemmap;
+       address_markers[VMALLOC_NR].start_address = VMALLOC_START;
+       debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops);
+       return 0;
+}
+device_initcall(pt_dump_init);
index b36537a..00be01c 100644 (file)
@@ -8,25 +8,38 @@
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 
+static pte_t *walk_page_table(unsigned long addr)
+{
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       pgdp = pgd_offset_k(addr);
+       if (pgd_none(*pgdp))
+               return NULL;
+       pudp = pud_offset(pgdp, addr);
+       if (pud_none(*pudp))
+               return NULL;
+       pmdp = pmd_offset(pudp, addr);
+       if (pmd_none(*pmdp) || pmd_large(*pmdp))
+               return NULL;
+       ptep = pte_offset_kernel(pmdp, addr);
+       if (pte_none(*ptep))
+               return NULL;
+       return ptep;
+}
+
 static void change_page_attr(unsigned long addr, int numpages,
                             pte_t (*set) (pte_t))
 {
        pte_t *ptep, pte;
-       pmd_t *pmdp;
-       pud_t *pudp;
-       pgd_t *pgdp;
        int i;
 
        for (i = 0; i < numpages; i++) {
-               pgdp = pgd_offset(&init_mm, addr);
-               pudp = pud_offset(pgdp, addr);
-               pmdp = pmd_offset(pudp, addr);
-               if (pmd_huge(*pmdp)) {
-                       WARN_ON_ONCE(1);
-                       continue;
-               }
-               ptep = pte_offset_kernel(pmdp, addr);
-
+               ptep = walk_page_table(addr);
+               if (WARN_ON_ONCE(!ptep))
+                       break;
                pte = *ptep;
                pte = set(pte);
                __ptep_ipte(addr, ptep);
@@ -40,21 +53,18 @@ int set_memory_ro(unsigned long addr, int numpages)
        change_page_attr(addr, numpages, pte_wrprotect);
        return 0;
 }
-EXPORT_SYMBOL_GPL(set_memory_ro);
 
 int set_memory_rw(unsigned long addr, int numpages)
 {
        change_page_attr(addr, numpages, pte_mkwrite);
        return 0;
 }
-EXPORT_SYMBOL_GPL(set_memory_rw);
 
 /* not possible */
 int set_memory_nx(unsigned long addr, int numpages)
 {
        return 0;
 }
-EXPORT_SYMBOL_GPL(set_memory_nx);
 
 int set_memory_x(unsigned long addr, int numpages)
 {
index c22abf9..387c7c6 100644 (file)
@@ -79,7 +79,8 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address)
  */
 static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
 {
-       unsigned long address;
+       unsigned long end = start + size;
+       unsigned long address = start;
        pgd_t *pg_dir;
        pud_t *pu_dir;
        pmd_t *pm_dir;
@@ -87,7 +88,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
        pte_t  pte;
        int ret = -ENOMEM;
 
-       for (address = start; address < start + size; address += PAGE_SIZE) {
+       while (address < end) {
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
                        pu_dir = vmem_pud_alloc();
@@ -108,12 +109,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                pm_dir = pmd_offset(pu_dir, address);
 
 #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
-               if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
-                   (address + HPAGE_SIZE <= start + size) &&
-                   (address >= HPAGE_SIZE)) {
+               if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
+                   !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
                        pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
                        pmd_val(*pm_dir) = pte_val(pte);
-                       address += HPAGE_SIZE - PAGE_SIZE;
+                       address += PMD_SIZE;
                        continue;
                }
 #endif
@@ -126,10 +126,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
 
                pt_dir = pte_offset_kernel(pm_dir, address);
                *pt_dir = pte;
+               address += PAGE_SIZE;
        }
        ret = 0;
 out:
-       flush_tlb_kernel_range(start, start + size);
+       flush_tlb_kernel_range(start, end);
        return ret;
 }
 
@@ -139,7 +140,8 @@ out:
  */
 static void vmem_remove_range(unsigned long start, unsigned long size)
 {
-       unsigned long address;
+       unsigned long end = start + size;
+       unsigned long address = start;
        pgd_t *pg_dir;
        pud_t *pu_dir;
        pmd_t *pm_dir;
@@ -147,25 +149,32 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
        pte_t  pte;
 
        pte_val(pte) = _PAGE_TYPE_EMPTY;
-       for (address = start; address < start + size; address += PAGE_SIZE) {
+       while (address < end) {
                pg_dir = pgd_offset_k(address);
+               if (pgd_none(*pg_dir)) {
+                       address += PGDIR_SIZE;
+                       continue;
+               }
                pu_dir = pud_offset(pg_dir, address);
-               if (pud_none(*pu_dir))
+               if (pud_none(*pu_dir)) {
+                       address += PUD_SIZE;
                        continue;
+               }
                pm_dir = pmd_offset(pu_dir, address);
-               if (pmd_none(*pm_dir))
+               if (pmd_none(*pm_dir)) {
+                       address += PMD_SIZE;
                        continue;
-
-               if (pmd_huge(*pm_dir)) {
+               }
+               if (pmd_large(*pm_dir)) {
                        pmd_clear(pm_dir);
-                       address += HPAGE_SIZE - PAGE_SIZE;
+                       address += PMD_SIZE;
                        continue;
                }
-
                pt_dir = pte_offset_kernel(pm_dir, address);
                *pt_dir = pte;
+               address += PAGE_SIZE;
        }
-       flush_tlb_kernel_range(start, start + size);
+       flush_tlb_kernel_range(start, end);
 }
 
 /*
@@ -330,8 +339,8 @@ void __init vmem_map_init(void)
        unsigned long start, end;
        int i;
 
-       ro_start = ((unsigned long)&_stext) & PAGE_MASK;
-       ro_end = PFN_ALIGN((unsigned long)&_eshared);
+       ro_start = PFN_ALIGN((unsigned long)&_stext);
+       ro_end = (unsigned long)&_eshared & PAGE_MASK;
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
                if (memory_chunk[i].type == CHUNK_CRASHK ||
                    memory_chunk[i].type == CHUNK_OLDMEM)
index 1e638e7..35ee2bf 100644 (file)
@@ -21,9 +21,6 @@ config UNICORE32
          designs licensed by PKUnity Ltd.
          Please see web page at <http://www.pkunity.com/>.
 
-config HAVE_PWM
-       bool
-
 config GENERIC_GPIO
        def_bool y
 
@@ -106,7 +103,8 @@ config PUV3_DB0913
 
 config PUV3_NB0916
        bool "NetBook board (0916)"
-       select HAVE_PWM
+       select PWM
+       select PWM_PUV3
 
 config PUV3_SMW0919
        bool "Security Mini-Workstation board (0919)"
@@ -220,12 +218,6 @@ config PUV3_GPIO
        select GPIO_SYSFS if EXPERIMENTAL
        default y
 
-config PUV3_PWM
-       tristate
-       default BACKLIGHT_PWM
-       help
-         Enable support for NB0916 PWM controllers
-
 if PUV3_NB0916
 
 menu "PKUnity NetBook-0916 Features"
index 7b91fe6..4a85fb4 100644 (file)
  * Interrupt Enable Reg OST_OIER
  */
 #define OST_OIER       (PKUNITY_OST_BASE + 0x001C)
+
 /*
- * PWM Pulse Width Control Reg OST_PWMPWCR
- */
-#define OST_PWMPWCR    (PKUNITY_OST_BASE + 0x0080)
-/*
- * PWM Duty Cycle Control Reg OST_PWMDCCR
- */
-#define OST_PWMDCCR    (PKUNITY_OST_BASE + 0x0084)
-/*
- * PWM Period Control Reg OST_PWMPCR
+ * PWM Registers: IO base address: PKUNITY_OST_BASE + 0x80
+ *      PWCR: Pulse Width Control Reg
+ *      DCCR: Duty Cycle Control Reg
+ *      PCR: Period Control Reg
  */
-#define OST_PWMPCR     (PKUNITY_OST_BASE + 0x0088)
+#define OST_PWM_PWCR   (0x00)
+#define OST_PWM_DCCR   (0x04)
+#define OST_PWM_PCR    (0x08)
 
 /*
  * Match detected 0 OST_OSSR_M0
index 3240101..fa497e0 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
 obj-$(CONFIG_ARCH_PUV3)                += clock.o irq.o time.o
 
 obj-$(CONFIG_PUV3_GPIO)                += gpio.o
-obj-$(CONFIG_PUV3_PWM)         += pwm.o
 obj-$(CONFIG_PUV3_PM)          += pm.o sleep.o
 obj-$(CONFIG_HIBERNATION)      += hibernate.o hibernate_asm.o
 
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
deleted file mode 100644 (file)
index 4615d51..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * linux/arch/unicore32/kernel/pwm.c
- *
- * Code specific to PKUnity SoC and UniCore ISA
- *
- *     Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
- *     Copyright (C) 2001-2010 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-#include <mach/hardware.h>
-
-struct pwm_device {
-       struct list_head        node;
-       struct platform_device *pdev;
-
-       const char      *label;
-       struct clk      *clk;
-       int             clk_enabled;
-
-       unsigned int    use_count;
-       unsigned int    pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long long c;
-       unsigned long period_cycles, prescale, pv, dc;
-
-       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       c = clk_get_rate(pwm->clk);
-       c = c * period_ns;
-       do_div(c, 1000000000);
-       period_cycles = c;
-
-       if (period_cycles < 1)
-               period_cycles = 1;
-       prescale = (period_cycles - 1) / 1024;
-       pv = period_cycles / (prescale + 1) - 1;
-
-       if (prescale > 63)
-               return -EINVAL;
-
-       if (duty_ns == period_ns)
-               dc = OST_PWMDCCR_FDCYCLE;
-       else
-               dc = (pv + 1) * duty_ns / period_ns;
-
-       /* NOTE: the clock to PWM has to be enabled first
-        * before writing to the registers
-        */
-       clk_enable(pwm->clk);
-       OST_PWMPWCR = prescale;
-       OST_PWMDCCR = pv - dc;
-       OST_PWMPCR  = pv;
-       clk_disable(pwm->clk);
-
-       return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       int rc = 0;
-
-       if (!pwm->clk_enabled) {
-               rc = clk_enable(pwm->clk);
-               if (!rc)
-                       pwm->clk_enabled = 1;
-       }
-       return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       if (pwm->clk_enabled) {
-               clk_disable(pwm->clk);
-               pwm->clk_enabled = 0;
-       }
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count++;
-                       pwm->label = label;
-               } else
-                       pwm = ERR_PTR(-EBUSY);
-       } else
-               pwm = ERR_PTR(-ENOENT);
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else
-               pr_warning("PWM device already freed\n");
-
-       mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->node, &pwm_list);
-       mutex_unlock(&pwm_lock);
-}
-
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
-               unsigned int pwm_id, struct pwm_device *parent_pwm)
-{
-       struct pwm_device *pwm;
-       struct resource *r;
-       int ret = 0;
-
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       pwm->clk = clk_get(NULL, "OST_CLK");
-       if (IS_ERR(pwm->clk)) {
-               ret = PTR_ERR(pwm->clk);
-               goto err_free;
-       }
-       pwm->clk_enabled = 0;
-
-       pwm->use_count = 0;
-       pwm->pwm_id = pwm_id;
-       pwm->pdev = pdev;
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free_clk;
-       }
-
-       __add_pwm(pwm);
-       platform_set_drvdata(pdev, pwm);
-       return pwm;
-
-err_free_clk:
-       clk_put(pwm->clk);
-err_free:
-       kfree(pwm);
-       return ERR_PTR(ret);
-}
-
-static int __devinit puv3_pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       return 0;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-       struct pwm_device *pwm;
-       struct resource *r;
-
-       pwm = platform_get_drvdata(pdev);
-       if (pwm == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pwm_lock);
-       list_del(&pwm->node);
-       mutex_unlock(&pwm_lock);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
-       clk_put(pwm->clk);
-       kfree(pwm);
-       return 0;
-}
-
-static struct platform_driver puv3_pwm_driver = {
-       .driver         = {
-               .name   = "PKUnity-v3-PWM",
-       },
-       .probe          = puv3_pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-};
-
-static int __init pwm_init(void)
-{
-       int ret = 0;
-
-       ret = platform_driver_register(&puv3_pwm_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register puv3_pwm_driver\n");
-               return ret;
-       }
-
-       return ret;
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&puv3_pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
index a1ea034..db7c549 100644 (file)
@@ -101,23 +101,6 @@ nouveau_parent_create_(struct nouveau_object *parent,
        return 0;
 }
 
-int
-_nouveau_parent_ctor(struct nouveau_object *parent,
-                    struct nouveau_object *engine,
-                    struct nouveau_oclass *oclass, void *data, u32 size,
-                    struct nouveau_object **pobject)
-{
-       struct nouveau_parent *object;
-       int ret;
-
-       ret = nouveau_parent_create(parent, engine, oclass, 0, NULL, 0, &object);
-       *pobject = nv_object(object);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 void
 nouveau_parent_destroy(struct nouveau_parent *parent)
 {
index d3aa251..3c2e940 100644 (file)
@@ -50,9 +50,6 @@ int  nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
                            int size, void **);
 void nouveau_parent_destroy(struct nouveau_parent *);
 
-int  _nouveau_parent_ctor(struct nouveau_object *, struct nouveau_object *,
-                         struct nouveau_oclass *, void *, u32,
-                         struct nouveau_object **);
 void _nouveau_parent_dtor(struct nouveau_object *);
 #define _nouveau_parent_init _nouveau_object_init
 #define _nouveau_parent_fini _nouveau_object_fini
index 49bff90..c24ec8a 100644 (file)
@@ -26,7 +26,7 @@ void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
 struct nouveau_timer {
        struct nouveau_subdev base;
        u64  (*read)(struct nouveau_timer *);
-       void (*alarm)(struct nouveau_timer *, u32 time, struct nouveau_alarm *);
+       void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
 };
 
 static inline struct nouveau_timer *
index 2fbb6df..dcb5c2b 100644 (file)
@@ -185,23 +185,22 @@ static void
 nouveau_bios_shadow_acpi(struct nouveau_bios *bios)
 {
        struct pci_dev *pdev = nv_device(bios)->pdev;
-       int cnt = 65536 / 4096;
-       int ret;
+       int ret, cnt, i;
+       u8  data[3];
 
        if (!nouveau_acpi_rom_supported(pdev))
                return;
 
-       bios->data = kmalloc(65536, GFP_KERNEL);
        bios->size = 0;
-       if (!bios->data)
-               return;
-
-       while (cnt--) {
-               ret = nouveau_acpi_get_bios_chunk(bios->data, bios->size, 4096);
-               if (ret != 4096)
-                       return;
+       if (nouveau_acpi_get_bios_chunk(data, 0, 3) == 3)
+               bios->size = data[2] * 512;
 
-               bios->size += 4096;
+       bios->data = kmalloc(bios->size, GFP_KERNEL);
+       for (i = 0; bios->data && i < bios->size; i += cnt) {
+               cnt = min((bios->size - i), (u32)4096);
+               ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
+               if (ret != cnt)
+                       break;
        }
 }
 
index fd181fb..f4147f6 100644 (file)
@@ -90,6 +90,7 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        priv->base.pll_set = nv50_clock_pll_set;
+       priv->base.pll_calc = nv04_clock_pll_calc;
        return 0;
 }
 
index f87a7a3..9360ddd 100644 (file)
@@ -92,7 +92,7 @@ nv50_fan_pwm_clock(struct nouveau_therm *therm)
                if (nv_rd32(therm, 0xc040) & 0x800000) {
                        /* Use the HOST clock (100 MHz)
                        * Where does this constant(2.4) comes from? */
-                       pwm_clock = (100000000 >> pwm_div) / 10 / 24;
+                       pwm_clock = (100000000 >> pwm_div) * 10 / 24;
                } else {
                        /* Where does this constant(20) comes from? */
                        pwm_clock = (crystal * 1000) >> pwm_div;
index 49976be..c26ca9b 100644 (file)
@@ -85,7 +85,7 @@ nv04_timer_alarm_trigger(struct nouveau_timer *ptimer)
 }
 
 static void
-nv04_timer_alarm(struct nouveau_timer *ptimer, u32 time,
+nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
                 struct nouveau_alarm *alarm)
 {
        struct nv04_timer_priv *priv = (void *)ptimer;
index 9e1449f..cf23c46 100644 (file)
@@ -3564,16 +3564,6 @@ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd)
        return srpt_get_cmd_state(ioctx);
 }
 
-static u16 srpt_set_fabric_sense_len(struct se_cmd *cmd, u32 sense_length)
-{
-       return 0;
-}
-
-static u16 srpt_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
 /**
  * srpt_parse_i_port_id() - Parse an initiator port ID.
  * @name: ASCII representation of a 128-bit initiator port ID.
@@ -3953,8 +3943,6 @@ static struct target_core_fabric_ops srpt_template = {
        .queue_data_in                  = srpt_queue_response,
        .queue_status                   = srpt_queue_status,
        .queue_tm_rsp                   = srpt_queue_response,
-       .get_fabric_sense_len           = srpt_get_fabric_sense_len,
-       .set_fabric_sense_len           = srpt_set_fabric_sense_len,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
index 16578d3..f508def 100644 (file)
@@ -63,6 +63,17 @@ config LEDS_LM3533
          hardware-accelerated blinking with maximum on and off periods of 9.8
          and 77 seconds respectively.
 
+config LEDS_LM3642
+       tristate "LED support for LM3642 Chip"
+       depends on LEDS_CLASS && I2C
+       select REGMAP_I2C
+       help
+         This option enables support for LEDs connected to LM3642.
+         The LM3642 is a 4MHz fixed-frequency synchronous boost
+         converter plus 1.5A constant current driver for a high-current
+         white LED.
+
+
 config LEDS_LOCOMO
        tristate "LED Support for Locomo device"
        depends on LEDS_CLASS
@@ -192,11 +203,12 @@ config LEDS_LP5521
          programming the engines.
 
 config LEDS_LP5523
-       tristate "LED Support for N.S. LP5523 LED driver chip"
+       tristate "LED Support for TI/National LP5523/55231 LED driver chip"
        depends on LEDS_CLASS && I2C
        help
-         If you say yes here you get support for the National Semiconductor
-         LP5523 LED driver. It is 9 channel chip with programmable engines.
+         If you say yes here you get support for TI/National Semiconductor
+         LP5523/55231 LED driver.
+         It is 9 channel chip with programmable engines.
          Driver provides direct control via LED class and interface for
          programming the engines.
 
@@ -422,13 +434,13 @@ config LEDS_MAX8997
          This option enables support for on-chip LED drivers on
          MAXIM MAX8997 PMIC.
 
-config LEDS_LM3556
-       tristate "LED support for LM3556 Chip"
+config LEDS_LM355x
+       tristate "LED support for LM355x Chips, LM3554 and LM3556"
        depends on LEDS_CLASS && I2C
        select REGMAP_I2C
        help
-         This option enables support for LEDs connected to LM3556.
-         LM3556 includes Torch, Flash and Indicator functions.
+         This option enables support for LEDs connected to LM355x.
+         LM355x includes Torch, Flash and Indicator functions.
 
 config LEDS_OT200
        tristate "LED support for the Bachmann OT200"
index a9b627c..3fb9641 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_BD2802)             += leds-bd2802.o
 obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
 obj-$(CONFIG_LEDS_LM3530)              += leds-lm3530.o
 obj-$(CONFIG_LEDS_LM3533)              += leds-lm3533.o
+obj-$(CONFIG_LEDS_LM3642)              += leds-lm3642.o
 obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
@@ -48,7 +49,7 @@ obj-$(CONFIG_LEDS_NETXBIG)            += leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 obj-$(CONFIG_LEDS_RENESAS_TPU)         += leds-renesas-tpu.o
 obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
-obj-$(CONFIG_LEDS_LM3556)              += leds-lm3556.o
+obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
 
 # LED SPI Drivers
index c599095..48cce18 100644 (file)
@@ -124,6 +124,16 @@ static void led_timer_function(unsigned long data)
        mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
+static void set_brightness_delayed(struct work_struct *ws)
+{
+       struct led_classdev *led_cdev =
+               container_of(ws, struct led_classdev, set_brightness_work);
+
+       led_stop_software_blink(led_cdev);
+
+       __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+}
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -191,6 +201,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        led_update_brightness(led_cdev);
 
+       INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
+
        init_timer(&led_cdev->blink_timer);
        led_cdev->blink_timer.function = led_timer_function;
        led_cdev->blink_timer.data = (unsigned long)led_cdev;
@@ -221,7 +233,10 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
        up_write(&led_cdev->trigger_lock);
 #endif
 
+       cancel_work_sync(&led_cdev->set_brightness_work);
+
        /* Stop blinking */
+       led_stop_software_blink(led_cdev);
        led_set_brightness(led_cdev, LED_OFF);
 
        device_unregister(led_cdev->dev);
index 2ab05af..ce8921a 100644 (file)
@@ -103,13 +103,23 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
 }
 EXPORT_SYMBOL(led_blink_set_oneshot);
 
-void led_set_brightness(struct led_classdev *led_cdev,
-                       enum led_brightness brightness)
+void led_stop_software_blink(struct led_classdev *led_cdev)
 {
-       /* stop and clear soft-blink timer */
        del_timer_sync(&led_cdev->blink_timer);
        led_cdev->blink_delay_on = 0;
        led_cdev->blink_delay_off = 0;
+}
+EXPORT_SYMBOL_GPL(led_stop_software_blink);
+
+void led_set_brightness(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
+{
+       /* delay brightness setting if need to stop soft-blink timer */
+       if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
+               led_cdev->delayed_set_value = brightness;
+               schedule_work(&led_cdev->set_brightness_work);
+               return;
+       }
 
        __led_set_brightness(led_cdev, brightness);
 }
index 363975b..262eb41 100644 (file)
@@ -102,6 +102,12 @@ EXPORT_SYMBOL_GPL(led_trigger_show);
 void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
 {
        unsigned long flags;
+       char *event = NULL;
+       char *envp[2];
+       const char *name;
+
+       name = trig ? trig->name : "none";
+       event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
 
        /* Remove any existing trigger */
        if (led_cdev->trigger) {
@@ -109,6 +115,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
                list_del(&led_cdev->trig_list);
                write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
                        flags);
+               cancel_work_sync(&led_cdev->set_brightness_work);
+               led_stop_software_blink(led_cdev);
                if (led_cdev->trigger->deactivate)
                        led_cdev->trigger->deactivate(led_cdev);
                led_cdev->trigger = NULL;
@@ -122,6 +130,13 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
                if (trig->activate)
                        trig->activate(led_cdev);
        }
+
+       if (event) {
+               envp[0] = event;
+               envp[1] = NULL;
+               kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp);
+               kfree(event);
+       }
 }
 EXPORT_SYMBOL_GPL(led_trigger_set);
 
@@ -224,7 +239,7 @@ void led_trigger_event(struct led_trigger *trig,
                struct led_classdev *led_cdev;
 
                led_cdev = list_entry(entry, struct led_classdev, trig_list);
-               __led_set_brightness(led_cdev, brightness);
+               led_set_brightness(led_cdev, brightness);
        }
        read_unlock(&trig->leddev_list_lock);
 }
index 1ed1677..e024b0b 100644 (file)
@@ -31,7 +31,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
 }
 
 /*
- * struct mail_led_whitelist - List of known good models
+ * struct clevo_mail_led_dmi_table - List of known good models
  *
  * Contains the known good models this driver is compatible with.
  * When adding a new model try to be as strict as possible. This
@@ -39,7 +39,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
  * detected as working, but in reality it is not) as low as
  * possible.
  */
-static struct dmi_system_id __initdata mail_led_whitelist[] = {
+static struct dmi_system_id __initdata clevo_mail_led_dmi_table[] = {
        {
                .callback = clevo_mail_led_dmi_callback,
                .ident = "Clevo D410J",
@@ -59,11 +59,10 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
        },
        {
                .callback = clevo_mail_led_dmi_callback,
-               .ident = "Positivo Mobile",
+               .ident = "Clevo M5x0V",
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
                        DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
                }
        },
@@ -89,6 +88,7 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, clevo_mail_led_dmi_table);
 
 static void clevo_mail_led_set(struct led_classdev *led_cdev,
                                enum led_brightness value)
@@ -180,7 +180,7 @@ static int __init clevo_mail_led_init(void)
 
        /* Check with the help of DMI if we are running on supported hardware */
        if (!nodetect) {
-               count = dmi_check_system(mail_led_whitelist);
+               count = dmi_check_system(clevo_mail_led_dmi_table);
        } else {
                count = 1;
                printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
index c032b21..087d1e6 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 
 struct gpio_led_data {
        struct led_classdev cdev;
@@ -170,11 +171,10 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
 {
        struct device_node *np = pdev->dev.of_node, *child;
        struct gpio_leds_priv *priv;
-       int count = 0, ret;
+       int count, ret;
 
        /* count LEDs in this device, so we know how much to allocate */
-       for_each_child_of_node(np, child)
-               count++;
+       count = of_get_child_count(np);
        if (!count)
                return NULL;
 
@@ -228,7 +228,6 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
 {
        return NULL;
 }
-#define of_gpio_leds_match NULL
 #endif /* CONFIG_OF_GPIO */
 
 
@@ -236,8 +235,14 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
 {
        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_leds_priv *priv;
+       struct pinctrl *pinctrl;
        int i, ret = 0;
 
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev,
+                       "pins are not configured from the driver\n");
+
        if (pdata && pdata->num_leds) {
                priv = devm_kzalloc(&pdev->dev,
                                sizeof_gpio_leds_priv(pdata->num_leds),
@@ -270,13 +275,13 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
 
 static int __devexit gpio_led_remove(struct platform_device *pdev)
 {
-       struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev);
+       struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
        int i;
 
        for (i = 0; i < priv->num_leds; i++)
                delete_gpio_led(&priv->leds[i]);
 
-       dev_set_drvdata(&pdev->dev, NULL);
+       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -287,7 +292,7 @@ static struct platform_driver gpio_led_driver = {
        .driver         = {
                .name   = "leds-gpio",
                .owner  = THIS_MODULE,
-               .of_match_table = of_gpio_leds_match,
+               .of_match_table = of_match_ptr(of_gpio_leds_match),
        },
 };
 
index 23637bd..b26306f 100644 (file)
@@ -150,7 +150,7 @@ static int lm3530_get_mode_from_str(const char *str)
                if (sysfs_streq(str, mode_map[i].mode))
                        return mode_map[i].mode_val;
 
-       return -1;
+       return -EINVAL;
 }
 
 static void lm3530_als_configure(struct lm3530_platform_data *pdata,
@@ -358,7 +358,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
        mode = lm3530_get_mode_from_str(buf);
        if (mode < 0) {
                dev_err(dev, "Invalid mode\n");
-               return -EINVAL;
+               return mode;
        }
 
        drvdata->mode = mode;
@@ -416,7 +416,7 @@ static int __devinit lm3530_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, drvdata);
 
-       drvdata->regulator = regulator_get(&client->dev, "vin");
+       drvdata->regulator = devm_regulator_get(&client->dev, "vin");
        if (IS_ERR(drvdata->regulator)) {
                dev_err(&client->dev, "regulator get failed\n");
                err = PTR_ERR(drvdata->regulator);
@@ -429,15 +429,13 @@ static int __devinit lm3530_probe(struct i2c_client *client,
                if (err < 0) {
                        dev_err(&client->dev,
                                "Register Init failed: %d\n", err);
-                       err = -ENODEV;
-                       goto err_reg_init;
+                       return err;
                }
        }
        err = led_classdev_register(&client->dev, &drvdata->led_dev);
        if (err < 0) {
                dev_err(&client->dev, "Register led class failed: %d\n", err);
-               err = -ENODEV;
-               goto err_class_register;
+               return err;
        }
 
        err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode);
@@ -451,9 +449,6 @@ static int __devinit lm3530_probe(struct i2c_client *client,
 
 err_create_file:
        led_classdev_unregister(&drvdata->led_dev);
-err_class_register:
-err_reg_init:
-       regulator_put(drvdata->regulator);
        return err;
 }
 
@@ -465,7 +460,6 @@ static int __devexit lm3530_remove(struct i2c_client *client)
 
        if (drvdata->enable)
                regulator_disable(drvdata->regulator);
-       regulator_put(drvdata->regulator);
        led_classdev_unregister(&drvdata->led_dev);
        return 0;
 }
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
deleted file mode 100644 (file)
index 3062abd..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
- * Copyright (C) 2012 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Please refer Documentation/leds/leds-lm3556.txt file.
- */
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/regmap.h>
-#include <linux/platform_data/leds-lm3556.h>
-
-#define REG_FILT_TIME                  (0x0)
-#define REG_IVFM_MODE                  (0x1)
-#define REG_NTC                                (0x2)
-#define REG_INDIC_TIME                 (0x3)
-#define REG_INDIC_BLINK                        (0x4)
-#define REG_INDIC_PERIOD               (0x5)
-#define REG_TORCH_TIME                 (0x6)
-#define REG_CONF                       (0x7)
-#define REG_FLASH                      (0x8)
-#define REG_I_CTRL                     (0x9)
-#define REG_ENABLE                     (0xA)
-#define REG_FLAG                       (0xB)
-#define REG_MAX                                (0xB)
-
-#define IVFM_FILTER_TIME_SHIFT         (3)
-#define UVLO_EN_SHIFT                  (7)
-#define HYSTERSIS_SHIFT                        (5)
-#define IVM_D_TH_SHIFT                 (2)
-#define IVFM_ADJ_MODE_SHIFT            (0)
-#define NTC_EVENT_LVL_SHIFT            (5)
-#define NTC_TRIP_TH_SHIFT              (2)
-#define NTC_BIAS_I_LVL_SHIFT           (0)
-#define INDIC_RAMP_UP_TIME_SHIFT       (3)
-#define INDIC_RAMP_DN_TIME_SHIFT       (0)
-#define INDIC_N_BLANK_SHIFT            (4)
-#define INDIC_PULSE_TIME_SHIFT         (0)
-#define INDIC_N_PERIOD_SHIFT           (0)
-#define TORCH_RAMP_UP_TIME_SHIFT       (3)
-#define TORCH_RAMP_DN_TIME_SHIFT       (0)
-#define STROBE_USUAGE_SHIFT            (7)
-#define STROBE_PIN_POLARITY_SHIFT      (6)
-#define TORCH_PIN_POLARITY_SHIFT       (5)
-#define TX_PIN_POLARITY_SHIFT          (4)
-#define TX_EVENT_LVL_SHIFT             (3)
-#define IVFM_EN_SHIFT                  (2)
-#define NTC_MODE_SHIFT                 (1)
-#define INDIC_MODE_SHIFT               (0)
-#define INDUCTOR_I_LIMIT_SHIFT         (6)
-#define FLASH_RAMP_TIME_SHIFT          (3)
-#define FLASH_TOUT_TIME_SHIFT          (0)
-#define TORCH_I_SHIFT                  (4)
-#define FLASH_I_SHIFT                  (0)
-#define NTC_EN_SHIFT                   (7)
-#define TX_PIN_EN_SHIFT                        (6)
-#define STROBE_PIN_EN_SHIFT            (5)
-#define TORCH_PIN_EN_SHIFT             (4)
-#define PRECHG_MODE_EN_SHIFT           (3)
-#define PASS_MODE_ONLY_EN_SHIFT                (2)
-#define MODE_BITS_SHIFT                        (0)
-
-#define IVFM_FILTER_TIME_MASK          (0x3)
-#define UVLO_EN_MASK                   (0x1)
-#define HYSTERSIS_MASK                 (0x3)
-#define IVM_D_TH_MASK                  (0x7)
-#define IVFM_ADJ_MODE_MASK             (0x3)
-#define NTC_EVENT_LVL_MASK             (0x1)
-#define NTC_TRIP_TH_MASK               (0x7)
-#define NTC_BIAS_I_LVL_MASK            (0x3)
-#define INDIC_RAMP_UP_TIME_MASK                (0x7)
-#define INDIC_RAMP_DN_TIME_MASK                (0x7)
-#define INDIC_N_BLANK_MASK             (0x7)
-#define INDIC_PULSE_TIME_MASK          (0x7)
-#define INDIC_N_PERIOD_MASK            (0x7)
-#define TORCH_RAMP_UP_TIME_MASK                (0x7)
-#define TORCH_RAMP_DN_TIME_MASK                (0x7)
-#define STROBE_USUAGE_MASK             (0x1)
-#define STROBE_PIN_POLARITY_MASK       (0x1)
-#define TORCH_PIN_POLARITY_MASK                (0x1)
-#define TX_PIN_POLARITY_MASK           (0x1)
-#define TX_EVENT_LVL_MASK              (0x1)
-#define IVFM_EN_MASK                   (0x1)
-#define NTC_MODE_MASK                  (0x1)
-#define INDIC_MODE_MASK                        (0x1)
-#define INDUCTOR_I_LIMIT_MASK          (0x3)
-#define FLASH_RAMP_TIME_MASK           (0x7)
-#define FLASH_TOUT_TIME_MASK           (0x7)
-#define TORCH_I_MASK                   (0x7)
-#define FLASH_I_MASK                   (0xF)
-#define NTC_EN_MASK                    (0x1)
-#define TX_PIN_EN_MASK                 (0x1)
-#define STROBE_PIN_EN_MASK             (0x1)
-#define TORCH_PIN_EN_MASK              (0x1)
-#define PRECHG_MODE_EN_MASK            (0x1)
-#define PASS_MODE_ONLY_EN_MASK         (0x1)
-#define MODE_BITS_MASK                 (0x13)
-#define EX_PIN_CONTROL_MASK            (0xF1)
-#define EX_PIN_ENABLE_MASK             (0x70)
-
-enum lm3556_indic_pulse_time {
-       PULSE_TIME_0_MS = 0,
-       PULSE_TIME_32_MS,
-       PULSE_TIME_64_MS,
-       PULSE_TIME_92_MS,
-       PULSE_TIME_128_MS,
-       PULSE_TIME_160_MS,
-       PULSE_TIME_196_MS,
-       PULSE_TIME_224_MS,
-       PULSE_TIME_256_MS,
-       PULSE_TIME_288_MS,
-       PULSE_TIME_320_MS,
-       PULSE_TIME_352_MS,
-       PULSE_TIME_384_MS,
-       PULSE_TIME_416_MS,
-       PULSE_TIME_448_MS,
-       PULSE_TIME_480_MS,
-};
-
-enum lm3556_indic_n_blank {
-       INDIC_N_BLANK_0 = 0,
-       INDIC_N_BLANK_1,
-       INDIC_N_BLANK_2,
-       INDIC_N_BLANK_3,
-       INDIC_N_BLANK_4,
-       INDIC_N_BLANK_5,
-       INDIC_N_BLANK_6,
-       INDIC_N_BLANK_7,
-       INDIC_N_BLANK_8,
-       INDIC_N_BLANK_9,
-       INDIC_N_BLANK_10,
-       INDIC_N_BLANK_11,
-       INDIC_N_BLANK_12,
-       INDIC_N_BLANK_13,
-       INDIC_N_BLANK_14,
-       INDIC_N_BLANK_15,
-};
-
-enum lm3556_indic_period {
-       INDIC_PERIOD_0 = 0,
-       INDIC_PERIOD_1,
-       INDIC_PERIOD_2,
-       INDIC_PERIOD_3,
-       INDIC_PERIOD_4,
-       INDIC_PERIOD_5,
-       INDIC_PERIOD_6,
-       INDIC_PERIOD_7,
-};
-
-enum lm3556_mode {
-       MODES_STASNDBY = 0,
-       MODES_INDIC,
-       MODES_TORCH,
-       MODES_FLASH
-};
-
-#define INDIC_PATTERN_SIZE 4
-
-struct indicator {
-       u8 blinking;
-       u8 period_cnt;
-};
-
-struct lm3556_chip_data {
-       struct device *dev;
-
-       struct led_classdev cdev_flash;
-       struct led_classdev cdev_torch;
-       struct led_classdev cdev_indicator;
-
-       struct lm3556_platform_data *pdata;
-       struct regmap *regmap;
-       struct mutex lock;
-
-       unsigned int last_flag;
-};
-
-/* indicator pattern */
-static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
-       [0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
-              | PULSE_TIME_32_MS, INDIC_PERIOD_1},
-       [1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
-              | PULSE_TIME_32_MS, INDIC_PERIOD_2},
-       [2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
-              | PULSE_TIME_32_MS, INDIC_PERIOD_4},
-       [3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
-              | PULSE_TIME_32_MS, INDIC_PERIOD_7},
-};
-
-/* chip initialize */
-static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
-{
-       unsigned int reg_val;
-       int ret;
-       struct lm3556_platform_data *pdata = chip->pdata;
-
-       /* set config register */
-       ret = regmap_read(chip->regmap, REG_CONF, &reg_val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to read REG_CONF Register\n");
-               goto out;
-       }
-
-       reg_val &= (~EX_PIN_CONTROL_MASK);
-       reg_val |= ((pdata->torch_pin_polarity & 0x01)
-                   << TORCH_PIN_POLARITY_SHIFT);
-       reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
-       reg_val |= ((pdata->strobe_pin_polarity & 0x01)
-                   << STROBE_PIN_POLARITY_SHIFT);
-       reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
-       reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
-
-       ret = regmap_write(chip->regmap, REG_CONF, reg_val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
-               goto out;
-       }
-
-       /* set enable register */
-       ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
-               goto out;
-       }
-
-       reg_val &= (~EX_PIN_ENABLE_MASK);
-       reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
-       reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
-       reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
-
-       ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
-               goto out;
-       }
-
-out:
-       return ret;
-}
-
-/* chip control */
-static int lm3556_control(struct lm3556_chip_data *chip,
-                         u8 brightness, enum lm3556_mode opmode)
-{
-       int ret;
-       struct lm3556_platform_data *pdata = chip->pdata;
-
-       ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
-               goto out;
-       }
-
-       if (chip->last_flag)
-               dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
-
-       /* brightness 0 means off-state */
-       if (!brightness)
-               opmode = MODES_STASNDBY;
-
-       switch (opmode) {
-       case MODES_TORCH:
-               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
-                                        TORCH_I_MASK << TORCH_I_SHIFT,
-                                        (brightness - 1) << TORCH_I_SHIFT);
-
-               if (pdata->torch_pin_en)
-                       opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
-               break;
-
-       case MODES_FLASH:
-               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
-                                        FLASH_I_MASK << FLASH_I_SHIFT,
-                                        (brightness - 1) << FLASH_I_SHIFT);
-               break;
-
-       case MODES_INDIC:
-               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
-                                        TORCH_I_MASK << TORCH_I_SHIFT,
-                                        (brightness - 1) << TORCH_I_SHIFT);
-               break;
-
-       case MODES_STASNDBY:
-               if (pdata->torch_pin_en)
-                       opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
-               break;
-
-       default:
-               return ret;
-       }
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
-               goto out;
-       }
-       ret = regmap_update_bits(chip->regmap, REG_ENABLE,
-                                MODE_BITS_MASK << MODE_BITS_SHIFT,
-                                opmode << MODE_BITS_SHIFT);
-
-out:
-       return ret;
-}
-
-/* torch */
-static void lm3556_torch_brightness_set(struct led_classdev *cdev,
-                                       enum led_brightness brightness)
-{
-       struct lm3556_chip_data *chip =
-           container_of(cdev, struct lm3556_chip_data, cdev_torch);
-
-       mutex_lock(&chip->lock);
-       lm3556_control(chip, brightness, MODES_TORCH);
-       mutex_unlock(&chip->lock);
-}
-
-/* flash */
-static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
-                                        enum led_brightness brightness)
-{
-       struct lm3556_chip_data *chip =
-           container_of(cdev, struct lm3556_chip_data, cdev_flash);
-
-       mutex_lock(&chip->lock);
-       lm3556_control(chip, brightness, MODES_FLASH);
-       mutex_unlock(&chip->lock);
-}
-
-/* indicator */
-static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
-                                           enum led_brightness brightness)
-{
-       struct lm3556_chip_data *chip =
-           container_of(cdev, struct lm3556_chip_data, cdev_indicator);
-
-       mutex_lock(&chip->lock);
-       lm3556_control(chip, brightness, MODES_INDIC);
-       mutex_unlock(&chip->lock);
-}
-
-/* indicator pattern */
-static ssize_t lm3556_indicator_pattern_store(struct device *dev,
-                                             struct device_attribute *devAttr,
-                                             const char *buf, size_t size)
-{
-       ssize_t ret;
-       struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct lm3556_chip_data *chip =
-           container_of(led_cdev, struct lm3556_chip_data, cdev_indicator);
-       unsigned int state;
-
-       ret = kstrtouint(buf, 10, &state);
-       if (ret)
-               goto out;
-       if (state > INDIC_PATTERN_SIZE - 1)
-               state = INDIC_PATTERN_SIZE - 1;
-
-       ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
-                          indicator_pattern[state].blinking);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
-               goto out;
-       }
-
-       ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
-                          indicator_pattern[state].period_cnt);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
-               goto out;
-       }
-
-       return size;
-out:
-       dev_err(chip->dev, "Indicator pattern doesn't saved\n");
-       return size;
-}
-
-static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
-
-static const struct regmap_config lm3556_regmap = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .max_register = REG_MAX,
-};
-
-/* module initialize */
-static int __devinit lm3556_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
-{
-       struct lm3556_platform_data *pdata = client->dev.platform_data;
-       struct lm3556_chip_data *chip;
-
-       int err;
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               dev_err(&client->dev, "i2c functionality check fail.\n");
-               return -EOPNOTSUPP;
-       }
-
-       if (pdata == NULL) {
-               dev_err(&client->dev, "Needs Platform Data.\n");
-               return -ENODATA;
-       }
-
-       chip =
-           devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
-                        GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
-       chip->dev = &client->dev;
-       chip->pdata = pdata;
-
-       chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap);
-       if (IS_ERR(chip->regmap)) {
-               err = PTR_ERR(chip->regmap);
-               dev_err(&client->dev, "Failed to allocate register map: %d\n",
-                       err);
-               return err;
-       }
-
-       mutex_init(&chip->lock);
-       i2c_set_clientdata(client, chip);
-
-       err = lm3556_chip_init(chip);
-       if (err < 0)
-               goto err_out;
-
-       /* flash */
-       chip->cdev_flash.name = "flash";
-       chip->cdev_flash.max_brightness = 16;
-       chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
-       err = led_classdev_register((struct device *)
-                                   &client->dev, &chip->cdev_flash);
-       if (err < 0)
-               goto err_out;
-       /* torch */
-       chip->cdev_torch.name = "torch";
-       chip->cdev_torch.max_brightness = 8;
-       chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
-       err = led_classdev_register((struct device *)
-                                   &client->dev, &chip->cdev_torch);
-       if (err < 0)
-               goto err_create_torch_file;
-       /* indicator */
-       chip->cdev_indicator.name = "indicator";
-       chip->cdev_indicator.max_brightness = 8;
-       chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
-       err = led_classdev_register((struct device *)
-                                   &client->dev, &chip->cdev_indicator);
-       if (err < 0)
-               goto err_create_indicator_file;
-
-       err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
-       if (err < 0)
-               goto err_create_pattern_file;
-
-       dev_info(&client->dev, "LM3556 is initialized\n");
-       return 0;
-
-err_create_pattern_file:
-       led_classdev_unregister(&chip->cdev_indicator);
-err_create_indicator_file:
-       led_classdev_unregister(&chip->cdev_torch);
-err_create_torch_file:
-       led_classdev_unregister(&chip->cdev_flash);
-err_out:
-       return err;
-}
-
-static int __devexit lm3556_remove(struct i2c_client *client)
-{
-       struct lm3556_chip_data *chip = i2c_get_clientdata(client);
-
-       device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
-       led_classdev_unregister(&chip->cdev_indicator);
-       led_classdev_unregister(&chip->cdev_torch);
-       led_classdev_unregister(&chip->cdev_flash);
-       regmap_write(chip->regmap, REG_ENABLE, 0);
-       return 0;
-}
-
-static const struct i2c_device_id lm3556_id[] = {
-       {LM3556_NAME, 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, lm3556_id);
-
-static struct i2c_driver lm3556_i2c_driver = {
-       .driver = {
-                  .name = LM3556_NAME,
-                  .owner = THIS_MODULE,
-                  .pm = NULL,
-                  },
-       .probe = lm3556_probe,
-       .remove = __devexit_p(lm3556_remove),
-       .id_table = lm3556_id,
-};
-
-module_i2c_driver(lm3556_i2c_driver);
-
-MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
-MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
-MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
new file mode 100644 (file)
index 0000000..065ec01
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+* Simple driver for Texas Instruments LM355x LED Flash driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/platform_data/leds-lm355x.h>
+
+enum lm355x_type {
+       CHIP_LM3554 = 0,
+       CHIP_LM3556,
+};
+
+enum lm355x_regs {
+       REG_FLAG = 0,
+       REG_TORCH_CFG,
+       REG_TORCH_CTRL,
+       REG_STROBE_CFG,
+       REG_FLASH_CTRL,
+       REG_INDI_CFG,
+       REG_INDI_CTRL,
+       REG_OPMODE,
+       REG_MAX,
+};
+
+/* operation mode */
+enum lm355x_mode {
+       MODE_SHDN = 0,
+       MODE_INDIC,
+       MODE_TORCH,
+       MODE_FLASH
+};
+
+/* register map info. */
+struct lm355x_reg_data {
+       u8 regno;
+       u8 mask;
+       u8 shift;
+};
+
+struct lm355x_chip_data {
+       struct device *dev;
+       enum lm355x_type type;
+
+       struct led_classdev cdev_flash;
+       struct led_classdev cdev_torch;
+       struct led_classdev cdev_indicator;
+
+       struct work_struct work_flash;
+       struct work_struct work_torch;
+       struct work_struct work_indicator;
+
+       u8 br_flash;
+       u8 br_torch;
+       u8 br_indicator;
+
+       struct lm355x_platform_data *pdata;
+       struct regmap *regmap;
+       struct mutex lock;
+
+       unsigned int last_flag;
+       struct lm355x_reg_data *regs;
+};
+
+/* specific indicator function for lm3556 */
+enum lm3556_indic_pulse_time {
+       PULSE_TIME_0_MS = 0,
+       PULSE_TIME_32_MS,
+       PULSE_TIME_64_MS,
+       PULSE_TIME_92_MS,
+       PULSE_TIME_128_MS,
+       PULSE_TIME_160_MS,
+       PULSE_TIME_196_MS,
+       PULSE_TIME_224_MS,
+       PULSE_TIME_256_MS,
+       PULSE_TIME_288_MS,
+       PULSE_TIME_320_MS,
+       PULSE_TIME_352_MS,
+       PULSE_TIME_384_MS,
+       PULSE_TIME_416_MS,
+       PULSE_TIME_448_MS,
+       PULSE_TIME_480_MS,
+};
+
+enum lm3556_indic_n_blank {
+       INDIC_N_BLANK_0 = 0,
+       INDIC_N_BLANK_1,
+       INDIC_N_BLANK_2,
+       INDIC_N_BLANK_3,
+       INDIC_N_BLANK_4,
+       INDIC_N_BLANK_5,
+       INDIC_N_BLANK_6,
+       INDIC_N_BLANK_7,
+       INDIC_N_BLANK_8,
+       INDIC_N_BLANK_9,
+       INDIC_N_BLANK_10,
+       INDIC_N_BLANK_11,
+       INDIC_N_BLANK_12,
+       INDIC_N_BLANK_13,
+       INDIC_N_BLANK_14,
+       INDIC_N_BLANK_15,
+};
+
+enum lm3556_indic_period {
+       INDIC_PERIOD_0 = 0,
+       INDIC_PERIOD_1,
+       INDIC_PERIOD_2,
+       INDIC_PERIOD_3,
+       INDIC_PERIOD_4,
+       INDIC_PERIOD_5,
+       INDIC_PERIOD_6,
+       INDIC_PERIOD_7,
+};
+
+#define INDIC_PATTERN_SIZE 4
+
+struct indicator {
+       u8 blinking;
+       u8 period_cnt;
+};
+
+/* indicator pattern data only for lm3556 */
+static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
+       [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1},
+       [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2},
+       [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4},
+       [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7},
+};
+
+static struct lm355x_reg_data lm3554_regs[REG_MAX] = {
+       [REG_FLAG] = {0xD0, 0xBF, 0},
+       [REG_TORCH_CFG] = {0xE0, 0x80, 7},
+       [REG_TORCH_CTRL] = {0xA0, 0x38, 3},
+       [REG_STROBE_CFG] = {0xE0, 0x04, 2},
+       [REG_FLASH_CTRL] = {0xB0, 0x78, 3},
+       [REG_INDI_CFG] = {0xE0, 0x08, 3},
+       [REG_INDI_CTRL] = {0xA0, 0xC0, 6},
+       [REG_OPMODE] = {0xA0, 0x03, 0},
+};
+
+static struct lm355x_reg_data lm3556_regs[REG_MAX] = {
+       [REG_FLAG] = {0x0B, 0xFF, 0},
+       [REG_TORCH_CFG] = {0x0A, 0x10, 4},
+       [REG_TORCH_CTRL] = {0x09, 0x70, 4},
+       [REG_STROBE_CFG] = {0x0A, 0x20, 5},
+       [REG_FLASH_CTRL] = {0x09, 0x0F, 0},
+       [REG_INDI_CFG] = {0xFF, 0xFF, 0},
+       [REG_INDI_CTRL] = {0x09, 0x70, 4},
+       [REG_OPMODE] = {0x0A, 0x03, 0},
+};
+
+static char lm355x_name[][I2C_NAME_SIZE] = {
+       [CHIP_LM3554] = LM3554_NAME,
+       [CHIP_LM3556] = LM3556_NAME,
+};
+
+/* chip initialize */
+static int __devinit lm355x_chip_init(struct lm355x_chip_data *chip)
+{
+       int ret;
+       unsigned int reg_val;
+       struct lm355x_platform_data *pdata = chip->pdata;
+
+       /* input and output pins configuration */
+       switch (chip->type) {
+       case CHIP_LM3554:
+               reg_val = pdata->pin_tx2 | pdata->ntc_pin;
+               ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
+               if (ret < 0)
+                       goto out;
+               reg_val = pdata->pass_mode;
+               ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
+               if (ret < 0)
+                       goto out;
+               break;
+
+       case CHIP_LM3556:
+               reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode;
+               ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
+               if (ret < 0)
+                       goto out;
+               break;
+       default:
+               return -ENODATA;
+       }
+
+       return ret;
+out:
+       dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+       return ret;
+}
+
+/* chip control */
+static void lm355x_control(struct lm355x_chip_data *chip,
+                          u8 brightness, enum lm355x_mode opmode)
+{
+       int ret;
+       unsigned int reg_val;
+       struct lm355x_platform_data *pdata = chip->pdata;
+       struct lm355x_reg_data *preg = chip->regs;
+
+       ret = regmap_read(chip->regmap, preg[REG_FLAG].regno, &chip->last_flag);
+       if (ret < 0)
+               goto out;
+       if (chip->last_flag & preg[REG_FLAG].mask)
+               dev_info(chip->dev, "%s Last FLAG is 0x%x\n",
+                        lm355x_name[chip->type],
+                        chip->last_flag & preg[REG_FLAG].mask);
+       /* brightness 0 means shutdown */
+       if (!brightness)
+               opmode = MODE_SHDN;
+
+       switch (opmode) {
+       case MODE_TORCH:
+               ret =
+                   regmap_update_bits(chip->regmap, preg[REG_TORCH_CTRL].regno,
+                                      preg[REG_TORCH_CTRL].mask,
+                                      (brightness - 1)
+                                      << preg[REG_TORCH_CTRL].shift);
+               if (ret < 0)
+                       goto out;
+
+               if (pdata->pin_tx1 != LM355x_PIN_TORCH_DISABLE) {
+                       ret =
+                           regmap_update_bits(chip->regmap,
+                                              preg[REG_TORCH_CFG].regno,
+                                              preg[REG_TORCH_CFG].mask,
+                                              0x01 <<
+                                              preg[REG_TORCH_CFG].shift);
+                       if (ret < 0)
+                               goto out;
+                       opmode = MODE_SHDN;
+                       dev_info(chip->dev,
+                                "torch brt is set - ext. torch pin mode\n");
+               }
+               break;
+
+       case MODE_FLASH:
+
+               ret =
+                   regmap_update_bits(chip->regmap, preg[REG_FLASH_CTRL].regno,
+                                      preg[REG_FLASH_CTRL].mask,
+                                      (brightness - 1)
+                                      << preg[REG_FLASH_CTRL].shift);
+               if (ret < 0)
+                       goto out;
+
+               if (pdata->pin_strobe != LM355x_PIN_STROBE_DISABLE) {
+                       if (chip->type == CHIP_LM3554)
+                               reg_val = 0x00;
+                       else
+                               reg_val = 0x01;
+                       ret =
+                           regmap_update_bits(chip->regmap,
+                                              preg[REG_STROBE_CFG].regno,
+                                              preg[REG_STROBE_CFG].mask,
+                                              reg_val <<
+                                              preg[REG_STROBE_CFG].shift);
+                       if (ret < 0)
+                               goto out;
+                       opmode = MODE_SHDN;
+                       dev_info(chip->dev,
+                                "flash brt is set - ext. strobe pin mode\n");
+               }
+               break;
+
+       case MODE_INDIC:
+               ret =
+                   regmap_update_bits(chip->regmap, preg[REG_INDI_CTRL].regno,
+                                      preg[REG_INDI_CTRL].mask,
+                                      (brightness - 1)
+                                      << preg[REG_INDI_CTRL].shift);
+               if (ret < 0)
+                       goto out;
+
+               if (pdata->pin_tx2 != LM355x_PIN_TX_DISABLE) {
+                       ret =
+                           regmap_update_bits(chip->regmap,
+                                              preg[REG_INDI_CFG].regno,
+                                              preg[REG_INDI_CFG].mask,
+                                              0x01 <<
+                                              preg[REG_INDI_CFG].shift);
+                       if (ret < 0)
+                               goto out;
+                       opmode = MODE_SHDN;
+               }
+               break;
+       case MODE_SHDN:
+               break;
+       default:
+               return;
+       }
+       /* operation mode control */
+       ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
+                                preg[REG_OPMODE].mask,
+                                opmode << preg[REG_OPMODE].shift);
+       if (ret < 0)
+               goto out;
+       return;
+out:
+       dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+       return;
+}
+
+/* torch */
+static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
+{
+       struct lm355x_chip_data *chip =
+           container_of(work, struct lm355x_chip_data, work_torch);
+
+       mutex_lock(&chip->lock);
+       lm355x_control(chip, chip->br_torch, MODE_TORCH);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm355x_torch_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm355x_chip_data *chip =
+           container_of(cdev, struct lm355x_chip_data, cdev_torch);
+
+       chip->br_torch = brightness;
+       schedule_work(&chip->work_torch);
+}
+
+/* flash */
+static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
+{
+       struct lm355x_chip_data *chip =
+           container_of(work, struct lm355x_chip_data, work_flash);
+
+       mutex_lock(&chip->lock);
+       lm355x_control(chip, chip->br_flash, MODE_FLASH);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
+                                        enum led_brightness brightness)
+{
+       struct lm355x_chip_data *chip =
+           container_of(cdev, struct lm355x_chip_data, cdev_flash);
+
+       chip->br_flash = brightness;
+       schedule_work(&chip->work_flash);
+}
+
+/* indicator */
+static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
+{
+       struct lm355x_chip_data *chip =
+           container_of(work, struct lm355x_chip_data, work_indicator);
+
+       mutex_lock(&chip->lock);
+       lm355x_control(chip, chip->br_indicator, MODE_INDIC);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
+                                           enum led_brightness brightness)
+{
+       struct lm355x_chip_data *chip =
+           container_of(cdev, struct lm355x_chip_data, cdev_indicator);
+
+       chip->br_indicator = brightness;
+       schedule_work(&chip->work_indicator);
+}
+
+/* indicator pattern only for lm3556*/
+static ssize_t lm3556_indicator_pattern_store(struct device *dev,
+                                             struct device_attribute *devAttr,
+                                             const char *buf, size_t size)
+{
+       ssize_t ret;
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm355x_chip_data *chip =
+           container_of(led_cdev, struct lm355x_chip_data, cdev_indicator);
+       unsigned int state;
+
+       ret = kstrtouint(buf, 10, &state);
+       if (ret)
+               goto out;
+       if (state > INDIC_PATTERN_SIZE - 1)
+               state = INDIC_PATTERN_SIZE - 1;
+
+       ret = regmap_write(chip->regmap, 0x04,
+                          indicator_pattern[state].blinking);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_write(chip->regmap, 0x05,
+                          indicator_pattern[state].period_cnt);
+       if (ret < 0)
+               goto out;
+
+       return size;
+out:
+       dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+       return size;
+}
+
+static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
+
+static const struct regmap_config lm355x_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xFF,
+};
+
+/* module initialize */
+static int __devinit lm355x_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct lm355x_platform_data *pdata = client->dev.platform_data;
+       struct lm355x_chip_data *chip;
+
+       int err;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "i2c functionality check fail.\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "needs Platform Data.\n");
+               return -ENODATA;
+       }
+
+       chip = devm_kzalloc(&client->dev,
+                           sizeof(struct lm355x_chip_data), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = &client->dev;
+       chip->type = id->driver_data;
+       switch (id->driver_data) {
+       case CHIP_LM3554:
+               chip->regs = lm3554_regs;
+               break;
+       case CHIP_LM3556:
+               chip->regs = lm3556_regs;
+               break;
+       default:
+               return -ENOSYS;
+       }
+       chip->pdata = pdata;
+
+       chip->regmap = devm_regmap_init_i2c(client, &lm355x_regmap);
+       if (IS_ERR(chip->regmap)) {
+               err = PTR_ERR(chip->regmap);
+               dev_err(&client->dev,
+                       "Failed to allocate register map: %d\n", err);
+               return err;
+       }
+
+       mutex_init(&chip->lock);
+       i2c_set_clientdata(client, chip);
+
+       err = lm355x_chip_init(chip);
+       if (err < 0)
+               goto err_out;
+
+       /* flash */
+       INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
+       chip->cdev_flash.name = "flash";
+       chip->cdev_flash.max_brightness = 16;
+       chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_flash);
+       if (err < 0)
+               goto err_out;
+       /* torch */
+       INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
+       chip->cdev_torch.name = "torch";
+       chip->cdev_torch.max_brightness = 8;
+       chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_torch);
+       if (err < 0)
+               goto err_create_torch_file;
+       /* indicator */
+       INIT_WORK(&chip->work_indicator,
+                 lm355x_deferred_indicator_brightness_set);
+       chip->cdev_indicator.name = "indicator";
+       if (id->driver_data == CHIP_LM3554)
+               chip->cdev_indicator.max_brightness = 4;
+       else
+               chip->cdev_indicator.max_brightness = 8;
+       chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_indicator);
+       if (err < 0)
+               goto err_create_indicator_file;
+       /* indicator pattern control only for LM3554 */
+       if (id->driver_data == CHIP_LM3556) {
+               err =
+                   device_create_file(chip->cdev_indicator.dev,
+                                      &dev_attr_pattern);
+               if (err < 0)
+                       goto err_create_pattern_file;
+       }
+
+       dev_info(&client->dev, "%s is initialized\n",
+                lm355x_name[id->driver_data]);
+       return 0;
+
+err_create_pattern_file:
+       led_classdev_unregister(&chip->cdev_indicator);
+err_create_indicator_file:
+       led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+       led_classdev_unregister(&chip->cdev_flash);
+err_out:
+       return err;
+}
+
+static int __devexit lm355x_remove(struct i2c_client *client)
+{
+       struct lm355x_chip_data *chip = i2c_get_clientdata(client);
+       struct lm355x_reg_data *preg = chip->regs;
+
+       regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
+       if (chip->type == CHIP_LM3556)
+               device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+       led_classdev_unregister(&chip->cdev_indicator);
+       flush_work(&chip->work_indicator);
+       led_classdev_unregister(&chip->cdev_torch);
+       flush_work(&chip->work_torch);
+       led_classdev_unregister(&chip->cdev_flash);
+       flush_work(&chip->work_flash);
+       dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
+
+       return 0;
+}
+
+static const struct i2c_device_id lm355x_id[] = {
+       {LM3554_NAME, CHIP_LM3554},
+       {LM3556_NAME, CHIP_LM3556},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm355x_id);
+
+static struct i2c_driver lm355x_i2c_driver = {
+       .driver = {
+                  .name = LM355x_NAME,
+                  .owner = THIS_MODULE,
+                  .pm = NULL,
+                  },
+       .probe = lm355x_probe,
+       .remove = __devexit_p(lm355x_remove),
+       .id_table = lm355x_id,
+};
+
+module_i2c_driver(lm355x_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
new file mode 100644 (file)
index 0000000..3285006
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+* Simple driver for Texas Instruments LM3642 LED Flash driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+*/
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/platform_data/leds-lm3642.h>
+
+#define        REG_FILT_TIME                   (0x0)
+#define        REG_IVFM_MODE                   (0x1)
+#define        REG_TORCH_TIME                  (0x6)
+#define        REG_FLASH                       (0x8)
+#define        REG_I_CTRL                      (0x9)
+#define        REG_ENABLE                      (0xA)
+#define        REG_FLAG                        (0xB)
+#define        REG_MAX                         (0xB)
+
+#define        UVLO_EN_SHIFT                   (7)
+#define        IVM_D_TH_SHIFT                  (2)
+#define        TORCH_RAMP_UP_TIME_SHIFT        (3)
+#define        TORCH_RAMP_DN_TIME_SHIFT        (0)
+#define        INDUCTOR_I_LIMIT_SHIFT          (6)
+#define        FLASH_RAMP_TIME_SHIFT           (3)
+#define        FLASH_TOUT_TIME_SHIFT           (0)
+#define        TORCH_I_SHIFT                   (4)
+#define        FLASH_I_SHIFT                   (0)
+#define        IVFM_SHIFT                      (7)
+#define        TX_PIN_EN_SHIFT                 (6)
+#define        STROBE_PIN_EN_SHIFT             (5)
+#define        TORCH_PIN_EN_SHIFT              (4)
+#define        MODE_BITS_SHIFT                 (0)
+
+#define        UVLO_EN_MASK                    (0x1)
+#define        IVM_D_TH_MASK                   (0x7)
+#define        TORCH_RAMP_UP_TIME_MASK         (0x7)
+#define        TORCH_RAMP_DN_TIME_MASK         (0x7)
+#define        INDUCTOR_I_LIMIT_MASK           (0x1)
+#define        FLASH_RAMP_TIME_MASK            (0x7)
+#define        FLASH_TOUT_TIME_MASK            (0x7)
+#define        TORCH_I_MASK                    (0x7)
+#define        FLASH_I_MASK                    (0xF)
+#define        IVFM_MASK                       (0x1)
+#define        TX_PIN_EN_MASK                  (0x1)
+#define        STROBE_PIN_EN_MASK              (0x1)
+#define        TORCH_PIN_EN_MASK               (0x1)
+#define        MODE_BITS_MASK                  (0x73)
+#define EX_PIN_CONTROL_MASK            (0x71)
+#define EX_PIN_ENABLE_MASK             (0x70)
+
+enum lm3642_mode {
+       MODES_STASNDBY = 0,
+       MODES_INDIC,
+       MODES_TORCH,
+       MODES_FLASH
+};
+
+struct lm3642_chip_data {
+       struct device *dev;
+
+       struct led_classdev cdev_flash;
+       struct led_classdev cdev_torch;
+       struct led_classdev cdev_indicator;
+
+       struct work_struct work_flash;
+       struct work_struct work_torch;
+       struct work_struct work_indicator;
+
+       u8 br_flash;
+       u8 br_torch;
+       u8 br_indicator;
+
+       enum lm3642_torch_pin_enable torch_pin;
+       enum lm3642_strobe_pin_enable strobe_pin;
+       enum lm3642_tx_pin_enable tx_pin;
+
+       struct lm3642_platform_data *pdata;
+       struct regmap *regmap;
+       struct mutex lock;
+
+       unsigned int last_flag;
+};
+
+/* chip initialize */
+static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip)
+{
+       int ret;
+       struct lm3642_platform_data *pdata = chip->pdata;
+
+       /* set enable register */
+       ret = regmap_update_bits(chip->regmap, REG_ENABLE, EX_PIN_ENABLE_MASK,
+                                pdata->tx_pin);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to update REG_ENABLE Register\n");
+       return ret;
+}
+
+/* chip control */
+static int lm3642_control(struct lm3642_chip_data *chip,
+                         u8 brightness, enum lm3642_mode opmode)
+{
+       int ret;
+
+       ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
+               goto out;
+       }
+
+       if (chip->last_flag)
+               dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
+
+       /* brightness 0 means off-state */
+       if (!brightness)
+               opmode = MODES_STASNDBY;
+
+       switch (opmode) {
+       case MODES_TORCH:
+               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+                                        TORCH_I_MASK << TORCH_I_SHIFT,
+                                        (brightness - 1) << TORCH_I_SHIFT);
+
+               if (chip->torch_pin)
+                       opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+               break;
+
+       case MODES_FLASH:
+               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+                                        FLASH_I_MASK << FLASH_I_SHIFT,
+                                        (brightness - 1) << FLASH_I_SHIFT);
+
+               if (chip->strobe_pin)
+                       opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT);
+               break;
+
+       case MODES_INDIC:
+               ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+                                        TORCH_I_MASK << TORCH_I_SHIFT,
+                                        (brightness - 1) << TORCH_I_SHIFT);
+               break;
+
+       case MODES_STASNDBY:
+
+               break;
+
+       default:
+               return ret;
+       }
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
+               goto out;
+       }
+
+       if (chip->tx_pin)
+               opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT);
+
+       ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+                                MODE_BITS_MASK << MODE_BITS_SHIFT,
+                                opmode << MODE_BITS_SHIFT);
+out:
+       return ret;
+}
+
+/* torch */
+
+/* torch pin config for lm3642*/
+static ssize_t lm3642_torch_pin_store(struct device *dev,
+                                     struct device_attribute *devAttr,
+                                     const char *buf, size_t size)
+{
+       ssize_t ret;
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm3642_chip_data *chip =
+           container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
+       unsigned int state;
+
+       ret = kstrtouint(buf, 10, &state);
+       if (ret)
+               goto out_strtoint;
+       if (state != 0)
+               state = 0x01 << TORCH_PIN_EN_SHIFT;
+
+       chip->torch_pin = state;
+       ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+                                TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,
+                                state);
+       if (ret < 0)
+               goto out;
+
+       return size;
+out:
+       dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+       return size;
+out_strtoint:
+       dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
+       return size;
+}
+
+static DEVICE_ATTR(torch_pin, 0666, NULL, lm3642_torch_pin_store);
+
+static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
+{
+       struct lm3642_chip_data *chip =
+           container_of(work, struct lm3642_chip_data, work_torch);
+
+       mutex_lock(&chip->lock);
+       lm3642_control(chip, chip->br_torch, MODES_TORCH);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm3642_torch_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm3642_chip_data *chip =
+           container_of(cdev, struct lm3642_chip_data, cdev_torch);
+
+       chip->br_torch = brightness;
+       schedule_work(&chip->work_torch);
+}
+
+/* flash */
+
+/* strobe pin config for lm3642*/
+static ssize_t lm3642_strobe_pin_store(struct device *dev,
+                                      struct device_attribute *devAttr,
+                                      const char *buf, size_t size)
+{
+       ssize_t ret;
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm3642_chip_data *chip =
+           container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
+       unsigned int state;
+
+       ret = kstrtouint(buf, 10, &state);
+       if (ret)
+               goto out_strtoint;
+       if (state != 0)
+               state = 0x01 << STROBE_PIN_EN_SHIFT;
+
+       chip->strobe_pin = state;
+       ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+                                STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,
+                                state);
+       if (ret < 0)
+               goto out;
+
+       return size;
+out:
+       dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+       return size;
+out_strtoint:
+       dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
+       return size;
+}
+
+static DEVICE_ATTR(strobe_pin, 0666, NULL, lm3642_strobe_pin_store);
+
+static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
+{
+       struct lm3642_chip_data *chip =
+           container_of(work, struct lm3642_chip_data, work_flash);
+
+       mutex_lock(&chip->lock);
+       lm3642_control(chip, chip->br_flash, MODES_FLASH);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
+                                        enum led_brightness brightness)
+{
+       struct lm3642_chip_data *chip =
+           container_of(cdev, struct lm3642_chip_data, cdev_flash);
+
+       chip->br_flash = brightness;
+       schedule_work(&chip->work_flash);
+}
+
+/* indicator */
+static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
+{
+       struct lm3642_chip_data *chip =
+           container_of(work, struct lm3642_chip_data, work_indicator);
+
+       mutex_lock(&chip->lock);
+       lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+       mutex_unlock(&chip->lock);
+}
+
+static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
+                                           enum led_brightness brightness)
+{
+       struct lm3642_chip_data *chip =
+           container_of(cdev, struct lm3642_chip_data, cdev_indicator);
+
+       chip->br_indicator = brightness;
+       schedule_work(&chip->work_indicator);
+}
+
+static const struct regmap_config lm3642_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = REG_MAX,
+};
+
+static int __devinit lm3642_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct lm3642_platform_data *pdata = client->dev.platform_data;
+       struct lm3642_chip_data *chip;
+
+       int err;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "i2c functionality check fail.\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "needs Platform Data.\n");
+               return -ENODATA;
+       }
+
+       chip = devm_kzalloc(&client->dev,
+                           sizeof(struct lm3642_chip_data), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = &client->dev;
+       chip->pdata = pdata;
+
+       chip->tx_pin = pdata->tx_pin;
+       chip->torch_pin = pdata->torch_pin;
+       chip->strobe_pin = pdata->strobe_pin;
+
+       chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);
+       if (IS_ERR(chip->regmap)) {
+               err = PTR_ERR(chip->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       err);
+               return err;
+       }
+
+       mutex_init(&chip->lock);
+       i2c_set_clientdata(client, chip);
+
+       err = lm3642_chip_init(chip);
+       if (err < 0)
+               goto err_out;
+
+       /* flash */
+       INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
+       chip->cdev_flash.name = "flash";
+       chip->cdev_flash.max_brightness = 16;
+       chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_flash);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to register flash\n");
+               goto err_out;
+       }
+       err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to create strobe-pin file\n");
+               goto err_create_flash_pin_file;
+       }
+
+       /* torch */
+       INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
+       chip->cdev_torch.name = "torch";
+       chip->cdev_torch.max_brightness = 8;
+       chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_torch);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to register torch\n");
+               goto err_create_torch_file;
+       }
+       err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to create torch-pin file\n");
+               goto err_create_torch_pin_file;
+       }
+
+       /* indicator */
+       INIT_WORK(&chip->work_indicator,
+                 lm3642_deferred_indicator_brightness_set);
+       chip->cdev_indicator.name = "indicator";
+       chip->cdev_indicator.max_brightness = 8;
+       chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
+       err = led_classdev_register((struct device *)
+                                   &client->dev, &chip->cdev_indicator);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to register indicator\n");
+               goto err_create_indicator_file;
+       }
+
+       dev_info(&client->dev, "LM3642 is initialized\n");
+       return 0;
+
+err_create_indicator_file:
+       device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+err_create_torch_pin_file:
+       led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+       device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+err_create_flash_pin_file:
+       led_classdev_unregister(&chip->cdev_flash);
+err_out:
+       return err;
+}
+
+static int __devexit lm3642_remove(struct i2c_client *client)
+{
+       struct lm3642_chip_data *chip = i2c_get_clientdata(client);
+
+       led_classdev_unregister(&chip->cdev_indicator);
+       flush_work(&chip->work_indicator);
+       device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+       led_classdev_unregister(&chip->cdev_torch);
+       flush_work(&chip->work_torch);
+       device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+       led_classdev_unregister(&chip->cdev_flash);
+       flush_work(&chip->work_flash);
+       regmap_write(chip->regmap, REG_ENABLE, 0);
+       return 0;
+}
+
+static const struct i2c_device_id lm3642_id[] = {
+       {LM3642_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3642_id);
+
+static struct i2c_driver lm3642_i2c_driver = {
+       .driver = {
+                  .name = LM3642_NAME,
+                  .owner = THIS_MODULE,
+                  .pm = NULL,
+                  },
+       .probe = lm3642_probe,
+       .remove = __devexit_p(lm3642_remove),
+       .id_table = lm3642_id,
+};
+
+module_i2c_driver(lm3642_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
index fbc12ac..97994ff 100644 (file)
 #define LED_ACTIVE(mux, led)           (!!(mux & (0x0001 << led)))
 #define SHIFT_MASK(id)                 (((id) - 1) * 2)
 
+enum lp5523_chip_id {
+       LP5523,
+       LP55231,
+};
+
 struct lp5523_engine {
        int             id;
        u8              mode;
@@ -150,7 +155,7 @@ static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
                            leds[led->id]);
 }
 
-static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
+static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
 static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
 static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern);
 
@@ -177,7 +182,7 @@ static int lp5523_detect(struct i2c_client *client)
        int ret;
        u8 buf;
 
-       ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40);
+       ret = lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
        if (ret)
                return ret;
        ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
@@ -338,7 +343,8 @@ static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
 {
        int i;
        u16 tmp_mux = 0;
-       len = len < LP5523_LEDS ? len : LP5523_LEDS;
+
+       len = min_t(int, len, LP5523_LEDS);
        for (i = 0; i < len; i++) {
                switch (buf[i]) {
                case '1':
@@ -546,6 +552,9 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
        unsigned cmd;
        u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
 
+       if (engine->mode != LP5523_CMD_LOAD)
+               return -EINVAL;
+
        while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
                /* separate sscanfs because length is working only for %s */
                ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
@@ -563,12 +572,7 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
                goto fail;
 
        mutex_lock(&chip->lock);
-
-       if (engine->mode == LP5523_CMD_LOAD)
-               ret = lp5523_load_program(engine, pattern);
-       else
-               ret = -EINVAL;
-
+       ret = lp5523_load_program(engine, pattern);
        mutex_unlock(&chip->lock);
 
        if (ret) {
@@ -755,6 +759,7 @@ static struct attribute *lp5523_attributes[] = {
        &dev_attr_engine2_leds.attr,
        &dev_attr_engine3_load.attr,
        &dev_attr_engine3_leds.attr,
+       NULL,
 };
 
 static const struct attribute_group lp5523_group = {
@@ -789,26 +794,28 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
 /*--------------------------------------------------------------*/
 /*                     Set chip operating mode                 */
 /*--------------------------------------------------------------*/
-static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
+static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
 {
-       int ret = 0;
-
        /* if in that mode already do nothing, except for run */
        if (mode == engine->mode && mode != LP5523_CMD_RUN)
-               return 0;
+               return;
 
-       if (mode == LP5523_CMD_RUN) {
-               ret = lp5523_run_program(engine);
-       } else if (mode == LP5523_CMD_LOAD) {
+       switch (mode) {
+       case LP5523_CMD_RUN:
+               lp5523_run_program(engine);
+               break;
+       case LP5523_CMD_LOAD:
                lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
                lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
-       } else if (mode == LP5523_CMD_DISABLED) {
+               break;
+       case LP5523_CMD_DISABLED:
                lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+               break;
+       default:
+               return;
        }
 
        engine->mode = mode;
-
-       return ret;
 }
 
 /*--------------------------------------------------------------*/
@@ -827,7 +834,8 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
 }
 
 static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
-                          int chan, struct lp5523_platform_data *pdata)
+                          int chan, struct lp5523_platform_data *pdata,
+                          const char *chip_name)
 {
        char name[32];
        int res;
@@ -846,10 +854,14 @@ static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
                        return -EINVAL;
                }
 
-               snprintf(name, sizeof(name), "%s:channel%d",
-                       pdata->label ?: "lp5523", chan);
+               if (pdata->led_config[chan].name) {
+                       led->cdev.name = pdata->led_config[chan].name;
+               } else {
+                       snprintf(name, sizeof(name), "%s:channel%d",
+                               pdata->label ? : chip_name, chan);
+                       led->cdev.name = name;
+               }
 
-               led->cdev.name = name;
                led->cdev.brightness_set = lp5523_set_brightness;
                res = led_classdev_register(dev, &led->cdev);
                if (res < 0) {
@@ -917,7 +929,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
        if (ret)
                goto fail1;
 
-       dev_info(&client->dev, "LP5523 Programmable led chip found\n");
+       dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
 
        /* Initialize engines */
        for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
@@ -945,7 +957,8 @@ static int __devinit lp5523_probe(struct i2c_client *client,
                INIT_WORK(&chip->leds[led].brightness_work,
                        lp5523_led_brightness_work);
 
-               ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
+               ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata,
+                               id->name);
                if (ret) {
                        dev_err(&client->dev, "error initializing leds\n");
                        goto fail2;
@@ -970,7 +983,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
 fail2:
        for (i = 0; i < chip->num_leds; i++) {
                led_classdev_unregister(&chip->leds[i].cdev);
-               cancel_work_sync(&chip->leds[i].brightness_work);
+               flush_work(&chip->leds[i].brightness_work);
        }
 fail1:
        if (pdata->enable)
@@ -985,11 +998,14 @@ static int lp5523_remove(struct i2c_client *client)
        struct lp5523_chip *chip = i2c_get_clientdata(client);
        int i;
 
+       /* Disable engine mode */
+       lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+
        lp5523_unregister_sysfs(client);
 
        for (i = 0; i < chip->num_leds; i++) {
                led_classdev_unregister(&chip->leds[i].cdev);
-               cancel_work_sync(&chip->leds[i].brightness_work);
+               flush_work(&chip->leds[i].brightness_work);
        }
 
        if (chip->pdata->enable)
@@ -1000,7 +1016,8 @@ static int lp5523_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lp5523_id[] = {
-       { "lp5523", 0 },
+       { "lp5523",  LP5523 },
+       { "lp55231", LP55231 },
        { }
 };
 
@@ -1008,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, lp5523_id);
 
 static struct i2c_driver lp5523_driver = {
        .driver = {
-               .name   = "lp5523",
+               .name   = "lp5523x",
        },
        .probe          = lp5523_probe,
        .remove         = lp5523_remove,
index edcd706..2f2f9c4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/platform_data/leds-pca9633.h>
 
 /* LED select registers determine the source that drives LED outputs */
 #define PCA9633_LED_OFF                0x0     /* LED driver off */
@@ -96,13 +97,13 @@ static int __devinit pca9633_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct pca9633_led *pca9633;
-       struct led_platform_data *pdata;
+       struct pca9633_platform_data *pdata;
        int i, err;
 
        pdata = client->dev.platform_data;
 
        if (pdata) {
-               if (pdata->num_leds <= 0 || pdata->num_leds > 4) {
+               if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) {
                        dev_err(&client->dev, "board info must claim at most 4 LEDs");
                        return -EINVAL;
                }
@@ -119,14 +120,14 @@ static int __devinit pca9633_probe(struct i2c_client *client,
                pca9633[i].led_num = i;
 
                /* Platform data can specify LED names and default triggers */
-               if (pdata && i < pdata->num_leds) {
-                       if (pdata->leds[i].name)
+               if (pdata && i < pdata->leds.num_leds) {
+                       if (pdata->leds.leds[i].name)
                                snprintf(pca9633[i].name,
                                         sizeof(pca9633[i].name), "pca9633:%s",
-                                        pdata->leds[i].name);
-                       if (pdata->leds[i].default_trigger)
+                                        pdata->leds.leds[i].name);
+                       if (pdata->leds.leds[i].default_trigger)
                                pca9633[i].led_cdev.default_trigger =
-                                       pdata->leds[i].default_trigger;
+                                       pdata->leds.leds[i].default_trigger;
                } else {
                        snprintf(pca9633[i].name, sizeof(pca9633[i].name),
                                 "pca9633:%d", i);
@@ -145,6 +146,10 @@ static int __devinit pca9633_probe(struct i2c_client *client,
        /* Disable LED all-call address and set normal mode */
        i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
 
+       /* Configure output: open-drain or totem pole (push-pull) */
+       if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN)
+               i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01);
+
        /* Turn off LEDs */
        i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
 
index 4c62113..88f23f8 100644 (file)
@@ -201,7 +201,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
        struct regulator *isink, *dcdc;
        struct wm8350_led *led;
        struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
-       int ret, i;
+       int i;
 
        if (pdata == NULL) {
                dev_err(&pdev->dev, "no platform data\n");
@@ -214,24 +214,21 @@ static int wm8350_led_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       isink = regulator_get(&pdev->dev, "led_isink");
+       isink = devm_regulator_get(&pdev->dev, "led_isink");
        if (IS_ERR(isink)) {
                printk(KERN_ERR "%s: can't get ISINK\n", __func__);
                return PTR_ERR(isink);
        }
 
-       dcdc = regulator_get(&pdev->dev, "led_vcc");
+       dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
        if (IS_ERR(dcdc)) {
                printk(KERN_ERR "%s: can't get DCDC\n", __func__);
-               ret = PTR_ERR(dcdc);
-               goto err_isink;
+               return PTR_ERR(dcdc);
        }
 
        led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
-       if (led == NULL) {
-               ret = -ENOMEM;
-               goto err_dcdc;
-       }
+       if (led == NULL)
+               return -ENOMEM;
 
        led->cdev.brightness_set = wm8350_led_set;
        led->cdev.default_trigger = pdata->default_trigger;
@@ -257,17 +254,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
        led->value = LED_OFF;
        platform_set_drvdata(pdev, led);
 
-       ret = led_classdev_register(&pdev->dev, &led->cdev);
-       if (ret < 0)
-               goto err_dcdc;
-
-       return 0;
-
- err_dcdc:
-       regulator_put(dcdc);
- err_isink:
-       regulator_put(isink);
-       return ret;
+       return led_classdev_register(&pdev->dev, &led->cdev);
 }
 
 static int wm8350_led_remove(struct platform_device *pdev)
@@ -277,8 +264,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
        led_classdev_unregister(&led->cdev);
        flush_work(&led->work);
        wm8350_led_disable(led);
-       regulator_put(led->dcdc);
-       regulator_put(led->isink);
        return 0;
 }
 
index d02acd4..4c50365 100644 (file)
@@ -32,6 +32,8 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
        return led_cdev->brightness;
 }
 
+void led_stop_software_blink(struct led_classdev *led_cdev);
+
 extern struct rw_semaphore leds_list_lock;
 extern struct list_head leds_list;
 
index 99c7335..b151b7c 100644 (file)
@@ -60,16 +60,6 @@ config ATMEL_PWM
          purposes including software controlled power-efficient backlights
          on LCD displays, motor control, and waveform generation.
 
-config AB8500_PWM
-       bool "AB8500 PWM support"
-       depends on AB8500_CORE && ARCH_U8500
-       select HAVE_PWM
-       depends on !PWM
-       help
-         This driver exports functions to enable/disble/config/free Pulse
-         Width Modulation in the Analog Baseband Chip AB8500.
-         It is used by led and backlight driver to control the intensity.
-
 config ATMEL_TCLIB
        bool "Atmel AT32/AT91 Timer/Counter Library"
        depends on (AVR32 || ARCH_AT91)
index b88df7a..2129377 100644 (file)
@@ -44,7 +44,6 @@ obj-$(CONFIG_VMWARE_BALLOON)  += vmw_balloon.o
 obj-$(CONFIG_ARM_CHARLCD)      += arm-charlcd.o
 obj-$(CONFIG_PCH_PHUB)         += pch_phub.o
 obj-y                          += ti-st/
-obj-$(CONFIG_AB8500_PWM)       += ab8500-pwm.o
 obj-y                          += lis3lv02d/
 obj-y                          += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
index d7c6b83..ed81720 100644 (file)
@@ -1,6 +1,5 @@
 menuconfig PWM
        bool "Pulse-Width Modulation (PWM) Support"
-       depends on !MACH_JZ4740 && !PUV3_PWM
        help
          Generic Pulse-Width Modulation (PWM) support.
 
@@ -29,6 +28,15 @@ menuconfig PWM
 
 if PWM
 
+config PWM_AB8500
+       tristate "AB8500 PWM support"
+       depends on AB8500_CORE && ARCH_U8500
+       help
+         Generic PWM framework driver for Analog Baseband AB8500.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-ab8500.
+
 config PWM_BFIN
        tristate "Blackfin PWM support"
        depends on BFIN_GPTIMERS
@@ -47,6 +55,16 @@ config PWM_IMX
          To compile this driver as a module, choose M here: the module
          will be called pwm-imx.
 
+config PWM_JZ4740
+       tristate "Ingenic JZ4740 PWM support"
+       depends on MACH_JZ4740
+       help
+         Generic PWM framework driver for Ingenic JZ4740 based
+         machines.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-jz4740.
+
 config PWM_LPC32XX
        tristate "LPC32XX PWM support"
        depends on ARCH_LPC32XX
@@ -67,6 +85,15 @@ config PWM_MXS
          To compile this driver as a module, choose M here: the module
          will be called pwm-mxs.
 
+config PWM_PUV3
+       tristate "PKUnity NetBook-0916 PWM support"
+       depends on ARCH_PUV3
+       help
+         Generic PWM framework driver for PKUnity NetBook-0916.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-puv3.
+
 config PWM_PXA
        tristate "PXA PWM support"
        depends on ARCH_PXA
index 78f123d..acfe482 100644 (file)
@@ -1,8 +1,11 @@
 obj-$(CONFIG_PWM)              += core.o
+obj-$(CONFIG_PWM_AB8500)       += pwm-ab8500.o
 obj-$(CONFIG_PWM_BFIN)         += pwm-bfin.o
 obj-$(CONFIG_PWM_IMX)          += pwm-imx.o
+obj-$(CONFIG_PWM_JZ4740)       += pwm-jz4740.o
 obj-$(CONFIG_PWM_LPC32XX)      += pwm-lpc32xx.o
 obj-$(CONFIG_PWM_MXS)          += pwm-mxs.o
+obj-$(CONFIG_PWM_PUV3)         += pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)          += pwm-pxa.o
 obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
 obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
index c6e0507..f5acdaa 100644 (file)
@@ -371,13 +371,35 @@ EXPORT_SYMBOL_GPL(pwm_free);
  */
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-       if (!pwm || period_ns == 0 || duty_ns > period_ns)
+       if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
                return -EINVAL;
 
        return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
 }
 EXPORT_SYMBOL_GPL(pwm_config);
 
+/**
+ * pwm_set_polarity() - configure the polarity of a PWM signal
+ * @pwm: PWM device
+ * @polarity: new polarity of the PWM signal
+ *
+ * Note that the polarity cannot be configured while the PWM device is enabled
+ */
+int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+       if (!pwm || !pwm->chip->ops)
+               return -EINVAL;
+
+       if (!pwm->chip->ops->set_polarity)
+               return -ENOSYS;
+
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               return -EBUSY;
+
+       return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
+}
+EXPORT_SYMBOL_GPL(pwm_set_polarity);
+
 /**
  * pwm_enable() - start a PWM output toggling
  * @pwm: PWM device
@@ -624,6 +646,64 @@ out:
 }
 EXPORT_SYMBOL_GPL(pwm_put);
 
+static void devm_pwm_release(struct device *dev, void *res)
+{
+       pwm_put(*(struct pwm_device **)res);
+}
+
+/**
+ * devm_pwm_get() - resource managed pwm_get()
+ * @dev: device for PWM consumer
+ * @con_id: consumer name
+ *
+ * This function performs like pwm_get() but the acquired PWM device will
+ * automatically be released on driver detach.
+ */
+struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
+{
+       struct pwm_device **ptr, *pwm;
+
+       ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       pwm = pwm_get(dev, con_id);
+       if (!IS_ERR(pwm)) {
+               *ptr = pwm;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return pwm;
+}
+EXPORT_SYMBOL_GPL(devm_pwm_get);
+
+static int devm_pwm_match(struct device *dev, void *res, void *data)
+{
+       struct pwm_device **p = res;
+
+       if (WARN_ON(!p || !*p))
+               return 0;
+
+       return *p == data;
+}
+
+/**
+ * devm_pwm_put() - resource managed pwm_put()
+ * @dev: device for PWM consumer
+ * @pwm: PWM device
+ *
+ * Release a PWM previously allocated using devm_pwm_get(). Calling this
+ * function is usually not needed because devm-allocated resources are
+ * automatically released on driver detach.
+ */
+void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
+{
+       WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm));
+}
+EXPORT_SYMBOL_GPL(devm_pwm_put);
+
 #ifdef CONFIG_DEBUG_FS
 static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
 {
similarity index 52%
rename from drivers/misc/ab8500-pwm.c
rename to drivers/pwm/pwm-ab8500.c
index d7a9aa1..cfb72ca 100644 (file)
 #define ENABLE_PWM                     1
 #define DISABLE_PWM                    0
 
-struct pwm_device {
-       struct device *dev;
-       struct list_head node;
-       const char *label;
-       unsigned int pwm_id;
+struct ab8500_pwm_chip {
+       struct pwm_chip chip;
 };
 
-static LIST_HEAD(pwm_list);
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                            int duty_ns, int period_ns)
 {
        int ret = 0;
        unsigned int higher_val, lower_val;
@@ -50,95 +46,94 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
         */
        higher_val = ((duty_ns & 0x0300) >> 8);
 
-       reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
+       reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2);
 
-       ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+       ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
                        reg, (u8)lower_val);
        if (ret < 0)
                return ret;
-       ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+       ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
                        (reg + 1), (u8)higher_val);
 
        return ret;
 }
-EXPORT_SYMBOL(pwm_config);
 
-int pwm_enable(struct pwm_device *pwm)
+static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        int ret;
 
-       ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+       ret = abx500_mask_and_set_register_interruptible(chip->dev,
                                AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
-                               1 << (pwm->pwm_id-1), ENABLE_PWM);
+                               1 << (chip->base - 1), ENABLE_PWM);
        if (ret < 0)
-               dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
                                                        pwm->label, ret);
        return ret;
 }
-EXPORT_SYMBOL(pwm_enable);
 
-void pwm_disable(struct pwm_device *pwm)
+static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        int ret;
 
-       ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+       ret = abx500_mask_and_set_register_interruptible(chip->dev,
                                AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
-                               1 << (pwm->pwm_id-1), DISABLE_PWM);
+                               1 << (chip->base - 1), DISABLE_PWM);
        if (ret < 0)
-               dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
                                                        pwm->label, ret);
        return;
 }
-EXPORT_SYMBOL(pwm_disable);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       pwm->label = label;
-                       pwm->pwm_id = pwm_id;
-                       return pwm;
-               }
-       }
-
-       return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(pwm_request);
 
-void pwm_free(struct pwm_device *pwm)
-{
-       pwm_disable(pwm);
-}
-EXPORT_SYMBOL(pwm_free);
+static const struct pwm_ops ab8500_pwm_ops = {
+       .config = ab8500_pwm_config,
+       .enable = ab8500_pwm_enable,
+       .disable = ab8500_pwm_disable,
+};
 
 static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
 {
-       struct pwm_device *pwm;
+       struct ab8500_pwm_chip *ab8500;
+       int err;
+
        /*
         * Nothing to be done in probe, this is required to get the
         * device which is required for ab8500 read and write
         */
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
+       ab8500 = kzalloc(sizeof(*ab8500), GFP_KERNEL);
+       if (ab8500 == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
                return -ENOMEM;
        }
-       pwm->dev = &pdev->dev;
-       pwm->pwm_id = pdev->id;
-       list_add_tail(&pwm->node, &pwm_list);
-       platform_set_drvdata(pdev, pwm);
-       dev_dbg(pwm->dev, "pwm probe successful\n");
+
+       ab8500->chip.dev = &pdev->dev;
+       ab8500->chip.ops = &ab8500_pwm_ops;
+       ab8500->chip.base = pdev->id;
+       ab8500->chip.npwm = 1;
+
+       err = pwmchip_add(&ab8500->chip);
+       if (err < 0) {
+               kfree(ab8500);
+               return err;
+       }
+
+       dev_dbg(&pdev->dev, "pwm probe successful\n");
+       platform_set_drvdata(pdev, ab8500);
+
        return 0;
 }
 
 static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
 {
-       struct pwm_device *pwm = platform_get_drvdata(pdev);
-       list_del(&pwm->node);
+       struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev);
+       int err;
+
+       err = pwmchip_remove(&ab8500->chip);
+       if (err < 0)
+               return err;
+
        dev_dbg(&pdev->dev, "pwm driver removed\n");
-       kfree(pwm);
+       kfree(ab8500);
+
        return 0;
 }
 
@@ -150,19 +145,8 @@ static struct platform_driver ab8500_pwm_driver = {
        .probe = ab8500_pwm_probe,
        .remove = __devexit_p(ab8500_pwm_remove),
 };
+module_platform_driver(ab8500_pwm_driver);
 
-static int __init ab8500_pwm_init(void)
-{
-       return platform_driver_register(&ab8500_pwm_driver);
-}
-
-static void __exit ab8500_pwm_exit(void)
-{
-       platform_driver_unregister(&ab8500_pwm_driver);
-}
-
-subsys_initcall(ab8500_pwm_init);
-module_exit(ab8500_pwm_exit);
 MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
 MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
 MODULE_ALIAS("platform:ab8500-pwm");
index d53c4e7..5da8e18 100644 (file)
@@ -69,9 +69,6 @@ static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        unsigned long period, duty;
        unsigned long long val;
 
-       if (duty_ns < 0 || duty_ns > period_ns)
-               return -EINVAL;
-
        val = (unsigned long long)get_sclk() * period_ns;
        do_div(val, NSEC_PER_SEC);
        period = val;
index 2a0b353..8a5d3ae 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pwm.h>
-#include <mach/hardware.h>
-
+#include <linux/of_device.h>
 
 /* i.MX1 and i.MX21 share the same PWM function block: */
 
@@ -25,6 +24,7 @@
 #define MX1_PWMS    0x04   /* PWM Sample Register */
 #define MX1_PWMP    0x08   /* PWM Period Register */
 
+#define MX1_PWMC_EN            (1 << 4)
 
 /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
 
 #define MX3_PWMCR_EN              (1 << 0)
 
 struct imx_chip {
-       struct clk      *clk;
+       struct clk      *clk_per;
+       struct clk      *clk_ipg;
 
-       int             clk_enabled;
+       int             enabled;
        void __iomem    *mmio_base;
 
        struct pwm_chip chip;
+
+       int (*config)(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns);
+       void (*set_enable)(struct pwm_chip *chip, bool enable);
 };
 
 #define to_imx_chip(chip)      container_of(chip, struct imx_chip, chip)
 
-static int imx_pwm_config(struct pwm_chip *chip,
+static int imx_pwm_config_v1(struct pwm_chip *chip,
                struct pwm_device *pwm, int duty_ns, int period_ns)
 {
        struct imx_chip *imx = to_imx_chip(chip);
 
-       if (!(cpu_is_mx1() || cpu_is_mx21())) {
-               unsigned long long c;
-               unsigned long period_cycles, duty_cycles, prescale;
-               u32 cr;
-
-               c = clk_get_rate(imx->clk);
-               c = c * period_ns;
-               do_div(c, 1000000000);
-               period_cycles = c;
-
-               prescale = period_cycles / 0x10000 + 1;
-
-               period_cycles /= prescale;
-               c = (unsigned long long)period_cycles * duty_ns;
-               do_div(c, period_ns);
-               duty_cycles = c;
-
-               /*
-                * according to imx pwm RM, the real period value should be
-                * PERIOD value in PWMPR plus 2.
-                */
-               if (period_cycles > 2)
-                       period_cycles -= 2;
-               else
-                       period_cycles = 0;
-
-               writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
-               writel(period_cycles, imx->mmio_base + MX3_PWMPR);
-
-               cr = MX3_PWMCR_PRESCALER(prescale) |
-                       MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
-                       MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
-
-               if (cpu_is_mx25())
-                       cr |= MX3_PWMCR_CLKSRC_IPG;
-               else
-                       cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
-
-               writel(cr, imx->mmio_base + MX3_PWMCR);
-       } else if (cpu_is_mx1() || cpu_is_mx21()) {
-               /* The PWM subsystem allows for exact frequencies. However,
-                * I cannot connect a scope on my device to the PWM line and
-                * thus cannot provide the program the PWM controller
-                * exactly. Instead, I'm relying on the fact that the
-                * Bootloader (u-boot or WinCE+haret) has programmed the PWM
-                * function group already. So I'll just modify the PWM sample
-                * register to follow the ratio of duty_ns vs. period_ns
-                * accordingly.
-                *
-                * This is good enough for programming the brightness of
-                * the LCD backlight.
-                *
-                * The real implementation would divide PERCLK[0] first by
-                * both the prescaler (/1 .. /128) and then by CLKSEL
-                * (/2 .. /16).
-                */
-               u32 max = readl(imx->mmio_base + MX1_PWMP);
-               u32 p = max * duty_ns / period_ns;
-               writel(max - p, imx->mmio_base + MX1_PWMS);
-       } else {
-               BUG();
-       }
+       /*
+        * The PWM subsystem allows for exact frequencies. However,
+        * I cannot connect a scope on my device to the PWM line and
+        * thus cannot provide the program the PWM controller
+        * exactly. Instead, I'm relying on the fact that the
+        * Bootloader (u-boot or WinCE+haret) has programmed the PWM
+        * function group already. So I'll just modify the PWM sample
+        * register to follow the ratio of duty_ns vs. period_ns
+        * accordingly.
+        *
+        * This is good enough for programming the brightness of
+        * the LCD backlight.
+        *
+        * The real implementation would divide PERCLK[0] first by
+        * both the prescaler (/1 .. /128) and then by CLKSEL
+        * (/2 .. /16).
+        */
+       u32 max = readl(imx->mmio_base + MX1_PWMP);
+       u32 p = max * duty_ns / period_ns;
+       writel(max - p, imx->mmio_base + MX1_PWMS);
 
        return 0;
 }
 
+static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       u32 val;
+
+       val = readl(imx->mmio_base + MX1_PWMC);
+
+       if (enable)
+               val |= MX1_PWMC_EN;
+       else
+               val &= ~MX1_PWMC_EN;
+
+       writel(val, imx->mmio_base + MX1_PWMC);
+}
+
+static int imx_pwm_config_v2(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, duty_cycles, prescale;
+       u32 cr;
+
+       c = clk_get_rate(imx->clk_per);
+       c = c * period_ns;
+       do_div(c, 1000000000);
+       period_cycles = c;
+
+       prescale = period_cycles / 0x10000 + 1;
+
+       period_cycles /= prescale;
+       c = (unsigned long long)period_cycles * duty_ns;
+       do_div(c, period_ns);
+       duty_cycles = c;
+
+       /*
+        * according to imx pwm RM, the real period value should be
+        * PERIOD value in PWMPR plus 2.
+        */
+       if (period_cycles > 2)
+               period_cycles -= 2;
+       else
+               period_cycles = 0;
+
+       writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
+       writel(period_cycles, imx->mmio_base + MX3_PWMPR);
+
+       cr = MX3_PWMCR_PRESCALER(prescale) |
+               MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
+               MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
+
+       if (imx->enabled)
+               cr |= MX3_PWMCR_EN;
+
+       writel(cr, imx->mmio_base + MX3_PWMCR);
+
+       return 0;
+}
+
+static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       u32 val;
+
+       val = readl(imx->mmio_base + MX3_PWMCR);
+
+       if (enable)
+               val |= MX3_PWMCR_EN;
+       else
+               val &= ~MX3_PWMCR_EN;
+
+       writel(val, imx->mmio_base + MX3_PWMCR);
+}
+
+static int imx_pwm_config(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       int ret;
+
+       ret = clk_prepare_enable(imx->clk_ipg);
+       if (ret)
+               return ret;
+
+       ret = imx->config(chip, pwm, duty_ns, period_ns);
+
+       clk_disable_unprepare(imx->clk_ipg);
+
+       return ret;
+}
+
 static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct imx_chip *imx = to_imx_chip(chip);
-       int rc = 0;
+       int ret;
 
-       if (!imx->clk_enabled) {
-               rc = clk_prepare_enable(imx->clk);
-               if (!rc)
-                       imx->clk_enabled = 1;
-       }
-       return rc;
+       ret = clk_prepare_enable(imx->clk_per);
+       if (ret)
+               return ret;
+
+       imx->set_enable(chip, true);
+
+       imx->enabled = 1;
+
+       return 0;
 }
 
 static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct imx_chip *imx = to_imx_chip(chip);
 
-       writel(0, imx->mmio_base + MX3_PWMCR);
+       imx->set_enable(chip, false);
 
-       if (imx->clk_enabled) {
-               clk_disable_unprepare(imx->clk);
-               imx->clk_enabled = 0;
-       }
+       clk_disable_unprepare(imx->clk_per);
+       imx->enabled = 0;
 }
 
 static struct pwm_ops imx_pwm_ops = {
@@ -153,30 +208,66 @@ static struct pwm_ops imx_pwm_ops = {
        .owner = THIS_MODULE,
 };
 
+struct imx_pwm_data {
+       int (*config)(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns);
+       void (*set_enable)(struct pwm_chip *chip, bool enable);
+};
+
+static struct imx_pwm_data imx_pwm_data_v1 = {
+       .config = imx_pwm_config_v1,
+       .set_enable = imx_pwm_set_enable_v1,
+};
+
+static struct imx_pwm_data imx_pwm_data_v2 = {
+       .config = imx_pwm_config_v2,
+       .set_enable = imx_pwm_set_enable_v2,
+};
+
+static const struct of_device_id imx_pwm_dt_ids[] = {
+       { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
+       { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
+
 static int __devinit imx_pwm_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(imx_pwm_dt_ids, &pdev->dev);
+       struct imx_pwm_data *data;
        struct imx_chip *imx;
        struct resource *r;
        int ret = 0;
 
+       if (!of_id)
+               return -ENODEV;
+
        imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
        if (imx == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
                return -ENOMEM;
        }
 
-       imx->clk = devm_clk_get(&pdev->dev, "pwm");
+       imx->clk_per = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(imx->clk_per)) {
+               dev_err(&pdev->dev, "getting per clock failed with %ld\n",
+                               PTR_ERR(imx->clk_per));
+               return PTR_ERR(imx->clk_per);
+       }
 
-       if (IS_ERR(imx->clk))
-               return PTR_ERR(imx->clk);
+       imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(imx->clk_ipg)) {
+               dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
+                               PTR_ERR(imx->clk_ipg));
+               return PTR_ERR(imx->clk_ipg);
+       }
 
        imx->chip.ops = &imx_pwm_ops;
        imx->chip.dev = &pdev->dev;
        imx->chip.base = -1;
        imx->chip.npwm = 1;
 
-       imx->clk_enabled = 0;
-
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
@@ -187,6 +278,10 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev)
        if (imx->mmio_base == NULL)
                return -EADDRNOTAVAIL;
 
+       data = of_id->data;
+       imx->config = data->config;
+       imx->set_enable = data->set_enable;
+
        ret = pwmchip_add(&imx->chip);
        if (ret < 0)
                return ret;
@@ -208,23 +303,14 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev)
 
 static struct platform_driver imx_pwm_driver = {
        .driver         = {
-               .name   = "mxc_pwm",
+               .name   = "imx-pwm",
+               .of_match_table = of_match_ptr(imx_pwm_dt_ids),
        },
        .probe          = imx_pwm_probe,
        .remove         = __devexit_p(imx_pwm_remove),
 };
 
-static int __init imx_pwm_init(void)
-{
-       return platform_driver_register(&imx_pwm_driver);
-}
-arch_initcall(imx_pwm_init);
-
-static void __exit imx_pwm_exit(void)
-{
-       platform_driver_unregister(&imx_pwm_driver);
-}
-module_exit(imx_pwm_exit);
+module_platform_driver(imx_pwm_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
new file mode 100644 (file)
index 0000000..10250fc
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  JZ4740 platform PWM support
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#include <asm/mach-jz4740/gpio.h>
+#include <asm/mach-jz4740/timer.h>
+
+#define NUM_PWM 8
+
+static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
+       JZ_GPIO_PWM0,
+       JZ_GPIO_PWM1,
+       JZ_GPIO_PWM2,
+       JZ_GPIO_PWM3,
+       JZ_GPIO_PWM4,
+       JZ_GPIO_PWM5,
+       JZ_GPIO_PWM6,
+       JZ_GPIO_PWM7,
+};
+
+struct jz4740_pwm_chip {
+       struct pwm_chip chip;
+       struct clk *clk;
+};
+
+static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
+{
+       return container_of(chip, struct jz4740_pwm_chip, chip);
+}
+
+static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
+       int ret;
+
+       /*
+        * Timers 0 and 1 are used for system tasks, so they are unavailable
+        * for use as PWMs.
+        */
+       if (pwm->hwpwm < 2)
+               return -EBUSY;
+
+       ret = gpio_request(gpio, pwm->label);
+       if (ret) {
+               dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
+                       gpio, ret);
+               return ret;
+       }
+
+       jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
+
+       jz4740_timer_start(pwm->hwpwm);
+
+       return 0;
+}
+
+static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
+
+       jz4740_timer_set_ctrl(pwm->hwpwm, 0);
+
+       jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
+       gpio_free(gpio);
+
+       jz4740_timer_stop(pwm->hwpwm);
+}
+
+static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
+
+       ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
+       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+       jz4740_timer_enable(pwm->hwpwm);
+
+       return 0;
+}
+
+static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
+
+       ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
+       jz4740_timer_disable(pwm->hwpwm);
+       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+}
+
+static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                            int duty_ns, int period_ns)
+{
+       struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
+       unsigned long long tmp;
+       unsigned long period, duty;
+       unsigned int prescaler = 0;
+       uint16_t ctrl;
+       bool is_enabled;
+
+       tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns;
+       do_div(tmp, 1000000000);
+       period = tmp;
+
+       while (period > 0xffff && prescaler < 6) {
+               period >>= 2;
+               ++prescaler;
+       }
+
+       if (prescaler == 6)
+               return -EINVAL;
+
+       tmp = (unsigned long long)period * duty_ns;
+       do_div(tmp, period_ns);
+       duty = period - tmp;
+
+       if (duty >= period)
+               duty = period - 1;
+
+       is_enabled = jz4740_timer_is_enabled(pwm->hwpwm);
+       if (is_enabled)
+               jz4740_pwm_disable(chip, pwm);
+
+       jz4740_timer_set_count(pwm->hwpwm, 0);
+       jz4740_timer_set_duty(pwm->hwpwm, duty);
+       jz4740_timer_set_period(pwm->hwpwm, period);
+
+       ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
+               JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
+
+       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+
+       if (is_enabled)
+               jz4740_pwm_enable(chip, pwm);
+
+       return 0;
+}
+
+static const struct pwm_ops jz4740_pwm_ops = {
+       .request = jz4740_pwm_request,
+       .free = jz4740_pwm_free,
+       .config = jz4740_pwm_config,
+       .enable = jz4740_pwm_enable,
+       .disable = jz4740_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int __devinit jz4740_pwm_probe(struct platform_device *pdev)
+{
+       struct jz4740_pwm_chip *jz4740;
+       int ret;
+
+       jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
+       if (!jz4740)
+               return -ENOMEM;
+
+       jz4740->clk = clk_get(NULL, "ext");
+       if (IS_ERR(jz4740->clk))
+               return PTR_ERR(jz4740->clk);
+
+       jz4740->chip.dev = &pdev->dev;
+       jz4740->chip.ops = &jz4740_pwm_ops;
+       jz4740->chip.npwm = NUM_PWM;
+       jz4740->chip.base = -1;
+
+       ret = pwmchip_add(&jz4740->chip);
+       if (ret < 0) {
+               clk_put(jz4740->clk);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, jz4740);
+
+       return 0;
+}
+
+static int __devexit jz4740_pwm_remove(struct platform_device *pdev)
+{
+       struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = pwmchip_remove(&jz4740->chip);
+       if (ret < 0)
+               return ret;
+
+       clk_put(jz4740->clk);
+
+       return 0;
+}
+
+static struct platform_driver jz4740_pwm_driver = {
+       .driver = {
+               .name = "jz4740-pwm",
+               .owner = THIS_MODULE,
+       },
+       .probe = jz4740_pwm_probe,
+       .remove = __devexit_p(jz4740_pwm_remove),
+};
+module_platform_driver(jz4740_pwm_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver");
+MODULE_ALIAS("platform:jz4740-pwm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
new file mode 100644 (file)
index 0000000..2a93f37
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * linux/arch/unicore32/kernel/pwm.c
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ *     Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ *     Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+#include <mach/hardware.h>
+
+struct puv3_pwm_chip {
+       struct pwm_chip chip;
+       void __iomem *base;
+       struct clk *clk;
+       bool enabled;
+};
+
+static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
+{
+       return container_of(chip, struct puv3_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                          int duty_ns, int period_ns)
+{
+       unsigned long period_cycles, prescale, pv, dc;
+       struct puv3_pwm_chip *puv3 = to_puv3(chip);
+       unsigned long long c;
+
+       c = clk_get_rate(puv3->clk);
+       c = c * period_ns;
+       do_div(c, 1000000000);
+       period_cycles = c;
+
+       if (period_cycles < 1)
+               period_cycles = 1;
+
+       prescale = (period_cycles - 1) / 1024;
+       pv = period_cycles / (prescale + 1) - 1;
+
+       if (prescale > 63)
+               return -EINVAL;
+
+       if (duty_ns == period_ns)
+               dc = OST_PWMDCCR_FDCYCLE;
+       else
+               dc = (pv + 1) * duty_ns / period_ns;
+
+       /*
+        * NOTE: the clock to PWM has to be enabled first
+        * before writing to the registers
+        */
+       clk_prepare_enable(puv3->clk);
+
+       writel(prescale, puv3->base + OST_PWM_PWCR);
+       writel(pv - dc, puv3->base + OST_PWM_DCCR);
+       writel(pv, puv3->base + OST_PWM_PCR);
+
+       clk_disable_unprepare(puv3->clk);
+
+       return 0;
+}
+
+static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+       return clk_prepare_enable(puv3->clk);
+}
+
+static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+       clk_disable_unprepare(puv3->clk);
+}
+
+static const struct pwm_ops puv3_pwm_ops = {
+       .config = puv3_pwm_config,
+       .enable = puv3_pwm_enable,
+       .disable = puv3_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+       struct puv3_pwm_chip *puv3;
+       struct resource *r;
+       int ret;
+
+       puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
+       if (puv3 == NULL) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
+       if (IS_ERR(puv3->clk))
+               return PTR_ERR(puv3->clk);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       puv3->base = devm_request_and_ioremap(&pdev->dev, r);
+       if (puv3->base == NULL)
+               return -EADDRNOTAVAIL;
+
+       puv3->chip.dev = &pdev->dev;
+       puv3->chip.ops = &puv3_pwm_ops;
+       puv3->chip.base = -1;
+       puv3->chip.npwm = 1;
+
+       ret = pwmchip_add(&puv3->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, puv3);
+       return 0;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+       struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&puv3->chip);
+}
+
+static struct platform_driver puv3_pwm_driver = {
+       .driver = {
+               .name = "PKUnity-v3-PWM",
+       },
+       .probe = pwm_probe,
+       .remove = __devexit_p(pwm_remove),
+};
+module_platform_driver(puv3_pwm_driver);
+
+MODULE_LICENSE("GPL v2");
index bd5867a..260c3a8 100644 (file)
@@ -70,9 +70,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        unsigned long offset;
        int rc;
 
-       if (period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
-
        offset = pwm->hwpwm ? 0x10 : 0;
 
        c = clk_get_rate(pc->clk);
index e5187c0..023a3be 100644 (file)
@@ -126,9 +126,6 @@ static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
                return -ERANGE;
 
-       if (duty_ns > period_ns)
-               return -EINVAL;
-
        if (period_ns == s3c->period_ns &&
            duty_ns == s3c->duty_ns)
                return 0;
index 4b66889..d6d4cf0 100644 (file)
@@ -32,6 +32,7 @@
 #define CAP3                   0x10
 #define CAP4                   0x14
 #define ECCTL2                 0x2A
+#define ECCTL2_APWM_POL_LOW    BIT(10)
 #define ECCTL2_APWM_MODE       BIT(9)
 #define ECCTL2_SYNC_SEL_DISA   (BIT(7) | BIT(6))
 #define ECCTL2_TSCTR_FREERUN   BIT(4)
@@ -59,7 +60,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        unsigned long period_cycles, duty_cycles;
        unsigned int reg_val;
 
-       if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+       if (period_ns > NSEC_PER_SEC)
                return -ERANGE;
 
        c = pc->clk_rate;
@@ -111,6 +112,26 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        return 0;
 }
 
+static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+               enum pwm_polarity polarity)
+{
+       struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+       unsigned short reg_val;
+
+       pm_runtime_get_sync(pc->chip.dev);
+       reg_val = readw(pc->mmio_base + ECCTL2);
+       if (polarity == PWM_POLARITY_INVERSED)
+               /* Duty cycle defines LOW period of PWM */
+               reg_val |= ECCTL2_APWM_POL_LOW;
+       else
+               /* Duty cycle defines HIGH period of PWM */
+               reg_val &= ~ECCTL2_APWM_POL_LOW;
+
+       writew(reg_val, pc->mmio_base + ECCTL2);
+       pm_runtime_put_sync(pc->chip.dev);
+       return 0;
+}
+
 static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
@@ -157,6 +178,7 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 static const struct pwm_ops ecap_pwm_ops = {
        .free           = ecap_pwm_free,
        .config         = ecap_pwm_config,
+       .set_polarity   = ecap_pwm_set_polarity,
        .enable         = ecap_pwm_enable,
        .disable        = ecap_pwm_disable,
        .owner          = THIS_MODULE,
index b1996bc..d3c1dff 100644 (file)
 #define AQCTL_ZRO_FRCHIGH      BIT(1)
 #define AQCTL_ZRO_FRCTOGGLE    (BIT(1) | BIT(0))
 
+#define AQCTL_CHANA_POLNORMAL  (AQCTL_CAU_FRCLOW | AQCTL_PRD_FRCHIGH | \
+                               AQCTL_ZRO_FRCHIGH)
+#define AQCTL_CHANA_POLINVERSED        (AQCTL_CAU_FRCHIGH | AQCTL_PRD_FRCLOW | \
+                               AQCTL_ZRO_FRCLOW)
+#define AQCTL_CHANB_POLNORMAL  (AQCTL_CBU_FRCLOW | AQCTL_PRD_FRCHIGH | \
+                               AQCTL_ZRO_FRCHIGH)
+#define AQCTL_CHANB_POLINVERSED        (AQCTL_CBU_FRCHIGH | AQCTL_PRD_FRCLOW | \
+                               AQCTL_ZRO_FRCLOW)
+
 #define AQSFRC_RLDCSF_MASK     (BIT(7) | BIT(6))
 #define AQSFRC_RLDCSF_ZRO      0
 #define AQSFRC_RLDCSF_PRD      BIT(6)
@@ -105,6 +114,7 @@ struct ehrpwm_pwm_chip {
        unsigned int    clk_rate;
        void __iomem    *mmio_base;
        unsigned long period_cycles[NUM_PWM_CHANNEL];
+       enum pwm_polarity polarity[NUM_PWM_CHANNEL];
 };
 
 static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -165,39 +175,37 @@ static int set_prescale_div(unsigned long rqst_prescaler,
        return 1;
 }
 
-static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan,
-               unsigned long duty_cycles)
+static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)
 {
-       int cmp_reg, aqctl_reg;
+       int aqctl_reg;
        unsigned short aqctl_val, aqctl_mask;
 
        /*
-        * Channels can be configured from action qualifier module.
-        * Channel 0 configured with compare A register and for
-        * up-counter mode.
-        * Channel 1 configured with compare B register and for
-        * up-counter mode.
+        * Configure PWM output to HIGH/LOW level on counter
+        * reaches compare register value and LOW/HIGH level
+        * on counter value reaches period register value and
+        * zero value on counter
         */
        if (chan == 1) {
                aqctl_reg = AQCTLB;
-               cmp_reg = CMPB;
-               /* Configure PWM Low from compare B value */
-               aqctl_val = AQCTL_CBU_FRCLOW;
                aqctl_mask = AQCTL_CBU_MASK;
+
+               if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
+                       aqctl_val = AQCTL_CHANB_POLINVERSED;
+               else
+                       aqctl_val = AQCTL_CHANB_POLNORMAL;
        } else {
-               cmp_reg = CMPA;
                aqctl_reg = AQCTLA;
-               /* Configure PWM Low from compare A value*/
-               aqctl_val = AQCTL_CAU_FRCLOW;
                aqctl_mask = AQCTL_CAU_MASK;
+
+               if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
+                       aqctl_val = AQCTL_CHANA_POLINVERSED;
+               else
+                       aqctl_val = AQCTL_CHANA_POLNORMAL;
        }
 
-       /* Configure PWM High from period value and zero value */
-       aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH;
        aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;
-       ehrpwm_modify(pc->mmio_base,  aqctl_reg, aqctl_mask, aqctl_val);
-
-       ehrpwm_write(pc->mmio_base,  cmp_reg, duty_cycles);
+       ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val);
 }
 
 /*
@@ -211,9 +219,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        unsigned long long c;
        unsigned long period_cycles, duty_cycles;
        unsigned short ps_divval, tb_divval;
-       int i;
+       int i, cmp_reg;
 
-       if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+       if (period_ns > NSEC_PER_SEC)
                return -ERANGE;
 
        c = pc->clk_rate;
@@ -278,12 +286,29 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,
                        TBCTL_CTRMODE_UP);
 
-       /* Configure the channel for duty cycle */
-       configure_chans(pc, pwm->hwpwm, duty_cycles);
+       if (pwm->hwpwm == 1)
+               /* Channel 1 configured with compare B register */
+               cmp_reg = CMPB;
+       else
+               /* Channel 0 configured with compare A register */
+               cmp_reg = CMPA;
+
+       ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
+
        pm_runtime_put_sync(chip->dev);
        return 0;
 }
 
+static int ehrpwm_pwm_set_polarity(struct pwm_chip *chip,
+               struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+       struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+
+       /* Configuration of polarity in hardware delayed, do at enable */
+       pc->polarity[pwm->hwpwm] = polarity;
+       return 0;
+}
+
 static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
@@ -307,6 +332,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 
+       /* Channels polarity can be configured from action qualifier module */
+       configure_polarity(pc, pwm->hwpwm);
+
        /* Enable time counter for free_run */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
        return 0;
@@ -358,6 +386,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 static const struct pwm_ops ehrpwm_pwm_ops = {
        .free           = ehrpwm_pwm_free,
        .config         = ehrpwm_pwm_config,
+       .set_polarity   = ehrpwm_pwm_set_polarity,
        .enable         = ehrpwm_pwm_enable,
        .disable        = ehrpwm_pwm_disable,
        .owner          = THIS_MODULE,
index a5a55da..b6ad0de 100644 (file)
@@ -69,23 +69,9 @@ static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *a
                                  size_t count);
 static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
                                  size_t count);
-static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
-                                 size_t count);
-static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
-                                 size_t count);
-static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t dcssblk_seglist_show(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf);
 
 static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
 static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
-static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
-                  dcssblk_save_store);
-static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
-                  dcssblk_shared_store);
-static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
 
 static struct device *dcssblk_root_dev;
 
@@ -416,6 +402,8 @@ out:
        up_write(&dcssblk_devices_sem);
        return rc;
 }
+static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
+                  dcssblk_shared_store);
 
 /*
  * device attribute for save operation on current copy
@@ -476,6 +464,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
        up_write(&dcssblk_devices_sem);
        return count;
 }
+static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
+                  dcssblk_save_store);
 
 /*
  * device attribute for showing all segments in a device
@@ -502,6 +492,21 @@ dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
        up_read(&dcssblk_devices_sem);
        return i;
 }
+static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
+
+static struct attribute *dcssblk_dev_attrs[] = {
+       &dev_attr_shared.attr,
+       &dev_attr_save.attr,
+       &dev_attr_seglist.attr,
+       NULL,
+};
+static struct attribute_group dcssblk_dev_attr_group = {
+       .attrs = dcssblk_dev_attrs,
+};
+static const struct attribute_group *dcssblk_dev_attr_groups[] = {
+       &dcssblk_dev_attr_group,
+       NULL,
+};
 
 /*
  * device attribute for adding devices
@@ -590,6 +595,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
 
        dev_set_name(&dev_info->dev, dev_info->segment_name);
        dev_info->dev.release = dcssblk_release_segment;
+       dev_info->dev.groups = dcssblk_dev_attr_groups;
        INIT_LIST_HEAD(&dev_info->lh);
        dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
        if (dev_info->gd == NULL) {
@@ -637,21 +643,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
         * register the device
         */
        rc = device_register(&dev_info->dev);
-       if (rc) {
-               module_put(THIS_MODULE);
-               goto dev_list_del;
-       }
-       get_device(&dev_info->dev);
-       rc = device_create_file(&dev_info->dev, &dev_attr_shared);
-       if (rc)
-               goto unregister_dev;
-       rc = device_create_file(&dev_info->dev, &dev_attr_save);
-       if (rc)
-               goto unregister_dev;
-       rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
        if (rc)
-               goto unregister_dev;
+               goto put_dev;
 
+       get_device(&dev_info->dev);
        add_disk(dev_info->gd);
 
        switch (dev_info->segment_type) {
@@ -668,12 +663,11 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        rc = count;
        goto out;
 
-unregister_dev:
+put_dev:
        list_del(&dev_info->lh);
        blk_cleanup_queue(dev_info->dcssblk_queue);
        dev_info->gd->queue = NULL;
        put_disk(dev_info->gd);
-       device_unregister(&dev_info->dev);
        list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
                segment_unload(seg_info->segment_name);
        }
index c7275e3..899ffa1 100644 (file)
@@ -39,7 +39,6 @@
 #include "zcrypt_msgtype6.h"
 #include "zcrypt_pcixcc.h"
 #include "zcrypt_cca_key.h"
-#include "zcrypt_msgtype6.h"
 
 #define PCIXCC_MIN_MOD_SIZE     16     /*  128 bits    */
 #define PCIXCC_MIN_MOD_SIZE_OLD         64     /*  512 bits    */
index bddc97c..0e09d8f 100644 (file)
@@ -1403,7 +1403,7 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha,
        ctio->u.status1.scsi_status =
            __constant_cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID);
        ctio->u.status1.response_len = __constant_cpu_to_le16(8);
-       ((uint32_t *)ctio->u.status1.sense_data)[0] = cpu_to_be32(resp_code);
+       ctio->u.status1.sense_data[0] = resp_code;
 
        qla2x00_start_iocbs(ha, ha->req);
 }
index 4752f65..2358c16 100644 (file)
@@ -735,17 +735,6 @@ static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 tcm_qla2xxx_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
-static u16 tcm_qla2xxx_set_fabric_sense_len(struct se_cmd *se_cmd,
-                                       u32 sense_length)
-{
-       return 0;
-}
-
 /* Local pointer to allocated TCM configfs fabric module */
 struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
 struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
@@ -1691,8 +1680,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
        .queue_data_in                  = tcm_qla2xxx_queue_data_in,
        .queue_status                   = tcm_qla2xxx_queue_status,
        .queue_tm_rsp                   = tcm_qla2xxx_queue_tm_rsp,
-       .get_fabric_sense_len           = tcm_qla2xxx_get_fabric_sense_len,
-       .set_fabric_sense_len           = tcm_qla2xxx_set_fabric_sense_len,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
@@ -1740,8 +1727,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .queue_data_in                  = tcm_qla2xxx_queue_data_in,
        .queue_status                   = tcm_qla2xxx_queue_status,
        .queue_tm_rsp                   = tcm_qla2xxx_queue_tm_rsp,
-       .get_fabric_sense_len           = tcm_qla2xxx_get_fabric_sense_len,
-       .set_fabric_sense_len           = tcm_qla2xxx_set_fabric_sense_len,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
index 97c0f78..d6ce218 100644 (file)
@@ -427,7 +427,7 @@ int iscsit_reset_np_thread(
        return 0;
 }
 
-int iscsit_del_np_comm(struct iscsi_np *np)
+static int iscsit_del_np_comm(struct iscsi_np *np)
 {
        if (np->np_socket)
                sock_release(np->np_socket);
@@ -785,10 +785,6 @@ static int iscsit_handle_scsi_cmd(
 
        hdr                     = (struct iscsi_scsi_req *) buf;
        payload_length          = ntoh24(hdr->dlength);
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->data_length        = be32_to_cpu(hdr->data_length);
-       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
 
        /* FIXME; Add checks for AdditionalHeaderSegment */
 
@@ -852,7 +848,7 @@ done:
                                buf, conn);
        }
 
-       if ((hdr->data_length == payload_length) &&
+       if ((be32_to_cpu(hdr->data_length )== payload_length) &&
            (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
                pr_err("Expected Data Transfer Length and Length of"
                        " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
@@ -861,7 +857,7 @@ done:
                                buf, conn);
        }
 
-       if (payload_length > hdr->data_length) {
+       if (payload_length > be32_to_cpu(hdr->data_length)) {
                pr_err("DataSegmentLength: %u is greater than"
                        " EDTL: %u, protocol error.\n", payload_length,
                                hdr->data_length);
@@ -869,10 +865,10 @@ done:
                                buf, conn);
        }
 
-       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+       if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("DataSegmentLength: %u is greater than"
-                       " MaxRecvDataSegmentLength: %u, protocol error.\n",
-                       payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+                       " MaxXmitDataSegmentLength: %u, protocol error.\n",
+                       payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
                return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
                                buf, conn);
        }
@@ -932,8 +928,8 @@ done:
                spin_unlock_bh(&conn->sess->ttt_lock);
        } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
                cmd->targ_xfer_tag = 0xFFFFFFFF;
-       cmd->cmd_sn             = hdr->cmdsn;
-       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
+       cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
        cmd->first_burst_len    = payload_length;
 
        if (cmd->data_direction == DMA_FROM_DEVICE) {
@@ -952,8 +948,9 @@ done:
         * Initialize struct se_cmd descriptor from target_core_mod infrastructure
         */
        transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
-                       conn->sess->se_sess, hdr->data_length, cmd->data_direction,
-                       sam_task_attr, &cmd->sense_buffer[0]);
+                       conn->sess->se_sess, be32_to_cpu(hdr->data_length),
+                       cmd->data_direction, sam_task_attr,
+                       cmd->sense_buffer + 2);
 
        pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
                " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
@@ -1028,7 +1025,7 @@ attach_cmd:
                                1, 0, buf, cmd);
        }
 
-       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+       iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
        /*
         * If no Immediate Data is attached, it's OK to return now.
@@ -1194,11 +1191,6 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
 
        hdr                     = (struct iscsi_data *) buf;
        payload_length          = ntoh24(hdr->dlength);
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->ttt                = be32_to_cpu(hdr->ttt);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
-       hdr->datasn             = be32_to_cpu(hdr->datasn);
-       hdr->offset             = be32_to_cpu(hdr->offset);
 
        if (!payload_length) {
                pr_err("DataOUT payload is ZERO, protocol error.\n");
@@ -1216,10 +1208,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
        }
        spin_unlock_bh(&conn->sess->session_stats_lock);
 
-       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+       if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("DataSegmentLength: %u is greater than"
-                       " MaxRecvDataSegmentLength: %u\n", payload_length,
-                       conn->conn_ops->MaxRecvDataSegmentLength);
+                       " MaxXmitDataSegmentLength: %u\n", payload_length,
+                       conn->conn_ops->MaxXmitDataSegmentLength);
                return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
                                        buf, conn);
        }
@@ -1250,7 +1242,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
        se_cmd = &cmd->se_cmd;
        iscsit_mod_dataout_timer(cmd);
 
-       if ((hdr->offset + payload_length) > cmd->se_cmd.data_length) {
+       if ((be32_to_cpu(hdr->offset) + payload_length) > cmd->se_cmd.data_length) {
                pr_err("DataOut Offset: %u, Length %u greater than"
                        " iSCSI Command EDTL %u, protocol error.\n",
                        hdr->offset, payload_length, cmd->se_cmd.data_length);
@@ -1333,7 +1325,8 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
        rx_size += payload_length;
        iov = &cmd->iov_data[0];
 
-       iov_ret = iscsit_map_iovec(cmd, iov, hdr->offset, payload_length);
+       iov_ret = iscsit_map_iovec(cmd, iov, be32_to_cpu(hdr->offset),
+                                  payload_length);
        if (iov_ret < 0)
                return -1;
 
@@ -1364,7 +1357,8 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
                u32 data_crc;
 
                data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
-                                                   hdr->offset, payload_length, padding,
+                                                   be32_to_cpu(hdr->offset),
+                                                   payload_length, padding,
                                                    cmd->pad_bytes);
 
                if (checksum != data_crc) {
@@ -1425,30 +1419,26 @@ static int iscsit_handle_nop_out(
 
        hdr                     = (struct iscsi_nopout *) buf;
        payload_length          = ntoh24(hdr->dlength);
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->ttt                = be32_to_cpu(hdr->ttt);
-       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
 
-       if ((hdr->itt == 0xFFFFFFFF) && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+       if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
                pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
                        " not set, protocol error.\n");
                return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
                                        buf, conn);
        }
 
-       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+       if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("NOPOUT Ping Data DataSegmentLength: %u is"
-                       " greater than MaxRecvDataSegmentLength: %u, protocol"
+                       " greater than MaxXmitDataSegmentLength: %u, protocol"
                        " error.\n", payload_length,
-                       conn->conn_ops->MaxRecvDataSegmentLength);
+                       conn->conn_ops->MaxXmitDataSegmentLength);
                return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
                                        buf, conn);
        }
 
        pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x,"
                " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
-               (hdr->itt == 0xFFFFFFFF) ? "Response" : "Request",
+               hdr->itt == RESERVED_ITT ? "Response" : "Request",
                hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
                payload_length);
        /*
@@ -1458,7 +1448,7 @@ static int iscsit_handle_nop_out(
         * Either way, make sure we allocate an struct iscsi_cmd, as both
         * can contain ping data.
         */
-       if (hdr->ttt == 0xFFFFFFFF) {
+       if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
                cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        return iscsit_add_reject(
@@ -1471,12 +1461,12 @@ static int iscsit_handle_nop_out(
                                                1 : 0);
                conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
                cmd->targ_xfer_tag      = 0xFFFFFFFF;
-               cmd->cmd_sn             = hdr->cmdsn;
-               cmd->exp_stat_sn        = hdr->exp_statsn;
+               cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
+               cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
                cmd->data_direction     = DMA_NONE;
        }
 
-       if (payload_length && (hdr->ttt == 0xFFFFFFFF)) {
+       if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
                rx_size = payload_length;
                ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
                if (!ping_data) {
@@ -1556,7 +1546,7 @@ static int iscsit_handle_nop_out(
                pr_debug("Ping Data: \"%s\"\n", ping_data);
        }
 
-       if (hdr->itt != 0xFFFFFFFF) {
+       if (hdr->itt != RESERVED_ITT) {
                if (!cmd) {
                        pr_err("Checking CmdSN for NOPOUT,"
                                " but cmd is NULL!\n");
@@ -1569,7 +1559,7 @@ static int iscsit_handle_nop_out(
                list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
                spin_unlock_bh(&conn->cmd_lock);
 
-               iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+               iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
                if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
                        iscsit_add_cmd_to_response_queue(cmd, conn,
@@ -1590,11 +1580,11 @@ static int iscsit_handle_nop_out(
                return 0;
        }
 
-       if (hdr->ttt != 0xFFFFFFFF) {
+       if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
                /*
                 * This was a response to a unsolicited NOPIN ping.
                 */
-               cmd = iscsit_find_cmd_from_ttt(conn, hdr->ttt);
+               cmd = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
                if (!cmd)
                        return -1;
 
@@ -1639,12 +1629,6 @@ static int iscsit_handle_task_mgt_cmd(
        u8 function;
 
        hdr                     = (struct iscsi_tm *) buf;
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->rtt                = be32_to_cpu(hdr->rtt);
-       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
-       hdr->refcmdsn           = be32_to_cpu(hdr->refcmdsn);
-       hdr->exp_datasn         = be32_to_cpu(hdr->exp_datasn);
        hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
        function = hdr->flags;
 
@@ -1655,9 +1639,9 @@ static int iscsit_handle_task_mgt_cmd(
 
        if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
            ((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
-            (hdr->rtt != ISCSI_RESERVED_TAG))) {
+            hdr->rtt != RESERVED_ITT)) {
                pr_err("RefTaskTag should be set to 0xFFFFFFFF.\n");
-               hdr->rtt = ISCSI_RESERVED_TAG;
+               hdr->rtt = RESERVED_ITT;
        }
 
        if ((function == ISCSI_TM_FUNC_TASK_REASSIGN) &&
@@ -1669,8 +1653,8 @@ static int iscsit_handle_task_mgt_cmd(
                                        buf, conn);
        }
        if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
-           (hdr->refcmdsn != ISCSI_RESERVED_TAG))
-               hdr->refcmdsn = ISCSI_RESERVED_TAG;
+           be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
+               hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
 
        cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
        if (!cmd)
@@ -1700,7 +1684,7 @@ static int iscsit_handle_task_mgt_cmd(
                transport_init_se_cmd(&cmd->se_cmd,
                                      &lio_target_fabric_configfs->tf_ops,
                                      conn->sess->se_sess, 0, DMA_NONE,
-                                     MSG_SIMPLE_TAG, &cmd->sense_buffer[0]);
+                                     MSG_SIMPLE_TAG, cmd->sense_buffer + 2);
 
                switch (function) {
                case ISCSI_TM_FUNC_ABORT_TASK:
@@ -1747,8 +1731,8 @@ static int iscsit_handle_task_mgt_cmd(
        cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
        cmd->init_task_tag      = hdr->itt;
        cmd->targ_xfer_tag      = 0xFFFFFFFF;
-       cmd->cmd_sn             = hdr->cmdsn;
-       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
+       cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
        se_tmr                  = cmd->se_cmd.se_tmr_req;
        tmr_req                 = cmd->tmr_req;
        /*
@@ -1832,7 +1816,7 @@ attach:
                                        ISCSI_REASON_PROTOCOL_ERROR,
                                        1, 0, buf, cmd);
        }
-       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+       iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
        if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE))
                return 0;
@@ -1869,15 +1853,11 @@ static int iscsit_handle_text_cmd(
 
        hdr                     = (struct iscsi_text *) buf;
        payload_length          = ntoh24(hdr->dlength);
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->ttt                = be32_to_cpu(hdr->ttt);
-       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
 
-       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+       if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("Unable to accept text parameter length: %u"
-                       "greater than MaxRecvDataSegmentLength %u.\n",
-                      payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+                       "greater than MaxXmitDataSegmentLength %u.\n",
+                      payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
                return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
                                        buf, conn);
        }
@@ -1989,15 +1969,15 @@ static int iscsit_handle_text_cmd(
        cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
        conn->sess->init_task_tag = cmd->init_task_tag  = hdr->itt;
        cmd->targ_xfer_tag      = 0xFFFFFFFF;
-       cmd->cmd_sn             = hdr->cmdsn;
-       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
+       cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
        cmd->data_direction     = DMA_NONE;
 
        spin_lock_bh(&conn->cmd_lock);
        list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
        spin_unlock_bh(&conn->cmd_lock);
 
-       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+       iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
        if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
                cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
@@ -2131,10 +2111,6 @@ static int iscsit_handle_logout_cmd(
 
        hdr                     = (struct iscsi_logout *) buf;
        reason_code             = (hdr->flags & 0x7f);
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->cid                = be16_to_cpu(hdr->cid);
-       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
-       hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
 
        if (tiqn) {
                spin_lock(&tiqn->logout_stats.lock);
@@ -2166,9 +2142,9 @@ static int iscsit_handle_logout_cmd(
        cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
        conn->sess->init_task_tag = cmd->init_task_tag  = hdr->itt;
        cmd->targ_xfer_tag      = 0xFFFFFFFF;
-       cmd->cmd_sn             = hdr->cmdsn;
-       cmd->exp_stat_sn        = hdr->exp_statsn;
-       cmd->logout_cid         = hdr->cid;
+       cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
+       cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
+       cmd->logout_cid         = be16_to_cpu(hdr->cid);
        cmd->logout_reason      = reason_code;
        cmd->data_direction     = DMA_NONE;
 
@@ -2178,7 +2154,7 @@ static int iscsit_handle_logout_cmd(
         */
        if ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) ||
           ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) &&
-           (hdr->cid == conn->cid)))
+           be16_to_cpu(hdr->cid) == conn->cid))
                logout_remove = 1;
 
        spin_lock_bh(&conn->cmd_lock);
@@ -2186,7 +2162,7 @@ static int iscsit_handle_logout_cmd(
        spin_unlock_bh(&conn->cmd_lock);
 
        if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY)
-               iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+               iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
        /*
         * Immediate commands are executed, well, immediately.
@@ -2219,11 +2195,6 @@ static int iscsit_handle_snack(
 
        hdr                     = (struct iscsi_snack *) buf;
        hdr->flags              &= ~ISCSI_FLAG_CMD_FINAL;
-       hdr->itt                = be32_to_cpu(hdr->itt);
-       hdr->ttt                = be32_to_cpu(hdr->ttt);
-       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
-       hdr->begrun             = be32_to_cpu(hdr->begrun);
-       hdr->runlength          = be32_to_cpu(hdr->runlength);
 
        pr_debug("Got ISCSI_INIT_SNACK, ITT: 0x%08x, ExpStatSN:"
                " 0x%08x, Type: 0x%02x, BegRun: 0x%08x, RunLength: 0x%08x,"
@@ -2243,13 +2214,18 @@ static int iscsit_handle_snack(
        switch (hdr->flags & ISCSI_FLAG_SNACK_TYPE_MASK) {
        case 0:
                return iscsit_handle_recovery_datain_or_r2t(conn, buf,
-                       hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength);
+                       hdr->itt,
+                       be32_to_cpu(hdr->ttt),
+                       be32_to_cpu(hdr->begrun),
+                       be32_to_cpu(hdr->runlength));
        case ISCSI_FLAG_SNACK_TYPE_STATUS:
-               return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt,
-                       hdr->begrun, hdr->runlength);
+               return iscsit_handle_status_snack(conn, hdr->itt,
+                       be32_to_cpu(hdr->ttt),
+                       be32_to_cpu(hdr->begrun), be32_to_cpu(hdr->runlength));
        case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
-               return iscsit_handle_data_ack(conn, hdr->ttt, hdr->begrun,
-                       hdr->runlength);
+               return iscsit_handle_data_ack(conn, be32_to_cpu(hdr->ttt),
+                       be32_to_cpu(hdr->begrun),
+                       be32_to_cpu(hdr->runlength));
        case ISCSI_FLAG_SNACK_TYPE_RDATA:
                /* FIXME: Support R-Data SNACK */
                pr_err("R-Data SNACK Not Supported.\n");
@@ -2414,7 +2390,7 @@ static int iscsit_send_conn_drop_async_message(
        hdr                     = (struct iscsi_async *) cmd->pdu;
        hdr->opcode             = ISCSI_OP_ASYNC_EVENT;
        hdr->flags              = ISCSI_FLAG_CMD_FINAL;
-       cmd->init_task_tag      = 0xFFFFFFFF;
+       cmd->init_task_tag      = RESERVED_ITT;
        cmd->targ_xfer_tag      = 0xFFFFFFFF;
        put_unaligned_be64(0xFFFFFFFFFFFFFFFFULL, &hdr->rsvd4[0]);
        cmd->stat_sn            = conn->stat_sn++;
@@ -2536,12 +2512,17 @@ static int iscsit_send_data_in(
        else
                put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
 
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
-       hdr->ttt                = (hdr->flags & ISCSI_FLAG_DATA_ACK) ?
-                                  cpu_to_be32(cmd->targ_xfer_tag) :
-                                  0xFFFFFFFF;
-       hdr->statsn             = (set_statsn) ? cpu_to_be32(cmd->stat_sn) :
-                                               0xFFFFFFFF;
+       hdr->itt                = cmd->init_task_tag;
+
+       if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+               hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
+       else
+               hdr->ttt                = cpu_to_be32(0xFFFFFFFF);
+       if (set_statsn)
+               hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+       else
+               hdr->statsn             = cpu_to_be32(0xFFFFFFFF);
+
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
        hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
        hdr->datasn             = cpu_to_be32(datain.data_sn);
@@ -2708,7 +2689,7 @@ static int iscsit_send_logout_response(
        hdr->opcode             = ISCSI_OP_LOGOUT_RSP;
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hdr->response           = cmd->logout_response;
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
 
@@ -2759,7 +2740,7 @@ static int iscsit_send_unsolicited_nopin(
        memset(hdr, 0, ISCSI_HDR_LEN);
        hdr->opcode             = ISCSI_OP_NOOP_IN;
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
        cmd->stat_sn            = conn->stat_sn;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
@@ -2816,7 +2797,7 @@ static int iscsit_send_nopin_response(
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hton24(hdr->dlength, cmd->buf_ptr_size);
        put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
@@ -2906,7 +2887,7 @@ static int iscsit_send_r2t(
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        int_to_scsilun(cmd->se_cmd.orig_fe_lun,
                        (struct scsi_lun *)&hdr->lun);
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        spin_lock_bh(&conn->sess->ttt_lock);
        r2t->targ_xfer_tag      = conn->sess->targ_xfer_tag++;
        if (r2t->targ_xfer_tag == 0xFFFFFFFF)
@@ -3074,7 +3055,7 @@ static int iscsit_send_status(
        }
        hdr->response           = cmd->iscsi_response;
        hdr->cmd_status         = cmd->se_cmd.scsi_status;
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
 
        iscsit_increment_maxcmdsn(cmd, conn->sess);
@@ -3092,15 +3073,18 @@ static int iscsit_send_status(
        if (cmd->se_cmd.sense_buffer &&
           ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
            (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+               put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer);
+               cmd->se_cmd.scsi_sense_length += sizeof (__be16);
+
                padding         = -(cmd->se_cmd.scsi_sense_length) & 3;
-               hton24(hdr->dlength, cmd->se_cmd.scsi_sense_length);
-               iov[iov_count].iov_base = cmd->se_cmd.sense_buffer;
+               hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
+               iov[iov_count].iov_base = cmd->sense_buffer;
                iov[iov_count++].iov_len =
                                (cmd->se_cmd.scsi_sense_length + padding);
                tx_size += cmd->se_cmd.scsi_sense_length;
 
                if (padding) {
-                       memset(cmd->se_cmd.sense_buffer +
+                       memset(cmd->sense_buffer +
                                cmd->se_cmd.scsi_sense_length, 0, padding);
                        tx_size += padding;
                        pr_debug("Adding %u bytes of padding to"
@@ -3109,7 +3093,7 @@ static int iscsit_send_status(
 
                if (conn->conn_ops->DataDigest) {
                        iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
-                               cmd->se_cmd.sense_buffer,
+                               cmd->sense_buffer,
                                (cmd->se_cmd.scsi_sense_length + padding),
                                0, NULL, (u8 *)&cmd->data_crc);
 
@@ -3184,7 +3168,7 @@ static int iscsit_send_task_mgt_rsp(
        hdr->opcode             = ISCSI_OP_SCSI_TMFUNC_RSP;
        hdr->flags              = ISCSI_FLAG_CMD_FINAL;
        hdr->response           = iscsit_convert_tcm_tmr_rsp(se_tmr);
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
 
@@ -3236,7 +3220,7 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
                struct sockaddr_in * sock_in =
                        (struct sockaddr_in *)&np->np_sockaddr;
 
-               if (sock_in->sin_addr.s_addr == INADDR_ANY)
+               if (sock_in->sin_addr.s_addr == htonl(INADDR_ANY))
                        ret = true;
        }
 
@@ -3271,7 +3255,6 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                len += 1;
 
                if ((len + payload_len) > buffer_len) {
-                       spin_unlock(&tiqn->tiqn_tpg_lock);
                        end_of_buf = 1;
                        goto eob;
                }
@@ -3358,7 +3341,7 @@ static int iscsit_send_text_rsp(
        hdr->opcode             = ISCSI_OP_TEXT_RSP;
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hton24(hdr->dlength, text_length);
-       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->itt                = cmd->init_task_tag;
        hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
@@ -3424,6 +3407,7 @@ static int iscsit_send_reject(
        hdr->opcode             = ISCSI_OP_REJECT;
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hton24(hdr->dlength, ISCSI_HDR_LEN);
+       hdr->ffffffff           = cpu_to_be32(0xffffffff);
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
        hdr->exp_cmdsn  = cpu_to_be32(conn->sess->exp_cmd_sn);
index 12abb4c..f1e4f31 100644 (file)
@@ -38,4 +38,9 @@ extern struct kmem_cache *lio_cmd_cache;
 extern struct kmem_cache *lio_qr_cache;
 extern struct kmem_cache *lio_r2t_cache;
 
+extern struct idr sess_idr;
+extern struct mutex auth_id_lock;
+extern spinlock_t sess_idr_lock;
+
+
 #endif   /*** ISCSI_TARGET_H ***/
index a7b25e7..ff6fd4f 100644 (file)
@@ -135,7 +135,7 @@ static struct configfs_attribute *lio_target_portal_attrs[] = {
 
 #define MAX_PORTAL_LEN         256
 
-struct se_tpg_np *lio_target_call_addnptotpg(
+static struct se_tpg_np *lio_target_call_addnptotpg(
        struct se_portal_group *se_tpg,
        struct config_group *group,
        const char *name)
@@ -1034,6 +1034,9 @@ TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR);
 DEF_TPG_PARAM(MaxRecvDataSegmentLength);
 TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR);
 
+DEF_TPG_PARAM(MaxXmitDataSegmentLength);
+TPG_PARAM_ATTR(MaxXmitDataSegmentLength, S_IRUGO | S_IWUSR);
+
 DEF_TPG_PARAM(MaxBurstLength);
 TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR);
 
@@ -1079,6 +1082,7 @@ static struct configfs_attribute *lio_target_tpg_param_attrs[] = {
        &iscsi_tpg_param_InitialR2T.attr,
        &iscsi_tpg_param_ImmediateData.attr,
        &iscsi_tpg_param_MaxRecvDataSegmentLength.attr,
+       &iscsi_tpg_param_MaxXmitDataSegmentLength.attr,
        &iscsi_tpg_param_MaxBurstLength.attr,
        &iscsi_tpg_param_FirstBurstLength.attr,
        &iscsi_tpg_param_DefaultTime2Wait.attr,
@@ -1166,7 +1170,7 @@ static struct configfs_attribute *lio_target_tpg_attrs[] = {
 
 /* Start items for lio_target_tiqn_cit */
 
-struct se_portal_group *lio_target_tiqn_addtpg(
+static struct se_portal_group *lio_target_tiqn_addtpg(
        struct se_wwn *wwn,
        struct config_group *group,
        const char *name)
@@ -1216,7 +1220,7 @@ out:
        return NULL;
 }
 
-void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
+static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
 {
        struct iscsi_portal_group *tpg;
        struct iscsi_tiqn *tiqn;
@@ -1248,7 +1252,7 @@ static struct configfs_attribute *lio_target_wwn_attrs[] = {
        NULL,
 };
 
-struct se_wwn *lio_target_call_coreaddtiqn(
+static struct se_wwn *lio_target_call_coreaddtiqn(
        struct target_fabric_configfs *tf,
        struct config_group *group,
        const char *name)
@@ -1296,7 +1300,7 @@ struct se_wwn *lio_target_call_coreaddtiqn(
        return &tiqn->tiqn_wwn;
 }
 
-void lio_target_call_coredeltiqn(
+static void lio_target_call_coredeltiqn(
        struct se_wwn *wwn)
 {
        struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
@@ -1471,7 +1475,8 @@ static u32 iscsi_get_task_tag(struct se_cmd *se_cmd)
 {
        struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
 
-       return cmd->init_task_tag;
+       /* only used for printks or comparism with ->ref_task_tag */
+       return (__force u32)cmd->init_task_tag;
 }
 
 static int iscsi_get_cmd_state(struct se_cmd *se_cmd)
@@ -1542,29 +1547,6 @@ static int lio_queue_status(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 lio_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
-       unsigned char *buffer = se_cmd->sense_buffer;
-       /*
-        * From RFC-3720 10.4.7.  Data Segment - Sense and Response Data Segment
-        * 16-bit SenseLength.
-        */
-       buffer[0] = ((sense_length >> 8) & 0xff);
-       buffer[1] = (sense_length & 0xff);
-       /*
-        * Return two byte offset into allocated sense_buffer.
-        */
-       return 2;
-}
-
-static u16 lio_get_fabric_sense_len(void)
-{
-       /*
-        * Return two byte offset into allocated sense_buffer.
-        */
-       return 2;
-}
-
 static int lio_queue_tm_rsp(struct se_cmd *se_cmd)
 {
        struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
@@ -1748,8 +1730,6 @@ int iscsi_target_register_configfs(void)
        fabric->tf_ops.queue_data_in = &lio_queue_data_in;
        fabric->tf_ops.queue_status = &lio_queue_status;
        fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
-       fabric->tf_ops.set_fabric_sense_len = &lio_set_fabric_sense_len;
-       fabric->tf_ops.get_fabric_sense_len = &lio_get_fabric_sense_len;
        /*
         * Setup function pointers for generic logic in target_core_fabric_configfs.c
         */
index 8a908b2..2ba9f9b 100644 (file)
 #define NA_DATAOUT_TIMEOUT_RETRIES     5
 #define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15
 #define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1
-#define NA_NOPIN_TIMEOUT               5
+#define NA_NOPIN_TIMEOUT               15
 #define NA_NOPIN_TIMEOUT_MAX           60
 #define NA_NOPIN_TIMEOUT_MIN           3
-#define NA_NOPIN_RESPONSE_TIMEOUT      5
+#define NA_NOPIN_RESPONSE_TIMEOUT      30
 #define NA_NOPIN_RESPONSE_TIMEOUT_MAX  60
 #define NA_NOPIN_RESPONSE_TIMEOUT_MIN  3
 #define NA_RANDOM_DATAIN_PDU_OFFSETS   0
@@ -239,6 +239,7 @@ struct iscsi_conn_ops {
        u8      HeaderDigest;                   /* [0,1] == [None,CRC32C] */
        u8      DataDigest;                     /* [0,1] == [None,CRC32C] */
        u32     MaxRecvDataSegmentLength;       /* [512..2**24-1] */
+       u32     MaxXmitDataSegmentLength;       /* [512..2**24-1] */
        u8      OFMarker;                       /* [0,1] == [No,Yes] */
        u8      IFMarker;                       /* [0,1] == [No,Yes] */
        u32     OFMarkInt;                      /* [1..65535] */
@@ -360,7 +361,7 @@ struct iscsi_cmd {
        /* Command flags */
        enum cmd_flags_table    cmd_flags;
        /* Initiator Task Tag assigned from Initiator */
-       u32                     init_task_tag;
+       itt_t                   init_task_tag;
        /* Target Transfer Tag assigned from Target */
        u32                     targ_xfer_tag;
        /* CmdSN assigned from Initiator */
@@ -478,7 +479,6 @@ struct iscsi_cmd {
 
 struct iscsi_tmr_req {
        bool                    task_reassign:1;
-       u32                     ref_cmd_sn;
        u32                     exp_data_sn;
        struct iscsi_cmd        *ref_cmd;
        struct iscsi_conn_recovery *conn_recovery;
@@ -505,7 +505,7 @@ struct iscsi_conn {
        u32                     auth_id;
        u32                     conn_flags;
        /* Used for iscsi_tx_login_rsp() */
-       u32                     login_itt;
+       itt_t                   login_itt;
        u32                     exp_statsn;
        /* Per connection status sequence number */
        u32                     stat_sn;
@@ -578,6 +578,7 @@ struct iscsi_conn_recovery {
        u16                     cid;
        u32                     cmd_count;
        u32                     maxrecvdatasegmentlength;
+       u32                     maxxmitdatasegmentlength;
        int                     ready_for_reallegiance;
        struct list_head        conn_recovery_cmd_list;
        spinlock_t              conn_recovery_cmd_lock;
@@ -597,7 +598,7 @@ struct iscsi_session {
        /* state session is currently in */
        u32                     session_state;
        /* session wide counter: initiator assigned task tag */
-       u32                     init_task_tag;
+       itt_t                   init_task_tag;
        /* session wide counter: target assigned task tag */
        u32                     targ_xfer_tag;
        u32                     cmdsn_window;
@@ -663,7 +664,7 @@ struct iscsi_login {
        u8 version_max;
        char isid[6];
        u32 cmd_sn;
-       u32 init_task_tag;
+       itt_t init_task_tag;
        u32 initial_exp_statsn;
        u32 rsp_length;
        u16 cid;
index 1a02016..8aacf61 100644 (file)
@@ -48,9 +48,9 @@ void iscsit_set_dataout_sequence_values(
        if (cmd->unsolicited_data) {
                cmd->seq_start_offset = cmd->write_data_done;
                cmd->seq_end_offset = (cmd->write_data_done +
-                       (cmd->se_cmd.data_length >
-                        conn->sess->sess_ops->FirstBurstLength) ?
-                       conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length);
+                       ((cmd->se_cmd.data_length >
+                         conn->sess->sess_ops->FirstBurstLength) ?
+                        conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length));
                return;
        }
 
@@ -95,14 +95,15 @@ static int iscsit_dataout_within_command_recovery_check(
         */
        if (conn->sess->sess_ops->DataSequenceInOrder) {
                if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&
-                   (cmd->write_data_done != hdr->offset))
+                   cmd->write_data_done != be32_to_cpu(hdr->offset))
                        goto dump;
 
                cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;
        } else {
                struct iscsi_seq *seq;
 
-               seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+               seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),
+                                           payload_length);
                if (!seq)
                        return DATAOUT_CANNOT_RECOVER;
                /*
@@ -111,15 +112,15 @@ static int iscsit_dataout_within_command_recovery_check(
                cmd->seq_ptr = seq;
 
                if (conn->sess->sess_ops->DataPDUInOrder) {
-                       if ((seq->status ==
-                            DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
-                          ((seq->offset != hdr->offset) ||
-                           (seq->data_sn != hdr->datasn)))
+                       if (seq->status ==
+                           DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&
+                          (seq->offset != be32_to_cpu(hdr->offset) ||
+                           seq->data_sn != be32_to_cpu(hdr->datasn)))
                                goto dump;
                } else {
-                       if ((seq->status ==
-                            DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
-                           (seq->data_sn != hdr->datasn))
+                       if (seq->status ==
+                            DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&
+                           seq->data_sn != be32_to_cpu(hdr->datasn))
                                goto dump;
                }
 
@@ -148,12 +149,12 @@ static int iscsit_dataout_check_unsolicited_sequence(
        u32 payload_length = ntoh24(hdr->dlength);
 
 
-       if ((hdr->offset < cmd->seq_start_offset) ||
-          ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+       if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||
+          ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {
                pr_err("Command ITT: 0x%08x with Offset: %u,"
                " Length: %u outside of Unsolicited Sequence %u:%u while"
                " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
-               hdr->offset, payload_length, cmd->seq_start_offset,
+               be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,
                        cmd->seq_end_offset);
                return DATAOUT_CANNOT_RECOVER;
        }
@@ -236,12 +237,12 @@ static int iscsit_dataout_check_sequence(
                 * fullfilling an Recovery R2T, it's best to just dump the
                 * payload here, instead of erroring out.
                 */
-               if ((hdr->offset < cmd->seq_start_offset) ||
-                  ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+               if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||
+                  ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {
                        pr_err("Command ITT: 0x%08x with Offset: %u,"
                        " Length: %u outside of Sequence %u:%u while"
                        " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
-                       hdr->offset, payload_length, cmd->seq_start_offset,
+                       be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,
                                cmd->seq_end_offset);
 
                        if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
@@ -251,7 +252,8 @@ static int iscsit_dataout_check_sequence(
 
                next_burst_len = (cmd->next_burst_len + payload_length);
        } else {
-               seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+               seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),
+                                           payload_length);
                if (!seq)
                        return DATAOUT_CANNOT_RECOVER;
                /*
@@ -366,16 +368,16 @@ static int iscsit_dataout_check_datasn(
                data_sn = seq->data_sn;
        }
 
-       if (hdr->datasn > data_sn) {
+       if (be32_to_cpu(hdr->datasn) > data_sn) {
                pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
                        " higher than expected 0x%08x.\n", cmd->init_task_tag,
-                               hdr->datasn, data_sn);
+                               be32_to_cpu(hdr->datasn), data_sn);
                recovery = 1;
                goto recover;
-       } else if (hdr->datasn < data_sn) {
+       } else if (be32_to_cpu(hdr->datasn) < data_sn) {
                pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
                        " lower than expected 0x%08x, discarding payload.\n",
-                       cmd->init_task_tag, hdr->datasn, data_sn);
+                       cmd->init_task_tag, be32_to_cpu(hdr->datasn), data_sn);
                dump = 1;
                goto dump;
        }
@@ -415,26 +417,27 @@ static int iscsit_dataout_pre_datapduinorder_yes(
         * error has occured and fail the connection.
         */
        if (conn->sess->sess_ops->DataSequenceInOrder) {
-               if (hdr->offset != cmd->write_data_done) {
+               if (be32_to_cpu(hdr->offset) != cmd->write_data_done) {
                        pr_err("Command ITT: 0x%08x, received offset"
                        " %u different than expected %u.\n", cmd->init_task_tag,
-                               hdr->offset, cmd->write_data_done);
+                               be32_to_cpu(hdr->offset), cmd->write_data_done);
                        recovery = 1;
                        goto recover;
                }
        } else {
                struct iscsi_seq *seq = cmd->seq_ptr;
 
-               if (hdr->offset > seq->offset) {
+               if (be32_to_cpu(hdr->offset) > seq->offset) {
                        pr_err("Command ITT: 0x%08x, received offset"
                        " %u greater than expected %u.\n", cmd->init_task_tag,
-                               hdr->offset, seq->offset);
+                               be32_to_cpu(hdr->offset), seq->offset);
                        recovery = 1;
                        goto recover;
-               } else if (hdr->offset < seq->offset) {
+               } else if (be32_to_cpu(hdr->offset) < seq->offset) {
                        pr_err("Command ITT: 0x%08x, received offset"
                        " %u less than expected %u, discarding payload.\n",
-                               cmd->init_task_tag, hdr->offset, seq->offset);
+                               cmd->init_task_tag, be32_to_cpu(hdr->offset),
+                               seq->offset);
                        dump = 1;
                        goto dump;
                }
@@ -453,7 +456,7 @@ dump:
                return DATAOUT_CANNOT_RECOVER;
 
        return (recovery) ? iscsit_recover_dataout_sequence(cmd,
-               hdr->offset, payload_length) :
+               be32_to_cpu(hdr->offset), payload_length) :
               (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;
 }
 
@@ -465,7 +468,8 @@ static int iscsit_dataout_pre_datapduinorder_no(
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
        u32 payload_length = ntoh24(hdr->dlength);
 
-       pdu = iscsit_get_pdu_holder(cmd, hdr->offset, payload_length);
+       pdu = iscsit_get_pdu_holder(cmd, be32_to_cpu(hdr->offset),
+                                   payload_length);
        if (!pdu)
                return DATAOUT_CANNOT_RECOVER;
 
@@ -479,7 +483,7 @@ static int iscsit_dataout_pre_datapduinorder_no(
        case ISCSI_PDU_RECEIVED_OK:
                pr_err("Command ITT: 0x%08x received already gotten"
                        " Offset: %u, Length: %u\n", cmd->init_task_tag,
-                               hdr->offset, payload_length);
+                               be32_to_cpu(hdr->offset), payload_length);
                return iscsit_dump_data_payload(cmd->conn, payload_length, 1);
        default:
                return DATAOUT_CANNOT_RECOVER;
@@ -553,7 +557,7 @@ static int iscsit_dataout_post_crc_passed(
        if (cmd->unsolicited_data) {
                if ((cmd->first_burst_len + payload_length) ==
                     conn->sess->sess_ops->FirstBurstLength) {
-                       if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                       if (iscsit_dataout_update_r2t(cmd, be32_to_cpu(hdr->offset),
                                        payload_length) < 0)
                                return DATAOUT_CANNOT_RECOVER;
                        send_r2t = 1;
@@ -561,7 +565,8 @@ static int iscsit_dataout_post_crc_passed(
 
                if (!conn->sess->sess_ops->DataPDUInOrder) {
                        ret = iscsit_dataout_update_datapduinorder_no(cmd,
-                               hdr->datasn, (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+                               be32_to_cpu(hdr->datasn),
+                               (hdr->flags & ISCSI_FLAG_CMD_FINAL));
                        if (ret == DATAOUT_CANNOT_RECOVER)
                                return ret;
                }
@@ -586,7 +591,8 @@ static int iscsit_dataout_post_crc_passed(
                if (conn->sess->sess_ops->DataSequenceInOrder) {
                        if ((cmd->next_burst_len + payload_length) ==
                             conn->sess->sess_ops->MaxBurstLength) {
-                               if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                               if (iscsit_dataout_update_r2t(cmd,
+                                               be32_to_cpu(hdr->offset),
                                                payload_length) < 0)
                                        return DATAOUT_CANNOT_RECOVER;
                                send_r2t = 1;
@@ -594,7 +600,7 @@ static int iscsit_dataout_post_crc_passed(
 
                        if (!conn->sess->sess_ops->DataPDUInOrder) {
                                ret = iscsit_dataout_update_datapduinorder_no(
-                                               cmd, hdr->datasn,
+                                               cmd, be32_to_cpu(hdr->datasn),
                                                (hdr->flags & ISCSI_FLAG_CMD_FINAL));
                                if (ret == DATAOUT_CANNOT_RECOVER)
                                        return ret;
@@ -610,7 +616,8 @@ static int iscsit_dataout_post_crc_passed(
 
                        if ((seq->next_burst_len + payload_length) ==
                             seq->xfer_len) {
-                               if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                               if (iscsit_dataout_update_r2t(cmd,
+                                               be32_to_cpu(hdr->offset),
                                                payload_length) < 0)
                                        return DATAOUT_CANNOT_RECOVER;
                                send_r2t = 1;
@@ -618,7 +625,7 @@ static int iscsit_dataout_post_crc_passed(
 
                        if (!conn->sess->sess_ops->DataPDUInOrder) {
                                ret = iscsit_dataout_update_datapduinorder_no(
-                                               cmd, hdr->datasn,
+                                               cmd, be32_to_cpu(hdr->datasn),
                                                (hdr->flags & ISCSI_FLAG_CMD_FINAL));
                                if (ret == DATAOUT_CANNOT_RECOVER)
                                        return ret;
@@ -678,14 +685,15 @@ static int iscsit_dataout_post_crc_failed(
        }
 
 recover:
-       return iscsit_recover_dataout_sequence(cmd, hdr->offset, payload_length);
+       return iscsit_recover_dataout_sequence(cmd, be32_to_cpu(hdr->offset),
+                                               payload_length);
 }
 
 /*
  *     Called from iscsit_handle_data_out() before DataOUT Payload is received
  *     and CRC computed.
  */
-extern int iscsit_check_pre_dataout(
+int iscsit_check_pre_dataout(
        struct iscsi_cmd *cmd,
        unsigned char *buf)
 {
@@ -789,7 +797,7 @@ static void iscsit_handle_time2retain_timeout(unsigned long data)
        target_put_session(sess->se_sess);
 }
 
-extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
+void iscsit_start_time2retain_handler(struct iscsi_session *sess)
 {
        int tpg_active;
        /*
@@ -822,7 +830,7 @@ extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
 /*
  *     Called with spin_lock_bh(&struct se_portal_group->session_lock) held
  */
-extern int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
+int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
 {
        struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
@@ -926,7 +934,7 @@ static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn)
        }
 }
 
-extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
+void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 {
        spin_lock_bh(&conn->state_lock);
        if (atomic_read(&conn->connection_exit)) {
index 3df8a2c..21f29d9 100644 (file)
@@ -466,7 +466,7 @@ static int iscsit_handle_recovery_datain(
 int iscsit_handle_recovery_datain_or_r2t(
        struct iscsi_conn *conn,
        unsigned char *buf,
-       u32 init_task_tag,
+       itt_t init_task_tag,
        u32 targ_xfer_tag,
        u32 begrun,
        u32 runlength)
@@ -498,7 +498,7 @@ int iscsit_handle_recovery_datain_or_r2t(
 /* #warning FIXME: Status SNACK needs to be dependent on OPCODE!!! */
 int iscsit_handle_status_snack(
        struct iscsi_conn *conn,
-       u32 init_task_tag,
+       itt_t init_task_tag,
        u32 targ_xfer_tag,
        u32 begrun,
        u32 runlength)
index 85e67e2..2a3ebf1 100644 (file)
@@ -7,8 +7,8 @@ extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
 extern int iscsit_create_recovery_datain_values_datasequenceinorder_no(
                        struct iscsi_cmd *, struct iscsi_datain_req *);
 extern int iscsit_handle_recovery_datain_or_r2t(struct iscsi_conn *, unsigned char *,
-                       u32, u32, u32, u32);
-extern int iscsit_handle_status_snack(struct iscsi_conn *, u32, u32,
+                       itt_t, u32, u32, u32);
+extern int iscsit_handle_status_snack(struct iscsi_conn *, itt_t, u32,
                        u32, u32);
 extern int iscsit_handle_data_ack(struct iscsi_conn *, u32, u32, u32);
 extern int iscsit_dataout_datapduinorder_no_fbit(struct iscsi_cmd *, struct iscsi_pdu *);
index 65aac14..17d8c20 100644 (file)
@@ -36,7 +36,7 @@
  */
 void iscsit_create_conn_recovery_datain_values(
        struct iscsi_cmd *cmd,
-       u32 exp_data_sn)
+       __be32 exp_data_sn)
 {
        u32 data_sn = 0;
        struct iscsi_conn *conn = cmd->conn;
@@ -44,7 +44,7 @@ void iscsit_create_conn_recovery_datain_values(
        cmd->next_burst_len = 0;
        cmd->read_data_done = 0;
 
-       while (exp_data_sn > data_sn) {
+       while (be32_to_cpu(exp_data_sn) > data_sn) {
                if ((cmd->next_burst_len +
                     conn->conn_ops->MaxRecvDataSegmentLength) <
                     conn->sess->sess_ops->MaxBurstLength) {
@@ -193,15 +193,13 @@ int iscsit_remove_active_connection_recovery_entry(
        return 0;
 }
 
-int iscsit_remove_inactive_connection_recovery_entry(
+static void iscsit_remove_inactive_connection_recovery_entry(
        struct iscsi_conn_recovery *cr,
        struct iscsi_session *sess)
 {
        spin_lock(&sess->cr_i_lock);
        list_del(&cr->cr_list);
        spin_unlock(&sess->cr_i_lock);
-
-       return 0;
 }
 
 /*
@@ -421,6 +419,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
        cr->cid = conn->cid;
        cr->cmd_count = cmd_count;
        cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength;
+       cr->maxxmitdatasegmentlength = conn->conn_ops->MaxXmitDataSegmentLength;
        cr->sess = conn->sess;
 
        iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr);
index 22f8d24..63f2501 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef ISCSI_TARGET_ERL2_H
 #define ISCSI_TARGET_ERL2_H
 
-extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, u32);
+extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32);
 extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
 extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
                        struct iscsi_session *, u16);
index 6aba439..cdc8a10 100644 (file)
 #include "iscsi_target.h"
 #include "iscsi_target_parameters.h"
 
-extern struct idr sess_idr;
-extern struct mutex auth_id_lock;
-extern spinlock_t sess_idr_lock;
-
 static int iscsi_login_init_conn(struct iscsi_conn *conn)
 {
        INIT_LIST_HEAD(&conn->conn_list);
@@ -196,10 +192,10 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
 static void iscsi_login_set_conn_values(
        struct iscsi_session *sess,
        struct iscsi_conn *conn,
-       u16 cid)
+       __be16 cid)
 {
        conn->sess              = sess;
-       conn->cid               = cid;
+       conn->cid               = be16_to_cpu(cid);
        /*
         * Generate a random Status sequence number (statsn) for the new
         * iSCSI connection.
@@ -234,7 +230,7 @@ static int iscsi_login_zero_tsih_s1(
        iscsi_login_set_conn_values(sess, conn, pdu->cid);
        sess->init_task_tag     = pdu->itt;
        memcpy(&sess->isid, pdu->isid, 6);
-       sess->exp_cmd_sn        = pdu->cmdsn;
+       sess->exp_cmd_sn        = be32_to_cpu(pdu->cmdsn);
        INIT_LIST_HEAD(&sess->sess_conn_list);
        INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list);
        INIT_LIST_HEAD(&sess->cr_active_list);
@@ -275,7 +271,7 @@ static int iscsi_login_zero_tsih_s1(
         * The FFP CmdSN window values will be allocated from the TPG's
         * Initiator Node's ACL once the login has been successfully completed.
         */
-       sess->max_cmd_sn        = pdu->cmdsn;
+       sess->max_cmd_sn        = be32_to_cpu(pdu->cmdsn);
 
        sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
        if (!sess->sess_ops) {
@@ -453,7 +449,7 @@ static int iscsi_login_non_zero_tsih_s2(
                   (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
                        continue;
                if (!memcmp(sess_p->isid, pdu->isid, 6) &&
-                    (sess_p->tsih == pdu->tsih)) {
+                    (sess_p->tsih == be16_to_cpu(pdu->tsih))) {
                        iscsit_inc_session_usage_count(sess_p);
                        iscsit_stop_time2retain_timer(sess_p);
                        sess = sess_p;
@@ -955,11 +951,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
 
        pdu                     = (struct iscsi_login_req *) buffer;
-       pdu->cid                = be16_to_cpu(pdu->cid);
-       pdu->tsih               = be16_to_cpu(pdu->tsih);
-       pdu->itt                = be32_to_cpu(pdu->itt);
-       pdu->cmdsn              = be32_to_cpu(pdu->cmdsn);
-       pdu->exp_statsn         = be32_to_cpu(pdu->exp_statsn);
+
        /*
         * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
         * when Status-Class != 0.
index 2dba448..e9053a0 100644 (file)
@@ -44,7 +44,7 @@ void convert_null_to_semi(char *buf, int len)
                        buf[i] = ';';
 }
 
-int strlen_semi(char *buf)
+static int strlen_semi(char *buf)
 {
        int i = 0;
 
@@ -339,14 +339,14 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
        hton24(login_rsp->dlength, login->rsp_length);
        memcpy(login_rsp->isid, login->isid, 6);
        login_rsp->tsih                 = cpu_to_be16(login->tsih);
-       login_rsp->itt                  = cpu_to_be32(login->init_task_tag);
+       login_rsp->itt                  = login->init_task_tag;
        login_rsp->statsn               = cpu_to_be32(conn->stat_sn++);
        login_rsp->exp_cmdsn            = cpu_to_be32(conn->sess->exp_cmd_sn);
        login_rsp->max_cmdsn            = cpu_to_be32(conn->sess->max_cmd_sn);
 
        pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x,"
                " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:"
-               " %u\n", login_rsp->flags, ntohl(login_rsp->itt),
+               " %u\n", login_rsp->flags, (__force u32)login_rsp->itt,
                ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn),
                ntohl(login_rsp->statsn), login->rsp_length);
 
@@ -360,12 +360,9 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
                return -1;
 
        login->rsp_length               = 0;
-       login_rsp->tsih                 = be16_to_cpu(login_rsp->tsih);
-       login_rsp->itt                  = be32_to_cpu(login_rsp->itt);
-       login_rsp->statsn               = be32_to_cpu(login_rsp->statsn);
        mutex_lock(&sess->cmdsn_mutex);
-       login_rsp->exp_cmdsn            = be32_to_cpu(sess->exp_cmd_sn);
-       login_rsp->max_cmdsn            = be32_to_cpu(sess->max_cmd_sn);
+       login_rsp->exp_cmdsn            = cpu_to_be32(sess->exp_cmd_sn);
+       login_rsp->max_cmdsn            = cpu_to_be32(sess->max_cmd_sn);
        mutex_unlock(&sess->cmdsn_mutex);
 
        return 0;
@@ -381,11 +378,6 @@ static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_log
 
        login_req = (struct iscsi_login_req *) login->req;
        payload_length                  = ntoh24(login_req->dlength);
-       login_req->tsih                 = be16_to_cpu(login_req->tsih);
-       login_req->itt                  = be32_to_cpu(login_req->itt);
-       login_req->cid                  = be16_to_cpu(login_req->cid);
-       login_req->cmdsn                = be32_to_cpu(login_req->cmdsn);
-       login_req->exp_statsn           = be32_to_cpu(login_req->exp_statsn);
 
        pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
                " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
@@ -550,7 +542,7 @@ static int iscsi_target_handle_csg_zero(
                        SENDER_INITIATOR|SENDER_RECEIVER,
                        login->req_buf,
                        payload_length,
-                       conn->param_list);
+                       conn);
        if (ret < 0)
                return -1;
 
@@ -627,7 +619,7 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
                        SENDER_INITIATOR|SENDER_RECEIVER,
                        login->req_buf,
                        payload_length,
-                       conn->param_list);
+                       conn);
        if (ret < 0)
                return -1;
 
@@ -762,11 +754,11 @@ static int iscsi_target_locate_portal(
        login->version_min      = login_req->min_version;
        login->version_max      = login_req->max_version;
        memcpy(login->isid, login_req->isid, 6);
-       login->cmd_sn           = login_req->cmdsn;
+       login->cmd_sn           = be32_to_cpu(login_req->cmdsn);
        login->init_task_tag    = login_req->itt;
-       login->initial_exp_statsn = login_req->exp_statsn;
-       login->cid              = login_req->cid;
-       login->tsih             = login_req->tsih;
+       login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+       login->cid              = be16_to_cpu(login_req->cid);
+       login->tsih             = be16_to_cpu(login_req->tsih);
 
        if (iscsi_target_get_initial_payload(conn, login) < 0)
                return -1;
@@ -1000,7 +992,6 @@ struct iscsi_login *iscsi_target_init_negotiation(
         *      Locates Target Portal from NP -> Target IQN
         */
        if (iscsi_target_locate_portal(np, conn, login) < 0) {
-               pr_err("iSCSI Login negotiation failed.\n");
                goto out;
        }
 
index 240f7aa..90b7400 100644 (file)
@@ -334,6 +334,13 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
        if (!param)
                goto out;
 
+       param = iscsi_set_default_param(pl, MAXXMITDATASEGMENTLENGTH,
+                       INITIAL_MAXXMITDATASEGMENTLENGTH,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_512_TO_16777215, USE_ALL);
+       if (!param)
+               goto out;
+
        param = iscsi_set_default_param(pl, MAXRECVDATASEGMENTLENGTH,
                        INITIAL_MAXRECVDATASEGMENTLENGTH,
                        PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
@@ -467,6 +474,8 @@ int iscsi_set_keys_to_negotiate(
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
                        SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+                       continue;
                } else if (!strcmp(param->name, MAXBURSTLENGTH)) {
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
@@ -1056,7 +1065,8 @@ out:
        return proposer_values;
 }
 
-static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
+static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value,
+                               struct iscsi_conn *conn)
 {
        u8 acceptor_boolean_value = 0, proposer_boolean_value = 0;
        char *negoitated_value = NULL;
@@ -1131,8 +1141,35 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
                                return -1;
                }
 
-               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
+               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
+                       struct iscsi_param *param_mxdsl;
+                       unsigned long long tmp;
+                       int rc;
+
+                       rc = strict_strtoull(param->value, 0, &tmp);
+                       if (rc < 0)
+                               return -1;
+
+                       conn->conn_ops->MaxRecvDataSegmentLength = tmp;
+                       pr_debug("Saving op->MaxRecvDataSegmentLength from"
+                               " original initiator received value: %u\n",
+                               conn->conn_ops->MaxRecvDataSegmentLength);
+
+                       param_mxdsl = iscsi_find_param_from_key(
+                                               MAXXMITDATASEGMENTLENGTH,
+                                               conn->param_list);
+                       if (!param_mxdsl)
+                               return -1;
+
+                       rc = iscsi_update_param_value(param,
+                                               param_mxdsl->value);
+                       if (rc < 0)
+                               return -1;
+
+                       pr_debug("Updated %s to target MXDSL value: %s\n",
+                                       param->name, param->value);
+               }
+
        } else if (IS_TYPE_NUMBER_RANGE(param)) {
                negoitated_value = iscsi_get_value_from_number_range(
                                        param, value);
@@ -1526,8 +1563,9 @@ int iscsi_decode_text_input(
        u8 sender,
        char *textbuf,
        u32 length,
-       struct iscsi_param_list *param_list)
+       struct iscsi_conn *conn)
 {
+       struct iscsi_param_list *param_list = conn->param_list;
        char *tmpbuf, *start = NULL, *end = NULL;
 
        tmpbuf = kzalloc(length + 1, GFP_KERNEL);
@@ -1585,7 +1623,7 @@ int iscsi_decode_text_input(
                        }
                        SET_PSTATE_RESPONSE_GOT(param);
                } else {
-                       if (iscsi_check_acceptor_state(param, value) < 0) {
+                       if (iscsi_check_acceptor_state(param, value, conn) < 0) {
                                kfree(tmpbuf);
                                return -1;
                        }
@@ -1720,6 +1758,18 @@ void iscsi_set_connection_parameters(
        pr_debug("---------------------------------------------------"
                        "---------------\n");
        list_for_each_entry(param, &param_list->param_list, p_list) {
+               /*
+                * Special case to set MAXXMITDATASEGMENTLENGTH from the
+                * target requested MaxRecvDataSegmentLength, even though
+                * this key is not sent over the wire.
+                */
+               if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+                       ops->MaxXmitDataSegmentLength =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxXmitDataSegmentLength:     %s\n",
+                               param->value);
+               }
+
                if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param))
                        continue;
                if (!strcmp(param->name, AUTHMETHOD)) {
@@ -1734,10 +1784,13 @@ void iscsi_set_connection_parameters(
                        pr_debug("DataDigest:                   %s\n",
                                param->value);
                } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
-                       ops->MaxRecvDataSegmentLength =
-                               simple_strtoul(param->value, &tmpptr, 0);
-                       pr_debug("MaxRecvDataSegmentLength:     %s\n",
-                               param->value);
+                       /*
+                        * At this point iscsi_check_acceptor_state() will have
+                        * set ops->MaxRecvDataSegmentLength from the original
+                        * initiator provided value.
+                        */
+                       pr_debug("MaxRecvDataSegmentLength:     %u\n",
+                               ops->MaxRecvDataSegmentLength);
                } else if (!strcmp(param->name, OFMARKER)) {
                        ops->OFMarker = !strcmp(param->value, YES);
                        pr_debug("OFMarker:                     %s\n",
index 6a37fd6..1e1b750 100644 (file)
@@ -36,7 +36,7 @@ extern void iscsi_release_param_list(struct iscsi_param_list *);
 extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_list *);
 extern int iscsi_extract_key_value(char *, char **, char **);
 extern int iscsi_update_param_value(struct iscsi_param *, char *);
-extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_param_list *);
+extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
 extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
                        struct iscsi_param_list *);
 extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
@@ -70,6 +70,7 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
 #define INITIALR2T                     "InitialR2T"
 #define IMMEDIATEDATA                  "ImmediateData"
 #define MAXRECVDATASEGMENTLENGTH       "MaxRecvDataSegmentLength"
+#define MAXXMITDATASEGMENTLENGTH       "MaxXmitDataSegmentLength"
 #define MAXBURSTLENGTH                 "MaxBurstLength"
 #define FIRSTBURSTLENGTH               "FirstBurstLength"
 #define DEFAULTTIME2WAIT               "DefaultTime2Wait"
@@ -113,6 +114,10 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
 #define INITIAL_INITIALR2T                     YES
 #define INITIAL_IMMEDIATEDATA                  YES
 #define INITIAL_MAXRECVDATASEGMENTLENGTH       "8192"
+/*
+ * Match outgoing MXDSL default to incoming Open-iSCSI default
+ */
+#define INITIAL_MAXXMITDATASEGMENTLENGTH       "262144"
 #define INITIAL_MAXBURSTLENGTH                 "262144"
 #define INITIAL_FIRSTBURSTLENGTH               "65536"
 #define INITIAL_DEFAULTTIME2WAIT               "2"
index 85a306e..edb592a 100644 (file)
@@ -219,8 +219,14 @@ static void iscsit_determine_counts_for_list(
        int check_immediate = 0;
        u32 burstlength = 0, offset = 0;
        u32 unsolicited_data_length = 0;
+       u32 mdsl;
        struct iscsi_conn *conn = cmd->conn;
 
+       if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
+               mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
+       else
+               mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
+
        if ((bl->type == PDULIST_IMMEDIATE) ||
            (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
                check_immediate = 1;
@@ -243,14 +249,13 @@ static void iscsit_determine_counts_for_list(
                        continue;
                }
                if (unsolicited_data_length > 0) {
-                       if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
-                                       >= cmd->se_cmd.data_length) {
+                       if ((offset + mdsl) >= cmd->se_cmd.data_length) {
                                unsolicited_data_length -=
                                        (cmd->se_cmd.data_length - offset);
                                offset += (cmd->se_cmd.data_length - offset);
                                continue;
                        }
-                       if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
+                       if ((offset + mdsl)
                                        >= conn->sess->sess_ops->FirstBurstLength) {
                                unsolicited_data_length -=
                                        (conn->sess->sess_ops->FirstBurstLength -
@@ -262,17 +267,15 @@ static void iscsit_determine_counts_for_list(
                                continue;
                        }
 
-                       offset += conn->conn_ops->MaxRecvDataSegmentLength;
-                       unsolicited_data_length -=
-                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       offset += mdsl;
+                       unsolicited_data_length -= mdsl;
                        continue;
                }
-               if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
-                    cmd->se_cmd.data_length) {
+               if ((offset + mdsl) >= cmd->se_cmd.data_length) {
                        offset += (cmd->se_cmd.data_length - offset);
                        continue;
                }
-               if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+               if ((burstlength + mdsl) >=
                     conn->sess->sess_ops->MaxBurstLength) {
                        offset += (conn->sess->sess_ops->MaxBurstLength -
                                        burstlength);
@@ -281,8 +284,8 @@ static void iscsit_determine_counts_for_list(
                        continue;
                }
 
-               burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
-               offset += conn->conn_ops->MaxRecvDataSegmentLength;
+               burstlength += mdsl;
+               offset += mdsl;
        }
 }
 
@@ -296,12 +299,17 @@ static int iscsit_do_build_pdu_and_seq_lists(
        struct iscsi_build_list *bl)
 {
        int check_immediate = 0, datapduinorder, datasequenceinorder;
-       u32 burstlength = 0, offset = 0, i = 0;
+       u32 burstlength = 0, offset = 0, i = 0, mdsl;
        u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
        struct iscsi_conn *conn = cmd->conn;
        struct iscsi_pdu *pdu = cmd->pdu_list;
        struct iscsi_seq *seq = cmd->seq_list;
 
+       if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
+               mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
+       else
+               mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
+
        datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
        datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
 
@@ -348,9 +356,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
                        continue;
                }
                if (unsolicited_data_length > 0) {
-                       if ((offset +
-                            conn->conn_ops->MaxRecvDataSegmentLength) >=
-                            cmd->se_cmd.data_length) {
+                       if ((offset + mdsl) >= cmd->se_cmd.data_length) {
                                if (!datapduinorder) {
                                        pdu[i].type = PDUTYPE_UNSOLICITED;
                                        pdu[i].length =
@@ -367,8 +373,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
                                offset += (cmd->se_cmd.data_length - offset);
                                continue;
                        }
-                       if ((offset +
-                            conn->conn_ops->MaxRecvDataSegmentLength) >=
+                       if ((offset + mdsl) >=
                                        conn->sess->sess_ops->FirstBurstLength) {
                                if (!datapduinorder) {
                                        pdu[i].type = PDUTYPE_UNSOLICITED;
@@ -396,17 +401,14 @@ static int iscsit_do_build_pdu_and_seq_lists(
 
                        if (!datapduinorder) {
                                pdu[i].type = PDUTYPE_UNSOLICITED;
-                               pdu[i++].length =
-                                    conn->conn_ops->MaxRecvDataSegmentLength;
+                               pdu[i++].length = mdsl;
                        }
-                       burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
-                       offset += conn->conn_ops->MaxRecvDataSegmentLength;
-                       unsolicited_data_length -=
-                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       burstlength += mdsl;
+                       offset += mdsl;
+                       unsolicited_data_length -= mdsl;
                        continue;
                }
-               if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
-                    cmd->se_cmd.data_length) {
+               if ((offset + mdsl) >= cmd->se_cmd.data_length) {
                        if (!datapduinorder) {
                                pdu[i].type = PDUTYPE_NORMAL;
                                pdu[i].length = (cmd->se_cmd.data_length - offset);
@@ -420,7 +422,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
                        offset += (cmd->se_cmd.data_length - offset);
                        continue;
                }
-               if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+               if ((burstlength + mdsl) >=
                     conn->sess->sess_ops->MaxBurstLength) {
                        if (!datapduinorder) {
                                pdu[i].type = PDUTYPE_NORMAL;
@@ -445,11 +447,10 @@ static int iscsit_do_build_pdu_and_seq_lists(
 
                if (!datapduinorder) {
                        pdu[i].type = PDUTYPE_NORMAL;
-                       pdu[i++].length =
-                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       pdu[i++].length = mdsl;
                }
-               burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
-               offset += conn->conn_ops->MaxRecvDataSegmentLength;
+               burstlength += mdsl;
+               offset += mdsl;
        }
 
        if (!datasequenceinorder) {
index f62fe12..4a99820 100644 (file)
@@ -50,21 +50,20 @@ u8 iscsit_tmr_abort_task(
        if (!ref_cmd) {
                pr_err("Unable to locate RefTaskTag: 0x%08x on CID:"
                        " %hu.\n", hdr->rtt, conn->cid);
-               return ((hdr->refcmdsn >= conn->sess->exp_cmd_sn) &&
-                       (hdr->refcmdsn <= conn->sess->max_cmd_sn)) ?
+               return (be32_to_cpu(hdr->refcmdsn) >= conn->sess->exp_cmd_sn &&
+                       be32_to_cpu(hdr->refcmdsn) <= conn->sess->max_cmd_sn) ?
                        ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK;
        }
-       if (ref_cmd->cmd_sn != hdr->refcmdsn) {
+       if (ref_cmd->cmd_sn != be32_to_cpu(hdr->refcmdsn)) {
                pr_err("RefCmdSN 0x%08x does not equal"
                        " task's CmdSN 0x%08x. Rejecting ABORT_TASK.\n",
                        hdr->refcmdsn, ref_cmd->cmd_sn);
                return ISCSI_TMF_RSP_REJECTED;
        }
 
-       se_tmr->ref_task_tag            = hdr->rtt;
+       se_tmr->ref_task_tag            = (__force u32)hdr->rtt;
        tmr_req->ref_cmd                = ref_cmd;
-       tmr_req->ref_cmd_sn             = hdr->refcmdsn;
-       tmr_req->exp_data_sn            = hdr->exp_datasn;
+       tmr_req->exp_data_sn            = be32_to_cpu(hdr->exp_datasn);
 
        return ISCSI_TMF_RSP_COMPLETE;
 }
@@ -146,7 +145,7 @@ u8 iscsit_tmr_task_reassign(
        }
        /*
         * Temporary check to prevent connection recovery for
-        * connections with a differing MaxRecvDataSegmentLength.
+        * connections with a differing Max*DataSegmentLength.
         */
        if (cr->maxrecvdatasegmentlength !=
            conn->conn_ops->MaxRecvDataSegmentLength) {
@@ -155,6 +154,13 @@ u8 iscsit_tmr_task_reassign(
                        " TMR TASK_REASSIGN.\n");
                return ISCSI_TMF_RSP_REJECTED;
        }
+       if (cr->maxxmitdatasegmentlength !=
+           conn->conn_ops->MaxXmitDataSegmentLength) {
+               pr_err("Unable to perform connection recovery for"
+                       " differing MaxXmitDataSegmentLength, rejecting"
+                       " TMR TASK_REASSIGN.\n");
+               return ISCSI_TMF_RSP_REJECTED;
+       }
 
        ref_lun = scsilun_to_int(&hdr->lun);
        if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) {
@@ -164,10 +170,9 @@ u8 iscsit_tmr_task_reassign(
                return ISCSI_TMF_RSP_REJECTED;
        }
 
-       se_tmr->ref_task_tag            = hdr->rtt;
+       se_tmr->ref_task_tag            = (__force u32)hdr->rtt;
        tmr_req->ref_cmd                = ref_cmd;
-       tmr_req->ref_cmd_sn             = hdr->refcmdsn;
-       tmr_req->exp_data_sn            = hdr->exp_datasn;
+       tmr_req->exp_data_sn            = be32_to_cpu(hdr->exp_datasn);
        tmr_req->conn_recovery          = cr;
        tmr_req->task_reassign          = 1;
        /*
@@ -455,7 +460,7 @@ static int iscsit_task_reassign_complete(
  *     Right now the only one that its really needed for is
  *     connection recovery releated TASK_REASSIGN.
  */
-extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
        struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
        struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
@@ -470,7 +475,7 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *con
 /*
  *     Nothing to do here, but leave it for good measure. :-)
  */
-int iscsit_task_reassign_prepare_read(
+static int iscsit_task_reassign_prepare_read(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
@@ -545,7 +550,7 @@ static void iscsit_task_reassign_prepare_unsolicited_dataout(
        }
 }
 
-int iscsit_task_reassign_prepare_write(
+static int iscsit_task_reassign_prepare_write(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
index a38a3f8..de9ea32 100644 (file)
@@ -677,6 +677,12 @@ int iscsit_ta_generate_node_acls(
        pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n",
                tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled");
 
+       if (flag == 1 && a->cache_dynamic_acls == 0) {
+               pr_debug("Explicitly setting cache_dynamic_acls=1 when "
+                       "generate_node_acls=1\n");
+               a->cache_dynamic_acls = 1;
+       }
+
        return 0;
 }
 
@@ -716,6 +722,12 @@ int iscsit_ta_cache_dynamic_acls(
                return -EINVAL;
        }
 
+       if (a->generate_node_acls == 1 && flag == 0) {
+               pr_debug("Skipping cache_dynamic_acls=0 when"
+                       " generate_node_acls=1\n");
+               return 0;
+       }
+
        a->cache_dynamic_acls = flag;
        pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group"
                " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ?
index 977e1cf..9d881a0 100644 (file)
@@ -40,7 +40,7 @@ static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
        spin_unlock(&active_ts_lock);
 }
 
-extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
+static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
 {
        spin_lock(&inactive_ts_lock);
        list_add_tail(&ts->ts_list, &inactive_ts_list);
@@ -76,7 +76,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
        return ts;
 }
 
-extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
+int iscsi_allocate_thread_sets(u32 thread_pair_count)
 {
        int allocated_thread_pair_count = 0, i, thread_id;
        struct iscsi_thread_set *ts = NULL;
@@ -140,7 +140,7 @@ extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
        return allocated_thread_pair_count;
 }
 
-extern void iscsi_deallocate_thread_sets(void)
+void iscsi_deallocate_thread_sets(void)
 {
        u32 released_count = 0;
        struct iscsi_thread_set *ts = NULL;
index 26e6a95..547d118 100644 (file)
@@ -5,7 +5,6 @@
  * Defines for thread sets.
  */
 extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *);
-extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *);
 extern int iscsi_allocate_thread_sets(u32);
 extern void iscsi_deallocate_thread_sets(void);
 extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *);
index b42cdeb..afd98cc 100644 (file)
@@ -274,14 +274,14 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
 int iscsit_sequence_cmd(
        struct iscsi_conn *conn,
        struct iscsi_cmd *cmd,
-       u32 cmdsn)
+       __be32 cmdsn)
 {
        int ret;
        int cmdsn_ret;
 
        mutex_lock(&conn->sess->cmdsn_mutex);
 
-       cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, cmdsn);
+       cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, be32_to_cpu(cmdsn));
        switch (cmdsn_ret) {
        case CMDSN_NORMAL_OPERATION:
                ret = iscsit_execute_cmd(cmd, 0);
@@ -289,7 +289,7 @@ int iscsit_sequence_cmd(
                        iscsit_execute_ooo_cmdsns(conn->sess);
                break;
        case CMDSN_HIGHER_THAN_EXP:
-               ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, cmdsn);
+               ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
                break;
        case CMDSN_LOWER_THAN_EXP:
                cmd->i_state = ISTATE_REMOVE;
@@ -351,7 +351,7 @@ int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
 
 struct iscsi_cmd *iscsit_find_cmd_from_itt(
        struct iscsi_conn *conn,
-       u32 init_task_tag)
+       itt_t init_task_tag)
 {
        struct iscsi_cmd *cmd;
 
@@ -371,7 +371,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
 
 struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
        struct iscsi_conn *conn,
-       u32 init_task_tag,
+       itt_t init_task_tag,
        u32 length)
 {
        struct iscsi_cmd *cmd;
@@ -417,7 +417,7 @@ int iscsit_find_cmd_for_recovery(
        struct iscsi_session *sess,
        struct iscsi_cmd **cmd_ptr,
        struct iscsi_conn_recovery **cr_ptr,
-       u32 init_task_tag)
+       itt_t init_task_tag)
 {
        struct iscsi_cmd *cmd = NULL;
        struct iscsi_conn_recovery *cr;
@@ -855,7 +855,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
        cmd->iscsi_opcode = ISCSI_OP_NOOP_IN;
        state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
                                ISTATE_SEND_NOPIN_NO_RESPONSE;
-       cmd->init_task_tag = 0xFFFFFFFF;
+       cmd->init_task_tag = RESERVED_ITT;
        spin_lock_bh(&conn->sess->ttt_lock);
        cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ :
                        0xFFFFFFFF;
@@ -1222,7 +1222,7 @@ int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_deta
        hdr->opcode             = ISCSI_OP_LOGIN_RSP;
        hdr->status_class       = status_class;
        hdr->status_detail      = status_detail;
-       hdr->itt                = cpu_to_be32(conn->login_itt);
+       hdr->itt                = conn->login_itt;
 
        iov.iov_base            = &iscsi_hdr;
        iov.iov_len             = ISCSI_HDR_LEN;
index e1c729b..44054bd 100644 (file)
@@ -12,14 +12,14 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
 extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u32 cmdsn);
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn);
 extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
-extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, u32);
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
 extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
-                       u32, u32);
+                       itt_t, u32);
 extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
 extern int iscsit_find_cmd_for_recovery(struct iscsi_session *, struct iscsi_cmd **,
-                       struct iscsi_conn_recovery **, u32);
+                       struct iscsi_conn_recovery **, itt_t);
 extern void iscsit_add_cmd_to_immediate_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
 extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *);
 extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
index 5491c63..2d444b1 100644 (file)
@@ -166,7 +166,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
        struct tcm_loop_tpg *tl_tpg;
        struct scatterlist *sgl_bidi = NULL;
        u32 sgl_bidi_count = 0;
-       int ret;
+       int rc;
 
        tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
        tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
@@ -187,12 +187,6 @@ static void tcm_loop_submission_work(struct work_struct *work)
                set_host_byte(sc, DID_ERROR);
                goto out_done;
        }
-
-       transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo,
-                       tl_nexus->se_sess,
-                       scsi_bufflen(sc), sc->sc_data_direction,
-                       tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]);
-
        if (scsi_bidi_cmnd(sc)) {
                struct scsi_data_buffer *sdb = scsi_in(sc);
 
@@ -201,56 +195,16 @@ static void tcm_loop_submission_work(struct work_struct *work)
                se_cmd->se_cmd_flags |= SCF_BIDI;
 
        }
-
-       if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
-               kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
+       rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
+                       &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
+                       scsi_bufflen(sc), tcm_loop_sam_attr(sc),
+                       sc->sc_data_direction, 0,
+                       scsi_sglist(sc), scsi_sg_count(sc),
+                       sgl_bidi, sgl_bidi_count);
+       if (rc < 0) {
                set_host_byte(sc, DID_NO_CONNECT);
                goto out_done;
        }
-
-       /*
-        * Because some userspace code via scsi-generic do not memset their
-        * associated read buffers, go ahead and do that here for type
-        * non-data CDBs.  Also note that this is currently guaranteed to be a
-        * single SGL for this case by target core in
-        * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer().
-        */
-       if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
-           se_cmd->data_direction == DMA_FROM_DEVICE) {
-               struct scatterlist *sg = scsi_sglist(sc);
-               unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
-
-               if (buf != NULL) {
-                       memset(buf, 0, sg->length);
-                       kunmap(sg_page(sg));
-               }
-       }
-
-       ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
-       if (ret == -ENOMEM) {
-               transport_send_check_condition_and_sense(se_cmd,
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       } else if (ret < 0) {
-               if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
-                       tcm_loop_queue_status(se_cmd);
-               else
-                       transport_send_check_condition_and_sense(se_cmd,
-                                       se_cmd->scsi_sense_reason, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       }
-
-       ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
-                       scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
-       if (ret) {
-               transport_send_check_condition_and_sense(se_cmd,
-                                       se_cmd->scsi_sense_reason, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       }
-       transport_handle_cdb_direct(se_cmd);
        return;
 
 out_done:
@@ -846,16 +800,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
-       return 0;
-}
-
-static u16 tcm_loop_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
 static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
 {
        switch (tl_hba->tl_proto_id) {
@@ -1373,8 +1317,6 @@ static int tcm_loop_register_configfs(void)
        fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
        fabric->tf_ops.queue_status = &tcm_loop_queue_status;
        fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
-       fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len;
-       fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len;
 
        /*
         * Setup function pointers for generic logic in target_core_fabric_configfs.c
index 39ddba5..0d6d7c1 100644 (file)
@@ -660,8 +660,7 @@ static void session_reconnect_expired(struct sbp_session *sess)
        spin_lock_bh(&sess->lock);
        list_for_each_entry_safe(login, temp, &sess->login_list, link) {
                login->sess = NULL;
-               list_del(&login->link);
-               list_add_tail(&login->link, &login_list);
+               list_move_tail(&login->link, &login_list);
        }
        spin_unlock_bh(&sess->lock);
 
@@ -1847,16 +1846,6 @@ static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
-       return 0;
-}
-
-static u16 sbp_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
 static int sbp_check_stop_free(struct se_cmd *se_cmd)
 {
        struct sbp_target_request *req = container_of(se_cmd,
@@ -2068,7 +2057,7 @@ static int sbp_update_unit_directory(struct sbp_tport *tport)
        return ret;
 }
 
-static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn)
 {
        const char *cp;
        char c, nibble;
@@ -2088,7 +2077,7 @@ static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
                err = 3;
                if (isdigit(c))
                        nibble = c - '0';
-               else if (isxdigit(c) && (islower(c) || !strict))
+               else if (isxdigit(c))
                        nibble = tolower(c) - 'a' + 10;
                else
                        goto fail;
@@ -2117,7 +2106,7 @@ static struct se_node_acl *sbp_make_nodeacl(
        u64 guid = 0;
        u32 nexus_depth = 1;
 
-       if (sbp_parse_wwn(name, &guid, 1) < 0)
+       if (sbp_parse_wwn(name, &guid) < 0)
                return ERR_PTR(-EINVAL);
 
        se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
@@ -2253,7 +2242,7 @@ static struct se_wwn *sbp_make_tport(
        struct sbp_tport *tport;
        u64 guid = 0;
 
-       if (sbp_parse_wwn(name, &guid, 1) < 0)
+       if (sbp_parse_wwn(name, &guid) < 0)
                return ERR_PTR(-EINVAL);
 
        tport = kzalloc(sizeof(*tport), GFP_KERNEL);
@@ -2534,8 +2523,6 @@ static struct target_core_fabric_ops sbp_ops = {
        .queue_data_in                  = sbp_queue_data_in,
        .queue_status                   = sbp_queue_status,
        .queue_tm_rsp                   = sbp_queue_tm_rsp,
-       .get_fabric_sense_len           = sbp_get_fabric_sense_len,
-       .set_fabric_sense_len           = sbp_set_fabric_sense_len,
        .check_stop_free                = sbp_check_stop_free,
 
        .fabric_make_wwn                = sbp_make_tport,
@@ -2556,9 +2543,9 @@ static int sbp_register_configfs(void)
        int ret;
 
        fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
-       if (!fabric) {
+       if (IS_ERR(fabric)) {
                pr_err("target_fabric_configfs_init() failed\n");
-               return -ENOMEM;
+               return PTR_ERR(fabric);
        }
 
        fabric->tf_ops = sbp_ops;
index 41641ba..9a5f9a7 100644 (file)
@@ -344,7 +344,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)
                         */
                        rtpi = get_unaligned_be16(ptr + 2);
                        /*
-                        * Locate the matching relative target port identifer
+                        * Locate the matching relative target port identifier
                         * for the struct se_device storage object.
                         */
                        spin_lock(&dev->se_port_lock);
index 801efa8..015f5be 100644 (file)
@@ -457,14 +457,6 @@ static int target_fabric_tf_ops_check(
                pr_err("Missing tfo->queue_tm_rsp()\n");
                return -EINVAL;
        }
-       if (!tfo->set_fabric_sense_len) {
-               pr_err("Missing tfo->set_fabric_sense_len()\n");
-               return -EINVAL;
-       }
-       if (!tfo->get_fabric_sense_len) {
-               pr_err("Missing tfo->get_fabric_sense_len()\n");
-               return -EINVAL;
-       }
        /*
         * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
         * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
@@ -1208,7 +1200,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
                " Target Node Endpoint: %s\n", tfo->get_fabric_name(),
                tfo->tpg_get_wwn(se_tpg));
        len += sprintf(page+len, "SPC-3 Reservation: Relative Port"
-               " Identifer Tag: %hu %s Portal Group Tag: %hu"
+               " Identifier Tag: %hu %s Portal Group Tag: %hu"
                " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi,
                tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg),
                tfo->get_fabric_name(), lun->unpacked_lun);
@@ -3132,6 +3124,7 @@ static int __init target_core_init_configfs(void)
                                GFP_KERNEL);
        if (!target_cg->default_groups) {
                pr_err("Unable to allocate target_cg->default_groups\n");
+               ret = -ENOMEM;
                goto out_global;
        }
 
@@ -3147,6 +3140,7 @@ static int __init target_core_init_configfs(void)
                                GFP_KERNEL);
        if (!hba_cg->default_groups) {
                pr_err("Unable to allocate hba_cg->default_groups\n");
+               ret = -ENOMEM;
                goto out_global;
        }
        config_group_init_type_name(&alua_group,
@@ -3162,6 +3156,7 @@ static int __init target_core_init_configfs(void)
                        GFP_KERNEL);
        if (!alua_cg->default_groups) {
                pr_err("Unable to allocate alua_cg->default_groups\n");
+               ret = -ENOMEM;
                goto out_global;
        }
 
@@ -3173,14 +3168,17 @@ static int __init target_core_init_configfs(void)
         * Add core/alua/lu_gps/default_lu_gp
         */
        lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1);
-       if (IS_ERR(lu_gp))
+       if (IS_ERR(lu_gp)) {
+               ret = -ENOMEM;
                goto out_global;
+       }
 
        lu_gp_cg = &alua_lu_gps_group;
        lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
                        GFP_KERNEL);
        if (!lu_gp_cg->default_groups) {
                pr_err("Unable to allocate lu_gp_cg->default_groups\n");
+               ret = -ENOMEM;
                goto out_global;
        }
 
index 9fc9a60..8d774da 100644 (file)
@@ -531,7 +531,7 @@ static struct se_port *core_alloc_port(struct se_device *dev)
        }
 again:
        /*
-        * Allocate the next RELATIVE TARGET PORT IDENTIFER for this struct se_device
+        * Allocate the next RELATIVE TARGET PORT IDENTIFIER for this struct se_device
         * Here is the table from spc4r17 section 7.7.3.8.
         *
         *    Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
@@ -548,7 +548,7 @@ again:
 
        list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) {
                /*
-                * Make sure RELATIVE TARGET PORT IDENTIFER is unique
+                * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
                 * for 16-bit wrap..
                 */
                if (port->sep_rtpi == port_tmp->sep_rtpi)
@@ -595,7 +595,7 @@ static void core_export_port(
        }
 
        dev->dev_port_count++;
-       port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFER */
+       port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFIER */
 }
 
 /*
@@ -988,8 +988,9 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                return -EINVAL;
        }
 
-       if (flag && dev->transport->fua_write_emulated == 0) {
-               pr_err("fua_write_emulated not supported\n");
+       if (flag &&
+           dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+               pr_err("emulate_fua_write not supported for pSCSI\n");
                return -EINVAL;
        }
        dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
@@ -1019,8 +1020,9 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                return -EINVAL;
        }
-       if (flag && dev->transport->write_cache_emulated == 0) {
-               pr_err("write_cache_emulated not supported\n");
+       if (flag &&
+           dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+               pr_err("emulate_write_cache not supported for pSCSI\n");
                return -EINVAL;
        }
        dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
index ea479e5..bca737b 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/init.h>
 #include <linux/fs.h>
index 283a36e..e460d62 100644 (file)
@@ -338,7 +338,7 @@ u32 iscsi_get_pr_transport_id_len(
         * 00b: iSCSI Initiator device TransportID format
         */
        if (pr_reg->isid_present_at_reg) {
-               len += 5; /* For ",i,0x" ASCII seperator */
+               len += 5; /* For ",i,0x" ASCII separator */
                len += 7; /* For iSCSI Initiator Session ID + Null terminator */
                *format_code = 1;
        } else
@@ -415,20 +415,20 @@ char *iscsi_parse_pr_out_transport_id(
                        *out_tid_len = (add_len + 4);
        }
        /*
-        * Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator
+        * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator
         * Session ID as defined in Table 390 - iSCSI initiator port TransportID
         * format.
         */
        if (format_code == 0x40) {
                p = strstr(&buf[4], ",i,0x");
                if (!p) {
-                       pr_err("Unable to locate \",i,0x\" seperator"
+                       pr_err("Unable to locate \",i,0x\" separator"
                                " for Initiator port identifier: %s\n",
                                &buf[4]);
                        return NULL;
                }
                *p = '\0'; /* Terminate iSCSI Name */
-               p += 5; /* Skip over ",i,0x" seperator */
+               p += 5; /* Skip over ",i,0x" separator */
 
                *port_nexus_ptr = p;
                /*
index cbb5aaf..0360383 100644 (file)
@@ -125,6 +125,19 @@ static struct se_device *fd_create_virtdevice(
         * of pure timestamp updates.
         */
        flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
+       /*
+        * Optionally allow fd_buffered_io=1 to be enabled for people
+        * who want use the fs buffer cache as an WriteCache mechanism.
+        *
+        * This means that in event of a hard failure, there is a risk
+        * of silent data-loss if the SCSI client has *not* performed a
+        * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE
+        * to write-out the entire device cache.
+        */
+       if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
+               pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");
+               flags &= ~O_DSYNC;
+       }
 
        file = filp_open(fd_dev->fd_dev_name, flags, 0600);
        if (IS_ERR(file)) {
@@ -188,6 +201,12 @@ static struct se_device *fd_create_virtdevice(
        if (!dev)
                goto fail;
 
+       if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
+               pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"
+                       " with FDBD_HAS_BUFFERED_IO_WCE\n");
+               dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1;
+       }
+
        fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
        fd_dev->fd_queue_depth = dev->queue_depth;
 
@@ -407,6 +426,7 @@ enum {
 static match_table_t tokens = {
        {Opt_fd_dev_name, "fd_dev_name=%s"},
        {Opt_fd_dev_size, "fd_dev_size=%s"},
+       {Opt_fd_buffered_io, "fd_buffered_io=%d"},
        {Opt_err, NULL}
 };
 
@@ -418,7 +438,7 @@ static ssize_t fd_set_configfs_dev_params(
        struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
        char *orig, *ptr, *arg_p, *opts;
        substring_t args[MAX_OPT_ARGS];
-       int ret = 0, token;
+       int ret = 0, arg, token;
 
        opts = kstrdup(page, GFP_KERNEL);
        if (!opts)
@@ -459,6 +479,19 @@ static ssize_t fd_set_configfs_dev_params(
                                        " bytes\n", fd_dev->fd_dev_size);
                        fd_dev->fbd_flags |= FBDF_HAS_SIZE;
                        break;
+               case Opt_fd_buffered_io:
+                       match_int(args, &arg);
+                       if (arg != 1) {
+                               pr_err("bogus fd_buffered_io=%d value\n", arg);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       pr_debug("FILEIO: Using buffered I/O"
+                               " operations for struct fd_dev\n");
+
+                       fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE;
+                       break;
                default:
                        break;
                }
@@ -490,8 +523,10 @@ static ssize_t fd_show_configfs_dev_params(
        ssize_t bl = 0;
 
        bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
-       bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: O_DSYNC\n",
-               fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+       bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: %s\n",
+               fd_dev->fd_dev_name, fd_dev->fd_dev_size,
+               (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ?
+               "Buffered-WCE" : "O_DSYNC");
        return bl;
 }
 
@@ -546,8 +581,6 @@ static struct se_subsystem_api fileio_template = {
        .name                   = "fileio",
        .owner                  = THIS_MODULE,
        .transport_type         = TRANSPORT_PLUGIN_VHBA_PDEV,
-       .write_cache_emulated   = 1,
-       .fua_write_emulated     = 1,
        .attach_hba             = fd_attach_hba,
        .detach_hba             = fd_detach_hba,
        .allocate_virtdevice    = fd_allocate_virtdevice,
index 70ce7fd..876ae53 100644 (file)
@@ -14,6 +14,7 @@
 
 #define FBDF_HAS_PATH          0x01
 #define FBDF_HAS_SIZE          0x02
+#define FDBD_HAS_BUFFERED_IO_WCE 0x04
 
 struct fd_dev {
        u32             fbd_flags;
index 9ba4954..29408d4 100644 (file)
@@ -454,14 +454,11 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
                                ret = -EEXIST;
                                goto out;
                        }
-                       arg_p = match_strdup(&args[0]);
-                       if (!arg_p) {
-                               ret = -ENOMEM;
+                       if (match_strlcpy(ib_dev->ibd_udev_path, &args[0],
+                               SE_UDEV_PATH_LEN) == 0) {
+                               ret = -EINVAL;
                                break;
                        }
-                       snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN,
-                                       "%s", arg_p);
-                       kfree(arg_p);
                        pr_debug("IBLOCK: Referencing UDEV path: %s\n",
                                        ib_dev->ibd_udev_path);
                        ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
@@ -657,6 +654,12 @@ static int iblock_execute_rw(struct se_cmd *cmd)
                goto fail;
        cmd->priv = ibr;
 
+       if (!sgl_nents) {
+               atomic_set(&ibr->pending, 1);
+               iblock_complete_cmd(cmd);
+               return 0;
+       }
+
        bio = iblock_get_bio(cmd, block_lba, sgl_nents);
        if (!bio)
                goto fail_free_ibr;
@@ -769,8 +772,6 @@ static struct se_subsystem_api iblock_template = {
        .name                   = "iblock",
        .owner                  = THIS_MODULE,
        .transport_type         = TRANSPORT_PLUGIN_VHBA_PDEV,
-       .write_cache_emulated   = 1,
-       .fua_write_emulated     = 1,
        .attach_hba             = iblock_attach_hba,
        .detach_hba             = iblock_detach_hba,
        .allocate_virtdevice    = iblock_allocate_virtdevice,
index 956c84c..8c323a9 100644 (file)
@@ -197,10 +197,10 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_session *sess = cmd->se_sess;
-       struct se_portal_group *tpg = sess->se_tpg;
+       struct se_portal_group *tpg;
        int ret = 0, rc;
 
-       if (!sess || !tpg)
+       if (!sess || !sess->se_tpg)
                goto out;
        rc = target_check_scsi2_reservation_conflict(cmd);
        if (rc == 1)
@@ -228,6 +228,7 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)
                dev->dev_res_bin_isid = 0;
                dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
        }
+       tpg = sess->se_tpg;
        pr_debug("SCSI-2 Released reservation for %s LUN: %u ->"
                " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
                cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
@@ -245,7 +246,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_session *sess = cmd->se_sess;
-       struct se_portal_group *tpg = sess->se_tpg;
+       struct se_portal_group *tpg;
        int ret = 0, rc;
 
        if ((cmd->t_task_cdb[1] & 0x01) &&
@@ -260,7 +261,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
         * This is currently the case for target_core_mod passthrough struct se_cmd
         * ops
         */
-       if (!sess || !tpg)
+       if (!sess || !sess->se_tpg)
                goto out;
        rc = target_check_scsi2_reservation_conflict(cmd);
        if (rc == 1)
@@ -272,6 +273,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
        }
 
        ret = 0;
+       tpg = sess->se_tpg;
        spin_lock(&dev->dev_reservation_lock);
        if (dev->dev_reserved_node_acl &&
           (dev->dev_reserved_node_acl != sess->se_node_acl)) {
@@ -1620,7 +1622,7 @@ static int core_scsi3_decode_spec_i_port(
                                goto out;
                        }
                        /*
-                        * Locate the desination initiator ACL to be registered
+                        * Locate the destination initiator ACL to be registered
                         * from the decoded fabric module specific TransportID
                         * at *i_str.
                         */
@@ -4257,7 +4259,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
                        buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
                        buf[off++] = (port->sep_rtpi & 0xff);
                } else
-                       off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */
+                       off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */
 
                /*
                 * Now, have the $FABRIC_MOD fill in the protocol identifier
index 9d7ce3d..617c086 100644 (file)
@@ -264,7 +264,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
                                        " length zero!\n");
                        break;
                }
-               pr_debug("T10 VPD Identifer Length: %d\n", ident_len);
+               pr_debug("T10 VPD Identifier Length: %d\n", ident_len);
 
                vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL);
                if (!vpd) {
index a9dd946..868f8aa 100644 (file)
@@ -40,8 +40,9 @@
 static int sbc_emulate_readcapacity(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
-       unsigned char *buf;
        unsigned long long blocks_long = dev->transport->get_blocks(dev);
+       unsigned char *rbuf;
+       unsigned char buf[8];
        u32 blocks;
 
        if (blocks_long >= 0x00000000ffffffff)
@@ -49,8 +50,6 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
        else
                blocks = (u32)blocks_long;
 
-       buf = transport_kmap_data_sg(cmd);
-
        buf[0] = (blocks >> 24) & 0xff;
        buf[1] = (blocks >> 16) & 0xff;
        buf[2] = (blocks >> 8) & 0xff;
@@ -60,7 +59,11 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
        buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
        buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
 
-       transport_kunmap_data_sg(cmd);
+       rbuf = transport_kmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
@@ -69,11 +72,11 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
 static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
-       unsigned char *buf;
+       unsigned char *rbuf;
+       unsigned char buf[32];
        unsigned long long blocks = dev->transport->get_blocks(dev);
 
-       buf = transport_kmap_data_sg(cmd);
-
+       memset(buf, 0, sizeof(buf));
        buf[0] = (blocks >> 56) & 0xff;
        buf[1] = (blocks >> 48) & 0xff;
        buf[2] = (blocks >> 40) & 0xff;
@@ -93,7 +96,11 @@ static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
        if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
                buf[14] = 0x80;
 
-       transport_kunmap_data_sg(cmd);
+       rbuf = transport_kmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
index 388a922..9229bd9 100644 (file)
@@ -600,30 +600,11 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
-       unsigned char *buf, *map_buf;
+       unsigned char *rbuf;
        unsigned char *cdb = cmd->t_task_cdb;
+       unsigned char buf[SE_INQUIRY_BUF];
        int p, ret;
 
-       map_buf = transport_kmap_data_sg(cmd);
-       /*
-        * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
-        * know we actually allocated a full page.  Otherwise, if the
-        * data buffer is too small, allocate a temporary buffer so we
-        * don't have to worry about overruns in all our INQUIRY
-        * emulation handling.
-        */
-       if (cmd->data_length < SE_INQUIRY_BUF &&
-           (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
-               buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
-               if (!buf) {
-                       transport_kunmap_data_sg(cmd);
-                       cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-                       return -ENOMEM;
-               }
-       } else {
-               buf = map_buf;
-       }
-
        if (dev == tpg->tpg_virt_lun0.lun_se_dev)
                buf[0] = 0x3f; /* Not connected */
        else
@@ -655,11 +636,11 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
        ret = -EINVAL;
 
 out:
-       if (buf != map_buf) {
-               memcpy(map_buf, buf, cmd->data_length);
-               kfree(buf);
+       rbuf = transport_kmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
        }
-       transport_kunmap_data_sg(cmd);
 
        if (!ret)
                target_complete_cmd(cmd, GOOD);
@@ -803,7 +784,7 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
        unsigned char *rbuf;
        int type = dev->transport->get_device_type(dev);
        int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
-       int offset = ten ? 8 : 4;
+       u32 offset = ten ? 8 : 4;
        int length = 0;
        unsigned char buf[SE_MODE_PAGE_BUF];
 
@@ -836,6 +817,7 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
                offset -= 2;
                buf[0] = (offset >> 8) & 0xff;
                buf[1] = offset & 0xff;
+               offset += 2;
 
                if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
                    (cmd->se_deve &&
@@ -845,13 +827,10 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
                if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
                    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
                        spc_modesense_dpofua(&buf[3], type);
-
-               if ((offset + 2) > cmd->data_length)
-                       offset = cmd->data_length;
-
        } else {
                offset -= 1;
                buf[0] = offset & 0xff;
+               offset += 1;
 
                if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
                    (cmd->se_deve &&
@@ -861,14 +840,13 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
                if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
                    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
                        spc_modesense_dpofua(&buf[2], type);
-
-               if ((offset + 1) > cmd->data_length)
-                       offset = cmd->data_length;
        }
 
        rbuf = transport_kmap_data_sg(cmd);
-       memcpy(rbuf, buf, offset);
-       transport_kunmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min(offset, cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
index 3d44beb..cb6b003 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/string.h>
-#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
index b8628a5..a531fe2 100644 (file)
@@ -303,7 +303,7 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
        }
        /*
         * Here we only create demo-mode MappedLUNs from the active
-        * TPG LUNs if the fabric is not explictly asking for
+        * TPG LUNs if the fabric is not explicitly asking for
         * tpg_check_demo_mode_login_only() == 1.
         */
        if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) ||
index 269f544..c33baff 100644 (file)
@@ -55,8 +55,6 @@
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
-static int sub_api_initialized;
-
 static struct workqueue_struct *target_completion_wq;
 static struct kmem_cache *se_sess_cache;
 struct kmem_cache *se_ua_cache;
@@ -195,6 +193,7 @@ u32 scsi_get_new_index(scsi_index_t type)
 void transport_subsystem_check_init(void)
 {
        int ret;
+       static int sub_api_initialized;
 
        if (sub_api_initialized)
                return;
@@ -211,12 +210,7 @@ void transport_subsystem_check_init(void)
        if (ret != 0)
                pr_err("Unable to load target_core_pscsi\n");
 
-       ret = request_module("target_core_stgt");
-       if (ret != 0)
-               pr_err("Unable to load target_core_stgt\n");
-
        sub_api_initialized = 1;
-       return;
 }
 
 struct se_session *transport_init_session(void)
@@ -573,9 +567,7 @@ static void target_complete_failure_work(struct work_struct *work)
  */
 static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
 {
-       unsigned char *buffer = cmd->sense_buffer;
        struct se_device *dev = cmd->se_dev;
-       u32 offset = 0;
 
        WARN_ON(!cmd->se_lun);
 
@@ -585,14 +577,11 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
        if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
                return NULL;
 
-       offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
-
-       /* Automatically padded */
-       cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+       cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
 
        pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n",
                dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
-       return &buffer[offset];
+       return cmd->sense_buffer;
 }
 
 void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
@@ -969,7 +958,7 @@ int
 transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
 {
        static const char hex_str[] = "0123456789abcdef";
-       int j = 0, i = 4; /* offset to start of the identifer */
+       int j = 0, i = 4; /* offset to start of the identifier */
 
        /*
         * The VPD Code Set (encoding)
@@ -1466,8 +1455,9 @@ int transport_handle_cdb_direct(
 }
 EXPORT_SYMBOL(transport_handle_cdb_direct);
 
-/**
- * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
+/*
+ * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized
+ *                      se_cmd + use pre-allocated SGL memory.
  *
  * @se_cmd: command descriptor to submit
  * @se_sess: associated se_sess for endpoint
@@ -1478,6 +1468,10 @@ EXPORT_SYMBOL(transport_handle_cdb_direct);
  * @task_addr: SAM task attribute
  * @data_dir: DMA data direction
  * @flags: flags for command submission from target_sc_flags_tables
+ * @sgl: struct scatterlist memory for unidirectional mapping
+ * @sgl_count: scatterlist count for unidirectional mapping
+ * @sgl_bidi: struct scatterlist memory for bidirectional READ mapping
+ * @sgl_bidi_count: scatterlist count for bidirectional READ mapping
  *
  * Returns non zero to signal active I/O shutdown failure.  All other
  * setup exceptions will be returned as a SCSI CHECK_CONDITION response,
@@ -1485,10 +1479,12 @@ EXPORT_SYMBOL(transport_handle_cdb_direct);
  *
  * This may only be called from process context, and also currently
  * assumes internal allocation of fabric payload buffer by target-core.
- **/
-int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+ */
+int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess,
                unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
-               u32 data_length, int task_attr, int data_dir, int flags)
+               u32 data_length, int task_attr, int data_dir, int flags,
+               struct scatterlist *sgl, u32 sgl_count,
+               struct scatterlist *sgl_bidi, u32 sgl_bidi_count)
 {
        struct se_portal_group *se_tpg;
        int rc;
@@ -1535,7 +1531,42 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
                transport_generic_request_failure(se_cmd);
                return 0;
        }
+       /*
+        * When a non zero sgl_count has been passed perform SGL passthrough
+        * mapping for pre-allocated fabric memory instead of having target
+        * core perform an internal SGL allocation..
+        */
+       if (sgl_count != 0) {
+               BUG_ON(!sgl);
+
+               /*
+                * A work-around for tcm_loop as some userspace code via
+                * scsi-generic do not memset their associated read buffers,
+                * so go ahead and do that here for type non-data CDBs.  Also
+                * note that this is currently guaranteed to be a single SGL
+                * for this case by target core in target_setup_cmd_from_cdb()
+                * -> transport_generic_cmd_sequencer().
+                */
+               if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
+                    se_cmd->data_direction == DMA_FROM_DEVICE) {
+                       unsigned char *buf = NULL;
+
+                       if (sgl)
+                               buf = kmap(sg_page(sgl)) + sgl->offset;
+
+                       if (buf) {
+                               memset(buf, 0, sgl->length);
+                               kunmap(sg_page(sgl));
+                       }
+               }
 
+               rc = transport_generic_map_mem_to_cmd(se_cmd, sgl, sgl_count,
+                               sgl_bidi, sgl_bidi_count);
+               if (rc != 0) {
+                       transport_generic_request_failure(se_cmd);
+                       return 0;
+               }
+       }
        /*
         * Check if we need to delay processing because of ALUA
         * Active/NonOptimized primary access state..
@@ -1545,6 +1576,38 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
        transport_handle_cdb_direct(se_cmd);
        return 0;
 }
+EXPORT_SYMBOL(target_submit_cmd_map_sgls);
+
+/*
+ * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
+ *
+ * @se_cmd: command descriptor to submit
+ * @se_sess: associated se_sess for endpoint
+ * @cdb: pointer to SCSI CDB
+ * @sense: pointer to SCSI sense buffer
+ * @unpacked_lun: unpacked LUN to reference for struct se_lun
+ * @data_length: fabric expected data transfer length
+ * @task_addr: SAM task attribute
+ * @data_dir: DMA data direction
+ * @flags: flags for command submission from target_sc_flags_tables
+ *
+ * Returns non zero to signal active I/O shutdown failure.  All other
+ * setup exceptions will be returned as a SCSI CHECK_CONDITION response,
+ * but still return zero here.
+ *
+ * This may only be called from process context, and also currently
+ * assumes internal allocation of fabric payload buffer by target-core.
+ *
+ * It also assumes interal target core SGL memory allocation.
+ */
+int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+               unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
+               u32 data_length, int task_attr, int data_dir, int flags)
+{
+       return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense,
+                       unpacked_lun, data_length, task_attr, data_dir,
+                       flags, NULL, 0, NULL, 0);
+}
 EXPORT_SYMBOL(target_submit_cmd);
 
 static void target_complete_tmr_failure(struct work_struct *work)
@@ -2300,23 +2363,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
                if (ret < 0)
                        goto out_fail;
        }
-       /*
-        * If this command doesn't have any payload and we don't have to call
-        * into the fabric for data transfers, go ahead and complete it right
-        * away.
-        */
-       if (!cmd->data_length &&
-           cmd->t_task_cdb[0] != REQUEST_SENSE &&
-           cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
-               spin_lock_irq(&cmd->t_state_lock);
-               cmd->t_state = TRANSPORT_COMPLETE;
-               cmd->transport_state |= CMD_T_ACTIVE;
-               spin_unlock_irq(&cmd->t_state_lock);
-
-               INIT_WORK(&cmd->work, target_complete_ok_work);
-               queue_work(target_completion_wq, &cmd->work);
-               return 0;
-       }
 
        atomic_inc(&cmd->t_fe_count);
 
@@ -2771,7 +2817,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
        spin_lock_irqsave(&cmd->t_state_lock, flags);
        cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
 
-       pr_debug("wait_for_tasks: Stopped wait_for_compltion("
+       pr_debug("wait_for_tasks: Stopped wait_for_completion("
                "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n",
                cmd->se_tfo->get_task_tag(cmd));
 
@@ -2810,7 +2856,6 @@ int transport_send_check_condition_and_sense(
 {
        unsigned char *buffer = cmd->sense_buffer;
        unsigned long flags;
-       int offset;
        u8 asc = 0, ascq = 0;
 
        spin_lock_irqsave(&cmd->t_state_lock, flags);
@@ -2826,14 +2871,7 @@ int transport_send_check_condition_and_sense(
 
        if (!from_transport)
                cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
-       /*
-        * Data Segment and SenseLength of the fabric response PDU.
-        *
-        * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE
-        * from include/scsi/scsi_cmnd.h
-        */
-       offset = cmd->se_tfo->set_fabric_sense_len(cmd,
-                               TRANSPORT_SENSE_BUFFER);
+
        /*
         * Actual SENSE DATA, see SPC-3 7.23.2  SPC_SENSE_KEY_OFFSET uses
         * SENSE KEY values from include/scsi/scsi.h
@@ -2841,151 +2879,151 @@ int transport_send_check_condition_and_sense(
        switch (reason) {
        case TCM_NON_EXISTENT_LUN:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL UNIT NOT SUPPORTED */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x25;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x25;
                break;
        case TCM_UNSUPPORTED_SCSI_OPCODE:
        case TCM_SECTOR_COUNT_TOO_MANY:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID COMMAND OPERATION CODE */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x20;
                break;
        case TCM_UNKNOWN_MODE_PAGE:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID FIELD IN CDB */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x24;
                break;
        case TCM_CHECK_CONDITION_ABORT_CMD:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* BUS DEVICE RESET FUNCTION OCCURRED */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29;
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x29;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
                break;
        case TCM_INCORRECT_AMOUNT_OF_DATA:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* WRITE ERROR */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
                /* NOT ENOUGH UNSOLICITED DATA */
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d;
                break;
        case TCM_INVALID_CDB_FIELD:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID FIELD IN CDB */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x24;
                break;
        case TCM_INVALID_PARAMETER_LIST:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID FIELD IN PARAMETER LIST */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x26;
                break;
        case TCM_UNEXPECTED_UNSOLICITED_DATA:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* WRITE ERROR */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
                /* UNEXPECTED_UNSOLICITED_DATA */
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c;
                break;
        case TCM_SERVICE_CRC_ERROR:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* PROTOCOL SERVICE CRC ERROR */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x47;
                /* N/A */
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x05;
                break;
        case TCM_SNACK_REJECTED:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* READ ERROR */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x11;
                /* FAILED RETRANSMISSION REQUEST */
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x13;
                break;
        case TCM_WRITE_PROTECTED:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* DATA PROTECT */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
+               buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
                /* WRITE PROTECTED */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x27;
                break;
        case TCM_ADDRESS_OUT_OF_RANGE:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL BLOCK ADDRESS OUT OF RANGE */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x21;
                break;
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* UNIT ATTENTION */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+               buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
                core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
-               buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+               buffer[SPC_ASC_KEY_OFFSET] = asc;
+               buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
                break;
        case TCM_CHECK_CONDITION_NOT_READY:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* Not Ready */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
+               buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
                transport_get_sense_codes(cmd, &asc, &ascq);
-               buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
-               buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+               buffer[SPC_ASC_KEY_OFFSET] = asc;
+               buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
                break;
        case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
        default:
                /* CURRENT ERROR */
-               buffer[offset] = 0x70;
-               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
-               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL UNIT COMMUNICATION FAILURE */
-               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x80;
                break;
        }
        /*
@@ -2996,7 +3034,7 @@ int transport_send_check_condition_and_sense(
         * Automatically padded, this value is encoded in the fabric's
         * data_length response PDU containing the SCSI defined sense data.
         */
-       cmd->scsi_sense_length  = TRANSPORT_SENSE_BUFFER + offset;
+       cmd->scsi_sense_length  = TRANSPORT_SENSE_BUFFER;
 
 after_reason:
        return cmd->se_tfo->queue_status(cmd);
index 823e692..b406f17 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 9501844..b74feb0 100644 (file)
@@ -495,16 +495,6 @@ static void ft_set_default_node_attr(struct se_node_acl *se_nacl)
 {
 }
 
-static u16 ft_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
-static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len)
-{
-       return 0;
-}
-
 static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
 {
        struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
@@ -542,8 +532,6 @@ static struct target_core_fabric_ops ft_fabric_ops = {
        .queue_data_in =                ft_queue_data_in,
        .queue_status =                 ft_queue_status,
        .queue_tm_rsp =                 ft_queue_tm_resp,
-       .get_fabric_sense_len =         ft_get_fabric_sense_len,
-       .set_fabric_sense_len =         ft_set_fabric_sense_len,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
index ad36ede..b6fd4cf 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -328,11 +327,12 @@ drop:
  */
 void ft_invl_hw_context(struct ft_cmd *cmd)
 {
-       struct fc_seq *seq = cmd->seq;
+       struct fc_seq *seq;
        struct fc_exch *ep = NULL;
        struct fc_lport *lport = NULL;
 
        BUG_ON(!cmd);
+       seq = cmd->seq;
 
        /* Cleanup the DDP context in HW if DDP was setup */
        if (cmd->was_ddp_setup && seq) {
index 3c9e5b5..9585010 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index eaa1005..97e68b3 100644 (file)
@@ -1472,16 +1472,6 @@ static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
-       return 0;
-}
-
-static u16 usbg_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
 static const char *usbg_check_wwn(const char *name)
 {
        const char *n;
@@ -1822,7 +1812,7 @@ static ssize_t tcm_usbg_tpg_store_nexus(
                ret = tcm_usbg_drop_nexus(tpg);
                return (!ret) ? count : ret;
        }
-       if (strlen(page) > USBG_NAMELEN) {
+       if (strlen(page) >= USBG_NAMELEN) {
                pr_err("Emulated NAA Sas Address: %s, exceeds"
                                " max: %d\n", page, USBG_NAMELEN);
                return -EINVAL;
@@ -1907,8 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = {
        .queue_data_in                  = usbg_send_read_response,
        .queue_status                   = usbg_send_status_response,
        .queue_tm_rsp                   = usbg_queue_tm_rsp,
-       .get_fabric_sense_len           = usbg_get_fabric_sense_len,
-       .set_fabric_sense_len           = usbg_set_fabric_sense_len,
        .check_stop_free                = usbg_check_stop_free,
 
        .fabric_make_wwn                = usbg_make_tport,
@@ -1968,7 +1956,6 @@ static void usbg_deregister_configfs(void)
 static struct usb_interface_descriptor bot_intf_desc = {
        .bLength =              sizeof(bot_intf_desc),
        .bDescriptorType =      USB_DT_INTERFACE,
-       .bAlternateSetting =    0,
        .bNumEndpoints =        2,
        .bAlternateSetting =    USB_G_ALT_INT_BBB,
        .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
index ed8e2e6..aa31692 100644 (file)
@@ -330,17 +330,6 @@ static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
        return 0;
 }
 
-static u16 tcm_vhost_set_fabric_sense_len(struct se_cmd *se_cmd,
-       u32 sense_length)
-{
-       return 0;
-}
-
-static u16 tcm_vhost_get_fabric_sense_len(void)
-{
-       return 0;
-}
-
 static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
 {
        struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
@@ -426,10 +415,7 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
 {
        struct tcm_vhost_cmd *tv_cmd;
        struct tcm_vhost_nexus *tv_nexus;
-       struct se_portal_group *se_tpg = &tv_tpg->se_tpg;
        struct se_session *se_sess;
-       struct se_cmd *se_cmd;
-       int sam_task_attr;
 
        tv_nexus = tv_tpg->tpg_nexus;
        if (!tv_nexus) {
@@ -445,23 +431,11 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
        }
        INIT_LIST_HEAD(&tv_cmd->tvc_completion_list);
        tv_cmd->tvc_tag = v_req->tag;
+       tv_cmd->tvc_task_attr = v_req->task_attr;
+       tv_cmd->tvc_exp_data_len = exp_data_len;
+       tv_cmd->tvc_data_direction = data_direction;
+       tv_cmd->tvc_nexus = tv_nexus;
 
-       se_cmd = &tv_cmd->tvc_se_cmd;
-       /*
-        * Locate the SAM Task Attr from virtio_scsi_cmd_req
-        */
-       sam_task_attr = v_req->task_attr;
-       /*
-        * Initialize struct se_cmd descriptor from TCM infrastructure
-        */
-       transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, exp_data_len,
-                               data_direction, sam_task_attr,
-                               &tv_cmd->tvc_sense_buf[0]);
-
-#if 0  /* FIXME: vhost_scsi_allocate_cmd() BIDI operation */
-       if (bidi)
-               se_cmd->se_cmd_flags |= SCF_BIDI;
-#endif
        return tv_cmd;
 }
 
@@ -560,37 +534,10 @@ static void tcm_vhost_submission_work(struct work_struct *work)
 {
        struct tcm_vhost_cmd *tv_cmd =
                container_of(work, struct tcm_vhost_cmd, work);
+       struct tcm_vhost_nexus *tv_nexus;
        struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
        struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
        int rc, sg_no_bidi = 0;
-       /*
-        * Locate the struct se_lun pointer based on v_req->lun, and
-        * attach it to struct se_cmd
-        */
-       rc = transport_lookup_cmd_lun(&tv_cmd->tvc_se_cmd, tv_cmd->tvc_lun);
-       if (rc < 0) {
-               pr_err("Failed to look up lun: %d\n", tv_cmd->tvc_lun);
-               transport_send_check_condition_and_sense(&tv_cmd->tvc_se_cmd,
-                       tv_cmd->tvc_se_cmd.scsi_sense_reason, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       }
-
-       rc = target_setup_cmd_from_cdb(se_cmd, tv_cmd->tvc_cdb);
-       if (rc == -ENOMEM) {
-               transport_send_check_condition_and_sense(se_cmd,
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       } else if (rc < 0) {
-               if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
-                       tcm_vhost_queue_status(se_cmd);
-               else
-                       transport_send_check_condition_and_sense(se_cmd,
-                                       se_cmd->scsi_sense_reason, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       }
 
        if (tv_cmd->tvc_sgl_count) {
                sg_ptr = tv_cmd->tvc_sgl;
@@ -608,17 +555,19 @@ static void tcm_vhost_submission_work(struct work_struct *work)
        } else {
                sg_ptr = NULL;
        }
-
-       rc = transport_generic_map_mem_to_cmd(se_cmd, sg_ptr,
-                               tv_cmd->tvc_sgl_count, sg_bidi_ptr,
-                               sg_no_bidi);
+       tv_nexus = tv_cmd->tvc_nexus;
+
+       rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess,
+                       tv_cmd->tvc_cdb, &tv_cmd->tvc_sense_buf[0],
+                       tv_cmd->tvc_lun, tv_cmd->tvc_exp_data_len,
+                       tv_cmd->tvc_task_attr, tv_cmd->tvc_data_direction,
+                       0, sg_ptr, tv_cmd->tvc_sgl_count,
+                       sg_bidi_ptr, sg_no_bidi);
        if (rc < 0) {
                transport_send_check_condition_and_sense(se_cmd,
-                               se_cmd->scsi_sense_reason, 0);
+                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
                transport_generic_free_cmd(se_cmd, 0);
-               return;
        }
-       transport_handle_cdb_direct(se_cmd);
 }
 
 static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
@@ -1531,8 +1480,6 @@ static struct target_core_fabric_ops tcm_vhost_ops = {
        .queue_data_in                  = tcm_vhost_queue_data_in,
        .queue_status                   = tcm_vhost_queue_status,
        .queue_tm_rsp                   = tcm_vhost_queue_tm_rsp,
-       .get_fabric_sense_len           = tcm_vhost_get_fabric_sense_len,
-       .set_fabric_sense_len           = tcm_vhost_set_fabric_sense_len,
        /*
         * Setup callers for generic logic in target_core_fabric_configfs.c
         */
index d9e9355..7e87c63 100644 (file)
@@ -5,6 +5,12 @@
 struct tcm_vhost_cmd {
        /* Descriptor from vhost_get_vq_desc() for virt_queue segment */
        int tvc_vq_desc;
+       /* virtio-scsi initiator task attribute */
+       int tvc_task_attr;
+       /* virtio-scsi initiator data direction */
+       enum dma_data_direction tvc_data_direction;
+       /* Expected data transfer length from virtio-scsi header */
+       u32 tvc_exp_data_len;
        /* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
        u64 tvc_tag;
        /* The number of scatterlists associated with this cmd */
@@ -17,6 +23,8 @@ struct tcm_vhost_cmd {
        struct virtio_scsi_cmd_resp __user *tvc_resp;
        /* Pointer to vhost_scsi for our device */
        struct vhost_scsi *tvc_vhost;
+       /* Pointer to vhost nexus memory */
+       struct tcm_vhost_nexus *tvc_nexus;
        /* The TCM I/O descriptor that is accessed via container_of() */
        struct se_cmd tvc_se_cmd;
        /* work item used for cmwq dispatch to tcm_vhost_submission_work() */
index 995f016..069983c 100644 (file)
@@ -213,7 +213,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        pb->exit = data->exit;
        pb->dev = &pdev->dev;
 
-       pb->pwm = pwm_get(&pdev->dev, NULL);
+       pb->pwm = devm_pwm_get(&pdev->dev, NULL);
        if (IS_ERR(pb->pwm)) {
                dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
 
@@ -246,7 +246,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                ret = PTR_ERR(bl);
-               goto err_bl;
+               goto err_alloc;
        }
 
        bl->props.brightness = data->dft_brightness;
@@ -255,8 +255,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, bl);
        return 0;
 
-err_bl:
-       pwm_put(pb->pwm);
 err_alloc:
        if (data->exit)
                data->exit(&pdev->dev);
@@ -271,7 +269,6 @@ static int pwm_backlight_remove(struct platform_device *pdev)
        backlight_device_unregister(bl);
        pwm_config(pb->pwm, 0, pb->period);
        pwm_disable(pb->pwm);
-       pwm_put(pb->pwm);
        if (pb->exit)
                pb->exit(&pdev->dev);
        return 0;
index 7ef14b3..e4fb3ba 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/utsname.h>
 #include <linux/kernel.h>
 #include <linux/ktime.h>
 #include <linux/slab.h>
@@ -19,6 +18,8 @@
 
 #include <asm/unaligned.h>
 
+#include "netns.h"
+
 #define NLMDBG_FACILITY                NLMDBG_MONITOR
 #define NSM_PROGRAM            100024
 #define NSM_VERSION            1
@@ -40,6 +41,7 @@ struct nsm_args {
        u32                     proc;
 
        char                    *mon_name;
+       char                    *nodename;
 };
 
 struct nsm_res {
@@ -70,7 +72,7 @@ static struct rpc_clnt *nsm_create(struct net *net)
        };
        struct rpc_create_args args = {
                .net                    = net,
-               .protocol               = XPRT_TRANSPORT_UDP,
+               .protocol               = XPRT_TRANSPORT_TCP,
                .address                = (struct sockaddr *)&sin,
                .addrsize               = sizeof(sin),
                .servername             = "rpc.statd",
@@ -83,10 +85,54 @@ static struct rpc_clnt *nsm_create(struct net *net)
        return rpc_create(&args);
 }
 
-static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
-                        struct net *net)
+static struct rpc_clnt *nsm_client_get(struct net *net)
 {
+       static DEFINE_MUTEX(nsm_create_mutex);
        struct rpc_clnt *clnt;
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+       spin_lock(&ln->nsm_clnt_lock);
+       if (ln->nsm_users) {
+               ln->nsm_users++;
+               clnt = ln->nsm_clnt;
+               spin_unlock(&ln->nsm_clnt_lock);
+               goto out;
+       }
+       spin_unlock(&ln->nsm_clnt_lock);
+
+       mutex_lock(&nsm_create_mutex);
+       clnt = nsm_create(net);
+       if (!IS_ERR(clnt)) {
+               ln->nsm_clnt = clnt;
+               smp_wmb();
+               ln->nsm_users = 1;
+       }
+       mutex_unlock(&nsm_create_mutex);
+out:
+       return clnt;
+}
+
+static void nsm_client_put(struct net *net)
+{
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+       struct rpc_clnt *clnt = ln->nsm_clnt;
+       int shutdown = 0;
+
+       spin_lock(&ln->nsm_clnt_lock);
+       if (ln->nsm_users) {
+               if (--ln->nsm_users)
+                       ln->nsm_clnt = NULL;
+               shutdown = !ln->nsm_users;
+       }
+       spin_unlock(&ln->nsm_clnt_lock);
+
+       if (shutdown)
+               rpc_shutdown_client(clnt);
+}
+
+static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
+                        struct rpc_clnt *clnt)
+{
        int             status;
        struct nsm_args args = {
                .priv           = &nsm->sm_priv,
@@ -94,31 +140,24 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
                .vers           = 3,
                .proc           = NLMPROC_NSM_NOTIFY,
                .mon_name       = nsm->sm_mon_name,
+               .nodename       = clnt->cl_nodename,
        };
        struct rpc_message msg = {
                .rpc_argp       = &args,
                .rpc_resp       = res,
        };
 
-       clnt = nsm_create(net);
-       if (IS_ERR(clnt)) {
-               status = PTR_ERR(clnt);
-               dprintk("lockd: failed to create NSM upcall transport, "
-                               "status=%d\n", status);
-               goto out;
-       }
+       BUG_ON(clnt == NULL);
 
        memset(res, 0, sizeof(*res));
 
        msg.rpc_proc = &clnt->cl_procinfo[proc];
-       status = rpc_call_sync(clnt, &msg, 0);
+       status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
        if (status < 0)
                dprintk("lockd: NSM upcall RPC failed, status=%d\n",
                                status);
        else
                status = 0;
-       rpc_shutdown_client(clnt);
- out:
        return status;
 }
 
@@ -138,6 +177,7 @@ int nsm_monitor(const struct nlm_host *host)
        struct nsm_handle *nsm = host->h_nsmhandle;
        struct nsm_res  res;
        int             status;
+       struct rpc_clnt *clnt;
 
        dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
 
@@ -150,7 +190,15 @@ int nsm_monitor(const struct nlm_host *host)
         */
        nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 
-       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
+       clnt = nsm_client_get(host->net);
+       if (IS_ERR(clnt)) {
+               status = PTR_ERR(clnt);
+               dprintk("lockd: failed to create NSM upcall transport, "
+                               "status=%d, net=%p\n", status, host->net);
+               return status;
+       }
+
+       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
        if (unlikely(res.status != 0))
                status = -EIO;
        if (unlikely(status < 0)) {
@@ -182,9 +230,11 @@ void nsm_unmonitor(const struct nlm_host *host)
 
        if (atomic_read(&nsm->sm_count) == 1
         && nsm->sm_monitored && !nsm->sm_sticky) {
+               struct lockd_net *ln = net_generic(host->net, lockd_net_id);
+
                dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 
-               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
+               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
                if (res.status != 0)
                        status = -EIO;
                if (status < 0)
@@ -192,6 +242,8 @@ void nsm_unmonitor(const struct nlm_host *host)
                                        nsm->sm_name);
                else
                        nsm->sm_monitored = 0;
+
+               nsm_client_put(host->net);
        }
 }
 
@@ -430,7 +482,7 @@ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
 {
        __be32 *p;
 
-       encode_nsm_string(xdr, utsname()->nodename);
+       encode_nsm_string(xdr, argp->nodename);
        p = xdr_reserve_space(xdr, 4 + 4 + 4);
        *p++ = cpu_to_be32(argp->prog);
        *p++ = cpu_to_be32(argp->vers);
index 4eee248..5010b55 100644 (file)
@@ -12,6 +12,10 @@ struct lockd_net {
        struct delayed_work grace_period_end;
        struct lock_manager lockd_manager;
        struct list_head grace_list;
+
+       spinlock_t nsm_clnt_lock;
+       unsigned int nsm_users;
+       struct rpc_clnt *nsm_clnt;
 };
 
 extern int lockd_net_id;
index 31a63f8..7e35587 100644 (file)
@@ -596,6 +596,7 @@ static int lockd_init_net(struct net *net)
 
        INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
        INIT_LIST_HEAD(&ln->grace_list);
+       spin_lock_init(&ln->nsm_clnt_lock);
        return 0;
 }
 
index db7ad71..13ca196 100644 (file)
@@ -95,8 +95,8 @@ config NFS_SWAP
          This option enables swapon to work on files located on NFS mounts.
 
 config NFS_V4_1
-       bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
-       depends on NFS_V4 && EXPERIMENTAL
+       bool "NFS client support for NFSv4.1"
+       depends on NFS_V4
        select SUNRPC_BACKCHANNEL
        help
          This option enables support for minor version 1 of the NFSv4 protocol
index dd392ed..f1027b0 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/bio.h>         /* struct bio */
 #include <linux/buffer_head.h> /* various write calls */
 #include <linux/prefetch.h>
+#include <linux/pagevec.h>
 
 #include "../pnfs.h"
 #include "../internal.h"
@@ -162,25 +163,39 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
        return bio;
 }
 
-static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+static struct bio *do_add_page_to_bio(struct bio *bio, int npg, int rw,
                                      sector_t isect, struct page *page,
                                      struct pnfs_block_extent *be,
                                      void (*end_io)(struct bio *, int err),
-                                     struct parallel_io *par)
+                                     struct parallel_io *par,
+                                     unsigned int offset, int len)
 {
+       isect = isect + (offset >> SECTOR_SHIFT);
+       dprintk("%s: npg %d rw %d isect %llu offset %u len %d\n", __func__,
+               npg, rw, (unsigned long long)isect, offset, len);
 retry:
        if (!bio) {
                bio = bl_alloc_init_bio(npg, isect, be, end_io, par);
                if (!bio)
                        return ERR_PTR(-ENOMEM);
        }
-       if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+       if (bio_add_page(bio, page, len, offset) < len) {
                bio = bl_submit_bio(rw, bio);
                goto retry;
        }
        return bio;
 }
 
+static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+                                     sector_t isect, struct page *page,
+                                     struct pnfs_block_extent *be,
+                                     void (*end_io)(struct bio *, int err),
+                                     struct parallel_io *par)
+{
+       return do_add_page_to_bio(bio, npg, rw, isect, page, be,
+                                 end_io, par, 0, PAGE_CACHE_SIZE);
+}
+
 /* This is basically copied from mpage_end_io_read */
 static void bl_end_io_read(struct bio *bio, int err)
 {
@@ -228,14 +243,6 @@ bl_end_par_io_read(void *data, int unused)
        schedule_work(&rdata->task.u.tk_work);
 }
 
-static bool
-bl_check_alignment(u64 offset, u32 len, unsigned long blkmask)
-{
-       if ((offset & blkmask) || (len & blkmask))
-               return false;
-       return true;
-}
-
 static enum pnfs_try_status
 bl_read_pagelist(struct nfs_read_data *rdata)
 {
@@ -246,15 +253,15 @@ bl_read_pagelist(struct nfs_read_data *rdata)
        sector_t isect, extent_length = 0;
        struct parallel_io *par;
        loff_t f_offset = rdata->args.offset;
+       size_t bytes_left = rdata->args.count;
+       unsigned int pg_offset, pg_len;
        struct page **pages = rdata->args.pages;
        int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
+       const bool is_dio = (header->dreq != NULL);
 
        dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
               rdata->pages.npages, f_offset, (unsigned int)rdata->args.count);
 
-       if (!bl_check_alignment(f_offset, rdata->args.count, PAGE_CACHE_MASK))
-               goto use_mds;
-
        par = alloc_parallel(rdata);
        if (!par)
                goto use_mds;
@@ -284,36 +291,53 @@ bl_read_pagelist(struct nfs_read_data *rdata)
                                extent_length = min(extent_length, cow_length);
                        }
                }
+
+               if (is_dio) {
+                       pg_offset = f_offset & ~PAGE_CACHE_MASK;
+                       if (pg_offset + bytes_left > PAGE_CACHE_SIZE)
+                               pg_len = PAGE_CACHE_SIZE - pg_offset;
+                       else
+                               pg_len = bytes_left;
+
+                       f_offset += pg_len;
+                       bytes_left -= pg_len;
+                       isect += (pg_offset >> SECTOR_SHIFT);
+               } else {
+                       pg_offset = 0;
+                       pg_len = PAGE_CACHE_SIZE;
+               }
+
                hole = is_hole(be, isect);
                if (hole && !cow_read) {
                        bio = bl_submit_bio(READ, bio);
                        /* Fill hole w/ zeroes w/o accessing device */
                        dprintk("%s Zeroing page for hole\n", __func__);
-                       zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+                       zero_user_segment(pages[i], pg_offset, pg_len);
                        print_page(pages[i]);
                        SetPageUptodate(pages[i]);
                } else {
                        struct pnfs_block_extent *be_read;
 
                        be_read = (hole && cow_read) ? cow_read : be;
-                       bio = bl_add_page_to_bio(bio, rdata->pages.npages - i,
+                       bio = do_add_page_to_bio(bio, rdata->pages.npages - i,
                                                 READ,
                                                 isect, pages[i], be_read,
-                                                bl_end_io_read, par);
+                                                bl_end_io_read, par,
+                                                pg_offset, pg_len);
                        if (IS_ERR(bio)) {
                                header->pnfs_error = PTR_ERR(bio);
                                bio = NULL;
                                goto out;
                        }
                }
-               isect += PAGE_CACHE_SECTORS;
+               isect += (pg_len >> SECTOR_SHIFT);
                extent_length -= PAGE_CACHE_SECTORS;
        }
        if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
                rdata->res.eof = 1;
-               rdata->res.count = header->inode->i_size - f_offset;
+               rdata->res.count = header->inode->i_size - rdata->args.offset;
        } else {
-               rdata->res.count = (isect << SECTOR_SHIFT) - f_offset;
+               rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset;
        }
 out:
        bl_put_extent(be);
@@ -461,6 +485,106 @@ map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be)
        return;
 }
 
+static void
+bl_read_single_end_io(struct bio *bio, int error)
+{
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct page *page = bvec->bv_page;
+
+       /* Only one page in bvec */
+       unlock_page(page);
+}
+
+static int
+bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be,
+                   unsigned int offset, unsigned int len)
+{
+       struct bio *bio;
+       struct page *shadow_page;
+       sector_t isect;
+       char *kaddr, *kshadow_addr;
+       int ret = 0;
+
+       dprintk("%s: offset %u len %u\n", __func__, offset, len);
+
+       shadow_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+       if (shadow_page == NULL)
+               return -ENOMEM;
+
+       bio = bio_alloc(GFP_NOIO, 1);
+       if (bio == NULL)
+               return -ENOMEM;
+
+       isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) +
+               (offset / SECTOR_SIZE);
+
+       bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+       bio->bi_bdev = be->be_mdev;
+       bio->bi_end_io = bl_read_single_end_io;
+
+       lock_page(shadow_page);
+       if (bio_add_page(bio, shadow_page,
+                        SECTOR_SIZE, round_down(offset, SECTOR_SIZE)) == 0) {
+               unlock_page(shadow_page);
+               bio_put(bio);
+               return -EIO;
+       }
+
+       submit_bio(READ, bio);
+       wait_on_page_locked(shadow_page);
+       if (unlikely(!test_bit(BIO_UPTODATE, &bio->bi_flags))) {
+               ret = -EIO;
+       } else {
+               kaddr = kmap_atomic(page);
+               kshadow_addr = kmap_atomic(shadow_page);
+               memcpy(kaddr + offset, kshadow_addr + offset, len);
+               kunmap_atomic(kshadow_addr);
+               kunmap_atomic(kaddr);
+       }
+       __free_page(shadow_page);
+       bio_put(bio);
+
+       return ret;
+}
+
+static int
+bl_read_partial_page_sync(struct page *page, struct pnfs_block_extent *be,
+                         unsigned int dirty_offset, unsigned int dirty_len,
+                         bool full_page)
+{
+       int ret = 0;
+       unsigned int start, end;
+
+       if (full_page) {
+               start = 0;
+               end = PAGE_CACHE_SIZE;
+       } else {
+               start = round_down(dirty_offset, SECTOR_SIZE);
+               end = round_up(dirty_offset + dirty_len, SECTOR_SIZE);
+       }
+
+       dprintk("%s: offset %u len %d\n", __func__, dirty_offset, dirty_len);
+       if (!be) {
+               zero_user_segments(page, start, dirty_offset,
+                                  dirty_offset + dirty_len, end);
+               if (start == 0 && end == PAGE_CACHE_SIZE &&
+                   trylock_page(page)) {
+                       SetPageUptodate(page);
+                       unlock_page(page);
+               }
+               return ret;
+       }
+
+       if (start != dirty_offset)
+               ret = bl_do_readpage_sync(page, be, start, dirty_offset - start);
+
+       if (!ret && (dirty_offset + dirty_len < end))
+               ret = bl_do_readpage_sync(page, be, dirty_offset + dirty_len,
+                                         end - dirty_offset - dirty_len);
+
+       return ret;
+}
+
 /* Given an unmapped page, zero it or read in page for COW, page is locked
  * by caller.
  */
@@ -494,7 +618,6 @@ init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read)
        SetPageUptodate(page);
 
 cleanup:
-       bl_put_extent(cow_read);
        if (bh)
                free_buffer_head(bh);
        if (ret) {
@@ -566,6 +689,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
        struct parallel_io *par = NULL;
        loff_t offset = wdata->args.offset;
        size_t count = wdata->args.count;
+       unsigned int pg_offset, pg_len, saved_len;
        struct page **pages = wdata->args.pages;
        struct page *page;
        pgoff_t index;
@@ -574,10 +698,13 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
            NFS_SERVER(header->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT;
 
        dprintk("%s enter, %Zu@%lld\n", __func__, count, offset);
-       /* Check for alignment first */
-       if (!bl_check_alignment(offset, count, PAGE_CACHE_MASK))
-               goto out_mds;
 
+       if (header->dreq != NULL &&
+           (!IS_ALIGNED(offset, NFS_SERVER(header->inode)->pnfs_blksize) ||
+            !IS_ALIGNED(count, NFS_SERVER(header->inode)->pnfs_blksize))) {
+               dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n");
+               goto out_mds;
+       }
        /* At this point, wdata->pages is a (sequential) list of nfs_pages.
         * We want to write each, and if there is an error set pnfs_error
         * to have it redone using nfs.
@@ -674,10 +801,11 @@ next_page:
                if (!extent_length) {
                        /* We've used up the previous extent */
                        bl_put_extent(be);
+                       bl_put_extent(cow_read);
                        bio = bl_submit_bio(WRITE, bio);
                        /* Get the next one */
                        be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg),
-                                            isect, NULL);
+                                            isect, &cow_read);
                        if (!be || !is_writable(be, isect)) {
                                header->pnfs_error = -EINVAL;
                                goto out;
@@ -694,7 +822,26 @@ next_page:
                        extent_length = be->be_length -
                            (isect - be->be_f_offset);
                }
-               if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+
+               dprintk("%s offset %lld count %Zu\n", __func__, offset, count);
+               pg_offset = offset & ~PAGE_CACHE_MASK;
+               if (pg_offset + count > PAGE_CACHE_SIZE)
+                       pg_len = PAGE_CACHE_SIZE - pg_offset;
+               else
+                       pg_len = count;
+
+               saved_len = pg_len;
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA &&
+                   !bl_is_sector_init(be->be_inval, isect)) {
+                       ret = bl_read_partial_page_sync(pages[i], cow_read,
+                                                       pg_offset, pg_len, true);
+                       if (ret) {
+                               dprintk("%s bl_read_partial_page_sync fail %d\n",
+                                       __func__, ret);
+                               header->pnfs_error = ret;
+                               goto out;
+                       }
+
                        ret = bl_mark_sectors_init(be->be_inval, isect,
                                                       PAGE_CACHE_SECTORS);
                        if (unlikely(ret)) {
@@ -703,15 +850,35 @@ next_page:
                                header->pnfs_error = ret;
                                goto out;
                        }
+
+                       /* Expand to full page write */
+                       pg_offset = 0;
+                       pg_len = PAGE_CACHE_SIZE;
+               } else if  ((pg_offset & (SECTOR_SIZE - 1)) ||
+                           (pg_len & (SECTOR_SIZE - 1))){
+                       /* ahh, nasty case. We have to do sync full sector
+                        * read-modify-write cycles.
+                        */
+                       unsigned int saved_offset = pg_offset;
+                       ret = bl_read_partial_page_sync(pages[i], be, pg_offset,
+                                                       pg_len, false);
+                       pg_offset = round_down(pg_offset, SECTOR_SIZE);
+                       pg_len = round_up(saved_offset + pg_len, SECTOR_SIZE)
+                                - pg_offset;
                }
-               bio = bl_add_page_to_bio(bio, wdata->pages.npages - i, WRITE,
+
+
+               bio = do_add_page_to_bio(bio, wdata->pages.npages - i, WRITE,
                                         isect, pages[i], be,
-                                        bl_end_io_write, par);
+                                        bl_end_io_write, par,
+                                        pg_offset, pg_len);
                if (IS_ERR(bio)) {
                        header->pnfs_error = PTR_ERR(bio);
                        bio = NULL;
                        goto out;
                }
+               offset += saved_len;
+               count -= saved_len;
                isect += PAGE_CACHE_SECTORS;
                last_isect = isect;
                extent_length -= PAGE_CACHE_SECTORS;
@@ -729,17 +896,16 @@ next_page:
        }
 
 write_done:
-       wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset);
-       if (count < wdata->res.count) {
-               wdata->res.count = count;
-       }
+       wdata->res.count = wdata->args.count;
 out:
        bl_put_extent(be);
+       bl_put_extent(cow_read);
        bl_submit_bio(WRITE, bio);
        put_parallel(par);
        return PNFS_ATTEMPTED;
 out_mds:
        bl_put_extent(be);
+       bl_put_extent(cow_read);
        kfree(par);
        return PNFS_NOT_ATTEMPTED;
 }
@@ -874,7 +1040,7 @@ static void free_blk_mountid(struct block_mount_id *mid)
        }
 }
 
-/* This is mostly copied from the filelayout's get_device_info function.
+/* This is mostly copied from the filelayout_get_device_info function.
  * It seems much of this should be at the generic pnfs level.
  */
 static struct pnfs_block_dev *
@@ -1011,33 +1177,95 @@ bl_clear_layoutdriver(struct nfs_server *server)
        return 0;
 }
 
+static bool
+is_aligned_req(struct nfs_page *req, unsigned int alignment)
+{
+       return IS_ALIGNED(req->wb_offset, alignment) &&
+              IS_ALIGNED(req->wb_bytes, alignment);
+}
+
 static void
 bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
 {
-       if (!bl_check_alignment(req->wb_offset, req->wb_bytes, PAGE_CACHE_MASK))
+       if (pgio->pg_dreq != NULL &&
+           !is_aligned_req(req, SECTOR_SIZE))
                nfs_pageio_reset_read_mds(pgio);
        else
                pnfs_generic_pg_init_read(pgio, req);
 }
 
+static bool
+bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+               struct nfs_page *req)
+{
+       if (pgio->pg_dreq != NULL &&
+           !is_aligned_req(req, SECTOR_SIZE))
+               return false;
+
+       return pnfs_generic_pg_test(pgio, prev, req);
+}
+
+/*
+ * Return the number of contiguous bytes for a given inode
+ * starting at page frame idx.
+ */
+static u64 pnfs_num_cont_bytes(struct inode *inode, pgoff_t idx)
+{
+       struct address_space *mapping = inode->i_mapping;
+       pgoff_t end;
+
+       /* Optimize common case that writes from 0 to end of file */
+       end = DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE);
+       if (end != NFS_I(inode)->npages) {
+               rcu_read_lock();
+               end = radix_tree_next_hole(&mapping->page_tree, idx + 1, ULONG_MAX);
+               rcu_read_unlock();
+       }
+
+       if (!end)
+               return i_size_read(inode) - (idx << PAGE_CACHE_SHIFT);
+       else
+               return (end - idx) << PAGE_CACHE_SHIFT;
+}
+
 static void
 bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
 {
-       if (!bl_check_alignment(req->wb_offset, req->wb_bytes, PAGE_CACHE_MASK))
+       if (pgio->pg_dreq != NULL &&
+           !is_aligned_req(req, PAGE_CACHE_SIZE)) {
                nfs_pageio_reset_write_mds(pgio);
-       else
-               pnfs_generic_pg_init_write(pgio, req);
+       } else {
+               u64 wb_size;
+               if (pgio->pg_dreq == NULL)
+                       wb_size = pnfs_num_cont_bytes(pgio->pg_inode,
+                                                     req->wb_index);
+               else
+                       wb_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
+               pnfs_generic_pg_init_write(pgio, req, wb_size);
+       }
+}
+
+static bool
+bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+                struct nfs_page *req)
+{
+       if (pgio->pg_dreq != NULL &&
+           !is_aligned_req(req, PAGE_CACHE_SIZE))
+               return false;
+
+       return pnfs_generic_pg_test(pgio, prev, req);
 }
 
 static const struct nfs_pageio_ops bl_pg_read_ops = {
        .pg_init = bl_pg_init_read,
-       .pg_test = pnfs_generic_pg_test,
+       .pg_test = bl_pg_test_read,
        .pg_doio = pnfs_generic_pg_readpages,
 };
 
 static const struct nfs_pageio_ops bl_pg_write_ops = {
        .pg_init = bl_pg_init_write,
-       .pg_test = pnfs_generic_pg_test,
+       .pg_test = bl_pg_test_write,
        .pg_doio = pnfs_generic_pg_writepages,
 };
 
index 0335069..f4891bd 100644 (file)
@@ -41,6 +41,7 @@
 
 #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
 #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
 
 struct block_mount_id {
        spinlock_t                      bm_lock;    /* protects list */
@@ -172,7 +173,6 @@ struct bl_msg_hdr {
 /* blocklayoutdev.c */
 ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
 void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
-struct block_device *nfs4_blkdev_get(dev_t dev);
 int nfs4_blkdev_put(struct block_device *bdev);
 struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server,
                                                struct pnfs_device *dev);
index c965542..a86c5bd 100644 (file)
@@ -53,22 +53,6 @@ static int decode_sector_number(__be32 **rp, sector_t *sp)
        return 0;
 }
 
-/* Open a block_device by device number. */
-struct block_device *nfs4_blkdev_get(dev_t dev)
-{
-       struct block_device *bd;
-
-       dprintk("%s enter\n", __func__);
-       bd = blkdev_get_by_dev(dev, FMODE_READ, NULL);
-       if (IS_ERR(bd))
-               goto fail;
-       return bd;
-fail:
-       dprintk("%s failed to open device : %ld\n",
-                       __func__, PTR_ERR(bd));
-       return NULL;
-}
-
 /*
  * Release the block device
  */
@@ -172,11 +156,12 @@ nfs4_blk_decode_device(struct nfs_server *server,
                goto out;
        }
 
-       bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
+       bd = blkdev_get_by_dev(MKDEV(reply->major, reply->minor),
+                              FMODE_READ, NULL);
        if (IS_ERR(bd)) {
-               rc = PTR_ERR(bd);
-               dprintk("%s failed to open device : %d\n", __func__, rc);
-               rv = ERR_PTR(rc);
+               dprintk("%s failed to open device : %ld\n", __func__,
+                       PTR_ERR(bd));
+               rv = ERR_CAST(bd);
                goto out;
        }
 
index 1f9a603..9c3e117 100644 (file)
@@ -683,8 +683,7 @@ encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
                p = xdr_encode_hyper(p, lce->bse_length << SECTOR_SHIFT);
                p = xdr_encode_hyper(p, 0LL);
                *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
-               list_del(&lce->bse_node);
-               list_add_tail(&lce->bse_node, &bl->bl_committing);
+               list_move_tail(&lce->bse_node, &bl->bl_committing);
                bl->bl_count--;
                count++;
        }
index 4c8459e..2245bef 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/nfs_fs.h>
+#include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
@@ -23,6 +24,7 @@
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "internal.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
 
@@ -37,7 +39,32 @@ static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
 static DEFINE_MUTEX(nfs_callback_mutex);
 static struct svc_program nfs4_callback_program;
 
-unsigned short nfs_callback_tcpport6;
+static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
+{
+       int ret;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       ret = svc_create_xprt(serv, "tcp", net, PF_INET,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret <= 0)
+               goto out_err;
+       nn->nfs_callback_tcpport = ret;
+       dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
+                       nn->nfs_callback_tcpport, PF_INET, net);
+
+       ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret > 0) {
+               nn->nfs_callback_tcpport6 = ret;
+               dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
+                               nn->nfs_callback_tcpport6, PF_INET6, net);
+       } else if (ret != -EAFNOSUPPORT)
+               goto out_err;
+       return 0;
+
+out_err:
+       return (ret) ? ret : -ENOMEM;
+}
 
 /*
  * This is the NFSv4 callback kernel thread.
@@ -78,38 +105,23 @@ nfs4_callback_svc(void *vrqstp)
  * Prepare to bring up the NFSv4 callback service
  */
 static struct svc_rqst *
-nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
+nfs4_callback_up(struct svc_serv *serv)
 {
-       int ret;
-
-       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
-                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
-       if (ret <= 0)
-               goto out_err;
-       nfs_callback_tcpport = ret;
-       dprintk("NFS: Callback listener port = %u (af %u)\n",
-                       nfs_callback_tcpport, PF_INET);
-
-       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
-                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
-       if (ret > 0) {
-               nfs_callback_tcpport6 = ret;
-               dprintk("NFS: Callback listener port = %u (af %u)\n",
-                               nfs_callback_tcpport6, PF_INET6);
-       } else if (ret == -EAFNOSUPPORT)
-               ret = 0;
-       else
-               goto out_err;
-
        return svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
-
-out_err:
-       if (ret == 0)
-               ret = -ENOMEM;
-       return ERR_PTR(ret);
 }
 
 #if defined(CONFIG_NFS_V4_1)
+static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
+{
+       /*
+        * Create an svc_sock for the back channel service that shares the
+        * fore channel connection.
+        * Returns the input port (0) and sets the svc_serv bc_xprt on success
+        */
+       return svc_create_xprt(serv, "tcp-bc", net, PF_INET, 0,
+                             SVC_SOCK_ANONYMOUS);
+}
+
 /*
  * The callback service for NFSv4.1 callbacks
  */
@@ -149,28 +161,9 @@ nfs41_callback_svc(void *vrqstp)
  * Bring up the NFSv4.1 callback service
  */
 static struct svc_rqst *
-nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
+nfs41_callback_up(struct svc_serv *serv)
 {
        struct svc_rqst *rqstp;
-       int ret;
-
-       /*
-        * Create an svc_sock for the back channel service that shares the
-        * fore channel connection.
-        * Returns the input port (0) and sets the svc_serv bc_xprt on success
-        */
-       ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
-                             SVC_SOCK_ANONYMOUS);
-       if (ret < 0) {
-               rqstp = ERR_PTR(ret);
-               goto out;
-       }
-
-       /*
-        * Save the svc_serv in the transport so that it can
-        * be referenced when the session backchannel is initialized
-        */
-       xprt->bc_serv = serv;
 
        INIT_LIST_HEAD(&serv->sv_cb_list);
        spin_lock_init(&serv->sv_cb_lock);
@@ -180,90 +173,74 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
                svc_xprt_put(serv->sv_bc_xprt);
                serv->sv_bc_xprt = NULL;
        }
-out:
        dprintk("--> %s return %ld\n", __func__,
                IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0);
        return rqstp;
 }
 
-static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
-               struct svc_serv *serv, struct rpc_xprt *xprt,
+static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
                struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
 {
-       if (minorversion) {
-               *rqstpp = nfs41_callback_up(serv, xprt);
-               *callback_svc = nfs41_callback_svc;
-       }
-       return minorversion;
+       *rqstpp = nfs41_callback_up(serv);
+       *callback_svc = nfs41_callback_svc;
 }
 
 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
-               struct nfs_callback_data *cb_info)
+               struct svc_serv *serv)
 {
        if (minorversion)
-               xprt->bc_serv = cb_info->serv;
+               /*
+                * Save the svc_serv in the transport so that it can
+                * be referenced when the session backchannel is initialized
+                */
+               xprt->bc_serv = serv;
 }
 #else
-static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
-               struct svc_serv *serv, struct rpc_xprt *xprt,
-               struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
+static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
 {
        return 0;
 }
 
+static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
+               struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
+{
+       *rqstpp = ERR_PTR(-ENOTSUPP);
+       *callback_svc = ERR_PTR(-ENOTSUPP);
+}
+
 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
-               struct nfs_callback_data *cb_info)
+               struct svc_serv *serv)
 {
 }
 #endif /* CONFIG_NFS_V4_1 */
 
-/*
- * Bring up the callback thread if it is not already up.
- */
-int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
+static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
+                                 struct svc_serv *serv)
 {
-       struct svc_serv *serv = NULL;
        struct svc_rqst *rqstp;
        int (*callback_svc)(void *vrqstp);
        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
        char svc_name[12];
-       int ret = 0;
-       int minorversion_setup;
-       struct net *net = &init_net;
+       int ret;
 
-       mutex_lock(&nfs_callback_mutex);
-       if (cb_info->users++ || cb_info->task != NULL) {
-               nfs_callback_bc_serv(minorversion, xprt, cb_info);
-               goto out;
-       }
-       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
-       if (!serv) {
-               ret = -ENOMEM;
-               goto out_err;
-       }
-       /* As there is only one thread we need to over-ride the
-        * default maximum of 80 connections
-        */
-       serv->sv_maxconn = 1024;
+       nfs_callback_bc_serv(minorversion, xprt, serv);
 
-       ret = svc_bind(serv, net);
-       if (ret < 0) {
-               printk(KERN_WARNING "NFS: bind callback service failed\n");
-               goto out_err;
-       }
+       if (cb_info->task)
+               return 0;
 
-       minorversion_setup =  nfs_minorversion_callback_svc_setup(minorversion,
-                                       serv, xprt, &rqstp, &callback_svc);
-       if (!minorversion_setup) {
+       switch (minorversion) {
+       case 0:
                /* v4.0 callback setup */
-               rqstp = nfs4_callback_up(serv, xprt);
+               rqstp = nfs4_callback_up(serv);
                callback_svc = nfs4_callback_svc;
+               break;
+       default:
+               nfs_minorversion_callback_svc_setup(serv,
+                               &rqstp, &callback_svc);
        }
 
-       if (IS_ERR(rqstp)) {
-               ret = PTR_ERR(rqstp);
-               goto out_err;
-       }
+       if (IS_ERR(rqstp))
+               return PTR_ERR(rqstp);
 
        svc_sock_update_bufs(serv);
 
@@ -276,41 +253,165 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
                svc_exit_thread(cb_info->rqst);
                cb_info->rqst = NULL;
                cb_info->task = NULL;
-               goto out_err;
+               return PTR_ERR(cb_info->task);
+       }
+       dprintk("nfs_callback_up: service started\n");
+       return 0;
+}
+
+static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       if (--nn->cb_users[minorversion])
+               return;
+
+       dprintk("NFS: destroy per-net callback data; net=%p\n", net);
+       svc_shutdown_net(serv, net);
+}
+
+static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       int ret;
+
+       if (nn->cb_users[minorversion]++)
+               return 0;
+
+       dprintk("NFS: create per-net callback data; net=%p\n", net);
+
+       ret = svc_bind(serv, net);
+       if (ret < 0) {
+               printk(KERN_WARNING "NFS: bind callback service failed\n");
+               goto err_bind;
+       }
+
+       switch (minorversion) {
+               case 0:
+                       ret = nfs4_callback_up_net(serv, net);
+                       break;
+               case 1:
+                       ret = nfs41_callback_up_net(serv, net);
+                       break;
+               default:
+                       printk(KERN_ERR "NFS: unknown callback version: %d\n",
+                                       minorversion);
+                       ret = -EINVAL;
+                       break;
        }
-out:
+
+       if (ret < 0) {
+               printk(KERN_ERR "NFS: callback service start failed\n");
+               goto err_socks;
+       }
+       return 0;
+
+err_socks:
+       svc_rpcb_cleanup(serv, net);
+err_bind:
+       dprintk("NFS: Couldn't create callback socket: err = %d; "
+                       "net = %p\n", ret, net);
+       return ret;
+}
+
+static struct svc_serv *nfs_callback_create_svc(int minorversion)
+{
+       struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
+       struct svc_serv *serv;
+
+       /*
+        * Check whether we're already up and running.
+        */
+       if (cb_info->task) {
+               /*
+                * Note: increase service usage, because later in case of error
+                * svc_destroy() will be called.
+                */
+               svc_get(cb_info->serv);
+               return cb_info->serv;
+       }
+
+       /*
+        * Sanity check: if there's no task,
+        * we should be the first user ...
+        */
+       if (cb_info->users)
+               printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
+                       cb_info->users);
+
+       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+       if (!serv) {
+               printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       /* As there is only one thread we need to over-ride the
+        * default maximum of 80 connections
+        */
+       serv->sv_maxconn = 1024;
+       dprintk("nfs_callback_create_svc: service created\n");
+       return serv;
+}
+
+/*
+ * Bring up the callback thread if it is not already up.
+ */
+int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
+{
+       struct svc_serv *serv;
+       struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
+       int ret;
+       struct net *net = xprt->xprt_net;
+
+       mutex_lock(&nfs_callback_mutex);
+
+       serv = nfs_callback_create_svc(minorversion);
+       if (IS_ERR(serv)) {
+               ret = PTR_ERR(serv);
+               goto err_create;
+       }
+
+       ret = nfs_callback_up_net(minorversion, serv, net);
+       if (ret < 0)
+               goto err_net;
+
+       ret = nfs_callback_start_svc(minorversion, xprt, serv);
+       if (ret < 0)
+               goto err_start;
+
+       cb_info->users++;
        /*
         * svc_create creates the svc_serv with sv_nrthreads == 1, and then
         * svc_prepare_thread increments that. So we need to call svc_destroy
         * on both success and failure so that the refcount is 1 when the
         * thread exits.
         */
-       if (serv)
-               svc_destroy(serv);
+err_net:
+       svc_destroy(serv);
+err_create:
        mutex_unlock(&nfs_callback_mutex);
        return ret;
-out_err:
-       dprintk("NFS: Couldn't create callback socket or server thread; "
-               "err = %d\n", ret);
-       cb_info->users--;
-       if (serv)
-               svc_shutdown_net(serv, net);
-       goto out;
+
+err_start:
+       nfs_callback_down_net(minorversion, serv, net);
+       dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
+       goto err_net;
 }
 
 /*
  * Kill the callback thread if it's no longer being used.
  */
-void nfs_callback_down(int minorversion)
+void nfs_callback_down(int minorversion, struct net *net)
 {
        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 
        mutex_lock(&nfs_callback_mutex);
+       nfs_callback_down_net(minorversion, cb_info->serv, net);
        cb_info->users--;
        if (cb_info->users == 0 && cb_info->task != NULL) {
                kthread_stop(cb_info->task);
-               svc_shutdown_net(cb_info->serv, &init_net);
+               dprintk("nfs_callback_down: service stopped\n");
                svc_exit_thread(cb_info->rqst);
+               dprintk("nfs_callback_down: service destroyed\n");
                cb_info->serv = NULL;
                cb_info->rqst = NULL;
                cb_info->task = NULL;
index b44d7b1..4251c2a 100644 (file)
@@ -194,7 +194,7 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
                                   struct cb_process_state *cps);
 #if IS_ENABLED(CONFIG_NFS_V4)
 extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
-extern void nfs_callback_down(int minorversion);
+extern void nfs_callback_down(int minorversion, struct net *net);
 extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation,
                                            const nfs4_stateid *stateid);
 extern int nfs4_set_callback_sessionid(struct nfs_client *clp);
@@ -209,6 +209,5 @@ extern int nfs4_set_callback_sessionid(struct nfs_client *clp);
 
 extern unsigned int nfs_callback_set_tcpport;
 extern unsigned short nfs_callback_tcpport;
-extern unsigned short nfs_callback_tcpport6;
 
 #endif /* __LINUX_FS_NFS_CALLBACK_H */
index 1b5d809..76b4a7a 100644 (file)
@@ -122,7 +122,15 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
                        ino = igrab(lo->plh_inode);
                        if (!ino)
                                continue;
-                       get_layout_hdr(lo);
+                       spin_lock(&ino->i_lock);
+                       /* Is this layout in the process of being freed? */
+                       if (NFS_I(ino)->layout != lo) {
+                               spin_unlock(&ino->i_lock);
+                               iput(ino);
+                               continue;
+                       }
+                       pnfs_get_layout_hdr(lo);
+                       spin_unlock(&ino->i_lock);
                        return lo;
                }
        }
@@ -158,7 +166,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        ino = lo->plh_inode;
        spin_lock(&ino->i_lock);
        if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
-           mark_matching_lsegs_invalid(lo, &free_me_list,
+           pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
                                        &args->cbl_range))
                rv = NFS4ERR_DELAY;
        else
@@ -166,7 +174,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&free_me_list);
-       put_layout_hdr(lo);
+       pnfs_put_layout_hdr(lo);
        iput(ino);
        return rv;
 }
@@ -196,9 +204,18 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
                        continue;
 
                list_for_each_entry(lo, &server->layouts, plh_layouts) {
-                       if (!igrab(lo->plh_inode))
+                       ino = igrab(lo->plh_inode);
+                       if (ino)
+                               continue;
+                       spin_lock(&ino->i_lock);
+                       /* Is this layout in the process of being freed? */
+                       if (NFS_I(ino)->layout != lo) {
+                               spin_unlock(&ino->i_lock);
+                               iput(ino);
                                continue;
-                       get_layout_hdr(lo);
+                       }
+                       pnfs_get_layout_hdr(lo);
+                       spin_unlock(&ino->i_lock);
                        BUG_ON(!list_empty(&lo->plh_bulk_recall));
                        list_add(&lo->plh_bulk_recall, &recall_list);
                }
@@ -211,12 +228,12 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
                ino = lo->plh_inode;
                spin_lock(&ino->i_lock);
                set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
-               if (mark_matching_lsegs_invalid(lo, &free_me_list, &range))
+               if (pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, &range))
                        rv = NFS4ERR_DELAY;
                list_del_init(&lo->plh_bulk_recall);
                spin_unlock(&ino->i_lock);
                pnfs_free_lseg_list(&free_me_list);
-               put_layout_hdr(lo);
+               pnfs_put_layout_hdr(lo);
                iput(ino);
        }
        return rv;
index 9969444..8b39a42 100644 (file)
@@ -93,10 +93,10 @@ static struct nfs_subversion *find_nfs_version(unsigned int version)
                        spin_unlock(&nfs_version_lock);
                        return nfs;
                }
-       };
+       }
 
        spin_unlock(&nfs_version_lock);
-       return ERR_PTR(-EPROTONOSUPPORT);;
+       return ERR_PTR(-EPROTONOSUPPORT);
 }
 
 struct nfs_subversion *get_nfs_version(unsigned int version)
@@ -498,7 +498,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
                        return nfs_found_client(cl_init, clp);
                }
                if (new) {
-                       list_add(&new->cl_share_link, &nn->nfs_client_list);
+                       list_add_tail(&new->cl_share_link,
+                                       &nn->nfs_client_list);
                        spin_unlock(&nn->nfs_client_lock);
                        new->cl_flags = cl_init->init_flags;
                        return rpc_ops->init_client(new, timeparms, ip_addr,
@@ -668,7 +669,8 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
 {
        struct nfs_client *clp = server->nfs_client;
 
-       server->client = rpc_clone_client(clp->cl_rpcclient);
+       server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
+                                                       pseudoflavour);
        if (IS_ERR(server->client)) {
                dprintk("%s: couldn't create rpc_client!\n", __func__);
                return PTR_ERR(server->client);
@@ -678,16 +680,6 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
                        timeo,
                        sizeof(server->client->cl_timeout_default));
        server->client->cl_timeout = &server->client->cl_timeout_default;
-
-       if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
-               struct rpc_auth *auth;
-
-               auth = rpcauth_create(pseudoflavour, server->client);
-               if (IS_ERR(auth)) {
-                       dprintk("%s: couldn't create credcache!\n", __func__);
-                       return PTR_ERR(auth);
-               }
-       }
        server->client->cl_softrtry = 0;
        if (server->flags & NFS_MOUNT_SOFT)
                server->client->cl_softrtry = 1;
@@ -761,6 +753,8 @@ static int nfs_init_server(struct nfs_server *server,
                        data->timeo, data->retrans);
        if (data->flags & NFS_MOUNT_NORESVPORT)
                set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+       if (server->options & NFS_OPTION_MIGRATION)
+               set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
 
        /* Allocate or find a client reference we can use */
        clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX);
@@ -855,7 +849,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
        if (server->wsize > NFS_MAX_FILE_IO_SIZE)
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       server->pnfs_blksize = fsinfo->blksize;
 
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
index 627f108..ce8cb92 100644 (file)
@@ -2072,7 +2072,7 @@ found:
        nfs_access_free_entry(entry);
 }
 
-static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
 {
        struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
        if (cache == NULL)
@@ -2098,6 +2098,20 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s
                spin_unlock(&nfs_access_lru_lock);
        }
 }
+EXPORT_SYMBOL_GPL(nfs_access_add_cache);
+
+void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
+{
+       entry->mask = 0;
+       if (access_result & NFS4_ACCESS_READ)
+               entry->mask |= MAY_READ;
+       if (access_result &
+           (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
+               entry->mask |= MAY_WRITE;
+       if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
+               entry->mask |= MAY_EXEC;
+}
+EXPORT_SYMBOL_GPL(nfs_access_set_mask);
 
 static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
 {
index 1ba385b..cae26cb 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/kref.h>
 #include <linux/slab.h>
 #include <linux/task_io_accounting_ops.h>
+#include <linux/module.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
@@ -78,6 +79,7 @@ struct nfs_direct_req {
        atomic_t                io_count;       /* i/os we're waiting for */
        spinlock_t              lock;           /* protect completion state */
        ssize_t                 count,          /* bytes actually processed */
+                               bytes_left,     /* bytes left to be sent */
                                error;          /* any reported error */
        struct completion       completion;     /* wait for i/o completion */
 
@@ -190,6 +192,12 @@ static void nfs_direct_req_release(struct nfs_direct_req *dreq)
        kref_put(&dreq->kref, nfs_direct_req_free);
 }
 
+ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq)
+{
+       return dreq->bytes_left;
+}
+EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left);
+
 /*
  * Collects and returns the final error value/byte-count.
  */
@@ -390,6 +398,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de
                        user_addr += req_len;
                        pos += req_len;
                        count -= req_len;
+                       dreq->bytes_left -= req_len;
                }
                /* The nfs_page now hold references to these pages */
                nfs_direct_release_pages(pagevec, npages);
@@ -450,23 +459,28 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
        ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct nfs_direct_req *dreq;
+       struct nfs_lock_context *l_ctx;
 
        dreq = nfs_direct_req_alloc();
        if (dreq == NULL)
                goto out;
 
        dreq->inode = inode;
+       dreq->bytes_left = iov_length(iov, nr_segs);
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
-       dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
-       if (dreq->l_ctx == NULL)
+       l_ctx = nfs_get_lock_context(dreq->ctx);
+       if (IS_ERR(l_ctx)) {
+               result = PTR_ERR(l_ctx);
                goto out_release;
+       }
+       dreq->l_ctx = l_ctx;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
+       NFS_I(inode)->read_io += iov_length(iov, nr_segs);
        result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
        if (!result)
                result = nfs_direct_wait(dreq);
-       NFS_I(inode)->read_io += result;
 out_release:
        nfs_direct_req_release(dreq);
 out:
@@ -706,6 +720,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d
                        user_addr += req_len;
                        pos += req_len;
                        count -= req_len;
+                       dreq->bytes_left -= req_len;
                }
                /* The nfs_page now hold references to these pages */
                nfs_direct_release_pages(pagevec, npages);
@@ -814,6 +829,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
        get_dreq(dreq);
        atomic_inc(&inode->i_dio_count);
 
+       NFS_I(dreq->inode)->write_io += iov_length(iov, nr_segs);
        for (seg = 0; seg < nr_segs; seg++) {
                const struct iovec *vec = &iov[seg];
                result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio);
@@ -825,7 +841,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                pos += vec->iov_len;
        }
        nfs_pageio_complete(&desc);
-       NFS_I(dreq->inode)->write_io += desc.pg_bytes_written;
 
        /*
         * If no bytes were started, return the error, and let the
@@ -849,16 +864,21 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
        ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct nfs_direct_req *dreq;
+       struct nfs_lock_context *l_ctx;
 
        dreq = nfs_direct_req_alloc();
        if (!dreq)
                goto out;
 
        dreq->inode = inode;
+       dreq->bytes_left = count;
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
-       dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
-       if (dreq->l_ctx == NULL)
+       l_ctx = nfs_get_lock_context(dreq->ctx);
+       if (IS_ERR(l_ctx)) {
+               result = PTR_ERR(l_ctx);
                goto out_release;
+       }
+       dreq->l_ctx = l_ctx;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
index f692be9..582bb88 100644 (file)
@@ -259,7 +259,7 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
        struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = dentry->d_inode;
-       int have_error, status;
+       int have_error, do_resend, status;
        int ret = 0;
 
        dprintk("NFS: fsync file(%s/%s) datasync %d\n",
@@ -267,15 +267,23 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
                        datasync);
 
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
+       do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
        have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
-       if (status >= 0 && ret < 0)
-               status = ret;
        have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
-       if (have_error)
+       if (have_error) {
                ret = xchg(&ctx->error, 0);
-       if (!ret && status < 0)
+               if (ret)
+                       goto out;
+       }
+       if (status < 0) {
                ret = status;
+               goto out;
+       }
+       do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
+       if (do_resend)
+               ret = -EAGAIN;
+out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(nfs_file_fsync_commit);
@@ -286,13 +294,22 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        int ret;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret != 0)
-               goto out;
-       mutex_lock(&inode->i_mutex);
-       ret = nfs_file_fsync_commit(file, start, end, datasync);
-       mutex_unlock(&inode->i_mutex);
-out:
+       do {
+               ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+               if (ret != 0)
+                       break;
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_file_fsync_commit(file, start, end, datasync);
+               mutex_unlock(&inode->i_mutex);
+               /*
+                * If nfs_file_fsync_commit detected a server reboot, then
+                * resend all dirty pages that might have been covered by
+                * the NFS_CONTEXT_RESEND_WRITES flag
+                */
+               start = 0;
+               end = LLONG_MAX;
+       } while (ret == -EAGAIN);
+
        return ret;
 }
 
index 4654ced..033803c 100644 (file)
@@ -32,6 +32,8 @@
 
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
 /*
index a850079..9cc4a3f 100644 (file)
 static const struct cred *id_resolver_cache;
 static struct key_type key_type_id_resolver_legacy;
 
-struct idmap {
-       struct rpc_pipe         *idmap_pipe;
-       struct key_construction *idmap_key_cons;
-       struct mutex            idmap_mutex;
-};
-
 struct idmap_legacy_upcalldata {
        struct rpc_pipe_msg pipe_msg;
        struct idmap_msg idmap_msg;
+       struct key_construction *key_cons;
        struct idmap *idmap;
 };
 
+struct idmap {
+       struct rpc_pipe         *idmap_pipe;
+       struct idmap_legacy_upcalldata *idmap_upcall_data;
+       struct mutex            idmap_mutex;
+};
+
 /**
  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
  * @fattr: fully initialised struct nfs_fattr
@@ -158,7 +159,7 @@ static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *re
                return 0;
        memcpy(buf, name, namelen);
        buf[namelen] = '\0';
-       if (strict_strtoul(buf, 0, &val) != 0)
+       if (kstrtoul(buf, 0, &val) != 0)
                return 0;
        *res = val;
        return 1;
@@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
                ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
                                            name, namelen, type, data,
                                            data_size, idmap);
-               idmap->idmap_key_cons = NULL;
                mutex_unlock(&idmap->idmap_mutex);
        }
        return ret;
@@ -364,7 +364,7 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ
        if (data_size <= 0) {
                ret = -EINVAL;
        } else {
-               ret = strict_strtol(id_str, 10, &id_long);
+               ret = kstrtol(id_str, 10, &id_long);
                *id = (__u32)id_long;
        }
        return ret;
@@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp)
        struct rpc_pipe *pipe;
        int error;
 
-       BUG_ON(clp->cl_idmap != NULL);
-
        idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
        if (idmap == NULL)
                return -ENOMEM;
@@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
 
        switch (event) {
        case RPC_PIPEFS_MOUNT:
-               BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
                err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
                                                clp->cl_idmap,
                                                clp->cl_idmap->idmap_pipe);
@@ -632,9 +629,6 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
        substring_t substr;
        int token, ret;
 
-       memset(im,  0, sizeof(*im));
-       memset(msg, 0, sizeof(*msg));
-
        im->im_type = IDMAP_TYPE_GROUP;
        token = match_token(desc, nfs_idmap_tokens, &substr);
 
@@ -665,6 +659,35 @@ out:
        return ret;
 }
 
+static bool
+nfs_idmap_prepare_pipe_upcall(struct idmap *idmap,
+               struct idmap_legacy_upcalldata *data)
+{
+       if (idmap->idmap_upcall_data != NULL) {
+               WARN_ON_ONCE(1);
+               return false;
+       }
+       idmap->idmap_upcall_data = data;
+       return true;
+}
+
+static void
+nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret)
+{
+       struct key_construction *cons = idmap->idmap_upcall_data->key_cons;
+
+       kfree(idmap->idmap_upcall_data);
+       idmap->idmap_upcall_data = NULL;
+       complete_request_key(cons, ret);
+}
+
+static void
+nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret)
+{
+       if (idmap->idmap_upcall_data != NULL)
+               nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
+}
+
 static int nfs_idmap_legacy_upcall(struct key_construction *cons,
                                   const char *op,
                                   void *aux)
@@ -677,29 +700,28 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
        int ret = -ENOMEM;
 
        /* msg and im are freed in idmap_pipe_destroy_msg */
-       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                goto out1;
 
        msg = &data->pipe_msg;
        im = &data->idmap_msg;
        data->idmap = idmap;
+       data->key_cons = cons;
 
        ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
        if (ret < 0)
                goto out2;
 
-       BUG_ON(idmap->idmap_key_cons != NULL);
-       idmap->idmap_key_cons = cons;
+       ret = -EAGAIN;
+       if (!nfs_idmap_prepare_pipe_upcall(idmap, data))
+               goto out2;
 
        ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
        if (ret < 0)
-               goto out3;
+               nfs_idmap_abort_pipe_upcall(idmap, ret);
 
        return ret;
-
-out3:
-       idmap->idmap_key_cons = NULL;
 out2:
        kfree(data);
 out1:
@@ -714,21 +736,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat
                                        authkey);
 }
 
-static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
+static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
+               struct idmap_msg *upcall,
+               struct key *key, struct key *authkey)
 {
        char id_str[NFS_UINT_MAXLEN];
-       int ret = -EINVAL;
+       int ret = -ENOKEY;
 
+       /* ret = -ENOKEY */
+       if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv)
+               goto out;
        switch (im->im_conv) {
        case IDMAP_CONV_NAMETOID:
+               if (strcmp(upcall->im_name, im->im_name) != 0)
+                       break;
                sprintf(id_str, "%d", im->im_id);
                ret = nfs_idmap_instantiate(key, authkey, id_str);
                break;
        case IDMAP_CONV_IDTONAME:
+               if (upcall->im_id != im->im_id)
+                       break;
                ret = nfs_idmap_instantiate(key, authkey, im->im_name);
                break;
+       default:
+               ret = -EINVAL;
        }
-
+out:
        return ret;
 }
 
@@ -740,14 +773,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        struct key_construction *cons;
        struct idmap_msg im;
        size_t namelen_in;
-       int ret;
+       int ret = -ENOKEY;
 
        /* If instantiation is successful, anyone waiting for key construction
         * will have been woken up and someone else may now have used
         * idmap_key_cons - so after this point we may no longer touch it.
         */
-       cons = ACCESS_ONCE(idmap->idmap_key_cons);
-       idmap->idmap_key_cons = NULL;
+       if (idmap->idmap_upcall_data == NULL)
+               goto out_noupcall;
+
+       cons = idmap->idmap_upcall_data->key_cons;
 
        if (mlen != sizeof(im)) {
                ret = -ENOSPC;
@@ -768,16 +803,19 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
                ret = -EINVAL;
                goto out;
-       }
+}
 
-       ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
+       ret = nfs_idmap_read_and_verify_message(&im,
+                       &idmap->idmap_upcall_data->idmap_msg,
+                       cons->key, cons->authkey);
        if (ret >= 0) {
                key_set_timeout(cons->key, nfs_idmap_cache_timeout);
                ret = mlen;
        }
 
 out:
-       complete_request_key(cons, ret);
+       nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
+out_noupcall:
        return ret;
 }
 
@@ -788,14 +826,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
                        struct idmap_legacy_upcalldata,
                        pipe_msg);
        struct idmap *idmap = data->idmap;
-       struct key_construction *cons;
-       if (msg->errno) {
-               cons = ACCESS_ONCE(idmap->idmap_key_cons);
-               idmap->idmap_key_cons = NULL;
-               complete_request_key(cons, msg->errno);
-       }
-       /* Free memory allocated in nfs_idmap_legacy_upcall() */
-       kfree(data);
+
+       if (msg->errno)
+               nfs_idmap_abort_pipe_upcall(idmap, msg->errno);
 }
 
 static void
@@ -803,7 +836,8 @@ idmap_release_pipe(struct inode *inode)
 {
        struct rpc_inode *rpci = RPC_I(inode);
        struct idmap *idmap = (struct idmap *)rpci->private;
-       idmap->idmap_key_cons = NULL;
+
+       nfs_idmap_abort_pipe_upcall(idmap, -EPIPE);
 }
 
 int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
index e4c716d..5c7325c 100644 (file)
@@ -547,8 +547,8 @@ EXPORT_SYMBOL_GPL(nfs_getattr);
 static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
 {
        atomic_set(&l_ctx->count, 1);
-       l_ctx->lockowner = current->files;
-       l_ctx->pid = current->tgid;
+       l_ctx->lockowner.l_owner = current->files;
+       l_ctx->lockowner.l_pid = current->tgid;
        INIT_LIST_HEAD(&l_ctx->list);
 }
 
@@ -557,9 +557,9 @@ static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context
        struct nfs_lock_context *pos;
 
        list_for_each_entry(pos, &ctx->lock_context.list, list) {
-               if (pos->lockowner != current->files)
+               if (pos->lockowner.l_owner != current->files)
                        continue;
-               if (pos->pid != current->tgid)
+               if (pos->lockowner.l_pid != current->tgid)
                        continue;
                atomic_inc(&pos->count);
                return pos;
@@ -578,7 +578,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
                spin_unlock(&inode->i_lock);
                new = kmalloc(sizeof(*new), GFP_KERNEL);
                if (new == NULL)
-                       return NULL;
+                       return ERR_PTR(-ENOMEM);
                nfs_init_lock_context(new);
                spin_lock(&inode->i_lock);
                res = __nfs_find_lock_context(ctx);
index 31fdb03..59b133c 100644 (file)
@@ -101,11 +101,11 @@ struct nfs_client_initdata {
  */
 struct nfs_parsed_mount_data {
        int                     flags;
-       int                     rsize, wsize;
-       int                     timeo, retrans;
-       int                     acregmin, acregmax,
+       unsigned int            rsize, wsize;
+       unsigned int            timeo, retrans;
+       unsigned int            acregmin, acregmax,
                                acdirmin, acdirmax;
-       int                     namlen;
+       unsigned int            namlen;
        unsigned int            options;
        unsigned int            bsize;
        unsigned int            auth_flavor_len;
@@ -464,6 +464,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode)
 {
        inode_dio_wait(inode);
 }
+extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq);
 
 /* nfs4proc.c */
 extern void __nfs4_read_done_cb(struct nfs_read_data *);
@@ -483,6 +484,12 @@ extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
                                   struct nfs4_sequence_args *args,
                                   struct nfs4_sequence_res *res,
                                   int cache_reply);
+extern int nfs40_walk_client_list(struct nfs_client *clp,
+                               struct nfs_client **result,
+                               struct rpc_cred *cred);
+extern int nfs41_walk_client_list(struct nfs_client *clp,
+                               struct nfs_client **result,
+                               struct rpc_cred *cred);
 
 /*
  * Determine the device name as a string
index 0539de1..8ee1fab 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef __NFS_NETNS_H__
 #define __NFS_NETNS_H__
 
+#include <linux/nfs4.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -22,6 +23,9 @@ struct nfs_net {
        struct list_head nfs_volume_list;
 #if IS_ENABLED(CONFIG_NFS_V4)
        struct idr cb_ident_idr; /* Protected by nfs_client_lock */
+       unsigned short nfs_callback_tcpport;
+       unsigned short nfs_callback_tcpport6;
+       int cb_users[NFS4_MAX_MINOR_VERSION + 1];
 #endif
        spinlock_t nfs_client_lock;
        struct timespec boot_time;
index da0618a..a525fde 100644 (file)
@@ -132,8 +132,8 @@ struct nfs4_lock_owner {
 struct nfs4_lock_state {
        struct list_head        ls_locks;       /* Other lock stateids */
        struct nfs4_state *     ls_state;       /* Pointer to open state */
-#define NFS_LOCK_INITIALIZED 1
-       int                     ls_flags;
+#define NFS_LOCK_INITIALIZED 0
+       unsigned long           ls_flags;
        struct nfs_seqid_counter        ls_seqid;
        nfs4_stateid            ls_stateid;
        atomic_t                ls_count;
@@ -191,6 +191,8 @@ struct nfs4_state_recovery_ops {
        int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
        struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
        int (*reclaim_complete)(struct nfs_client *);
+       int (*detect_trunking)(struct nfs_client *, struct nfs_client **,
+               struct rpc_cred *);
 };
 
 struct nfs4_state_maintenance_ops {
@@ -223,7 +225,7 @@ extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
 extern int nfs4_destroy_clientid(struct nfs_client *clp);
 extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
 extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
-extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
+extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
                                  struct nfs4_fs_locations *, struct page *);
@@ -320,9 +322,15 @@ extern void nfs4_renew_state(struct work_struct *);
 /* nfs4state.c */
 struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
+int nfs4_discover_server_trunking(struct nfs_client *clp,
+                       struct nfs_client **);
+int nfs40_discover_server_trunking(struct nfs_client *clp,
+                       struct nfs_client **, struct rpc_cred *);
 #if defined(CONFIG_NFS_V4_1)
 struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
+int nfs41_discover_server_trunking(struct nfs_client *clp,
+                       struct nfs_client **, struct rpc_cred *);
 extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
 #else
 static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
@@ -351,7 +359,7 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
-               fmode_t, fl_owner_t, pid_t);
+               fmode_t, const struct nfs_lockowner *);
 
 extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
@@ -372,6 +380,9 @@ extern bool nfs4_disable_idmapping;
 extern unsigned short max_session_slots;
 extern unsigned short send_implementation_id;
 
+#define NFS4_CLIENT_ID_UNIQ_LEN                (64)
+extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
+
 /* nfs4sysctl.c */
 #ifdef CONFIG_SYSCTL
 int nfs4_register_sysctl(void);
index 24eb663..6bacfde 100644 (file)
@@ -84,7 +84,7 @@ error:
 static void nfs4_destroy_callback(struct nfs_client *clp)
 {
        if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
-               nfs_callback_down(clp->cl_mvops->minor_version);
+               nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
 }
 
 static void nfs4_shutdown_client(struct nfs_client *clp)
@@ -185,6 +185,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                                    rpc_authflavor_t authflavour)
 {
        char buf[INET6_ADDRSTRLEN + 1];
+       struct nfs_client *old;
        int error;
 
        if (clp->cl_cons_state == NFS_CS_READY) {
@@ -230,6 +231,17 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
 
        if (!nfs4_has_session(clp))
                nfs_mark_client_ready(clp, NFS_CS_READY);
+
+       error = nfs4_discover_server_trunking(clp, &old);
+       if (error < 0)
+               goto error;
+       if (clp != old) {
+               clp->cl_preserve_clid = true;
+               nfs_put_client(clp);
+               clp = old;
+               atomic_inc(&clp->cl_count);
+       }
+
        return clp;
 
 error:
@@ -239,6 +251,248 @@ error:
        return ERR_PTR(error);
 }
 
+/*
+ * SETCLIENTID just did a callback update with the callback ident in
+ * "drop," but server trunking discovery claims "drop" and "keep" are
+ * actually the same server.  Swap the callback IDs so that "keep"
+ * will continue to use the callback ident the server now knows about,
+ * and so that "keep"'s original callback ident is destroyed when
+ * "drop" is freed.
+ */
+static void nfs4_swap_callback_idents(struct nfs_client *keep,
+                                     struct nfs_client *drop)
+{
+       struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
+       unsigned int save = keep->cl_cb_ident;
+
+       if (keep->cl_cb_ident == drop->cl_cb_ident)
+               return;
+
+       dprintk("%s: keeping callback ident %u and dropping ident %u\n",
+               __func__, keep->cl_cb_ident, drop->cl_cb_ident);
+
+       spin_lock(&nn->nfs_client_lock);
+
+       idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
+       keep->cl_cb_ident = drop->cl_cb_ident;
+
+       idr_replace(&nn->cb_ident_idr, drop, save);
+       drop->cl_cb_ident = save;
+
+       spin_unlock(&nn->nfs_client_lock);
+}
+
+/**
+ * nfs40_walk_client_list - Find server that recognizes a client ID
+ *
+ * @new: nfs_client with client ID to test
+ * @result: OUT: found nfs_client, or new
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in "result."
+ *
+ * NB: nfs40_walk_client_list() relies on the new nfs_client being
+ *     the last nfs_client on the list.
+ */
+int nfs40_walk_client_list(struct nfs_client *new,
+                          struct nfs_client **result,
+                          struct rpc_cred *cred)
+{
+       struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+       struct nfs_client *pos, *n, *prev = NULL;
+       struct nfs4_setclientid_res clid = {
+               .clientid       = new->cl_clientid,
+               .confirm        = new->cl_confirm,
+       };
+       int status;
+
+       spin_lock(&nn->nfs_client_lock);
+       list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+               /* If "pos" isn't marked ready, we can't trust the
+                * remaining fields in "pos" */
+               if (pos->cl_cons_state < NFS_CS_READY)
+                       continue;
+
+               if (pos->rpc_ops != new->rpc_ops)
+                       continue;
+
+               if (pos->cl_proto != new->cl_proto)
+                       continue;
+
+               if (pos->cl_minorversion != new->cl_minorversion)
+                       continue;
+
+               if (pos->cl_clientid != new->cl_clientid)
+                       continue;
+
+               atomic_inc(&pos->cl_count);
+               spin_unlock(&nn->nfs_client_lock);
+
+               if (prev)
+                       nfs_put_client(prev);
+
+               status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
+               if (status == 0) {
+                       nfs4_swap_callback_idents(pos, new);
+
+                       nfs_put_client(pos);
+                       *result = pos;
+                       dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
+                               __func__, pos, atomic_read(&pos->cl_count));
+                       return 0;
+               }
+               if (status != -NFS4ERR_STALE_CLIENTID) {
+                       nfs_put_client(pos);
+                       dprintk("NFS: <-- %s status = %d, no result\n",
+                               __func__, status);
+                       return status;
+               }
+
+               spin_lock(&nn->nfs_client_lock);
+               prev = pos;
+       }
+
+       /*
+        * No matching nfs_client found.  This should be impossible,
+        * because the new nfs_client has already been added to
+        * nfs_client_list by nfs_get_client().
+        *
+        * Don't BUG(), since the caller is holding a mutex.
+        */
+       if (prev)
+               nfs_put_client(prev);
+       spin_unlock(&nn->nfs_client_lock);
+       pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
+       return -NFS4ERR_STALE_CLIENTID;
+}
+
+#ifdef CONFIG_NFS_V4_1
+/*
+ * Returns true if the client IDs match
+ */
+static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
+{
+       if (a->cl_clientid != b->cl_clientid) {
+               dprintk("NFS: --> %s client ID %llx does not match %llx\n",
+                       __func__, a->cl_clientid, b->cl_clientid);
+               return false;
+       }
+       dprintk("NFS: --> %s client ID %llx matches %llx\n",
+               __func__, a->cl_clientid, b->cl_clientid);
+       return true;
+}
+
+/*
+ * Returns true if the server owners match
+ */
+static bool
+nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
+{
+       struct nfs41_server_owner *o1 = a->cl_serverowner;
+       struct nfs41_server_owner *o2 = b->cl_serverowner;
+
+       if (o1->minor_id != o2->minor_id) {
+               dprintk("NFS: --> %s server owner minor IDs do not match\n",
+                       __func__);
+               return false;
+       }
+
+       if (o1->major_id_sz != o2->major_id_sz)
+               goto out_major_mismatch;
+       if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
+               goto out_major_mismatch;
+
+       dprintk("NFS: --> %s server owners match\n", __func__);
+       return true;
+
+out_major_mismatch:
+       dprintk("NFS: --> %s server owner major IDs do not match\n",
+               __func__);
+       return false;
+}
+
+/**
+ * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
+ *
+ * @new: nfs_client with client ID to test
+ * @result: OUT: found nfs_client, or new
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in "result."
+ *
+ * NB: nfs41_walk_client_list() relies on the new nfs_client being
+ *     the last nfs_client on the list.
+ */
+int nfs41_walk_client_list(struct nfs_client *new,
+                          struct nfs_client **result,
+                          struct rpc_cred *cred)
+{
+       struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+       struct nfs_client *pos, *n, *prev = NULL;
+       int error;
+
+       spin_lock(&nn->nfs_client_lock);
+       list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+               /* If "pos" isn't marked ready, we can't trust the
+                * remaining fields in "pos", especially the client
+                * ID and serverowner fields.  Wait for CREATE_SESSION
+                * to finish. */
+               if (pos->cl_cons_state < NFS_CS_READY) {
+                       atomic_inc(&pos->cl_count);
+                       spin_unlock(&nn->nfs_client_lock);
+
+                       if (prev)
+                               nfs_put_client(prev);
+                       prev = pos;
+
+                       error = nfs_wait_client_init_complete(pos);
+                       if (error < 0) {
+                               nfs_put_client(pos);
+                               spin_lock(&nn->nfs_client_lock);
+                               continue;
+                       }
+
+                       spin_lock(&nn->nfs_client_lock);
+               }
+
+               if (pos->rpc_ops != new->rpc_ops)
+                       continue;
+
+               if (pos->cl_proto != new->cl_proto)
+                       continue;
+
+               if (pos->cl_minorversion != new->cl_minorversion)
+                       continue;
+
+               if (!nfs4_match_clientids(pos, new))
+                       continue;
+
+               if (!nfs4_match_serverowners(pos, new))
+                       continue;
+
+               spin_unlock(&nn->nfs_client_lock);
+               dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
+                       __func__, pos, atomic_read(&pos->cl_count));
+
+               *result = pos;
+               return 0;
+       }
+
+       /*
+        * No matching nfs_client found.  This should be impossible,
+        * because the new nfs_client has already been added to
+        * nfs_client_list by nfs_get_client().
+        *
+        * Don't BUG(), since the caller is holding a mutex.
+        */
+       spin_unlock(&nn->nfs_client_lock);
+       pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
+       return -NFS4ERR_STALE_CLIENTID;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
 static void nfs4_destroy_server(struct nfs_server *server)
 {
        nfs_server_return_all_delegations(server);
index eb5eb8e..afddd66 100644 (file)
@@ -95,16 +95,25 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        int ret;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret != 0)
-               goto out;
-       mutex_lock(&inode->i_mutex);
-       ret = nfs_file_fsync_commit(file, start, end, datasync);
-       if (!ret && !datasync)
-               /* application has asked for meta-data sync */
-               ret = pnfs_layoutcommit_inode(inode, true);
-       mutex_unlock(&inode->i_mutex);
-out:
+       do {
+               ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+               if (ret != 0)
+                       break;
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_file_fsync_commit(file, start, end, datasync);
+               if (!ret && !datasync)
+                       /* application has asked for meta-data sync */
+                       ret = pnfs_layoutcommit_inode(inode, true);
+               mutex_unlock(&inode->i_mutex);
+               /*
+                * If nfs_file_fsync_commit detected a server reboot, then
+                * resend all dirty pages that might have been covered by
+                * the NFS_CONTEXT_RESEND_WRITES flag
+                */
+               start = 0;
+               end = LLONG_MAX;
+       } while (ret == -EAGAIN);
+
        return ret;
 }
 
index 53f94d9..52d8472 100644 (file)
@@ -190,8 +190,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                 * i/o and all i/o waiting on the slot table to the MDS until
                 * layout is destroyed and a new valid layout is obtained.
                 */
-               set_bit(NFS_LAYOUT_INVALID,
-                               &NFS_I(inode)->layout->plh_flags);
                pnfs_destroy_layout(NFS_I(inode));
                rpc_wake_up(&tbl->slot_tbl_waitq);
                goto reset;
@@ -205,7 +203,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
        case -EPIPE:
                dprintk("%s DS connection error %d\n", __func__,
                        task->tk_status);
-               filelayout_mark_devid_invalid(devid);
+               nfs4_mark_deviceid_unavailable(devid);
                clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
                _pnfs_return_layout(inode);
                rpc_wake_up(&tbl->slot_tbl_waitq);
@@ -269,6 +267,21 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
                (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
 }
 
+bool
+filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
+{
+       return filelayout_test_devid_invalid(node) ||
+               nfs4_test_deviceid_unavailable(node);
+}
+
+static bool
+filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
+{
+       struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);
+
+       return filelayout_test_devid_unavailable(node);
+}
+
 /*
  * Call ops for the async read/write cases
  * In the case of dense layouts, the offset needs to be reset to its
@@ -453,7 +466,7 @@ static void filelayout_commit_release(void *calldata)
        struct nfs_commit_data *data = calldata;
 
        data->completion_ops->completion(data);
-       put_lseg(data->lseg);
+       pnfs_put_lseg(data->lseg);
        nfs_put_client(data->ds_clp);
        nfs_commitdata_release(data);
 }
@@ -608,13 +621,13 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
        d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld,
                                   NFS_SERVER(lo->plh_inode)->nfs_client, id);
        if (d == NULL) {
-               dsaddr = get_device_info(lo->plh_inode, id, gfp_flags);
+               dsaddr = filelayout_get_device_info(lo->plh_inode, id, gfp_flags);
                if (dsaddr == NULL)
                        goto out;
        } else
                dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
-       /* Found deviceid is being reaped */
-       if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags))
+       /* Found deviceid is unavailable */
+       if (filelayout_test_devid_unavailable(&dsaddr->id_node))
                        goto out_put;
 
        fl->dsaddr = dsaddr;
@@ -931,7 +944,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
        nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq);
        status = filelayout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS);
        if (status < 0) {
-               put_lseg(pgio->pg_lseg);
+               pnfs_put_lseg(pgio->pg_lseg);
                pgio->pg_lseg = NULL;
                goto out_mds;
        }
@@ -985,7 +998,7 @@ filelayout_clear_request_commit(struct nfs_page *req,
 out:
        nfs_request_remove_commit_list(req, cinfo);
        spin_unlock(cinfo->lock);
-       put_lseg(freeme);
+       pnfs_put_lseg(freeme);
 }
 
 static struct list_head *
@@ -1018,7 +1031,7 @@ filelayout_choose_commit_list(struct nfs_page *req,
                 * off due to a rewrite, in which case it will be done in
                 * filelayout_clear_request_commit
                 */
-               buckets[i].wlseg = get_lseg(lseg);
+               buckets[i].wlseg = pnfs_get_lseg(lseg);
        }
        set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
        cinfo->ds->nwritten++;
@@ -1128,7 +1141,7 @@ filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
                if (list_empty(src))
                        bucket->wlseg = NULL;
                else
-                       get_lseg(bucket->clseg);
+                       pnfs_get_lseg(bucket->clseg);
        }
        return ret;
 }
@@ -1159,12 +1172,12 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
 
        /* NOTE cinfo->lock is NOT held, relying on fact that this is
         * only called on single thread per dreq.
-        * Can't take the lock because need to do put_lseg
+        * Can't take the lock because need to do pnfs_put_lseg
         */
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
                if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
                        BUG_ON(!list_empty(&b->written));
-                       put_lseg(b->wlseg);
+                       pnfs_put_lseg(b->wlseg);
                        b->wlseg = NULL;
                }
        }
@@ -1200,7 +1213,7 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
                if (list_empty(&bucket->committing))
                        continue;
                nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo);
-               put_lseg(bucket->clseg);
+               pnfs_put_lseg(bucket->clseg);
                bucket->clseg = NULL;
        }
        /* Caller will clean up entries put on list */
index 43fe802..dca47d7 100644 (file)
@@ -128,24 +128,14 @@ filelayout_mark_devid_invalid(struct nfs4_deviceid_node *node)
        set_bit(NFS_DEVICEID_INVALID, &node->flags);
 }
 
-static inline bool
-filelayout_test_layout_invalid(struct pnfs_layout_hdr *lo)
-{
-       return test_bit(NFS_LAYOUT_INVALID, &lo->plh_flags);
-}
-
 static inline bool
 filelayout_test_devid_invalid(struct nfs4_deviceid_node *node)
 {
        return test_bit(NFS_DEVICEID_INVALID, &node->flags);
 }
 
-static inline bool
-filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
-{
-       return filelayout_test_devid_invalid(FILELAYOUT_DEVID_NODE(lseg)) ||
-               filelayout_test_layout_invalid(lseg->pls_layout);
-}
+extern bool
+filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node);
 
 extern struct nfs_fh *
 nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
@@ -158,7 +148,7 @@ struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
 extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
 extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
 struct nfs4_file_layout_dsaddr *
-get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
+filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
 void nfs4_ds_disconnect(struct nfs_client *clp);
 
 #endif /* FS_NFS_NFS4FILELAYOUT_H */
index f81231f..3336d5e 100644 (file)
@@ -690,7 +690,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl
  * of available devices, and return it.
  */
 struct nfs4_file_layout_dsaddr *
-get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
+filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
 {
        struct pnfs_device *pdev = NULL;
        u32 max_resp_sz;
@@ -804,13 +804,14 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
 
-       if (filelayout_test_devid_invalid(devid))
+       if (filelayout_test_devid_unavailable(devid))
                return NULL;
 
        if (ds == NULL) {
                printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
                        __func__, ds_idx);
-               goto mark_dev_invalid;
+               filelayout_mark_devid_invalid(devid);
+               return NULL;
        }
 
        if (!ds->ds_clp) {
@@ -818,14 +819,12 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
                int err;
 
                err = nfs4_ds_connect(s, ds);
-               if (err)
-                       goto mark_dev_invalid;
+               if (err) {
+                       nfs4_mark_deviceid_unavailable(devid);
+                       return NULL;
+               }
        }
        return ds;
-
-mark_dev_invalid:
-       filelayout_mark_devid_invalid(devid);
-       return NULL;
 }
 
 module_param(dataserver_retrans, uint, 0644);
index 017b4b0..79fbb61 100644 (file)
@@ -192,25 +192,13 @@ out:
 struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
                                        struct qstr *name)
 {
-       struct rpc_clnt *clone;
-       struct rpc_auth *auth;
        rpc_authflavor_t flavor;
 
        flavor = nfs4_negotiate_security(inode, name);
        if ((int)flavor < 0)
-               return ERR_PTR(flavor);
+               return ERR_PTR((int)flavor);
 
-       clone = rpc_clone_client(clnt);
-       if (IS_ERR(clone))
-               return clone;
-
-       auth = rpcauth_create(flavor, clone);
-       if (!auth) {
-               rpc_shutdown_client(clone);
-               clone = ERR_PTR(-EIO);
-       }
-
-       return clone;
+       return rpc_clone_client_set_auth(clnt, flavor);
 }
 
 static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
index 1e50326..68b21d8 100644 (file)
@@ -104,6 +104,8 @@ static int nfs4_map_errors(int err)
                return -EACCES;
        case -NFS4ERR_MINOR_VERS_MISMATCH:
                return -EPROTONOSUPPORT;
+       case -NFS4ERR_ACCESS:
+               return -EACCES;
        default:
                dprintk("%s could not handle NFSv4 error %d\n",
                                __func__, -err);
@@ -150,6 +152,12 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
        FATTR4_WORD2_MDSTHRESHOLD
 };
 
+static const u32 nfs4_open_noattr_bitmap[3] = {
+       FATTR4_WORD0_TYPE
+       | FATTR4_WORD0_CHANGE
+       | FATTR4_WORD0_FILEID,
+};
+
 const u32 nfs4_statfs_bitmap[2] = {
        FATTR4_WORD0_FILES_AVAIL
        | FATTR4_WORD0_FILES_FREE
@@ -832,6 +840,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.seqid = p->o_arg.seqid;
        p->c_res.seqid = p->c_arg.seqid;
        p->o_res.server = p->o_arg.server;
+       p->o_res.access_request = p->o_arg.access;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
 }
@@ -860,6 +869,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.fh = NFS_FH(dir);
        p->o_arg.open_flags = flags;
        p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
+       /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
+        * will return permission denied for all bits until close */
+       if (!(flags & O_EXCL)) {
+               /* ask server to check for all possible rights as results
+                * are cached */
+               p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
+                                 NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE;
+       }
        p->o_arg.clientid = server->nfs_client->cl_clientid;
        p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
        p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
@@ -1115,11 +1132,80 @@ out_return_state:
        return state;
 }
 
-static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+static void
+nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
+{
+       struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
+       struct nfs_delegation *delegation;
+       int delegation_flags = 0;
+
+       rcu_read_lock();
+       delegation = rcu_dereference(NFS_I(state->inode)->delegation);
+       if (delegation)
+               delegation_flags = delegation->flags;
+       rcu_read_unlock();
+       if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
+               pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
+                                  "returning a delegation for "
+                                  "OPEN(CLAIM_DELEGATE_CUR)\n",
+                                  clp->cl_hostname);
+       } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
+               nfs_inode_set_delegation(state->inode,
+                                        data->owner->so_cred,
+                                        &data->o_res);
+       else
+               nfs_inode_reclaim_delegation(state->inode,
+                                            data->owner->so_cred,
+                                            &data->o_res);
+}
+
+/*
+ * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
+ * and update the nfs4_state.
+ */
+static struct nfs4_state *
+_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+{
+       struct inode *inode = data->state->inode;
+       struct nfs4_state *state = data->state;
+       int ret;
+
+       if (!data->rpc_done) {
+               ret = data->rpc_status;
+               goto err;
+       }
+
+       ret = -ESTALE;
+       if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
+           !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
+           !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
+               goto err;
+
+       ret = -ENOMEM;
+       state = nfs4_get_open_state(inode, data->owner);
+       if (state == NULL)
+               goto err;
+
+       ret = nfs_refresh_inode(inode, &data->f_attr);
+       if (ret)
+               goto err;
+
+       if (data->o_res.delegation_type != 0)
+               nfs4_opendata_check_deleg(data, state);
+       update_open_stateid(state, &data->o_res.stateid, NULL,
+                           data->o_arg.fmode);
+
+       return state;
+err:
+       return ERR_PTR(ret);
+
+}
+
+static struct nfs4_state *
+_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
 {
        struct inode *inode;
        struct nfs4_state *state = NULL;
-       struct nfs_delegation *delegation;
        int ret;
 
        if (!data->rpc_done) {
@@ -1138,30 +1224,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
        state = nfs4_get_open_state(inode, data->owner);
        if (state == NULL)
                goto err_put_inode;
-       if (data->o_res.delegation_type != 0) {
-               struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
-               int delegation_flags = 0;
-
-               rcu_read_lock();
-               delegation = rcu_dereference(NFS_I(inode)->delegation);
-               if (delegation)
-                       delegation_flags = delegation->flags;
-               rcu_read_unlock();
-               if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
-                       pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
-                                       "returning a delegation for "
-                                       "OPEN(CLAIM_DELEGATE_CUR)\n",
-                                       clp->cl_hostname);
-               } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
-                       nfs_inode_set_delegation(state->inode,
-                                       data->owner->so_cred,
-                                       &data->o_res);
-               else
-                       nfs_inode_reclaim_delegation(state->inode,
-                                       data->owner->so_cred,
-                                       &data->o_res);
-       }
-
+       if (data->o_res.delegation_type != 0)
+               nfs4_opendata_check_deleg(data, state);
        update_open_stateid(state, &data->o_res.stateid, NULL,
                        data->o_arg.fmode);
        iput(inode);
@@ -1173,6 +1237,14 @@ err:
        return ERR_PTR(ret);
 }
 
+static struct nfs4_state *
+nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+{
+       if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
+               return _nfs4_opendata_reclaim_to_nfs4_state(data);
+       return _nfs4_opendata_to_nfs4_state(data);
+}
+
 static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
 {
        struct nfs_inode *nfsi = NFS_I(state->inode);
@@ -1494,6 +1566,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
        if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+               data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
                nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
        }
        data->timestamp = jiffies;
@@ -1526,7 +1599,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
                return;
 
        if (task->tk_status == 0) {
-               switch (data->o_res.f_attr->mode & S_IFMT) {
+               if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
+                       switch (data->o_res.f_attr->mode & S_IFMT) {
                        case S_IFREG:
                                break;
                        case S_IFLNK:
@@ -1537,6 +1611,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
                                break;
                        default:
                                data->rpc_status = -ENOTDIR;
+                       }
                }
                renew_lease(data->o_res.server, data->timestamp);
                if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
@@ -1643,6 +1718,39 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
        return status;
 }
 
+static int nfs4_opendata_access(struct rpc_cred *cred,
+                               struct nfs4_opendata *opendata,
+                               struct nfs4_state *state, fmode_t fmode)
+{
+       struct nfs_access_entry cache;
+       u32 mask;
+
+       /* access call failed or for some reason the server doesn't
+        * support any access modes -- defer access call until later */
+       if (opendata->o_res.access_supported == 0)
+               return 0;
+
+       mask = 0;
+       /* don't check MAY_WRITE - a newly created file may not have
+        * write mode bits, but POSIX allows the creating process to write */
+       if (fmode & FMODE_READ)
+               mask |= MAY_READ;
+       if (fmode & FMODE_EXEC)
+               mask |= MAY_EXEC;
+
+       cache.cred = cred;
+       cache.jiffies = jiffies;
+       nfs_access_set_mask(&cache, opendata->o_res.access_result);
+       nfs_access_add_cache(state->inode, &cache);
+
+       if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
+               return 0;
+
+       /* even though OPEN succeeded, access is denied. Close the file */
+       nfs4_close_state(state, fmode);
+       return -NFS4ERR_ACCESS;
+}
+
 /*
  * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
  */
@@ -1774,7 +1882,11 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
                 * informs us the stateid is unrecognized. */
                if (status != -NFS4ERR_BAD_STATEID)
                        nfs41_free_stateid(server, stateid);
+               nfs_remove_bad_delegation(state->inode);
 
+               write_seqlock(&state->seqlock);
+               nfs4_stateid_copy(&state->stateid, &state->open_stateid);
+               write_sequnlock(&state->seqlock);
                clear_bit(NFS_DELEGATED_STATE, &state->flags);
        }
 }
@@ -1790,7 +1902,7 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
 static int nfs41_check_open_stateid(struct nfs4_state *state)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
-       nfs4_stateid *stateid = &state->stateid;
+       nfs4_stateid *stateid = &state->open_stateid;
        int status;
 
        /* If a state reset has been done, test_stateid is unneeded */
@@ -1896,6 +2008,10 @@ static int _nfs4_do_open(struct inode *dir,
        if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
 
+       status = nfs4_opendata_access(cred, opendata, state, fmode);
+       if (status != 0)
+               goto err_opendata_put;
+
        if (opendata->o_arg.open_flags & O_EXCL) {
                nfs4_exclusive_attrset(opendata, sattr);
 
@@ -1941,7 +2057,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        struct nfs4_state *res;
        int status;
 
-       fmode &= FMODE_READ|FMODE_WRITE;
+       fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
        do {
                status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
                                       &res, ctx_th);
@@ -2013,8 +2129,12 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        nfs_fattr_init(fattr);
 
        if (state != NULL) {
+               struct nfs_lockowner lockowner = {
+                       .l_owner = current->files,
+                       .l_pid = current->tgid,
+               };
                nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
-                               current->files, current->tgid);
+                               &lockowner);
        } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
                                FMODE_WRITE)) {
                /* Use that stateid */
@@ -2133,6 +2253,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_closedata *calldata = data;
        struct nfs4_state *state = calldata->state;
+       struct inode *inode = calldata->inode;
        int call_close = 0;
 
        dprintk("%s: begin!\n", __func__);
@@ -2166,16 +2287,13 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (calldata->arg.fmode == 0) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
                if (calldata->roc &&
-                   pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
-                       rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
-                                    task, NULL);
+                   pnfs_roc_drain(inode, &calldata->roc_barrier, task))
                        goto out;
-               }
        }
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
-       if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
+       if (nfs4_setup_sequence(NFS_SERVER(inode),
                                &calldata->arg.seq_args,
                                &calldata->res.seq_res,
                                task))
@@ -2202,7 +2320,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
  *
  * NOTE: Caller must be holding the sp->so_owner semaphore!
  */
-int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
+int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_closedata *calldata;
@@ -2238,7 +2356,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
-       calldata->roc = roc;
+       calldata->roc = pnfs_roc(state->inode);
        nfs_sb_active(calldata->inode->i_sb);
 
        msg.rpc_argp = &calldata->arg;
@@ -2255,8 +2373,6 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
 out_free_calldata:
        kfree(calldata);
 out:
-       if (roc)
-               pnfs_roc_release(state->inode);
        nfs4_put_open_state(state);
        nfs4_put_state_owner(sp);
        return status;
@@ -2399,7 +2515,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
        int ret;
 
        auth = rpcauth_create(flavor, server->client);
-       if (!auth) {
+       if (IS_ERR(auth)) {
                ret = -EIO;
                goto out;
        }
@@ -2767,13 +2883,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (!status) {
-               entry->mask = 0;
-               if (res.access & NFS4_ACCESS_READ)
-                       entry->mask |= MAY_READ;
-               if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
-                       entry->mask |= MAY_WRITE;
-               if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
-                       entry->mask |= MAY_EXEC;
+               nfs_access_set_mask(entry, res.access);
                nfs_refresh_inode(inode, res.fattr);
        }
        nfs_free_fattr(res.fattr);
@@ -3362,8 +3472,11 @@ static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, s
 
        nfs_fattr_init(fsinfo->fattr);
        error = nfs4_do_fsinfo(server, fhandle, fsinfo);
-       if (error == 0)
+       if (error == 0) {
+               /* block layout checks this! */
+               server->pnfs_blksize = fsinfo->blksize;
                set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
+       }
 
        return error;
 }
@@ -4007,6 +4120,36 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
 }
 
+static unsigned int
+nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
+                                  char *buf, size_t len)
+{
+       unsigned int result;
+
+       rcu_read_lock();
+       result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
+                               clp->cl_ipaddr,
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                                       RPC_DISPLAY_ADDR),
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                                       RPC_DISPLAY_PROTO));
+       rcu_read_unlock();
+       return result;
+}
+
+static unsigned int
+nfs4_init_uniform_client_string(const struct nfs_client *clp,
+                               char *buf, size_t len)
+{
+       char *nodename = clp->cl_rpcclient->cl_nodename;
+
+       if (nfs4_client_id_uniquifier[0] != '\0')
+               nodename = nfs4_client_id_uniquifier;
+       return scnprintf(buf, len, "Linux NFSv%u.%u %s",
+                               clp->rpc_ops->version, clp->cl_minorversion,
+                               nodename);
+}
+
 /**
  * nfs4_proc_setclientid - Negotiate client ID
  * @clp: state data structure
@@ -4037,15 +4180,18 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
 
        /* nfs_client_id4 */
        nfs4_init_boot_verifier(clp, &sc_verifier);
-       rcu_read_lock();
-       setclientid.sc_name_len = scnprintf(setclientid.sc_name,
-                       sizeof(setclientid.sc_name), "%s/%s %s",
-                       clp->cl_ipaddr,
-                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                               RPC_DISPLAY_ADDR),
-                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                               RPC_DISPLAY_PROTO));
+       if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
+               setclientid.sc_name_len =
+                               nfs4_init_uniform_client_string(clp,
+                                               setclientid.sc_name,
+                                               sizeof(setclientid.sc_name));
+       else
+               setclientid.sc_name_len =
+                               nfs4_init_nonuniform_client_string(clp,
+                                               setclientid.sc_name,
+                                               sizeof(setclientid.sc_name));
        /* cb_client4 */
+       rcu_read_lock();
        setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
                                sizeof(setclientid.sc_netid),
                                rpc_peeraddr2str(clp->cl_rpcclient,
@@ -4391,7 +4537,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
 
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                return;
-       if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
+       if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
                task->tk_action = NULL;
                return;
@@ -4585,7 +4731,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
        }
        if (data->rpc_status == 0) {
                nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
-               data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
+               set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
                renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
        }
 out:
@@ -4632,7 +4778,7 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
        case -NFS4ERR_BAD_STATEID:
                lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
                if (new_lock_owner != 0 ||
-                  (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
+                  test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
                        nfs4_schedule_stateid_recovery(server, lsp->ls_state);
                break;
        case -NFS4ERR_STALE_STATEID:
@@ -4756,7 +4902,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
        struct nfs_server *server = NFS_SERVER(state->inode);
 
        list_for_each_entry(lsp, &state->lock_states, ls_locks) {
-               if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+               if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
                        status = nfs41_test_stateid(server, &lsp->ls_stateid);
                        if (status != NFS_OK) {
                                /* Free the stateid unless the server
@@ -4764,7 +4910,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                                if (status != -NFS4ERR_BAD_STATEID)
                                        nfs41_free_stateid(server,
                                                        &lsp->ls_stateid);
-                               lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+                               clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
                                ret = status;
                        }
                }
@@ -5267,10 +5413,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        };
 
        nfs4_init_boot_verifier(clp, &verifier);
-       args.id_len = scnprintf(args.id, sizeof(args.id),
-                               "%s/%s",
-                               clp->cl_ipaddr,
-                               clp->cl_rpcclient->cl_nodename);
+       args.id_len = nfs4_init_uniform_client_string(clp, args.id,
+                                                       sizeof(args.id));
        dprintk("NFS call  exchange_id auth=%s, '%.*s'\n",
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                args.id_len, args.id);
@@ -5391,6 +5535,8 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
                goto out;
        if (clp->cl_exchange_flags == 0)
                goto out;
+       if (clp->cl_preserve_clid)
+               goto out;
        cred = nfs4_get_exchange_id_cred(clp);
        ret = nfs4_proc_destroy_clientid(clp, cred);
        if (cred)
@@ -6196,26 +6342,44 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
-       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct inode *inode = lgp->args.inode;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct pnfs_layout_hdr *lo;
+       struct nfs4_state *state = NULL;
 
        dprintk("--> %s\n", __func__);
 
        if (!nfs4_sequence_done(task, &lgp->res.seq_res))
-               return;
+               goto out;
 
        switch (task->tk_status) {
        case 0:
-               break;
+               goto out;
        case -NFS4ERR_LAYOUTTRYLATER:
        case -NFS4ERR_RECALLCONFLICT:
                task->tk_status = -NFS4ERR_DELAY;
-               /* Fall through */
-       default:
-               if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
-                       rpc_restart_call_prepare(task);
-                       return;
+               break;
+       case -NFS4ERR_EXPIRED:
+       case -NFS4ERR_BAD_STATEID:
+               spin_lock(&inode->i_lock);
+               lo = NFS_I(inode)->layout;
+               if (!lo || list_empty(&lo->plh_segs)) {
+                       spin_unlock(&inode->i_lock);
+                       /* If the open stateid was bad, then recover it. */
+                       state = lgp->args.ctx->state;
+               } else {
+                       LIST_HEAD(head);
+
+                       pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
+                       spin_unlock(&inode->i_lock);
+                       /* Mark the bad layout state as invalid, then
+                        * retry using the open stateid. */
+                       pnfs_free_lseg_list(&head);
                }
        }
+       if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
+               rpc_restart_call_prepare(task);
+out:
        dprintk("<-- %s\n", __func__);
 }
 
@@ -6282,7 +6446,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
        .rpc_release = nfs4_layoutget_release,
 };
 
-void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
+struct pnfs_layout_segment *
+nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 {
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
        size_t max_pages = max_response_pages(server);
@@ -6299,6 +6464,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
                .callback_data = lgp,
                .flags = RPC_TASK_ASYNC,
        };
+       struct pnfs_layout_segment *lseg = NULL;
        int status = 0;
 
        dprintk("--> %s\n", __func__);
@@ -6306,7 +6472,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
        if (!lgp->args.layout.pages) {
                nfs4_layoutget_release(lgp);
-               return;
+               return ERR_PTR(-ENOMEM);
        }
        lgp->args.layout.pglen = max_pages * PAGE_SIZE;
 
@@ -6315,15 +6481,17 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
-               return;
+               return ERR_CAST(task);
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
        if (status == 0)
-               status = pnfs_layout_process(lgp);
+               lseg = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
-       return;
+       if (status)
+               return ERR_PTR(status);
+       return lseg;
 }
 
 static void
@@ -6342,7 +6510,6 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
        struct nfs_server *server;
-       struct pnfs_layout_hdr *lo = lrp->args.layout;
 
        dprintk("--> %s\n", __func__);
 
@@ -6354,20 +6521,21 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
                rpc_restart_call_prepare(task);
                return;
        }
-       spin_lock(&lo->plh_inode->i_lock);
-       if (task->tk_status == 0 && lrp->res.lrs_present)
-               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
-       lo->plh_block_lgets--;
-       spin_unlock(&lo->plh_inode->i_lock);
        dprintk("<-- %s\n", __func__);
 }
 
 static void nfs4_layoutreturn_release(void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
+       struct pnfs_layout_hdr *lo = lrp->args.layout;
 
        dprintk("--> %s\n", __func__);
-       put_layout_hdr(lrp->args.layout);
+       spin_lock(&lo->plh_inode->i_lock);
+       if (lrp->res.lrs_present)
+               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       lo->plh_block_lgets--;
+       spin_unlock(&lo->plh_inode->i_lock);
+       pnfs_put_layout_hdr(lrp->args.layout);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
 }
@@ -6541,7 +6709,7 @@ static void nfs4_layoutcommit_release(void *calldata)
                list_del_init(&lseg->pls_lc_list);
                if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
                                       &lseg->pls_flags))
-                       put_lseg(lseg);
+                       pnfs_put_lseg(lseg);
        }
 
        clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
@@ -6800,6 +6968,7 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs4_init_clientid,
        .get_clid_cred  = nfs4_get_setclientid_cred,
+       .detect_trunking = nfs40_discover_server_trunking,
 };
 
 #if defined(CONFIG_NFS_V4_1)
@@ -6811,6 +6980,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
        .reclaim_complete = nfs41_proc_reclaim_complete,
+       .detect_trunking = nfs41_discover_server_trunking,
 };
 #endif /* CONFIG_NFS_V4_1 */
 
index 55148de..c351e6b 100644 (file)
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
+#include <linux/sunrpc/clnt.h>
+
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "delegation.h"
 #include "internal.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY                NFSDBG_STATE
 
 #define OPENOWNER_POOL_SIZE    8
 
 const nfs4_stateid zero_stateid;
-
+static DEFINE_MUTEX(nfs_clid_init_mutex);
 static LIST_HEAD(nfs4_clientid_list);
 
 int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
@@ -73,12 +76,13 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
        };
        unsigned short port;
        int status;
+       struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
 
        if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
                goto do_confirm;
-       port = nfs_callback_tcpport;
+       port = nn->nfs_callback_tcpport;
        if (clp->cl_addr.ss_family == AF_INET6)
-               port = nfs_callback_tcpport6;
+               port = nn->nfs_callback_tcpport6;
 
        status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
        if (status != 0)
@@ -96,6 +100,56 @@ out:
        return status;
 }
 
+/**
+ * nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in
+ * "result".
+ *
+ * Note: The returned client may not yet be marked ready.
+ */
+int nfs40_discover_server_trunking(struct nfs_client *clp,
+                                  struct nfs_client **result,
+                                  struct rpc_cred *cred)
+{
+       struct nfs4_setclientid_res clid = {
+               .clientid = clp->cl_clientid,
+               .confirm = clp->cl_confirm,
+       };
+       struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
+       unsigned short port;
+       int status;
+
+       port = nn->nfs_callback_tcpport;
+       if (clp->cl_addr.ss_family == AF_INET6)
+               port = nn->nfs_callback_tcpport6;
+
+       status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
+       if (status != 0)
+               goto out;
+       clp->cl_clientid = clid.clientid;
+       clp->cl_confirm = clid.confirm;
+
+       status = nfs40_walk_client_list(clp, result, cred);
+       switch (status) {
+       case -NFS4ERR_STALE_CLIENTID:
+               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       case 0:
+               /* Sustain the lease, even if it's empty.  If the clientid4
+                * goes stale it's of no use for trunking discovery. */
+               nfs4_schedule_state_renewal(*result);
+               break;
+       }
+
+out:
+       return status;
+}
+
 struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
 {
        struct rpc_cred *cred = NULL;
@@ -275,6 +329,33 @@ out:
        return status;
 }
 
+/**
+ * nfs41_discover_server_trunking - Detect server IP address trunking (mv1)
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ * @cred: credential to use for trunking test
+ *
+ * Returns NFS4_OK, a negative errno, or a negative NFS4ERR status.
+ * If NFS4_OK is returned, an nfs_client pointer is planted in
+ * "result".
+ *
+ * Note: The returned client may not yet be marked ready.
+ */
+int nfs41_discover_server_trunking(struct nfs_client *clp,
+                                  struct nfs_client **result,
+                                  struct rpc_cred *cred)
+{
+       int status;
+
+       status = nfs4_proc_exchange_id(clp, cred);
+       if (status != NFS4_OK)
+               return status;
+       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+
+       return nfs41_walk_client_list(clp, result, cred);
+}
+
 struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
 {
        struct rpc_cred *cred;
@@ -729,11 +810,8 @@ static void __nfs4_close(struct nfs4_state *state,
        if (!call_close) {
                nfs4_put_open_state(state);
                nfs4_put_state_owner(owner);
-       } else {
-               bool roc = pnfs_roc(state->inode);
-
-               nfs4_do_close(state, gfp_mask, wait, roc);
-       }
+       } else
+               nfs4_do_close(state, gfp_mask, wait);
 }
 
 void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
@@ -865,7 +943,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
        if (list_empty(&state->lock_states))
                clear_bit(LK_STATE_IN_USE, &state->flags);
        spin_unlock(&state->state_lock);
-       if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+       if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
                if (nfs4_release_lockowner(lsp) == 0)
                        return;
        }
@@ -911,17 +989,25 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 }
 
 static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
-               fl_owner_t fl_owner, pid_t fl_pid)
+               const struct nfs_lockowner *lockowner)
 {
        struct nfs4_lock_state *lsp;
+       fl_owner_t fl_owner;
+       pid_t fl_pid;
        bool ret = false;
 
+
+       if (lockowner == NULL)
+               goto out;
+
        if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
                goto out;
 
+       fl_owner = lockowner->l_owner;
+       fl_pid = lockowner->l_pid;
        spin_lock(&state->state_lock);
        lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
-       if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
+       if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
                ret = true;
        }
@@ -946,11 +1032,11 @@ static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
  * requests.
  */
 void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
-               fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
+               fmode_t fmode, const struct nfs_lockowner *lockowner)
 {
        if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
                return;
-       if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
+       if (nfs4_copy_lock_stateid(dst, state, lockowner))
                return;
        nfs4_copy_open_stateid(dst, state);
 }
@@ -1289,7 +1375,7 @@ restart:
                        if (status >= 0) {
                                spin_lock(&state->state_lock);
                                list_for_each_entry(lock, &state->lock_states, ls_locks) {
-                                       if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
+                                       if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
                                                pr_warn_ratelimited("NFS: "
                                                        "%s: Lock reclaim "
                                                        "failed!\n", __func__);
@@ -1361,7 +1447,7 @@ static void nfs4_clear_open_state(struct nfs4_state *state)
        spin_lock(&state->state_lock);
        list_for_each_entry(lock, &state->lock_states, ls_locks) {
                lock->ls_seqid.flags = 0;
-               lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
+               clear_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags);
        }
        spin_unlock(&state->state_lock);
 }
@@ -1595,8 +1681,8 @@ out:
        return nfs4_recovery_handle_error(clp, status);
 }
 
-/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
- * on EXCHANGE_ID for v4.1
+/* Set NFS4CLNT_LEASE_EXPIRED and reclaim reboot state for all v4.0 errors
+ * and for recoverable errors on EXCHANGE_ID for v4.1
  */
 static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
 {
@@ -1606,8 +1692,12 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                        return -ESERVERFAULT;
                /* Lease confirmation error: retry after purging the lease */
                ssleep(1);
+               clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+               break;
        case -NFS4ERR_STALE_CLIENTID:
                clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+               nfs4_state_clear_reclaim_reboot(clp);
+               nfs4_state_start_reclaim_reboot(clp);
                break;
        case -NFS4ERR_CLID_INUSE:
                pr_err("NFS: Server %s reports our clientid is in use\n",
@@ -1698,6 +1788,109 @@ static int nfs4_purge_lease(struct nfs_client *clp)
        return 0;
 }
 
+/**
+ * nfs4_discover_server_trunking - Detect server IP address trunking
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ *
+ * Returns zero or a negative errno.  If zero is returned,
+ * an nfs_client pointer is planted in "result".
+ *
+ * Note: since we are invoked in process context, and
+ * not from inside the state manager, we cannot use
+ * nfs4_handle_reclaim_lease_error().
+ */
+int nfs4_discover_server_trunking(struct nfs_client *clp,
+                                 struct nfs_client **result)
+{
+       const struct nfs4_state_recovery_ops *ops =
+                               clp->cl_mvops->reboot_recovery_ops;
+       rpc_authflavor_t *flavors, flav, save;
+       struct rpc_clnt *clnt;
+       struct rpc_cred *cred;
+       int i, len, status;
+
+       dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
+
+       len = NFS_MAX_SECFLAVORS;
+       flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
+       if (flavors == NULL) {
+               status = -ENOMEM;
+               goto out;
+       }
+       len = rpcauth_list_flavors(flavors, len);
+       if (len < 0) {
+               status = len;
+               goto out_free;
+       }
+       clnt = clp->cl_rpcclient;
+       save = clnt->cl_auth->au_flavor;
+       i = 0;
+
+       mutex_lock(&nfs_clid_init_mutex);
+       status  = -ENOENT;
+again:
+       cred = ops->get_clid_cred(clp);
+       if (cred == NULL)
+               goto out_unlock;
+
+       status = ops->detect_trunking(clp, result, cred);
+       put_rpccred(cred);
+       switch (status) {
+       case 0:
+               break;
+
+       case -EACCES:
+               if (clp->cl_machine_cred == NULL)
+                       break;
+               /* Handle case where the user hasn't set up machine creds */
+               nfs4_clear_machine_cred(clp);
+       case -NFS4ERR_DELAY:
+       case -ETIMEDOUT:
+       case -EAGAIN:
+               ssleep(1);
+               dprintk("NFS: %s after status %d, retrying\n",
+                       __func__, status);
+               goto again;
+
+       case -NFS4ERR_CLID_INUSE:
+       case -NFS4ERR_WRONGSEC:
+               status = -EPERM;
+               if (i >= len)
+                       break;
+
+               flav = flavors[i++];
+               if (flav == save)
+                       flav = flavors[i++];
+               clnt = rpc_clone_client_set_auth(clnt, flav);
+               if (IS_ERR(clnt)) {
+                       status = PTR_ERR(clnt);
+                       break;
+               }
+               clp->cl_rpcclient = clnt;
+               goto again;
+
+       case -NFS4ERR_MINOR_VERS_MISMATCH:
+               status = -EPROTONOSUPPORT;
+               break;
+
+       case -EKEYEXPIRED:
+               nfs4_warn_keyexpired(clp->cl_hostname);
+       case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
+                                * in nfs4_exchange_id */
+               status = -EKEYEXPIRED;
+       }
+
+out_unlock:
+       mutex_unlock(&nfs_clid_init_mutex);
+out_free:
+       kfree(flavors);
+out:
+       dprintk("NFS: %s: status = %d\n", __func__, status);
+       return status;
+}
+
 #ifdef CONFIG_NFS_V4_1
 void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 {
@@ -2008,6 +2201,7 @@ out_error:
        pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
                        " with error %d\n", section_sep, section,
                        clp->cl_hostname, -status);
+       ssleep(1);
        nfs4_end_drain_session(clp);
        nfs4_clear_state_manager_bit(clp);
 }
index 5729bc8..2628d92 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/nfs_idmap.h>
 #include <linux/nfs_fs.h>
 
+#include "nfs4_fs.h"
 #include "callback.h"
 
 static const int nfs_set_port_min = 0;
index 8dba6bd..40836ee 100644 (file)
@@ -447,12 +447,14 @@ static int nfs4_stat_to_errno(int);
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
                                encode_open_maxsz + \
+                               encode_access_maxsz + \
                                encode_getfh_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
                                decode_open_maxsz + \
+                               decode_access_maxsz + \
                                decode_getfh_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_open_confirm_sz \
@@ -467,11 +469,13 @@ static int nfs4_stat_to_errno(int);
                                        encode_sequence_maxsz + \
                                        encode_putfh_maxsz + \
                                        encode_open_maxsz + \
+                                       encode_access_maxsz + \
                                        encode_getattr_maxsz)
 #define NFS4_dec_open_noattr_sz        (compound_decode_hdr_maxsz + \
                                        decode_sequence_maxsz + \
                                        decode_putfh_maxsz + \
                                        decode_open_maxsz + \
+                                       decode_access_maxsz + \
                                        decode_getattr_maxsz)
 #define NFS4_enc_open_downgrade_sz \
                                (compound_encode_hdr_maxsz + \
@@ -1509,8 +1513,12 @@ static void encode_open_stateid(struct xdr_stream *xdr,
        nfs4_stateid stateid;
 
        if (ctx->state != NULL) {
+               const struct nfs_lockowner *lockowner = NULL;
+
+               if (l_ctx != NULL)
+                       lockowner = &l_ctx->lockowner;
                nfs4_select_rw_stateid(&stateid, ctx->state,
-                               fmode, l_ctx->lockowner, l_ctx->pid);
+                               fmode, lockowner);
                if (zero_seqid)
                        stateid.seqid = 0;
                encode_nfs4_stateid(xdr, &stateid);
@@ -2216,6 +2224,8 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_putfh(xdr, args->fh, &hdr);
        encode_open(xdr, args, &hdr);
        encode_getfh(xdr, &hdr);
+       if (args->access)
+               encode_access(xdr, args->access, &hdr);
        encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
        encode_nops(&hdr);
 }
@@ -2252,7 +2262,9 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        encode_open(xdr, args, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       if (args->access)
+               encode_access(xdr, args->access, &hdr);
+       encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
        encode_nops(&hdr);
 }
 
@@ -4095,7 +4107,7 @@ out_overflow:
        return -EIO;
 }
 
-static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
+static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
 {
        __be32 *p;
        uint32_t supp, acc;
@@ -4109,8 +4121,8 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
                goto out_overflow;
        supp = be32_to_cpup(p++);
        acc = be32_to_cpup(p);
-       access->supported = supp;
-       access->access = acc;
+       *supported = supp;
+       *access = acc;
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -5642,7 +5654,8 @@ static int decode_getdeviceinfo(struct xdr_stream *xdr,
         * and places the remaining xdr data in xdr_buf->tail
         */
        pdev->mincount = be32_to_cpup(p);
-       xdr_read_pages(xdr, pdev->mincount); /* include space for the length */
+       if (xdr_read_pages(xdr, pdev->mincount) != pdev->mincount)
+               goto out_overflow;
 
        /* Parse notification bitmap, verifying that it is zero. */
        p = xdr_inline_decode(xdr, 4);
@@ -5887,7 +5900,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_putfh(xdr);
        if (status != 0)
                goto out;
-       status = decode_access(xdr, res);
+       status = decode_access(xdr, &res->supported, &res->access);
        if (status != 0)
                goto out;
        decode_getfattr(xdr, res->fattr, res->server);
@@ -6228,6 +6241,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_getfh(xdr, &res->fh);
        if (status)
                goto out;
+       if (res->access_request)
+               decode_access(xdr, &res->access_supported, &res->access_result);
        decode_getfattr(xdr, res->f_attr, res->server);
 out:
        return status;
@@ -6276,6 +6291,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
        status = decode_open(xdr, res);
        if (status)
                goto out;
+       if (res->access_request)
+               decode_access(xdr, &res->access_supported, &res->access_result);
        decode_getfattr(xdr, res->f_attr, res->server);
 out:
        return status;
index ea6d111..be731e6 100644 (file)
@@ -41,6 +41,7 @@
 #include <scsi/osd_ore.h>
 
 #include "objlayout.h"
+#include "../internal.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
@@ -606,8 +607,14 @@ static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
 void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
 {
        unsigned long stripe_end = 0;
+       u64 wb_size;
 
-       pnfs_generic_pg_init_write(pgio, req);
+       if (pgio->pg_dreq == NULL)
+               wb_size = i_size_read(pgio->pg_inode) - req_offset(req);
+       else
+               wb_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
+       pnfs_generic_pg_init_write(pgio, req, wb_size);
        if (unlikely(pgio->pg_lseg == NULL))
                return; /* Not pNFS */
 
index 311a796..e56e846 100644 (file)
@@ -102,6 +102,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
                   unsigned int offset, unsigned int count)
 {
        struct nfs_page         *req;
+       struct nfs_lock_context *l_ctx;
 
        /* try to allocate the request struct */
        req = nfs_page_alloc();
@@ -109,11 +110,12 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
                return ERR_PTR(-ENOMEM);
 
        /* get lock context early so we can deal with alloc failures */
-       req->wb_lock_context = nfs_get_lock_context(ctx);
-       if (req->wb_lock_context == NULL) {
+       l_ctx = nfs_get_lock_context(ctx);
+       if (IS_ERR(l_ctx)) {
                nfs_page_free(req);
-               return ERR_PTR(-ENOMEM);
+               return ERR_CAST(l_ctx);
        }
+       req->wb_lock_context = l_ctx;
 
        /* Initialize the request struct. Initially, we assume a
         * long write-back delay. This will be adjusted in
@@ -290,7 +292,9 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
 {
        if (req->wb_context->cred != prev->wb_context->cred)
                return false;
-       if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner)
+       if (req->wb_lock_context->lockowner.l_owner != prev->wb_lock_context->lockowner.l_owner)
+               return false;
+       if (req->wb_lock_context->lockowner.l_pid != prev->wb_lock_context->lockowner.l_pid)
                return false;
        if (req->wb_context->state != prev->wb_context->state)
                return false;
index 2e00fea..fe624c9 100644 (file)
@@ -35,6 +35,7 @@
 #include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS
+#define PNFS_LAYOUTGET_RETRY_TIMEOUT (120*HZ)
 
 /* Locking:
  *
@@ -190,7 +191,7 @@ EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
 
 /* Need to hold i_lock if caller does not already hold reference */
 void
-get_layout_hdr(struct pnfs_layout_hdr *lo)
+pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo)
 {
        atomic_inc(&lo->plh_refcount);
 }
@@ -199,43 +200,107 @@ static struct pnfs_layout_hdr *
 pnfs_alloc_layout_hdr(struct inode *ino, gfp_t gfp_flags)
 {
        struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
-       return ld->alloc_layout_hdr ? ld->alloc_layout_hdr(ino, gfp_flags) :
-               kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags);
+       return ld->alloc_layout_hdr(ino, gfp_flags);
 }
 
 static void
 pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
 {
-       struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
+       struct nfs_server *server = NFS_SERVER(lo->plh_inode);
+       struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
+
+       if (!list_empty(&lo->plh_layouts)) {
+               struct nfs_client *clp = server->nfs_client;
+
+               spin_lock(&clp->cl_lock);
+               list_del_init(&lo->plh_layouts);
+               spin_unlock(&clp->cl_lock);
+       }
        put_rpccred(lo->plh_lc_cred);
-       return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
+       return ld->free_layout_hdr(lo);
 }
 
 static void
-destroy_layout_hdr(struct pnfs_layout_hdr *lo)
+pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo)
 {
+       struct nfs_inode *nfsi = NFS_I(lo->plh_inode);
        dprintk("%s: freeing layout cache %p\n", __func__, lo);
-       BUG_ON(!list_empty(&lo->plh_layouts));
-       NFS_I(lo->plh_inode)->layout = NULL;
-       pnfs_free_layout_hdr(lo);
+       nfsi->layout = NULL;
+       /* Reset MDS Threshold I/O counters */
+       nfsi->write_io = 0;
+       nfsi->read_io = 0;
+}
+
+void
+pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct inode *inode = lo->plh_inode;
+
+       if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
+               pnfs_detach_layout_hdr(lo);
+               spin_unlock(&inode->i_lock);
+               pnfs_free_layout_hdr(lo);
+       }
+}
+
+static int
+pnfs_iomode_to_fail_bit(u32 iomode)
+{
+       return iomode == IOMODE_RW ?
+               NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
 }
 
 static void
-put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+pnfs_layout_set_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
 {
-       if (atomic_dec_and_test(&lo->plh_refcount))
-               destroy_layout_hdr(lo);
+       lo->plh_retry_timestamp = jiffies;
+       if (test_and_set_bit(fail_bit, &lo->plh_flags))
+               atomic_inc(&lo->plh_refcount);
 }
 
-void
-put_layout_hdr(struct pnfs_layout_hdr *lo)
+static void
+pnfs_layout_clear_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
+{
+       if (test_and_clear_bit(fail_bit, &lo->plh_flags))
+               atomic_dec(&lo->plh_refcount);
+}
+
+static void
+pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
 {
        struct inode *inode = lo->plh_inode;
+       struct pnfs_layout_range range = {
+               .iomode = iomode,
+               .offset = 0,
+               .length = NFS4_MAX_UINT64,
+       };
+       LIST_HEAD(head);
 
-       if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
-               destroy_layout_hdr(lo);
-               spin_unlock(&inode->i_lock);
+       spin_lock(&inode->i_lock);
+       pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
+       pnfs_mark_matching_lsegs_invalid(lo, &head, &range);
+       spin_unlock(&inode->i_lock);
+       pnfs_free_lseg_list(&head);
+       dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
+                       iomode == IOMODE_RW ?  "RW" : "READ");
+}
+
+static bool
+pnfs_layout_io_test_failed(struct pnfs_layout_hdr *lo, u32 iomode)
+{
+       unsigned long start, end;
+       int fail_bit = pnfs_iomode_to_fail_bit(iomode);
+
+       if (test_bit(fail_bit, &lo->plh_flags) == 0)
+               return false;
+       end = jiffies;
+       start = end - PNFS_LAYOUTGET_RETRY_TIMEOUT;
+       if (!time_in_range(lo->plh_retry_timestamp, start, end)) {
+               /* It is time to retry the failed layoutgets */
+               pnfs_layout_clear_fail_bit(lo, fail_bit);
+               return false;
        }
+       return true;
 }
 
 static void
@@ -249,33 +314,32 @@ init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
        lseg->pls_layout = lo;
 }
 
-static void free_lseg(struct pnfs_layout_segment *lseg)
+static void pnfs_free_lseg(struct pnfs_layout_segment *lseg)
 {
        struct inode *ino = lseg->pls_layout->plh_inode;
 
        NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
-       /* Matched by get_layout_hdr in pnfs_insert_layout */
-       put_layout_hdr(NFS_I(ino)->layout);
 }
 
 static void
-put_lseg_common(struct pnfs_layout_segment *lseg)
+pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
+               struct pnfs_layout_segment *lseg)
 {
-       struct inode *inode = lseg->pls_layout->plh_inode;
+       struct inode *inode = lo->plh_inode;
 
        WARN_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
        list_del_init(&lseg->pls_list);
-       if (list_empty(&lseg->pls_layout->plh_segs)) {
-               set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags);
-               /* Matched by initial refcount set in alloc_init_layout_hdr */
-               put_layout_hdr_locked(lseg->pls_layout);
-       }
+       /* Matched by pnfs_get_layout_hdr in pnfs_layout_insert_lseg */
+       atomic_dec(&lo->plh_refcount);
+       if (list_empty(&lo->plh_segs))
+               clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
        rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
 }
 
 void
-put_lseg(struct pnfs_layout_segment *lseg)
+pnfs_put_lseg(struct pnfs_layout_segment *lseg)
 {
+       struct pnfs_layout_hdr *lo;
        struct inode *inode;
 
        if (!lseg)
@@ -284,17 +348,17 @@ put_lseg(struct pnfs_layout_segment *lseg)
        dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg,
                atomic_read(&lseg->pls_refcount),
                test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
-       inode = lseg->pls_layout->plh_inode;
+       lo = lseg->pls_layout;
+       inode = lo->plh_inode;
        if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
-               LIST_HEAD(free_me);
-
-               put_lseg_common(lseg);
-               list_add(&lseg->pls_list, &free_me);
+               pnfs_get_layout_hdr(lo);
+               pnfs_layout_remove_lseg(lo, lseg);
                spin_unlock(&inode->i_lock);
-               pnfs_free_lseg_list(&free_me);
+               pnfs_free_lseg(lseg);
+               pnfs_put_layout_hdr(lo);
        }
 }
-EXPORT_SYMBOL_GPL(put_lseg);
+EXPORT_SYMBOL_GPL(pnfs_put_lseg);
 
 static inline u64
 end_offset(u64 start, u64 len)
@@ -378,7 +442,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
                dprintk("%s: lseg %p ref %d\n", __func__, lseg,
                        atomic_read(&lseg->pls_refcount));
                if (atomic_dec_and_test(&lseg->pls_refcount)) {
-                       put_lseg_common(lseg);
+                       pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
                        list_add(&lseg->pls_list, tmp_list);
                        rv = 1;
                }
@@ -390,7 +454,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
  * after call.
  */
 int
-mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
+pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                            struct list_head *tmp_list,
                            struct pnfs_layout_range *recall_range)
 {
@@ -399,14 +463,8 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
 
        dprintk("%s:Begin lo %p\n", __func__, lo);
 
-       if (list_empty(&lo->plh_segs)) {
-               /* Reset MDS Threshold I/O counters */
-               NFS_I(lo->plh_inode)->write_io = 0;
-               NFS_I(lo->plh_inode)->read_io = 0;
-               if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags))
-                       put_layout_hdr_locked(lo);
+       if (list_empty(&lo->plh_segs))
                return 0;
-       }
        list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
                if (!recall_range ||
                    should_free_lseg(&lseg->pls_range, recall_range)) {
@@ -426,25 +484,13 @@ void
 pnfs_free_lseg_list(struct list_head *free_me)
 {
        struct pnfs_layout_segment *lseg, *tmp;
-       struct pnfs_layout_hdr *lo;
 
        if (list_empty(free_me))
                return;
 
-       lo = list_first_entry(free_me, struct pnfs_layout_segment,
-                             pls_list)->pls_layout;
-
-       if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) {
-               struct nfs_client *clp;
-
-               clp = NFS_SERVER(lo->plh_inode)->nfs_client;
-               spin_lock(&clp->cl_lock);
-               list_del_init(&lo->plh_layouts);
-               spin_unlock(&clp->cl_lock);
-       }
        list_for_each_entry_safe(lseg, tmp, free_me, pls_list) {
                list_del(&lseg->pls_list);
-               free_lseg(lseg);
+               pnfs_free_lseg(lseg);
        }
 }
 
@@ -458,10 +504,15 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
        lo = nfsi->layout;
        if (lo) {
                lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
-               mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
-       }
-       spin_unlock(&nfsi->vfs_inode.i_lock);
-       pnfs_free_lseg_list(&tmp_list);
+               pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+               pnfs_get_layout_hdr(lo);
+               pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED);
+               pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED);
+               spin_unlock(&nfsi->vfs_inode.i_lock);
+               pnfs_free_lseg_list(&tmp_list);
+               pnfs_put_layout_hdr(lo);
+       } else
+               spin_unlock(&nfsi->vfs_inode.i_lock);
 }
 EXPORT_SYMBOL_GPL(pnfs_destroy_layout);
 
@@ -498,46 +549,54 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
        }
 }
 
+/*
+ * Compare 2 layout stateid sequence ids, to see which is newer,
+ * taking into account wraparound issues.
+ */
+static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
+{
+       return (s32)s1 - (s32)s2 > 0;
+}
+
 /* update lo->plh_stateid with new if is more recent */
 void
 pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
                        bool update_barrier)
 {
-       u32 oldseq, newseq;
+       u32 oldseq, newseq, new_barrier;
+       int empty = list_empty(&lo->plh_segs);
 
        oldseq = be32_to_cpu(lo->plh_stateid.seqid);
        newseq = be32_to_cpu(new->seqid);
-       if ((int)(newseq - oldseq) > 0) {
+       if (empty || pnfs_seqid_is_newer(newseq, oldseq)) {
                nfs4_stateid_copy(&lo->plh_stateid, new);
                if (update_barrier) {
-                       u32 new_barrier = be32_to_cpu(new->seqid);
-
-                       if ((int)(new_barrier - lo->plh_barrier))
-                               lo->plh_barrier = new_barrier;
+                       new_barrier = be32_to_cpu(new->seqid);
                } else {
                        /* Because of wraparound, we want to keep the barrier
-                        * "close" to the current seqids.  It needs to be
-                        * within 2**31 to count as "behind", so if it
-                        * gets too near that limit, give us a litle leeway
-                        * and bring it to within 2**30.
-                        * NOTE - and yes, this is all unsigned arithmetic.
+                        * "close" to the current seqids.
                         */
-                       if (unlikely((newseq - lo->plh_barrier) > (3 << 29)))
-                               lo->plh_barrier = newseq - (1 << 30);
+                       new_barrier = newseq - atomic_read(&lo->plh_outstanding);
                }
+               if (empty || pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
+                       lo->plh_barrier = new_barrier;
        }
 }
 
+static bool
+pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
+               const nfs4_stateid *stateid)
+{
+       u32 seqid = be32_to_cpu(stateid->seqid);
+
+       return !pnfs_seqid_is_newer(seqid, lo->plh_barrier);
+}
+
 /* lget is set to 1 if called from inside send_layoutget call chain */
 static bool
-pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
-                       int lget)
+pnfs_layoutgets_blocked(const struct pnfs_layout_hdr *lo, int lget)
 {
-       if ((stateid) &&
-           (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0)
-               return true;
        return lo->plh_block_lgets ||
-               test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
                test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
                (list_empty(&lo->plh_segs) &&
                 (atomic_read(&lo->plh_outstanding) > lget));
@@ -551,7 +610,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
 
        dprintk("--> %s\n", __func__);
        spin_lock(&lo->plh_inode->i_lock);
-       if (pnfs_layoutgets_blocked(lo, NULL, 1)) {
+       if (pnfs_layoutgets_blocked(lo, 1)) {
                status = -EAGAIN;
        } else if (list_empty(&lo->plh_segs)) {
                int seq;
@@ -582,7 +641,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        struct inode *ino = lo->plh_inode;
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs4_layoutget *lgp;
-       struct pnfs_layout_segment *lseg = NULL;
+       struct pnfs_layout_segment *lseg;
 
        dprintk("--> %s\n", __func__);
 
@@ -599,16 +658,22 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
-       lgp->lsegpp = &lseg;
        lgp->gfp_flags = gfp_flags;
 
        /* Synchronously retrieve layout information from server and
         * store in lseg.
         */
-       nfs4_proc_layoutget(lgp, gfp_flags);
-       if (!lseg) {
-               /* remember that LAYOUTGET failed and suspend trying */
-               set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
+       lseg = nfs4_proc_layoutget(lgp, gfp_flags);
+       if (IS_ERR(lseg)) {
+               switch (PTR_ERR(lseg)) {
+               case -ENOMEM:
+               case -ERESTARTSYS:
+                       break;
+               default:
+                       /* remember that LAYOUTGET failed and suspend trying */
+                       pnfs_layout_io_set_failed(lo, range->iomode);
+               }
+               return NULL;
        }
 
        return lseg;
@@ -636,25 +701,24 @@ _pnfs_return_layout(struct inode *ino)
 
        spin_lock(&ino->i_lock);
        lo = nfsi->layout;
-       if (!lo || pnfs_test_layout_returned(lo)) {
+       if (!lo) {
                spin_unlock(&ino->i_lock);
                dprintk("NFS: %s no layout to return\n", __func__);
                goto out;
        }
        stateid = nfsi->layout->plh_stateid;
        /* Reference matched in nfs4_layoutreturn_release */
-       get_layout_hdr(lo);
+       pnfs_get_layout_hdr(lo);
        empty = list_empty(&lo->plh_segs);
-       mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+       pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
        /* Don't send a LAYOUTRETURN if list was initially empty */
        if (empty) {
                spin_unlock(&ino->i_lock);
-               put_layout_hdr(lo);
+               pnfs_put_layout_hdr(lo);
                dprintk("NFS: %s no layout segments to return\n", __func__);
                goto out;
        }
        lo->plh_block_lgets++;
-       pnfs_mark_layout_returned(lo);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
 
@@ -663,10 +727,10 @@ _pnfs_return_layout(struct inode *ino)
        lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
        if (unlikely(lrp == NULL)) {
                status = -ENOMEM;
-               set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags);
-               set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags);
-               pnfs_clear_layout_returned(lo);
-               put_layout_hdr(lo);
+               spin_lock(&ino->i_lock);
+               lo->plh_block_lgets--;
+               spin_unlock(&ino->i_lock);
+               pnfs_put_layout_hdr(lo);
                goto out;
        }
 
@@ -703,7 +767,7 @@ bool pnfs_roc(struct inode *ino)
        if (!found)
                goto out_nolayout;
        lo->plh_block_lgets++;
-       get_layout_hdr(lo); /* matched in pnfs_roc_release */
+       pnfs_get_layout_hdr(lo); /* matched in pnfs_roc_release */
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
        return true;
@@ -720,8 +784,12 @@ void pnfs_roc_release(struct inode *ino)
        spin_lock(&ino->i_lock);
        lo = NFS_I(ino)->layout;
        lo->plh_block_lgets--;
-       put_layout_hdr_locked(lo);
-       spin_unlock(&ino->i_lock);
+       if (atomic_dec_and_test(&lo->plh_refcount)) {
+               pnfs_detach_layout_hdr(lo);
+               spin_unlock(&ino->i_lock);
+               pnfs_free_layout_hdr(lo);
+       } else
+               spin_unlock(&ino->i_lock);
 }
 
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
@@ -730,32 +798,34 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
 
        spin_lock(&ino->i_lock);
        lo = NFS_I(ino)->layout;
-       if ((int)(barrier - lo->plh_barrier) > 0)
+       if (pnfs_seqid_is_newer(barrier, lo->plh_barrier))
                lo->plh_barrier = barrier;
        spin_unlock(&ino->i_lock);
 }
 
-bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
+bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
+       struct pnfs_layout_hdr *lo;
        struct pnfs_layout_segment *lseg;
+       u32 current_seqid;
        bool found = false;
 
        spin_lock(&ino->i_lock);
        list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
                if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
+                       rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
                        found = true;
-                       break;
+                       goto out;
                }
-       if (!found) {
-               struct pnfs_layout_hdr *lo = nfsi->layout;
-               u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
+       lo = nfsi->layout;
+       current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 
-               /* Since close does not return a layout stateid for use as
-                * a barrier, we choose the worst-case barrier.
-                */
-               *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
-       }
+       /* Since close does not return a layout stateid for use as
+        * a barrier, we choose the worst-case barrier.
+        */
+       *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
+out:
        spin_unlock(&ino->i_lock);
        return found;
 }
@@ -786,14 +856,13 @@ cmp_layout(struct pnfs_layout_range *l1,
 }
 
 static void
-pnfs_insert_layout(struct pnfs_layout_hdr *lo,
+pnfs_layout_insert_lseg(struct pnfs_layout_hdr *lo,
                   struct pnfs_layout_segment *lseg)
 {
        struct pnfs_layout_segment *lp;
 
        dprintk("%s:Begin\n", __func__);
 
-       assert_spin_locked(&lo->plh_inode->i_lock);
        list_for_each_entry(lp, &lo->plh_segs, pls_list) {
                if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0)
                        continue;
@@ -813,7 +882,7 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
                __func__, lseg, lseg->pls_range.iomode,
                lseg->pls_range.offset, lseg->pls_range.length);
 out:
-       get_layout_hdr(lo);
+       pnfs_get_layout_hdr(lo);
 
        dprintk("%s:Return\n", __func__);
 }
@@ -847,21 +916,19 @@ pnfs_find_alloc_layout(struct inode *ino,
 
        dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
 
-       assert_spin_locked(&ino->i_lock);
-       if (nfsi->layout) {
-               if (test_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags))
-                       return NULL;
-               else
-                       return nfsi->layout;
-       }
+       if (nfsi->layout != NULL)
+               goto out_existing;
        spin_unlock(&ino->i_lock);
        new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
        spin_lock(&ino->i_lock);
 
-       if (likely(nfsi->layout == NULL))       /* Won the race? */
+       if (likely(nfsi->layout == NULL)) {     /* Won the race? */
                nfsi->layout = new;
-       else
-               pnfs_free_layout_hdr(new);
+               return new;
+       }
+       pnfs_free_layout_hdr(new);
+out_existing:
+       pnfs_get_layout_hdr(nfsi->layout);
        return nfsi->layout;
 }
 
@@ -904,11 +971,10 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo,
 
        dprintk("%s:Begin\n", __func__);
 
-       assert_spin_locked(&lo->plh_inode->i_lock);
        list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
                if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
                    is_matching_lseg(&lseg->pls_range, range)) {
-                       ret = get_lseg(lseg);
+                       ret = pnfs_get_lseg(lseg);
                        break;
                }
                if (lseg->pls_range.offset > range->offset)
@@ -1013,7 +1079,6 @@ pnfs_update_layout(struct inode *ino,
                .length = count,
        };
        unsigned pg_offset;
-       struct nfs_inode *nfsi = NFS_I(ino);
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs_client *clp = server->nfs_client;
        struct pnfs_layout_hdr *lo;
@@ -1021,16 +1086,16 @@ pnfs_update_layout(struct inode *ino,
        bool first = false;
 
        if (!pnfs_enabled_sb(NFS_SERVER(ino)))
-               return NULL;
+               goto out;
 
        if (pnfs_within_mdsthreshold(ctx, ino, iomode))
-               return NULL;
+               goto out;
 
        spin_lock(&ino->i_lock);
        lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
        if (lo == NULL) {
-               dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
-               goto out_unlock;
+               spin_unlock(&ino->i_lock);
+               goto out;
        }
 
        /* Do we even need to bother with this? */
@@ -1040,7 +1105,7 @@ pnfs_update_layout(struct inode *ino,
        }
 
        /* if LAYOUTGET already failed once we don't try again */
-       if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags))
+       if (pnfs_layout_io_test_failed(lo, iomode))
                goto out_unlock;
 
        /* Check to see if the layout for the given range already exists */
@@ -1048,17 +1113,13 @@ pnfs_update_layout(struct inode *ino,
        if (lseg)
                goto out_unlock;
 
-       if (pnfs_layoutgets_blocked(lo, NULL, 0))
+       if (pnfs_layoutgets_blocked(lo, 0))
                goto out_unlock;
        atomic_inc(&lo->plh_outstanding);
 
-       get_layout_hdr(lo);
        if (list_empty(&lo->plh_segs))
                first = true;
 
-       /* Enable LAYOUTRETURNs */
-       pnfs_clear_layout_returned(lo);
-
        spin_unlock(&ino->i_lock);
        if (first) {
                /* The lo must be on the clp list if there is any
@@ -1079,24 +1140,26 @@ pnfs_update_layout(struct inode *ino,
                arg.length = PAGE_CACHE_ALIGN(arg.length);
 
        lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
-       if (!lseg && first) {
-               spin_lock(&clp->cl_lock);
-               list_del_init(&lo->plh_layouts);
-               spin_unlock(&clp->cl_lock);
-       }
        atomic_dec(&lo->plh_outstanding);
-       put_layout_hdr(lo);
+out_put_layout_hdr:
+       pnfs_put_layout_hdr(lo);
 out:
-       dprintk("%s end, state 0x%lx lseg %p\n", __func__,
-               nfsi->layout ? nfsi->layout->plh_flags : -1, lseg);
+       dprintk("%s: inode %s/%llu pNFS layout segment %s for "
+                       "(%s, offset: %llu, length: %llu)\n",
+                       __func__, ino->i_sb->s_id,
+                       (unsigned long long)NFS_FILEID(ino),
+                       lseg == NULL ? "not found" : "found",
+                       iomode==IOMODE_RW ?  "read/write" : "read-only",
+                       (unsigned long long)pos,
+                       (unsigned long long)count);
        return lseg;
 out_unlock:
        spin_unlock(&ino->i_lock);
-       goto out;
+       goto out_put_layout_hdr;
 }
 EXPORT_SYMBOL_GPL(pnfs_update_layout);
 
-int
+struct pnfs_layout_segment *
 pnfs_layout_process(struct nfs4_layoutget *lgp)
 {
        struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout;
@@ -1123,25 +1186,29 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                goto out_forget_reply;
        }
 
-       if (pnfs_layoutgets_blocked(lo, &res->stateid, 1)) {
+       if (pnfs_layoutgets_blocked(lo, 1) ||
+           pnfs_layout_stateid_blocked(lo, &res->stateid)) {
                dprintk("%s forget reply due to state\n", __func__);
                goto out_forget_reply;
        }
+
+       /* Done processing layoutget. Set the layout stateid */
+       pnfs_set_layout_stateid(lo, &res->stateid, false);
+
        init_lseg(lo, lseg);
        lseg->pls_range = res->range;
-       *lgp->lsegpp = get_lseg(lseg);
-       pnfs_insert_layout(lo, lseg);
+       pnfs_get_lseg(lseg);
+       pnfs_layout_insert_lseg(lo, lseg);
 
        if (res->return_on_close) {
                set_bit(NFS_LSEG_ROC, &lseg->pls_flags);
                set_bit(NFS_LAYOUT_ROC, &lo->plh_flags);
        }
 
-       /* Done processing layoutget. Set the layout stateid */
-       pnfs_set_layout_stateid(lo, &res->stateid, false);
        spin_unlock(&ino->i_lock);
+       return lseg;
 out:
-       return status;
+       return ERR_PTR(status);
 
 out_forget_reply:
        spin_unlock(&ino->i_lock);
@@ -1153,16 +1220,24 @@ out_forget_reply:
 void
 pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
 {
+       u64 rd_size = req->wb_bytes;
+
        BUG_ON(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                nfs_pageio_reset_read_mds(pgio);
                return;
        }
+
+       if (pgio->pg_dreq == NULL)
+               rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
+       else
+               rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
        pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                           req->wb_context,
                                           req_offset(req),
-                                          req->wb_bytes,
+                                          rd_size,
                                           IOMODE_READ,
                                           GFP_KERNEL);
        /* If no lseg, fall back to read through mds */
@@ -1173,7 +1248,8 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
 
 void
-pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
+                          struct nfs_page *req, u64 wb_size)
 {
        BUG_ON(pgio->pg_lseg != NULL);
 
@@ -1181,10 +1257,11 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *
                nfs_pageio_reset_write_mds(pgio);
                return;
        }
+
        pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                           req->wb_context,
                                           req_offset(req),
-                                          req->wb_bytes,
+                                          wb_size,
                                           IOMODE_RW,
                                           GFP_NOFS);
        /* If no lseg, fall back to write through mds */
@@ -1362,12 +1439,12 @@ pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *he
                if (trypnfs == PNFS_NOT_ATTEMPTED)
                        pnfs_write_through_mds(desc, data);
        }
-       put_lseg(lseg);
+       pnfs_put_lseg(lseg);
 }
 
 static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
 {
-       put_lseg(hdr->lseg);
+       pnfs_put_lseg(hdr->lseg);
        nfs_writehdr_free(hdr);
 }
 EXPORT_SYMBOL_GPL(pnfs_writehdr_free);
@@ -1382,17 +1459,17 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
        whdr = nfs_writehdr_alloc();
        if (!whdr) {
                desc->pg_completion_ops->error_cleanup(&desc->pg_list);
-               put_lseg(desc->pg_lseg);
+               pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
                return -ENOMEM;
        }
        hdr = &whdr->header;
        nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
-       hdr->lseg = get_lseg(desc->pg_lseg);
+       hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
        atomic_inc(&hdr->refcnt);
        ret = nfs_generic_flush(desc, hdr);
        if (ret != 0) {
-               put_lseg(desc->pg_lseg);
+               pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
        } else
                pnfs_do_multiple_writes(desc, &hdr->rpc_list, desc->pg_ioflags);
@@ -1517,12 +1594,12 @@ pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *hea
                if (trypnfs == PNFS_NOT_ATTEMPTED)
                        pnfs_read_through_mds(desc, data);
        }
-       put_lseg(lseg);
+       pnfs_put_lseg(lseg);
 }
 
 static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
 {
-       put_lseg(hdr->lseg);
+       pnfs_put_lseg(hdr->lseg);
        nfs_readhdr_free(hdr);
 }
 EXPORT_SYMBOL_GPL(pnfs_readhdr_free);
@@ -1538,17 +1615,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
        if (!rhdr) {
                desc->pg_completion_ops->error_cleanup(&desc->pg_list);
                ret = -ENOMEM;
-               put_lseg(desc->pg_lseg);
+               pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
                return ret;
        }
        hdr = &rhdr->header;
        nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
-       hdr->lseg = get_lseg(desc->pg_lseg);
+       hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
        atomic_inc(&hdr->refcnt);
        ret = nfs_generic_pagein(desc, hdr);
        if (ret != 0) {
-               put_lseg(desc->pg_lseg);
+               pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
        } else
                pnfs_do_multiple_reads(desc, &hdr->rpc_list);
@@ -1574,13 +1651,7 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
 
 void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
 {
-       if (lseg->pls_range.iomode == IOMODE_RW) {
-               dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
-               set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
-       } else {
-               dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
-               set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
-       }
+       pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode);
 }
 EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
 
@@ -1601,7 +1672,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
        }
        if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &hdr->lseg->pls_flags)) {
                /* references matched in nfs4_layoutcommit_release */
-               get_lseg(hdr->lseg);
+               pnfs_get_lseg(hdr->lseg);
        }
        if (end_pos > nfsi->layout->plh_lwb)
                nfsi->layout->plh_lwb = end_pos;
index 745aa1b..2d722db 100644 (file)
@@ -62,9 +62,6 @@ enum {
        NFS_LAYOUT_RW_FAILED,           /* get rw layout failed stop trying */
        NFS_LAYOUT_BULK_RECALL,         /* bulk recall affecting layout */
        NFS_LAYOUT_ROC,                 /* some lseg had roc bit set */
-       NFS_LAYOUT_DESTROYED,           /* no new use of layout allowed */
-       NFS_LAYOUT_INVALID,             /* layout is being destroyed */
-       NFS_LAYOUT_RETURNED,            /* layout has already been returned */
 };
 
 enum layoutdriver_policy_flags {
@@ -140,6 +137,7 @@ struct pnfs_layout_hdr {
        atomic_t                plh_outstanding; /* number of RPCs out */
        unsigned long           plh_block_lgets; /* block LAYOUTGET if >0 */
        u32                     plh_barrier; /* ignore lower seqids */
+       unsigned long           plh_retry_timestamp;
        unsigned long           plh_flags;
        loff_t                  plh_lwb; /* last write byte for layoutcommit */
        struct rpc_cred         *plh_lc_cred; /* layoutcommit cred */
@@ -172,12 +170,12 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server,
                                   struct pnfs_devicelist *devlist);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
-extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
+extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
 extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 
 /* pnfs.c */
-void get_layout_hdr(struct pnfs_layout_hdr *lo);
-void put_lseg(struct pnfs_layout_segment *lseg);
+void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo);
+void pnfs_put_lseg(struct pnfs_layout_segment *lseg);
 
 void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *,
                           const struct nfs_pgio_completion_ops *);
@@ -188,28 +186,29 @@ void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
 void unset_pnfs_layoutdriver(struct nfs_server *);
 void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
 int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
-void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *, struct nfs_page *);
+void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
+                               struct nfs_page *req, u64 wb_size);
 int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
 bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req);
 void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg);
-int pnfs_layout_process(struct nfs4_layoutget *lgp);
+struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp);
 void pnfs_free_lseg_list(struct list_head *tmp_list);
 void pnfs_destroy_layout(struct nfs_inode *);
 void pnfs_destroy_all_layouts(struct nfs_client *);
-void put_layout_hdr(struct pnfs_layout_hdr *lo);
+void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo);
 void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
                             const nfs4_stateid *new,
                             bool update_barrier);
 int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
                                  struct pnfs_layout_hdr *lo,
                                  struct nfs4_state *open_state);
-int mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
+int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                                struct list_head *tmp_list,
                                struct pnfs_layout_range *recall_range);
 bool pnfs_roc(struct inode *ino);
 void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
-bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
+bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task);
 void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
 void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
 int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
@@ -233,6 +232,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);
 /* nfs4_deviceid_flags */
 enum {
        NFS_DEVICEID_INVALID = 0,       /* set when MDS clientid recalled */
+       NFS_DEVICEID_UNAVAILABLE,       /* device temporarily unavailable */
 };
 
 /* pnfs_dev.c */
@@ -242,6 +242,7 @@ struct nfs4_deviceid_node {
        const struct pnfs_layoutdriver_type *ld;
        const struct nfs_client         *nfs_client;
        unsigned long                   flags;
+       unsigned long                   timestamp_unavailable;
        struct nfs4_deviceid            deviceid;
        atomic_t                        ref;
 };
@@ -254,34 +255,12 @@ void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
                             const struct nfs4_deviceid *);
 struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *);
 bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *);
+void nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node);
+bool nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node);
 void nfs4_deviceid_purge_client(const struct nfs_client *);
 
-static inline void
-pnfs_mark_layout_returned(struct pnfs_layout_hdr *lo)
-{
-       set_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline void
-pnfs_clear_layout_returned(struct pnfs_layout_hdr *lo)
-{
-       clear_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline bool
-pnfs_test_layout_returned(struct pnfs_layout_hdr *lo)
-{
-       return test_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline int lo_fail_bit(u32 iomode)
-{
-       return iomode == IOMODE_RW ?
-                        NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
-}
-
 static inline struct pnfs_layout_segment *
-get_lseg(struct pnfs_layout_segment *lseg)
+pnfs_get_lseg(struct pnfs_layout_segment *lseg)
 {
        if (lseg) {
                atomic_inc(&lseg->pls_refcount);
@@ -406,12 +385,12 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
 }
 
 static inline struct pnfs_layout_segment *
-get_lseg(struct pnfs_layout_segment *lseg)
+pnfs_get_lseg(struct pnfs_layout_segment *lseg)
 {
        return NULL;
 }
 
-static inline void put_lseg(struct pnfs_layout_segment *lseg)
+static inline void pnfs_put_lseg(struct pnfs_layout_segment *lseg)
 {
 }
 
@@ -443,7 +422,7 @@ pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
 }
 
 static inline bool
-pnfs_roc_drain(struct inode *ino, u32 *barrier)
+pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
 {
        return false;
 }
index 73f701f..d35b62e 100644 (file)
@@ -40,6 +40,8 @@
 #define NFS4_DEVICE_ID_HASH_SIZE       (1 << NFS4_DEVICE_ID_HASH_BITS)
 #define NFS4_DEVICE_ID_HASH_MASK       (NFS4_DEVICE_ID_HASH_SIZE - 1)
 
+#define PNFS_DEVICE_RETRY_TIMEOUT (120*HZ)
+
 static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
 static DEFINE_SPINLOCK(nfs4_deviceid_lock);
 
@@ -218,6 +220,30 @@ nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
 }
 EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);
 
+void
+nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node)
+{
+       node->timestamp_unavailable = jiffies;
+       set_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
+}
+EXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable);
+
+bool
+nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node)
+{
+       if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
+               unsigned long start, end;
+
+               end = jiffies;
+               start = end - PNFS_DEVICE_RETRY_TIMEOUT;
+               if (time_in_range(node->timestamp_unavailable, start, end))
+                       return true;
+               clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
+       }
+       return false;
+}
+EXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable);
+
 static void
 _deviceid_purge_client(const struct nfs_client *clp, long hash)
 {
@@ -276,3 +302,4 @@ nfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
        }
        rcu_read_unlock();
 }
+
index d2c7f5d..e831bce 100644 (file)
@@ -88,6 +88,7 @@ enum {
        Opt_sharecache, Opt_nosharecache,
        Opt_resvport, Opt_noresvport,
        Opt_fscache, Opt_nofscache,
+       Opt_migration, Opt_nomigration,
 
        /* Mount options that take integer arguments */
        Opt_port,
@@ -147,6 +148,8 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_noresvport, "noresvport" },
        { Opt_fscache, "fsc" },
        { Opt_nofscache, "nofsc" },
+       { Opt_migration, "migration" },
+       { Opt_nomigration, "nomigration" },
 
        { Opt_port, "port=%s" },
        { Opt_rsize, "rsize=%s" },
@@ -676,6 +679,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        if (nfss->options & NFS_OPTION_FSCACHE)
                seq_printf(m, ",fsc");
 
+       if (nfss->options & NFS_OPTION_MIGRATION)
+               seq_printf(m, ",migration");
+
        if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) {
                if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
                        seq_printf(m, ",lookupcache=none");
@@ -1106,7 +1112,7 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option)
        string = match_strdup(args);
        if (string == NULL)
                return -ENOMEM;
-       rc = strict_strtoul(string, 10, option);
+       rc = kstrtoul(string, 10, option);
        kfree(string);
 
        return rc;
@@ -1243,6 +1249,12 @@ static int nfs_parse_mount_options(char *raw,
                        kfree(mnt->fscache_uniq);
                        mnt->fscache_uniq = NULL;
                        break;
+               case Opt_migration:
+                       mnt->options |= NFS_OPTION_MIGRATION;
+                       break;
+               case Opt_nomigration:
+                       mnt->options &= NFS_OPTION_MIGRATION;
+                       break;
 
                /*
                 * options that take numeric values
@@ -1535,6 +1547,10 @@ static int nfs_parse_mount_options(char *raw,
        if (mnt->minorversion && mnt->version != 4)
                goto out_minorversion_mismatch;
 
+       if (mnt->options & NFS_OPTION_MIGRATION &&
+           mnt->version != 4 && mnt->minorversion != 0)
+               goto out_migration_misuse;
+
        /*
         * verify that any proto=/mountproto= options match the address
         * families in the addr=/mountaddr= options.
@@ -1572,6 +1588,10 @@ out_minorversion_mismatch:
        printk(KERN_INFO "NFS: mount option vers=%u does not support "
                         "minorversion=%u\n", mnt->version, mnt->minorversion);
        return 0;
+out_migration_misuse:
+       printk(KERN_INFO
+               "NFS: 'migration' not supported for this NFS version\n");
+       return 0;
 out_nomem:
        printk(KERN_INFO "NFS: not enough memory to parse option\n");
        return 0;
@@ -2494,7 +2514,7 @@ EXPORT_SYMBOL_GPL(nfs_kill_super);
 /*
  * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
  */
-struct dentry *
+static struct dentry *
 nfs_xdev_mount(struct file_system_type *fs_type, int flags,
                const char *dev_name, void *raw_data)
 {
@@ -2642,6 +2662,7 @@ unsigned int nfs_idmap_cache_timeout = 600;
 bool nfs4_disable_idmapping = true;
 unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
 unsigned short send_implementation_id = 1;
+char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
 
 EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
 EXPORT_SYMBOL_GPL(nfs_callback_tcpport);
@@ -2649,6 +2670,7 @@ EXPORT_SYMBOL_GPL(nfs_idmap_cache_timeout);
 EXPORT_SYMBOL_GPL(nfs4_disable_idmapping);
 EXPORT_SYMBOL_GPL(max_session_slots);
 EXPORT_SYMBOL_GPL(send_implementation_id);
+EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
 
 #define NFS_CALLBACK_MAXPORTNR (65535U)
 
@@ -2659,7 +2681,7 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
 
        if (!val)
                return -EINVAL;
-       ret = strict_strtoul(val, 0, &num);
+       ret = kstrtoul(val, 0, &num);
        if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR)
                return -EINVAL;
        *((unsigned int *)kp->arg) = num;
@@ -2674,6 +2696,8 @@ static struct kernel_param_ops param_ops_portnr = {
 module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
 module_param(nfs_idmap_cache_timeout, int, 0644);
 module_param(nfs4_disable_idmapping, bool, 0644);
+module_param_string(nfs4_unique_id, nfs4_client_id_uniquifier,
+                       NFS4_CLIENT_ID_UNIQ_LEN, 0600);
 MODULE_PARM_DESC(nfs4_disable_idmapping,
                "Turn off NFSv4 idmapping when using 'sec=sys'");
 module_param(max_session_slots, ushort, 0644);
@@ -2682,6 +2706,7 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
 module_param(send_implementation_id, ushort, 0644);
 MODULE_PARM_DESC(send_implementation_id,
                "Send implementation ID with NFSv4.1 exchange_id");
+MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string");
 MODULE_ALIAS("nfs4");
 
 #endif /* CONFIG_NFS_V4 */
index e3b5537..9347ab7 100644 (file)
@@ -846,6 +846,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
 int nfs_flush_incompatible(struct file *file, struct page *page)
 {
        struct nfs_open_context *ctx = nfs_file_open_context(file);
+       struct nfs_lock_context *l_ctx;
        struct nfs_page *req;
        int do_flush, status;
        /*
@@ -860,9 +861,12 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
                req = nfs_page_find_request(page);
                if (req == NULL)
                        return 0;
-               do_flush = req->wb_page != page || req->wb_context != ctx ||
-                       req->wb_lock_context->lockowner != current->files ||
-                       req->wb_lock_context->pid != current->tgid;
+               l_ctx = req->wb_lock_context;
+               do_flush = req->wb_page != page || req->wb_context != ctx;
+               if (l_ctx) {
+                       do_flush |= l_ctx->lockowner.l_owner != current->files
+                               || l_ctx->lockowner.l_pid != current->tgid;
+               }
                nfs_release_request(req);
                if (!do_flush)
                        return 0;
@@ -1576,6 +1580,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                /* We have a mismatch. Write the page again */
                dprintk(" mismatch\n");
                nfs_mark_request_dirty(req);
+               set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
        next:
                nfs_unlock_and_release_request(req);
        }
index 2694289..727877f 100644 (file)
@@ -26,6 +26,7 @@
 /* See Documentation/leds/leds-lp5523.txt */
 
 struct lp5523_led_config {
+       const char      *name;
        u8              chan_nr;
        u8              led_current; /* mA x10, 0 if led is not connected */
        u8              max_current;
index c6f8dad..6e53bb3 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/timer.h>
+#include <linux/workqueue.h>
 
 struct device;
 /*
@@ -69,6 +70,9 @@ struct led_classdev {
        struct timer_list        blink_timer;
        int                      blink_brightness;
 
+       struct work_struct      set_brightness_work;
+       int                     delayed_set_value;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore      trigger_lock;
index 4b03f56..334a2f5 100644 (file)
@@ -81,12 +81,16 @@ struct nfs_access_entry {
        int                     mask;
 };
 
+struct nfs_lockowner {
+       fl_owner_t l_owner;
+       pid_t l_pid;
+};
+
 struct nfs_lock_context {
        atomic_t count;
        struct list_head list;
        struct nfs_open_context *open_context;
-       fl_owner_t lockowner;
-       pid_t pid;
+       struct nfs_lockowner lockowner;
 };
 
 struct nfs4_state;
@@ -99,6 +103,7 @@ struct nfs_open_context {
 
        unsigned long flags;
 #define NFS_CONTEXT_ERROR_WRITE                (0)
+#define NFS_CONTEXT_RESEND_WRITES      (1)
        int error;
 
        struct list_head list;
@@ -355,6 +360,8 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
+extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
 extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
index 310c63c..a9e76ee 100644 (file)
@@ -39,6 +39,7 @@ struct nfs_client {
        unsigned long           cl_flags;       /* behavior switches */
 #define NFS_CS_NORESVPORT      0               /* - use ephemeral src port */
 #define NFS_CS_DISCRTRY                1               /* - disconnect on RPC retry */
+#define NFS_CS_MIGRATION       2               /* - transparent state migr */
        struct sockaddr_storage cl_addr;        /* server identifier */
        size_t                  cl_addrlen;
        char *                  cl_hostname;    /* hostname of server */
@@ -81,6 +82,7 @@ struct nfs_client {
        /* The flags used for obtaining the clientid during EXCHANGE_ID */
        u32                     cl_exchange_flags;
        struct nfs4_session     *cl_session;    /* shared session */
+       bool                    cl_preserve_clid;
        struct nfs41_server_owner *cl_serverowner;
        struct nfs41_server_scope *cl_serverscope;
        struct nfs41_impl_id    *cl_implid;
@@ -125,6 +127,7 @@ struct nfs_server {
        unsigned int            namelen;
        unsigned int            options;        /* extra options enabled by mount */
 #define NFS_OPTION_FSCACHE     0x00000001      /* - local caching enabled */
+#define NFS_OPTION_MIGRATION   0x00000002      /* - NFSv4 migration enabled */
 
        struct nfs_fsid         fsid;
        __u64                   maxfilesize;    /* maximum file size */
index be9cf3c..a73ea89 100644 (file)
@@ -251,7 +251,6 @@ struct nfs4_layoutget_res {
 struct nfs4_layoutget {
        struct nfs4_layoutget_args args;
        struct nfs4_layoutget_res res;
-       struct pnfs_layout_segment **lsegpp;
        gfp_t gfp_flags;
 };
 
@@ -335,6 +334,7 @@ struct nfs_openargs {
        struct nfs_seqid *      seqid;
        int                     open_flags;
        fmode_t                 fmode;
+       u32                     access;
        __u64                   clientid;
        struct stateowner_id    id;
        union {
@@ -369,6 +369,9 @@ struct nfs_openres {
        struct nfs4_string      *owner;
        struct nfs4_string      *group_owner;
        struct nfs4_sequence_res        seq_res;
+       __u32                   access_request;
+       __u32                   access_supported;
+       __u32                   access_result;
 };
 
 /*
diff --git a/include/linux/platform_data/leds-lm3556.h b/include/linux/platform_data/leds-lm3556.h
deleted file mode 100644 (file)
index 4b4e7d6..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
- * Copyright (C) 2012 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef __LINUX_LM3556_H
-#define __LINUX_LM3556_H
-
-#define LM3556_NAME "leds-lm3556"
-
-enum lm3556_pin_polarity {
-       PIN_LOW_ACTIVE = 0,
-       PIN_HIGH_ACTIVE,
-};
-
-enum lm3556_pin_enable {
-       PIN_DISABLED = 0,
-       PIN_ENABLED,
-};
-
-enum lm3556_strobe_usuage {
-       STROBE_EDGE_DETECT = 0,
-       STROBE_LEVEL_DETECT,
-};
-
-enum lm3556_indic_mode {
-       INDIC_MODE_INTERNAL = 0,
-       INDIC_MODE_EXTERNAL,
-};
-
-struct lm3556_platform_data {
-       enum lm3556_pin_enable torch_pin_en;
-       enum lm3556_pin_polarity torch_pin_polarity;
-
-       enum lm3556_strobe_usuage strobe_usuage;
-       enum lm3556_pin_enable strobe_pin_en;
-       enum lm3556_pin_polarity strobe_pin_polarity;
-
-       enum lm3556_pin_enable tx_pin_en;
-       enum lm3556_pin_polarity tx_pin_polarity;
-
-       enum lm3556_indic_mode indicator_mode;
-};
-
-#endif /* __LINUX_LM3556_H */
diff --git a/include/linux/platform_data/leds-lm355x.h b/include/linux/platform_data/leds-lm355x.h
new file mode 100644 (file)
index 0000000..b88724b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Simple driver for Texas Instruments LM355x LED driver chip
+ *
+ * Author: G.Shark Jeong <gshark.jeong@gmail.com>
+ *         Daniel Jeong <daniel.jeong@ti.com>
+ */
+
+#define LM355x_NAME "leds-lm355x"
+#define LM3554_NAME "leds-lm3554"
+#define LM3556_NAME "leds-lm3556"
+
+/* lm3554 : strobe def. on */
+enum lm355x_strobe {
+       LM355x_PIN_STROBE_DISABLE = 0x00,
+       LM355x_PIN_STROBE_ENABLE = 0x01,
+};
+
+enum lm355x_torch {
+       LM355x_PIN_TORCH_DISABLE = 0,
+       LM3554_PIN_TORCH_ENABLE = 0x80,
+       LM3556_PIN_TORCH_ENABLE = 0x10,
+};
+
+enum lm355x_tx2 {
+       LM355x_PIN_TX_DISABLE = 0,
+       LM3554_PIN_TX_ENABLE = 0x20,
+       LM3556_PIN_TX_ENABLE = 0x40,
+};
+
+enum lm355x_ntc {
+       LM355x_PIN_NTC_DISABLE = 0,
+       LM3554_PIN_NTC_ENABLE = 0x08,
+       LM3556_PIN_NTC_ENABLE = 0x80,
+};
+
+enum lm355x_pmode {
+       LM355x_PMODE_DISABLE = 0,
+       LM355x_PMODE_ENABLE = 0x04,
+};
+
+/*
+ * struct lm3554_platform_data
+ * @pin_strobe: strobe input
+ * @pin_torch : input pin
+ *              lm3554-tx1/torch/gpio1
+ *              lm3556-torch
+ * @pin_tx2   : input pin
+ *              lm3554-envm/tx2/gpio2
+ *              lm3556-tx pin
+ * @ntc_pin  : output pin
+ *              lm3554-ledi/ntc
+ *              lm3556-temp pin
+ * @pass_mode : pass mode
+ */
+struct lm355x_platform_data {
+       enum lm355x_strobe pin_strobe;
+       enum lm355x_torch pin_tx1;
+       enum lm355x_tx2 pin_tx2;
+       enum lm355x_ntc ntc_pin;
+
+       enum lm355x_pmode pass_mode;
+};
diff --git a/include/linux/platform_data/leds-lm3642.h b/include/linux/platform_data/leds-lm3642.h
new file mode 100644 (file)
index 0000000..72d6ee6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+* Copyright (C) 2012 Texas Instruments
+*
+* License Terms: GNU General Public License v2
+*
+* Simple driver for Texas Instruments LM3642 LED driver chip
+*
+* Author: G.Shark Jeong <gshark.jeong@gmail.com>
+*         Daniel Jeong <daniel.jeong@ti.com>
+*/
+
+#ifndef __LINUX_LM3642_H
+#define __LINUX_LM3642_H
+
+#define LM3642_NAME "leds-lm3642"
+
+enum lm3642_torch_pin_enable {
+       LM3642_TORCH_PIN_DISABLE = 0x00,
+       LM3642_TORCH_PIN_ENABLE = 0x10,
+};
+
+enum lm3642_strobe_pin_enable {
+       LM3642_STROBE_PIN_DISABLE = 0x00,
+       LM3642_STROBE_PIN_ENABLE = 0x20,
+};
+
+enum lm3642_tx_pin_enable {
+       LM3642_TX_PIN_DISABLE = 0x00,
+       LM3642_TX_PIN_ENABLE = 0x40,
+};
+
+struct lm3642_platform_data {
+       enum lm3642_torch_pin_enable torch_pin;
+       enum lm3642_strobe_pin_enable strobe_pin;
+       enum lm3642_tx_pin_enable tx_pin;
+};
+
+#endif /* __LINUX_LM3642_H */
diff --git a/include/linux/platform_data/leds-pca9633.h b/include/linux/platform_data/leds-pca9633.h
new file mode 100644 (file)
index 0000000..c5bf29b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * PCA9633 LED chip driver.
+ *
+ * Copyright 2012 bct electronic GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __LINUX_PCA9633_H
+#define __LINUX_PCA9633_H
+#include <linux/leds.h>
+
+enum pca9633_outdrv {
+       PCA9633_OPEN_DRAIN,
+       PCA9633_TOTEM_POLE, /* aka push-pull */
+};
+
+struct pca9633_platform_data {
+       struct led_platform_data leds;
+       enum pca9633_outdrv outdrv;
+};
+
+#endif /* __LINUX_PCA9633_H*/
index 21d076c..112b314 100644 (file)
@@ -1,11 +1,13 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/err.h>
 #include <linux/of.h>
 
 struct pwm_device;
 struct seq_file;
 
+#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM)
 /*
  * pwm_request - request a PWM device
  */
@@ -30,10 +32,47 @@ int pwm_enable(struct pwm_device *pwm);
  * pwm_disable - stop a PWM output toggling
  */
 void pwm_disable(struct pwm_device *pwm);
+#else
+static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_free(struct pwm_device *pwm)
+{
+}
+
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       return -EINVAL;
+}
+
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+       return -EINVAL;
+}
+
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+}
+#endif
 
-#ifdef CONFIG_PWM
 struct pwm_chip;
 
+/**
+ * enum pwm_polarity - polarity of a PWM signal
+ * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty-
+ * cycle, followed by a low signal for the remainder of the pulse
+ * period
+ * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty-
+ * cycle, followed by a high signal for the remainder of the pulse
+ * period
+ */
+enum pwm_polarity {
+       PWM_POLARITY_NORMAL,
+       PWM_POLARITY_INVERSED,
+};
+
 enum {
        PWMF_REQUESTED = 1 << 0,
        PWMF_ENABLED = 1 << 1,
@@ -61,11 +100,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
        return pwm ? pwm->period : 0;
 }
 
+/*
+ * pwm_set_polarity - configure the polarity of a PWM signal
+ */
+int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
+
 /**
  * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
  * @config: configure duty cycles and period length for this PWM
+ * @set_polarity: configure the polarity of this PWM
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
  * @dbg_show: optional routine to show contents in debugfs
@@ -79,6 +124,9 @@ struct pwm_ops {
        int                     (*config)(struct pwm_chip *chip,
                                          struct pwm_device *pwm,
                                          int duty_ns, int period_ns);
+       int                     (*set_polarity)(struct pwm_chip *chip,
+                                         struct pwm_device *pwm,
+                                         enum pwm_polarity polarity);
        int                     (*enable)(struct pwm_chip *chip,
                                          struct pwm_device *pwm);
        void                    (*disable)(struct pwm_chip *chip,
@@ -113,6 +161,7 @@ struct pwm_chip {
        unsigned int            of_pwm_n_cells;
 };
 
+#if IS_ENABLED(CONFIG_PWM)
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
 void *pwm_get_chip_data(struct pwm_device *pwm);
 
@@ -125,6 +174,57 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
 struct pwm_device *pwm_get(struct device *dev, const char *consumer);
 void pwm_put(struct pwm_device *pwm);
 
+struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer);
+void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
+#else
+static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
+{
+       return -EINVAL;
+}
+
+static inline void *pwm_get_chip_data(struct pwm_device *pwm)
+{
+       return NULL;
+}
+
+static inline int pwmchip_add(struct pwm_chip *chip)
+{
+       return -EINVAL;
+}
+
+static inline int pwmchip_remove(struct pwm_chip *chip)
+{
+       return -EINVAL;
+}
+
+static inline struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
+                                                      unsigned int index,
+                                                      const char *label)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline struct pwm_device *pwm_get(struct device *dev,
+                                        const char *consumer)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_put(struct pwm_device *pwm)
+{
+}
+
+static inline struct pwm_device *devm_pwm_get(struct device *dev,
+                                             const char *consumer)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
+{
+}
+#endif
+
 struct pwm_lookup {
        struct list_head list;
        const char *provider;
@@ -141,8 +241,12 @@ struct pwm_lookup {
                .con_id = _con_id,                      \
        }
 
+#if IS_ENABLED(CONFIG_PWM)
 void pwm_add_table(struct pwm_lookup *table, size_t num);
-
+#else
+static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
+{
+}
 #endif
 
 #endif /* __LINUX_PWM_H */
index 523547e..34206b8 100644 (file)
@@ -130,6 +130,8 @@ struct rpc_clnt     *rpc_bind_new_program(struct rpc_clnt *,
                                const struct rpc_program *, u32);
 void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
 struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
+struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *,
+                               rpc_authflavor_t);
 void           rpc_shutdown_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
 void           rpc_task_release_client(struct rpc_task *);
index bf8c49f..951cb9b 100644 (file)
@@ -173,8 +173,7 @@ struct rpc_xprt {
        unsigned int            min_reqs;       /* min number of slots */
        atomic_t                num_reqs;       /* total slots */
        unsigned long           state;          /* transport state */
-       unsigned char           shutdown   : 1, /* being shut down */
-                               resvport   : 1; /* use a reserved port */
+       unsigned char           resvport   : 1; /* use a reserved port */
        unsigned int            swapper;        /* we're swapping over this
                                                   transport */
        unsigned int            bind_index;     /* bind function index */
index 941c84b..2acd540 100644 (file)
@@ -13,9 +13,6 @@ struct se_subsystem_api {
 
        u8 transport_type;
 
-       unsigned int fua_write_emulated : 1;
-       unsigned int write_cache_emulated : 1;
-
        int (*attach_hba)(struct se_hba *, u32);
        void (*detach_hba)(struct se_hba *);
        int (*pmode_enable_hba)(struct se_hba *, unsigned long);
index 69fb3cf..81ddb4a 100644 (file)
@@ -62,8 +62,6 @@ struct target_core_fabric_ops {
        int (*queue_data_in)(struct se_cmd *);
        int (*queue_status)(struct se_cmd *);
        int (*queue_tm_rsp)(struct se_cmd *);
-       u16 (*set_fabric_sense_len)(struct se_cmd *, u32);
-       u16 (*get_fabric_sense_len)(void);
        /*
         * fabric module calls for target_core_fabric_configfs.c
         */
@@ -102,6 +100,9 @@ void        transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
                struct se_session *, u32, int, int, unsigned char *);
 int    transport_lookup_cmd_lun(struct se_cmd *, u32);
 int    target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
+int    target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *,
+               unsigned char *, unsigned char *, u32, u32, int, int, int,
+               struct scatterlist *, u32, struct scatterlist *, u32);
 int    target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
                unsigned char *, u32, u32, int, int, int);
 int    target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
index 34c5220..909dc0c 100644 (file)
@@ -239,7 +239,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
        }
        return q;
 err:
-       dprintk("RPC:       gss_fill_context returning %ld\n", -PTR_ERR(p));
+       dprintk("RPC:       %s returning %ld\n", __func__, -PTR_ERR(p));
        return p;
 }
 
@@ -301,10 +301,10 @@ __gss_find_upcall(struct rpc_pipe *pipe, uid_t uid)
                if (pos->uid != uid)
                        continue;
                atomic_inc(&pos->count);
-               dprintk("RPC:       gss_find_upcall found msg %p\n", pos);
+               dprintk("RPC:       %s found msg %p\n", __func__, pos);
                return pos;
        }
-       dprintk("RPC:       gss_find_upcall found nothing\n");
+       dprintk("RPC:       %s found nothing\n", __func__);
        return NULL;
 }
 
@@ -507,8 +507,8 @@ gss_refresh_upcall(struct rpc_task *task)
        struct rpc_pipe *pipe;
        int err = 0;
 
-       dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
-                                                               cred->cr_uid);
+       dprintk("RPC: %5u %s for uid %u\n",
+               task->tk_pid, __func__, cred->cr_uid);
        gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
        if (PTR_ERR(gss_msg) == -EAGAIN) {
                /* XXX: warning on the first, under the assumption we
@@ -539,8 +539,8 @@ gss_refresh_upcall(struct rpc_task *task)
        spin_unlock(&pipe->lock);
        gss_release_msg(gss_msg);
 out:
-       dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
-                       task->tk_pid, cred->cr_uid, err);
+       dprintk("RPC: %5u %s for uid %u result %d\n",
+               task->tk_pid, __func__, cred->cr_uid, err);
        return err;
 }
 
@@ -553,7 +553,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
        DEFINE_WAIT(wait);
        int err = 0;
 
-       dprintk("RPC:       gss_upcall for uid %u\n", cred->cr_uid);
+       dprintk("RPC:       %s for uid %u\n", __func__, cred->cr_uid);
 retry:
        gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
        if (PTR_ERR(gss_msg) == -EAGAIN) {
@@ -594,8 +594,8 @@ out_intr:
        finish_wait(&gss_msg->waitqueue, &wait);
        gss_release_msg(gss_msg);
 out:
-       dprintk("RPC:       gss_create_upcall for uid %u result %d\n",
-                       cred->cr_uid, err);
+       dprintk("RPC:       %s for uid %u result %d\n",
+               __func__, cred->cr_uid, err);
        return err;
 }
 
@@ -681,7 +681,7 @@ err_put_ctx:
 err:
        kfree(buf);
 out:
-       dprintk("RPC:       gss_pipe_downcall returning %Zd\n", err);
+       dprintk("RPC:       %s returning %Zd\n", __func__, err);
        return err;
 }
 
@@ -747,8 +747,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
        struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg);
 
        if (msg->errno < 0) {
-               dprintk("RPC:       gss_pipe_destroy_msg releasing msg %p\n",
-                               gss_msg);
+               dprintk("RPC:       %s releasing msg %p\n",
+                       __func__, gss_msg);
                atomic_inc(&gss_msg->count);
                gss_unhash_msg(gss_msg);
                if (msg->errno == -ETIMEDOUT)
@@ -976,7 +976,7 @@ gss_destroying_context(struct rpc_cred *cred)
 static void
 gss_do_free_ctx(struct gss_cl_ctx *ctx)
 {
-       dprintk("RPC:       gss_free_ctx\n");
+       dprintk("RPC:       %s\n", __func__);
 
        gss_delete_sec_context(&ctx->gc_gss_ctx);
        kfree(ctx->gc_wire_ctx.data);
@@ -999,7 +999,7 @@ gss_free_ctx(struct gss_cl_ctx *ctx)
 static void
 gss_free_cred(struct gss_cred *gss_cred)
 {
-       dprintk("RPC:       gss_free_cred %p\n", gss_cred);
+       dprintk("RPC:       %s cred=%p\n", __func__, gss_cred);
        kfree(gss_cred);
 }
 
@@ -1049,8 +1049,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        struct gss_cred *cred = NULL;
        int err = -ENOMEM;
 
-       dprintk("RPC:       gss_create_cred for uid %d, flavor %d\n",
-               acred->uid, auth->au_flavor);
+       dprintk("RPC:       %s for uid %d, flavor %d\n",
+               __func__, acred->uid, auth->au_flavor);
 
        if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
                goto out_err;
@@ -1069,7 +1069,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        return &cred->gc_base;
 
 out_err:
-       dprintk("RPC:       gss_create_cred failed with error %d\n", err);
+       dprintk("RPC:       %s failed with error %d\n", __func__, err);
        return ERR_PTR(err);
 }
 
@@ -1127,7 +1127,7 @@ gss_marshal(struct rpc_task *task, __be32 *p)
        struct kvec     iov;
        struct xdr_buf  verf_buf;
 
-       dprintk("RPC: %5u gss_marshal\n", task->tk_pid);
+       dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
 
        *p++ = htonl(RPC_AUTH_GSS);
        cred_len = p++;
@@ -1253,7 +1253,7 @@ gss_validate(struct rpc_task *task, __be32 *p)
        u32             flav,len;
        u32             maj_stat;
 
-       dprintk("RPC: %5u gss_validate\n", task->tk_pid);
+       dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
 
        flav = ntohl(*p++);
        if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
@@ -1271,20 +1271,20 @@ gss_validate(struct rpc_task *task, __be32 *p)
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
                clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        if (maj_stat) {
-               dprintk("RPC: %5u gss_validate: gss_verify_mic returned "
-                               "error 0x%08x\n", task->tk_pid, maj_stat);
+               dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
+                       task->tk_pid, __func__, maj_stat);
                goto out_bad;
        }
        /* We leave it to unwrap to calculate au_rslack. For now we just
         * calculate the length of the verifier: */
        cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
        gss_put_ctx(ctx);
-       dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n",
-                       task->tk_pid);
+       dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n",
+                       task->tk_pid, __func__);
        return p + XDR_QUADLEN(len);
 out_bad:
        gss_put_ctx(ctx);
-       dprintk("RPC: %5u gss_validate failed.\n", task->tk_pid);
+       dprintk("RPC: %5u %s failed.\n", task->tk_pid, __func__);
        return NULL;
 }
 
@@ -1466,7 +1466,7 @@ gss_wrap_req(struct rpc_task *task,
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
        int             status = -EIO;
 
-       dprintk("RPC: %5u gss_wrap_req\n", task->tk_pid);
+       dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
        if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
                /* The spec seems a little ambiguous here, but I think that not
                 * wrapping context destruction requests makes the most sense.
@@ -1489,7 +1489,7 @@ gss_wrap_req(struct rpc_task *task,
        }
 out:
        gss_put_ctx(ctx);
-       dprintk("RPC: %5u gss_wrap_req returning %d\n", task->tk_pid, status);
+       dprintk("RPC: %5u %s returning %d\n", task->tk_pid, __func__, status);
        return status;
 }
 
@@ -1604,8 +1604,8 @@ out_decode:
        status = gss_unwrap_req_decode(decode, rqstp, p, obj);
 out:
        gss_put_ctx(ctx);
-       dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
-                       status);
+       dprintk("RPC: %5u %s returning %d\n",
+               task->tk_pid, __func__, status);
        return status;
 }
 
index fa48c60..cdc7564 100644 (file)
@@ -490,61 +490,86 @@ EXPORT_SYMBOL_GPL(rpc_create);
  * same transport while varying parameters such as the authentication
  * flavour.
  */
-struct rpc_clnt *
-rpc_clone_client(struct rpc_clnt *clnt)
+static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
+                                          struct rpc_clnt *clnt)
 {
-       struct rpc_clnt *new;
        struct rpc_xprt *xprt;
-       int err = -ENOMEM;
+       struct rpc_clnt *new;
+       int err;
 
-       new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
-       if (!new)
-               goto out_no_clnt;
-       new->cl_parent = clnt;
-       /* Turn off autobind on clones */
-       new->cl_autobind = 0;
-       INIT_LIST_HEAD(&new->cl_tasks);
-       spin_lock_init(&new->cl_lock);
-       rpc_init_rtt(&new->cl_rtt_default, clnt->cl_timeout->to_initval);
-       new->cl_metrics = rpc_alloc_iostats(clnt);
-       if (new->cl_metrics == NULL)
-               goto out_no_stats;
-       if (clnt->cl_principal) {
-               new->cl_principal = kstrdup(clnt->cl_principal, GFP_KERNEL);
-               if (new->cl_principal == NULL)
-                       goto out_no_principal;
-       }
+       err = -ENOMEM;
        rcu_read_lock();
        xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
        rcu_read_unlock();
        if (xprt == NULL)
-               goto out_no_transport;
-       rcu_assign_pointer(new->cl_xprt, xprt);
-       atomic_set(&new->cl_count, 1);
-       err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
-       if (err != 0)
-               goto out_no_path;
-       rpc_clnt_set_nodename(new, utsname()->nodename);
-       if (new->cl_auth)
-               atomic_inc(&new->cl_auth->au_count);
+               goto out_err;
+       args->servername = xprt->servername;
+
+       new = rpc_new_client(args, xprt);
+       if (IS_ERR(new)) {
+               err = PTR_ERR(new);
+               goto out_put;
+       }
+
        atomic_inc(&clnt->cl_count);
-       rpc_register_client(new);
-       rpciod_up();
+       new->cl_parent = clnt;
+
+       /* Turn off autobind on clones */
+       new->cl_autobind = 0;
+       new->cl_softrtry = clnt->cl_softrtry;
+       new->cl_discrtry = clnt->cl_discrtry;
+       new->cl_chatty = clnt->cl_chatty;
        return new;
-out_no_path:
+
+out_put:
        xprt_put(xprt);
-out_no_transport:
-       kfree(new->cl_principal);
-out_no_principal:
-       rpc_free_iostats(new->cl_metrics);
-out_no_stats:
-       kfree(new);
-out_no_clnt:
+out_err:
        dprintk("RPC:       %s: returned error %d\n", __func__, err);
        return ERR_PTR(err);
 }
+
+/**
+ * rpc_clone_client - Clone an RPC client structure
+ *
+ * @clnt: RPC client whose parameters are copied
+ *
+ * Returns a fresh RPC client or an ERR_PTR.
+ */
+struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
+{
+       struct rpc_create_args args = {
+               .program        = clnt->cl_program,
+               .prognumber     = clnt->cl_prog,
+               .version        = clnt->cl_vers,
+               .authflavor     = clnt->cl_auth->au_flavor,
+               .client_name    = clnt->cl_principal,
+       };
+       return __rpc_clone_client(&args, clnt);
+}
 EXPORT_SYMBOL_GPL(rpc_clone_client);
 
+/**
+ * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
+ *
+ * @clnt: RPC client whose parameters are copied
+ * @auth: security flavor for new client
+ *
+ * Returns a fresh RPC client or an ERR_PTR.
+ */
+struct rpc_clnt *
+rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+{
+       struct rpc_create_args args = {
+               .program        = clnt->cl_program,
+               .prognumber     = clnt->cl_prog,
+               .version        = clnt->cl_vers,
+               .authflavor     = flavor,
+               .client_name    = clnt->cl_principal,
+       };
+       return __rpc_clone_client(&args, clnt);
+}
+EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
+
 /*
  * Kill all tasks for the given client.
  * XXX: kill their descendants as well?
index 21fde99..80f5dd2 100644 (file)
@@ -1119,8 +1119,8 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
                return -ENOMEM;
-       dprintk("RPC:   sending pipefs MOUNT notification for net %p%s\n", net,
-                                                               NET_NAME(net));
+       dprintk("RPC:       sending pipefs MOUNT notification for net %p%s\n",
+               net, NET_NAME(net));
        sn->pipefs_sb = sb;
        err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_MOUNT,
@@ -1155,8 +1155,8 @@ static void rpc_kill_sb(struct super_block *sb)
        sn->pipefs_sb = NULL;
        mutex_unlock(&sn->pipefs_sb_lock);
        put_net(net);
-       dprintk("RPC:   sending pipefs UMOUNT notification for net %p%s\n", net,
-                                                               NET_NAME(net));
+       dprintk("RPC:       sending pipefs UMOUNT notification for net %p%s\n",
+               net, NET_NAME(net));
        blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_UMOUNT,
                                           sb);
index 128494e..6357fcb 100644 (file)
@@ -1022,7 +1022,7 @@ static int rpciod_start(void)
         * Create the rpciod thread and wait for it to start.
         */
        dprintk("RPC:       creating workqueue rpciod\n");
-       wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 0);
+       wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 1);
        rpciod_workqueue = wq;
        return rpciod_workqueue != NULL;
 }
index 0afba1b..08f50af 100644 (file)
@@ -730,19 +730,24 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
 
        if (xdr->nwords == 0)
                return 0;
-       if (nwords > xdr->nwords) {
-               nwords = xdr->nwords;
-               len = nwords << 2;
-       }
        /* Realign pages to current pointer position */
        iov  = buf->head;
-       if (iov->iov_len > cur)
+       if (iov->iov_len > cur) {
                xdr_shrink_bufhead(buf, iov->iov_len - cur);
+               xdr->nwords = XDR_QUADLEN(buf->len - cur);
+       }
 
-       /* Truncate page data and move it into the tail */
-       if (buf->page_len > len)
+       if (nwords > xdr->nwords) {
+               nwords = xdr->nwords;
+               len = nwords << 2;
+       }
+       if (buf->page_len <= len)
+               len = buf->page_len;
+       else if (nwords < xdr->nwords) {
+               /* Truncate page data and move it into the tail */
                xdr_shrink_pagelen(buf, buf->page_len - len);
-       xdr->nwords = XDR_QUADLEN(buf->len - cur);
+               xdr->nwords = XDR_QUADLEN(buf->len - cur);
+       }
        return len;
 }
 
index 5d7f61d..bd462a5 100644 (file)
@@ -231,7 +231,7 @@ EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
 static void xprt_clear_locked(struct rpc_xprt *xprt)
 {
        xprt->snd_task = NULL;
-       if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
+       if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
                smp_mb__before_clear_bit();
                clear_bit(XPRT_LOCKED, &xprt->state);
                smp_mb__after_clear_bit();
@@ -504,9 +504,6 @@ EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
  */
 void xprt_write_space(struct rpc_xprt *xprt)
 {
-       if (unlikely(xprt->shutdown))
-               return;
-
        spin_lock_bh(&xprt->transport_lock);
        if (xprt->snd_task) {
                dprintk("RPC:       write space: waking waiting task on "
@@ -679,7 +676,7 @@ xprt_init_autodisconnect(unsigned long data)
        struct rpc_xprt *xprt = (struct rpc_xprt *)data;
 
        spin_lock(&xprt->transport_lock);
-       if (!list_empty(&xprt->recv) || xprt->shutdown)
+       if (!list_empty(&xprt->recv))
                goto out_abort;
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
                goto out_abort;
@@ -1262,7 +1259,6 @@ out:
 static void xprt_destroy(struct rpc_xprt *xprt)
 {
        dprintk("RPC:       destroying transport %p\n", xprt);
-       xprt->shutdown = 1;
        del_timer_sync(&xprt->timer);
 
        rpc_destroy_wait_queue(&xprt->binding);
index 5d9202d..c9aa7a3 100644 (file)
@@ -199,21 +199,15 @@ xprt_rdma_connect_worker(struct work_struct *work)
        struct rpc_xprt *xprt = &r_xprt->xprt;
        int rc = 0;
 
-       if (!xprt->shutdown) {
-               current->flags |= PF_FSTRANS;
-               xprt_clear_connected(xprt);
-
-               dprintk("RPC:       %s: %sconnect\n", __func__,
-                               r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
-               rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
-               if (rc)
-                       goto out;
-       }
-       goto out_clear;
+       current->flags |= PF_FSTRANS;
+       xprt_clear_connected(xprt);
+
+       dprintk("RPC:       %s: %sconnect\n", __func__,
+                       r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
+       rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+       if (rc)
+               xprt_wake_pending_tasks(xprt, rc);
 
-out:
-       xprt_wake_pending_tasks(xprt, rc);
-out_clear:
        dprintk("RPC:       %s: exit\n", __func__);
        xprt_clear_connecting(xprt);
        current->flags &= ~PF_FSTRANS;
index a35b8e5..aaaadfb 100644 (file)
@@ -917,9 +917,6 @@ static void xs_local_data_ready(struct sock *sk, int len)
        if (skb == NULL)
                goto out;
 
-       if (xprt->shutdown)
-               goto dropit;
-
        repsize = skb->len - sizeof(rpc_fraghdr);
        if (repsize < 4) {
                dprintk("RPC:       impossible RPC reply size %d\n", repsize);
@@ -981,9 +978,6 @@ static void xs_udp_data_ready(struct sock *sk, int len)
        if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
                goto out;
 
-       if (xprt->shutdown)
-               goto dropit;
-
        repsize = skb->len - sizeof(struct udphdr);
        if (repsize < 4) {
                dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
@@ -1025,6 +1019,16 @@ static void xs_udp_data_ready(struct sock *sk, int len)
        read_unlock_bh(&sk->sk_callback_lock);
 }
 
+/*
+ * Helper function to force a TCP close if the server is sending
+ * junk and/or it has put us in CLOSE_WAIT
+ */
+static void xs_tcp_force_close(struct rpc_xprt *xprt)
+{
+       set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
+       xprt_force_disconnect(xprt);
+}
+
 static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1051,7 +1055,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea
        /* Sanity check of the record length */
        if (unlikely(transport->tcp_reclen < 8)) {
                dprintk("RPC:       invalid TCP record fragment length\n");
-               xprt_force_disconnect(xprt);
+               xs_tcp_force_close(xprt);
                return;
        }
        dprintk("RPC:       reading TCP record fragment of length %d\n",
@@ -1132,7 +1136,7 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport,
                break;
        default:
                dprintk("RPC:       invalid request message type\n");
-               xprt_force_disconnect(&transport->xprt);
+               xs_tcp_force_close(&transport->xprt);
        }
        xs_tcp_check_fraghdr(transport);
 }
@@ -1402,9 +1406,6 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes)
        read_lock_bh(&sk->sk_callback_lock);
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
-       if (xprt->shutdown)
-               goto out;
-
        /* Any data means we had a useful conversation, so
         * the we don't need to delay the next reconnect
         */
@@ -1455,6 +1456,8 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt)
 static void xs_sock_mark_closed(struct rpc_xprt *xprt)
 {
        smp_mb__before_clear_bit();
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
        clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
        clear_bit(XPRT_CLOSING, &xprt->state);
        smp_mb__after_clear_bit();
@@ -1512,8 +1515,8 @@ static void xs_tcp_state_change(struct sock *sk)
                break;
        case TCP_CLOSE_WAIT:
                /* The server initiated a shutdown of the socket */
-               xprt_force_disconnect(xprt);
                xprt->connect_cookie++;
+               xs_tcp_force_close(xprt);
        case TCP_CLOSING:
                /*
                 * If the server closed down the connection, make sure that
@@ -1889,9 +1892,6 @@ static void xs_local_setup_socket(struct work_struct *work)
        struct socket *sock;
        int status = -EIO;
 
-       if (xprt->shutdown)
-               goto out;
-
        current->flags |= PF_FSTRANS;
 
        clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
@@ -2008,9 +2008,6 @@ static void xs_udp_setup_socket(struct work_struct *work)
        struct socket *sock = transport->sock;
        int status = -EIO;
 
-       if (xprt->shutdown)
-               goto out;
-
        current->flags |= PF_FSTRANS;
 
        /* Start by resetting any existing state */
@@ -2156,9 +2153,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
        struct rpc_xprt *xprt = &transport->xprt;
        int status = -EIO;
 
-       if (xprt->shutdown)
-               goto out;
-
        current->flags |= PF_FSTRANS;
 
        if (!sock) {
@@ -2199,8 +2193,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
                /* We're probably in TIME_WAIT. Get rid of existing socket,
                 * and retry
                 */
-               set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
-               xprt_force_disconnect(xprt);
+               xs_tcp_force_close(xprt);
                break;
        case -ECONNREFUSED:
        case -ECONNRESET:
@@ -2528,6 +2521,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
 static struct rpc_xprt_ops bc_tcp_ops = {
        .reserve_xprt           = xprt_reserve_xprt,
        .release_xprt           = xprt_release_xprt,
+       .alloc_slot             = xprt_alloc_slot,
        .rpcbind                = xs_local_rpcbind,
        .buf_alloc              = bc_malloc,
        .buf_free               = bc_free,